@ckeditor/ckeditor5-core 30.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +17 -0
- package/README.md +18 -0
- package/lang/contexts.json +8 -0
- package/lang/translations/af.po +41 -0
- package/lang/translations/ar.po +41 -0
- package/lang/translations/ast.po +41 -0
- package/lang/translations/az.po +41 -0
- package/lang/translations/bg.po +41 -0
- package/lang/translations/ca.po +41 -0
- package/lang/translations/cs.po +41 -0
- package/lang/translations/da.po +41 -0
- package/lang/translations/de-ch.po +41 -0
- package/lang/translations/de.po +41 -0
- package/lang/translations/el.po +41 -0
- package/lang/translations/en-au.po +41 -0
- package/lang/translations/en-gb.po +41 -0
- package/lang/translations/en.po +41 -0
- package/lang/translations/eo.po +41 -0
- package/lang/translations/es.po +41 -0
- package/lang/translations/et.po +41 -0
- package/lang/translations/eu.po +41 -0
- package/lang/translations/fa.po +41 -0
- package/lang/translations/fi.po +41 -0
- package/lang/translations/fr.po +41 -0
- package/lang/translations/gl.po +41 -0
- package/lang/translations/he.po +41 -0
- package/lang/translations/hi.po +41 -0
- package/lang/translations/hr.po +41 -0
- package/lang/translations/hu.po +41 -0
- package/lang/translations/id.po +41 -0
- package/lang/translations/it.po +41 -0
- package/lang/translations/ja.po +41 -0
- package/lang/translations/km.po +41 -0
- package/lang/translations/kn.po +41 -0
- package/lang/translations/ko.po +41 -0
- package/lang/translations/ku.po +41 -0
- package/lang/translations/lt.po +41 -0
- package/lang/translations/lv.po +41 -0
- package/lang/translations/nb.po +41 -0
- package/lang/translations/ne.po +41 -0
- package/lang/translations/nl.po +41 -0
- package/lang/translations/no.po +41 -0
- package/lang/translations/oc.po +41 -0
- package/lang/translations/pl.po +41 -0
- package/lang/translations/pt-br.po +41 -0
- package/lang/translations/pt.po +41 -0
- package/lang/translations/ro.po +41 -0
- package/lang/translations/ru.po +41 -0
- package/lang/translations/sk.po +41 -0
- package/lang/translations/sl.po +41 -0
- package/lang/translations/sq.po +41 -0
- package/lang/translations/sr-latn.po +41 -0
- package/lang/translations/sr.po +41 -0
- package/lang/translations/sv.po +41 -0
- package/lang/translations/th.po +41 -0
- package/lang/translations/tk.po +41 -0
- package/lang/translations/tr.po +41 -0
- package/lang/translations/tt.po +41 -0
- package/lang/translations/ug.po +41 -0
- package/lang/translations/uk.po +41 -0
- package/lang/translations/vi.po +41 -0
- package/lang/translations/zh-cn.po +41 -0
- package/lang/translations/zh.po +41 -0
- package/package.json +65 -0
- package/src/command.js +244 -0
- package/src/commandcollection.js +109 -0
- package/src/context.js +355 -0
- package/src/contextplugin.js +61 -0
- package/src/editingkeystrokehandler.js +72 -0
- package/src/editor/editor.js +448 -0
- package/src/editor/editorconfig.jsdoc +325 -0
- package/src/editor/editorui.js +275 -0
- package/src/editor/editorwithui.jsdoc +29 -0
- package/src/editor/utils/attachtoform.js +67 -0
- package/src/editor/utils/dataapimixin.js +81 -0
- package/src/editor/utils/elementapimixin.js +65 -0
- package/src/editor/utils/securesourceelement.js +49 -0
- package/src/index.js +95 -0
- package/src/multicommand.js +101 -0
- package/src/pendingactions.js +155 -0
- package/src/plugin.js +292 -0
- package/src/plugincollection.js +597 -0
- package/theme/icons/align-bottom.svg +1 -0
- package/theme/icons/align-center.svg +1 -0
- package/theme/icons/align-justify.svg +1 -0
- package/theme/icons/align-left.svg +1 -0
- package/theme/icons/align-middle.svg +1 -0
- package/theme/icons/align-right.svg +1 -0
- package/theme/icons/align-top.svg +1 -0
- package/theme/icons/cancel.svg +1 -0
- package/theme/icons/caption.svg +1 -0
- package/theme/icons/check.svg +1 -0
- package/theme/icons/cog.svg +1 -0
- package/theme/icons/eraser.svg +1 -0
- package/theme/icons/image.svg +1 -0
- package/theme/icons/low-vision.svg +1 -0
- package/theme/icons/object-center.svg +1 -0
- package/theme/icons/object-full-width.svg +1 -0
- package/theme/icons/object-inline-left.svg +1 -0
- package/theme/icons/object-inline-right.svg +1 -0
- package/theme/icons/object-inline.svg +1 -0
- package/theme/icons/object-left.svg +1 -0
- package/theme/icons/object-right.svg +1 -0
- package/theme/icons/object-size-full.svg +1 -0
- package/theme/icons/object-size-large.svg +1 -0
- package/theme/icons/object-size-medium.svg +1 -0
- package/theme/icons/object-size-small.svg +1 -0
- package/theme/icons/pencil.svg +1 -0
- package/theme/icons/pilcrow.svg +1 -0
- package/theme/icons/quote.svg +1 -0
- package/theme/icons/three-vertical-dots.svg +1 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @module core/plugincollection
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
11
|
+
import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
|
|
12
|
+
import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization.
|
|
16
|
+
*
|
|
17
|
+
* @mixes module:utils/emittermixin~EmitterMixin
|
|
18
|
+
*/
|
|
19
|
+
export default class PluginCollection {
|
|
20
|
+
/**
|
|
21
|
+
* Creates an instance of the plugin collection class.
|
|
22
|
+
* Allows loading and initializing plugins and their dependencies.
|
|
23
|
+
* Allows providing a list of already loaded plugins. These plugins will not be destroyed along with this collection.
|
|
24
|
+
*
|
|
25
|
+
* @param {module:core/editor/editor~Editor|module:core/context~Context} context
|
|
26
|
+
* @param {Array.<Function>} [availablePlugins] Plugins (constructors) which the collection will be able to use
|
|
27
|
+
* when {@link module:core/plugincollection~PluginCollection#init} is used with the plugin names (strings, instead of constructors).
|
|
28
|
+
* Usually, the editor will pass its built-in plugins to the collection so they can later be
|
|
29
|
+
* used in `config.plugins` or `config.removePlugins` by names.
|
|
30
|
+
* @param {Iterable.<Array>} contextPlugins A list of already initialized plugins represented by a
|
|
31
|
+
* `[ PluginConstructor, pluginInstance ]` pair.
|
|
32
|
+
*/
|
|
33
|
+
constructor( context, availablePlugins = [], contextPlugins = [] ) {
|
|
34
|
+
/**
|
|
35
|
+
* @protected
|
|
36
|
+
* @type {module:core/editor/editor~Editor|module:core/context~Context}
|
|
37
|
+
*/
|
|
38
|
+
this._context = context;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @protected
|
|
42
|
+
* @type {Map}
|
|
43
|
+
*/
|
|
44
|
+
this._plugins = new Map();
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A map of plugin constructors that can be retrieved by their names.
|
|
48
|
+
*
|
|
49
|
+
* @protected
|
|
50
|
+
* @type {Map.<String|Function,Function>}
|
|
51
|
+
*/
|
|
52
|
+
this._availablePlugins = new Map();
|
|
53
|
+
|
|
54
|
+
for ( const PluginConstructor of availablePlugins ) {
|
|
55
|
+
if ( PluginConstructor.pluginName ) {
|
|
56
|
+
this._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Map of {@link module:core/contextplugin~ContextPlugin context plugins} which can be retrieved by their constructors or instances.
|
|
62
|
+
*
|
|
63
|
+
* @protected
|
|
64
|
+
* @type {Map<Function,Function>}
|
|
65
|
+
*/
|
|
66
|
+
this._contextPlugins = new Map();
|
|
67
|
+
|
|
68
|
+
for ( const [ PluginConstructor, pluginInstance ] of contextPlugins ) {
|
|
69
|
+
this._contextPlugins.set( PluginConstructor, pluginInstance );
|
|
70
|
+
this._contextPlugins.set( pluginInstance, PluginConstructor );
|
|
71
|
+
|
|
72
|
+
// To make it possible to require a plugin by its name.
|
|
73
|
+
if ( PluginConstructor.pluginName ) {
|
|
74
|
+
this._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Iterable interface.
|
|
81
|
+
*
|
|
82
|
+
* Returns `[ PluginConstructor, pluginInstance ]` pairs.
|
|
83
|
+
*
|
|
84
|
+
* @returns {Iterable.<Array>}
|
|
85
|
+
*/
|
|
86
|
+
* [ Symbol.iterator ]() {
|
|
87
|
+
for ( const entry of this._plugins ) {
|
|
88
|
+
if ( typeof entry[ 0 ] == 'function' ) {
|
|
89
|
+
yield entry;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Gets the plugin instance by its constructor or name.
|
|
96
|
+
*
|
|
97
|
+
* // Check if 'Clipboard' plugin was loaded.
|
|
98
|
+
* if ( editor.plugins.has( 'ClipboardPipeline' ) ) {
|
|
99
|
+
* // Get clipboard plugin instance
|
|
100
|
+
* const clipboard = editor.plugins.get( 'ClipboardPipeline' );
|
|
101
|
+
*
|
|
102
|
+
* this.listenTo( clipboard, 'inputTransformation', ( evt, data ) => {
|
|
103
|
+
* // Do something on clipboard input.
|
|
104
|
+
* } );
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* **Note**: This method will throw an error if a plugin is not loaded. Use `{@link #has editor.plugins.has()}`
|
|
108
|
+
* to check if a plugin is available.
|
|
109
|
+
*
|
|
110
|
+
* @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.
|
|
111
|
+
* @returns {module:core/plugin~PluginInterface}
|
|
112
|
+
*/
|
|
113
|
+
get( key ) {
|
|
114
|
+
const plugin = this._plugins.get( key );
|
|
115
|
+
|
|
116
|
+
if ( !plugin ) {
|
|
117
|
+
let pluginName = key;
|
|
118
|
+
|
|
119
|
+
if ( typeof key == 'function' ) {
|
|
120
|
+
pluginName = key.pluginName || key.name;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The plugin is not loaded and could not be obtained.
|
|
125
|
+
*
|
|
126
|
+
* Plugin classes (constructors) need to be provided to the editor and must be loaded before they can be obtained from
|
|
127
|
+
* the plugin collection.
|
|
128
|
+
* This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}
|
|
129
|
+
* property.
|
|
130
|
+
*
|
|
131
|
+
* **Note**: You can use `{@link module:core/plugincollection~PluginCollection#has editor.plugins.has()}`
|
|
132
|
+
* to check if a plugin was loaded.
|
|
133
|
+
*
|
|
134
|
+
* @error plugincollection-plugin-not-loaded
|
|
135
|
+
* @param {String} plugin The name of the plugin which is not loaded.
|
|
136
|
+
*/
|
|
137
|
+
throw new CKEditorError( 'plugincollection-plugin-not-loaded', this._context, { plugin: pluginName } );
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return plugin;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Checks if a plugin is loaded.
|
|
145
|
+
*
|
|
146
|
+
* // Check if the 'Clipboard' plugin was loaded.
|
|
147
|
+
* if ( editor.plugins.has( 'ClipboardPipeline' ) ) {
|
|
148
|
+
* // Now use the clipboard plugin instance:
|
|
149
|
+
* const clipboard = editor.plugins.get( 'ClipboardPipeline' );
|
|
150
|
+
*
|
|
151
|
+
* // ...
|
|
152
|
+
* }
|
|
153
|
+
*
|
|
154
|
+
* @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.
|
|
155
|
+
* @returns {Boolean}
|
|
156
|
+
*/
|
|
157
|
+
has( key ) {
|
|
158
|
+
return this._plugins.has( key );
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Initializes a set of plugins and adds them to the collection.
|
|
163
|
+
*
|
|
164
|
+
* @param {Array.<Function|String>} plugins An array of {@link module:core/plugin~PluginInterface plugin constructors}
|
|
165
|
+
* or {@link module:core/plugin~PluginInterface.pluginName plugin names}.
|
|
166
|
+
* @param {Array.<String|Function>} [pluginsToRemove] Names of the plugins or plugin constructors
|
|
167
|
+
* that should not be loaded (despite being specified in the `plugins` array).
|
|
168
|
+
* @param {Array.<Function>} [pluginsSubstitutions] An array of {@link module:core/plugin~PluginInterface plugin constructors}
|
|
169
|
+
* that will be used to replace plugins of the same names that were passed in `plugins` or that are in their dependency tree.
|
|
170
|
+
* A useful option for replacing built-in plugins while creating tests (for mocking their APIs). Plugins that will be replaced
|
|
171
|
+
* must follow these rules:
|
|
172
|
+
* * The new plugin must be a class.
|
|
173
|
+
* * The new plugin must be named.
|
|
174
|
+
* * Both plugins must not depend on other plugins.
|
|
175
|
+
* @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which gets resolved once all plugins are loaded
|
|
176
|
+
* and available in the collection.
|
|
177
|
+
*/
|
|
178
|
+
init( plugins, pluginsToRemove = [], pluginsSubstitutions = [] ) {
|
|
179
|
+
// Plugin initialization procedure consists of 2 main steps:
|
|
180
|
+
// 1) collecting all available plugin constructors,
|
|
181
|
+
// 2) verification whether all required plugins can be instantiated.
|
|
182
|
+
//
|
|
183
|
+
// In the first step, all plugin constructors, available in the provided `plugins` array and inside
|
|
184
|
+
// plugin's dependencies (from the `Plugin.requires` array), are recursively collected and added to the existing
|
|
185
|
+
// `this._availablePlugins` map, but without any verification at the given moment. Performing the verification
|
|
186
|
+
// at this point (during the plugin constructor searching) would cause false errors to occur, that some plugin
|
|
187
|
+
// is missing but in fact it may be defined further in the array as the dependency of other plugin. After
|
|
188
|
+
// traversing the entire dependency tree, it will be checked if all required "top level" plugins are available.
|
|
189
|
+
//
|
|
190
|
+
// In the second step, the list of plugins that have not been explicitly removed is traversed to get all the
|
|
191
|
+
// plugin constructors to be instantiated in the correct order and to validate against some rules. Finally, if
|
|
192
|
+
// no plugin is missing and no other error has been found, they all will be instantiated.
|
|
193
|
+
const that = this;
|
|
194
|
+
const context = this._context;
|
|
195
|
+
|
|
196
|
+
findAvailablePluginConstructors( plugins );
|
|
197
|
+
|
|
198
|
+
validatePlugins( plugins );
|
|
199
|
+
|
|
200
|
+
const pluginsToLoad = plugins.filter( plugin => !isPluginRemoved( plugin, pluginsToRemove ) );
|
|
201
|
+
|
|
202
|
+
const pluginConstructors = [ ...getPluginConstructors( pluginsToLoad ) ];
|
|
203
|
+
|
|
204
|
+
substitutePlugins( pluginConstructors, pluginsSubstitutions );
|
|
205
|
+
|
|
206
|
+
const pluginInstances = loadPlugins( pluginConstructors );
|
|
207
|
+
|
|
208
|
+
return initPlugins( pluginInstances, 'init' )
|
|
209
|
+
.then( () => initPlugins( pluginInstances, 'afterInit' ) )
|
|
210
|
+
.then( () => pluginInstances );
|
|
211
|
+
|
|
212
|
+
function isPluginConstructor( plugin ) {
|
|
213
|
+
return typeof plugin === 'function';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isContextPlugin( plugin ) {
|
|
217
|
+
return isPluginConstructor( plugin ) && plugin.isContextPlugin;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function isPluginRemoved( plugin, pluginsToRemove ) {
|
|
221
|
+
return pluginsToRemove.some( removedPlugin => {
|
|
222
|
+
if ( removedPlugin === plugin ) {
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if ( getPluginName( plugin ) === removedPlugin ) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if ( getPluginName( removedPlugin ) === plugin ) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return false;
|
|
235
|
+
} );
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function getPluginName( plugin ) {
|
|
239
|
+
return isPluginConstructor( plugin ) ?
|
|
240
|
+
plugin.pluginName || plugin.name :
|
|
241
|
+
plugin;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function findAvailablePluginConstructors( plugins, processed = new Set() ) {
|
|
245
|
+
plugins.forEach( plugin => {
|
|
246
|
+
if ( !isPluginConstructor( plugin ) ) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if ( processed.has( plugin ) ) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
processed.add( plugin );
|
|
255
|
+
|
|
256
|
+
if ( plugin.pluginName && !that._availablePlugins.has( plugin.pluginName ) ) {
|
|
257
|
+
that._availablePlugins.set( plugin.pluginName, plugin );
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if ( plugin.requires ) {
|
|
261
|
+
findAvailablePluginConstructors( plugin.requires, processed );
|
|
262
|
+
}
|
|
263
|
+
} );
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function getPluginConstructors( plugins, processed = new Set() ) {
|
|
267
|
+
return plugins
|
|
268
|
+
.map( plugin => {
|
|
269
|
+
return isPluginConstructor( plugin ) ?
|
|
270
|
+
plugin :
|
|
271
|
+
that._availablePlugins.get( plugin );
|
|
272
|
+
} )
|
|
273
|
+
.reduce( ( result, plugin ) => {
|
|
274
|
+
if ( processed.has( plugin ) ) {
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
processed.add( plugin );
|
|
279
|
+
|
|
280
|
+
if ( plugin.requires ) {
|
|
281
|
+
validatePlugins( plugin.requires, plugin );
|
|
282
|
+
|
|
283
|
+
getPluginConstructors( plugin.requires, processed ).forEach( plugin => result.add( plugin ) );
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return result.add( plugin );
|
|
287
|
+
}, new Set() );
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function validatePlugins( plugins, parentPluginConstructor = null ) {
|
|
291
|
+
plugins
|
|
292
|
+
.map( plugin => {
|
|
293
|
+
return isPluginConstructor( plugin ) ?
|
|
294
|
+
plugin :
|
|
295
|
+
that._availablePlugins.get( plugin ) || plugin;
|
|
296
|
+
} )
|
|
297
|
+
.forEach( plugin => {
|
|
298
|
+
checkMissingPlugin( plugin, parentPluginConstructor );
|
|
299
|
+
checkContextPlugin( plugin, parentPluginConstructor );
|
|
300
|
+
checkRemovedPlugin( plugin, parentPluginConstructor );
|
|
301
|
+
} );
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function checkMissingPlugin( plugin, parentPluginConstructor ) {
|
|
305
|
+
if ( isPluginConstructor( plugin ) ) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if ( parentPluginConstructor ) {
|
|
310
|
+
/**
|
|
311
|
+
* A required "soft" dependency was not found on the plugin list.
|
|
312
|
+
*
|
|
313
|
+
* When configuring the editor, either prior to building (via
|
|
314
|
+
* {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}) or when
|
|
315
|
+
* creating a new instance of the editor (e.g. via
|
|
316
|
+
* {@link module:core/editor/editorconfig~EditorConfig#plugins `config.plugins`}), you need to provide
|
|
317
|
+
* some of the dependencies for other plugins that you used.
|
|
318
|
+
*
|
|
319
|
+
* This error is thrown when one of these dependencies was not provided. The name of the missing plugin
|
|
320
|
+
* can be found in `missingPlugin` and the plugin that required it in `requiredBy`.
|
|
321
|
+
*
|
|
322
|
+
* In order to resolve it, you need to import the missing plugin and add it to the
|
|
323
|
+
* current list of plugins (`Editor.builtinPlugins` or `config.plugins`/`config.extraPlugins`).
|
|
324
|
+
*
|
|
325
|
+
* Soft requirements were introduced in version 26.0.0. If you happen to stumble upon this error
|
|
326
|
+
* when upgrading to version 26.0.0, read also the
|
|
327
|
+
* {@glink builds/guides/migration/migration-to-26 Migration to 26.0.0} guide.
|
|
328
|
+
*
|
|
329
|
+
* @error plugincollection-soft-required
|
|
330
|
+
* @param {String} missingPlugin The name of the required plugin.
|
|
331
|
+
* @param {String} requiredBy The name of the plugin that requires the other plugin.
|
|
332
|
+
*/
|
|
333
|
+
throw new CKEditorError(
|
|
334
|
+
'plugincollection-soft-required',
|
|
335
|
+
context,
|
|
336
|
+
{ missingPlugin: plugin, requiredBy: getPluginName( parentPluginConstructor ) }
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* A plugin is not available and could not be loaded.
|
|
342
|
+
*
|
|
343
|
+
* Plugin classes (constructors) need to be provided to the editor before they can be loaded by name.
|
|
344
|
+
* This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}
|
|
345
|
+
* property.
|
|
346
|
+
*
|
|
347
|
+
* **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**, it means
|
|
348
|
+
* that you try to enable a plugin which was not included in that build. This may be due to a typo
|
|
349
|
+
* in the plugin name or simply because that plugin is not a part of this build. In the latter scenario,
|
|
350
|
+
* read more about {@glink builds/guides/development/custom-builds custom builds}.
|
|
351
|
+
*
|
|
352
|
+
* **If you see this warning when using one of the editor creators directly** (not a build), then it means
|
|
353
|
+
* that you tried loading plugins by name. However, unlike CKEditor 4, CKEditor 5 does not implement a "plugin loader".
|
|
354
|
+
* This means that CKEditor 5 does not know where to load the plugin modules from. Therefore, you need to
|
|
355
|
+
* provide each plugin through a reference (as a constructor function). Check out the examples in
|
|
356
|
+
* {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source "Building from source"}.
|
|
357
|
+
*
|
|
358
|
+
* @error plugincollection-plugin-not-found
|
|
359
|
+
* @param {String} plugin The name of the plugin which could not be loaded.
|
|
360
|
+
*/
|
|
361
|
+
throw new CKEditorError(
|
|
362
|
+
'plugincollection-plugin-not-found',
|
|
363
|
+
context,
|
|
364
|
+
{ plugin }
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function checkContextPlugin( plugin, parentPluginConstructor ) {
|
|
369
|
+
if ( !isContextPlugin( parentPluginConstructor ) ) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if ( isContextPlugin( plugin ) ) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* If a plugin is a context plugin, all plugins it requires should also be context plugins
|
|
379
|
+
* instead of plugins. In other words, if one plugin can be used in the context,
|
|
380
|
+
* all its requirements should also be ready to be used in the context. Note that the context
|
|
381
|
+
* provides only a part of the API provided by the editor. If one plugin needs a full
|
|
382
|
+
* editor API, all plugins which require it are considered as plugins that need a full
|
|
383
|
+
* editor API.
|
|
384
|
+
*
|
|
385
|
+
* @error plugincollection-context-required
|
|
386
|
+
* @param {String} plugin The name of the required plugin.
|
|
387
|
+
* @param {String} requiredBy The name of the parent plugin.
|
|
388
|
+
*/
|
|
389
|
+
throw new CKEditorError(
|
|
390
|
+
'plugincollection-context-required',
|
|
391
|
+
context,
|
|
392
|
+
{ plugin: getPluginName( plugin ), requiredBy: getPluginName( parentPluginConstructor ) }
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function checkRemovedPlugin( plugin, parentPluginConstructor ) {
|
|
397
|
+
if ( !parentPluginConstructor ) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if ( !isPluginRemoved( plugin, pluginsToRemove ) ) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Cannot load a plugin because one of its dependencies is listed in the `removePlugins` option.
|
|
407
|
+
*
|
|
408
|
+
* @error plugincollection-required
|
|
409
|
+
* @param {String} plugin The name of the required plugin.
|
|
410
|
+
* @param {String} requiredBy The name of the parent plugin.
|
|
411
|
+
*/
|
|
412
|
+
throw new CKEditorError(
|
|
413
|
+
'plugincollection-required',
|
|
414
|
+
context,
|
|
415
|
+
{ plugin: getPluginName( plugin ), requiredBy: getPluginName( parentPluginConstructor ) }
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function loadPlugins( pluginConstructors ) {
|
|
420
|
+
return pluginConstructors.map( PluginConstructor => {
|
|
421
|
+
const pluginInstance = that._contextPlugins.get( PluginConstructor ) || new PluginConstructor( context );
|
|
422
|
+
|
|
423
|
+
that._add( PluginConstructor, pluginInstance );
|
|
424
|
+
|
|
425
|
+
return pluginInstance;
|
|
426
|
+
} );
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function initPlugins( pluginInstances, method ) {
|
|
430
|
+
return pluginInstances.reduce( ( promise, plugin ) => {
|
|
431
|
+
if ( !plugin[ method ] ) {
|
|
432
|
+
return promise;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if ( that._contextPlugins.has( plugin ) ) {
|
|
436
|
+
return promise;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return promise.then( plugin[ method ].bind( plugin ) );
|
|
440
|
+
}, Promise.resolve() );
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Replaces plugin constructors with the specified set of plugins.
|
|
444
|
+
//
|
|
445
|
+
// @param {Array.<Function>} pluginConstructors
|
|
446
|
+
// @param {Array.<Function>} pluginsSubstitutions
|
|
447
|
+
function substitutePlugins( pluginConstructors, pluginsSubstitutions ) {
|
|
448
|
+
for ( const pluginItem of pluginsSubstitutions ) {
|
|
449
|
+
if ( typeof pluginItem != 'function' ) {
|
|
450
|
+
/**
|
|
451
|
+
* The plugin replacing an existing plugin must be a function.
|
|
452
|
+
*
|
|
453
|
+
* @error plugincollection-replace-plugin-invalid-type
|
|
454
|
+
*/
|
|
455
|
+
throw new CKEditorError( 'plugincollection-replace-plugin-invalid-type', null, { pluginItem } );
|
|
456
|
+
}
|
|
457
|
+
const pluginName = pluginItem.pluginName;
|
|
458
|
+
|
|
459
|
+
if ( !pluginName ) {
|
|
460
|
+
/**
|
|
461
|
+
* The plugin replacing an existing plugin must have a name.
|
|
462
|
+
*
|
|
463
|
+
* @error plugincollection-replace-plugin-missing-name
|
|
464
|
+
*/
|
|
465
|
+
throw new CKEditorError( 'plugincollection-replace-plugin-missing-name', null, { pluginItem } );
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if ( pluginItem.requires && pluginItem.requires.length ) {
|
|
469
|
+
/**
|
|
470
|
+
* The plugin replacing an existing plugin cannot depend on other plugins.
|
|
471
|
+
*
|
|
472
|
+
* @error plugincollection-plugin-for-replacing-cannot-have-dependencies
|
|
473
|
+
*/
|
|
474
|
+
throw new CKEditorError( 'plugincollection-plugin-for-replacing-cannot-have-dependencies', null, { pluginName } );
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const pluginToReplace = that._availablePlugins.get( pluginName );
|
|
478
|
+
|
|
479
|
+
if ( !pluginToReplace ) {
|
|
480
|
+
/**
|
|
481
|
+
* The replaced plugin does not exist in the
|
|
482
|
+
* {@link module:core/plugincollection~PluginCollection available plugins} collection.
|
|
483
|
+
*
|
|
484
|
+
* @error plugincollection-plugin-for-replacing-not-exist
|
|
485
|
+
*/
|
|
486
|
+
throw new CKEditorError( 'plugincollection-plugin-for-replacing-not-exist', null, { pluginName } );
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const indexInPluginConstructors = pluginConstructors.indexOf( pluginToReplace );
|
|
490
|
+
|
|
491
|
+
if ( indexInPluginConstructors === -1 ) {
|
|
492
|
+
// The Context feature can substitute plugins as well.
|
|
493
|
+
// It may happen that the editor will be created with the given context, where the plugin for substitute
|
|
494
|
+
// was already replaced. In such a case, we don't want to do it again.
|
|
495
|
+
if ( that._contextPlugins.has( pluginToReplace ) ) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* The replaced plugin will not be loaded so it cannot be replaced.
|
|
501
|
+
*
|
|
502
|
+
* @error plugincollection-plugin-for-replacing-not-loaded
|
|
503
|
+
*/
|
|
504
|
+
throw new CKEditorError( 'plugincollection-plugin-for-replacing-not-loaded', null, { pluginName } );
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if ( pluginToReplace.requires && pluginToReplace.requires.length ) {
|
|
508
|
+
/**
|
|
509
|
+
* The replaced plugin cannot depend on other plugins.
|
|
510
|
+
*
|
|
511
|
+
* @error plugincollection-replaced-plugin-cannot-have-dependencies
|
|
512
|
+
*/
|
|
513
|
+
throw new CKEditorError( 'plugincollection-replaced-plugin-cannot-have-dependencies', null, { pluginName } );
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
pluginConstructors.splice( indexInPluginConstructors, 1, pluginItem );
|
|
517
|
+
that._availablePlugins.set( pluginName, pluginItem );
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Destroys all loaded plugins.
|
|
524
|
+
*
|
|
525
|
+
* @returns {Promise}
|
|
526
|
+
*/
|
|
527
|
+
destroy() {
|
|
528
|
+
const promises = [];
|
|
529
|
+
|
|
530
|
+
for ( const [ , pluginInstance ] of this ) {
|
|
531
|
+
if ( typeof pluginInstance.destroy == 'function' && !this._contextPlugins.has( pluginInstance ) ) {
|
|
532
|
+
promises.push( pluginInstance.destroy() );
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return Promise.all( promises );
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Adds the plugin to the collection. Exposed mainly for testing purposes.
|
|
541
|
+
*
|
|
542
|
+
* @protected
|
|
543
|
+
* @param {Function} PluginConstructor The plugin constructor.
|
|
544
|
+
* @param {module:core/plugin~PluginInterface} plugin The instance of the plugin.
|
|
545
|
+
*/
|
|
546
|
+
_add( PluginConstructor, plugin ) {
|
|
547
|
+
this._plugins.set( PluginConstructor, plugin );
|
|
548
|
+
|
|
549
|
+
const pluginName = PluginConstructor.pluginName;
|
|
550
|
+
|
|
551
|
+
if ( !pluginName ) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if ( this._plugins.has( pluginName ) ) {
|
|
556
|
+
/**
|
|
557
|
+
* Two plugins with the same {@link module:core/plugin~PluginInterface.pluginName} were loaded.
|
|
558
|
+
* This will lead to runtime conflicts between these plugins.
|
|
559
|
+
*
|
|
560
|
+
* In practice, this warning usually means that new plugins were added to an existing CKEditor 5 build.
|
|
561
|
+
* Plugins should always be added to a source version of the editor (`@ckeditor/ckeditor5-editor-*`),
|
|
562
|
+
* not to an editor imported from one of the `@ckeditor/ckeditor5-build-*` packages.
|
|
563
|
+
*
|
|
564
|
+
* Check your import paths and the list of plugins passed to
|
|
565
|
+
* {@link module:core/editor/editor~Editor.create `Editor.create()`}
|
|
566
|
+
* or specified in {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}.
|
|
567
|
+
*
|
|
568
|
+
* The second option is that your `node_modules/` directory contains duplicated versions of the same
|
|
569
|
+
* CKEditor 5 packages. Normally, on clean installations, npm deduplicates packages in `node_modules/`, so
|
|
570
|
+
* it may be enough to call `rm -rf node_modules && npm i`. However, if you installed conflicting versions
|
|
571
|
+
* of some packages, their dependencies may need to be installed in more than one version which may lead to this
|
|
572
|
+
* warning.
|
|
573
|
+
*
|
|
574
|
+
* Technically speaking, this error occurs because after adding a plugin to an existing editor build
|
|
575
|
+
* the dependencies of this plugin are being duplicated.
|
|
576
|
+
* They are already built into that editor build and now get added for the second time as dependencies
|
|
577
|
+
* of the plugin you are installing.
|
|
578
|
+
*
|
|
579
|
+
* Read more about {@glink builds/guides/integration/installing-plugins installing plugins}.
|
|
580
|
+
*
|
|
581
|
+
* @error plugincollection-plugin-name-conflict
|
|
582
|
+
* @param {String} pluginName The duplicated plugin name.
|
|
583
|
+
* @param {Function} plugin1 The first plugin constructor.
|
|
584
|
+
* @param {Function} plugin2 The second plugin constructor.
|
|
585
|
+
*/
|
|
586
|
+
throw new CKEditorError(
|
|
587
|
+
'plugincollection-plugin-name-conflict',
|
|
588
|
+
null,
|
|
589
|
+
{ pluginName, plugin1: this._plugins.get( pluginName ).constructor, plugin2: PluginConstructor }
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
this._plugins.set( pluginName, plugin );
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
mix( PluginCollection, EmitterMixin );
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m9.239 13.938-2.88-1.663a.75.75 0 0 1 .75-1.3L9 12.067V4.75a.75.75 0 1 1 1.5 0v7.318l1.89-1.093a.75.75 0 0 1 .75 1.3l-2.879 1.663a.752.752 0 0 1-.511.187.752.752 0 0 1-.511-.187zM4.25 17a.75.75 0 1 1 0-1.5h10.5a.75.75 0 0 1 0 1.5H4.25z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.75 11.875a.752.752 0 0 1 .508.184l2.883 1.666a.75.75 0 0 1-.659 1.344l-.091-.044-1.892-1.093.001 4.318a.75.75 0 1 1-1.5 0v-4.317l-1.89 1.092a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .51-.187zM15.25 9a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM9.75.375a.75.75 0 0 1 .75.75v4.318l1.89-1.093.092-.045a.75.75 0 0 1 .659 1.344l-2.883 1.667a.752.752 0 0 1-.508.184.752.752 0 0 1-.511-.187L6.359 5.65a.75.75 0 0 1 .75-1.299L9 5.442V1.125a.75.75 0 0 1 .75-.75z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18 3.75a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 8a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 4a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75zm0-8a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m10.261 7.062 2.88 1.663a.75.75 0 0 1-.75 1.3L10.5 8.933v7.317a.75.75 0 1 1-1.5 0V8.932l-1.89 1.093a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .511-.187.752.752 0 0 1 .511.187zM15.25 4a.75.75 0 1 1 0 1.5H4.75a.75.75 0 0 1 0-1.5h10.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.591 10.177 4.243 4.242a1 1 0 0 1-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 0 1-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 0 1 5.934 4.52l4.243 4.243 4.242-4.243a1 1 0 1 1 1.415 1.414l-4.243 4.243z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 16h9a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/><path d="M17 1a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h14zm0 1.5H3a.5.5 0 0 0-.492.41L2.5 3v9a.5.5 0 0 0 .41.492L3 12.5h14a.5.5 0 0 0 .492-.41L17.5 12V3a.5.5 0 0 0-.41-.492L17 2.5z" fill-opacity=".6"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.972 16.615a.997.997 0 0 1-.744-.292l-4.596-4.596a1 1 0 1 1 1.414-1.414l3.926 3.926 9.937-9.937a1 1 0 0 1 1.414 1.415L7.717 16.323a.997.997 0 0 1-.745.292z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.333 2 .19 2.263a5.899 5.899 0 0 1 1.458.604L14.714 3.4 16.6 5.286l-1.467 1.733c.263.452.468.942.605 1.46L18 8.666v2.666l-2.263.19a5.899 5.899 0 0 1-.604 1.458l1.467 1.733-1.886 1.886-1.733-1.467a5.899 5.899 0 0 1-1.46.605L11.334 18H8.667l-.19-2.263a5.899 5.899 0 0 1-1.458-.604L5.286 16.6 3.4 14.714l1.467-1.733a5.899 5.899 0 0 1-.604-1.458L2 11.333V8.667l2.262-.189a5.899 5.899 0 0 1 .605-1.459L3.4 5.286 5.286 3.4l1.733 1.467a5.899 5.899 0 0 1 1.46-.605L8.666 2h2.666zM10 6.267a3.733 3.733 0 1 0 0 7.466 3.733 3.733 0 0 0 0-7.466z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m8.636 9.531-2.758 3.94a.5.5 0 0 0 .122.696l3.224 2.284h1.314l2.636-3.736L8.636 9.53zm.288 8.451L5.14 15.396a2 2 0 0 1-.491-2.786l6.673-9.53a2 2 0 0 1 2.785-.49l3.742 2.62a2 2 0 0 1 .491 2.785l-7.269 10.053-2.147-.066z"/><path d="M4 18h5.523v-1H4zm-2 0h1v-1H2z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 0 1 .87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 1 1 3.4-1.96 1.96 1.96 0 0 1-3.4 1.96z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.085 6.22 2.943 4.078a.75.75 0 1 1 1.06-1.06l2.592 2.59A11.094 11.094 0 0 1 10 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 0 1-.09 1.138.488.488 0 0 1-.15.084.75.75 0 0 1-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 0 0-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 0 1-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 0 0-.124.2c-.043.077-.08.158-.108.241a.534.534 0 0 0-.028.133.29.29 0 0 0 .008.072.927.927 0 0 0 .082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 0 1 1.108 5.992l.345.344.046-.018a9.313 9.313 0 0 0 2-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 0 0 .036-.12.29.29 0 0 0 .008-.072.492.492 0 0 0-.028-.133.999.999 0 0 0-.036-.096 2.165 2.165 0 0 0-.071-.145 2.917 2.917 0 0 0-.125-.2 3.592 3.592 0 0 0-.263-.335 5.444 5.444 0 0 0-.53-.523 7.955 7.955 0 0 0-1.054-.768 9.766 9.766 0 0 0-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21-.069.002a.508.508 0 0 0-.254.097.496.496 0 0 0-.104.679.498.498 0 0 0 .326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 0 1 2.017 1.513c.024.061.043.125.069.185a.494.494 0 0 0 .45.287h.008a.496.496 0 0 0 .35-.158.482.482 0 0 0 .13-.335.638.638 0 0 0-.048-.219 3.379 3.379 0 0 0-.36-.723 3.438 3.438 0 0 0-2.791-1.543l-.028-.001h-.013z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M15.003 7v5.5a1 1 0 0 1-1 1H5.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H6.5V12h6.997V7.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18 7v5.5a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1zm-1.505.5H3.504V12h12.991V7.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm11.5 9H18v1.5h-4.5zm0-3H18v1.5h-4.5zm0-3H18v1.5h-4.5zM2 15h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2zm0-9h5v1.5H2zm0 3h5v1.5H2zm0 3h5v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm11.5 9H18v1.5h-4.5zM2 15h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>
|