locomotive-aloha-rails 0.23.2.1 → 0.23.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.md +3 -3
  2. data/lib/aloha/rails/engine.rb +1 -1
  3. data/lib/aloha/rails/version.rb +2 -2
  4. data/lib/tasks/aloha-assets.rake +1 -1
  5. data/vendor/assets/javascripts/aloha/css/aloha-sidebar.css +41 -17
  6. data/vendor/assets/javascripts/aloha/css/aloha.css +2 -2
  7. data/vendor/assets/javascripts/aloha/lib/aloha/contenthandlermanager.js +19 -18
  8. data/vendor/assets/javascripts/aloha/lib/aloha/engine.js +168 -9
  9. data/vendor/assets/javascripts/aloha/lib/aloha/ephemera.js +8 -1
  10. data/vendor/assets/javascripts/aloha/lib/aloha/markup.js +3 -2
  11. data/vendor/assets/javascripts/aloha/lib/aloha/pluginmanager.js +8 -0
  12. data/vendor/assets/javascripts/aloha/lib/aloha/sidebar.js +1 -1
  13. data/vendor/assets/javascripts/aloha/lib/aloha/state-override.js +59 -37
  14. data/vendor/assets/javascripts/aloha/lib/util/arrays.js +53 -6
  15. data/vendor/assets/javascripts/aloha/lib/util/boundary-markers.js +86 -0
  16. data/vendor/assets/javascripts/aloha/lib/util/dom2.js +178 -19
  17. data/vendor/assets/javascripts/aloha/lib/util/html.js +77 -10
  18. data/vendor/assets/javascripts/aloha/lib/util/maps.js +23 -1
  19. data/vendor/assets/javascripts/aloha/lib/util/range-context.js +429 -181
  20. data/vendor/assets/javascripts/aloha/lib/util/strings.js +9 -1
  21. data/vendor/assets/javascripts/aloha/plugins/common/align/nls/de/i18n.js +4 -1
  22. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/blockmanager.js +2 -5
  23. data/vendor/assets/javascripts/aloha/plugins/common/characterpicker/css/characterpicker.css +6 -3
  24. data/vendor/assets/javascripts/aloha/plugins/common/characterpicker/lib/characterpicker-plugin.js +29 -32
  25. data/vendor/assets/javascripts/aloha/plugins/common/contenthandler/lib/blockelementcontenthandler.js +41 -70
  26. data/vendor/assets/javascripts/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml.js +1 -1
  27. data/vendor/assets/javascripts/aloha/plugins/common/format/lib/format-plugin.js +22 -10
  28. data/vendor/assets/javascripts/aloha/plugins/common/link/css/link.css +2 -8
  29. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-cell.js +7 -0
  30. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-plugin.js +149 -131
  31. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table.js +77 -47
  32. data/vendor/assets/javascripts/aloha/plugins/common/ui/lib/port-helper-attribute-field.js +4 -8
  33. data/vendor/assets/javascripts/aloha/plugins/common/ui/nls/de/i18n.js +1 -0
  34. data/vendor/assets/javascripts/aloha/plugins/extra/cite/css/cite.css +0 -10
  35. data/vendor/assets/javascripts/aloha/plugins/extra/cite/lib/cite-plugin.js +4 -4
  36. data/vendor/assets/javascripts/aloha/plugins/extra/headerids/lib/headerids-plugin.js +84 -32
  37. data/vendor/assets/javascripts/aloha/plugins/extra/numerated-headers/nls/de/i18n.js +2 -1
  38. data/vendor/assets/javascripts/aloha/plugins/extra/numerated-headers/nls/i18n.js +2 -1
  39. metadata +15 -14
@@ -72,6 +72,7 @@ define([
72
72
  'util/dom2',
73
73
  'util/functions',
74
74
  'util/misc',
75
+ 'util/browser',
75
76
  'PubSub'
76
77
  ], function (
77
78
  $,
@@ -84,6 +85,7 @@ define([
84
85
  Dom,
85
86
  Functions,
86
87
  Misc,
88
+ Browser,
87
89
  PubSub
88
90
  ) {
89
91
  'use strict';
@@ -325,7 +327,12 @@ define([
325
327
  var data = $elem.attr('data-aloha-ephemera-attr');
326
328
  var i;
327
329
  var attrs;
328
- $elem.removeAttr('data-aloha-ephemera-attr');
330
+ // Because IE7 crashes if we remove this attribute. If the
331
+ // dom-to-xhtml plugin is turned on, it will handle the removal
332
+ // of this attribute during serialization.
333
+ if (!Browser.ie7) {
334
+ $elem.removeAttr('data-aloha-ephemera-attr');
335
+ }
329
336
  if (typeof data === 'string') {
330
337
  attrs = Strings.words(data);
331
338
  for (i = 0; i < attrs.length; i++) {
@@ -27,6 +27,7 @@
27
27
  define([
28
28
  'aloha/core',
29
29
  'util/class',
30
+ 'util/html',
30
31
  'jquery',
31
32
  'aloha/ecma5shims',
32
33
  'aloha/console',
@@ -34,6 +35,7 @@ define([
34
35
  ], function (
35
36
  Aloha,
36
37
  Class,
38
+ Html,
37
39
  jQuery,
38
40
  shims,
39
41
  console,
@@ -384,14 +386,13 @@ define([
384
386
 
385
387
  // ENTER
386
388
  if (event.keyCode === 13) {
387
- if (event.shiftKey) {
389
+ if (event.shiftKey || !Html.allowNestedParagraph(Aloha.activeEditable)) {
388
390
  Aloha.execCommand('insertlinebreak', false);
389
391
  return false;
390
392
  }
391
393
  Aloha.execCommand('insertparagraph', false);
392
394
  return false;
393
395
  }
394
-
395
396
  return true;
396
397
  },
397
398
 
@@ -80,6 +80,12 @@ define([
80
80
  * successfully initialized.
81
81
  */
82
82
  function initializePlugins(plugins, callback) {
83
+ if (0 === plugins.length) {
84
+ if (callback) {
85
+ callback();
86
+ }
87
+ return;
88
+ }
83
89
  var numToEnable = plugins.length;
84
90
  var onInit = function () {
85
91
  if (0 === --numToEnable && callback) {
@@ -102,6 +108,8 @@ define([
102
108
  } else {
103
109
  onInit();
104
110
  }
111
+ } else {
112
+ onInit();
105
113
  }
106
114
  }
107
115
  }
@@ -910,7 +910,7 @@ define([
910
910
  var that = this;
911
911
  this.element.addClass('collapsed');
912
912
  this.content.stop().animate(
913
- { height: 5 },
913
+ { height: 3 },
914
914
  250,
915
915
  'easeOutExpo',
916
916
  function () {
@@ -27,42 +27,38 @@
27
27
  define([
28
28
  'aloha/core',
29
29
  'jquery',
30
- 'aloha/selection',
31
30
  'aloha/command',
32
31
  'util/dom2',
32
+ 'util/maps',
33
+ 'util/range',
33
34
  'PubSub'
34
35
  ], function (
35
36
  Aloha,
36
37
  jQuery,
37
- Selection,
38
38
  Command,
39
39
  Dom,
40
+ Maps,
41
+ RangeObject,
40
42
  PubSub
41
43
  ) {
42
44
  'use strict';
43
45
 
44
- var enabled = Aloha.settings.stateOverride;
46
+ // Because we want to provide an easy way to disable the state-override feature.
47
+ var enabled = Aloha.settings.stateOverride !== false;
48
+ var overrides = null;
49
+ var overrideRange = null;
45
50
 
46
- // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#state-override
47
- // "Whenever the number of ranges in the selection changes to
48
- // something different, and whenever a boundary point of the range
49
- // at a given index in the selection changes to something different,
50
- // the state override and value override must be unset for every
51
- // command."
52
- Aloha.bind('aloha-selection-changed', function (event, range) {
53
- if (Command.resetOverrides(range)) {
54
- // Because the UI may reflect the any potentially state
55
- // overrides that are now no longer in effect, we must
56
- // redraw the UI according to the current selection.
57
- PubSub.pub('aloha.selection.context-change', {
58
- range: range,
59
- event: event
60
- });
61
- }
62
- });
51
+ function rangeObjectFromRange(range) {
52
+ return new RangeObject(range);
53
+ }
54
+
55
+ function clear() {
56
+ overrideRange = null;
57
+ overrides = null;
58
+ }
63
59
 
64
60
  function keyPressHandler(event) {
65
- if (!enabled) {
61
+ if (!overrides) {
66
62
  return;
67
63
  }
68
64
  if (event.altKey || event.ctrlKey || !event.which) {
@@ -74,32 +70,37 @@ define([
74
70
  }
75
71
  var text = String.fromCharCode(event.which);
76
72
  var range = selection.getRangeAt(0);
77
- // Because execCommand may invoke for example the bold command,
78
- // which selects the inserted text to make it bold, and by doing
79
- // so fires a selection-changed event. This is unnecessary and
80
- // causes a flicker in the UI where the bold state of the button
81
- // switches from bold to unbold and to bold again.
82
- Aloha.Selection.preventSelectionChanged();
83
- Command.execCommand('insertText', null, text, range);
73
+ Dom.insertSelectText(text, range);
74
+ Maps.forEach(overrides, function (formatFn, command) {
75
+ formatFn(command, range);
76
+ });
77
+ Dom.collapseToEnd(range);
78
+ selection.removeAllRanges();
79
+ selection.addRange(range);
84
80
  // Because we handled the character insert ourselves via
85
81
  // insertText we must not let the browser's default action
86
82
  // insert the character a second time.
87
83
  event.preventDefault();
88
84
  }
89
85
 
90
- function rangeFromRangeObject(alohaRange) {
91
- var range = Aloha.createRange();
92
- range.setStart(alohaRange.startContainer, alohaRange.startOffset);
93
- range.setEnd(alohaRange.endContainer, alohaRange.endOffset);
94
- return range;
86
+ function set(command, range, formatFn) {
87
+ if (!enabled) {
88
+ return;
89
+ }
90
+ overrideRange = range;
91
+ overrides = overrides || {};
92
+ overrides[command] = formatFn;
95
93
  }
96
94
 
97
- function setWithRangeObject(command, state, rangeObject) {
95
+ function setWithRangeObject(command, rangeObject, formatFn) {
98
96
  if (!enabled) {
99
97
  return;
100
98
  }
101
- var range = rangeFromRangeObject(rangeObject);
102
- Command.setStateOverride(command, state, range);
99
+ set(command, Dom.rangeFromRangeObject(rangeObject), function (command, range) {
100
+ var rangeObject = rangeObjectFromRange(range);
101
+ formatFn(command, rangeObject);
102
+ Dom.setRangeFromRef(range, rangeObject);
103
+ });
103
104
  // Because without doing rangeObject.select(), the
104
105
  // next insertText command (see editable.js) will
105
106
  // not be reached and instead the browsers default
@@ -117,9 +118,30 @@ define([
117
118
  return enabled;
118
119
  }
119
120
 
121
+ // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#state-override
122
+ // "Whenever the number of ranges in the selection changes to
123
+ // something different, and whenever a boundary point of the range
124
+ // at a given index in the selection changes to something different,
125
+ // the state override and value override must be unset for every
126
+ // command."
127
+ Aloha.bind('aloha-selection-changed', function (event, range) {
128
+ if (overrideRange && !Dom.areRangesEq(overrideRange, range)) {
129
+ clear();
130
+ // Because the UI may reflect the any potentially state
131
+ // overrides that are now no longer in effect, we must
132
+ // redraw the UI according to the current selection.
133
+ PubSub.pub('aloha.selection.context-change', {
134
+ range: range,
135
+ event: event
136
+ });
137
+ }
138
+ });
139
+
120
140
  return {
121
141
  enabled: enabledAccessor,
122
142
  keyPressHandler: keyPressHandler,
123
- setWithRangeObject: setWithRangeObject
143
+ setWithRangeObject: setWithRangeObject,
144
+ set: set,
145
+ clear: clear
124
146
  };
125
147
  });
@@ -24,7 +24,7 @@
24
24
  * provided you include this license notice and a URL through which
25
25
  * recipients can access the Corresponding Source.
26
26
  */
27
- define([], function () {
27
+ define(['util/functions'], function (Fn) {
28
28
  'use strict';
29
29
 
30
30
  /**
@@ -104,10 +104,10 @@ define([], function () {
104
104
  }
105
105
 
106
106
  /**
107
- * ECMAScript map replacement
107
+ * Emulates ECMAScript edition 5 Arrays.map
108
108
  * See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map
109
109
  * And http://es5.github.com/#x15.4.4.19
110
- * It's not exactly according to standard, but it does exactly what one expects.
110
+ * It's not exactly according to standard, but it does what one expects.
111
111
  */
112
112
  function map(a, fn) {
113
113
  var i, len, result = [];
@@ -169,7 +169,7 @@ define([], function () {
169
169
  * Arrays.reduce([2, 3, 4], 1, function (a, b) { return a + b; });
170
170
  * returns the result of (((1 + 2) + 3) + 4)
171
171
  *
172
- * Emulates ECMA5 Array.reduce.
172
+ * Emulates ECMAScript edition 5 Array.reduce.
173
173
  *
174
174
  * @param a
175
175
  * An array of values.
@@ -206,7 +206,9 @@ define([], function () {
206
206
  }
207
207
 
208
208
  /**
209
- * Emulates ECMA5 Array.forEach.
209
+ * For each item in xs, call cb(item, index, xs).
210
+ *
211
+ * Emulates ECMAScript edition 5 Array.forEach.
210
212
  */
211
213
  function forEach(xs, cb) {
212
214
  var i,
@@ -216,6 +218,33 @@ define([], function () {
216
218
  }
217
219
  }
218
220
 
221
+ /**
222
+ * Returns true if the given predicate function returns true for at
223
+ * least one item.
224
+ *
225
+ * Emulates ECMAScript edition 5 Array.some.
226
+ */
227
+ function some(xs, pred) {
228
+ var i,
229
+ len;
230
+ for (i = 0, len = xs.length; i < len; i++) {
231
+ if (pred(xs[i])) {
232
+ return true;
233
+ }
234
+ }
235
+ return false;
236
+ }
237
+
238
+ /**
239
+ * Returns true if the given predicate function returns true for all
240
+ * items in xs.
241
+ *
242
+ * Emulates ECMAScript edition 5 Array.every.
243
+ */
244
+ function every(xs, pred) {
245
+ return !some(xs, Fn.complement(pred));
246
+ }
247
+
219
248
  /**
220
249
  * Returns all items in xs that are also contained in zs.
221
250
  */
@@ -225,16 +254,34 @@ define([], function () {
225
254
  });
226
255
  }
227
256
 
257
+ /**
258
+ * Returns the last item in xs or null.
259
+ */
260
+ function last(xs) {
261
+ return xs.length ? xs[xs.length - 1] : null;
262
+ }
263
+
264
+ /**
265
+ * Returns the second item in xs.
266
+ */
267
+ function second(xs) {
268
+ return xs[1];
269
+ }
270
+
228
271
  return {
229
272
  filter: filter,
230
273
  indexOf: indexOf,
231
274
  reduce: reduce,
232
275
  forEach: forEach,
276
+ some: some,
277
+ every: every,
233
278
  map: Array.prototype.map ? mapNative : map,
234
279
  contains: contains,
235
280
  equal: equal,
236
281
  applyNotNull: applyNotNull,
237
282
  sortUnique: sortUnique,
238
- intersect: intersect
283
+ intersect: intersect,
284
+ second: second,
285
+ last: last
239
286
  };
240
287
  });
@@ -0,0 +1,86 @@
1
+ define(['util/dom2', 'util/arrays', 'util/strings'], function (Dom, Arrays, Strings) {
2
+ 'use strict';
3
+
4
+ function insert(range) {
5
+ var leftMarkerChar = (3 === range.startContainer.nodeType ? '[' : '{');
6
+ var rightMarkerChar = (3 === range.endContainer.nodeType ? ']' : '}');
7
+ Dom.splitTextContainers(range);
8
+ var leftMarker = document.createTextNode(leftMarkerChar);
9
+ var rightMarker = document.createTextNode(rightMarkerChar);
10
+ var start = Dom.cursorFromBoundaryPoint(range.startContainer, range.startOffset);
11
+ var end = Dom.cursorFromBoundaryPoint(range.endContainer, range.endOffset);
12
+ start.insert(leftMarker);
13
+ end.insert(rightMarker);
14
+ }
15
+
16
+ function extract(rootElem, range) {
17
+ var markers = ['[', '{', '}', ']'];
18
+ var markersFound = 0;
19
+ function setBoundaryPoint(marker, node) {
20
+ var setFn;
21
+ if (0 === markersFound) {
22
+ setFn = 'setStart';
23
+ if (marker !== '[' && marker !== '{') {
24
+ throw "end marker before start marker";
25
+ }
26
+ } else if (1 === markersFound) {
27
+ setFn = 'setEnd';
28
+ if (marker !== ']' && marker !== '}') {
29
+ throw "start marker before end marker";
30
+ }
31
+ } else {
32
+ throw "Too many markers";
33
+ }
34
+ markersFound += 1;
35
+ if (marker === '[' || marker === ']') {
36
+ var previousSibling = node.previousSibling;
37
+ if (!previousSibling || 3 !== previousSibling.nodeType) {
38
+ previousSibling = document.createTextNode('');
39
+ node.parentNode.insertBefore(previousSibling, node);
40
+ }
41
+ range[setFn].call(range, previousSibling, previousSibling.length);
42
+ // Because we have set a text offset.
43
+ return false;
44
+ } else { // marker === '{' || marker === '}'
45
+ range[setFn].call(range, node.parentNode, Dom.nodeIndex(node));
46
+ // Because we have set a non-text offset.
47
+ return true;
48
+ }
49
+ }
50
+ function extractMarkers(node) {
51
+ if (3 !== node.nodeType) {
52
+ return;
53
+ }
54
+ var text = node.nodeValue;
55
+ var parts = Strings.splitIncl(text, /[\[\{\}\]]/g);
56
+ // Because modifying every text node when there can be
57
+ // only two markers seems like too much overhead.
58
+ if (!Arrays.contains(markers, parts[0]) && parts.length < 2) {
59
+ return;
60
+ }
61
+ // Because non-text boundary positions must not be joined again.
62
+ var forceNextSplit = false;
63
+ Arrays.forEach(parts, function (part, i) {
64
+ // Because we don't want to join text nodes we haven't split.
65
+ forceNextSplit = forceNextSplit || (i === 0);
66
+ if (Arrays.contains(markers, part)) {
67
+ forceNextSplit = setBoundaryPoint(part, node);
68
+ } else if (!forceNextSplit && node.previousSibling && 3 === node.previousSibling.nodeType) {
69
+ node.previousSibling.insertData(node.previousSibling.length, part);
70
+ } else {
71
+ node.parentNode.insertBefore(document.createTextNode(part), node);
72
+ }
73
+ });
74
+ node.parentNode.removeChild(node);
75
+ }
76
+ Dom.walkRec(rootElem, extractMarkers);
77
+ if (2 !== markersFound) {
78
+ throw "Missing one or both markers";
79
+ }
80
+ }
81
+
82
+ return {
83
+ insert: insert,
84
+ extract: extract
85
+ };
86
+ });
@@ -25,19 +25,25 @@
25
25
  * recipients can access the Corresponding Source.
26
26
  */
27
27
  define([
28
+ 'aloha/core',
28
29
  'jquery',
29
30
  'util/functions',
30
31
  'util/maps',
31
32
  'util/arrays',
32
33
  'util/strings',
33
- 'util/browser'
34
+ 'util/browser',
35
+ 'util/dom',
36
+ 'util/range'
34
37
  ], function (
38
+ Aloha,
35
39
  $,
36
40
  Fn,
37
41
  Maps,
38
42
  Arrays,
39
43
  Strings,
40
- Browser
44
+ Browser,
45
+ Dom1,
46
+ RangeObject
41
47
  ) {
42
48
  'use strict';
43
49
 
@@ -293,7 +299,6 @@ define([
293
299
  return index;
294
300
  }
295
301
 
296
-
297
302
  function nodeIndex(node) {
298
303
  var ret = 0;
299
304
  while (node.previousSibling) {
@@ -304,6 +309,7 @@ define([
304
309
  }
305
310
 
306
311
  /**
312
+ * Can't use elem.childNodes.length because
307
313
  * http://www.quirksmode.org/dom/w3c_core.html
308
314
  * "IE up to 8 does not count empty text nodes."
309
315
  */
@@ -347,7 +353,7 @@ define([
347
353
  return node;
348
354
  }
349
355
 
350
- function shallowRemove(node) {
356
+ function removeShallow(node) {
351
357
  var parent = node.parentNode;
352
358
  moveNextAll(parent, node.firstChild, node);
353
359
  parent.removeChild(node);
@@ -506,6 +512,24 @@ define([
506
512
  });
507
513
  }
508
514
 
515
+ function next(node, until, arg) {
516
+ while (node && !until(node, arg)) {
517
+ node = node.nextSibling;
518
+ }
519
+ return node;
520
+ }
521
+
522
+ function parent(node, until, arg) {
523
+ while (node && !until(node, arg)) {
524
+ node = node.parentNode;
525
+ }
526
+ return node;
527
+ }
528
+
529
+ function isTextNode(node) {
530
+ return 3 === node.nodeType;
531
+ }
532
+
509
533
  function splitTextNode(node, offset) {
510
534
  // Because node.splitText() is buggy on IE, split it manually.
511
535
  // http://www.quirksmode.org/dom/w3c_core.html
@@ -543,10 +567,26 @@ define([
543
567
  range[setProp].call(range, container, offset);
544
568
  }
545
569
 
546
- function splitNodeAdjustRange(splitNode, splitOffset, sc, so, ec, eo, range) {
570
+ /**
571
+ * Splits the given text node at the given offset and, if the given
572
+ * range happens to have start or end containers equal to the given
573
+ * text node, adjusts it such that start and end position will point
574
+ * at the same position in the new text nodes.
575
+ *
576
+ * It is guaranteed that an adjusted boundary point will not point
577
+ * to the end of a text node. Instead, it will point to the next
578
+ * node. This guarantee often happens to be useful.
579
+ *
580
+ * If splitNode is not a text node, does nothing.
581
+ */
582
+ function splitTextNodeAdjustRange(splitNode, splitOffset, range) {
547
583
  if (3 !== splitNode.nodeType) {
548
584
  return;
549
585
  }
586
+ var sc = range.startContainer;
587
+ var so = range.startOffset;
588
+ var ec = range.endContainer;
589
+ var eo = range.endOffset;
550
590
  var newNodeBeforeSplit = splitTextNode(splitNode, splitOffset);
551
591
  adjustRangeAfterSplit(range, sc, so, 'setStart', splitNode, newNodeBeforeSplit);
552
592
  adjustRangeAfterSplit(range, ec, eo, 'setEnd', splitNode, newNodeBeforeSplit);
@@ -555,44 +595,47 @@ define([
555
595
  function splitTextContainers(range) {
556
596
  var sc = range.startContainer;
557
597
  var so = range.startOffset;
598
+ splitTextNodeAdjustRange(sc, so, range);
599
+ // Because the range may have been adjusted.
558
600
  var ec = range.endContainer;
559
601
  var eo = range.endOffset;
560
- splitNodeAdjustRange(sc, so, sc, so, ec, eo, range);
561
- // Because the range may have been adjusted.
562
- sc = range.startContainer;
563
- so = range.startOffset;
564
- ec = range.endContainer;
565
- eo = range.endOffset;
566
- splitNodeAdjustRange(ec, eo, sc, so, ec, eo, range);
602
+ splitTextNodeAdjustRange(ec, eo, range);
567
603
  }
568
604
 
569
605
  function walkUntil(node, fn, until, arg) {
570
606
  while (node && !until(node, arg)) {
571
- node = fn(node, arg);
607
+ var next = node.nextSibling;
608
+ fn(node, arg);
609
+ node = next;
572
610
  }
573
- return node;
574
611
  }
575
612
 
576
613
  function walk(node, fn, arg) {
577
614
  walkUntil(node, fn, Fn.returnFalse, arg);
578
615
  }
579
616
 
617
+ /**
618
+ * Depth-first postwalk of the given DOM node.
619
+ */
580
620
  function walkRec(node, fn, arg) {
581
621
  if (1 === node.nodeType) {
582
622
  walk(node.firstChild, function (node) {
583
- return walkRec(node, fn, arg);
623
+ walkRec(node, fn, arg);
584
624
  });
585
625
  }
586
- return fn(node, arg);
626
+ fn(node, arg);
587
627
  }
588
628
 
589
629
  function walkUntilNode(node, fn, untilNode, arg) {
590
- return walkUntil(node, fn, function (nextNode) {
630
+ walkUntil(node, fn, function (nextNode) {
591
631
  return nextNode === untilNode;
592
632
  }, arg);
593
633
  }
594
634
 
595
635
  function StableRange(range) {
636
+ if (!range) {
637
+ return;
638
+ }
596
639
  this.startContainer = range.startContainer;
597
640
  this.startOffset = range.startOffset;
598
641
  this.endContainer = range.endContainer;
@@ -710,6 +753,109 @@ define([
710
753
  });
711
754
  }
712
755
 
756
+ function areRangesEq(a, b) {
757
+ return a.startContainer === b.startContainer
758
+ && a.startOffset === b.startOffset
759
+ && a.endContainer === b.endContainer
760
+ && a.endOffset === b.endOffset;
761
+ }
762
+
763
+ function insertSelectText(text, range) {
764
+ // Because empty text nodes are generally not nice and even
765
+ // cause problems with IE8 (elem.childNodes).
766
+ if (!text.length) {
767
+ return;
768
+ }
769
+ splitTextNodeAdjustRange(range.startContainer, range.startOffset, range);
770
+ var node = nodeAtOffset(range.startContainer, range.startOffset);
771
+ var atEnd = isAtEnd(range.startContainer, range.startOffset);
772
+ // Because if the node following the insert position is already
773
+ // a text node we can just reuse it.
774
+ if (!atEnd && 3 === node.nodeType) {
775
+ node.insertData(0, text);
776
+ range.setStart(node, 0);
777
+ range.setEnd(node, text.length);
778
+ return;
779
+ }
780
+ // Because if the node preceding the insert position is already
781
+ // a text node we can just reuse it.
782
+ var prev;
783
+ if (!atEnd) {
784
+ prev = node.previousSibling;
785
+ } else {
786
+ prev = node.lastChild;
787
+ }
788
+ if (prev && 3 === prev.nodeType) {
789
+ prev.insertData(prev.length, text);
790
+ range.setStart(prev, prev.length - text.length);
791
+ range.setEnd(prev, prev.length);
792
+ return;
793
+ }
794
+ // Because if we can't reuse any text nodes, we have to insert a
795
+ // new one.
796
+ var textNode = document.createTextNode(text);
797
+ insert(textNode, node, atEnd);
798
+ range.setStart(textNode, 0);
799
+ range.setEnd(textNode, textNode.length);
800
+ }
801
+
802
+ function collapseToEnd(range) {
803
+ range.setStart(range.endContainer, range.endOffset);
804
+ }
805
+
806
+ function rangeFromRangeObject(alohaRange) {
807
+ var range = Aloha.createRange();
808
+ range.setStart(alohaRange.startContainer, alohaRange.startOffset);
809
+ range.setEnd(alohaRange.endContainer, alohaRange.endOffset);
810
+ return range;
811
+ }
812
+
813
+ function extendToWord(range) {
814
+ var rangeObject = new RangeObject(range);
815
+ Dom1.extendToWord(rangeObject);
816
+ setRangeFromRef(range, rangeObject);
817
+ }
818
+
819
+ function cloneShallow(node) {
820
+ return node.cloneNode(false);
821
+ }
822
+
823
+ /**
824
+ * Sets a style on the given element by modifying it's style attribute.
825
+ */
826
+ function setStyle(node, name, value) {
827
+ // Because only the empty string removes a style.
828
+ $(node).css(name, null == value ? '' : value);
829
+ }
830
+
831
+ /**
832
+ * Gets a style from the given element's style attribute.
833
+ * Note that this is different from the computed/inherited style.
834
+ */
835
+ function getStyle(node, name) {
836
+ // Because IE7 needs dashesToCamelCase().
837
+ name = Strings.dashesToCamelCase(name);
838
+ return node.nodeType === 1 ? node.style[name] : null;
839
+ }
840
+
841
+ /**
842
+ * Gets the computed/inherited style of the given node.
843
+ * @param node may be a text node.
844
+ */
845
+ function getComputedStyle(node, name) {
846
+ if (node.currentStyle) {
847
+ return node.currentStyle[name];
848
+ }
849
+ var doc = node.ownerDocument;
850
+ if (doc.defaultView && doc.defaultView.getComputedStyle) {
851
+ var styles = doc.defaultView.getComputedStyle(node, null);
852
+ if (styles) {
853
+ return styles[name] || styles.getPropertyValue(name);
854
+ }
855
+ }
856
+ return null;
857
+ }
858
+
713
859
  return {
714
860
  moveNextAll: moveNextAll,
715
861
  attrNames: attrNames,
@@ -718,7 +864,7 @@ define([
718
864
  indexByName: indexByName,
719
865
  indexByClassHaveList: indexByClassHaveList,
720
866
  outerHtml: outerHtml,
721
- shallowRemove: shallowRemove,
867
+ removeShallow: removeShallow,
722
868
  wrap: wrap,
723
869
  insert: insert,
724
870
  cursor: cursor,
@@ -731,6 +877,9 @@ define([
731
877
  childAndParentsUntilIncl: childAndParentsUntilIncl,
732
878
  childAndParentsUntilNode: childAndParentsUntilNode,
733
879
  childAndParentsUntilInclNode: childAndParentsUntilInclNode,
880
+ next: next,
881
+ parent: parent,
882
+ isTextNode: isTextNode,
734
883
  nodeIndex: nodeIndex,
735
884
  splitTextNode: splitTextNode,
736
885
  splitTextContainers: splitTextContainers,
@@ -743,6 +892,16 @@ define([
743
892
  trimRangeClosingOpening: trimRangeClosingOpening,
744
893
  setRangeFromRef: setRangeFromRef,
745
894
  setRangeStartFromCursor: setRangeStartFromCursor,
746
- setRangeEndFromCursor: setRangeEndFromCursor
895
+ setRangeEndFromCursor: setRangeEndFromCursor,
896
+ splitTextNodeAdjustRange: splitTextNodeAdjustRange,
897
+ insertSelectText: insertSelectText,
898
+ areRangesEq: areRangesEq,
899
+ collapseToEnd: collapseToEnd,
900
+ extendToWord: extendToWord,
901
+ rangeFromRangeObject: rangeFromRangeObject,
902
+ cloneShallow: cloneShallow,
903
+ setStyle: setStyle,
904
+ getStyle: getStyle,
905
+ getComputedStyle: getComputedStyle
747
906
  };
748
907
  });