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