[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

   1  /**

   2   * 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   * https://github.com/timdown/rangy

   8   *

   9   * Depends on Rangy core.

  10   *

  11   * Copyright 2015, Tim Down

  12   * Licensed under the MIT license.

  13   * Version: 1.3.0

  14   * Build date: 10 May 2015

  15   */
  16  (function(factory, root) {
  17      // No AMD or CommonJS support so we use the rangy property of root (probably the global variable)
  18      factory(root.rangy);
  19  })(function(rangy) {
  20      rangy.createModule("Serializer", ["WrappedSelection"], function(api, module) {
  21          var UNDEF = "undefined";
  22          var util = api.util;
  23  
  24          // encodeURIComponent and decodeURIComponent are required for cookie handling
  25          if (typeof encodeURIComponent == UNDEF || typeof decodeURIComponent == UNDEF) {
  26              module.fail("encodeURIComponent and/or decodeURIComponent method is missing");
  27          }
  28  
  29          // Checksum for checking whether range can be serialized
  30          var crc32 = (function() {
  31              function utf8encode(str) {
  32                  var utf8CharCodes = [];
  33  
  34                  for (var i = 0, len = str.length, c; i < len; ++i) {
  35                      c = str.charCodeAt(i);
  36                      if (c < 128) {
  37                          utf8CharCodes.push(c);
  38                      } else if (c < 2048) {
  39                          utf8CharCodes.push((c >> 6) | 192, (c & 63) | 128);
  40                      } else {
  41                          utf8CharCodes.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128);
  42                      }
  43                  }
  44                  return utf8CharCodes;
  45              }
  46  
  47              var cachedCrcTable = null;
  48  
  49              function buildCRCTable() {
  50                  var table = [];
  51                  for (var i = 0, j, crc; i < 256; ++i) {
  52                      crc = i;
  53                      j = 8;
  54                      while (j--) {
  55                          if ((crc & 1) == 1) {
  56                              crc = (crc >>> 1) ^ 0xEDB88320;
  57                          } else {
  58                              crc >>>= 1;
  59                          }
  60                      }
  61                      table[i] = crc >>> 0;
  62                  }
  63                  return table;
  64              }
  65  
  66              function getCrcTable() {
  67                  if (!cachedCrcTable) {
  68                      cachedCrcTable = buildCRCTable();
  69                  }
  70                  return cachedCrcTable;
  71              }
  72  
  73              return function(str) {
  74                  var utf8CharCodes = utf8encode(str), crc = -1, crcTable = getCrcTable();
  75                  for (var i = 0, len = utf8CharCodes.length, y; i < len; ++i) {
  76                      y = (crc ^ utf8CharCodes[i]) & 0xFF;
  77                      crc = (crc >>> 8) ^ crcTable[y];
  78                  }
  79                  return (crc ^ -1) >>> 0;
  80              };
  81          })();
  82  
  83          var dom = api.dom;
  84  
  85          function escapeTextForHtml(str) {
  86              return str.replace(/</g, "&lt;").replace(/>/g, "&gt;");
  87          }
  88  
  89          function nodeToInfoString(node, infoParts) {
  90              infoParts = infoParts || [];
  91              var nodeType = node.nodeType, children = node.childNodes, childCount = children.length;
  92              var nodeInfo = [nodeType, node.nodeName, childCount].join(":");
  93              var start = "", end = "";
  94              switch (nodeType) {
  95                  case 3: // Text node
  96                      start = escapeTextForHtml(node.nodeValue);
  97                      break;
  98                  case 8: // Comment
  99                      start = "<!--" + escapeTextForHtml(node.nodeValue) + "-->";
 100                      break;
 101                  default:
 102                      start = "<" + nodeInfo + ">";
 103                      end = "</>";
 104                      break;
 105              }
 106              if (start) {
 107                  infoParts.push(start);
 108              }
 109              for (var i = 0; i < childCount; ++i) {
 110                  nodeToInfoString(children[i], infoParts);
 111              }
 112              if (end) {
 113                  infoParts.push(end);
 114              }
 115              return infoParts;
 116          }
 117  
 118          // Creates a string representation of the specified element's contents that is similar to innerHTML but omits all
 119          // attributes and comments and includes child node counts. This is done instead of using innerHTML to work around
 120          // IE <= 8's policy of including element properties in attributes, which ruins things by changing an element's
 121          // innerHTML whenever the user changes an input within the element.
 122          function getElementChecksum(el) {
 123              var info = nodeToInfoString(el).join("");
 124              return crc32(info).toString(16);
 125          }
 126  
 127          function serializePosition(node, offset, rootNode) {
 128              var pathParts = [], n = node;
 129              rootNode = rootNode || dom.getDocument(node).documentElement;
 130              while (n && n != rootNode) {
 131                  pathParts.push(dom.getNodeIndex(n, true));
 132                  n = n.parentNode;
 133              }
 134              return pathParts.join("/") + ":" + offset;
 135          }
 136  
 137          function deserializePosition(serialized, rootNode, doc) {
 138              if (!rootNode) {
 139                  rootNode = (doc || document).documentElement;
 140              }
 141              var parts = serialized.split(":");
 142              var node = rootNode;
 143              var nodeIndices = parts[0] ? parts[0].split("/") : [], i = nodeIndices.length, nodeIndex;
 144  
 145              while (i--) {
 146                  nodeIndex = parseInt(nodeIndices[i], 10);
 147                  if (nodeIndex < node.childNodes.length) {
 148                      node = node.childNodes[nodeIndex];
 149                  } else {
 150                      throw module.createError("deserializePosition() failed: node " + dom.inspectNode(node) +
 151                              " has no child with index " + nodeIndex + ", " + i);
 152                  }
 153              }
 154  
 155              return new dom.DomPosition(node, parseInt(parts[1], 10));
 156          }
 157  
 158          function serializeRange(range, omitChecksum, rootNode) {
 159              rootNode = rootNode || api.DomRange.getRangeDocument(range).documentElement;
 160              if (!dom.isOrIsAncestorOf(rootNode, range.commonAncestorContainer)) {
 161                  throw module.createError("serializeRange(): range " + range.inspect() +
 162                      " is not wholly contained within specified root node " + dom.inspectNode(rootNode));
 163              }
 164              var serialized = serializePosition(range.startContainer, range.startOffset, rootNode) + "," +
 165                  serializePosition(range.endContainer, range.endOffset, rootNode);
 166              if (!omitChecksum) {
 167                  serialized += "{" + getElementChecksum(rootNode) + "}";
 168              }
 169              return serialized;
 170          }
 171  
 172          var deserializeRegex = /^([^,]+),([^,\{]+)(\{([^}]+)\})?$/;
 173  
 174          function deserializeRange(serialized, rootNode, doc) {
 175              if (rootNode) {
 176                  doc = doc || dom.getDocument(rootNode);
 177              } else {
 178                  doc = doc || document;
 179                  rootNode = doc.documentElement;
 180              }
 181              var result = deserializeRegex.exec(serialized);
 182              var checksum = result[4];
 183              if (checksum) {
 184                  var rootNodeChecksum = getElementChecksum(rootNode);
 185                  if (checksum !== rootNodeChecksum) {
 186                      throw module.createError("deserializeRange(): checksums of serialized range root node (" + checksum +
 187                          ") and target root node (" + rootNodeChecksum + ") do not match");
 188                  }
 189              }
 190              var start = deserializePosition(result[1], rootNode, doc), end = deserializePosition(result[2], rootNode, doc);
 191              var range = api.createRange(doc);
 192              range.setStartAndEnd(start.node, start.offset, end.node, end.offset);
 193              return range;
 194          }
 195  
 196          function canDeserializeRange(serialized, rootNode, doc) {
 197              if (!rootNode) {
 198                  rootNode = (doc || document).documentElement;
 199              }
 200              var result = deserializeRegex.exec(serialized);
 201              var checksum = result[3];
 202              return !checksum || checksum === getElementChecksum(rootNode);
 203          }
 204  
 205          function serializeSelection(selection, omitChecksum, rootNode) {
 206              selection = api.getSelection(selection);
 207              var ranges = selection.getAllRanges(), serializedRanges = [];
 208              for (var i = 0, len = ranges.length; i < len; ++i) {
 209                  serializedRanges[i] = serializeRange(ranges[i], omitChecksum, rootNode);
 210              }
 211              return serializedRanges.join("|");
 212          }
 213  
 214          function deserializeSelection(serialized, rootNode, win) {
 215              if (rootNode) {
 216                  win = win || dom.getWindow(rootNode);
 217              } else {
 218                  win = win || window;
 219                  rootNode = win.document.documentElement;
 220              }
 221              var serializedRanges = serialized.split("|");
 222              var sel = api.getSelection(win);
 223              var ranges = [];
 224  
 225              for (var i = 0, len = serializedRanges.length; i < len; ++i) {
 226                  ranges[i] = deserializeRange(serializedRanges[i], rootNode, win.document);
 227              }
 228              sel.setRanges(ranges);
 229  
 230              return sel;
 231          }
 232  
 233          function canDeserializeSelection(serialized, rootNode, win) {
 234              var doc;
 235              if (rootNode) {
 236                  doc = win ? win.document : dom.getDocument(rootNode);
 237              } else {
 238                  win = win || window;
 239                  rootNode = win.document.documentElement;
 240              }
 241              var serializedRanges = serialized.split("|");
 242  
 243              for (var i = 0, len = serializedRanges.length; i < len; ++i) {
 244                  if (!canDeserializeRange(serializedRanges[i], rootNode, doc)) {
 245                      return false;
 246                  }
 247              }
 248  
 249              return true;
 250          }
 251  
 252          var cookieName = "rangySerializedSelection";
 253  
 254          function getSerializedSelectionFromCookie(cookie) {
 255              var parts = cookie.split(/[;,]/);
 256              for (var i = 0, len = parts.length, nameVal, val; i < len; ++i) {
 257                  nameVal = parts[i].split("=");
 258                  if (nameVal[0].replace(/^\s+/, "") == cookieName) {
 259                      val = nameVal[1];
 260                      if (val) {
 261                          return decodeURIComponent(val.replace(/\s+$/, ""));
 262                      }
 263                  }
 264              }
 265              return null;
 266          }
 267  
 268          function restoreSelectionFromCookie(win) {
 269              win = win || window;
 270              var serialized = getSerializedSelectionFromCookie(win.document.cookie);
 271              if (serialized) {
 272                  deserializeSelection(serialized, win.doc);
 273              }
 274          }
 275  
 276          function saveSelectionCookie(win, props) {
 277              win = win || window;
 278              props = (typeof props == "object") ? props : {};
 279              var expires = props.expires ? ";expires=" + props.expires.toUTCString() : "";
 280              var path = props.path ? ";path=" + props.path : "";
 281              var domain = props.domain ? ";domain=" + props.domain : "";
 282              var secure = props.secure ? ";secure" : "";
 283              var serialized = serializeSelection(api.getSelection(win));
 284              win.document.cookie = encodeURIComponent(cookieName) + "=" + encodeURIComponent(serialized) + expires + path + domain + secure;
 285          }
 286  
 287          util.extend(api, {
 288              serializePosition: serializePosition,
 289              deserializePosition: deserializePosition,
 290              serializeRange: serializeRange,
 291              deserializeRange: deserializeRange,
 292              canDeserializeRange: canDeserializeRange,
 293              serializeSelection: serializeSelection,
 294              deserializeSelection: deserializeSelection,
 295              canDeserializeSelection: canDeserializeSelection,
 296              restoreSelectionFromCookie: restoreSelectionFromCookie,
 297              saveSelectionCookie: saveSelectionCookie,
 298              getElementChecksum: getElementChecksum,
 299              nodeToInfoString: nodeToInfoString
 300          });
 301  
 302          util.crc32 = crc32;
 303      });
 304      
 305      return rangy;
 306  }, this);


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1