[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/editor/atto/yui/src/rangy/js/ -> rangy-serializer.js (source)

   1  /**

   2   * @license Serializer module for Rangy.

   3   * Serializes Ranges and Selections. An example use would be to store a user's selection on a particular page in a

   4   * cookie or local storage and restore it on the user's next visit to the same page.

   5   *

   6   * Part of Rangy, a cross-browser JavaScript range and selection library

   7   * http://code.google.com/p/rangy/

   8   *

   9   * Depends on Rangy core.

  10   *

  11   * Copyright 2012, Tim Down

  12   * Licensed under the MIT license.

  13   * Version: 1.2.3

  14   * Build date: 26 February 2012

  15   */
  16  rangy.createModule("Serializer", function(api, module) {
  17      api.requireModules( ["WrappedSelection", "WrappedRange"] );
  18      var UNDEF = "undefined";
  19  
  20      // encodeURIComponent and decodeURIComponent are required for cookie handling

  21      if (typeof encodeURIComponent == UNDEF || typeof decodeURIComponent == UNDEF) {
  22          module.fail("Global object is missing encodeURIComponent and/or decodeURIComponent method");
  23      }
  24  
  25      // Checksum for checking whether range can be serialized

  26      var crc32 = (function() {
  27          function utf8encode(str) {
  28              var utf8CharCodes = [];
  29  
  30              for (var i = 0, len = str.length, c; i < len; ++i) {
  31                  c = str.charCodeAt(i);
  32                  if (c < 128) {
  33                      utf8CharCodes.push(c);
  34                  } else if (c < 2048) {
  35                      utf8CharCodes.push((c >> 6) | 192, (c & 63) | 128);
  36                  } else {
  37                      utf8CharCodes.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128);
  38                  }
  39              }
  40              return utf8CharCodes;
  41          }
  42  
  43          var cachedCrcTable = null;
  44  
  45          function buildCRCTable() {
  46              var table = [];
  47              for (var i = 0, j, crc; i < 256; ++i) {
  48                  crc = i;
  49                  j = 8;
  50                  while (j--) {
  51                      if ((crc & 1) == 1) {
  52                          crc = (crc >>> 1) ^ 0xEDB88320;
  53                      } else {
  54                          crc >>>= 1;
  55                      }
  56                  }
  57                  table[i] = crc >>> 0;
  58              }
  59              return table;
  60          }
  61  
  62          function getCrcTable() {
  63              if (!cachedCrcTable) {
  64                  cachedCrcTable = buildCRCTable();
  65              }
  66              return cachedCrcTable;
  67          }
  68  
  69          return function(str) {
  70              var utf8CharCodes = utf8encode(str), crc = -1, crcTable = getCrcTable();
  71              for (var i = 0, len = utf8CharCodes.length, y; i < len; ++i) {
  72                  y = (crc ^ utf8CharCodes[i]) & 0xFF;
  73                  crc = (crc >>> 8) ^ crcTable[y];
  74              }
  75              return (crc ^ -1) >>> 0;
  76          };
  77      })();
  78  
  79      var dom = api.dom;
  80  
  81      function escapeTextForHtml(str) {
  82          return str.replace(/</g, "&lt;").replace(/>/g, "&gt;");
  83      }
  84  
  85      function nodeToInfoString(node, infoParts) {
  86          infoParts = infoParts || [];
  87          var nodeType = node.nodeType, children = node.childNodes, childCount = children.length;
  88          var nodeInfo = [nodeType, node.nodeName, childCount].join(":");
  89          var start = "", end = "";
  90          switch (nodeType) {
  91              case 3: // Text node
  92                  start = escapeTextForHtml(node.nodeValue);
  93                  break;
  94              case 8: // Comment
  95                  start = "<!--" + escapeTextForHtml(node.nodeValue) + "-->";
  96                  break;
  97              default:
  98                  start = "<" + nodeInfo + ">";
  99                  end = "</>";
 100                  break;
 101          }
 102          if (start) {
 103              infoParts.push(start);
 104          }
 105          for (var i = 0; i < childCount; ++i) {
 106              nodeToInfoString(children[i], infoParts);
 107          }
 108          if (end) {
 109              infoParts.push(end);
 110          }
 111          return infoParts;
 112      }
 113  
 114      // Creates a string representation of the specified element's contents that is similar to innerHTML but omits all

 115      // attributes and comments and includes child node counts. This is done instead of using innerHTML to work around

 116      // IE <= 8's policy of including element properties in attributes, which ruins things by changing an element's

 117      // innerHTML whenever the user changes an input within the element.

 118      function getElementChecksum(el) {
 119          var info = nodeToInfoString(el).join("");
 120          return crc32(info).toString(16);
 121      }
 122  
 123      function serializePosition(node, offset, rootNode) {
 124          var pathBits = [], n = node;
 125          rootNode = rootNode || dom.getDocument(node).documentElement;
 126          while (n && n != rootNode) {
 127              pathBits.push(dom.getNodeIndex(n, true));
 128              n = n.parentNode;
 129          }
 130          return pathBits.join("/") + ":" + offset;
 131      }
 132  
 133      function deserializePosition(serialized, rootNode, doc) {
 134          if (rootNode) {
 135              doc = doc || dom.getDocument(rootNode);
 136          } else {
 137              doc = doc || document;
 138              rootNode = doc.documentElement;
 139          }
 140          var bits = serialized.split(":");
 141          var node = rootNode;
 142          var nodeIndices = bits[0] ? bits[0].split("/") : [], i = nodeIndices.length, nodeIndex;
 143  
 144          while (i--) {
 145              nodeIndex = parseInt(nodeIndices[i], 10);
 146              if (nodeIndex < node.childNodes.length) {
 147                  node = node.childNodes[parseInt(nodeIndices[i], 10)];
 148              } else {
 149                  throw module.createError("deserializePosition failed: node " + dom.inspectNode(node) +
 150                          " has no child with index " + nodeIndex + ", " + i);
 151              }
 152          }
 153  
 154          return new dom.DomPosition(node, parseInt(bits[1], 10));
 155      }
 156  
 157      function serializeRange(range, omitChecksum, rootNode) {
 158          rootNode = rootNode || api.DomRange.getRangeDocument(range).documentElement;
 159          if (!dom.isAncestorOf(rootNode, range.commonAncestorContainer, true)) {
 160              throw new Error("serializeRange: range is not wholly contained within specified root node");
 161          }
 162          var serialized = serializePosition(range.startContainer, range.startOffset, rootNode) + "," +
 163              serializePosition(range.endContainer, range.endOffset, rootNode);
 164          if (!omitChecksum) {
 165              serialized += "{" + getElementChecksum(rootNode) + "}";
 166          }
 167          return serialized;
 168      }
 169  
 170      function deserializeRange(serialized, rootNode, doc) {
 171          if (rootNode) {
 172              doc = doc || dom.getDocument(rootNode);
 173          } else {
 174              doc = doc || document;
 175              rootNode = doc.documentElement;
 176          }
 177          var result = /^([^,]+),([^,\{]+)({([^}]+)})?$/.exec(serialized);
 178          var checksum = result[4], rootNodeChecksum = getElementChecksum(rootNode);
 179          if (checksum && checksum !== getElementChecksum(rootNode)) {
 180              throw new Error("deserializeRange: checksums of serialized range root node (" + checksum +
 181                      ") and target root node (" + rootNodeChecksum + ") do not match");
 182          }
 183          var start = deserializePosition(result[1], rootNode, doc), end = deserializePosition(result[2], rootNode, doc);
 184          var range = api.createRange(doc);
 185          range.setStart(start.node, start.offset);
 186          range.setEnd(end.node, end.offset);
 187          return range;
 188      }
 189  
 190      function canDeserializeRange(serialized, rootNode, doc) {
 191          if (rootNode) {
 192              doc = doc || dom.getDocument(rootNode);
 193          } else {
 194              doc = doc || document;
 195              rootNode = doc.documentElement;
 196          }
 197          var result = /^([^,]+),([^,]+)({([^}]+)})?$/.exec(serialized);
 198          var checksum = result[3];
 199          return !checksum || checksum === getElementChecksum(rootNode);
 200      }
 201  
 202      function serializeSelection(selection, omitChecksum, rootNode) {
 203          selection = selection || api.getSelection();
 204          var ranges = selection.getAllRanges(), serializedRanges = [];
 205          for (var i = 0, len = ranges.length; i < len; ++i) {
 206              serializedRanges[i] = serializeRange(ranges[i], omitChecksum, rootNode);
 207          }
 208          return serializedRanges.join("|");
 209      }
 210  
 211      function deserializeSelection(serialized, rootNode, win) {
 212          if (rootNode) {
 213              win = win || dom.getWindow(rootNode);
 214          } else {
 215              win = win || window;
 216              rootNode = win.document.documentElement;
 217          }
 218          var serializedRanges = serialized.split("|");
 219          var sel = api.getSelection(win);
 220          var ranges = [];
 221  
 222          for (var i = 0, len = serializedRanges.length; i < len; ++i) {
 223              ranges[i] = deserializeRange(serializedRanges[i], rootNode, win.document);
 224          }
 225          sel.setRanges(ranges);
 226  
 227          return sel;
 228      }
 229  
 230      function canDeserializeSelection(serialized, rootNode, win) {
 231          var doc;
 232          if (rootNode) {
 233              doc = win ? win.document : dom.getDocument(rootNode);
 234          } else {
 235              win = win || window;
 236              rootNode = win.document.documentElement;
 237          }
 238          var serializedRanges = serialized.split("|");
 239  
 240          for (var i = 0, len = serializedRanges.length; i < len; ++i) {
 241              if (!canDeserializeRange(serializedRanges[i], rootNode, doc)) {
 242                  return false;
 243              }
 244          }
 245  
 246          return true;
 247      }
 248  
 249  
 250      var cookieName = "rangySerializedSelection";
 251  
 252      function getSerializedSelectionFromCookie(cookie) {
 253          var parts = cookie.split(/[;,]/);
 254          for (var i = 0, len = parts.length, nameVal, val; i < len; ++i) {
 255              nameVal = parts[i].split("=");
 256              if (nameVal[0].replace(/^\s+/, "") == cookieName) {
 257                  val = nameVal[1];
 258                  if (val) {
 259                      return decodeURIComponent(val.replace(/\s+$/, ""));
 260                  }
 261              }
 262          }
 263          return null;
 264      }
 265  
 266      function restoreSelectionFromCookie(win) {
 267          win = win || window;
 268          var serialized = getSerializedSelectionFromCookie(win.document.cookie);
 269          if (serialized) {
 270              deserializeSelection(serialized, win.doc)
 271          }
 272      }
 273  
 274      function saveSelectionCookie(win, props) {
 275          win = win || window;
 276          props = (typeof props == "object") ? props : {};
 277          var expires = props.expires ? ";expires=" + props.expires.toUTCString() : "";
 278          var path = props.path ? ";path=" + props.path : "";
 279          var domain = props.domain ? ";domain=" + props.domain : "";
 280          var secure = props.secure ? ";secure" : "";
 281          var serialized = serializeSelection(api.getSelection(win));
 282          win.document.cookie = encodeURIComponent(cookieName) + "=" + encodeURIComponent(serialized) + expires + path + domain + secure;
 283      }
 284  
 285      api.serializePosition = serializePosition;
 286      api.deserializePosition = deserializePosition;
 287  
 288      api.serializeRange = serializeRange;
 289      api.deserializeRange = deserializeRange;
 290      api.canDeserializeRange = canDeserializeRange;
 291  
 292      api.serializeSelection = serializeSelection;
 293      api.deserializeSelection = deserializeSelection;
 294      api.canDeserializeSelection = canDeserializeSelection;
 295  
 296      api.restoreSelectionFromCookie = restoreSelectionFromCookie;
 297      api.saveSelectionCookie = saveSelectionCookie;
 298  
 299      api.getElementChecksum = getElementChecksum;
 300  });


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1