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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }