Completed
Branch master (30706c)
by Ron
57:09 queued 06:53
created

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

Complexity

Total Complexity 141
Complexity/F 1.5

Size

Lines of Code 594
Function Count 94

Duplication

Duplicated Lines 115
Ratio 19.36 %

Importance

Changes 0
Metric Value
eloc 423
c 0
b 0
f 0
dl 115
loc 594
rs 2
wmc 141
mnd 47
bc 47
fnc 94
bpm 0.5
cpm 1.5
noi 18

1 Function

Rating   Name   Duplication   Size   Complexity  
F plugin.js ➔ Plugin 0 2 141

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/textpattern/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 textpattern = (function () {
0 ignored issues
show
Unused Code introduced by
The variable textpattern seems to be never used. Consider removing it.
Loading history...
3
    'use strict';
4
5
    var Cell = function (initial) {
6
      var value = initial;
7
      var get = function () {
8
        return value;
9
      };
10
      var set = function (v) {
11
        value = v;
12
      };
13
      var clone = function () {
14
        return Cell(get());
15
      };
16
      return {
17
        get: get,
18
        set: set,
19
        clone: clone
20
      };
21
    };
22
23
    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...
24
25
    var constant = function (value) {
26
      return function () {
27
        return value;
28
      };
29
    };
30
    var never = constant(false);
31
    var always = constant(true);
32
33
    var never$1 = never;
34
    var always$1 = always;
35
    var none = function () {
36
      return NONE;
37
    };
38 View Code Duplication
    var NONE = function () {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
39
      var eq = function (o) {
40
        return o.isNone();
41
      };
42
      var call$$1 = function (thunk) {
43
        return thunk();
44
      };
45
      var id = function (n) {
46
        return n;
47
      };
48
      var noop$$1 = function () {
49
      };
50
      var nul = function () {
51
        return null;
52
      };
53
      var undef = function () {
54
        return undefined;
55
      };
56
      var me = {
57
        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...
58
          return n();
59
        },
60
        is: never$1,
61
        isSome: never$1,
62
        isNone: always$1,
63
        getOr: id,
64
        getOrThunk: call$$1,
65
        getOrDie: function (msg) {
66
          throw new Error(msg || 'error: getOrDie called on none.');
67
        },
68
        getOrNull: nul,
69
        getOrUndefined: undef,
70
        or: id,
71
        orThunk: call$$1,
72
        map: none,
73
        ap: none,
74
        each: noop$$1,
75
        bind: none,
76
        flatten: none,
77
        exists: never$1,
78
        forall: always$1,
79
        filter: none,
80
        equals: eq,
81
        equals_: eq,
82
        toArray: function () {
83
          return [];
84
        },
85
        toString: constant('none()')
86
      };
87
      if (Object.freeze)
88
        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...
89
      return me;
90
    }();
91 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...
92
      var constant_a = function () {
93
        return a;
94
      };
95
      var self = function () {
96
        return me;
97
      };
98
      var map = function (f) {
99
        return some(f(a));
100
      };
101
      var bind = function (f) {
102
        return f(a);
103
      };
104
      var me = {
105
        fold: function (n, s) {
106
          return s(a);
107
        },
108
        is: function (v) {
109
          return a === v;
110
        },
111
        isSome: always$1,
112
        isNone: never$1,
113
        getOr: constant_a,
114
        getOrThunk: constant_a,
115
        getOrDie: constant_a,
116
        getOrNull: constant_a,
117
        getOrUndefined: constant_a,
118
        or: self,
119
        orThunk: self,
120
        map: map,
121
        ap: function (optfab) {
122
          return optfab.fold(none, function (fab) {
123
            return some(fab(a));
124
          });
125
        },
126
        each: function (f) {
127
          f(a);
128
        },
129
        bind: bind,
130
        flatten: constant_a,
131
        exists: bind,
132
        forall: bind,
133
        filter: function (f) {
134
          return f(a) ? me : NONE;
135
        },
136
        equals: function (o) {
137
          return o.is(a);
138
        },
139
        equals_: function (o, elementEq) {
140
          return o.fold(never$1, function (b) {
141
            return elementEq(a, b);
142
          });
143
        },
144
        toArray: function () {
145
          return [a];
146
        },
147
        toString: function () {
148
          return 'some(' + a + ')';
149
        }
150
      };
151
      return me;
152
    };
153
    var from = function (value) {
154
      return value === null || value === undefined ? NONE : some(value);
155
    };
156
    var Option = {
157
      some: some,
158
      none: none,
159
      from: from
160
    };
161
162
    var typeOf = function (x) {
163
      if (x === null)
164
        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...
165
      var t = typeof x;
166
      if (t === 'object' && Array.prototype.isPrototypeOf(x))
167
        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...
168
      if (t === 'object' && String.prototype.isPrototypeOf(x))
169
        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...
170
      return t;
171
    };
172
    var isType = function (type) {
173
      return function (value) {
174
        return typeOf(value) === type;
175
      };
176
    };
177
    var isFunction = isType('function');
178
179
    var filter = function (xs, pred) {
180
      var r = [];
181
      for (var i = 0, len = xs.length; i < len; i++) {
182
        var x = xs[i];
183
        if (pred(x, i, xs)) {
184
          r.push(x);
185
        }
186
      }
187
      return r;
188
    };
189
    var slice = Array.prototype.slice;
190
    var sort = function (xs, comparator) {
191
      var copy = slice.call(xs, 0);
192
      copy.sort(comparator);
193
      return copy;
194
    };
195
    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...
196
      return slice.call(x);
197
    };
198
199
    var hasOwnProperty = Object.hasOwnProperty;
200
    var get = function (obj, key) {
201
      return has(obj, key) ? Option.some(obj[key]) : Option.none();
202
    };
203
    var has = function (obj, key) {
204
      return hasOwnProperty.call(obj, key);
205
    };
206
207
    var isInlinePattern = function (pattern) {
208
      return has(pattern, 'start') && has(pattern, 'end');
209
    };
210
    var isBlockPattern = function (pattern) {
211
      return !has(pattern, 'end') && !has(pattern, 'replacement');
212
    };
213
    var isReplacementPattern = function (pattern) {
214
      return has(pattern, 'replacement');
215
    };
216
    var sortPatterns = function (patterns) {
217
      return sort(patterns, function (a, b) {
218
        if (a.start.length === b.start.length) {
219
          return 0;
220
        }
221
        return a.start.length > b.start.length ? -1 : 1;
222
      });
223
    };
224
    var createPatternSet = function (patterns) {
225
      return {
226
        inlinePatterns: sortPatterns(filter(patterns, isInlinePattern)),
227
        blockPatterns: sortPatterns(filter(patterns, isBlockPattern)),
228
        replacementPatterns: filter(patterns, isReplacementPattern)
229
      };
230
    };
231
232
    var get$1 = function (patternsState) {
233
      var setPatterns = function (newPatterns) {
234
        patternsState.set(createPatternSet(newPatterns));
235
      };
236
      var getPatterns = function () {
237
        return patternsState.get().inlinePatterns.concat(patternsState.get().blockPatterns, patternsState.get().replacementPatterns);
238
      };
239
      return {
240
        setPatterns: setPatterns,
241
        getPatterns: getPatterns
242
      };
243
    };
244
    var Api = { get: get$1 };
245
246
    var defaultPatterns = [
247
      {
248
        start: '*',
249
        end: '*',
250
        format: 'italic'
251
      },
252
      {
253
        start: '**',
254
        end: '**',
255
        format: 'bold'
256
      },
257
      {
258
        start: '***',
259
        end: '***',
260
        format: [
261
          'bold',
262
          'italic'
263
        ]
264
      },
265
      {
266
        start: '#',
267
        format: 'h1'
268
      },
269
      {
270
        start: '##',
271
        format: 'h2'
272
      },
273
      {
274
        start: '###',
275
        format: 'h3'
276
      },
277
      {
278
        start: '####',
279
        format: 'h4'
280
      },
281
      {
282
        start: '#####',
283
        format: 'h5'
284
      },
285
      {
286
        start: '######',
287
        format: 'h6'
288
      },
289
      {
290
        start: '1. ',
291
        cmd: 'InsertOrderedList'
292
      },
293
      {
294
        start: '* ',
295
        cmd: 'InsertUnorderedList'
296
      },
297
      {
298
        start: '- ',
299
        cmd: 'InsertUnorderedList'
300
      }
301
    ];
302
    var getPatternSet = function (editorSettings) {
303
      var patterns = get(editorSettings, 'textpattern_patterns').getOr(defaultPatterns);
304
      return createPatternSet(patterns);
305
    };
306
307
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Delay');
308
309
    var global$2 = tinymce.util.Tools.resolve('tinymce.util.VK');
310
311
    var global$3 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
312
313
    var global$4 = tinymce.util.Tools.resolve('tinymce.util.Tools');
314
315
    var findPattern = function (patterns, text) {
316
      for (var i = 0; i < patterns.length; i++) {
317
        var pattern = patterns[i];
318
        if (text.indexOf(pattern.start) !== 0) {
319
          continue;
320
        }
321
        if (pattern.end && text.lastIndexOf(pattern.end) !== text.length - pattern.end.length) {
322
          continue;
323
        }
324
        return pattern;
325
      }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
326
    };
327
    var isMatchingPattern = function (pattern, text, offset, delta) {
328
      var textEnd = text.substr(offset - pattern.end.length - delta, pattern.end.length);
329
      return textEnd === pattern.end;
330
    };
331
    var hasContent = function (offset, delta, pattern) {
332
      return offset - delta - pattern.end.length - pattern.start.length > 0;
333
    };
334
    var findEndPattern = function (patterns, text, offset, delta) {
335
      var pattern, i;
336
      for (i = 0; i < patterns.length; i++) {
337
        pattern = patterns[i];
338
        if (pattern.end !== undefined && isMatchingPattern(pattern, text, offset, delta) && hasContent(offset, delta, pattern)) {
339
          return pattern;
340
        }
341
      }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
342
    };
343
    var findInlinePattern = function (patterns, rng, space) {
344
      if (rng.collapsed === false) {
345
        return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
346
      }
347
      var container = rng.startContainer;
348
      var text = container.data;
349
      var delta = space === true ? 1 : 0;
350
      if (container.nodeType !== 3) {
351
        return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
352
      }
353
      var endPattern = findEndPattern(patterns, text, rng.startOffset, delta);
354
      if (endPattern === undefined) {
355
        return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
356
      }
357
      var endOffset = text.lastIndexOf(endPattern.end, rng.startOffset - delta);
358
      var startOffset = text.lastIndexOf(endPattern.start, endOffset - endPattern.end.length);
359
      endOffset = text.indexOf(endPattern.end, startOffset + endPattern.start.length);
360
      if (startOffset === -1) {
361
        return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
362
      }
363
      var patternRng = document.createRange();
364
      patternRng.setStart(container, startOffset);
365
      patternRng.setEnd(container, endOffset + endPattern.end.length);
366
      var startPattern = findPattern(patterns, patternRng.toString());
367
      if (endPattern === undefined || startPattern !== endPattern || container.data.length <= endPattern.start.length + endPattern.end.length) {
368
        return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
369
      }
370
      return {
371
        pattern: endPattern,
372
        startOffset: startOffset,
373
        endOffset: endOffset
374
      };
375
    };
376
    var findReplacementPattern = function (patterns, startSearch, text) {
377
      for (var i = 0; i < patterns.length; i++) {
378
        var index = text.lastIndexOf(patterns[i].start, startSearch);
379
        if (index !== -1) {
380
          return Option.some({
381
            pattern: patterns[i],
382
            startOffset: index
383
          });
384
        }
385
      }
386
      return Option.none();
387
    };
388
389
    var setSelection = function (editor, textNode, offset) {
390
      var newRng = editor.dom.createRng();
391
      newRng.setStart(textNode, offset);
392
      newRng.setEnd(textNode, offset);
393
      editor.selection.setRng(newRng);
394
    };
395
    var splitContainer = function (container, pattern, endOffset, startOffset) {
396
      container = startOffset > 0 ? container.splitText(startOffset) : container;
397
      container.splitText(endOffset - startOffset + pattern.end.length);
398
      container.deleteData(0, pattern.start.length);
399
      container.deleteData(container.data.length - pattern.end.length, pattern.end.length);
400
      return container;
401
    };
402
    var splitAndApply = function (editor, container, found) {
403
      var formatArray = global$4.isArray(found.pattern.format) ? found.pattern.format : [found.pattern.format];
404
      var validFormats = global$4.grep(formatArray, function (formatName) {
405
        var format = editor.formatter.get(formatName);
406
        return format && format[0].inline;
407
      });
408
      if (validFormats.length !== 0) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if validFormats.length !== 0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
409
        editor.undoManager.transact(function () {
410
          container = splitContainer(container, found.pattern, found.endOffset, found.startOffset);
411
          formatArray.forEach(function (format) {
412
            editor.formatter.apply(format, {}, container);
413
          });
414
        });
415
        return container;
416
      }
417
    };
418
    var applyInlinePattern = function (editor, patterns, space) {
419
      var rng = editor.selection.getRng();
420
      return Option.from(findInlinePattern(patterns, rng, space)).map(function (foundPattern) {
421
        return splitAndApply(editor, rng.startContainer, foundPattern);
422
      });
423
    };
424
    var applyInlinePatternSpace = function (editor, patterns) {
425
      applyInlinePattern(editor, patterns, true).each(function (wrappedTextNode) {
426
        var lastChar = wrappedTextNode.data.slice(-1);
427
        if (/[\u00a0 ]/.test(lastChar)) {
428
          wrappedTextNode.deleteData(wrappedTextNode.data.length - 1, 1);
429
          var lastCharNode = editor.dom.doc.createTextNode(lastChar);
430
          editor.dom.insertAfter(lastCharNode, wrappedTextNode.parentNode);
431
          setSelection(editor, lastCharNode, 1);
432
        }
433
      });
434
    };
435
    var applyInlinePatternEnter = function (editor, patterns) {
436
      applyInlinePattern(editor, patterns, false).each(function (wrappedTextNode) {
437
        setSelection(editor, wrappedTextNode, wrappedTextNode.data.length);
438
      });
439
    };
440
    var applyBlockPattern = function (editor, patterns) {
441
      var selection, dom, container, firstTextNode, node, format, textBlockElm, pattern, walker, rng, offset;
442
      selection = editor.selection;
443
      dom = editor.dom;
444
      if (!selection.isCollapsed()) {
445
        return;
446
      }
447
      textBlockElm = dom.getParent(selection.getStart(), 'p');
448
      if (textBlockElm) {
449
        walker = new global$3(textBlockElm, textBlockElm);
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like global$3 should be capitalized.
Loading history...
450
        while (node = walker.next()) {
451
          if (node.nodeType === 3) {
452
            firstTextNode = node;
453
            break;
454
          }
455
        }
456
        if (firstTextNode) {
457
          pattern = findPattern(patterns, firstTextNode.data);
458
          if (!pattern) {
459
            return;
460
          }
461
          rng = selection.getRng(true);
462
          container = rng.startContainer;
463
          offset = rng.startOffset;
464
          if (firstTextNode === container) {
465
            offset = Math.max(0, offset - pattern.start.length);
466
          }
467
          if (global$4.trim(firstTextNode.data).length === pattern.start.length) {
468
            return;
469
          }
470
          if (pattern.format) {
471
            format = editor.formatter.get(pattern.format);
472
            if (format && format[0].block) {
473
              firstTextNode.deleteData(0, pattern.start.length);
474
              editor.formatter.apply(pattern.format, {}, firstTextNode);
475
              rng.setStart(container, offset);
476
              rng.collapse(true);
477
              selection.setRng(rng);
478
            }
479
          }
480
          if (pattern.cmd) {
481
            editor.undoManager.transact(function () {
482
              firstTextNode.deleteData(0, pattern.start.length);
483
              editor.execCommand(pattern.cmd);
484
            });
485
          }
486
        }
487
      }
488
    };
489
    var replaceData = function (target, match) {
490
      target.deleteData(match.startOffset, match.pattern.start.length);
491
      target.insertData(match.startOffset, match.pattern.replacement);
492
    };
493
    var replaceMiddle = function (editor, target, match) {
494
      var startOffset = editor.selection.getRng().startOffset;
495
      replaceData(target, match);
496
      var newOffset = startOffset - match.pattern.start.length + match.pattern.replacement.length;
497
      setSelection(editor, target, newOffset);
498
    };
499
    var replaceEnd = function (editor, target, match) {
500
      replaceData(target, match);
501
      setSelection(editor, target, target.data.length);
502
    };
503
    var replace = function (editor, target, match) {
504
      if (match.startOffset < target.data.length) {
505
        replaceMiddle(editor, target, match);
506
      } else {
507
        replaceEnd(editor, target, match);
508
      }
509
    };
510
    var applyReplacementPattern = function (editor, patterns) {
511
      var rng = editor.selection.getRng();
512
      if (rng.collapsed && rng.startContainer.nodeType === 3) {
513
        var container_1 = rng.startContainer;
514
        findReplacementPattern(patterns, rng.startOffset, container_1.data).each(function (match) {
515
          replace(editor, container_1, match);
516
        });
517
      }
518
    };
519
520
    var handleEnter = function (editor, patternSet) {
521
      applyReplacementPattern(editor, patternSet.replacementPatterns);
522
      applyInlinePatternEnter(editor, patternSet.inlinePatterns);
523
      applyBlockPattern(editor, patternSet.blockPatterns);
524
    };
525
    var handleInlineKey = function (editor, patternSet) {
526
      applyReplacementPattern(editor, patternSet.replacementPatterns);
527
      applyInlinePatternSpace(editor, patternSet.inlinePatterns);
528
    };
529
    var checkKeyEvent = function (codes, event, predicate) {
530
      for (var i = 0; i < codes.length; i++) {
531
        if (predicate(codes[i], event)) {
532
          return true;
533
        }
534
      }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
535
    };
536
    var checkKeyCode = function (codes, event) {
537
      return checkKeyEvent(codes, event, function (code, event) {
538
        return code === event.keyCode && global$2.modifierPressed(event) === false;
539
      });
540
    };
541
    var checkCharCode = function (chars, event) {
542
      return checkKeyEvent(chars, event, function (chr, event) {
543
        return chr.charCodeAt(0) === event.charCode;
544
      });
545
    };
546
    var KeyHandler = {
547
      handleEnter: handleEnter,
548
      handleInlineKey: handleInlineKey,
549
      checkCharCode: checkCharCode,
550
      checkKeyCode: checkKeyCode
551
    };
552
553
    var setup = function (editor, patternsState) {
554
      var charCodes = [
555
        ',',
556
        '.',
557
        ';',
558
        ':',
559
        '!',
560
        '?'
561
      ];
562
      var keyCodes = [32];
563
      editor.on('keydown', function (e) {
564
        if (e.keyCode === 13 && !global$2.modifierPressed(e)) {
565
          KeyHandler.handleEnter(editor, patternsState.get());
566
        }
567
      }, true);
568
      editor.on('keyup', function (e) {
569
        if (KeyHandler.checkKeyCode(keyCodes, e)) {
570
          KeyHandler.handleInlineKey(editor, patternsState.get());
571
        }
572
      });
573
      editor.on('keypress', function (e) {
574
        if (KeyHandler.checkCharCode(charCodes, e)) {
575
          global$1.setEditorTimeout(editor, function () {
576
            KeyHandler.handleInlineKey(editor, patternsState.get());
577
          });
578
        }
579
      });
580
    };
581
    var Keyboard = { setup: setup };
582
583
    global.add('textpattern', function (editor) {
584
      var patternsState = Cell(getPatternSet(editor.settings));
585
      Keyboard.setup(editor, patternsState);
586
      return Api.get(patternsState);
587
    });
588
    function Plugin () {
589
    }
590
591
    return Plugin;
592
593
}());
594
})();
595