-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
132 lines (108 loc) · 3.55 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* Module dependencies.
*/
var uid = require('component-uid');
var getDocument = require('get-document');
var insertNode = require('range-insert-node');
var debug = require('debug')('save-range');
/**
* Module exports.
*/
exports = module.exports = save;
exports.save = save;
exports.load = load;
/**
* Saves the start and end markers of the given `range` into the DOM for
* "revival" at a later point.
*
* @param {Range} range - DOM Range instance to "save"
* @return {Object} returns an opaque object that should be passed back to the
* `load()` function once you want to turn the DOM serialization back into a DOM
* Range instance.
* @public
*/
function save (range, doc) {
if (!doc) doc = getDocument(range) || document;
var parent = range.commonAncestorContainer;
// ensure that "parent" is not a TextNode
while (parent && parent.nodeType === 3 /* Node.TEXT_NODE */) {
parent = parent.parentNode;
}
var info = {
id: uid(8),
range: range,
document: doc,
parent: parent,
collapsed: Boolean(range.collapsed)
};
debug('generated id %o to save Range instance', info.id);
// end marker
var endRange = range.cloneRange();
endRange.collapse(false);
var endMarker = doc.createElement('span');
endMarker.className = 'save-range-marker ' + info.id + '-end';
debug('inserting "end marker" %o', endMarker);
insertNode(endRange, endMarker);
// start marker (if not `collapsed`)
if (info.collapsed) {
debug('skipping "start marker" because Range is `collapsed`');
} else {
var startNode = range.startContainer;
var startOffset = range.startOffset;
var startRange = range.cloneRange();
startRange.collapse(true);
var startMarker = doc.createElement('span');
startMarker.className = 'save-range-marker ' + info.id + '-start';
debug('inserting "start marker" %o', startMarker);
insertNode(startRange, startMarker);
if (startNode.nodeType === 3) {
if (startMarker.nextSibling) {
startNode = startMarker.nextSibling;
startOffset = 0;
} else if (startMarker.previousSibling) {
startNode = startMarker.previousSibling;
startOffset = startNode.nodeValue.length;
}
range.setStart(startNode, startOffset);
}
}
return info;
}
/**
* Restores a `range` instance with the given range `info` object returned from
* a prevous call to `save()`.
*
* @param {Object} info - the serialized Range info object returned from
* a previous `save()` call.
* @param {Element} [parent] - Optional explicit `parent` DOM element to check for
* the DOM markers inside of.
* @return {Range} return a Range instance with its boundaries set to the original
* points from the `save()` call.
* @public
*/
function load (info, parent) {
var range = info.range;
if (!parent) parent = info.parent || info.document;
debug('loading Range using parent %o', parent);
var end = parent.getElementsByClassName(info.id + '-end')[0];
if (end) {
range.setEndAfter(end);
} else {
debug('could not find DOM marker with class name %o', info.id + '-end');
}
if (info.collapsed) {
if (end) range.setStartBefore(end);
} else {
var start = parent.getElementsByClassName(info.id + '-start')[0];
if (start) {
range.setStartBefore(start);
// remove "start marker" from the DOM
start.parentNode.removeChild(start);
} else {
debug('could not find DOM marker with class name %o', info.id + '-start');
}
}
// remove "end marker" from the DOM
if (end) end.parentNode.removeChild(end);
return range;
}