Merge conflict, Editor.js

This commit is contained in:
Artur Paikin 2021-07-30 14:31:21 +01:00
commit bb1c615dc4
39 changed files with 402 additions and 454 deletions

View file

@ -10,7 +10,6 @@ module.exports = class MyCustomProvider extends UIPlugin {
this.id = this.opts.id || 'MyCustomProvider'
Provider.initPlugin(this, opts)
this.title = 'MyUnsplash'
this.icon = () => (
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
<path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z" fill="#000000" fillRule="nonzero" />
@ -24,6 +23,14 @@ module.exports = class MyCustomProvider extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameMyUnsplash: 'MyUnsplash',
},
}
this.i18nInit()
this.title = this.i18n('MyUnsplash')
this.files = []
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)

2
package-lock.json generated
View file

@ -89718,7 +89718,7 @@
"@uppy/google-drive": "*",
"@uppy/informer": "file:../informer",
"@uppy/provider-views": "file:../provider-views",
"@uppy/status-bar": "*",
"@uppy/status-bar": "file:../status-bar",
"@uppy/thumbnail-generator": "file:../thumbnail-generator",
"@uppy/utils": "file:../utils",
"classnames": "^2.2.6",

View file

@ -90,24 +90,11 @@ module.exports = class AwsS3 extends BasePlugin {
this.opts = { ...defaultOptions, ...opts }
this.i18nInit()
this.client = new RequestClient(uppy, opts)
this.handleUpload = this.handleUpload.bind(this)
this.requests = new RateLimitedQueue(this.opts.limit)
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
getUploadParameters (file) {
if (!this.opts.companionUrl) {
throw new Error('Expected a `companionUrl` option containing a Companion address.')

View file

@ -32,6 +32,14 @@ module.exports = class Box extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameBox: 'Box',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameBox')
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)
}

View file

@ -8,9 +8,33 @@ function stripSlash (url) {
return url.replace(/\/$/, '')
}
async function handleJSONResponse (res) {
if (res.status === 401) {
throw new AuthError()
}
const jsonPromise = res.json()
if (res.status < 200 || res.status > 300) {
let errMsg = `Failed request with status: ${res.status}. ${res.statusText}`
try {
const errData = await jsonPromise
errMsg = errData.message ? `${errMsg} message: ${errData.message}` : errMsg
errMsg = errData.requestId ? `${errMsg} request-Id: ${errData.requestId}` : errMsg
} finally {
// eslint-disable-next-line no-unsafe-finally
throw new Error(errMsg)
}
}
return jsonPromise
}
module.exports = class RequestClient {
// eslint-disable-next-line global-require
static VERSION = require('../package.json').version
#getPostResponseFunc = skip => response => (skip ? response : this.onReceiveResponse(response))
constructor (uppy, opts) {
this.uppy = uppy
this.opts = opts
@ -25,32 +49,20 @@ module.exports = class RequestClient {
return stripSlash(companion && companion[host] ? companion[host] : host)
}
get defaultHeaders () {
return {
Accept: 'application/json',
'Content-Type': 'application/json',
'Uppy-Versions': `@uppy/companion-client=${RequestClient.VERSION}`,
}
static defaultHeaders ={
Accept: 'application/json',
'Content-Type': 'application/json',
'Uppy-Versions': `@uppy/companion-client=${RequestClient.VERSION}`,
}
headers () {
const userHeaders = this.opts.companionHeaders || {}
return Promise.resolve({
...this.defaultHeaders,
...RequestClient.defaultHeaders,
...userHeaders,
})
}
_getPostResponseFunc (skip) {
return (response) => {
if (!skip) {
return this.onReceiveResponse(response)
}
return response
}
}
onReceiveResponse (response) {
const state = this.uppy.getState()
const companion = state.companion || {}
@ -65,28 +77,22 @@ module.exports = class RequestClient {
return response
}
_getUrl (url) {
#getUrl (url) {
if (/^(https?:|)\/\//.test(url)) {
return url
}
return `${this.hostname}/${url}`
}
_json (res) {
if (res.status === 401) {
throw new AuthError()
#errorHandler (method, path) {
return (err) => {
if (!err?.isAuthError) {
const error = new Error(`Could not ${method} ${this.#getUrl(path)}`)
error.cause = err
err = error // eslint-disable-line no-param-reassign
}
return Promise.reject(err)
}
if (res.status < 200 || res.status > 300) {
let errMsg = `Failed request with status: ${res.status}. ${res.statusText}`
return res.json()
.then((errData) => {
errMsg = errData.message ? `${errMsg} message: ${errData.message}` : errMsg
errMsg = errData.requestId ? `${errMsg} request-Id: ${errData.requestId}` : errMsg
throw new Error(errMsg)
}).catch(() => { throw new Error(errMsg) })
}
return res.json()
}
preflight (path) {
@ -94,7 +100,7 @@ module.exports = class RequestClient {
return Promise.resolve(this.allowedHeaders.slice())
}
return fetch(this._getUrl(path), {
return fetch(this.#getUrl(path), {
method: 'OPTIONS',
})
.then((response) => {
@ -117,9 +123,9 @@ module.exports = class RequestClient {
.then(([allowedHeaders, headers]) => {
// filter to keep only allowed Headers
Object.keys(headers).forEach((header) => {
if (allowedHeaders.indexOf(header.toLowerCase()) === -1) {
this.uppy.log(`[CompanionClient] excluding unallowed header ${header}`)
delete headers[header]
if (!allowedHeaders.includes(header.toLowerCase())) {
this.uppy.log(`[CompanionClient] excluding disallowed header ${header}`)
delete headers[header] // eslint-disable-line no-param-reassign
}
})
@ -128,55 +134,43 @@ module.exports = class RequestClient {
}
get (path, skipPostResponse) {
const method = 'get'
return this.preflightAndHeaders(path)
.then((headers) => fetchWithNetworkError(this._getUrl(path), {
method: 'get',
.then((headers) => fetchWithNetworkError(this.#getUrl(path), {
method,
headers,
credentials: this.opts.companionCookiesRule || 'same-origin',
}))
.then(this._getPostResponseFunc(skipPostResponse))
.then((res) => this._json(res))
.catch((err) => {
if (!err.isAuthError) {
err.message = `Could not get ${this._getUrl(path)}. ${err.message}`
}
return Promise.reject(err)
})
.then(this.#getPostResponseFunc(skipPostResponse))
.then(handleJSONResponse)
.catch(this.#errorHandler(method, path))
}
post (path, data, skipPostResponse) {
const method = 'post'
return this.preflightAndHeaders(path)
.then((headers) => fetchWithNetworkError(this._getUrl(path), {
method: 'post',
.then((headers) => fetchWithNetworkError(this.#getUrl(path), {
method,
headers,
credentials: this.opts.companionCookiesRule || 'same-origin',
body: JSON.stringify(data),
}))
.then(this._getPostResponseFunc(skipPostResponse))
.then((res) => this._json(res))
.catch((err) => {
if (!err.isAuthError) {
err.message = `Could not post ${this._getUrl(path)}. ${err.message}`
}
return Promise.reject(err)
})
.then(this.#getPostResponseFunc(skipPostResponse))
.then(handleJSONResponse)
.catch(this.#errorHandler(method, path))
}
delete (path, data, skipPostResponse) {
const method = 'delete'
return this.preflightAndHeaders(path)
.then((headers) => fetchWithNetworkError(`${this.hostname}/${path}`, {
method: 'delete',
method,
headers,
credentials: this.opts.companionCookiesRule || 'same-origin',
body: data ? JSON.stringify(data) : null,
}))
.then(this._getPostResponseFunc(skipPostResponse))
.then((res) => this._json(res))
.catch((err) => {
if (!err.isAuthError) {
err.message = `Could not delete ${this._getUrl(path)}. ${err.message}`
}
return Promise.reject(err)
})
.then(this.#getPostResponseFunc(skipPostResponse))
.then(handleJSONResponse)
.catch(this.#errorHandler(method, path))
}
}

View file

@ -1,83 +1,84 @@
const ee = require('namespace-emitter')
module.exports = class UppySocket {
#queued = []
#emitter = ee()
#isOpen = false
#socket
constructor (opts) {
this.opts = opts
this._queued = []
this.isOpen = false
this.emitter = ee()
this._handleMessage = this._handleMessage.bind(this)
this.close = this.close.bind(this)
this.emit = this.emit.bind(this)
this.on = this.on.bind(this)
this.once = this.once.bind(this)
this.send = this.send.bind(this)
if (!opts || opts.autoOpen !== false) {
this.open()
}
}
get isOpen () { return this.#isOpen }
[Symbol.for('uppy test: getSocket')] () { return this.#socket }
[Symbol.for('uppy test: getQueued')] () { return this.#queued }
open () {
this.socket = new WebSocket(this.opts.target)
this.#socket = new WebSocket(this.opts.target)
this.socket.onopen = (e) => {
this.isOpen = true
this.#socket.onopen = () => {
this.#isOpen = true
while (this._queued.length > 0 && this.isOpen) {
const first = this._queued[0]
while (this.#queued.length > 0 && this.#isOpen) {
const first = this.#queued.shift()
this.send(first.action, first.payload)
this._queued = this._queued.slice(1)
}
}
this.socket.onclose = (e) => {
this.isOpen = false
this.#socket.onclose = () => {
this.#isOpen = false
}
this.socket.onmessage = this._handleMessage
this.#socket.onmessage = this.#handleMessage
}
close () {
if (this.socket) {
this.socket.close()
}
this.#socket?.close()
}
send (action, payload) {
// attach uuid
if (!this.isOpen) {
this._queued.push({ action, payload })
if (!this.#isOpen) {
this.#queued.push({ action, payload })
return
}
this.socket.send(JSON.stringify({
this.#socket.send(JSON.stringify({
action,
payload,
}))
}
on (action, handler) {
this.emitter.on(action, handler)
this.#emitter.on(action, handler)
}
emit (action, payload) {
this.emitter.emit(action, payload)
this.#emitter.emit(action, payload)
}
once (action, handler) {
this.emitter.once(action, handler)
this.#emitter.once(action, handler)
}
_handleMessage (e) {
#handleMessage= (e) => {
try {
const message = JSON.parse(e.data)
this.emit(message.action, message.payload)
} catch (err) {
console.log(err)
// TODO: use a more robust error handler.
console.log(err) // eslint-disable-line no-console
}
}
}

View file

@ -15,10 +15,12 @@ describe('Socket', () => {
webSocketConstructorSpy(target)
}
// eslint-disable-next-line class-methods-use-this
close (args) {
webSocketCloseSpy(args)
}
// eslint-disable-next-line class-methods-use-this
send (json) {
webSocketSendSpy(json)
}
@ -52,7 +54,7 @@ describe('Socket', () => {
it('should send a message via the websocket if the connection is open', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket.socket
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
webSocketInstance.triggerOpen()
uppySocket.send('bar', 'boo')
@ -66,17 +68,17 @@ describe('Socket', () => {
const uppySocket = new UppySocket({ target: 'foo' })
uppySocket.send('bar', 'boo')
expect(uppySocket._queued).toEqual([{ action: 'bar', payload: 'boo' }])
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([{ action: 'bar', payload: 'boo' }])
expect(webSocketSendSpy.mock.calls.length).toEqual(0)
})
it('should queue any messages for the websocket if the connection is not open, then send them when the connection is open', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket.socket
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
uppySocket.send('bar', 'boo')
uppySocket.send('moo', 'baa')
expect(uppySocket._queued).toEqual([
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([
{ action: 'bar', payload: 'boo' },
{ action: 'moo', payload: 'baa' },
])
@ -84,7 +86,7 @@ describe('Socket', () => {
webSocketInstance.triggerOpen()
expect(uppySocket._queued).toEqual([])
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([])
expect(webSocketSendSpy.mock.calls.length).toEqual(2)
expect(webSocketSendSpy.mock.calls[0]).toEqual([
JSON.stringify({ action: 'bar', payload: 'boo' }),
@ -96,19 +98,19 @@ describe('Socket', () => {
it('should start queuing any messages when the websocket connection is closed', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket.socket
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
webSocketInstance.triggerOpen()
uppySocket.send('bar', 'boo')
expect(uppySocket._queued).toEqual([])
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([])
webSocketInstance.triggerClose()
uppySocket.send('bar', 'boo')
expect(uppySocket._queued).toEqual([{ action: 'bar', payload: 'boo' }])
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([{ action: 'bar', payload: 'boo' }])
})
it('should close the websocket when it is force closed', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket.socket
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
webSocketInstance.triggerOpen()
uppySocket.close()
@ -117,7 +119,7 @@ describe('Socket', () => {
it('should be able to subscribe to messages received on the websocket', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket.socket
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
const emitterListenerMock = jest.fn()
uppySocket.on('hi', emitterListenerMock)

View file

@ -65,7 +65,7 @@ export interface SocketOptions {
}
export class Socket {
isOpen: boolean
readonly isOpen: boolean
constructor (opts: SocketOptions)

View file

@ -6,6 +6,9 @@
*
* See `Plugin` for the extended version with Preact rendering for interfaces.
*/
const Translator = require('@uppy/utils/lib/Translator')
module.exports = class BasePlugin {
constructor (uppy, opts = {}) {
this.uppy = uppy
@ -34,6 +37,14 @@ module.exports = class BasePlugin {
setOptions (newOpts) {
this.opts = { ...this.opts, ...newOpts }
this.setPluginState() // so that UI re-renders with new options
this.i18nInit()
}
i18nInit () {
const translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = translator.translate.bind(translator)
this.i18nArray = translator.translateArray.bind(translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
/**

View file

@ -54,6 +54,14 @@ class Uppy {
#emitter = ee()
#translator
#preProcessors = new Set()
#uploaders = new Set()
#postProcessors = new Set()
/**
* Instantiate Uppy
*
@ -173,10 +181,6 @@ class Uppy {
// [Practical Check] Firefox, try to upload a big file for a prolonged period of time. Laptop will start to heat up.
this.calculateProgress = throttle(this.calculateProgress.bind(this), 500, { leading: true, trailing: true })
this.preProcessors = []
this.uploaders = []
this.postProcessors = []
this.store = this.opts.store
this.setState({
plugins: {},
@ -279,10 +283,16 @@ class Uppy {
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.opts.locale])
this.locale = this.translator.locale
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.#translator = new Translator([this.defaultLocale, this.opts.locale])
this.locale = this.#translator.locale
}
i18n (...args) {
return this.#translator.translate(...args)
}
i18nArray (...args) {
return this.#translator.translateArray(...args)
}
setOptions (newOpts) {
@ -335,36 +345,27 @@ class Uppy {
}
addPreProcessor (fn) {
this.preProcessors.push(fn)
this.#preProcessors.add(fn)
}
removePreProcessor (fn) {
const i = this.preProcessors.indexOf(fn)
if (i !== -1) {
this.preProcessors.splice(i, 1)
}
return this.#preProcessors.delete(fn)
}
addPostProcessor (fn) {
this.postProcessors.push(fn)
this.#postProcessors.add(fn)
}
removePostProcessor (fn) {
const i = this.postProcessors.indexOf(fn)
if (i !== -1) {
this.postProcessors.splice(i, 1)
}
return this.#postProcessors.delete(fn)
}
addUploader (fn) {
this.uploaders.push(fn)
this.#uploaders.add(fn)
}
removeUploader (fn) {
const i = this.uploaders.indexOf(fn)
if (i !== -1) {
this.uploaders.splice(i, 1)
}
return this.#uploaders.delete(fn)
}
setMeta (data) {
@ -1199,7 +1200,7 @@ class Uppy {
this.setFileState(file.id, {
progress: {
...currentProgress,
postprocess: this.postProcessors.length > 0 ? {
postprocess: this.#postProcessors.size > 0 ? {
mode: 'indeterminate',
} : null,
uploadComplete: true,
@ -1592,9 +1593,9 @@ class Uppy {
const restoreStep = uploadData.step
const steps = [
...this.preProcessors,
...this.uploaders,
...this.postProcessors,
...this.#preProcessors,
...this.#uploaders,
...this.#postProcessors,
]
let lastStep = Promise.resolve()
steps.forEach((fn, step) => {

View file

@ -327,24 +327,13 @@ describe('src/Core', () => {
})
describe('preprocessors', () => {
it('should add a preprocessor', () => {
it('should add and remove preprocessor', () => {
const core = new Core()
const preprocessor = () => { }
expect(core.removePreProcessor(preprocessor)).toBe(false)
core.addPreProcessor(preprocessor)
expect(core.preProcessors[0]).toEqual(preprocessor)
})
it('should remove a preprocessor', () => {
const core = new Core()
const preprocessor1 = () => { }
const preprocessor2 = () => { }
const preprocessor3 = () => { }
core.addPreProcessor(preprocessor1)
core.addPreProcessor(preprocessor2)
core.addPreProcessor(preprocessor3)
expect(core.preProcessors.length).toEqual(3)
core.removePreProcessor(preprocessor2)
expect(core.preProcessors.length).toEqual(2)
expect(core.removePreProcessor(preprocessor)).toBe(true)
expect(core.removePreProcessor(preprocessor)).toBe(false)
})
it('should execute all the preprocessors when uploading a file', () => {
@ -456,24 +445,13 @@ describe('src/Core', () => {
})
describe('postprocessors', () => {
it('should add a postprocessor', () => {
it('should add and remove postprocessor', () => {
const core = new Core()
const postprocessor = () => { }
expect(core.removePostProcessor(postprocessor)).toBe(false)
core.addPostProcessor(postprocessor)
expect(core.postProcessors[0]).toEqual(postprocessor)
})
it('should remove a postprocessor', () => {
const core = new Core()
const postprocessor1 = () => { }
const postprocessor2 = () => { }
const postprocessor3 = () => { }
core.addPostProcessor(postprocessor1)
core.addPostProcessor(postprocessor2)
core.addPostProcessor(postprocessor3)
expect(core.postProcessors.length).toEqual(3)
core.removePostProcessor(postprocessor2)
expect(core.postProcessors.length).toEqual(2)
expect(core.removePostProcessor(postprocessor)).toBe(true)
expect(core.removePostProcessor(postprocessor)).toBe(false)
})
it('should execute all the postprocessors when uploading a file', () => {
@ -586,24 +564,13 @@ describe('src/Core', () => {
})
describe('uploaders', () => {
it('should add an uploader', () => {
it('should add and remove uploader', () => {
const core = new Core()
const uploader = () => { }
expect(core.removeUploader(uploader)).toBe(false)
core.addUploader(uploader)
expect(core.uploaders[0]).toEqual(uploader)
})
it('should remove an uploader', () => {
const core = new Core()
const uploader1 = () => { }
const uploader2 = () => { }
const uploader3 = () => { }
core.addUploader(uploader1)
core.addUploader(uploader2)
core.addUploader(uploader3)
expect(core.uploaders.length).toEqual(3)
core.removeUploader(uploader2)
expect(core.uploaders.length).toEqual(2)
expect(core.removeUploader(uploader)).toBe(true)
expect(core.removeUploader(uploader)).toBe(false)
})
})

View file

@ -165,18 +165,6 @@ module.exports = class Dashboard extends UIPlugin {
this.removeDragOverClassTimeout = null
}
setOptions = (newOpts) => {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit = () => {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
removeTarget = (plugin) => {
const pluginState = this.getPluginState()
// filter out the one we want to remove

View file

@ -38,12 +38,12 @@ module.exports = class DragDrop extends UIPlugin {
// Merge default options with the ones set by user
this.opts = { ...defaultOpts, ...opts }
this.i18nInit()
// Check for browser dragDrop support
this.isDragDropSupported = isDragDropSupported()
this.removeDragOverClassTimeout = null
this.i18nInit()
// Bind `this` to class methods
this.onInputChange = this.onInputChange.bind(this)
this.handleDragOver = this.handleDragOver.bind(this)
@ -53,18 +53,6 @@ module.exports = class DragDrop extends UIPlugin {
this.render = this.render.bind(this)
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
addFiles (files) {
const descriptors = files.map((file) => ({
source: this.id,

View file

@ -29,6 +29,14 @@ module.exports = class Dropbox extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameDropbox: 'Dropbox',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameDropbox')
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)
}

View file

@ -29,6 +29,14 @@ module.exports = class Facebook extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameFacebook: 'Facebook',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameFacebook')
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)
}

View file

@ -38,18 +38,6 @@ module.exports = class FileInput extends UIPlugin {
this.handleClick = this.handleClick.bind(this)
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
addFiles (files) {
const descriptors = files.map((file) => ({
source: this.id,

View file

@ -30,6 +30,14 @@ module.exports = class GoogleDrive extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameGoogleDrive: 'Google Drive',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameGoogleDrive')
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)
}

View file

@ -31,43 +31,15 @@ module.exports = class Editor extends Component {
this.cropper.destroy()
}
renderRevert () {
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('revert')}
data-microtip-position="top"
role="tooltip"
onClick={() => {
this.cropper.reset()
this.cropper.setAspectRatio(0)
}}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z" />
</svg>
</button>
)
}
save = () => {
const { opts, save, currentImage } = this.props
renderRotate () {
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
onClick={() => this.cropper.rotate(-90)}
aria-label={this.props.i18n('rotate')}
data-microtip-position="top"
role="tooltip"
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0zm0 0h24v24H0V0z" fill="none" />
<path d="M14 10a2 2 0 012 2v7a2 2 0 01-2 2H6a2 2 0 01-2-2v-7a2 2 0 012-2h8zm0 1.75H6a.25.25 0 00-.243.193L5.75 12v7a.25.25 0 00.193.243L6 19.25h8a.25.25 0 00.243-.193L14.25 19v-7a.25.25 0 00-.193-.243L14 11.75zM12 .76V4c2.3 0 4.61.88 6.36 2.64a8.95 8.95 0 012.634 6.025L21 13a1 1 0 01-1.993.117L19 13h-.003a6.979 6.979 0 00-2.047-4.95 6.97 6.97 0 00-4.652-2.044L12 6v3.24L7.76 5 12 .76z" />
</svg>
</button>
)
this.cropper.getCroppedCanvas(opts.cropperOptions.croppedCanvasOptions)
.toBlob(
(blob) => save(blob),
currentImage.type,
opts.quality
)
}
granularRotateOnChange = (ev) => {
@ -83,11 +55,15 @@ module.exports = class Editor extends Component {
}
renderGranularRotate () {
const { i18n } = this.props
const { rotationDelta, rotationAngle } = this.state
return (
// eslint-disable-next-line jsx-a11y/label-has-associated-control
<label
data-microtip-position="top"
role="tooltip"
aria-label={`${this.state.rotationAngle}º`}
aria-label={`${rotationAngle}º`}
className="uppy-ImageCropper-rangeWrapper uppy-u-reset"
>
<input
@ -95,23 +71,65 @@ module.exports = class Editor extends Component {
type="range"
onInput={this.granularRotateOnChange}
onChange={this.granularRotateOnChange}
value={this.state.rotationDelta}
value={rotationDelta}
min="-45"
max="44"
aria-label={this.props.i18n('rotate')}
aria-label={i18n('rotate')}
/>
</label>
)
}
renderFlip () {
renderRevert () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('flipHorizontal')}
aria-label={i18n('revert')}
data-microtip-position="top"
onClick={() => {
this.cropper.reset()
this.cropper.setAspectRatio(0)
}}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z" />
</svg>
</button>
)
}
renderRotate () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
onClick={() => this.cropper.rotate(-90)}
aria-label={i18n('rotate')}
data-microtip-position="top"
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0zm0 0h24v24H0V0z" fill="none" />
<path d="M14 10a2 2 0 012 2v7a2 2 0 01-2 2H6a2 2 0 01-2-2v-7a2 2 0 012-2h8zm0 1.75H6a.25.25 0 00-.243.193L5.75 12v7a.25.25 0 00.193.243L6 19.25h8a.25.25 0 00.243-.193L14.25 19v-7a.25.25 0 00-.193-.243L14 11.75zM12 .76V4c2.3 0 4.61.88 6.36 2.64a8.95 8.95 0 012.634 6.025L21 13a1 1 0 01-1.993.117L19 13h-.003a6.979 6.979 0 00-2.047-4.95 6.97 6.97 0 00-4.652-2.044L12 6v3.24L7.76 5 12 .76z" />
</svg>
</button>
)
}
renderFlip () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={i18n('flipHorizontal')}
data-microtip-position="top"
role="tooltip"
onClick={() => this.cropper.scaleX(-this.cropper.getData().scaleX || -1)}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
@ -123,13 +141,14 @@ module.exports = class Editor extends Component {
}
renderZoomIn () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('zoomIn')}
aria-label={i18n('zoomIn')}
data-microtip-position="top"
role="tooltip"
onClick={() => this.cropper.zoom(0.1)}
>
<svg aria-hidden="true" className="uppy-c-icon" height="24" viewBox="0 0 24 24" width="24">
@ -142,13 +161,14 @@ module.exports = class Editor extends Component {
}
renderZoomOut () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('zoomOut')}
aria-label={i18n('zoomOut')}
data-microtip-position="top"
role="tooltip"
onClick={() => this.cropper.zoom(-0.1)}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
@ -160,13 +180,14 @@ module.exports = class Editor extends Component {
}
renderCropSquare () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('aspectRatioSquare')}
aria-label={i18n('aspectRatioSquare')}
data-microtip-position="top"
role="tooltip"
onClick={() => this.cropper.setAspectRatio(1)}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
@ -178,13 +199,14 @@ module.exports = class Editor extends Component {
}
renderCropWidescreen () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('aspectRatioLandscape')}
aria-label={i18n('aspectRatioLandscape')}
data-microtip-position="top"
role="tooltip"
onClick={() => this.cropper.setAspectRatio(16 / 9)}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
@ -196,13 +218,14 @@ module.exports = class Editor extends Component {
}
renderCropWidescreenVertical () {
const { i18n } = this.props
return (
<button
type="button"
className="uppy-u-reset uppy-c-btn"
aria-label={this.props.i18n('aspectRatioPortrait')}
aria-label={i18n('aspectRatioPortrait')}
data-microtip-position="top"
role="tooltip"
onClick={() => this.cropper.setAspectRatio(9 / 16)}
>
<svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">

View file

@ -4,6 +4,7 @@ const { h } = require('preact')
const Editor = require('./Editor')
module.exports = class ImageEditor extends UIPlugin {
// eslint-disable-next-line global-require
static VERSION = require('../package.json').version
constructor (uppy, opts) {
@ -30,6 +31,7 @@ module.exports = class ImageEditor extends UIPlugin {
background: false,
autoCropArea: 1,
responsive: true,
croppedCanvasOptions: {},
}
const defaultActions = {
@ -64,18 +66,7 @@ module.exports = class ImageEditor extends UIPlugin {
this.i18nInit()
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
// this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
// eslint-disable-next-line class-methods-use-this
canEditFile (file) {
if (!file.type || file.isRemote) {
return false
@ -145,8 +136,9 @@ module.exports = class ImageEditor extends UIPlugin {
render () {
const { currentImage } = this.getPluginState()
if (currentImage === null || currentImage.isRemote) {
return
return null
}
return (

View file

@ -1,4 +1,5 @@
import type { PluginOptions, UIPlugin, PluginTarget } from '@uppy/core'
import type Cropper from 'cropperjs'
import ImageEditorLocale from './generatedLocale'
type Actions = {
@ -13,8 +14,12 @@ type Actions = {
cropWidescreenVertical: boolean
}
interface UppyCropperOptions extends Cropper.Options {
croppedCanvasOptions: Cropper.GetCroppedCanvasOptions
}
export interface ImageEditorOptions extends PluginOptions {
cropperOptions?: Record<string, unknown>
cropperOptions?: UppyCropperOptions
actions?: Actions
quality?: number
target?: PluginTarget

View file

@ -10,7 +10,6 @@ module.exports = class Instagram extends UIPlugin {
super(uppy, opts)
this.id = this.opts.id || 'Instagram'
Provider.initPlugin(this, opts)
this.title = this.opts.title || 'Instagram'
this.icon = () => (
<svg aria-hidden="true" focusable="false" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fillRule="evenodd">
@ -20,6 +19,14 @@ module.exports = class Instagram extends UIPlugin {
</svg>
)
this.defaultLocale = {
strings: {
pluginNameInstagram: 'Instagram',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameInstagram')
this.provider = new Provider(uppy, {
companionUrl: this.opts.companionUrl,
companionHeaders: this.opts.companionHeaders,

View file

@ -91,6 +91,14 @@ en_US.strings = {
pause: 'Pause',
paused: 'Paused',
pauseUpload: 'Pause upload',
pluginNameBox: 'Box',
pluginNameCamera: 'Camera',
pluginNameDropbox: 'Dropbox',
pluginNameFacebook: 'Facebook',
pluginNameGoogleDrive: 'Google Drive',
pluginNameInstagram: 'Instagram',
pluginNameOneDrive: 'OneDrive',
pluginNameZoom: 'Zoom',
poweredBy: 'Powered by %{uppy}',
processingXFiles: {
'0': 'Processing %{smart_count} file',

View file

@ -31,6 +31,14 @@ module.exports = class OneDrive extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameOneDrive: 'OneDrive',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameOneDrive')
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)
}

View file

@ -65,9 +65,7 @@ module.exports = class ScreenCapture extends UIPlugin {
this.opts = { ...defaultOptions, ...opts }
// i18n
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.i18nInit()
// uppy plugin class related
this.install = this.install.bind(this)

View file

@ -73,17 +73,6 @@ module.exports = class StatusBar extends UIPlugin {
this.install = this.install.bind(this)
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
getTotalSpeed (files) {
let totalSpeed = 0
files.forEach((file) => {

View file

@ -40,19 +40,6 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
if (this.opts.lazy && this.opts.waitForThumbnailsBeforeUpload) {
throw new Error('ThumbnailGenerator: The `lazy` and `waitForThumbnailsBeforeUpload` options are mutually exclusive. Please ensure at most one of them is set to `true`.')
}
this.i18nInit()
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
/**

View file

@ -82,18 +82,6 @@ module.exports = class Transloadit extends BasePlugin {
this.completedFiles = Object.create(null)
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
#getClientVersion () {
const list = [
`uppy-core:${this.uppy.constructor.VERSION}`,

View file

@ -65,18 +65,6 @@ module.exports = class Url extends UIPlugin {
})
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
getFileNameFromUrl (url) {
return url.substring(url.lastIndexOf('/') + 1)
}

View file

@ -61,7 +61,6 @@ module.exports = class Webcam extends UIPlugin {
// eslint-disable-next-line no-restricted-globals
this.protocol = location.protocol.match(/https/i) ? 'https' : 'http'
this.id = this.opts.id || 'Webcam'
this.title = this.opts.title || 'Camera'
this.type = 'acquirer'
this.capturedMediaFile = null
this.icon = () => (
@ -75,6 +74,7 @@ module.exports = class Webcam extends UIPlugin {
this.defaultLocale = {
strings: {
pluginNameCamera: 'Camera',
smile: 'Smile!',
takePicture: 'Take a picture',
startRecording: 'Begin video recording',
@ -109,12 +109,11 @@ module.exports = class Webcam extends UIPlugin {
}
this.opts = { ...defaultOptions, ...opts }
this.i18nInit()
this.title = this.i18n('pluginNameCamera')
this.install = this.install.bind(this)
this.setPluginState = this.setPluginState.bind(this)
this.render = this.render.bind(this)
// Camera controls
@ -154,15 +153,6 @@ module.exports = class Webcam extends UIPlugin {
...newOpts?.videoConstraints,
},
})
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.i18nArray = this.translator.translateArray.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
hasCameraCheck () {

View file

@ -119,8 +119,6 @@ module.exports = class XHRUpload extends BasePlugin {
this.opts = { ...defaultOptions, ...opts }
this.i18nInit()
this.handleUpload = this.handleUpload.bind(this)
// Simultaneous upload limiting is shared across all uploads with this plugin.
@ -137,17 +135,6 @@ module.exports = class XHRUpload extends BasePlugin {
this.uploaderEvents = Object.create(null)
}
setOptions (newOpts) {
super.setOptions(newOpts)
this.i18nInit()
}
i18nInit () {
this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
this.i18n = this.translator.translate.bind(this.translator)
this.setPluginState() // so that UI re-renders and we see the updated locale
}
getOptions (file) {
const overrides = this.uppy.getState().xhrUpload
const { headers } = this.opts

View file

@ -30,6 +30,14 @@ module.exports = class Zoom extends UIPlugin {
pluginId: this.id,
})
this.defaultLocale = {
strings: {
pluginNameZoom: 'Zoom',
},
}
this.i18nInit()
this.title = this.i18n('pluginNameZoom')
this.onFirstRender = this.onFirstRender.bind(this)
this.render = this.render.bind(this)
}

View file

@ -47,11 +47,11 @@ describe('Chaos monkey', function () {
return browser.execute(() => {
window.addLogMessage('Cancelling a file')
// prefer deleting a file that is uploading right now
var selector = Math.random() <= 0.7
const selector = Math.random() <= 0.7
? '.is-inprogress .uppy-Dashboard-Item-action--remove'
: '.uppy-Dashboard-Item-action--remove'
var buttons = document.querySelectorAll(selector)
var del = buttons[Math.floor(Math.random() * buttons.length)]
const buttons = document.querySelectorAll(selector)
const del = buttons[Math.floor(Math.random() * buttons.length)]
if (del) del.click()
})
}
@ -59,7 +59,7 @@ describe('Chaos monkey', function () {
function startUploadIfAnyWaitingFiles () {
return browser.execute(() => {
window.addLogMessage('Starting upload')
var start = document.querySelector('.uppy-StatusBar-actionBtn--upload')
const start = document.querySelector('.uppy-StatusBar-actionBtn--upload')
if (start) start.click()
})
}
@ -67,7 +67,7 @@ describe('Chaos monkey', function () {
function cancelAll () {
return browser.execute(() => {
window.addLogMessage('Cancelling everything')
var button = document.querySelector('.uppy-DashboardContent-back')
const button = document.querySelector('.uppy-DashboardContent-back')
if (button) button.click()
})
}

View file

@ -3,7 +3,7 @@ const Dashboard = require('@uppy/dashboard')
const Transloadit = require('@uppy/transloadit')
function initUppyTransloadit (transloaditKey) {
var uppyTransloadit = new Uppy({
const uppyTransloadit = new Uppy({
id: 'uppyTransloadit',
debug: true,
autoProceed: true,
@ -36,9 +36,9 @@ function initUppyTransloadit (transloaditKey) {
console.log('Result here ====>', stepName, result)
console.log('Cropped image url is here ====>', result.url)
var img = new Image()
const img = new Image()
img.onload = function () {
var result = document.createElement('div')
const result = document.createElement('div')
result.setAttribute('id', 'uppy-result')
result.textContent = 'ok'
document.body.appendChild(result)

View file

@ -13,18 +13,18 @@ function selectFakeFile (uppyID, name, type, b64) {
// https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
function base64toBlob (base64Data, contentType) {
contentType = contentType || ''
var sliceSize = 1024
var byteCharacters = atob(base64Data)
var bytesLength = byteCharacters.length
var slicesCount = Math.ceil(bytesLength / sliceSize)
var byteArrays = new Array(slicesCount)
const sliceSize = 1024
const byteCharacters = atob(base64Data)
const bytesLength = byteCharacters.length
const slicesCount = Math.ceil(bytesLength / sliceSize)
const byteArrays = new Array(slicesCount)
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize
var end = Math.min(begin + sliceSize, bytesLength)
for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
const begin = sliceIndex * sliceSize
const end = Math.min(begin + sliceSize, bytesLength)
var bytes = new Array(end - begin)
for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
const bytes = new Array(end - begin)
for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0)
}
byteArrays[sliceIndex] = new Uint8Array(bytes)
@ -32,7 +32,7 @@ function selectFakeFile (uppyID, name, type, b64) {
return new Blob(byteArrays, { type: contentType })
}
var blob = base64toBlob(b64, type)
const blob = base64toBlob(b64, type)
window[uppyID].addFile({
source: 'test',
@ -43,7 +43,7 @@ function selectFakeFile (uppyID, name, type, b64) {
}
function ensureInputVisible (selector) {
var input = document.querySelector(selector)
const input = document.querySelector(selector)
input.style = 'width: auto; height: auto; opacity: 1; z-index: 199'
input.removeAttribute('hidden')
input.removeAttribute('aria-hidden')

View file

@ -128,7 +128,7 @@ exports.config = {
* @param {Array<string>} specs List of spec file paths that are to be run
*/
before (capabilities, specs) {
var chai = require('chai')
const chai = require('chai')
global.expect = chai.expect
global.capabilities = capabilities
chai.Should()

View file

@ -1,4 +1,4 @@
var deepFreeze = require('deep-freeze')
const deepFreeze = require('deep-freeze')
/**
* Default store + deepFreeze on setState to make sure nothing is mutated accidentally

View file

@ -2,13 +2,13 @@
// We fire our own build-examples.js and tell it which example to build -
// that script then writes temporary js files
// which we return via the callback.
var exec = require('child_process').exec
var path = require('path')
var fs = require('fs')
var uuid = require('uuid')
const { exec } = require('child_process')
const path = require('path')
const fs = require('fs')
const uuid = require('uuid')
var webRoot = path.dirname(path.dirname(__dirname))
var browserifyScript = `${webRoot}/build-examples.js`
const webRoot = path.dirname(path.dirname(__dirname))
const browserifyScript = `${webRoot}/build-examples.js`
function parseExamplesBrowserify (data, options, callback) {
if (!data || !data.path) {
@ -20,9 +20,9 @@ function parseExamplesBrowserify (data, options, callback) {
}
// var slug = data.path.replace(/[^a-zA-Z0-9\_\.]/g, '-')
var slug = uuid.v4()
var tmpFile = `/tmp/${slug}.js`
var cmd = `node ${browserifyScript} ${data.path} ${tmpFile} --colors`
const slug = uuid.v4()
const tmpFile = `/tmp/${slug}.js`
const cmd = `node ${browserifyScript} ${data.path} ${tmpFile} --colors`
// hexo.log.i('hexo-renderer-uppyexamples: change detected in examples. running: ' + cmd);
exec(cmd, (err, stdout, stderr) => {
if (err) {

View file

@ -64,6 +64,7 @@ uppy.use(ImageEditor, {
background: false,
autoCropArea: 1,
responsive: true,
croppedCanvasOptions: {},
},
actions: {
revert: true,
@ -89,7 +90,10 @@ Quality of the resulting blob that will be saved in Uppy after editing/cropping.
### `cropperOptions`
Image Editor is using the excellent [Cropper.js](https://fengyuanchen.github.io/cropperjs/), and if youd like to fine tune the Cropper.js instance, you can pass options to it.
Image Editor is using the excellent [Cropper.js](https://fengyuanchen.github.io/cropperjs/).
`cropperOptions` will be directly passed to `Cropper` and therefor can expect the same values as documented
in their [README](https://github.com/fengyuanchen/cropperjs/blob/HEAD/README.md#options),
with the addition of `croppedCanvasOptions`, which will be passed to [`getCroppedCanvas`](https://github.com/fengyuanchen/cropperjs/blob/HEAD/README.md#getcroppedcanvasoptions).
### `actions`

View file

@ -1,9 +1,9 @@
(function () {
var each = [].forEach
var doc = document.documentElement
var body = document.body
let each = [].forEach
let doc = document.documentElement
let { body } = document
var isIndex = body.classList.contains('page-index')
let isIndex = body.classList.contains('page-index')
// On index page
if (isIndex) {
@ -15,29 +15,29 @@
function InnerPage () {
// var main = document.querySelector('.js-MainContent')
var menuButton = document.querySelector('.js-MenuBtn')
var header = document.querySelector('.js-MainHeader')
var menu = document.querySelector('.js-Sidebar')
var content = document.querySelector('.js-Content')
var transloaditBar = document.querySelector('.js-TransloaditBar')
let menuButton = document.querySelector('.js-MenuBtn')
let header = document.querySelector('.js-MainHeader')
let menu = document.querySelector('.js-Sidebar')
let content = document.querySelector('.js-Content')
let transloaditBar = document.querySelector('.js-TransloaditBar')
var animating = false
var allLinks = []
let animating = false
let allLinks = []
// // listen for scroll event to do positioning & highlights
// window.addEventListener('scroll', updateSidebar)
// window.addEventListener('resize', updateSidebar)
function makeSidebarTop () {
var headerHeight = header.offsetHeight
var transloaditBarHeight = 0
let headerHeight = header.offsetHeight
let transloaditBarHeight = 0
if (transloaditBar) {
transloaditBarHeight = transloaditBar.offsetHeight
}
if (window.matchMedia('(min-width: 1024px)').matches) {
var headerTopOffset = header.getBoundingClientRect().top
let headerTopOffset = header.getBoundingClientRect().top
menu.style.top = `${headerHeight + headerTopOffset}px`
} else {
menu.style.paddingTop = `${headerHeight + transloaditBarHeight + 20}px`
@ -50,8 +50,8 @@
window.addEventListener('resize', makeSidebarTop)
function updateSidebar () {
var top = (doc && doc.scrollTop) || body.scrollTop
var headerHeight = header.offsetHeight
let top = (doc && doc.scrollTop) || body.scrollTop
let headerHeight = header.offsetHeight
if (top > (headerHeight - 25)) {
// main.classList.add('fix-sidebar')
header.classList.add('fix-header')
@ -60,9 +60,9 @@
header.classList.remove('fix-header')
}
if (animating || !allLinks) return
var last
for (var i = 0; i < allLinks.length; i++) {
var link = allLinks[i]
let last
for (let i = 0; i < allLinks.length; i++) {
let link = allLinks[i]
if (link.offsetTop > top) {
if (!last) last = link
break
@ -76,8 +76,8 @@
}
function makeLink (h) {
var link = document.createElement('li')
var text = h.textContent.replace(/\(.*\)$/, '')
let link = document.createElement('li')
let text = h.textContent.replace(/\(.*\)$/, '')
// make sure the ids are link-able...
h.id = h.id
.replace(/\(.*\)$/, '')
@ -90,8 +90,8 @@
}
function collectH3s (h) {
var h3s = []
var next = h.nextSibling
let h3s = []
let next = h.nextSibling
while (next && next.tagName !== 'H2') {
if (next.tagName === 'H3') {
h3s.push(next)
@ -102,7 +102,7 @@
}
function makeSubLinks (h3s, small) {
var container = document.createElement('ul')
let container = document.createElement('ul')
if (small) {
container.className = 'menu-sub'
}
@ -113,8 +113,8 @@
}
function setActive (id) {
var previousActive = menu.querySelector('.section-link.active')
var currentActive = typeof id === 'string'
let previousActive = menu.querySelector('.section-link.active')
let currentActive = typeof id === 'string'
? menu.querySelector(`.section-link[href="#${id}"]`)
: id
if (currentActive !== previousActive) {
@ -127,7 +127,7 @@
if (link.getAttribute('data-scroll') === 'no') {
return
}
var wrapper = document.createElement('a')
let wrapper = document.createElement('a')
wrapper.href = `#${link.id}`
wrapper.setAttribute('data-scroll', '')
link.parentNode.insertBefore(wrapper, link)
@ -146,13 +146,13 @@
function initSubHeaders () {
// build sidebar
var currentPageAnchor = menu.querySelector('.sidebar-link.current')
var isDocs = content.classList.contains('docs')
let currentPageAnchor = menu.querySelector('.sidebar-link.current')
let isDocs = content.classList.contains('docs')
if (!isDocs) return
if (currentPageAnchor) {
var sectionContainer
let sectionContainer
// if (false && isAPI) {
// sectionContainer = document.querySelector('.menu-root')
@ -166,12 +166,12 @@
sectionContainer.className = 'menu-sub'
currentPageAnchor.parentNode.appendChild(sectionContainer)
var h2s = content.querySelectorAll('h2')
let h2s = content.querySelectorAll('h2')
if (h2s.length) {
each.call(h2s, (h) => {
sectionContainer.appendChild(makeLink(h))
var h3s = collectH3s(h)
let h3s = collectH3s(h)
allLinks.push(h)
allLinks.push.apply(allLinks, h3s)
if (h3s.length) {
@ -179,7 +179,7 @@
}
})
} else {
var h3s = content.querySelectorAll('h3')
let h3s = content.querySelectorAll('h3')
each.call(h3s, (h) => {
sectionContainer.appendChild(makeLink(h))
allLinks.push(h)
@ -215,7 +215,7 @@
window.addEventListener('resize', updateSidebar)
}
var isBlog = menu.classList.contains('is-blog')
let isBlog = menu.classList.contains('is-blog')
if (!isBlog) {
initSubHeaders()
}
@ -224,19 +224,19 @@
function IndexPage () {
// Tabs
window.addEventListener('load', () => {
var tabs = document.querySelectorAll('.Tabs-link')
let tabs = document.querySelectorAll('.Tabs-link')
function myTabClicks (tabClickEvent) {
for (var i = 0; i < tabs.length; i++) {
tabs[i].classList.remove('Tabs-link--active')
}
var clickedTab = tabClickEvent.currentTarget
let clickedTab = tabClickEvent.currentTarget
clickedTab.classList.add('Tabs-link--active')
tabClickEvent.preventDefault()
tabClickEvent.stopPropagation()
var myContentPanes = document.querySelectorAll('.TabPane')
let myContentPanes = document.querySelectorAll('.TabPane')
for (i = 0; i < myContentPanes.length; i++) {
myContentPanes[i].classList.remove('TabPane--active')
@ -244,24 +244,24 @@
// storing reference to event.currentTarget, otherwise we get
// all the children like SVGs, instead of our target — the link element
var anchorReference = tabClickEvent.currentTarget
var activePaneId = anchorReference.getAttribute('href')
var activePane = document.querySelector(activePaneId)
let anchorReference = tabClickEvent.currentTarget
let activePaneId = anchorReference.getAttribute('href')
let activePane = document.querySelector(activePaneId)
activePane.classList.add('TabPane--active')
}
for (var i = 0; i < tabs.length; i++) {
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener('click', myTabClicks)
}
})
var tagline = document.querySelector('.MainHeader-tagline')
var taglinePart = document.querySelector('.MainHeader-taglinePart')
var taglineList = document.querySelector('.MainHeader-taglineList')
var taglineCounter = taglineList.children.length
let tagline = document.querySelector('.MainHeader-tagline')
let taglinePart = document.querySelector('.MainHeader-taglinePart')
let taglineList = document.querySelector('.MainHeader-taglineList')
let taglineCounter = taglineList.children.length
function shuffleTaglines () {
for (var i = taglineList.children.length; i >= 0; i--) {
for (let i = taglineList.children.length; i >= 0; i--) {
taglineList.appendChild(taglineList.children[Math.random() * i | 0])
}
}
@ -269,7 +269,7 @@
function loopTaglines () {
taglineCounter--
if (taglineCounter >= 0) {
var taglineText = taglineList.children[taglineCounter].textContent
let taglineText = taglineList.children[taglineCounter].textContent
showTagline(taglineText)
return
}