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

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