Completed
Branch master (2f299a)
by Ron
09:20
created

public/js/tinymce/plugins/help/plugin.js   F

Complexity

Total Complexity 101
Complexity/F 1.36

Size

Lines of Code 688
Function Count 74

Duplication

Duplicated Lines 129
Ratio 18.75 %

Importance

Changes 0
Metric Value
eloc 501
nc 32768
dl 129
loc 688
c 0
b 0
f 0
cc 0
rs 2
wmc 101
mnd 2
bc 84
fnc 74
bpm 1.1351
cpm 1.3648
noi 9

43 Functions

Rating   Name   Duplication   Size   Complexity  
A plugin.js ➔ fastIndex 0 3 1
A plugin.js ➔ makeRow 0 23 1
A plugin.js ➔ noop$$1 2 2 1
A plugin.js ➔ find 0 9 3
A plugin.js ➔ filter 0 10 3
A plugin.js ➔ installedPlugins 0 7 1
A plugin.js ➔ getPluginKeys 0 4 2
A plugin.js ➔ constant 0 5 1
A plugin.js ➔ call$$1 3 3 1
A plugin.js ➔ slowIndexOf 0 8 3
A plugin.js ➔ slowIndex 0 3 1
A me.getOrDie 3 3 1
A global.add(ꞌhelpꞌ) 0 5 1
B plugin.js ➔ some 62 62 1
A plugin.js ➔ supplant 0 10 1
A plugin.js ➔ availablePlugins 0 7 1
A plugin.js ➔ ??? 0 3 1
B help.constructor 129 686 4
A plugin.js ➔ none 0 3 1
A plugin.js ➔ open 0 18 1
A plugin.js ➔ eq 3 3 1
A me.toArray 3 3 1
A plugin.js ➔ makeTab 0 17 1
A plugin.js ➔ makeTab$1 0 14 1
A plugin.js ➔ contains 0 3 1
A plugin.js ➔ Plugin 0 2 1
A me.fold 3 3 1
B NONE.constructor 53 53 2
A plugin.js ➔ nul 3 3 1
A plugin.js ➔ register$1 0 12 1
A plugin.js ➔ id 3 3 1
B plugin.js ➔ typeOf 0 10 6
A plugin.js ➔ not 0 9 1
A plugin.js ➔ getVersion 0 3 2
A plugin.js ➔ curry 14 14 2
A plugin.js ➔ map 0 9 2
A plugin.js ➔ register 0 3 1
A plugin.js ➔ isType 0 5 1
A plugin.js ➔ from 0 3 3
A plugin.js ➔ undef 3 3 1
A plugin.js ➔ pluginLister 0 12 1
A plugin.js ➔ maybeUrlize 0 13 1
A rawIndexOf.constructor 0 10 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like public/js/tinymce/plugins/help/plugin.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
(function () {
2
var help = (function () {
0 ignored issues
show
Unused Code introduced by
The variable help seems to be never used. Consider removing it.
Loading history...
3
    'use strict';
4
5
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
0 ignored issues
show
Bug introduced by
The variable tinymce seems to be never declared. If this is a global, consider adding a /** global: tinymce */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
7
    var constant = function (value) {
8
      return function () {
9
        return value;
10
      };
11
    };
12 View Code Duplication
    function curry(fn) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
13
      var initialArgs = [];
14
      for (var _i = 1; _i < arguments.length; _i++) {
15
        initialArgs[_i - 1] = arguments[_i];
16
      }
17
      return function () {
18
        var restArgs = [];
19
        for (var _i = 0; _i < arguments.length; _i++) {
20
          restArgs[_i] = arguments[_i];
21
        }
22
        var all = initialArgs.concat(restArgs);
23
        return fn.apply(null, all);
24
      };
25
    }
26
    var not = function (f) {
27
      return function () {
28
        var args = [];
29
        for (var _i = 0; _i < arguments.length; _i++) {
30
          args[_i] = arguments[_i];
31
        }
32
        return !f.apply(null, args);
33
      };
34
    };
35
    var never = constant(false);
36
    var always = constant(true);
37
38
    var never$1 = never;
39
    var always$1 = always;
40
    var none = function () {
41
      return NONE;
42
    };
43 View Code Duplication
    var NONE = function () {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
44
      var eq = function (o) {
45
        return o.isNone();
46
      };
47
      var call$$1 = function (thunk) {
48
        return thunk();
49
      };
50
      var id = function (n) {
51
        return n;
52
      };
53
      var noop$$1 = function () {
54
      };
55
      var nul = function () {
56
        return null;
57
      };
58
      var undef = function () {
59
        return undefined;
60
      };
61
      var me = {
62
        fold: function (n, s) {
0 ignored issues
show
Unused Code introduced by
The parameter s is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
63
          return n();
64
        },
65
        is: never$1,
66
        isSome: never$1,
67
        isNone: always$1,
68
        getOr: id,
69
        getOrThunk: call$$1,
70
        getOrDie: function (msg) {
71
          throw new Error(msg || 'error: getOrDie called on none.');
72
        },
73
        getOrNull: nul,
74
        getOrUndefined: undef,
75
        or: id,
76
        orThunk: call$$1,
77
        map: none,
78
        ap: none,
79
        each: noop$$1,
80
        bind: none,
81
        flatten: none,
82
        exists: never$1,
83
        forall: always$1,
84
        filter: none,
85
        equals: eq,
86
        equals_: eq,
87
        toArray: function () {
88
          return [];
89
        },
90
        toString: constant('none()')
91
      };
92
      if (Object.freeze)
93
        Object.freeze(me);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
94
      return me;
95
    }();
96 View Code Duplication
    var some = function (a) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
97
      var constant_a = function () {
98
        return a;
99
      };
100
      var self = function () {
101
        return me;
102
      };
103
      var map = function (f) {
104
        return some(f(a));
105
      };
106
      var bind = function (f) {
107
        return f(a);
108
      };
109
      var me = {
110
        fold: function (n, s) {
111
          return s(a);
112
        },
113
        is: function (v) {
114
          return a === v;
115
        },
116
        isSome: always$1,
117
        isNone: never$1,
118
        getOr: constant_a,
119
        getOrThunk: constant_a,
120
        getOrDie: constant_a,
121
        getOrNull: constant_a,
122
        getOrUndefined: constant_a,
123
        or: self,
124
        orThunk: self,
125
        map: map,
126
        ap: function (optfab) {
127
          return optfab.fold(none, function (fab) {
128
            return some(fab(a));
129
          });
130
        },
131
        each: function (f) {
132
          f(a);
133
        },
134
        bind: bind,
135
        flatten: constant_a,
136
        exists: bind,
137
        forall: bind,
138
        filter: function (f) {
139
          return f(a) ? me : NONE;
140
        },
141
        equals: function (o) {
142
          return o.is(a);
143
        },
144
        equals_: function (o, elementEq) {
145
          return o.fold(never$1, function (b) {
146
            return elementEq(a, b);
147
          });
148
        },
149
        toArray: function () {
150
          return [a];
151
        },
152
        toString: function () {
153
          return 'some(' + a + ')';
154
        }
155
      };
156
      return me;
157
    };
158
    var from = function (value) {
159
      return value === null || value === undefined ? NONE : some(value);
160
    };
161
    var Option = {
162
      some: some,
163
      none: none,
164
      from: from
165
    };
166
167
    var typeOf = function (x) {
168
      if (x === null)
169
        return 'null';
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
170
      var t = typeof x;
171
      if (t === 'object' && Array.prototype.isPrototypeOf(x))
172
        return 'array';
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
173
      if (t === 'object' && String.prototype.isPrototypeOf(x))
174
        return 'string';
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
175
      return t;
176
    };
177
    var isType = function (type) {
178
      return function (value) {
179
        return typeOf(value) === type;
180
      };
181
    };
182
    var isFunction = isType('function');
183
184
    var rawIndexOf = function () {
185
      var pIndexOf = Array.prototype.indexOf;
186
      var fastIndex = function (xs, x) {
187
        return pIndexOf.call(xs, x);
188
      };
189
      var slowIndex = function (xs, x) {
190
        return slowIndexOf(xs, x);
191
      };
192
      return pIndexOf === undefined ? slowIndex : fastIndex;
193
    }();
194
    var contains = function (xs, x) {
195
      return rawIndexOf(xs, x) > -1;
196
    };
197
    var map = function (xs, f) {
198
      var len = xs.length;
199
      var r = new Array(len);
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
200
      for (var i = 0; i < len; i++) {
201
        var x = xs[i];
202
        r[i] = f(x, i, xs);
203
      }
204
      return r;
205
    };
206
    var filter = function (xs, pred) {
207
      var r = [];
208
      for (var i = 0, len = xs.length; i < len; i++) {
209
        var x = xs[i];
210
        if (pred(x, i, xs)) {
211
          r.push(x);
212
        }
213
      }
214
      return r;
215
    };
216
    var find = function (xs, pred) {
217
      for (var i = 0, len = xs.length; i < len; i++) {
218
        var x = xs[i];
219
        if (pred(x, i, xs)) {
220
          return Option.some(x);
221
        }
222
      }
223
      return Option.none();
224
    };
225
    var slowIndexOf = function (xs, x) {
226
      for (var i = 0, len = xs.length; i < len; ++i) {
227
        if (xs[i] === x) {
228
          return i;
229
        }
230
      }
231
      return -1;
232
    };
233
    var slice = Array.prototype.slice;
234
    var from$1 = isFunction(Array.from) ? Array.from : function (x) {
0 ignored issues
show
Unused Code introduced by
The variable from$1 seems to be never used. Consider removing it.
Loading history...
235
      return slice.call(x);
236
    };
237
238
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.I18n');
239
240
    var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
241
242
    var meta = global$2.mac ? '\u2318' : 'Ctrl';
243
    var access = global$2.mac ? 'Ctrl + Alt' : 'Shift + Alt';
244
    var shortcuts = [
245
      {
246
        shortcut: meta + ' + B',
247
        action: 'Bold'
248
      },
249
      {
250
        shortcut: meta + ' + I',
251
        action: 'Italic'
252
      },
253
      {
254
        shortcut: meta + ' + U',
255
        action: 'Underline'
256
      },
257
      {
258
        shortcut: meta + ' + A',
259
        action: 'Select all'
260
      },
261
      {
262
        shortcut: meta + ' + Y or ' + meta + ' + Shift + Z',
263
        action: 'Redo'
264
      },
265
      {
266
        shortcut: meta + ' + Z',
267
        action: 'Undo'
268
      },
269
      {
270
        shortcut: access + ' + 1',
271
        action: 'Header 1'
272
      },
273
      {
274
        shortcut: access + ' + 2',
275
        action: 'Header 2'
276
      },
277
      {
278
        shortcut: access + ' + 3',
279
        action: 'Header 3'
280
      },
281
      {
282
        shortcut: access + ' + 4',
283
        action: 'Header 4'
284
      },
285
      {
286
        shortcut: access + ' + 5',
287
        action: 'Header 5'
288
      },
289
      {
290
        shortcut: access + ' + 6',
291
        action: 'Header 6'
292
      },
293
      {
294
        shortcut: access + ' + 7',
295
        action: 'Paragraph'
296
      },
297
      {
298
        shortcut: access + ' + 8',
299
        action: 'Div'
300
      },
301
      {
302
        shortcut: access + ' + 9',
303
        action: 'Address'
304
      },
305
      {
306
        shortcut: 'Alt + F9',
307
        action: 'Focus to menubar'
308
      },
309
      {
310
        shortcut: 'Alt + F10',
311
        action: 'Focus to toolbar'
312
      },
313
      {
314
        shortcut: 'Alt + F11',
315
        action: 'Focus to element path'
316
      },
317
      {
318
        shortcut: 'Ctrl + F9',
319
        action: 'Focus to contextual toolbar'
320
      },
321
      {
322
        shortcut: meta + ' + K',
323
        action: 'Insert link (if link plugin activated)'
324
      },
325
      {
326
        shortcut: meta + ' + S',
327
        action: 'Save (if save plugin activated)'
328
      },
329
      {
330
        shortcut: meta + ' + F',
331
        action: 'Find (if searchreplace plugin activated)'
332
      }
333
    ];
334
    var KeyboardShortcuts = { shortcuts: shortcuts };
335
336
    var makeTab = function () {
337
      var makeAriaLabel = function (shortcut) {
338
        return 'aria-label="Action: ' + shortcut.action + ', Shortcut: ' + shortcut.shortcut.replace(/Ctrl/g, 'Control') + '"';
339
      };
340
      var shortcutLisString = map(KeyboardShortcuts.shortcuts, function (shortcut) {
341
        return '<tr data-mce-tabstop="1" tabindex="-1" ' + makeAriaLabel(shortcut) + '>' + '<td>' + global$1.translate(shortcut.action) + '</td>' + '<td>' + shortcut.shortcut + '</td>' + '</tr>';
342
      }).join('');
343
      return {
344
        title: 'Handy Shortcuts',
345
        type: 'container',
346
        style: 'overflow-y: auto; overflow-x: hidden; max-height: 250px',
347
        items: [{
348
            type: 'container',
349
            html: '<div>' + '<table class="mce-table-striped">' + '<thead>' + '<th>' + global$1.translate('Action') + '</th>' + '<th>' + global$1.translate('Shortcut') + '</th>' + '</thead>' + shortcutLisString + '</table>' + '</div>'
350
          }]
351
      };
352
    };
353
    var KeyboardShortcutsTab = { makeTab: makeTab };
354
355
    var keys = Object.keys;
356
357
    var supplant = function (str, obj) {
358
      var isStringOrNumber = function (a) {
359
        var t = typeof a;
360
        return t === 'string' || t === 'number';
361
      };
362
      return str.replace(/\$\{([^{}]*)\}/g, function (fullMatch, key) {
363
        var value = obj[key];
364
        return isStringOrNumber(value) ? value.toString() : fullMatch;
365
      });
366
    };
367
368
    var urls = [
369
      {
370
        key: 'advlist',
371
        name: 'Advanced List'
372
      },
373
      {
374
        key: 'anchor',
375
        name: 'Anchor'
376
      },
377
      {
378
        key: 'autolink',
379
        name: 'Autolink'
380
      },
381
      {
382
        key: 'autoresize',
383
        name: 'Autoresize'
384
      },
385
      {
386
        key: 'autosave',
387
        name: 'Autosave'
388
      },
389
      {
390
        key: 'bbcode',
391
        name: 'BBCode'
392
      },
393
      {
394
        key: 'charmap',
395
        name: 'Character Map'
396
      },
397
      {
398
        key: 'code',
399
        name: 'Code'
400
      },
401
      {
402
        key: 'codesample',
403
        name: 'Code Sample'
404
      },
405
      {
406
        key: 'colorpicker',
407
        name: 'Color Picker'
408
      },
409
      {
410
        key: 'compat3x',
411
        name: '3.x Compatibility'
412
      },
413
      {
414
        key: 'contextmenu',
415
        name: 'Context Menu'
416
      },
417
      {
418
        key: 'directionality',
419
        name: 'Directionality'
420
      },
421
      {
422
        key: 'emoticons',
423
        name: 'Emoticons'
424
      },
425
      {
426
        key: 'fullpage',
427
        name: 'Full Page'
428
      },
429
      {
430
        key: 'fullscreen',
431
        name: 'Full Screen'
432
      },
433
      {
434
        key: 'help',
435
        name: 'Help'
436
      },
437
      {
438
        key: 'hr',
439
        name: 'Horizontal Rule'
440
      },
441
      {
442
        key: 'image',
443
        name: 'Image'
444
      },
445
      {
446
        key: 'imagetools',
447
        name: 'Image Tools'
448
      },
449
      {
450
        key: 'importcss',
451
        name: 'Import CSS'
452
      },
453
      {
454
        key: 'insertdatetime',
455
        name: 'Insert Date/Time'
456
      },
457
      {
458
        key: 'legacyoutput',
459
        name: 'Legacy Output'
460
      },
461
      {
462
        key: 'link',
463
        name: 'Link'
464
      },
465
      {
466
        key: 'lists',
467
        name: 'Lists'
468
      },
469
      {
470
        key: 'media',
471
        name: 'Media'
472
      },
473
      {
474
        key: 'nonbreaking',
475
        name: 'Nonbreaking'
476
      },
477
      {
478
        key: 'noneditable',
479
        name: 'Noneditable'
480
      },
481
      {
482
        key: 'pagebreak',
483
        name: 'Page Break'
484
      },
485
      {
486
        key: 'paste',
487
        name: 'Paste'
488
      },
489
      {
490
        key: 'preview',
491
        name: 'Preview'
492
      },
493
      {
494
        key: 'print',
495
        name: 'Print'
496
      },
497
      {
498
        key: 'save',
499
        name: 'Save'
500
      },
501
      {
502
        key: 'searchreplace',
503
        name: 'Search and Replace'
504
      },
505
      {
506
        key: 'spellchecker',
507
        name: 'Spell Checker'
508
      },
509
      {
510
        key: 'tabfocus',
511
        name: 'Tab Focus'
512
      },
513
      {
514
        key: 'table',
515
        name: 'Table'
516
      },
517
      {
518
        key: 'template',
519
        name: 'Template'
520
      },
521
      {
522
        key: 'textcolor',
523
        name: 'Text Color'
524
      },
525
      {
526
        key: 'textpattern',
527
        name: 'Text Pattern'
528
      },
529
      {
530
        key: 'toc',
531
        name: 'Table of Contents'
532
      },
533
      {
534
        key: 'visualblocks',
535
        name: 'Visual Blocks'
536
      },
537
      {
538
        key: 'visualchars',
539
        name: 'Visual Characters'
540
      },
541
      {
542
        key: 'wordcount',
543
        name: 'Word Count'
544
      }
545
    ];
546
    var PluginUrls = { urls: urls };
547
548
    var makeLink = curry(supplant, '<a href="${url}" target="_blank" rel="noopener">${name}</a>');
549
    var maybeUrlize = function (editor, key) {
550
      return find(PluginUrls.urls, function (x) {
551
        return x.key === key;
552
      }).fold(function () {
553
        var getMetadata = editor.plugins[key].getMetadata;
554
        return typeof getMetadata === 'function' ? makeLink(getMetadata()) : key;
555
      }, function (x) {
556
        return makeLink({
557
          name: x.name,
558
          url: 'https://www.tinymce.com/docs/plugins/' + x.key
559
        });
560
      });
561
    };
562
    var getPluginKeys = function (editor) {
563
      var keys$$1 = keys(editor.plugins);
564
      return editor.settings.forced_plugins === undefined ? keys$$1 : filter(keys$$1, not(curry(contains, editor.settings.forced_plugins)));
565
    };
566
    var pluginLister = function (editor) {
567
      var pluginKeys = getPluginKeys(editor);
568
      var pluginLis = map(pluginKeys, function (key) {
569
        return '<li>' + maybeUrlize(editor, key) + '</li>';
570
      });
571
      var count = pluginLis.length;
572
      var pluginsString = pluginLis.join('');
573
      return '<p><b>' + global$1.translate([
574
        'Plugins installed ({0}):',
575
        count
576
      ]) + '</b></p>' + '<ul>' + pluginsString + '</ul>';
577
    };
578
    var installedPlugins = function (editor) {
579
      return {
580
        type: 'container',
581
        html: '<div style="overflow-y: auto; overflow-x: hidden; max-height: 230px; height: 230px;" data-mce-tabstop="1" tabindex="-1">' + pluginLister(editor) + '</div>',
582
        flex: 1
583
      };
584
    };
585
    var availablePlugins = function () {
586
      return {
587
        type: 'container',
588
        html: '<div style="padding: 10px; background: #e3e7f4; height: 100%;" data-mce-tabstop="1" tabindex="-1">' + '<p><b>' + global$1.translate('Premium plugins:') + '</b></p>' + '<ul>' + '<li>PowerPaste</li>' + '<li>Spell Checker Pro</li>' + '<li>Accessibility Checker</li>' + '<li>Advanced Code Editor</li>' + '<li>Enhanced Media Embed</li>' + '<li>Link Checker</li>' + '</ul><br />' + '<p style="float: right;"><a href="https://www.tinymce.com/pricing/?utm_campaign=editor_referral&utm_medium=help_dialog&utm_source=tinymce" target="_blank">' + global$1.translate('Learn more...') + '</a></p>' + '</div>',
589
        flex: 1
590
      };
591
    };
592
    var makeTab$1 = function (editor) {
593
      return {
594
        title: 'Plugins',
595
        type: 'container',
596
        style: 'overflow-y: auto; overflow-x: hidden;',
597
        layout: 'flex',
598
        padding: 10,
599
        spacing: 10,
600
        items: [
601
          installedPlugins(editor),
602
          availablePlugins()
603
        ]
604
      };
605
    };
606
    var PluginsTab = { makeTab: makeTab$1 };
607
608
    var global$3 = tinymce.util.Tools.resolve('tinymce.EditorManager');
609
610
    var getVersion = function (major, minor) {
611
      return major.indexOf('@') === 0 ? 'X.X.X' : major + '.' + minor;
612
    };
613
    var makeRow = function () {
614
      var version = getVersion(global$3.majorVersion, global$3.minorVersion);
615
      var changeLogLink = '<a href="https://www.tinymce.com/docs/changelog/?utm_campaign=editor_referral&utm_medium=help_dialog&utm_source=tinymce" target="_blank">TinyMCE ' + version + '</a>';
616
      return [
617
        {
618
          type: 'label',
619
          html: global$1.translate([
620
            'You are using {0}',
621
            changeLogLink
622
          ])
623
        },
624
        {
625
          type: 'spacer',
626
          flex: 1
627
        },
628
        {
629
          text: 'Close',
630
          onclick: function () {
631
            this.parent().parent().close();
632
          }
633
        }
634
      ];
635
    };
636
    var ButtonsRow = { makeRow: makeRow };
637
638
    var open = function (editor, pluginUrl) {
639
      return function () {
640
        editor.windowManager.open({
641
          title: 'Help',
642
          bodyType: 'tabpanel',
643
          layout: 'flex',
644
          body: [
645
            KeyboardShortcutsTab.makeTab(),
646
            PluginsTab.makeTab(editor)
647
          ],
648
          buttons: ButtonsRow.makeRow(),
649
          onPostRender: function () {
650
            var title = this.getEl('title');
651
            title.innerHTML = '<img src="' + pluginUrl + '/img/logo.png" alt="TinyMCE Logo" style="display: inline-block; width: 200px; height: 50px">';
652
          }
653
        });
654
      };
655
    };
656
    var Dialog = { open: open };
657
658
    var register = function (editor, pluginUrl) {
659
      editor.addCommand('mceHelp', Dialog.open(editor, pluginUrl));
660
    };
661
    var Commands = { register: register };
662
663
    var register$1 = function (editor, pluginUrl) {
664
      editor.addButton('help', {
665
        icon: 'help',
666
        onclick: Dialog.open(editor, pluginUrl)
667
      });
668
      editor.addMenuItem('help', {
669
        text: 'Help',
670
        icon: 'help',
671
        context: 'help',
672
        onclick: Dialog.open(editor, pluginUrl)
673
      });
674
    };
675
    var Buttons = { register: register$1 };
676
677
    global.add('help', function (editor, pluginUrl) {
678
      Buttons.register(editor, pluginUrl);
679
      Commands.register(editor, pluginUrl);
680
      editor.shortcuts.add('Alt+0', 'Open help dialog', 'mceHelp');
681
    });
682
    function Plugin () {
683
    }
684
685
    return Plugin;
686
687
}());
688
})();
689