1 | const preact = require('preact')
|
2 | const findDOMElement = require('@uppy/utils/lib/findDOMElement')
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | function debounce (fn) {
|
8 | let calling = null
|
9 | let latestArgs = null
|
10 | return (...args) => {
|
11 | latestArgs = args
|
12 | if (!calling) {
|
13 | calling = Promise.resolve().then(() => {
|
14 | calling = null
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | return fn(...latestArgs)
|
20 | })
|
21 | }
|
22 | return calling
|
23 | }
|
24 | }
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | module.exports = class Plugin {
|
36 | constructor (uppy, opts) {
|
37 | this.uppy = uppy
|
38 | this.opts = opts || {}
|
39 |
|
40 | this.update = this.update.bind(this)
|
41 | this.mount = this.mount.bind(this)
|
42 | this.install = this.install.bind(this)
|
43 | this.uninstall = this.uninstall.bind(this)
|
44 | }
|
45 |
|
46 | getPluginState () {
|
47 | const { plugins } = this.uppy.getState()
|
48 | return plugins[this.id] || {}
|
49 | }
|
50 |
|
51 | setPluginState (update) {
|
52 | const { plugins } = this.uppy.getState()
|
53 |
|
54 | this.uppy.setState({
|
55 | plugins: {
|
56 | ...plugins,
|
57 | [this.id]: {
|
58 | ...plugins[this.id],
|
59 | ...update,
|
60 | },
|
61 | },
|
62 | })
|
63 | }
|
64 |
|
65 | setOptions (newOpts) {
|
66 | this.opts = { ...this.opts, ...newOpts }
|
67 | this.setPluginState()
|
68 | }
|
69 |
|
70 | update (state) {
|
71 | if (typeof this.el === 'undefined') {
|
72 | return
|
73 | }
|
74 |
|
75 | if (this._updateUI) {
|
76 | this._updateUI(state)
|
77 | }
|
78 | }
|
79 |
|
80 |
|
81 | afterUpdate () {
|
82 |
|
83 | }
|
84 |
|
85 | |
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | onMount () {
|
92 |
|
93 | }
|
94 |
|
95 | |
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | mount (target, plugin) {
|
104 | const callerPluginName = plugin.id
|
105 |
|
106 | const targetElement = findDOMElement(target)
|
107 |
|
108 | if (targetElement) {
|
109 | this.isTargetDOMEl = true
|
110 |
|
111 |
|
112 | this.rerender = (state) => {
|
113 |
|
114 |
|
115 |
|
116 | if (!this.uppy.getPlugin(this.id)) return
|
117 | this.el = preact.render(this.render(state), targetElement, this.el)
|
118 | this.afterUpdate()
|
119 | }
|
120 | this._updateUI = debounce(this.rerender)
|
121 |
|
122 | this.uppy.log(`Installing ${callerPluginName} to a DOM element '${target}'`)
|
123 |
|
124 |
|
125 | if (this.opts.replaceTargetContent) {
|
126 | targetElement.innerHTML = ''
|
127 | }
|
128 |
|
129 | this.el = preact.render(this.render(this.uppy.getState()), targetElement)
|
130 |
|
131 | this.onMount()
|
132 | return this.el
|
133 | }
|
134 |
|
135 | let targetPlugin
|
136 | if (typeof target === 'object' && target instanceof Plugin) {
|
137 |
|
138 | targetPlugin = target
|
139 | } else if (typeof target === 'function') {
|
140 |
|
141 | const Target = target
|
142 |
|
143 | this.uppy.iteratePlugins((plugin) => {
|
144 | if (plugin instanceof Target) {
|
145 | targetPlugin = plugin
|
146 | return false
|
147 | }
|
148 | })
|
149 | }
|
150 |
|
151 | if (targetPlugin) {
|
152 | this.uppy.log(`Installing ${callerPluginName} to ${targetPlugin.id}`)
|
153 | this.parent = targetPlugin
|
154 | this.el = targetPlugin.addTarget(plugin)
|
155 |
|
156 | this.onMount()
|
157 | return this.el
|
158 | }
|
159 |
|
160 | this.uppy.log(`Not installing ${callerPluginName}`)
|
161 |
|
162 | let message = `Invalid target option given to ${callerPluginName}.`
|
163 | if (typeof target === 'function') {
|
164 | message += ' The given target is not a Plugin class. '
|
165 | + 'Please check that you\'re not specifying a React Component instead of a plugin. '
|
166 | + 'If you are using @uppy/* packages directly, make sure you have only 1 version of @uppy/core installed: '
|
167 | + 'run `npm ls @uppy/core` on the command line and verify that all the versions match and are deduped correctly.'
|
168 | } else {
|
169 | message += 'If you meant to target an HTML element, please make sure that the element exists. '
|
170 | + 'Check that the <script> tag initializing Uppy is right before the closing </body> tag at the end of the page. '
|
171 | + '(see https://github.com/transloadit/uppy/issues/1042)\n\n'
|
172 | + 'If you meant to target a plugin, please confirm that your `import` statements or `require` calls are correct.'
|
173 | }
|
174 | throw new Error(message)
|
175 | }
|
176 |
|
177 | render (state) {
|
178 | throw (new Error('Extend the render method to add your plugin to a DOM element'))
|
179 | }
|
180 |
|
181 | addTarget (plugin) {
|
182 | throw (new Error('Extend the addTarget method to add your plugin to another plugin\'s target'))
|
183 | }
|
184 |
|
185 | unmount () {
|
186 | if (this.isTargetDOMEl && this.el && this.el.parentNode) {
|
187 | this.el.parentNode.removeChild(this.el)
|
188 | }
|
189 | }
|
190 |
|
191 | install () {
|
192 |
|
193 | }
|
194 |
|
195 | uninstall () {
|
196 | this.unmount()
|
197 | }
|
198 | }
|