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

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 +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
  }