@textbus/platform-browser 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.
@@ -28,7 +28,8 @@ export declare class DomRenderer implements NativeRenderer {
28
28
  xlinktype: string;
29
29
  'xlink:type': string;
30
30
  };
31
- formElement: Record<string, string[]>;
31
+ booleanProps: Record<string, string[]>;
32
+ valueProps: Record<string, string[]>;
32
33
  listen<T = any>(node: NativeNode, type: string, callback: (ev: T) => any): void;
33
34
  unListen(node: NativeNode, type: string, callback: (ev: any) => any): void;
34
35
  createTextNode(textContent: string): NativeNode;
@@ -48,5 +49,5 @@ export declare class DomRenderer implements NativeRenderer {
48
49
  removeXlinkAttribute(target: NativeNode, key: string): void;
49
50
  replace(newChild: NativeNode, oldChild: NativeNode): void;
50
51
  copy(): void;
51
- static replaceEmpty(s: string, target: string): string;
52
+ static replaceEmpty(s: string): string;
52
53
  }
@@ -1,6 +1,6 @@
1
1
  import { Injector } from '@tanbo/di';
2
2
  import { Observable } from '@tanbo/stream';
3
- import { Commander, Controller, Keyboard, Scheduler, Selection } from '@textbus/core';
3
+ import { Commander, Controller, Keyboard, Renderer, Scheduler, Selection } from '@textbus/core';
4
4
  import { Caret, CaretPosition, CompositionState, Input, Scroller } from './types';
5
5
  import { Parser } from '../dom-support/parser';
6
6
  declare class NativeCaret implements Caret {
@@ -29,6 +29,7 @@ export declare class NativeInput extends Input {
29
29
  private scheduler;
30
30
  private selection;
31
31
  private keyboard;
32
+ private renderer;
32
33
  private commander;
33
34
  private controller;
34
35
  caret: NativeCaret;
@@ -45,7 +46,7 @@ export declare class NativeInput extends Input {
45
46
  private isSafari;
46
47
  private isMac;
47
48
  private isSougouPinYin;
48
- constructor(injector: Injector, parser: Parser, scheduler: Scheduler, selection: Selection, keyboard: Keyboard, commander: Commander, controller: Controller);
49
+ constructor(injector: Injector, parser: Parser, scheduler: Scheduler, selection: Selection, keyboard: Keyboard, renderer: Renderer, commander: Commander, controller: Controller);
49
50
  focus(nativeRange: Range): void;
50
51
  blur(): void;
51
52
  destroy(): void;
@@ -1118,14 +1118,20 @@ let DomRenderer = DomRenderer_1 = class DomRenderer {
1118
1118
  xlinktype: 'xlink:type',
1119
1119
  'xlink:type': 'xlink:type'
1120
1120
  };
1121
- this.formElement = {
1122
- input: ['disabled', 'readonly', 'value'],
1121
+ this.booleanProps = {
1122
+ input: ['disabled', 'readonly'],
1123
1123
  select: ['disabled', 'readonly'],
1124
- option: ['disabled', 'selected', 'value'],
1124
+ option: ['disabled', 'selected'],
1125
1125
  button: ['disabled'],
1126
1126
  video: ['controls', 'autoplay', 'loop', 'muted'],
1127
1127
  audio: ['controls', 'autoplay', 'loop', 'muted'],
1128
1128
  };
1129
+ this.valueProps = {
1130
+ input: ['value'],
1131
+ option: ['value'],
1132
+ video: ['src'],
1133
+ audio: ['src']
1134
+ };
1129
1135
  }
1130
1136
  listen(node, type, callback) {
1131
1137
  node.addEventListener(type, callback);
@@ -1134,7 +1140,7 @@ let DomRenderer = DomRenderer_1 = class DomRenderer {
1134
1140
  node.removeEventListener(type, callback);
1135
1141
  }
1136
1142
  createTextNode(textContent) {
1137
- return document.createTextNode(DomRenderer_1.replaceEmpty(textContent, '\u00a0'));
1143
+ return document.createTextNode(DomRenderer_1.replaceEmpty(textContent));
1138
1144
  }
1139
1145
  createElement(name) {
1140
1146
  if (this.isSVG.test(name)) {
@@ -1165,8 +1171,9 @@ let DomRenderer = DomRenderer_1 = class DomRenderer {
1165
1171
  target.style[key] = value !== null && value !== void 0 ? value : '';
1166
1172
  }
1167
1173
  syncTextContent(target, content) {
1168
- if (target.textContent !== content) {
1169
- target.textContent = content;
1174
+ const c = DomRenderer_1.replaceEmpty(content);
1175
+ if (target.textContent !== c) {
1176
+ target.textContent = c;
1170
1177
  }
1171
1178
  }
1172
1179
  removeStyle(target, key) {
@@ -1178,20 +1185,30 @@ let DomRenderer = DomRenderer_1 = class DomRenderer {
1178
1185
  return;
1179
1186
  }
1180
1187
  target.setAttribute(key, value);
1181
- const propNames = this.formElement[target.tagName.toLowerCase()];
1182
- if (propNames && propNames.includes(key)) {
1188
+ const tag = target.tagName.toLowerCase();
1189
+ const booleanTagNames = this.booleanProps[tag];
1190
+ const valueTagNames = this.valueProps[tag];
1191
+ if (booleanTagNames && booleanTagNames.includes(key)) {
1183
1192
  target[key] = Boolean(value);
1184
1193
  }
1194
+ if (valueTagNames && valueTagNames.includes(key)) {
1195
+ target[key] = value;
1196
+ }
1185
1197
  }
1186
1198
  removeAttribute(target, key) {
1187
1199
  if (this.possibleXlinkNames[key]) {
1188
1200
  this.removeXlinkAttribute(target, this.possibleXlinkNames[key]);
1189
1201
  }
1190
1202
  target.removeAttribute(key);
1191
- const propNames = this.formElement[target.tagName.toLowerCase()];
1192
- if (propNames && propNames.includes(key)) {
1203
+ const tag = target.tagName.toLowerCase();
1204
+ const booleanTagNames = this.booleanProps[tag];
1205
+ const valueTagNames = this.valueProps[tag];
1206
+ if (booleanTagNames && booleanTagNames.includes(key)) {
1193
1207
  target[key] = false;
1194
1208
  }
1209
+ if (valueTagNames && valueTagNames.includes(key)) {
1210
+ target[key] = '';
1211
+ }
1195
1212
  }
1196
1213
  setXlinkAttribute(target, key, value) {
1197
1214
  target.setAttributeNS(this.xlinkNameSpace, key, value);
@@ -1205,12 +1222,13 @@ let DomRenderer = DomRenderer_1 = class DomRenderer {
1205
1222
  copy() {
1206
1223
  document.execCommand('copy');
1207
1224
  }
1208
- static replaceEmpty(s, target) {
1225
+ static replaceEmpty(s) {
1226
+ const empty = '\u00a0';
1209
1227
  return s.replace(/\s\s+/g, str => {
1210
1228
  return ' ' + Array.from({
1211
1229
  length: str.length - 1
1212
- }).fill(target).join('');
1213
- }).replace(/^\s|\s$/g, target);
1230
+ }).fill(empty).join('');
1231
+ }).replace(/^\s|\s$/g, empty);
1214
1232
  }
1215
1233
  };
1216
1234
  DomRenderer = DomRenderer_1 = __decorate([
@@ -1984,13 +2002,14 @@ let NativeInput = class NativeInput extends Input {
1984
2002
  get disabled() {
1985
2003
  return this._disabled;
1986
2004
  }
1987
- constructor(injector, parser, scheduler, selection, keyboard, commander, controller) {
2005
+ constructor(injector, parser, scheduler, selection, keyboard, renderer, commander, controller) {
1988
2006
  super();
1989
2007
  this.injector = injector;
1990
2008
  this.parser = parser;
1991
2009
  this.scheduler = scheduler;
1992
2010
  this.selection = selection;
1993
2011
  this.keyboard = keyboard;
2012
+ this.renderer = renderer;
1994
2013
  this.commander = commander;
1995
2014
  this.controller = controller;
1996
2015
  this.caret = new NativeCaret(this.scheduler);
@@ -2161,15 +2180,35 @@ let NativeInput = class NativeInput extends Input {
2161
2180
  data: ev.data
2162
2181
  });
2163
2182
  invokeListener(startSlot.parent, 'onCompositionUpdate', event);
2164
- }), merge(fromEvent(input, 'beforeinput').pipe(filter(ev => {
2183
+ }), merge(fromEvent(input, 'beforeinput').pipe(map(ev => {
2184
+ var _a;
2165
2185
  ev.preventDefault();
2186
+ if (ev.inputType === 'insertCompositionText') {
2187
+ return null;
2188
+ }
2189
+ if (ev.inputType === 'insertReplacementText') {
2190
+ const range = ev.getTargetRanges()[0];
2191
+ const location = this.renderer.getLocationByNativeNode(range.startContainer);
2192
+ const startSlot = this.selection.startSlot;
2193
+ this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
2194
+ this.commander.delete();
2195
+ return ((_a = ev.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text')) || ev.data || null;
2196
+ }
2197
+ isCompositionEnd = ev.inputType === 'insertFromComposition';
2198
+ if (isCompositionEnd && this.composition) {
2199
+ return null;
2200
+ }
2166
2201
  if (this.isSafari) {
2167
- isCompositionEnd = ev.inputType === 'insertFromComposition';
2168
- return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
2202
+ if (ev.inputType === 'insertText' || isCompositionEnd) {
2203
+ return ev.data;
2204
+ }
2169
2205
  }
2170
- return !ev.isComposing && !!ev.data;
2171
- }), map(ev => {
2172
- return ev.data;
2206
+ if (!ev.isComposing && !!ev.data) {
2207
+ return ev.data;
2208
+ }
2209
+ return null;
2210
+ }), filter(text => {
2211
+ return text;
2173
2212
  })), this.isSafari ? new Observable() : fromEvent(input, 'compositionend').pipe(map(ev => {
2174
2213
  isCompositionEnd = true;
2175
2214
  ev.preventDefault();
@@ -2202,6 +2241,7 @@ NativeInput = __decorate([
2202
2241
  Scheduler,
2203
2242
  Selection,
2204
2243
  Keyboard,
2244
+ Renderer,
2205
2245
  Commander,
2206
2246
  Controller])
2207
2247
  ], NativeInput);
package/bundles/index.js CHANGED
@@ -1120,14 +1120,20 @@ exports.DomRenderer = DomRenderer_1 = class DomRenderer {
1120
1120
  xlinktype: 'xlink:type',
1121
1121
  'xlink:type': 'xlink:type'
1122
1122
  };
1123
- this.formElement = {
1124
- input: ['disabled', 'readonly', 'value'],
1123
+ this.booleanProps = {
1124
+ input: ['disabled', 'readonly'],
1125
1125
  select: ['disabled', 'readonly'],
1126
- option: ['disabled', 'selected', 'value'],
1126
+ option: ['disabled', 'selected'],
1127
1127
  button: ['disabled'],
1128
1128
  video: ['controls', 'autoplay', 'loop', 'muted'],
1129
1129
  audio: ['controls', 'autoplay', 'loop', 'muted'],
1130
1130
  };
1131
+ this.valueProps = {
1132
+ input: ['value'],
1133
+ option: ['value'],
1134
+ video: ['src'],
1135
+ audio: ['src']
1136
+ };
1131
1137
  }
1132
1138
  listen(node, type, callback) {
1133
1139
  node.addEventListener(type, callback);
@@ -1136,7 +1142,7 @@ exports.DomRenderer = DomRenderer_1 = class DomRenderer {
1136
1142
  node.removeEventListener(type, callback);
1137
1143
  }
1138
1144
  createTextNode(textContent) {
1139
- return document.createTextNode(DomRenderer_1.replaceEmpty(textContent, '\u00a0'));
1145
+ return document.createTextNode(DomRenderer_1.replaceEmpty(textContent));
1140
1146
  }
1141
1147
  createElement(name) {
1142
1148
  if (this.isSVG.test(name)) {
@@ -1167,8 +1173,9 @@ exports.DomRenderer = DomRenderer_1 = class DomRenderer {
1167
1173
  target.style[key] = value !== null && value !== void 0 ? value : '';
1168
1174
  }
1169
1175
  syncTextContent(target, content) {
1170
- if (target.textContent !== content) {
1171
- target.textContent = content;
1176
+ const c = DomRenderer_1.replaceEmpty(content);
1177
+ if (target.textContent !== c) {
1178
+ target.textContent = c;
1172
1179
  }
1173
1180
  }
1174
1181
  removeStyle(target, key) {
@@ -1180,20 +1187,30 @@ exports.DomRenderer = DomRenderer_1 = class DomRenderer {
1180
1187
  return;
1181
1188
  }
1182
1189
  target.setAttribute(key, value);
1183
- const propNames = this.formElement[target.tagName.toLowerCase()];
1184
- if (propNames && propNames.includes(key)) {
1190
+ const tag = target.tagName.toLowerCase();
1191
+ const booleanTagNames = this.booleanProps[tag];
1192
+ const valueTagNames = this.valueProps[tag];
1193
+ if (booleanTagNames && booleanTagNames.includes(key)) {
1185
1194
  target[key] = Boolean(value);
1186
1195
  }
1196
+ if (valueTagNames && valueTagNames.includes(key)) {
1197
+ target[key] = value;
1198
+ }
1187
1199
  }
1188
1200
  removeAttribute(target, key) {
1189
1201
  if (this.possibleXlinkNames[key]) {
1190
1202
  this.removeXlinkAttribute(target, this.possibleXlinkNames[key]);
1191
1203
  }
1192
1204
  target.removeAttribute(key);
1193
- const propNames = this.formElement[target.tagName.toLowerCase()];
1194
- if (propNames && propNames.includes(key)) {
1205
+ const tag = target.tagName.toLowerCase();
1206
+ const booleanTagNames = this.booleanProps[tag];
1207
+ const valueTagNames = this.valueProps[tag];
1208
+ if (booleanTagNames && booleanTagNames.includes(key)) {
1195
1209
  target[key] = false;
1196
1210
  }
1211
+ if (valueTagNames && valueTagNames.includes(key)) {
1212
+ target[key] = '';
1213
+ }
1197
1214
  }
1198
1215
  setXlinkAttribute(target, key, value) {
1199
1216
  target.setAttributeNS(this.xlinkNameSpace, key, value);
@@ -1207,12 +1224,13 @@ exports.DomRenderer = DomRenderer_1 = class DomRenderer {
1207
1224
  copy() {
1208
1225
  document.execCommand('copy');
1209
1226
  }
1210
- static replaceEmpty(s, target) {
1227
+ static replaceEmpty(s) {
1228
+ const empty = '\u00a0';
1211
1229
  return s.replace(/\s\s+/g, str => {
1212
1230
  return ' ' + Array.from({
1213
1231
  length: str.length - 1
1214
- }).fill(target).join('');
1215
- }).replace(/^\s|\s$/g, target);
1232
+ }).fill(empty).join('');
1233
+ }).replace(/^\s|\s$/g, empty);
1216
1234
  }
1217
1235
  };
1218
1236
  exports.DomRenderer = DomRenderer_1 = __decorate([
@@ -1986,13 +2004,14 @@ exports.NativeInput = class NativeInput extends Input {
1986
2004
  get disabled() {
1987
2005
  return this._disabled;
1988
2006
  }
1989
- constructor(injector, parser, scheduler, selection, keyboard, commander, controller) {
2007
+ constructor(injector, parser, scheduler, selection, keyboard, renderer, commander, controller) {
1990
2008
  super();
1991
2009
  this.injector = injector;
1992
2010
  this.parser = parser;
1993
2011
  this.scheduler = scheduler;
1994
2012
  this.selection = selection;
1995
2013
  this.keyboard = keyboard;
2014
+ this.renderer = renderer;
1996
2015
  this.commander = commander;
1997
2016
  this.controller = controller;
1998
2017
  this.caret = new NativeCaret(this.scheduler);
@@ -2163,15 +2182,35 @@ exports.NativeInput = class NativeInput extends Input {
2163
2182
  data: ev.data
2164
2183
  });
2165
2184
  core.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
2166
- }), stream.merge(stream.fromEvent(input, 'beforeinput').pipe(stream.filter(ev => {
2185
+ }), stream.merge(stream.fromEvent(input, 'beforeinput').pipe(stream.map(ev => {
2186
+ var _a;
2167
2187
  ev.preventDefault();
2188
+ if (ev.inputType === 'insertCompositionText') {
2189
+ return null;
2190
+ }
2191
+ if (ev.inputType === 'insertReplacementText') {
2192
+ const range = ev.getTargetRanges()[0];
2193
+ const location = this.renderer.getLocationByNativeNode(range.startContainer);
2194
+ const startSlot = this.selection.startSlot;
2195
+ this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
2196
+ this.commander.delete();
2197
+ return ((_a = ev.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text')) || ev.data || null;
2198
+ }
2199
+ isCompositionEnd = ev.inputType === 'insertFromComposition';
2200
+ if (isCompositionEnd && this.composition) {
2201
+ return null;
2202
+ }
2168
2203
  if (this.isSafari) {
2169
- isCompositionEnd = ev.inputType === 'insertFromComposition';
2170
- return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
2204
+ if (ev.inputType === 'insertText' || isCompositionEnd) {
2205
+ return ev.data;
2206
+ }
2171
2207
  }
2172
- return !ev.isComposing && !!ev.data;
2173
- }), stream.map(ev => {
2174
- return ev.data;
2208
+ if (!ev.isComposing && !!ev.data) {
2209
+ return ev.data;
2210
+ }
2211
+ return null;
2212
+ }), stream.filter(text => {
2213
+ return text;
2175
2214
  })), this.isSafari ? new stream.Observable() : stream.fromEvent(input, 'compositionend').pipe(stream.map(ev => {
2176
2215
  isCompositionEnd = true;
2177
2216
  ev.preventDefault();
@@ -2204,6 +2243,7 @@ exports.NativeInput = __decorate([
2204
2243
  core.Scheduler,
2205
2244
  core.Selection,
2206
2245
  core.Keyboard,
2246
+ core.Renderer,
2207
2247
  core.Commander,
2208
2248
  core.Controller])
2209
2249
  ], exports.NativeInput);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@textbus/platform-browser",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "Textbus is a rich text editor and framework that is highly customizable and extensible to achieve rich wysiwyg effects.",
5
5
  "main": "./bundles/index.js",
6
6
  "module": "./bundles/index.esm.js",
@@ -48,5 +48,5 @@
48
48
  "bugs": {
49
49
  "url": "https://github.com/textbus/textbus.git/issues"
50
50
  },
51
- "gitHead": "1a8732460b4e218117d176277bc18021c90779dc"
51
+ "gitHead": "01d6397297fa0999b4ef6ffef3ae36b37118ad44"
52
52
  }