@taufik-nurrohman/text-editor.source 3.0.0 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. package/index.js +211 -114
  2. package/index.min.js +1 -1
  3. package/index.mjs +166 -84
  4. package/package.json +2 -1
package/index.js CHANGED
@@ -27,17 +27,6 @@
27
27
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = f() : typeof define === 'function' && define.amd ? define(f) : (g = typeof globalThis !== 'undefined' ? globalThis : g || self, (g.TextEditor = g.TextEditor || {}, g.TextEditor.Source = f()));
28
28
  })(this, (function () {
29
29
  'use strict';
30
- var debounce = function debounce(then, time) {
31
- var timer;
32
- return function () {
33
- var _arguments = arguments,
34
- _this = this;
35
- timer && clearTimeout(timer);
36
- timer = setTimeout(function () {
37
- return then.apply(_this, _arguments);
38
- }, time);
39
- };
40
- };
41
30
  var hasValue = function hasValue(x, data) {
42
31
  return -1 !== data.indexOf(x);
43
32
  };
@@ -47,12 +36,21 @@
47
36
  var isDefined$1 = function isDefined(x) {
48
37
  return 'undefined' !== typeof x;
49
38
  };
39
+ var isFunction = function isFunction(x) {
40
+ return 'function' === typeof x;
41
+ };
50
42
  var isInstance$1 = function isInstance(x, of) {
51
43
  return x && isSet$1(of) && x instanceof of ;
52
44
  };
45
+ var isInteger = function isInteger(x) {
46
+ return isNumber(x) && 0 === x % 1;
47
+ };
53
48
  var isNull$1 = function isNull(x) {
54
49
  return null === x;
55
50
  };
51
+ var isNumber = function isNumber(x) {
52
+ return 'number' === typeof x;
53
+ };
56
54
  var isObject = function isObject(x, isPlain) {
57
55
  if (isPlain === void 0) {
58
56
  isPlain = true;
@@ -65,9 +63,6 @@
65
63
  var isSet$1 = function isSet(x) {
66
64
  return isDefined$1(x) && !isNull$1(x);
67
65
  };
68
- var isString = function isString(x) {
69
- return 'string' === typeof x;
70
- };
71
66
  var toCount = function toCount(x) {
72
67
  return x.length;
73
68
  };
@@ -106,18 +101,21 @@
106
101
  }
107
102
  return out;
108
103
  };
109
- var offEvent = function offEvent(name, node, then) {
110
- node.removeEventListener(name, then);
104
+ var W = window;
105
+ var debounce = function debounce(then, time) {
106
+ var timer;
107
+ return function () {
108
+ var _arguments = arguments,
109
+ _this = this;
110
+ timer && clearTimeout(timer);
111
+ timer = setTimeout(function () {
112
+ return then.apply(_this, _arguments);
113
+ }, time);
114
+ };
111
115
  };
112
116
  var offEventDefault = function offEventDefault(e) {
113
117
  return e && e.preventDefault();
114
118
  };
115
- var onEvent = function onEvent(name, node, then, options) {
116
- if (options === void 0) {
117
- options = false;
118
- }
119
- node.addEventListener(name, then, options);
120
- };
121
119
  var isDefined = function isDefined(x) {
122
120
  return 'undefined' !== typeof x;
123
121
  };
@@ -145,39 +143,41 @@
145
143
  var bounce = debounce(function ($) {
146
144
  return $.record();
147
145
  }, 10);
146
+ var name = 'TextEditor.Source';
148
147
 
149
148
  function onKeyDown(e) {
150
- var _editor$state$source, _editor$state$source2;
151
- var self = this,
152
- editor = self.TextEditor,
153
- keys = editor.k();
154
- if (!editor || e.defaultPrevented) {
155
- return;
156
- }
157
- bounce(editor);
158
- if (editor.keys[keys]) {
149
+ var _$$state$source, _$$state$source2;
150
+ var $ = this,
151
+ key = $.k(false).pop(),
152
+ // Capture the last key
153
+ keys = $.k();
154
+ bounce($);
155
+ if (e.defaultPrevented || $.keys[keys]) {
159
156
  return;
160
157
  }
161
158
  var charAfter,
162
159
  charBefore,
163
- charIndent = ((_editor$state$source = editor.state.source) == null ? void 0 : _editor$state$source.tab) || editor.state.tab || '\t',
164
- charPairs = ((_editor$state$source2 = editor.state.source) == null ? void 0 : _editor$state$source2.pairs) || {},
160
+ charIndent = ((_$$state$source = $.state.source) == null ? void 0 : _$$state$source.tab) || $.state.tab || '\t',
161
+ charPairs = ((_$$state$source2 = $.state.source) == null ? void 0 : _$$state$source2.pairs) || {},
165
162
  charPairsValues = toObjectValues(charPairs);
166
- var _editor$$ = editor.$(),
167
- after = _editor$$.after,
168
- before = _editor$$.before,
169
- end = _editor$$.end,
170
- start = _editor$$.start,
171
- value = _editor$$.value,
163
+ if (isInteger(charIndent)) {
164
+ charIndent = ' '.repeat(charIndent);
165
+ }
166
+ var _$$$ = $.$(),
167
+ after = _$$$.after,
168
+ before = _$$$.before,
169
+ end = _$$$.end,
170
+ start = _$$$.start,
171
+ value = _$$$.value,
172
172
  lineAfter = after.split('\n').shift(),
173
173
  lineBefore = before.split('\n').pop(),
174
- lineMatch = lineBefore.match(/^(\s+)/),
175
- lineMatchIndent = lineMatch && lineMatch[1] || "";
174
+ lineMatch = /^\s+/.exec(lineBefore),
175
+ lineMatchIndent = lineMatch && lineMatch[0] || "";
176
176
  if (CTRL_PREFIX + SHIFT_PREFIX + 'Enter' === keys) {
177
177
  if (before || after) {
178
178
  // Insert line above with `⎈⇧↵`
179
179
  offEventDefault(e);
180
- return editor.select(start - toCount(lineBefore)).wrap(lineMatchIndent, '\n').insert(value).record(), false;
180
+ return $.select(start - toCount(lineBefore)).wrap(lineMatchIndent, '\n').insert(value).record(), false;
181
181
  }
182
182
  return;
183
183
  }
@@ -185,7 +185,7 @@
185
185
  if (before || after) {
186
186
  // Insert line below with `⎈↵`
187
187
  offEventDefault(e);
188
- return editor.select(end + toCount(lineAfter)).wrap('\n' + lineMatchIndent, "").insert(value).record(), false;
188
+ return $.select(end + toCount(lineAfter)).wrap('\n' + lineMatchIndent, "").insert(value).record(), false;
189
189
  }
190
190
  }
191
191
  // Do nothing
@@ -197,11 +197,11 @@
197
197
  charAfter = charPairs[charBefore = before.slice(-1)];
198
198
  if (!value && charAfter && charBefore && charAfter === after[0]) {
199
199
  offEventDefault(e);
200
- return editor.wrap(' ', ' ');
200
+ return $.wrap(' ', ' ');
201
201
  }
202
202
  return;
203
203
  }
204
- if ('Backspace' === keys) {
204
+ if ('Backspace' === keys || 'Delete' === keys) {
205
205
  charAfter = charPairs[charBefore = before.slice(-1)];
206
206
  // Do nothing on escape
207
207
  if ('\\' === charBefore) {
@@ -210,7 +210,7 @@
210
210
  if (value) {
211
211
  if (after && before && charAfter && charAfter === after[0] && !before.endsWith('\\' + charBefore)) {
212
212
  offEventDefault(e);
213
- return editor.record().peel(charBefore, charAfter).record();
213
+ return $.record().peel(charBefore, charAfter).record();
214
214
  }
215
215
  return;
216
216
  }
@@ -219,19 +219,19 @@
219
219
  if (after.startsWith(' ' + charAfter) && before.endsWith(charBefore + ' ') || after.startsWith('\n' + lineMatchIndent + charAfter) && before.endsWith(charBefore + '\n' + lineMatchIndent)) {
220
220
  // Collapse bracket(s)
221
221
  offEventDefault(e);
222
- return editor.trim("", "").record();
222
+ return $.trim("", "").record();
223
223
  }
224
224
  }
225
225
  // Outdent
226
- if (lineBefore.endsWith(charIndent)) {
226
+ if ('Delete' !== keys && lineBefore.endsWith(charIndent)) {
227
227
  offEventDefault(e);
228
- return editor.pull(charIndent).record();
228
+ return $.pull(charIndent).record();
229
229
  }
230
230
  if (after && before && !before.endsWith('\\' + charBefore)) {
231
231
  if (charAfter === after[0] && charBefore === before.slice(-1)) {
232
232
  // Peel pair
233
233
  offEventDefault(e);
234
- return editor.peel(charBefore, charAfter).record();
234
+ return $.peel(charBefore, charAfter).record();
235
235
  }
236
236
  }
237
237
  return;
@@ -240,11 +240,11 @@
240
240
  if (!value) {
241
241
  if (after && before && (charAfter = charPairs[charBefore = before.slice(-1)]) && charAfter === after[0]) {
242
242
  offEventDefault(e);
243
- return editor.wrap('\n' + lineMatchIndent + (charBefore !== charAfter ? charIndent : ""), '\n' + lineMatchIndent).record();
243
+ return $.wrap('\n' + lineMatchIndent + (charBefore !== charAfter ? charIndent : ""), '\n' + lineMatchIndent).record();
244
244
  }
245
245
  if (lineMatchIndent) {
246
246
  offEventDefault(e);
247
- return editor.insert('\n' + lineMatchIndent, -1).record();
247
+ return $.insert('\n' + lineMatchIndent, -1).record();
248
248
  }
249
249
  }
250
250
  return;
@@ -254,30 +254,29 @@
254
254
  return;
255
255
  }
256
256
  charAfter = hasValue(after[0], charPairsValues) ? after[0] : charPairs[charBefore];
257
- keys = keys.replace(SHIFT_PREFIX, "");
258
257
  // `|}`
259
- if (!value && after && before && charAfter && keys === charAfter) {
258
+ if (!value && after && before && charAfter && key === charAfter) {
260
259
  // Move to the next character
261
260
  // `}|`
262
261
  offEventDefault(e);
263
- return editor.select(start + 1).record();
262
+ return $.select(start + 1).record();
264
263
  }
265
264
  for (charBefore in charPairs) {
266
265
  charAfter = charPairs[charBefore];
267
266
  // `{|`
268
- if (keys === charBefore && charAfter) {
267
+ if (key === charBefore && charAfter) {
269
268
  // Wrap pair or selection
270
269
  // `{|}` `{|aaa|}`
271
270
  offEventDefault(e);
272
- return editor.wrap(charBefore, charAfter).record();
271
+ return $.wrap(charBefore, charAfter).record();
273
272
  }
274
273
  // `|}`
275
- if (keys === charAfter) {
274
+ if (key === charAfter) {
276
275
  if (value) {
277
276
  // Wrap selection
278
277
  // `{|aaa|}`
279
278
  offEventDefault(e);
280
- return editor.record().wrap(charBefore, charAfter).record();
279
+ return $.record().wrap(charBefore, charAfter).record();
281
280
  }
282
281
  break;
283
282
  }
@@ -298,17 +297,17 @@
298
297
  tokens.push('[\\s\\S]'); // Last try!
299
298
  if (CTRL_PREFIX + 'ArrowLeft' === keys) {
300
299
  offEventDefault(e);
301
- if (m = before.match(toPattern('(' + tokens.join('|') + ')$', ""))) {
302
- return editor.insert("").select(start - toCount(m[0])).insert(value).record();
300
+ if (m = toPattern('(' + tokens.join('|') + ')$', "").exec(before)) {
301
+ return $.insert("").select(start - toCount(m[0])).insert(value).record();
303
302
  }
304
- return editor.select();
303
+ return $.select();
305
304
  }
306
305
  if (CTRL_PREFIX + 'ArrowRight' === keys) {
307
306
  offEventDefault(e);
308
307
  if (m = after.match(toPattern('^(' + tokens.join('|') + ')', ""))) {
309
- return editor.insert("").select(end + toCount(m[0]) - toCount(value)).insert(value).record();
308
+ return $.insert("").select(end + toCount(m[0]) - toCount(value)).insert(value).record();
310
309
  }
311
- return editor.select();
310
+ return $.select();
312
311
  }
313
312
  }
314
313
  // Force to select the current line if there is no selection
@@ -318,41 +317,42 @@
318
317
  if (CTRL_PREFIX + 'ArrowUp' === keys) {
319
318
  offEventDefault(e);
320
319
  if (!hasValue('\n', before)) {
321
- return editor.select();
320
+ return $.select();
322
321
  }
323
- editor.insert("");
324
- editor.replace(/^([^\n]*?)(\n|$)/, '$2', 1);
325
- editor.replace(/(^|\n)([^\n]*?)$/, "", -1);
326
- var $ = editor.$();
327
- before = $.before;
328
- start = $.start;
322
+ $.insert("");
323
+ $.replace(/^([^\n]*?)(\n|$)/, '$2', 1);
324
+ $.replace(/(^|\n)([^\n]*?)$/, "", -1);
325
+ var s = $.$();
326
+ before = s.before;
327
+ start = s.start;
329
328
  lineBefore = before.split('\n').pop();
330
- editor.select(start = start - toCount(lineBefore)).wrap(value, '\n');
331
- editor.select(start, start + toCount(value));
332
- return editor.record();
329
+ $.select(start = start - toCount(lineBefore)).wrap(value, '\n');
330
+ $.select(start, start + toCount(value));
331
+ return $.record();
333
332
  }
334
333
  if (CTRL_PREFIX + 'ArrowDown' === keys) {
335
334
  offEventDefault(e);
336
335
  if (!hasValue('\n', after)) {
337
- return editor.select();
336
+ return $.select();
338
337
  }
339
- editor.insert("");
340
- editor.replace(/^([^\n]*?)(\n|$)/, "", 1);
341
- editor.replace(/(^|\n)([^\n]*?)$/, '$1', -1);
342
- var _$ = editor.$();
343
- after = _$.after;
344
- end = _$.end;
338
+ $.insert("");
339
+ $.replace(/^([^\n]*?)(\n|$)/, "", 1);
340
+ $.replace(/(^|\n)([^\n]*?)$/, '$1', -1);
341
+ var _s = $.$();
342
+ after = _s.after;
343
+ end = _s.end;
345
344
  lineAfter = after.split('\n').shift();
346
- editor.select(end = end + toCount(lineAfter)).wrap('\n', value);
345
+ $.select(end = end + toCount(lineAfter)).wrap('\n', value);
347
346
  end += 1;
348
- editor.select(end, end + toCount(value));
349
- return editor.record();
347
+ $.select(end, end + toCount(value));
348
+ return $.record();
350
349
  }
351
350
  return;
352
351
  }
353
352
 
354
- function attach(self) {
353
+ function attach() {
355
354
  var $ = this;
355
+ var $$ = $.constructor.prototype;
356
356
  $.state = fromStates({
357
357
  source: {
358
358
  pairs: {
@@ -363,51 +363,148 @@
363
363
  '"': '"',
364
364
  "'": "'",
365
365
  '<': '>'
366
- },
367
- type: null
366
+ }
368
367
  }
369
368
  }, $.state);
370
- $.toggle = function (open, close, wrap, tidy) {
371
- if (tidy === void 0) {
372
- tidy = false;
369
+ !isFunction($$.alert) && ($$.alert = function (hint, then) {
370
+ W.alert && W.alert(hint);
371
+ return isFunction(then) && then.call(this, true);
372
+ });
373
+ !isFunction($$.confirm) && ($$.confirm = function (hint, then) {
374
+ return isFunction(then) && then.call(this, W.confirm && W.confirm(hint));
375
+ });
376
+ !isFunction($$.insertBlock) && ($$.insertBlock = function (value, mode) {
377
+ var $ = this;
378
+ var _$$$2 = $.$(),
379
+ after = _$$$2.after,
380
+ before = _$$$2.before,
381
+ end = _$$$2.end,
382
+ start = _$$$2.start,
383
+ lineAfter = after.split('\n').shift(),
384
+ lineAfterCount = toCount(lineAfter),
385
+ lineBefore = before.split('\n').pop(),
386
+ lineBeforeCount = toCount(lineBefore),
387
+ lineMatch = /^\s+/.exec(lineBefore),
388
+ lineMatchIndent = lineMatch && lineMatch[0] || "";
389
+ if (-1 === mode) {
390
+ return $.select(start - lineBeforeCount).insert('\n', 1).push(lineMatchIndent).insert(value, 1, false);
373
391
  }
374
- if (!close && "" !== close) {
375
- close = open;
392
+ if (1 === mode) {
393
+ return $.select(end + lineAfterCount).insert('\n', -1).push(lineMatchIndent).insert(value, 1, false);
376
394
  }
377
- var _$$$ = $.$(),
378
- after = _$$$.after,
379
- before = _$$$.before,
380
- value = _$$$.value,
395
+ return $.select(start - lineBeforeCount, end + lineAfterCount).insert(value, mode, true).wrap(lineMatchIndent, "");
396
+ });
397
+ !isFunction($$.peelBlock) && ($$.peelBlock = function (open, close, wrap) {
398
+ var $ = this;
399
+ var _$$$3 = $.$(),
400
+ after = _$$$3.after,
401
+ before = _$$$3.before,
402
+ end = _$$$3.end,
403
+ start = _$$$3.start,
404
+ value = _$$$3.value,
381
405
  closeCount = toCount(close),
406
+ lineAfter = after.split('\n').shift(),
407
+ lineAfterCount = toCount(lineAfter),
408
+ lineBefore = before.split('\n').pop(),
409
+ lineBeforeCount = toCount(lineBefore),
382
410
  openCount = toCount(open);
383
- if (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount) || close === after.slice(0, closeCount) && open === before.slice(-openCount)) {
384
- return $.peel(open, close, wrap);
411
+ if (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount) || close === lineAfter.slice(-closeCount) && open === lineBefore.slice(0, openCount)) {
412
+ return $.select(start - lineBeforeCount + (wrap ? 0 : openCount), end + lineAfterCount - (wrap ? 0 : closeCount)).peel(open, close, wrap);
385
413
  }
386
- if (false !== tidy) {
387
- if (isString(tidy)) {
388
- tidy = [tidy, tidy];
389
- } else if (!isArray(tidy)) {
390
- tidy = ["", ""];
414
+ return $.select(start, end);
415
+ });
416
+ !isFunction($$.prompt) && ($$.prompt = function (hint, value, then) {
417
+ return isFunction(then) && then.call(this, W.prompt ? W.prompt(hint, value) : false);
418
+ });
419
+ !isFunction($$.selectBlock) && ($$.selectBlock = function (withSpaces) {
420
+ if (withSpaces === void 0) {
421
+ withSpaces = true;
422
+ }
423
+ var $ = this;
424
+ var _$$$4 = $.$(),
425
+ after = _$$$4.after,
426
+ before = _$$$4.before,
427
+ end = _$$$4.end,
428
+ start = _$$$4.start,
429
+ value = _$$$4.value,
430
+ lineAfter = after.split('\n').shift(),
431
+ lineAfterCount = toCount(lineAfter),
432
+ lineBefore = before.split('\n').pop(),
433
+ lineBeforeCount = toCount(lineBefore);
434
+ if (!withSpaces) {
435
+ var lineAfterSpaces = /\s+$/.exec(lineAfter),
436
+ lineBeforeSpaces = /^\s+/.exec(lineBefore);
437
+ if (lineAfterSpaces) {
438
+ lineAfterCount -= toCount(lineAfterSpaces[0]);
439
+ }
440
+ if (lineBeforeSpaces) {
441
+ lineBeforeCount -= toCount(lineBeforeSpaces[0]);
391
442
  }
392
- if (!isSet$1(tidy[1])) {
393
- tidy[1] = tidy[0];
443
+ }
444
+ $.select(start - lineBeforeCount, end + lineAfterCount);
445
+ if (!withSpaces) {
446
+ var s = $.$(),
447
+ m;
448
+ end = s.end;
449
+ start = s.start;
450
+ value = s.value;
451
+ if (m = /^(\s+)?[\s\S]+?(\s+)?$/.exec(value)) {
452
+ return $.select(start + toCount(m[1] || ""), end - toCount(m[2] || ""));
394
453
  }
395
- $.trim(tidy[0], tidy[1]);
454
+ }
455
+ return $;
456
+ });
457
+ !isFunction($$.toggle) && ($$.toggle = function (open, close, wrap) {
458
+ var $ = this;
459
+ var _$$$5 = $.$(),
460
+ after = _$$$5.after,
461
+ before = _$$$5.before,
462
+ value = _$$$5.value,
463
+ closeCount = toCount(close),
464
+ openCount = toCount(open);
465
+ if (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount) || close === after.slice(0, closeCount) && open === before.slice(-openCount)) {
466
+ return $.peel(open, close, wrap);
396
467
  }
397
468
  return $.wrap(open, close, wrap);
398
- };
399
- onEvent('keydown', self, onKeyDown);
400
- return $.record();
469
+ });
470
+ !isFunction($$.toggleBlock) && ($$.toggleBlock = function (open, close, wrap) {
471
+ var $ = this;
472
+ var _$$$6 = $.$(),
473
+ after = _$$$6.after,
474
+ before = _$$$6.before,
475
+ value = _$$$6.value,
476
+ closeCount = toCount(close),
477
+ lineAfter = after.split('\n').shift(),
478
+ lineBefore = before.split('\n').pop(),
479
+ openCount = toCount(open);
480
+ if (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount) || close === lineAfter.slice(-closeCount) && open === lineBefore.slice(0, openCount)) {
481
+ return $.peelBlock(open, close, wrap);
482
+ }
483
+ return $.wrapBlock(open, close, wrap);
484
+ });
485
+ !isFunction($$.wrapBlock) && ($$.wrapBlock = function (open, close, wrap) {
486
+ var $ = this;
487
+ var _$$$7 = $.$(),
488
+ after = _$$$7.after,
489
+ before = _$$$7.before,
490
+ end = _$$$7.end,
491
+ start = _$$$7.start,
492
+ lineAfter = after.split('\n').shift(),
493
+ lineAfterCount = toCount(lineAfter),
494
+ lineBefore = before.split('\n').pop(),
495
+ lineBeforeCount = toCount(lineBefore);
496
+ return $.select(start - lineBeforeCount, end + lineAfterCount).wrap(open, close, wrap);
497
+ });
498
+ return $.on('key.down', onKeyDown).record();
401
499
  }
402
500
 
403
- function detach(self) {
404
- var $ = this;
405
- offEvent('keydown', self, onKeyDown);
406
- return $;
501
+ function detach() {
502
+ return this.off('key.down', onKeyDown);
407
503
  }
408
504
  var index_js = {
409
505
  attach: attach,
410
- detach: detach
506
+ detach: detach,
507
+ name: name
411
508
  };
412
509
  return index_js;
413
510
  }));
package/index.min.js CHANGED
@@ -23,4 +23,4 @@
23
23
  * SOFTWARE.
24
24
  *
25
25
  */
26
- !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):((e="undefined"!=typeof globalThis?globalThis:e||self).TextEditor=e.TextEditor||{},e.TextEditor.Source=r())}(this,(function(){"use strict";var e,r,t,n=function(e,r){return-1!==r.indexOf(e)},i=function(e){return Array.isArray(e)},o=function(e,r){return void 0===r&&(r=!0),"object"==typeof e&&(!r||function(e,r){return e&&c(r)&&e instanceof r}(e,Object))},c=function(e){return function(e){return void 0!==e}(e)&&!function(e){return null===e}(e)},s=function(e){return e.length},u=function e(){for(var r=arguments.length,t=Array(r),u=0;u<r;u++)t[u]=arguments[u];for(var f=t.shift(),a=0,l=s(t);a<l;++a)for(var d in t[a])if(c(f[d]))if(i(f[d])&&i(t[a][d])){f[d]=[].concat(f[d]);for(var p=0,v=s(t[a][d]);p<v;++p)n(t[a][d][p],f[d])||f[d].push(t[a][d][p])}else o(f[d])&&o(t[a][d])?f[d]=e({},f[d],t[a][d]):f[d]=t[a][d];else f[d]=t[a][d];return f},f=function(e){return e&&e.preventDefault()},a=function(e){return function(e){return void 0!==e}(e)&&!function(e){return null===e}(e)},l=function(e){return t=RegExp,(r=e)&&a(t)&&r instanceof t;var r,t},d=function(e,r){return l(e)?e:RegExp(e,a(r)?r:"g")},p="Control-",v="Shift-",h=(e=function(e){return e.record()},r=10,function(){var n=arguments,i=this;t&&clearTimeout(t),t=setTimeout((function(){return e.apply(i,n)}),r)});function w(e){var r,t,i=this.TextEditor,o=i.k();if(i&&!e.defaultPrevented&&(h(i),!i.keys[o])){var c,u,a=(null==(r=i.state.source)?void 0:r.tab)||i.state.tab||"\t",l=(null==(t=i.state.source)?void 0:t.pairs)||{},w=Object.values(l),y=i.$(),b=y.after,m=y.before,E=y.end,g=y.start,$=y.value,x=b.split("\n").shift(),A=m.split("\n").pop(),T=A.match(/^(\s+)/),W=T&&T[1]||"";if(p+v+"Enter"===o)return m||b?(f(e),i.select(g-s(A)).wrap(W,"\n").insert($).record(),!1):void 0;if(p+"Enter"===o&&(m||b))return f(e),i.select(E+s(x)).wrap("\n"+W,"").insert($).record(),!1;if("Alt-"!=o+"-"&&p!==o+"-"){if(" "===o)return c=l[u=m.slice(-1)],!$&&c&&u&&c===b[0]?(f(e),i.wrap(" "," ")):void 0;if("Backspace"===o){if(c=l[u=m.slice(-1)],"\\"===u)return;return $?b&&m&&c&&c===b[0]&&!m.endsWith("\\"+u)?(f(e),i.record().peel(u,c).record()):void 0:(c=l[u=m.trim().slice(-1)])&&u&&(b.startsWith(" "+c)&&m.endsWith(u+" ")||b.startsWith("\n"+W+c)&&m.endsWith(u+"\n"+W))?(f(e),i.trim("","").record()):A.endsWith(a)?(f(e),i.pull(a).record()):b&&m&&!m.endsWith("\\"+u)&&c===b[0]&&u===m.slice(-1)?(f(e),i.peel(u,c).record()):void 0}if("Enter"!==o&&v+"Enter"!==o){if("\\"!==(u=m.slice(-1))){if(c=n(b[0],w)?b[0]:l[u],o=o.replace(v,""),!$&&b&&m&&c&&o===c)return f(e),i.select(g+1).record();for(u in l){if(c=l[u],o===u&&c)return f(e),i.wrap(u,c).record();if(o===c){if($)return f(e),i.record().wrap(u,c).record();break}}var j,k,L,O=[];if($){for(j in l)(k=l[j])&&O.push("(?:\\"+j+"(?:\\\\.|[^\\"+j+(k!==j?"\\"+k:"")+"])*\\"+k+")");if(O.push("\\w+"),O.push("\\s+"),O.push("[\\s\\S]"),p+"ArrowLeft"===o)return f(e),(L=m.match(d("("+O.join("|")+")$","")))?i.insert("").select(g-s(L[0])).insert($).record():i.select();if(p+"ArrowRight"===o)return f(e),(L=b.match(d("^("+O.join("|")+")","")))?i.insert("").select(E+s(L[0])-s($)).insert($).record():i.select()}if(E+=s(x),g-=s(A),$=A+$+x,p+"ArrowUp"===o){if(f(e),!n("\n",m))return i.select();i.insert(""),i.replace(/^([^\n]*?)(\n|$)/,"$2",1),i.replace(/(^|\n)([^\n]*?)$/,"",-1);var R=i.$();return m=R.before,g=R.start,A=m.split("\n").pop(),i.select(g-=s(A)).wrap($,"\n"),i.select(g,g+s($)),i.record()}if(p+"ArrowDown"===o){if(f(e),!n("\n",b))return i.select();i.insert(""),i.replace(/^([^\n]*?)(\n|$)/,"",1),i.replace(/(^|\n)([^\n]*?)$/,"$1",-1);var S=i.$();return b=S.after,E=S.end,x=b.split("\n").shift(),i.select(E+=s(x)).wrap("\n",$),E+=1,i.select(E,E+s($)),i.record()}}}else if(!$){if(b&&m&&(c=l[u=m.slice(-1)])&&c===b[0])return f(e),i.wrap("\n"+W+(u!==c?a:""),"\n"+W).record();if(W)return f(e),i.insert("\n"+W,-1).record()}}else f(e)}}var y={attach:function(e){var r=this;return r.state=u({source:{pairs:{"`":"`","(":")","{":"}","[":"]",'"':'"',"'":"'","<":">"},type:null}},r.state),r.toggle=function(e,t,n,o){void 0===o&&(o=!1),t||""===t||(t=e);var u=r.$(),f=u.after,a=u.before,l=u.value,d=s(t),p=s(e);return n&&t===l.slice(-d)&&e===l.slice(0,p)||t===f.slice(0,d)&&e===a.slice(-p)?r.peel(e,t,n):(!1!==o&&("string"==typeof o?o=[o,o]:i(o)||(o=["",""]),c(o[1])||(o[1]=o[0]),r.trim(o[0],o[1])),r.wrap(e,t,n))},function(e,r,t,n){void 0===n&&(n=!1),r.addEventListener(e,t,n)}("keydown",e,w),r.record()},detach:function(e){return function(e,r,t){r.removeEventListener(e,t)}("keydown",e,w),this}};return y}));
26
+ !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):((e="undefined"!=typeof globalThis?globalThis:e||self).TextEditor=e.TextEditor||{},e.TextEditor.Source=r())}(this,(function(){"use strict";var e,r,t,n=function(e,r){return-1!==r.indexOf(e)},i=function(e){return Array.isArray(e)},o=function(e){return"function"==typeof e},s=function(e){return"number"==typeof e},c=function(e,r){return void 0===r&&(r=!0),"object"==typeof e&&(!r||function(e,r){return e&&l(r)&&e instanceof r}(e,Object))},l=function(e){return function(e){return void 0!==e}(e)&&!function(e){return null===e}(e)},f=function(e){return e.length},u=function e(){for(var r=arguments.length,t=Array(r),o=0;o<r;o++)t[o]=arguments[o];for(var s=t.shift(),u=0,a=f(t);u<a;++u)for(var p in t[u])if(l(s[p]))if(i(s[p])&&i(t[u][p])){s[p]=[].concat(s[p]);for(var d=0,h=f(t[u][p]);d<h;++d)n(t[u][p][d],s[p])||s[p].push(t[u][p][d])}else c(s[p])&&c(t[u][p])?s[p]=e({},s[p],t[u][p]):s[p]=t[u][p];else s[p]=t[u][p];return s},a=window,p=function(e){return e&&e.preventDefault()},d=function(e){return function(e){return void 0!==e}(e)&&!function(e){return null===e}(e)},h=function(e){return t=RegExp,(r=e)&&d(t)&&r instanceof t;var r,t},v=function(e,r){return h(e)?e:RegExp(e,d(r)?r:"g")},w="Control-",k="Shift-",$=(e=function(e){return e.record()},r=10,function(){var n=arguments,i=this;t&&clearTimeout(t),t=setTimeout((function(){return e.apply(i,n)}),r)});function b(e){var r,t,i=this,o=i.k(!1).pop(),c=i.k();if($(i),!e.defaultPrevented&&!i.keys[c]){var l,u,a=(null==(r=i.state.source)?void 0:r.tab)||i.state.tab||"\t",d=(null==(t=i.state.source)?void 0:t.pairs)||{},h=Object.values(d);(function(e){return s(e)&&0==e%1})(a)&&(a=" ".repeat(a));var b=i.$(),m=b.after,g=b.before,x=b.end,y=b.start,B=b.value,E=m.split("\n").shift(),A=g.split("\n").pop(),T=/^\s+/.exec(A),W=T&&T[0]||"";if(w+k+"Enter"===c)return g||m?(p(e),i.select(y-f(A)).wrap(W,"\n").insert(B).record(),!1):void 0;if(w+"Enter"===c&&(g||m))return p(e),i.select(x+f(E)).wrap("\n"+W,"").insert(B).record(),!1;if("Alt-"!=c+"-"&&w!==c+"-"){if(" "===c)return l=d[u=g.slice(-1)],!B&&l&&u&&l===m[0]?(p(e),i.wrap(" "," ")):void 0;if("Backspace"===c||"Delete"===c){if(l=d[u=g.slice(-1)],"\\"===u)return;return B?m&&g&&l&&l===m[0]&&!g.endsWith("\\"+u)?(p(e),i.record().peel(u,l).record()):void 0:(l=d[u=g.trim().slice(-1)])&&u&&(m.startsWith(" "+l)&&g.endsWith(u+" ")||m.startsWith("\n"+W+l)&&g.endsWith(u+"\n"+W))?(p(e),i.trim("","").record()):"Delete"!==c&&A.endsWith(a)?(p(e),i.pull(a).record()):m&&g&&!g.endsWith("\\"+u)&&l===m[0]&&u===g.slice(-1)?(p(e),i.peel(u,l).record()):void 0}if("Enter"!==c&&k+"Enter"!==c){if("\\"!==(u=g.slice(-1))){if(l=n(m[0],h)?m[0]:d[u],!B&&m&&g&&l&&o===l)return p(e),i.select(y+1).record();for(u in d){if(l=d[u],o===u&&l)return p(e),i.wrap(u,l).record();if(o===l){if(B)return p(e),i.record().wrap(u,l).record();break}}var j,S,D,O=[];if(B){for(j in d)(S=d[j])&&O.push("(?:\\"+j+"(?:\\\\.|[^\\"+j+(S!==j?"\\"+S:"")+"])*\\"+S+")");if(O.push("\\w+"),O.push("\\s+"),O.push("[\\s\\S]"),w+"ArrowLeft"===c)return p(e),(D=v("("+O.join("|")+")$","").exec(g))?i.insert("").select(y-f(D[0])).insert(B).record():i.select();if(w+"ArrowRight"===c)return p(e),(D=m.match(v("^("+O.join("|")+")","")))?i.insert("").select(x+f(D[0])-f(B)).insert(B).record():i.select()}if(x+=f(E),y-=f(A),B=A+B+E,w+"ArrowUp"===c){if(p(e),!n("\n",g))return i.select();i.insert(""),i.replace(/^([^\n]*?)(\n|$)/,"$2",1),i.replace(/(^|\n)([^\n]*?)$/,"",-1);var R=i.$();return g=R.before,y=R.start,A=g.split("\n").pop(),i.select(y-=f(A)).wrap(B,"\n"),i.select(y,y+f(B)),i.record()}if(w+"ArrowDown"===c){if(p(e),!n("\n",m))return i.select();i.insert(""),i.replace(/^([^\n]*?)(\n|$)/,"",1),i.replace(/(^|\n)([^\n]*?)$/,"$1",-1);var C=i.$();return m=C.after,x=C.end,E=m.split("\n").shift(),i.select(x+=f(E)).wrap("\n",B),x+=1,i.select(x,x+f(B)),i.record()}}}else if(!B){if(m&&g&&(l=d[u=g.slice(-1)])&&l===m[0])return p(e),i.wrap("\n"+W+(u!==l?a:""),"\n"+W).record();if(W)return p(e),i.insert("\n"+W,-1).record()}}else p(e)}}var m={attach:function(){var e=this,r=e.constructor.prototype;return e.state=u({source:{pairs:{"`":"`","(":")","{":"}","[":"]",'"':'"',"'":"'","<":">"}}},e.state),!o(r.alert)&&(r.alert=function(e,r){return a.alert&&a.alert(e),o(r)&&r.call(this,!0)}),!o(r.confirm)&&(r.confirm=function(e,r){return o(r)&&r.call(this,a.confirm&&a.confirm(e))}),!o(r.insertBlock)&&(r.insertBlock=function(e,r){var t=this,n=t.$(),i=n.after,o=n.before,s=n.end,c=n.start,l=i.split("\n").shift(),u=f(l),a=o.split("\n").pop(),p=f(a),d=/^\s+/.exec(a),h=d&&d[0]||"";return-1===r?t.select(c-p).insert("\n",1).push(h).insert(e,1,!1):1===r?t.select(s+u).insert("\n",-1).push(h).insert(e,1,!1):t.select(c-p,s+u).insert(e,r,!0).wrap(h,"")}),!o(r.peelBlock)&&(r.peelBlock=function(e,r,t){var n=this,i=n.$(),o=i.after,s=i.before,c=i.end,l=i.start,u=i.value,a=f(r),p=o.split("\n").shift(),d=f(p),h=s.split("\n").pop(),v=f(h),w=f(e);return t&&r===u.slice(-a)&&e===u.slice(0,w)||r===p.slice(-a)&&e===h.slice(0,w)?n.select(l-v+(t?0:w),c+d-(t?0:a)).peel(e,r,t):n.select(l,c)}),!o(r.prompt)&&(r.prompt=function(e,r,t){return o(t)&&t.call(this,!!a.prompt&&a.prompt(e,r))}),!o(r.selectBlock)&&(r.selectBlock=function(e){void 0===e&&(e=!0);var r=this,t=r.$(),n=t.after,i=t.before,o=t.end,s=t.start,c=t.value,l=n.split("\n").shift(),u=f(l),a=i.split("\n").pop(),p=f(a);if(!e){var d=/\s+$/.exec(l),h=/^\s+/.exec(a);d&&(u-=f(d[0])),h&&(p-=f(h[0]))}if(r.select(s-p,o+u),!e){var v,w=r.$();if(o=w.end,s=w.start,c=w.value,v=/^(\s+)?[\s\S]+?(\s+)?$/.exec(c))return r.select(s+f(v[1]||""),o-f(v[2]||""))}return r}),!o(r.toggle)&&(r.toggle=function(e,r,t){var n=this,i=n.$(),o=i.after,s=i.before,c=i.value,l=f(r),u=f(e);return t&&r===c.slice(-l)&&e===c.slice(0,u)||r===o.slice(0,l)&&e===s.slice(-u)?n.peel(e,r,t):n.wrap(e,r,t)}),!o(r.toggleBlock)&&(r.toggleBlock=function(e,r,t){var n=this,i=n.$(),o=i.after,s=i.before,c=i.value,l=f(r),u=o.split("\n").shift(),a=s.split("\n").pop(),p=f(e);return t&&r===c.slice(-l)&&e===c.slice(0,p)||r===u.slice(-l)&&e===a.slice(0,p)?n.peelBlock(e,r,t):n.wrapBlock(e,r,t)}),!o(r.wrapBlock)&&(r.wrapBlock=function(e,r,t){var n=this.$(),i=n.after,o=n.before,s=n.end,c=n.start,l=i.split("\n").shift(),u=f(l),a=o.split("\n").pop(),p=f(a);return this.select(c-p,s+u).wrap(e,r,t)}),e.on("key.down",b).record()},detach:function(){return this.off("key.down",b)},name:"TextEditor.Source"};return m}));
package/index.mjs CHANGED
@@ -1,8 +1,9 @@
1
+ import {W} from '@taufik-nurrohman/document';
1
2
  import {debounce} from '@taufik-nurrohman/tick';
2
3
  import {fromStates} from '@taufik-nurrohman/from';
3
4
  import {hasValue} from '@taufik-nurrohman/has';
4
- import {isArray, isSet, isString} from '@taufik-nurrohman/is';
5
- import {onEvent, offEvent, offEventDefault} from '@taufik-nurrohman/event';
5
+ import {isArray, isFunction, isInteger, isSet, isString} from '@taufik-nurrohman/is';
6
+ import {offEventDefault} from '@taufik-nurrohman/event';
6
7
  import {toCount, toObjectValues} from '@taufik-nurrohman/to';
7
8
  import {toPattern} from '@taufik-nurrohman/pattern';
8
9
 
@@ -11,33 +12,34 @@ const CTRL_PREFIX = 'Control-';
11
12
  const SHIFT_PREFIX = 'Shift-';
12
13
 
13
14
  const bounce = debounce($ => $.record(), 10);
15
+ const name = 'TextEditor.Source';
14
16
 
15
17
  function onKeyDown(e) {
16
- let self = this,
17
- editor = self.TextEditor,
18
- keys = editor.k();
19
- if (!editor || e.defaultPrevented) {
20
- return;
21
- }
22
- bounce(editor);
23
- if (editor.keys[keys]) {
18
+ let $ = this,
19
+ key = $.k(false).pop(), // Capture the last key
20
+ keys = $.k();
21
+ bounce($);
22
+ if (e.defaultPrevented || $.keys[keys]) {
24
23
  return;
25
24
  }
26
25
  let charAfter,
27
26
  charBefore,
28
- charIndent = editor.state.source?.tab || editor.state.tab || '\t',
29
- charPairs = editor.state.source?.pairs || {},
27
+ charIndent = $.state.source?.tab || $.state.tab || '\t',
28
+ charPairs = $.state.source?.pairs || {},
30
29
  charPairsValues = toObjectValues(charPairs);
31
- let {after, before, end, start, value} = editor.$(),
30
+ if (isInteger(charIndent)) {
31
+ charIndent = ' '.repeat(charIndent);
32
+ }
33
+ let {after, before, end, start, value} = $.$(),
32
34
  lineAfter = after.split('\n').shift(),
33
35
  lineBefore = before.split('\n').pop(),
34
- lineMatch = lineBefore.match(/^(\s+)/),
35
- lineMatchIndent = lineMatch && lineMatch[1] || "";
36
+ lineMatch = /^\s+/.exec(lineBefore),
37
+ lineMatchIndent = lineMatch && lineMatch[0] || "";
36
38
  if (CTRL_PREFIX + SHIFT_PREFIX + 'Enter' === keys) {
37
39
  if (before || after) {
38
40
  // Insert line above with `⎈⇧↵`
39
41
  offEventDefault(e);
40
- return editor.select(start - toCount(lineBefore)).wrap(lineMatchIndent, '\n').insert(value).record(), false;
42
+ return $.select(start - toCount(lineBefore)).wrap(lineMatchIndent, '\n').insert(value).record(), false;
41
43
  }
42
44
  return;
43
45
  }
@@ -45,7 +47,7 @@ function onKeyDown(e) {
45
47
  if (before || after) {
46
48
  // Insert line below with `⎈↵`
47
49
  offEventDefault(e);
48
- return editor.select(end + toCount(lineAfter)).wrap('\n' + lineMatchIndent, "").insert(value).record(), false;
50
+ return $.select(end + toCount(lineAfter)).wrap('\n' + lineMatchIndent, "").insert(value).record(), false;
49
51
  }
50
52
  }
51
53
  // Do nothing
@@ -57,11 +59,11 @@ function onKeyDown(e) {
57
59
  charAfter = charPairs[charBefore = before.slice(-1)];
58
60
  if (!value && charAfter && charBefore && charAfter === after[0]) {
59
61
  offEventDefault(e);
60
- return editor.wrap(' ', ' ');
62
+ return $.wrap(' ', ' ');
61
63
  }
62
64
  return;
63
65
  }
64
- if ('Backspace' === keys) {
66
+ if ('Backspace' === keys || 'Delete' === keys) {
65
67
  charAfter = charPairs[charBefore = before.slice(-1)];
66
68
  // Do nothing on escape
67
69
  if ('\\' === charBefore) {
@@ -70,7 +72,7 @@ function onKeyDown(e) {
70
72
  if (value) {
71
73
  if (after && before && charAfter && charAfter === after[0] && !before.endsWith('\\' + charBefore)) {
72
74
  offEventDefault(e);
73
- return editor.record().peel(charBefore, charAfter).record();
75
+ return $.record().peel(charBefore, charAfter).record();
74
76
  }
75
77
  return;
76
78
  }
@@ -82,19 +84,19 @@ function onKeyDown(e) {
82
84
  ) {
83
85
  // Collapse bracket(s)
84
86
  offEventDefault(e);
85
- return editor.trim("", "").record();
87
+ return $.trim("", "").record();
86
88
  }
87
89
  }
88
90
  // Outdent
89
- if (lineBefore.endsWith(charIndent)) {
91
+ if ('Delete' !== keys && lineBefore.endsWith(charIndent)) {
90
92
  offEventDefault(e);
91
- return editor.pull(charIndent).record();
93
+ return $.pull(charIndent).record();
92
94
  }
93
95
  if (after && before && !before.endsWith('\\' + charBefore)) {
94
96
  if (charAfter === after[0] && charBefore === before.slice(-1)) {
95
97
  // Peel pair
96
98
  offEventDefault(e);
97
- return editor.peel(charBefore, charAfter).record();
99
+ return $.peel(charBefore, charAfter).record();
98
100
  }
99
101
  }
100
102
  return;
@@ -103,11 +105,11 @@ function onKeyDown(e) {
103
105
  if (!value) {
104
106
  if (after && before && (charAfter = charPairs[charBefore = before.slice(-1)]) && charAfter === after[0]) {
105
107
  offEventDefault(e);
106
- return editor.wrap('\n' + lineMatchIndent + (charBefore !== charAfter ? charIndent : ""), '\n' + lineMatchIndent).record();
108
+ return $.wrap('\n' + lineMatchIndent + (charBefore !== charAfter ? charIndent : ""), '\n' + lineMatchIndent).record();
107
109
  }
108
110
  if (lineMatchIndent) {
109
111
  offEventDefault(e);
110
- return editor.insert('\n' + lineMatchIndent, -1).record();
112
+ return $.insert('\n' + lineMatchIndent, -1).record();
111
113
  }
112
114
  }
113
115
  return;
@@ -117,30 +119,29 @@ function onKeyDown(e) {
117
119
  return;
118
120
  }
119
121
  charAfter = hasValue(after[0], charPairsValues) ? after[0] : charPairs[charBefore];
120
- keys = keys.replace(SHIFT_PREFIX, "");
121
122
  // `|}`
122
- if (!value && after && before && charAfter && keys === charAfter) {
123
+ if (!value && after && before && charAfter && key === charAfter) {
123
124
  // Move to the next character
124
125
  // `}|`
125
126
  offEventDefault(e);
126
- return editor.select(start + 1).record();
127
+ return $.select(start + 1).record();
127
128
  }
128
129
  for (charBefore in charPairs) {
129
130
  charAfter = charPairs[charBefore];
130
131
  // `{|`
131
- if (keys === charBefore && charAfter) {
132
+ if (key === charBefore && charAfter) {
132
133
  // Wrap pair or selection
133
134
  // `{|}` `{|aaa|}`
134
135
  offEventDefault(e);
135
- return editor.wrap(charBefore, charAfter).record();
136
+ return $.wrap(charBefore, charAfter).record();
136
137
  }
137
138
  // `|}`
138
- if (keys === charAfter) {
139
+ if (key === charAfter) {
139
140
  if (value) {
140
141
  // Wrap selection
141
142
  // `{|aaa|}`
142
143
  offEventDefault(e);
143
- return editor.record().wrap(charBefore, charAfter).record();
144
+ return $.record().wrap(charBefore, charAfter).record();
144
145
  }
145
146
  break;
146
147
  }
@@ -160,17 +161,17 @@ function onKeyDown(e) {
160
161
  tokens.push('[\\s\\S]'); // Last try!
161
162
  if (CTRL_PREFIX + 'ArrowLeft' === keys) {
162
163
  offEventDefault(e);
163
- if (m = before.match(toPattern('(' + tokens.join('|') + ')$', ""))) {
164
- return editor.insert("").select(start - toCount(m[0])).insert(value).record();
164
+ if (m = toPattern('(' + tokens.join('|') + ')$', "").exec(before)) {
165
+ return $.insert("").select(start - toCount(m[0])).insert(value).record();
165
166
  }
166
- return editor.select();
167
+ return $.select();
167
168
  }
168
169
  if (CTRL_PREFIX + 'ArrowRight' === keys) {
169
170
  offEventDefault(e);
170
171
  if (m = after.match(toPattern('^(' + tokens.join('|') + ')', ""))) {
171
- return editor.insert("").select(end + toCount(m[0]) - toCount(value)).insert(value).record();
172
+ return $.insert("").select(end + toCount(m[0]) - toCount(value)).insert(value).record();
172
173
  }
173
- return editor.select();
174
+ return $.select();
174
175
  }
175
176
  }
176
177
  // Force to select the current line if there is no selection
@@ -180,41 +181,42 @@ function onKeyDown(e) {
180
181
  if (CTRL_PREFIX + 'ArrowUp' === keys) {
181
182
  offEventDefault(e);
182
183
  if (!hasValue('\n', before)) {
183
- return editor.select();
184
+ return $.select();
184
185
  }
185
- editor.insert("");
186
- editor.replace(/^([^\n]*?)(\n|$)/, '$2', 1);
187
- editor.replace(/(^|\n)([^\n]*?)$/, "", -1);
188
- let $ = editor.$();
189
- before = $.before;
190
- start = $.start;
186
+ $.insert("");
187
+ $.replace(/^([^\n]*?)(\n|$)/, '$2', 1);
188
+ $.replace(/(^|\n)([^\n]*?)$/, "", -1);
189
+ let s = $.$();
190
+ before = s.before;
191
+ start = s.start;
191
192
  lineBefore = before.split('\n').pop();
192
- editor.select(start = start - toCount(lineBefore)).wrap(value, '\n');
193
- editor.select(start, start + toCount(value));
194
- return editor.record();
193
+ $.select(start = start - toCount(lineBefore)).wrap(value, '\n');
194
+ $.select(start, start + toCount(value));
195
+ return $.record();
195
196
  }
196
197
  if (CTRL_PREFIX + 'ArrowDown' === keys) {
197
198
  offEventDefault(e);
198
199
  if (!hasValue('\n', after)) {
199
- return editor.select();
200
+ return $.select();
200
201
  }
201
- editor.insert("");
202
- editor.replace(/^([^\n]*?)(\n|$)/, "", 1);
203
- editor.replace(/(^|\n)([^\n]*?)$/, '$1', -1);
204
- let $ = editor.$();
205
- after = $.after;
206
- end = $.end;
202
+ $.insert("");
203
+ $.replace(/^([^\n]*?)(\n|$)/, "", 1);
204
+ $.replace(/(^|\n)([^\n]*?)$/, '$1', -1);
205
+ let s = $.$();
206
+ after = s.after;
207
+ end = s.end;
207
208
  lineAfter = after.split('\n').shift();
208
- editor.select(end = end + toCount(lineAfter)).wrap('\n', value);
209
+ $.select(end = end + toCount(lineAfter)).wrap('\n', value);
209
210
  end += 1;
210
- editor.select(end, end + toCount(value));
211
- return editor.record();
211
+ $.select(end, end + toCount(value));
212
+ return $.record();
212
213
  }
213
214
  return;
214
215
  }
215
216
 
216
- function attach(self) {
217
- let $ = this;
217
+ function attach() {
218
+ const $ = this;
219
+ const $$ = $.constructor.prototype;
218
220
  $.state = fromStates({
219
221
  source: {
220
222
  pairs: {
@@ -225,44 +227,124 @@ function attach(self) {
225
227
  '"': '"',
226
228
  "'": "'",
227
229
  '<': '>'
228
- },
229
- type: null
230
+ }
230
231
  }
231
232
  }, $.state);
232
- $.toggle = function (open, close, wrap, tidy = false) {
233
- if (!close && "" !== close) {
234
- close = open;
233
+ !isFunction($$.alert) && ($$.alert = function (hint, then) {
234
+ W.alert && W.alert(hint);
235
+ return isFunction(then) && then.call(this, true);
236
+ });
237
+ !isFunction($$.confirm) && ($$.confirm = function (hint, then) {
238
+ return isFunction(then) && then.call(this, W.confirm && W.confirm(hint));
239
+ });
240
+ !isFunction($$.insertBlock) && ($$.insertBlock = function (value, mode) {
241
+ let $ = this;
242
+ let {after, before, end, start} = $.$(),
243
+ lineAfter = after.split('\n').shift(),
244
+ lineAfterCount = toCount(lineAfter),
245
+ lineBefore = before.split('\n').pop(),
246
+ lineBeforeCount = toCount(lineBefore),
247
+ lineMatch = /^\s+/.exec(lineBefore),
248
+ lineMatchIndent = lineMatch && lineMatch[0] || "";
249
+ if (-1 === mode) {
250
+ return $.select(start - lineBeforeCount).insert('\n', 1).push(lineMatchIndent).insert(value, 1, false);
235
251
  }
236
- let {after, before, value} = $.$(),
252
+ if (1 === mode) {
253
+ return $.select(end + lineAfterCount).insert('\n', -1).push(lineMatchIndent).insert(value, 1, false);
254
+ }
255
+ return $.select(start - lineBeforeCount, end + lineAfterCount).insert(value, mode, true).wrap(lineMatchIndent, "");
256
+ });
257
+ !isFunction($$.peelBlock) && ($$.peelBlock = function (open, close, wrap) {
258
+ let $ = this;
259
+ let {after, before, end, start, value} = $.$(),
237
260
  closeCount = toCount(close),
261
+ lineAfter = after.split('\n').shift(),
262
+ lineAfterCount = toCount(lineAfter),
263
+ lineBefore = before.split('\n').pop(),
264
+ lineBeforeCount = toCount(lineBefore),
238
265
  openCount = toCount(open);
239
266
  if (
240
267
  (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount)) ||
241
- (close === after.slice(0, closeCount) && open === before.slice(-openCount))
268
+ (close === lineAfter.slice(-closeCount) && open === lineBefore.slice(0, openCount))
242
269
  ) {
243
- return $.peel(open, close, wrap);
270
+ return $.select(start - lineBeforeCount + (wrap ? 0 : openCount), end + lineAfterCount - (wrap ? 0 : closeCount)).peel(open, close, wrap);
244
271
  }
245
- if (false !== tidy) {
246
- if (isString(tidy)) {
247
- tidy = [tidy, tidy];
248
- } else if (!isArray(tidy)) {
249
- tidy = ["", ""];
272
+ return $.select(start, end);
273
+ });
274
+ !isFunction($$.prompt) && ($$.prompt = function (hint, value, then) {
275
+ return isFunction(then) && then.call(this, W.prompt ? W.prompt(hint, value) : false);
276
+ });
277
+ !isFunction($$.selectBlock) && ($$.selectBlock = function (withSpaces = true) {
278
+ let $ = this;
279
+ let {after, before, end, start, value} = $.$(),
280
+ lineAfter = after.split('\n').shift(),
281
+ lineAfterCount = toCount(lineAfter),
282
+ lineBefore = before.split('\n').pop(),
283
+ lineBeforeCount = toCount(lineBefore);
284
+ if (!withSpaces) {
285
+ let lineAfterSpaces = /\s+$/.exec(lineAfter),
286
+ lineBeforeSpaces = /^\s+/.exec(lineBefore);
287
+ if (lineAfterSpaces) {
288
+ lineAfterCount -= toCount(lineAfterSpaces[0]);
289
+ }
290
+ if (lineBeforeSpaces) {
291
+ lineBeforeCount -= toCount(lineBeforeSpaces[0]);
250
292
  }
251
- if (!isSet(tidy[1])) {
252
- tidy[1] = tidy[0];
293
+ }
294
+ $.select(start - lineBeforeCount, end + lineAfterCount);
295
+ if (!withSpaces) {
296
+ let s = $.$(), m;
297
+ end = s.end;
298
+ start = s.start;
299
+ value = s.value;
300
+ if (m = /^(\s+)?[\s\S]+?(\s+)?$/.exec(value)) {
301
+ return $.select(start + toCount(m[1] || ""), end - toCount(m[2] || ""));
253
302
  }
254
- $.trim(tidy[0], tidy[1]);
303
+ }
304
+ return $;
305
+ });
306
+ !isFunction($$.toggle) && ($$.toggle = function (open, close, wrap) {
307
+ let $ = this;
308
+ let {after, before, value} = $.$(),
309
+ closeCount = toCount(close),
310
+ openCount = toCount(open);
311
+ if (
312
+ (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount)) ||
313
+ (close === after.slice(0, closeCount) && open === before.slice(-openCount))
314
+ ) {
315
+ return $.peel(open, close, wrap);
255
316
  }
256
317
  return $.wrap(open, close, wrap);
257
- };
258
- onEvent('keydown', self, onKeyDown);
259
- return $.record();
318
+ });
319
+ !isFunction($$.toggleBlock) && ($$.toggleBlock = function (open, close, wrap) {
320
+ let $ = this;
321
+ let {after, before, value} = $.$(),
322
+ closeCount = toCount(close),
323
+ lineAfter = after.split('\n').shift(),
324
+ lineBefore = before.split('\n').pop(),
325
+ openCount = toCount(open);
326
+ if (
327
+ (wrap && close === value.slice(-closeCount) && open === value.slice(0, openCount)) ||
328
+ (close === lineAfter.slice(-closeCount) && open === lineBefore.slice(0, openCount))
329
+ ) {
330
+ return $.peelBlock(open, close, wrap);
331
+ }
332
+ return $.wrapBlock(open, close, wrap);
333
+ });
334
+ !isFunction($$.wrapBlock) && ($$.wrapBlock = function (open, close, wrap) {
335
+ let $ = this;
336
+ let {after, before, end, start} = $.$(),
337
+ lineAfter = after.split('\n').shift(),
338
+ lineAfterCount = toCount(lineAfter),
339
+ lineBefore = before.split('\n').pop(),
340
+ lineBeforeCount = toCount(lineBefore);
341
+ return $.select(start - lineBeforeCount, end + lineAfterCount).wrap(open, close, wrap);
342
+ });
343
+ return $.on('key.down', onKeyDown).record();
260
344
  }
261
345
 
262
- function detach(self) {
263
- let $ = this;
264
- offEvent('keydown', self, onKeyDown);
265
- return $;
346
+ function detach() {
347
+ return this.off('key.down', onKeyDown);
266
348
  }
267
349
 
268
- export default {attach, detach};
350
+ export default {attach, detach, name};
package/package.json CHANGED
@@ -3,6 +3,7 @@
3
3
  "browser": "index.min.js",
4
4
  "bugs": "https://github.com/taufik-nurrohman/text-editor.source/issues",
5
5
  "dependencies": {
6
+ "@taufik-nurrohman/document": "*",
6
7
  "@taufik-nurrohman/event": "*",
7
8
  "@taufik-nurrohman/from": "*",
8
9
  "@taufik-nurrohman/has": "*",
@@ -52,5 +53,5 @@
52
53
  "scripts": {
53
54
  "pack": "pack --clean=false --from=.factory --js-format=umd --js-name=TextEditor.Source --js-top='%(js.license)' --mjs=true --to=."
54
55
  },
55
- "version": "3.0.0"
56
+ "version": "3.0.2"
56
57
  }