[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 /** 2 * @license Selection save and restore module for Rangy. 3 * Saves and restores user selections using marker invisible elements in the DOM. 4 * 5 * Part of Rangy, a cross-browser JavaScript range and selection library 6 * http://code.google.com/p/rangy/ 7 * 8 * Depends on Rangy core. 9 * 10 * Copyright 2012, Tim Down 11 * Licensed under the MIT license. 12 * Version: 1.2.3 13 * Build date: 26 February 2012 14 */ 15 rangy.createModule("SaveRestore", function(api, module) { 16 api.requireModules( ["DomUtil", "DomRange", "WrappedRange"] ); 17 18 var dom = api.dom; 19 20 var markerTextChar = "\ufeff"; 21 22 function gEBI(id, doc) { 23 return (doc || document).getElementById(id); 24 } 25 26 function insertRangeBoundaryMarker(range, atStart) { 27 var markerId = "selectionBoundary_" + (+new Date()) + "_" + ("" + Math.random()).slice(2); 28 var markerEl; 29 var doc = dom.getDocument(range.startContainer); 30 31 // Clone the Range and collapse to the appropriate boundary point 32 var boundaryRange = range.cloneRange(); 33 boundaryRange.collapse(atStart); 34 35 // Create the marker element containing a single invisible character using DOM methods and insert it 36 markerEl = doc.createElement("span"); 37 markerEl.id = markerId; 38 markerEl.style.lineHeight = "0"; 39 markerEl.style.display = "none"; 40 markerEl.className = "rangySelectionBoundary"; 41 markerEl.appendChild(doc.createTextNode(markerTextChar)); 42 43 boundaryRange.insertNode(markerEl); 44 boundaryRange.detach(); 45 return markerEl; 46 } 47 48 function setRangeBoundary(doc, range, markerId, atStart) { 49 var markerEl = gEBI(markerId, doc); 50 if (markerEl) { 51 range[atStart ? "setStartBefore" : "setEndBefore"](markerEl); 52 markerEl.parentNode.removeChild(markerEl); 53 } else { 54 module.warn("Marker element has been removed. Cannot restore selection."); 55 } 56 } 57 58 function compareRanges(r1, r2) { 59 return r2.compareBoundaryPoints(r1.START_TO_START, r1); 60 } 61 62 function saveSelection(win) { 63 win = win || window; 64 var doc = win.document; 65 if (!api.isSelectionValid(win)) { 66 module.warn("Cannot save selection. This usually happens when the selection is collapsed and the selection document has lost focus."); 67 return; 68 } 69 var sel = api.getSelection(win); 70 var ranges = sel.getAllRanges(); 71 var rangeInfos = [], startEl, endEl, range; 72 73 // Order the ranges by position within the DOM, latest first 74 ranges.sort(compareRanges); 75 76 for (var i = 0, len = ranges.length; i < len; ++i) { 77 range = ranges[i]; 78 if (range.collapsed) { 79 endEl = insertRangeBoundaryMarker(range, false); 80 rangeInfos.push({ 81 markerId: endEl.id, 82 collapsed: true 83 }); 84 } else { 85 endEl = insertRangeBoundaryMarker(range, false); 86 startEl = insertRangeBoundaryMarker(range, true); 87 88 rangeInfos[i] = { 89 startMarkerId: startEl.id, 90 endMarkerId: endEl.id, 91 collapsed: false, 92 backwards: ranges.length == 1 && sel.isBackwards() 93 }; 94 } 95 } 96 97 // Now that all the markers are in place and DOM manipulation over, adjust each range's boundaries to lie 98 // between its markers 99 for (i = len - 1; i >= 0; --i) { 100 range = ranges[i]; 101 if (range.collapsed) { 102 range.collapseBefore(gEBI(rangeInfos[i].markerId, doc)); 103 } else { 104 range.setEndBefore(gEBI(rangeInfos[i].endMarkerId, doc)); 105 range.setStartAfter(gEBI(rangeInfos[i].startMarkerId, doc)); 106 } 107 } 108 109 // Ensure current selection is unaffected 110 sel.setRanges(ranges); 111 return { 112 win: win, 113 doc: doc, 114 rangeInfos: rangeInfos, 115 restored: false 116 }; 117 } 118 119 function restoreSelection(savedSelection, preserveDirection) { 120 if (!savedSelection.restored) { 121 var rangeInfos = savedSelection.rangeInfos; 122 var sel = api.getSelection(savedSelection.win); 123 var ranges = []; 124 125 // Ranges are in reverse order of appearance in the DOM. We want to restore earliest first to avoid 126 // normalization affecting previously restored ranges. 127 for (var len = rangeInfos.length, i = len - 1, rangeInfo, range; i >= 0; --i) { 128 rangeInfo = rangeInfos[i]; 129 range = api.createRange(savedSelection.doc); 130 if (rangeInfo.collapsed) { 131 var markerEl = gEBI(rangeInfo.markerId, savedSelection.doc); 132 if (markerEl) { 133 markerEl.style.display = "inline"; 134 var previousNode = markerEl.previousSibling; 135 136 // Workaround for issue 17 137 if (previousNode && previousNode.nodeType == 3) { 138 markerEl.parentNode.removeChild(markerEl); 139 range.collapseToPoint(previousNode, previousNode.length); 140 } else { 141 range.collapseBefore(markerEl); 142 markerEl.parentNode.removeChild(markerEl); 143 } 144 } else { 145 module.warn("Marker element has been removed. Cannot restore selection."); 146 } 147 } else { 148 setRangeBoundary(savedSelection.doc, range, rangeInfo.startMarkerId, true); 149 setRangeBoundary(savedSelection.doc, range, rangeInfo.endMarkerId, false); 150 } 151 152 // Normalizing range boundaries is only viable if the selection contains only one range. For example, 153 // if the selection contained two ranges that were both contained within the same single text node, 154 // both would alter the same text node when restoring and break the other range. 155 if (len == 1) { 156 range.normalizeBoundaries(); 157 } 158 ranges[i] = range; 159 } 160 if (len == 1 && preserveDirection && api.features.selectionHasExtend && rangeInfos[0].backwards) { 161 sel.removeAllRanges(); 162 sel.addRange(ranges[0], true); 163 } else { 164 sel.setRanges(ranges); 165 } 166 167 savedSelection.restored = true; 168 } 169 } 170 171 function removeMarkerElement(doc, markerId) { 172 var markerEl = gEBI(markerId, doc); 173 if (markerEl) { 174 markerEl.parentNode.removeChild(markerEl); 175 } 176 } 177 178 function removeMarkers(savedSelection) { 179 var rangeInfos = savedSelection.rangeInfos; 180 for (var i = 0, len = rangeInfos.length, rangeInfo; i < len; ++i) { 181 rangeInfo = rangeInfos[i]; 182 if (rangeInfo.collapsed) { 183 removeMarkerElement(savedSelection.doc, rangeInfo.markerId); 184 } else { 185 removeMarkerElement(savedSelection.doc, rangeInfo.startMarkerId); 186 removeMarkerElement(savedSelection.doc, rangeInfo.endMarkerId); 187 } 188 } 189 } 190 191 api.saveSelection = saveSelection; 192 api.restoreSelection = restoreSelection; 193 api.removeMarkerElement = removeMarkerElement; 194 api.removeMarkers = removeMarkers; 195 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |