X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff..269195b3729c1bdc22e9053ee4ebca667ea8549d:/Android/webViewMarker/src/main/assets/rangy-serializer.js diff --git a/Android/webViewMarker/src/main/assets/rangy-serializer.js b/Android/webViewMarker/src/main/assets/rangy-serializer.js new file mode 100755 index 0000000..79edc13 --- /dev/null +++ b/Android/webViewMarker/src/main/assets/rangy-serializer.js @@ -0,0 +1,300 @@ +/** + * @license Serializer module for Rangy. + * Serializes Ranges and Selections. An example use would be to store a user's selection on a particular page in a + * cookie or local storage and restore it on the user's next visit to the same page. + * + * Part of Rangy, a cross-browser JavaScript range and selection library + * http://code.google.com/p/rangy/ + * + * Depends on Rangy core. + * + * Copyright 2012, Tim Down + * Licensed under the MIT license. + * Version: 1.2.3 + * Build date: 26 February 2012 + */ +rangy.createModule("Serializer", function(api, module) { + api.requireModules( ["WrappedSelection", "WrappedRange"] ); + var UNDEF = "undefined"; + + // encodeURIComponent and decodeURIComponent are required for cookie handling + if (typeof encodeURIComponent == UNDEF || typeof decodeURIComponent == UNDEF) { + module.fail("Global object is missing encodeURIComponent and/or decodeURIComponent method"); + } + + // Checksum for checking whether range can be serialized + var crc32 = (function() { + function utf8encode(str) { + var utf8CharCodes = []; + + for (var i = 0, len = str.length, c; i < len; ++i) { + c = str.charCodeAt(i); + if (c < 128) { + utf8CharCodes.push(c); + } else if (c < 2048) { + utf8CharCodes.push((c >> 6) | 192, (c & 63) | 128); + } else { + utf8CharCodes.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128); + } + } + return utf8CharCodes; + } + + var cachedCrcTable = null; + + function buildCRCTable() { + var table = []; + for (var i = 0, j, crc; i < 256; ++i) { + crc = i; + j = 8; + while (j--) { + if ((crc & 1) == 1) { + crc = (crc >>> 1) ^ 0xEDB88320; + } else { + crc >>>= 1; + } + } + table[i] = crc >>> 0; + } + return table; + } + + function getCrcTable() { + if (!cachedCrcTable) { + cachedCrcTable = buildCRCTable(); + } + return cachedCrcTable; + } + + return function(str) { + var utf8CharCodes = utf8encode(str), crc = -1, crcTable = getCrcTable(); + for (var i = 0, len = utf8CharCodes.length, y; i < len; ++i) { + y = (crc ^ utf8CharCodes[i]) & 0xFF; + crc = (crc >>> 8) ^ crcTable[y]; + } + return (crc ^ -1) >>> 0; + }; + })(); + + var dom = api.dom; + + function escapeTextForHtml(str) { + return str.replace(//g, ">"); + } + + function nodeToInfoString(node, infoParts) { + infoParts = infoParts || []; + var nodeType = node.nodeType, children = node.childNodes, childCount = children.length; + var nodeInfo = [nodeType, node.nodeName, childCount].join(":"); + var start = "", end = ""; + switch (nodeType) { + case 3: // Text node + start = escapeTextForHtml(node.nodeValue); + break; + case 8: // Comment + start = ""; + break; + default: + start = "<" + nodeInfo + ">"; + end = ""; + break; + } + if (start) { + infoParts.push(start); + } + for (var i = 0; i < childCount; ++i) { + nodeToInfoString(children[i], infoParts); + } + if (end) { + infoParts.push(end); + } + return infoParts; + } + + // Creates a string representation of the specified element's contents that is similar to innerHTML but omits all + // attributes and comments and includes child node counts. This is done instead of using innerHTML to work around + // IE <= 8's policy of including element properties in attributes, which ruins things by changing an element's + // innerHTML whenever the user changes an input within the element. + function getElementChecksum(el) { + var info = nodeToInfoString(el).join(""); + return crc32(info).toString(16); + } + + function serializePosition(node, offset, rootNode) { + var pathBits = [], n = node; + rootNode = rootNode || dom.getDocument(node).documentElement; + while (n && n != rootNode) { + pathBits.push(dom.getNodeIndex(n, true)); + n = n.parentNode; + } + return pathBits.join("/") + ":" + offset; + } + + function deserializePosition(serialized, rootNode, doc) { + if (rootNode) { + doc = doc || dom.getDocument(rootNode); + } else { + doc = doc || document; + rootNode = doc.documentElement; + } + var bits = serialized.split(":"); + var node = rootNode; + var nodeIndices = bits[0] ? bits[0].split("/") : [], i = nodeIndices.length, nodeIndex; + + while (i--) { + nodeIndex = parseInt(nodeIndices[i], 10); + if (nodeIndex < node.childNodes.length) { + node = node.childNodes[parseInt(nodeIndices[i], 10)]; + } else { + throw module.createError("deserializePosition failed: node " + dom.inspectNode(node) + + " has no child with index " + nodeIndex + ", " + i); + } + } + + return new dom.DomPosition(node, parseInt(bits[1], 10)); + } + + function serializeRange(range, omitChecksum, rootNode) { + rootNode = rootNode || api.DomRange.getRangeDocument(range).documentElement; + if (!dom.isAncestorOf(rootNode, range.commonAncestorContainer, true)) { + throw new Error("serializeRange: range is not wholly contained within specified root node"); + } + var serialized = serializePosition(range.startContainer, range.startOffset, rootNode) + "," + + serializePosition(range.endContainer, range.endOffset, rootNode); + if (!omitChecksum) { + serialized += "{" + getElementChecksum(rootNode) + "}"; + } + return serialized; + } + + function deserializeRange(serialized, rootNode, doc) { + if (rootNode) { + doc = doc || dom.getDocument(rootNode); + } else { + doc = doc || document; + rootNode = doc.documentElement; + } + var result = /^([^,]+),([^,\{]+)({([^}]+)})?$/.exec(serialized); + var checksum = result[4], rootNodeChecksum = getElementChecksum(rootNode); + if (checksum && checksum !== getElementChecksum(rootNode)) { + throw new Error("deserializeRange: checksums of serialized range root node (" + checksum + + ") and target root node (" + rootNodeChecksum + ") do not match"); + } + var start = deserializePosition(result[1], rootNode, doc), end = deserializePosition(result[2], rootNode, doc); + var range = api.createRange(doc); + range.setStart(start.node, start.offset); + range.setEnd(end.node, end.offset); + return range; + } + + function canDeserializeRange(serialized, rootNode, doc) { + if (rootNode) { + doc = doc || dom.getDocument(rootNode); + } else { + doc = doc || document; + rootNode = doc.documentElement; + } + var result = /^([^,]+),([^,]+)({([^}]+)})?$/.exec(serialized); + var checksum = result[3]; + return !checksum || checksum === getElementChecksum(rootNode); + } + + function serializeSelection(selection, omitChecksum, rootNode) { + selection = selection || api.getSelection(); + var ranges = selection.getAllRanges(), serializedRanges = []; + for (var i = 0, len = ranges.length; i < len; ++i) { + serializedRanges[i] = serializeRange(ranges[i], omitChecksum, rootNode); + } + return serializedRanges.join("|"); + } + + function deserializeSelection(serialized, rootNode, win) { + if (rootNode) { + win = win || dom.getWindow(rootNode); + } else { + win = win || window; + rootNode = win.document.documentElement; + } + var serializedRanges = serialized.split("|"); + var sel = api.getSelection(win); + var ranges = []; + + for (var i = 0, len = serializedRanges.length; i < len; ++i) { + ranges[i] = deserializeRange(serializedRanges[i], rootNode, win.document); + } + sel.setRanges(ranges); + + return sel; + } + + function canDeserializeSelection(serialized, rootNode, win) { + var doc; + if (rootNode) { + doc = win ? win.document : dom.getDocument(rootNode); + } else { + win = win || window; + rootNode = win.document.documentElement; + } + var serializedRanges = serialized.split("|"); + + for (var i = 0, len = serializedRanges.length; i < len; ++i) { + if (!canDeserializeRange(serializedRanges[i], rootNode, doc)) { + return false; + } + } + + return true; + } + + + var cookieName = "rangySerializedSelection"; + + function getSerializedSelectionFromCookie(cookie) { + var parts = cookie.split(/[;,]/); + for (var i = 0, len = parts.length, nameVal, val; i < len; ++i) { + nameVal = parts[i].split("="); + if (nameVal[0].replace(/^\s+/, "") == cookieName) { + val = nameVal[1]; + if (val) { + return decodeURIComponent(val.replace(/\s+$/, "")); + } + } + } + return null; + } + + function restoreSelectionFromCookie(win) { + win = win || window; + var serialized = getSerializedSelectionFromCookie(win.document.cookie); + if (serialized) { + deserializeSelection(serialized, win.doc) + } + } + + function saveSelectionCookie(win, props) { + win = win || window; + props = (typeof props == "object") ? props : {}; + var expires = props.expires ? ";expires=" + props.expires.toUTCString() : ""; + var path = props.path ? ";path=" + props.path : ""; + var domain = props.domain ? ";domain=" + props.domain : ""; + var secure = props.secure ? ";secure" : ""; + var serialized = serializeSelection(api.getSelection(win)); + win.document.cookie = encodeURIComponent(cookieName) + "=" + encodeURIComponent(serialized) + expires + path + domain + secure; + } + + api.serializePosition = serializePosition; + api.deserializePosition = deserializePosition; + + api.serializeRange = serializeRange; + api.deserializeRange = deserializeRange; + api.canDeserializeRange = canDeserializeRange; + + api.serializeSelection = serializeSelection; + api.deserializeSelection = deserializeSelection; + api.canDeserializeSelection = canDeserializeSelection; + + api.restoreSelectionFromCookie = restoreSelectionFromCookie; + api.saveSelectionCookie = saveSelectionCookie; + + api.getElementChecksum = getElementChecksum; +});