locomotive-aloha-rails 0.23.2.1 → 0.23.2.2

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