summaryrefslogtreecommitdiff
path: root/static
diff options
context:
space:
mode:
authorPeter 'Pita' Martischka <petermartischka - googlemail - com>2012-02-14 09:21:45 -0800
committerPeter 'Pita' Martischka <petermartischka - googlemail - com>2012-02-14 09:21:45 -0800
commit5751a8e43450e96eac03a5007494fa0aca508076 (patch)
tree32220823b91d45c972d72fb5166623f642ddb35e /static
parentda1fbaad9aec6d766142119ef97746638dfd7ad6 (diff)
parente0d23e3c5d9feb1fc4ff88fa923bb6d1fa1aae18 (diff)
downloadetherpad-lite-5751a8e43450e96eac03a5007494fa0aca508076.zip
Merge pull request #352 from cweider/modulize-share
Module Sharing
Diffstat (limited to 'static')
-rw-r--r--static/js/AttributePoolFactory.js90
-rw-r--r--static/js/Changeset.js (renamed from static/js/easysync2.js)1693
-rw-r--r--static/js/ace2_common.js10
-rw-r--r--static/js/ace2_inner.js4
-rw-r--r--static/js/broadcast.js10
-rw-r--r--static/js/changesettracker.js4
-rw-r--r--static/js/contentcollector.js2
-rw-r--r--static/js/cssmanager_client.js118
-rw-r--r--static/js/domline.js32
-rw-r--r--static/js/domline_client.js309
-rw-r--r--static/js/easysync2_client.js2274
-rw-r--r--static/js/linestylefilter.js2
-rw-r--r--static/js/linestylefilter_client.js343
-rw-r--r--static/js/pad.js46
-rw-r--r--static/js/pad_utils.js64
-rw-r--r--static/js/security.js54
-rw-r--r--static/js/timeslider.js38
-rw-r--r--static/js/undomodule.js2
18 files changed, 800 insertions, 4295 deletions
diff --git a/static/js/AttributePoolFactory.js b/static/js/AttributePoolFactory.js
new file mode 100644
index 00000000..00b58dbb
--- /dev/null
+++ b/static/js/AttributePoolFactory.js
@@ -0,0 +1,90 @@
+/**
+ * This code represents the Attribute Pool Object of the original Etherpad.
+ * 90% of the code is still like in the original Etherpad
+ * Look at https://github.com/ether/pad/blob/master/infrastructure/ace/www/easysync2.js
+ * You can find a explanation what a attribute pool is here:
+ * https://github.com/Pita/etherpad-lite/blob/master/doc/easysync/easysync-notes.txt
+ */
+
+/*
+ * Copyright 2009 Google Inc., 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+exports.createAttributePool = function () {
+ var p = {};
+ p.numToAttrib = {}; // e.g. {0: ['foo','bar']}
+ p.attribToNum = {}; // e.g. {'foo,bar': 0}
+ p.nextNum = 0;
+
+ p.putAttrib = function (attrib, dontAddIfAbsent) {
+ var str = String(attrib);
+ if (str in p.attribToNum) {
+ return p.attribToNum[str];
+ }
+ if (dontAddIfAbsent) {
+ return -1;
+ }
+ var num = p.nextNum++;
+ p.attribToNum[str] = num;
+ p.numToAttrib[num] = [String(attrib[0] || ''), String(attrib[1] || '')];
+ return num;
+ };
+
+ p.getAttrib = function (num) {
+ var pair = p.numToAttrib[num];
+ if (!pair) {
+ return pair;
+ }
+ return [pair[0], pair[1]]; // return a mutable copy
+ };
+
+ p.getAttribKey = function (num) {
+ var pair = p.numToAttrib[num];
+ if (!pair) return '';
+ return pair[0];
+ };
+
+ p.getAttribValue = function (num) {
+ var pair = p.numToAttrib[num];
+ if (!pair) return '';
+ return pair[1];
+ };
+
+ p.eachAttrib = function (func) {
+ for (var n in p.numToAttrib) {
+ var pair = p.numToAttrib[n];
+ func(pair[0], pair[1]);
+ }
+ };
+
+ p.toJsonable = function () {
+ return {
+ numToAttrib: p.numToAttrib,
+ nextNum: p.nextNum
+ };
+ };
+
+ p.fromJsonable = function (obj) {
+ p.numToAttrib = obj.numToAttrib;
+ p.nextNum = obj.nextNum;
+ p.attribToNum = {};
+ for (var n in p.numToAttrib) {
+ p.attribToNum[String(p.numToAttrib[n])] = Number(n);
+ }
+ return p;
+ };
+
+ return p;
+}
diff --git a/static/js/easysync2.js b/static/js/Changeset.js
index cef868a1..715836d5 100644
--- a/static/js/easysync2.js
+++ b/static/js/Changeset.js
@@ -1,13 +1,16 @@
+/*
+ * This is the Changeset library copied from the old Etherpad with some modifications to use it in node.js
+ * Can be found in https://github.com/ether/pad/blob/master/infrastructure/ace/www/easysync2.js
+ */
+
/**
- * This code is mostly from the old Etherpad. Please help us to comment this code.
+ * This code is mostly from the old Etherpad. Please help us to comment this code.
* This helps other people to understand this code better and helps them to improve it.
* TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
*/
-// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.easysync2
-// %APPJET%: jimport("com.etherpad.Easysync2Support");
-/**
- * Copyright 2009 Google Inc.
+/*
+ * Copyright 2009 Google Inc., 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,203 +25,101 @@
* limitations under the License.
*/
-//var _opt = (this.Easysync2Support || null);
-var _opt = null; // disable optimization for now
-
-function AttribPool()
-{
- var p = {};
- p.numToAttrib = {}; // e.g. {0: ['foo','bar']}
- p.attribToNum = {}; // e.g. {'foo,bar': 0}
- p.nextNum = 0;
-
- p.putAttrib = function(attrib, dontAddIfAbsent)
- {
- var str = String(attrib);
- if (str in p.attribToNum)
- {
- return p.attribToNum[str];
- }
- if (dontAddIfAbsent)
- {
- return -1;
- }
- var num = p.nextNum++;
- p.attribToNum[str] = num;
- p.numToAttrib[num] = [String(attrib[0] || ''), String(attrib[1] || '')];
- return num;
- };
-
- p.getAttrib = function(num)
- {
- var pair = p.numToAttrib[num];
- if (!pair) return pair;
- return [pair[0], pair[1]]; // return a mutable copy
- };
+var AttributePoolFactory = require("/AttributePoolFactory");
- p.getAttribKey = function(num)
- {
- var pair = p.numToAttrib[num];
- if (!pair) return '';
- return pair[0];
- };
-
- p.getAttribValue = function(num)
- {
- var pair = p.numToAttrib[num];
- if (!pair) return '';
- return pair[1];
- };
-
- p.eachAttrib = function(func)
- {
- for (var n in p.numToAttrib)
- {
- var pair = p.numToAttrib[n];
- func(pair[0], pair[1]);
- }
- };
-
- p.toJsonable = function()
- {
- return {
- numToAttrib: p.numToAttrib,
- nextNum: p.nextNum
- };
- };
-
- p.fromJsonable = function(obj)
- {
- p.numToAttrib = obj.numToAttrib;
- p.nextNum = obj.nextNum;
- p.attribToNum = {};
- for (var n in p.numToAttrib)
- {
- p.attribToNum[String(p.numToAttrib[n])] = Number(n);
- }
- return p;
- };
-
- return p;
-}
+var _opt = null;
-var Changeset = {};
-
-Changeset.error = function error(msg)
-{
+//var exports = {};
+exports.error = function error(msg) {
var e = new Error(msg);
e.easysync = true;
throw e;
};
-Changeset.assert = function assert(b, msgParts)
-{
- if (!b)
- {
+exports.assert = function assert(b, msgParts) {
+ if (!b) {
var msg = Array.prototype.slice.call(arguments, 1).join('');
- Changeset.error("Changeset: " + msg);
+ exports.error("exports: " + msg);
}
};
-Changeset.parseNum = function(str)
-{
+exports.parseNum = function (str) {
return parseInt(str, 36);
};
-Changeset.numToString = function(num)
-{
+exports.numToString = function (num) {
return num.toString(36).toLowerCase();
};
-Changeset.toBaseTen = function(cs)
-{
+exports.toBaseTen = function (cs) {
var dollarIndex = cs.indexOf('$');
var beforeDollar = cs.substring(0, dollarIndex);
var fromDollar = cs.substring(dollarIndex);
- return beforeDollar.replace(/[0-9a-z]+/g, function(s)
- {
- return String(Changeset.parseNum(s));
+ return beforeDollar.replace(/[0-9a-z]+/g, function (s) {
+ return String(exports.parseNum(s));
}) + fromDollar;
};
-Changeset.oldLen = function(cs)
-{
- return Changeset.unpack(cs).oldLen;
+exports.oldLen = function (cs) {
+ return exports.unpack(cs).oldLen;
};
-Changeset.newLen = function(cs)
-{
- return Changeset.unpack(cs).newLen;
+exports.newLen = function (cs) {
+ return exports.unpack(cs).newLen;
};
-Changeset.opIterator = function(opsStr, optStartIndex)
-{
+exports.opIterator = function (opsStr, optStartIndex) {
//print(opsStr);
var regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|\?|/g;
var startIndex = (optStartIndex || 0);
var curIndex = startIndex;
var prevIndex = curIndex;
- function nextRegexMatch()
- {
+ function nextRegexMatch() {
prevIndex = curIndex;
var result;
- if (_opt)
- {
+ if (_opt) {
result = _opt.nextOpInString(opsStr, curIndex);
- if (result)
- {
- if (result.opcode() == '?')
- {
- Changeset.error("Hit error opcode in op stream");
+ if (result) {
+ if (result.opcode() == '?') {
+ exports.error("Hit error opcode in op stream");
}
curIndex = result.lastIndex();
}
- }
- else
- {
+ } else {
regex.lastIndex = curIndex;
result = regex.exec(opsStr);
curIndex = regex.lastIndex;
- if (result[0] == '?')
- {
- Changeset.error("Hit error opcode in op stream");
+ if (result[0] == '?') {
+ exports.error("Hit error opcode in op stream");
}
}
return result;
}
var regexResult = nextRegexMatch();
- var obj = Changeset.newOp();
+ var obj = exports.newOp();
- function next(optObj)
- {
+ function next(optObj) {
var op = (optObj || obj);
- if (_opt && regexResult)
- {
+ if (_opt && regexResult) {
op.attribs = regexResult.attribs();
op.lines = regexResult.lines();
op.chars = regexResult.chars();
op.opcode = regexResult.opcode();
regexResult = nextRegexMatch();
- }
- else if ((!_opt) && regexResult[0])
- {
+ } else if ((!_opt) && regexResult[0]) {
op.attribs = regexResult[1];
- op.lines = Changeset.parseNum(regexResult[2] || 0);
+ op.lines = exports.parseNum(regexResult[2] || 0);
op.opcode = regexResult[3];
- op.chars = Changeset.parseNum(regexResult[4]);
+ op.chars = exports.parseNum(regexResult[4]);
regexResult = nextRegexMatch();
- }
- else
- {
- Changeset.clearOp(op);
+ } else {
+ exports.clearOp(op);
}
return op;
}
- function hasNext()
- {
+ function hasNext() {
return !!(_opt ? regexResult : regexResult[0]);
}
- function lastIndex()
- {
+ function lastIndex() {
return prevIndex;
}
return {
@@ -228,15 +129,13 @@ Changeset.opIterator = function(opsStr, optStartIndex)
};
};
-Changeset.clearOp = function(op)
-{
+exports.clearOp = function (op) {
op.opcode = '';
op.chars = 0;
op.lines = 0;
op.attribs = '';
};
-Changeset.newOp = function(optOpcode)
-{
+exports.newOp = function (optOpcode) {
return {
opcode: (optOpcode || ''),
chars: 0,
@@ -244,8 +143,7 @@ Changeset.newOp = function(optOpcode)
attribs: ''
};
};
-Changeset.cloneOp = function(op)
-{
+exports.cloneOp = function (op) {
return {
opcode: op.opcode,
chars: op.chars,
@@ -253,60 +151,54 @@ Changeset.cloneOp = function(op)
attribs: op.attribs
};
};
-Changeset.copyOp = function(op1, op2)
-{
+exports.copyOp = function (op1, op2) {
op2.opcode = op1.opcode;
op2.chars = op1.chars;
op2.lines = op1.lines;
op2.attribs = op1.attribs;
};
-Changeset.opString = function(op)
-{
+exports.opString = function (op) {
// just for debugging
if (!op.opcode) return 'null';
- var assem = Changeset.opAssembler();
+ var assem = exports.opAssembler();
assem.append(op);
return assem.toString();
};
-Changeset.stringOp = function(str)
-{
+exports.stringOp = function (str) {
// just for debugging
- return Changeset.opIterator(str).next();
+ return exports.opIterator(str).next();
};
-Changeset.checkRep = function(cs)
-{
+exports.checkRep = function (cs) {
// doesn't check things that require access to attrib pool (e.g. attribute order)
// or original string (e.g. newline positions)
- var unpacked = Changeset.unpack(cs);
+ var unpacked = exports.unpack(cs);
var oldLen = unpacked.oldLen;
var newLen = unpacked.newLen;
var ops = unpacked.ops;
var charBank = unpacked.charBank;
- var assem = Changeset.smartOpAssembler();
+ var assem = exports.smartOpAssembler();
var oldPos = 0;
var calcNewLen = 0;
var numInserted = 0;
- var iter = Changeset.opIterator(ops);
- while (iter.hasNext())
- {
+ var iter = exports.opIterator(ops);
+ while (iter.hasNext()) {
var o = iter.next();
- switch (o.opcode)
- {
+ switch (o.opcode) {
case '=':
oldPos += o.chars;
calcNewLen += o.chars;
break;
case '-':
oldPos += o.chars;
- Changeset.assert(oldPos < oldLen, oldPos, " >= ", oldLen, " in ", cs);
+ exports.assert(oldPos < oldLen, oldPos, " >= ", oldLen, " in ", cs);
break;
case '+':
{
calcNewLen += o.chars;
numInserted += o.chars;
- Changeset.assert(calcNewLen < newLen, calcNewLen, " >= ", newLen, " in ", cs);
+ exports.assert(calcNewLen < newLen, calcNewLen, " >= ", newLen, " in ", cs);
break;
}
}
@@ -315,75 +207,62 @@ Changeset.checkRep = function(cs)
calcNewLen += oldLen - oldPos;
charBank = charBank.substring(0, numInserted);
- while (charBank.length < numInserted)
- {
+ while (charBank.length < numInserted) {
charBank += "?";
}
assem.endDocument();
- var normalized = Changeset.pack(oldLen, calcNewLen, assem.toString(), charBank);
- Changeset.assert(normalized == cs, normalized, ' != ', cs);
+ var normalized = exports.pack(oldLen, calcNewLen, assem.toString(), charBank);
+ exports.assert(normalized == cs, normalized, ' != ', cs);
return cs;
}
-Changeset.smartOpAssembler = function()
-{
- // Like opAssembler but able to produce conforming changesets
+exports.smartOpAssembler = function () {
+ // Like opAssembler but able to produce conforming exportss
// from slightly looser input, at the cost of speed.
// Specifically:
// - merges consecutive operations that can be merged
// - strips final "="
// - ignores 0-length changes
// - reorders consecutive + and - (which margingOpAssembler doesn't do)
- var minusAssem = Changeset.mergingOpAssembler();
- var plusAssem = Changeset.mergingOpAssembler();
- var keepAssem = Changeset.mergingOpAssembler();
- var assem = Changeset.stringAssembler();
+ var minusAssem = exports.mergingOpAssembler();
+ var plusAssem = exports.mergingOpAssembler();
+ var keepAssem = exports.mergingOpAssembler();
+ var assem = exports.stringAssembler();
var lastOpcode = '';
var lengthChange = 0;
- function flushKeeps()
- {
+ function flushKeeps() {
assem.append(keepAssem.toString());
keepAssem.clear();
}
- function flushPlusMinus()
- {
+ function flushPlusMinus() {
assem.append(minusAssem.toString());
minusAssem.clear();
assem.append(plusAssem.toString());
plusAssem.clear();
}
- function append(op)
- {
+ function append(op) {
if (!op.opcode) return;
if (!op.chars) return;
- if (op.opcode == '-')
- {
- if (lastOpcode == '=')
- {
+ if (op.opcode == '-') {
+ if (lastOpcode == '=') {
flushKeeps();
}
minusAssem.append(op);
lengthChange -= op.chars;
- }
- else if (op.opcode == '+')
- {
- if (lastOpcode == '=')
- {
+ } else if (op.opcode == '+') {
+ if (lastOpcode == '=') {
flushKeeps();
}
plusAssem.append(op);
lengthChange += op.chars;
- }
- else if (op.opcode == '=')
- {
- if (lastOpcode != '=')
- {
+ } else if (op.opcode == '=') {
+ if (lastOpcode != '=') {
flushPlusMinus();
}
keepAssem.append(op);
@@ -391,19 +270,15 @@ Changeset.smartOpAssembler = function()
lastOpcode = op.opcode;
}
- function appendOpWithText(opcode, text, attribs, pool)
- {
- var op = Changeset.newOp(opcode);
- op.attribs = Changeset.makeAttribsString(opcode, attribs, pool);
+ function appendOpWithText(opcode, text, attribs, pool) {
+ var op = exports.newOp(opcode);
+ op.attribs = exports.makeAttribsString(opcode, attribs, pool);
var lastNewlinePos = text.lastIndexOf('\n');
- if (lastNewlinePos < 0)
- {
+ if (lastNewlinePos < 0) {
op.chars = text.length;
op.lines = 0;
append(op);
- }
- else
- {
+ } else {
op.chars = lastNewlinePos + 1;
op.lines = text.match(/\n/g).length;
append(op);
@@ -413,15 +288,13 @@ Changeset.smartOpAssembler = function()
}
}
- function toString()
- {
+ function toString() {
flushPlusMinus();
flushKeeps();
return assem.toString();
}
- function clear()
- {
+ function clear() {
minusAssem.clear();
plusAssem.clear();
keepAssem.clear();
@@ -429,13 +302,11 @@ Changeset.smartOpAssembler = function()
lengthChange = 0;
}
- function endDocument()
- {
+ function endDocument() {
keepAssem.endDocument();
}
- function getLengthChange()
- {
+ function getLengthChange() {
return lengthChange;
}
@@ -449,29 +320,23 @@ Changeset.smartOpAssembler = function()
};
};
-if (_opt)
-{
- Changeset.mergingOpAssembler = function()
- {
+if (_opt) {
+ exports.mergingOpAssembler = function () {
var assem = _opt.mergingOpAssembler();
- function append(op)
- {
+ function append(op) {
assem.append(op.opcode, op.chars, op.lines, op.attribs);
}
- function toString()
- {
+ function toString() {
return assem.toString();
}
- function clear()
- {
+ function clear() {
assem.clear();
}
- function endDocument()
- {
+ function endDocument() {
assem.endDocument();
}
@@ -482,17 +347,14 @@ if (_opt)
endDocument: endDocument
};
};
-}
-else
-{
- Changeset.mergingOpAssembler = function()
- {
+} else {
+ exports.mergingOpAssembler = function () {
// This assembler can be used in production; it efficiently
// merges consecutive operations that are mergeable, ignores
// no-ops, and drops final pure "keeps". It does not re-order
// operations.
- var assem = Changeset.opAssembler();
- var bufOp = Changeset.newOp();
+ var assem = exports.opAssembler();
+ var bufOp = exports.newOp();
// If we get, for example, insertions [xxx\n,yyy], those don't merge,
// but if we get [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n].
@@ -500,19 +362,13 @@ else
// ops immediately after it.
var bufOpAdditionalCharsAfterNewline = 0;
- function flush(isEndDocument)
- {
- if (bufOp.opcode)
- {
- if (isEndDocument && bufOp.opcode == '=' && !bufOp.attribs)
- {
+ function flush(isEndDocument) {
+ if (bufOp.opcode) {
+ if (isEndDocument && bufOp.opcode == '=' && !bufOp.attribs) {
// final merged keep, leave it implicit
- }
- else
- {
+ } else {
assem.append(bufOp);
- if (bufOpAdditionalCharsAfterNewline)
- {
+ if (bufOpAdditionalCharsAfterNewline) {
bufOp.chars = bufOpAdditionalCharsAfterNewline;
bufOp.lines = 0;
assem.append(bufOp);
@@ -523,53 +379,40 @@ else
}
}
- function append(op)
- {
- if (op.chars > 0)
- {
- if (bufOp.opcode == op.opcode && bufOp.attribs == op.attribs)
- {
- if (op.lines > 0)
- {
+ function append(op) {
+ if (op.chars > 0) {
+ if (bufOp.opcode == op.opcode && bufOp.attribs == op.attribs) {
+ if (op.lines > 0) {
// bufOp and additional chars are all mergeable into a multi-line op
bufOp.chars += bufOpAdditionalCharsAfterNewline + op.chars;
bufOp.lines += op.lines;
bufOpAdditionalCharsAfterNewline = 0;
- }
- else if (bufOp.lines == 0)
- {
+ } else if (bufOp.lines == 0) {
// both bufOp and op are in-line
bufOp.chars += op.chars;
- }
- else
- {
+ } else {
// append in-line text to multi-line bufOp
bufOpAdditionalCharsAfterNewline += op.chars;
}
- }
- else
- {
+ } else {
flush();
- Changeset.copyOp(op, bufOp);
+ exports.copyOp(op, bufOp);
}
}
}
- function endDocument()
- {
+ function endDocument() {
flush(true);
}
- function toString()
- {
+ function toString() {
flush();
return assem.toString();
}
- function clear()
- {
+ function clear() {
assem.clear();
- Changeset.clearOp(bufOp);
+ exports.clearOp(bufOp);
}
return {
append: append,
@@ -580,26 +423,20 @@ else
};
}
-if (_opt)
-{
- Changeset.opAssembler = function()
- {
+if (_opt) {
+ exports.opAssembler = function () {
var assem = _opt.opAssembler();
// this function allows op to be mutated later (doesn't keep a ref)
-
- function append(op)
- {
+ function append(op) {
assem.append(op.opcode, op.chars, op.lines, op.attribs);
}
- function toString()
- {
+ function toString() {
return assem.toString();
}
- function clear()
- {
+ function clear() {
assem.clear();
}
return {
@@ -608,33 +445,25 @@ if (_opt)
clear: clear
};
};
-}
-else
-{
- Changeset.opAssembler = function()
- {
+} else {
+ exports.opAssembler = function () {
var pieces = [];
// this function allows op to be mutated later (doesn't keep a ref)
-
- function append(op)
- {
+ function append(op) {
pieces.push(op.attribs);
- if (op.lines)
- {
- pieces.push('|', Changeset.numToString(op.lines));
+ if (op.lines) {
+ pieces.push('|', exports.numToString(op.lines));
}
pieces.push(op.opcode);
- pieces.push(Changeset.numToString(op.chars));
+ pieces.push(exports.numToString(op.chars));
}
- function toString()
- {
+ function toString() {
return pieces.join('');
}
- function clear()
- {
+ function clear() {
pieces.length = 0;
}
return {
@@ -645,38 +474,32 @@ else
};
}
-Changeset.stringIterator = function(str)
-{
+exports.stringIterator = function (str) {
var curIndex = 0;
- function assertRemaining(n)
- {
- Changeset.assert(n <= remaining(), "!(", n, " <= ", remaining(), ")");
+ function assertRemaining(n) {
+ exports.assert(n <= remaining(), "!(", n, " <= ", remaining(), ")");
}
- function take(n)
- {
+ function take(n) {
assertRemaining(n);
var s = str.substr(curIndex, n);
curIndex += n;
return s;
}
- function peek(n)
- {
+ function peek(n) {
assertRemaining(n);
var s = str.substr(curIndex, n);
return s;
}
- function skip(n)
- {
+ function skip(n) {
assertRemaining(n);
curIndex += n;
}
- function remaining()
- {
+ function remaining() {
return str.length - curIndex;
}
return {
@@ -687,17 +510,14 @@ Changeset.stringIterator = function(str)
};
};
-Changeset.stringAssembler = function()
-{
+exports.stringAssembler = function () {
var pieces = [];
- function append(x)
- {
+ function append(x) {
pieces.push(String(x));
}
- function toString()
- {
+ function toString() {
return pieces.join('');
}
return {
@@ -707,10 +527,9 @@ Changeset.stringAssembler = function()
};
// "lines" need not be an array as long as it supports certain calls (lines_foo inside).
-Changeset.textLinesMutator = function(lines)
-{
+exports.textLinesMutator = function (lines) {
// Mutates lines, an array of strings, in place.
- // Mutation operations have the same constraints as changeset operations
+ // Mutation operations have the same constraints as exports operations
// with respect to newlines, but not the other additional constraints
// (i.e. ins/del ordering, forbidden no-ops, non-mergeability, final newline).
// Can be used to mutate lists of strings where the last char of each string
@@ -727,120 +546,87 @@ Changeset.textLinesMutator = function(lines)
// invariant: if (inSplice && (curLine >= curSplice[0] + curSplice.length - 2)) then
// curCol == 0
- function lines_applySplice(s)
- {
+ function lines_applySplice(s) {
lines.splice.apply(lines, s);
}
- function lines_toSource()
- {
+ function lines_toSource() {
return lines.toSource();
}
- function lines_get(idx)
- {
- if (lines.get)
- {
+ function lines_get(idx) {
+ if (lines.get) {
return lines.get(idx);
- }
- else
- {
+ } else {
return lines[idx];
}
}
// can be unimplemented if removeLines's return value not needed
-
- function lines_slice(start, end)
- {
- if (lines.slice)
- {
+ function lines_slice(start, end) {
+ if (lines.slice) {
return lines.slice(start, end);
- }
- else
- {
+ } else {
return [];
}
}
- function lines_length()
- {
- if ((typeof lines.length) == "number")
- {
+ function lines_length() {
+ if ((typeof lines.length) == "number") {
return lines.length;
- }
- else
- {
+ } else {
return lines.length();
}
}
- function enterSplice()
- {
+ function enterSplice() {
curSplice[0] = curLine;
curSplice[1] = 0;
- if (curCol > 0)
- {
+ if (curCol > 0) {
putCurLineInSplice();
}
inSplice = true;
}
- function leaveSplice()
- {
+ function leaveSplice() {
lines_applySplice(curSplice);
curSplice.length = 2;
curSplice[0] = curSplice[1] = 0;
inSplice = false;
}
- function isCurLineInSplice()
- {
+ function isCurLineInSplice() {
return (curLine - curSplice[0] < (curSplice.length - 2));
}
- function debugPrint(typ)
- {
+ function debugPrint(typ) {
print(typ + ": " + curSplice.toSource() + " / " + curLine + "," + curCol + " / " + lines_toSource());
}
- function putCurLineInSplice()
- {
- if (!isCurLineInSplice())
- {
+ function putCurLineInSplice() {
+ if (!isCurLineInSplice()) {
curSplice.push(lines_get(curSplice[0] + curSplice[1]));
curSplice[1]++;
}
return 2 + curLine - curSplice[0];
}
- function skipLines(L, includeInSplice)
- {
- if (L)
- {
- if (includeInSplice)
- {
- if (!inSplice)
- {
+ function skipLines(L, includeInSplice) {
+ if (L) {
+ if (includeInSplice) {
+ if (!inSplice) {
enterSplice();
}
- for (var i = 0; i < L; i++)
- {
+ for (var i = 0; i < L; i++) {
curCol = 0;
putCurLineInSplice();
curLine++;
}
- }
- else
- {
- if (inSplice)
- {
- if (L > 1)
- {
+ } else {
+ if (inSplice) {
+ if (L > 1) {
leaveSplice();
- }
- else
- {
+ } else {
putCurLineInSplice();
}
}
@@ -857,22 +643,15 @@ Changeset.textLinesMutator = function(lines)
//debugPrint("skip");
}
- function skip(N, L, includeInSplice)
- {
- if (N)
- {
- if (L)
- {
+ function skip(N, L, includeInSplice) {
+ if (N) {
+ if (L) {
skipLines(L, includeInSplice);
- }
- else
- {
- if (includeInSplice && !inSplice)
- {
+ } else {
+ if (includeInSplice && !inSplice) {
enterSplice();
}
- if (inSplice)
- {
+ if (inSplice) {
putCurLineInSplice();
}
curCol += N;
@@ -881,34 +660,26 @@ Changeset.textLinesMutator = function(lines)
}
}
- function removeLines(L)
- {
+ function removeLines(L) {
var removed = '';
- if (L)
- {
- if (!inSplice)
- {
+ if (L) {
+ if (!inSplice) {
enterSplice();
}
- function nextKLinesText(k)
- {
+ function nextKLinesText(k) {
var m = curSplice[0] + curSplice[1];
return lines_slice(m, m + k).join('');
}
- if (isCurLineInSplice())
- {
+ if (isCurLineInSplice()) {
//print(curCol);
- if (curCol == 0)
- {
+ if (curCol == 0) {
removed = curSplice[curSplice.length - 1];
// print("FOO"); // case foo
curSplice.length--;
removed += nextKLinesText(L - 1);
curSplice[1] += L - 1;
- }
- else
- {
+ } else {
removed = nextKLinesText(L - 1);
curSplice[1] += L - 1;
var sline = curSplice.length - 1;
@@ -916,9 +687,7 @@ Changeset.textLinesMutator = function(lines)
curSplice[sline] = curSplice[sline].substring(0, curCol) + lines_get(curSplice[0] + curSplice[1]);
curSplice[1] += 1;
}
- }
- else
- {
+ } else {
removed = nextKLinesText(L);
curSplice[1] += L;
}
@@ -927,19 +696,13 @@ Changeset.textLinesMutator = function(lines)
return removed;
}
- function remove(N, L)
- {
+ function remove(N, L) {
var removed = '';
- if (N)
- {
- if (L)
- {
+ if (N) {
+ if (L) {
return removeLines(L);
- }
- else
- {
- if (!inSplice)
- {
+ } else {
+ if (!inSplice) {
enterSplice();
}
var sline = putCurLineInSplice();
@@ -951,19 +714,14 @@ Changeset.textLinesMutator = function(lines)
return removed;
}
- function insert(text, L)
- {
- if (text)
- {
- if (!inSplice)
- {
+ function insert(text, L) {
+ if (text) {
+ if (!inSplice) {
enterSplice();
}
- if (L)
- {
- var newLines = Changeset.splitTextLines(text);
- if (isCurLineInSplice())
- {
+ if (L) {
+ var newLines = exports.splitTextLines(text);
+ if (isCurLineInSplice()) {
//if (curCol == 0) {
//curSplice.length--;
//curSplice[1]--;
@@ -982,15 +740,11 @@ Changeset.textLinesMutator = function(lines)
curSplice.push(theLine.substring(lineCol));
curCol = 0;
//}
- }
- else
- {
+ } else {
Array.prototype.push.apply(curSplice, newLines);
curLine += newLines.length;
}
- }
- else
- {
+ } else {
var sline = putCurLineInSplice();
curSplice[sline] = curSplice[sline].substring(0, curCol) + text + curSplice[sline].substring(curCol);
curCol += text.length;
@@ -999,21 +753,17 @@ Changeset.textLinesMutator = function(lines)
}
}
- function hasMore()
- {
+ function hasMore() {
//print(lines.length+" / "+inSplice+" / "+(curSplice.length - 2)+" / "+curSplice[1]);
var docLines = lines_length();
- if (inSplice)
- {
+ if (inSplice) {
docLines += curSplice.length - 2 - curSplice[1];
}
return curLine < docLines;
}
- function close()
- {
- if (inSplice)
- {
+ function close() {
+ if (inSplice) {
leaveSplice();
}
//debugPrint("close");
@@ -1031,21 +781,18 @@ Changeset.textLinesMutator = function(lines)
return self;
};
-Changeset.applyZip = function(in1, idx1, in2, idx2, func)
-{
- var iter1 = Changeset.opIterator(in1, idx1);
- var iter2 = Changeset.opIterator(in2, idx2);
- var assem = Changeset.smartOpAssembler();
- var op1 = Changeset.newOp();
- var op2 = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (op1.opcode || iter1.hasNext() || op2.opcode || iter2.hasNext())
- {
+exports.applyZip = function (in1, idx1, in2, idx2, func) {
+ var iter1 = exports.opIterator(in1, idx1);
+ var iter2 = exports.opIterator(in2, idx2);
+ var assem = exports.smartOpAssembler();
+ var op1 = exports.newOp();
+ var op2 = exports.newOp();
+ var opOut = exports.newOp();
+ while (op1.opcode || iter1.hasNext() || op2.opcode || iter2.hasNext()) {
if ((!op1.opcode) && iter1.hasNext()) iter1.next(op1);
if ((!op2.opcode) && iter2.hasNext()) iter2.next(op2);
func(op1, op2, opOut);
- if (opOut.opcode)
- {
+ if (opOut.opcode) {
//print(opOut.toSource());
assem.append(opOut);
opOut.opcode = '';
@@ -1055,17 +802,15 @@ Changeset.applyZip = function(in1, idx1, in2, idx2, func)
return assem.toString();
};
-Changeset.unpack = function(cs)
-{
+exports.unpack = function (cs) {
var headerRegex = /Z:([0-9a-z]+)([><])([0-9a-z]+)|/;
var headerMatch = headerRegex.exec(cs);
- if ((!headerMatch) || (!headerMatch[0]))
- {
- Changeset.error("Not a changeset: " + cs);
+ if ((!headerMatch) || (!headerMatch[0])) {
+ exports.error("Not a exports: " + cs);
}
- var oldLen = Changeset.parseNum(headerMatch[1]);
+ var oldLen = exports.parseNum(headerMatch[1]);
var changeSign = (headerMatch[2] == '>') ? 1 : -1;
- var changeMag = Changeset.parseNum(headerMatch[3]);
+ var changeMag = exports.parseNum(headerMatch[3]);
var newLen = oldLen + changeSign * changeMag;
var opsStart = headerMatch[0].length;
var opsEnd = cs.indexOf("$");
@@ -1078,28 +823,24 @@ Changeset.unpack = function(cs)
};
};
-Changeset.pack = function(oldLen, newLen, opsStr, bank)
-{
+exports.pack = function (oldLen, newLen, opsStr, bank) {
var lenDiff = newLen - oldLen;
- var lenDiffStr = (lenDiff >= 0 ? '>' + Changeset.numToString(lenDiff) : '<' + Changeset.numToString(-lenDiff));
+ var lenDiffStr = (lenDiff >= 0 ? '>' + exports.numToString(lenDiff) : '<' + exports.numToString(-lenDiff));
var a = [];
- a.push('Z:', Changeset.numToString(oldLen), lenDiffStr, opsStr, '$', bank);
+ a.push('Z:', exports.numToString(oldLen), lenDiffStr, opsStr, '$', bank);
return a.join('');
};
-Changeset.applyToText = function(cs, str)
-{
- var unpacked = Changeset.unpack(cs);
- Changeset.assert(str.length == unpacked.oldLen, "mismatched apply: ", str.length, " / ", unpacked.oldLen);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var strIter = Changeset.stringIterator(str);
- var assem = Changeset.stringAssembler();
- while (csIter.hasNext())
- {
+exports.applyToText = function (cs, str) {
+ var unpacked = exports.unpack(cs);
+ exports.assert(str.length == unpacked.oldLen, "mismatched apply: ", str.length, " / ", unpacked.oldLen);
+ var csIter = exports.opIterator(unpacked.ops);
+ var bankIter = exports.stringIterator(unpacked.charBank);
+ var strIter = exports.stringIterator(str);
+ var assem = exports.stringAssembler();
+ while (csIter.hasNext()) {
var op = csIter.next();
- switch (op.opcode)
- {
+ switch (op.opcode) {
case '+':
assem.append(bankIter.take(op.chars));
break;
@@ -1115,17 +856,14 @@ Changeset.applyToText = function(cs, str)
return assem.toString();
};
-Changeset.mutateTextLines = function(cs, lines)
-{
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var mut = Changeset.textLinesMutator(lines);
- while (csIter.hasNext())
- {
+exports.mutateTextLines = function (cs, lines) {
+ var unpacked = exports.unpack(cs);
+ var csIter = exports.opIterator(unpacked.ops);
+ var bankIter = exports.stringIterator(unpacked.charBank);
+ var mut = exports.textLinesMutator(lines);
+ while (csIter.hasNext()) {
var op = csIter.next();
- switch (op.opcode)
- {
+ switch (op.opcode) {
case '+':
mut.insert(bankIter.take(op.chars), op.lines);
break;
@@ -1140,8 +878,7 @@ Changeset.mutateTextLines = function(cs, lines)
mut.close();
};
-Changeset.composeAttributes = function(att1, att2, resultIsMutation, pool)
-{
+exports.composeAttributes = function (att1, att2, resultIsMutation, pool) {
// att1 and att2 are strings like "*3*f*1c", asMutation is a boolean.
// Sometimes attribute (key,value) pairs are treated as attribute presence
// information, while other times they are treated as operations that
@@ -1155,9 +892,8 @@ Changeset.composeAttributes = function(att1, att2, resultIsMutation, pool)
// ([(bold, true)], [(bold, )], true) -> [(bold, )]
// ([(bold, true)], [(bold, )], false) -> []
// pool can be null if att2 has no attributes.
- if ((!att1) && resultIsMutation)
- {
- // In the case of a mutation (i.e. composing two changesets),
+ if ((!att1) && resultIsMutation) {
+ // In the case of a mutation (i.e. composing two exportss),
// an att2 composed with an empy att1 is just att2. If att1
// is part of an attribution string, then att2 may remove
// attributes that are already gone, so don't do this optimization.
@@ -1165,76 +901,58 @@ Changeset.composeAttributes = function(att1, att2, resultIsMutation, pool)
}
if (!att2) return att1;
var atts = [];
- att1.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- atts.push(pool.getAttrib(Changeset.parseNum(a)));
+ att1.replace(/\*([0-9a-z]+)/g, function (_, a) {
+ atts.push(pool.getAttrib(exports.parseNum(a)));
return '';
});
- att2.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- var pair = pool.getAttrib(Changeset.parseNum(a));
+ att2.replace(/\*([0-9a-z]+)/g, function (_, a) {
+ var pair = pool.getAttrib(exports.parseNum(a));
var found = false;
- for (var i = 0; i < atts.length; i++)
- {
+ for (var i = 0; i < atts.length; i++) {
var oldPair = atts[i];
- if (oldPair[0] == pair[0])
- {
- if (pair[1] || resultIsMutation)
- {
+ if (oldPair[0] == pair[0]) {
+ if (pair[1] || resultIsMutation) {
oldPair[1] = pair[1];
- }
- else
- {
+ } else {
atts.splice(i, 1);
}
found = true;
break;
}
}
- if ((!found) && (pair[1] || resultIsMutation))
- {
+ if ((!found) && (pair[1] || resultIsMutation)) {
atts.push(pair);
}
return '';
});
atts.sort();
- var buf = Changeset.stringAssembler();
- for (var i = 0; i < atts.length; i++)
- {
+ var buf = exports.stringAssembler();
+ for (var i = 0; i < atts.length; i++) {
buf.append('*');
- buf.append(Changeset.numToString(pool.putAttrib(atts[i])));
+ buf.append(exports.numToString(pool.putAttrib(atts[i])));
}
//print(att1+" / "+att2+" / "+buf.toString());
return buf.toString();
};
-Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool)
-{
+exports._slicerZipperFunc = function (attOp, csOp, opOut, pool) {
// attOp is the op from the sequence that is being operated on, either an
- // attribution string or the earlier of two changesets being composed.
+ // attribution string or the earlier of two exportss being composed.
// pool can be null if definitely not needed.
//print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- if (attOp.opcode == '-')
- {
- Changeset.copyOp(attOp, opOut);
+ if (attOp.opcode == '-') {
+ exports.copyOp(attOp, opOut);
attOp.opcode = '';
- }
- else if (!attOp.opcode)
- {
- Changeset.copyOp(csOp, opOut);
+ } else if (!attOp.opcode) {
+ exports.copyOp(csOp, opOut);
csOp.opcode = '';
- }
- else
- {
- switch (csOp.opcode)
- {
+ } else {
+ switch (csOp.opcode) {
case '-':
{
- if (csOp.chars <= attOp.chars)
- {
+ if (csOp.chars <= attOp.chars) {
// delete or delete part
- if (attOp.opcode == '=')
- {
+ if (attOp.opcode == '=') {
opOut.opcode = '-';
opOut.chars = csOp.chars;
opOut.lines = csOp.lines;
@@ -1243,16 +961,12 @@ Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool)
attOp.chars -= csOp.chars;
attOp.lines -= csOp.lines;
csOp.opcode = '';
- if (!attOp.chars)
- {
+ if (!attOp.chars) {
attOp.opcode = '';
}
- }
- else
- {
+ } else {
// delete and keep going
- if (attOp.opcode == '=')
- {
+ if (attOp.opcode == '=') {
opOut.opcode = '-';
opOut.chars = attOp.chars;
opOut.lines = attOp.lines;
@@ -1267,34 +981,30 @@ Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool)
case '+':
{
// insert
- Changeset.copyOp(csOp, opOut);
+ exports.copyOp(csOp, opOut);
csOp.opcode = '';
break;
}
case '=':
{
- if (csOp.chars <= attOp.chars)
- {
+ if (csOp.chars <= attOp.chars) {
// keep or keep part
opOut.opcode = attOp.opcode;
opOut.chars = csOp.chars;
opOut.lines = csOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
+ opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
csOp.opcode = '';
attOp.chars -= csOp.chars;
attOp.lines -= csOp.lines;
- if (!attOp.chars)
- {
+ if (!attOp.chars) {
attOp.opcode = '';
}
- }
- else
- {
+ } else {
// keep and keep going
opOut.opcode = attOp.opcode;
opOut.chars = attOp.chars;
opOut.lines = attOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
+ opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
attOp.opcode = '';
csOp.chars -= attOp.chars;
csOp.lines -= attOp.lines;
@@ -1303,7 +1013,7 @@ Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool)
}
case '':
{
- Changeset.copyOp(attOp, opOut);
+ exports.copyOp(attOp, opOut);
attOp.opcode = '';
break;
}
@@ -1311,190 +1021,155 @@ Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool)
}
};
-Changeset.applyToAttribution = function(cs, astr, pool)
-{
- var unpacked = Changeset.unpack(cs);
+exports.applyToAttribution = function (cs, astr, pool) {
+ var unpacked = exports.unpack(cs);
- return Changeset.applyZip(astr, 0, unpacked.ops, 0, function(op1, op2, opOut)
- {
- return Changeset._slicerZipperFunc(op1, op2, opOut, pool);
+ return exports.applyZip(astr, 0, unpacked.ops, 0, function (op1, op2, opOut) {
+ return exports._slicerZipperFunc(op1, op2, opOut, pool);
});
};
-/*Changeset.oneInsertedLineAtATimeOpIterator = function(opsStr, optStartIndex, charBank) {
- var iter = Changeset.opIterator(opsStr, optStartIndex);
+/*exports.oneInsertedLineAtATimeOpIterator = function(opsStr, optStartIndex, charBank) {
+ var iter = exports.opIterator(opsStr, optStartIndex);
var bankIndex = 0;
};*/
-Changeset.mutateAttributionLines = function(cs, lines, pool)
-{
+exports.mutateAttributionLines = function (cs, lines, pool) {
//dmesg(cs);
//dmesg(lines.toSource()+" ->");
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
+ var unpacked = exports.unpack(cs);
+ var csIter = exports.opIterator(unpacked.ops);
var csBank = unpacked.charBank;
var csBankIndex = 0;
// treat the attribution lines as text lines, mutating a line at a time
- var mut = Changeset.textLinesMutator(lines);
+ var mut = exports.textLinesMutator(lines);
var lineIter = null;
- function isNextMutOp()
- {
+ function isNextMutOp() {
return (lineIter && lineIter.hasNext()) || mut.hasMore();
}
- function nextMutOp(destOp)
- {
- if ((!(lineIter && lineIter.hasNext())) && mut.hasMore())
- {
+ function nextMutOp(destOp) {
+ if ((!(lineIter && lineIter.hasNext())) && mut.hasMore()) {
var line = mut.removeLines(1);
- lineIter = Changeset.opIterator(line);
+ lineIter = exports.opIterator(line);
}
- if (lineIter && lineIter.hasNext())
- {
+ if (lineIter && lineIter.hasNext()) {
lineIter.next(destOp);
- }
- else
- {
+ } else {
destOp.opcode = '';
}
}
var lineAssem = null;
- function outputMutOp(op)
- {
+ function outputMutOp(op) {
//print("outputMutOp: "+op.toSource());
- if (!lineAssem)
- {
- lineAssem = Changeset.mergingOpAssembler();
+ if (!lineAssem) {
+ lineAssem = exports.mergingOpAssembler();
}
lineAssem.append(op);
- if (op.lines > 0)
- {
- Changeset.assert(op.lines == 1, "Can't have op.lines of ", op.lines, " in attribution lines");
+ if (op.lines > 0) {
+ exports.assert(op.lines == 1, "Can't have op.lines of ", op.lines, " in attribution lines");
// ship it to the mut
mut.insert(lineAssem.toString(), 1);
lineAssem = null;
}
}
- var csOp = Changeset.newOp();
- var attOp = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (csOp.opcode || csIter.hasNext() || attOp.opcode || isNextMutOp())
- {
- if ((!csOp.opcode) && csIter.hasNext())
- {
+ var csOp = exports.newOp();
+ var attOp = exports.newOp();
+ var opOut = exports.newOp();
+ while (csOp.opcode || csIter.hasNext() || attOp.opcode || isNextMutOp()) {
+ if ((!csOp.opcode) && csIter.hasNext()) {
csIter.next(csOp);
}
//print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
//print(csOp.opcode+"/"+csOp.lines+"/"+csOp.attribs+"/"+lineAssem+"/"+lineIter+"/"+(lineIter?lineIter.hasNext():null));
//print("csOp: "+csOp.toSource());
- if ((!csOp.opcode) && (!attOp.opcode) && (!lineAssem) && (!(lineIter && lineIter.hasNext())))
- {
+ if ((!csOp.opcode) && (!attOp.opcode) && (!lineAssem) && (!(lineIter && lineIter.hasNext()))) {
break; // done
- }
- else if (csOp.opcode == '=' && csOp.lines > 0 && (!csOp.attribs) && (!attOp.opcode) && (!lineAssem) && (!(lineIter && lineIter.hasNext())))
- {
+ } else if (csOp.opcode == '=' && csOp.lines > 0 && (!csOp.attribs) && (!attOp.opcode) && (!lineAssem) && (!(lineIter && lineIter.hasNext()))) {
// skip multiple lines; this is what makes small changes not order of the document size
mut.skipLines(csOp.lines);
//print("skipped: "+csOp.lines);
csOp.opcode = '';
- }
- else if (csOp.opcode == '+')
- {
- if (csOp.lines > 1)
- {
+ } else if (csOp.opcode == '+') {
+ if (csOp.lines > 1) {
var firstLineLen = csBank.indexOf('\n', csBankIndex) + 1 - csBankIndex;
- Changeset.copyOp(csOp, opOut);
+ exports.copyOp(csOp, opOut);
csOp.chars -= firstLineLen;
csOp.lines--;
opOut.lines = 1;
opOut.chars = firstLineLen;
- }
- else
- {
- Changeset.copyOp(csOp, opOut);
+ } else {
+ exports.copyOp(csOp, opOut);
csOp.opcode = '';
}
outputMutOp(opOut);
csBankIndex += opOut.chars;
opOut.opcode = '';
- }
- else
- {
- if ((!attOp.opcode) && isNextMutOp())
- {
+ } else {
+ if ((!attOp.opcode) && isNextMutOp()) {
nextMutOp(attOp);
}
//print("attOp: "+attOp.toSource());
- Changeset._slicerZipperFunc(attOp, csOp, opOut, pool);
- if (opOut.opcode)
- {
+ exports._slicerZipperFunc(attOp, csOp, opOut, pool);
+ if (opOut.opcode) {
outputMutOp(opOut);
opOut.opcode = '';
}
}
}
- Changeset.assert(!lineAssem, "line assembler not finished");
+ exports.assert(!lineAssem, "line assembler not finished");
mut.close();
//dmesg("-> "+lines.toSource());
};
-Changeset.joinAttributionLines = function(theAlines)
-{
- var assem = Changeset.mergingOpAssembler();
- for (var i = 0; i < theAlines.length; i++)
- {
+exports.joinAttributionLines = function (theAlines) {
+ var assem = exports.mergingOpAssembler();
+ for (var i = 0; i < theAlines.length; i++) {
var aline = theAlines[i];
- var iter = Changeset.opIterator(aline);
- while (iter.hasNext())
- {
+ var iter = exports.opIterator(aline);
+ while (iter.hasNext()) {
assem.append(iter.next());
}
}
return assem.toString();
};
-Changeset.splitAttributionLines = function(attrOps, text)
-{
- var iter = Changeset.opIterator(attrOps);
- var assem = Changeset.mergingOpAssembler();
+exports.splitAttributionLines = function (attrOps, text) {
+ var iter = exports.opIterator(attrOps);
+ var assem = exports.mergingOpAssembler();
var lines = [];
var pos = 0;
- function appendOp(op)
- {
+ function appendOp(op) {
assem.append(op);
- if (op.lines > 0)
- {
+ if (op.lines > 0) {
lines.push(assem.toString());
assem.clear();
}
pos += op.chars;
}
- while (iter.hasNext())
- {
+ while (iter.hasNext()) {
var op = iter.next();
var numChars = op.chars;
var numLines = op.lines;
- while (numLines > 1)
- {
+ while (numLines > 1) {
var newlineEnd = text.indexOf('\n', pos) + 1;
- Changeset.assert(newlineEnd > 0, "newlineEnd <= 0 in splitAttributionLines");
+ exports.assert(newlineEnd > 0, "newlineEnd <= 0 in splitAttributionLines");
op.chars = newlineEnd - pos;
op.lines = 1;
appendOp(op);
numChars -= op.chars;
numLines -= op.lines;
}
- if (numLines == 1)
- {
+ if (numLines == 1) {
op.chars = numChars;
op.lines = 1;
}
@@ -1504,149 +1179,121 @@ Changeset.splitAttributionLines = function(attrOps, text)
return lines;
};
-Changeset.splitTextLines = function(text)
-{
+exports.splitTextLines = function (text) {
return text.match(/[^\n]*(?:\n|[^\n]$)/g);
};
-Changeset.compose = function(cs1, cs2, pool)
-{
- var unpacked1 = Changeset.unpack(cs1);
- var unpacked2 = Changeset.unpack(cs2);
+exports.compose = function (cs1, cs2, pool) {
+ var unpacked1 = exports.unpack(cs1);
+ var unpacked2 = exports.unpack(cs2);
var len1 = unpacked1.oldLen;
var len2 = unpacked1.newLen;
- Changeset.assert(len2 == unpacked2.oldLen, "mismatched composition");
+ exports.assert(len2 == unpacked2.oldLen, "mismatched composition");
var len3 = unpacked2.newLen;
- var bankIter1 = Changeset.stringIterator(unpacked1.charBank);
- var bankIter2 = Changeset.stringIterator(unpacked2.charBank);
- var bankAssem = Changeset.stringAssembler();
-
- var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut)
- {
- //var debugBuilder = Changeset.stringAssembler();
- //debugBuilder.append(Changeset.opString(op1));
+ var bankIter1 = exports.stringIterator(unpacked1.charBank);
+ var bankIter2 = exports.stringIterator(unpacked2.charBank);
+ var bankAssem = exports.stringAssembler();
+
+ var newOps = exports.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function (op1, op2, opOut) {
+ //var debugBuilder = exports.stringAssembler();
+ //debugBuilder.append(exports.opString(op1));
//debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
+ //debugBuilder.append(exports.opString(op2));
//debugBuilder.append(' / ');
var op1code = op1.opcode;
var op2code = op2.opcode;
- if (op1code == '+' && op2code == '-')
- {
+ if (op1code == '+' && op2code == '-') {
bankIter1.skip(Math.min(op1.chars, op2.chars));
}
- Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- if (opOut.opcode == '+')
- {
- if (op2code == '+')
- {
+ exports._slicerZipperFunc(op1, op2, opOut, pool);
+ if (opOut.opcode == '+') {
+ if (op2code == '+') {
bankAssem.append(bankIter2.take(opOut.chars));
- }
- else
- {
+ } else {
bankAssem.append(bankIter1.take(opOut.chars));
}
}
- //debugBuilder.append(Changeset.opString(op1));
+ //debugBuilder.append(exports.opString(op1));
//debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
+ //debugBuilder.append(exports.opString(op2));
//debugBuilder.append(' -> ');
- //debugBuilder.append(Changeset.opString(opOut));
+ //debugBuilder.append(exports.opString(opOut));
//print(debugBuilder.toString());
});
- return Changeset.pack(len1, len3, newOps, bankAssem.toString());
+ return exports.pack(len1, len3, newOps, bankAssem.toString());
};
-Changeset.attributeTester = function(attribPair, pool)
-{
+exports.attributeTester = function (attribPair, pool) {
// returns a function that tests if a string of attributes
// (e.g. *3*4) contains a given attribute key,value that
// is already present in the pool.
- if (!pool)
- {
+ if (!pool) {
return never;
}
var attribNum = pool.putAttrib(attribPair, true);
- if (attribNum < 0)
- {
+ if (attribNum < 0) {
return never;
- }
- else
- {
- var re = new RegExp('\\*' + Changeset.numToString(attribNum) + '(?!\\w)');
- return function(attribs)
- {
+ } else {
+ var re = new RegExp('\\*' + exports.numToString(attribNum) + '(?!\\w)');
+ return function (attribs) {
return re.test(attribs);
};
}
- function never(attribs)
- {
+ function never(attribs) {
return false;
}
};
-Changeset.identity = function(N)
-{
- return Changeset.pack(N, N, "", "");
+exports.identity = function (N) {
+ return exports.pack(N, N, "", "");
};
-Changeset.makeSplice = function(oldFullText, spliceStart, numRemoved, newText, optNewTextAPairs, pool)
-{
+exports.makeSplice = function (oldFullText, spliceStart, numRemoved, newText, optNewTextAPairs, pool) {
var oldLen = oldFullText.length;
- if (spliceStart >= oldLen)
- {
+ if (spliceStart >= oldLen) {
spliceStart = oldLen - 1;
}
- if (numRemoved > oldFullText.length - spliceStart - 1)
- {
+ if (numRemoved > oldFullText.length - spliceStart - 1) {
numRemoved = oldFullText.length - spliceStart - 1;
}
var oldText = oldFullText.substring(spliceStart, spliceStart + numRemoved);
var newLen = oldLen + newText.length - oldText.length;
- var assem = Changeset.smartOpAssembler();
+ var assem = exports.smartOpAssembler();
assem.appendOpWithText('=', oldFullText.substring(0, spliceStart));
assem.appendOpWithText('-', oldText);
assem.appendOpWithText('+', newText, optNewTextAPairs, pool);
assem.endDocument();
- return Changeset.pack(oldLen, newLen, assem.toString(), newText);
+ return exports.pack(oldLen, newLen, assem.toString(), newText);
};
-Changeset.toSplices = function(cs)
-{
+exports.toSplices = function (cs) {
// get a list of splices, [startChar, endChar, newText]
- var unpacked = Changeset.unpack(cs);
+ var unpacked = exports.unpack(cs);
var splices = [];
var oldPos = 0;
- var iter = Changeset.opIterator(unpacked.ops);
- var charIter = Changeset.stringIterator(unpacked.charBank);
+ var iter = exports.opIterator(unpacked.ops);
+ var charIter = exports.stringIterator(unpacked.charBank);
var inSplice = false;
- while (iter.hasNext())
- {
+ while (iter.hasNext()) {
var op = iter.next();
- if (op.opcode == '=')
- {
+ if (op.opcode == '=') {
oldPos += op.chars;
inSplice = false;
- }
- else
- {
- if (!inSplice)
- {
+ } else {
+ if (!inSplice) {
splices.push([oldPos, oldPos, ""]);
inSplice = true;
}
- if (op.opcode == '-')
- {
+ if (op.opcode == '-') {
oldPos += op.chars;
splices[splices.length - 1][1] += op.chars;
- }
- else if (op.opcode == '+')
- {
+ } else if (op.opcode == '+') {
splices[splices.length - 1][2] += charIter.take(op.chars);
}
}
@@ -1655,56 +1302,40 @@ Changeset.toSplices = function(cs)
return splices;
};
-Changeset.characterRangeFollow = function(cs, startChar, endChar, insertionsAfter)
-{
+exports.characterRangeFollow = function (cs, startChar, endChar, insertionsAfter) {
var newStartChar = startChar;
var newEndChar = endChar;
- var splices = Changeset.toSplices(cs);
+ var splices = exports.toSplices(cs);
var lengthChangeSoFar = 0;
- for (var i = 0; i < splices.length; i++)
- {
+ for (var i = 0; i < splices.length; i++) {
var splice = splices[i];
var spliceStart = splice[0] + lengthChangeSoFar;
var spliceEnd = splice[1] + lengthChangeSoFar;
var newTextLength = splice[2].length;
var thisLengthChange = newTextLength - (spliceEnd - spliceStart);
- if (spliceStart <= newStartChar && spliceEnd >= newEndChar)
- {
+ if (spliceStart <= newStartChar && spliceEnd >= newEndChar) {
// splice fully replaces/deletes range
// (also case that handles insertion at a collapsed selection)
- if (insertionsAfter)
- {
+ if (insertionsAfter) {
newStartChar = newEndChar = spliceStart;
- }
- else
- {
+ } else {
newStartChar = newEndChar = spliceStart + newTextLength;
}
- }
- else if (spliceEnd <= newStartChar)
- {
+ } else if (spliceEnd <= newStartChar) {
// splice is before range
newStartChar += thisLengthChange;
newEndChar += thisLengthChange;
- }
- else if (spliceStart >= newEndChar)
- {
+ } else if (spliceStart >= newEndChar) {
// splice is after range
- }
- else if (spliceStart >= newStartChar && spliceEnd <= newEndChar)
- {
+ } else if (spliceStart >= newStartChar && spliceEnd <= newEndChar) {
// splice is inside range
newEndChar += thisLengthChange;
- }
- else if (spliceEnd < newEndChar)
- {
+ } else if (spliceEnd < newEndChar) {
// splice overlaps beginning of range
newStartChar = spliceStart + newTextLength;
newEndChar += thisLengthChange;
- }
- else
- {
+ } else {
// splice overlaps end of range
newEndChar = spliceStart;
}
@@ -1715,79 +1346,63 @@ Changeset.characterRangeFollow = function(cs, startChar, endChar, insertionsAfte
return [newStartChar, newEndChar];
};
-Changeset.moveOpsToNewPool = function(cs, oldPool, newPool)
-{
- // works on changeset or attribution string
+exports.moveOpsToNewPool = function (cs, oldPool, newPool) {
+ // works on exports or attribution string
var dollarPos = cs.indexOf('$');
- if (dollarPos < 0)
- {
+ if (dollarPos < 0) {
dollarPos = cs.length;
}
var upToDollar = cs.substring(0, dollarPos);
var fromDollar = cs.substring(dollarPos);
// order of attribs stays the same
- return upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- var oldNum = Changeset.parseNum(a);
+ return upToDollar.replace(/\*([0-9a-z]+)/g, function (_, a) {
+ var oldNum = exports.parseNum(a);
var pair = oldPool.getAttrib(oldNum);
var newNum = newPool.putAttrib(pair);
- return '*' + Changeset.numToString(newNum);
+ return '*' + exports.numToString(newNum);
}) + fromDollar;
};
-Changeset.makeAttribution = function(text)
-{
- var assem = Changeset.smartOpAssembler();
+exports.makeAttribution = function (text) {
+ var assem = exports.smartOpAssembler();
assem.appendOpWithText('+', text);
return assem.toString();
};
-// callable on a changeset, attribution string, or attribs property of an op
-Changeset.eachAttribNumber = function(cs, func)
-{
+// callable on a exports, attribution string, or attribs property of an op
+exports.eachAttribNumber = function (cs, func) {
var dollarPos = cs.indexOf('$');
- if (dollarPos < 0)
- {
+ if (dollarPos < 0) {
dollarPos = cs.length;
}
var upToDollar = cs.substring(0, dollarPos);
- upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- func(Changeset.parseNum(a));
+ upToDollar.replace(/\*([0-9a-z]+)/g, function (_, a) {
+ func(exports.parseNum(a));
return '';
});
};
-// callable on a changeset, attribution string, or attribs property of an op,
+// callable on a exports, attribution string, or attribs property of an op,
// though it may easily create adjacent ops that can be merged.
-Changeset.filterAttribNumbers = function(cs, filter)
-{
- return Changeset.mapAttribNumbers(cs, filter);
+exports.filterAttribNumbers = function (cs, filter) {
+ return exports.mapAttribNumbers(cs, filter);
};
-Changeset.mapAttribNumbers = function(cs, func)
-{
+exports.mapAttribNumbers = function (cs, func) {
var dollarPos = cs.indexOf('$');
- if (dollarPos < 0)
- {
+ if (dollarPos < 0) {
dollarPos = cs.length;
}
var upToDollar = cs.substring(0, dollarPos);
- var newUpToDollar = upToDollar.replace(/\*([0-9a-z]+)/g, function(s, a)
- {
- var n = func(Changeset.parseNum(a));
- if (n === true)
- {
+ var newUpToDollar = upToDollar.replace(/\*([0-9a-z]+)/g, function (s, a) {
+ var n = func(exports.parseNum(a));
+ if (n === true) {
return s;
- }
- else if ((typeof n) === "number")
- {
- return '*' + Changeset.numToString(n);
- }
- else
- {
+ } else if ((typeof n) === "number") {
+ return '*' + exports.numToString(n);
+ } else {
return '';
}
});
@@ -1795,108 +1410,88 @@ Changeset.mapAttribNumbers = function(cs, func)
return newUpToDollar + cs.substring(dollarPos);
};
-Changeset.makeAText = function(text, attribs)
-{
+exports.makeAText = function (text, attribs) {
return {
text: text,
- attribs: (attribs || Changeset.makeAttribution(text))
+ attribs: (attribs || exports.makeAttribution(text))
};
};
-Changeset.applyToAText = function(cs, atext, pool)
-{
+exports.applyToAText = function (cs, atext, pool) {
return {
- text: Changeset.applyToText(cs, atext.text),
- attribs: Changeset.applyToAttribution(cs, atext.attribs, pool)
+ text: exports.applyToText(cs, atext.text),
+ attribs: exports.applyToAttribution(cs, atext.attribs, pool)
};
};
-Changeset.cloneAText = function(atext)
-{
+exports.cloneAText = function (atext) {
return {
text: atext.text,
attribs: atext.attribs
};
};
-Changeset.copyAText = function(atext1, atext2)
-{
+exports.copyAText = function (atext1, atext2) {
atext2.text = atext1.text;
atext2.attribs = atext1.attribs;
};
-Changeset.appendATextToAssembler = function(atext, assem)
-{
+exports.appendATextToAssembler = function (atext, assem) {
// intentionally skips last newline char of atext
- var iter = Changeset.opIterator(atext.attribs);
- var op = Changeset.newOp();
- while (iter.hasNext())
- {
+ var iter = exports.opIterator(atext.attribs);
+ var op = exports.newOp();
+ while (iter.hasNext()) {
iter.next(op);
- if (!iter.hasNext())
- {
+ if (!iter.hasNext()) {
// last op, exclude final newline
- if (op.lines <= 1)
- {
+ if (op.lines <= 1) {
op.lines = 0;
op.chars--;
- if (op.chars)
- {
+ if (op.chars) {
assem.append(op);
}
- }
- else
- {
- var nextToLastNewlineEnd = atext.text.lastIndexOf('\n', atext.text.length - 2) + 1;
+ } else {
+ var nextToLastNewlineEnd =
+ atext.text.lastIndexOf('\n', atext.text.length - 2) + 1;
var lastLineLength = atext.text.length - nextToLastNewlineEnd - 1;
op.lines--;
op.chars -= (lastLineLength + 1);
assem.append(op);
op.lines = 0;
op.chars = lastLineLength;
- if (op.chars)
- {
+ if (op.chars) {
assem.append(op);
}
}
- }
- else
- {
+ } else {
assem.append(op);
}
}
};
-Changeset.prepareForWire = function(cs, pool)
-{
- var newPool = new AttribPool();
- var newCs = Changeset.moveOpsToNewPool(cs, pool, newPool);
+exports.prepareForWire = function (cs, pool) {
+ var newPool = AttributePoolFactory.createAttributePool();;
+ var newCs = exports.moveOpsToNewPool(cs, pool, newPool);
return {
translated: newCs,
pool: newPool
};
};
-Changeset.isIdentity = function(cs)
-{
- var unpacked = Changeset.unpack(cs);
+exports.isIdentity = function (cs) {
+ var unpacked = exports.unpack(cs);
return unpacked.ops == "" && unpacked.oldLen == unpacked.newLen;
};
-Changeset.opAttributeValue = function(op, key, pool)
-{
- return Changeset.attribsAttributeValue(op.attribs, key, pool);
+exports.opAttributeValue = function (op, key, pool) {
+ return exports.attribsAttributeValue(op.attribs, key, pool);
};
-Changeset.attribsAttributeValue = function(attribs, key, pool)
-{
+exports.attribsAttributeValue = function (attribs, key, pool) {
var value = '';
- if (attribs)
- {
- Changeset.eachAttribNumber(attribs, function(n)
- {
- if (pool.getAttribKey(n) == key)
- {
+ if (attribs) {
+ exports.eachAttribNumber(attribs, function (n) {
+ if (pool.getAttribKey(n) == key) {
value = pool.getAttribValue(n);
}
});
@@ -1904,36 +1499,31 @@ Changeset.attribsAttributeValue = function(attribs, key, pool)
return value;
};
-Changeset.builder = function(oldLen)
-{
- var assem = Changeset.smartOpAssembler();
- var o = Changeset.newOp();
- var charBank = Changeset.stringAssembler();
+exports.builder = function (oldLen) {
+ var assem = exports.smartOpAssembler();
+ var o = exports.newOp();
+ var charBank = exports.stringAssembler();
var self = {
// attribs are [[key1,value1],[key2,value2],...] or '*0*1...' (no pool needed in latter case)
- keep: function(N, L, attribs, pool)
- {
+ keep: function (N, L, attribs, pool) {
o.opcode = '=';
- o.attribs = (attribs && Changeset.makeAttribsString('=', attribs, pool)) || '';
+ o.attribs = (attribs && exports.makeAttribsString('=', attribs, pool)) || '';
o.chars = N;
o.lines = (L || 0);
assem.append(o);
return self;
},
- keepText: function(text, attribs, pool)
- {
+ keepText: function (text, attribs, pool) {
assem.appendOpWithText('=', text, attribs, pool);
return self;
},
- insert: function(text, attribs, pool)
- {
+ insert: function (text, attribs, pool) {
assem.appendOpWithText('+', text, attribs, pool);
charBank.append(text);
return self;
},
- remove: function(N, L)
- {
+ remove: function (N, L) {
o.opcode = '-';
o.attribs = '';
o.chars = N;
@@ -1941,42 +1531,32 @@ Changeset.builder = function(oldLen)
assem.append(o);
return self;
},
- toString: function()
- {
+ toString: function () {
assem.endDocument();
var newLen = oldLen + assem.getLengthChange();
- return Changeset.pack(oldLen, newLen, assem.toString(), charBank.toString());
+ return exports.pack(oldLen, newLen, assem.toString(), charBank.toString());
}
};
return self;
};
-Changeset.makeAttribsString = function(opcode, attribs, pool)
-{
+exports.makeAttribsString = function (opcode, attribs, pool) {
// makeAttribsString(opcode, '*3') or makeAttribsString(opcode, [['foo','bar']], myPool) work
- if (!attribs)
- {
+ if (!attribs) {
return '';
- }
- else if ((typeof attribs) == "string")
- {
+ } else if ((typeof attribs) == "string") {
return attribs;
- }
- else if (pool && attribs && attribs.length)
- {
- if (attribs.length > 1)
- {
+ } else if (pool && attribs && attribs.length) {
+ if (attribs.length > 1) {
attribs = attribs.slice();
attribs.sort();
}
var result = [];
- for (var i = 0; i < attribs.length; i++)
- {
+ for (var i = 0; i < attribs.length; i++) {
var pair = attribs[i];
- if (opcode == '=' || (opcode == '+' && pair[1]))
- {
- result.push('*' + Changeset.numToString(pool.putAttrib(pair)));
+ if (opcode == '=' || (opcode == '+' && pair[1])) {
+ result.push('*' + exports.numToString(pool.putAttrib(pair)));
}
}
return result.join('');
@@ -1984,30 +1564,24 @@ Changeset.makeAttribsString = function(opcode, attribs, pool)
};
// like "substring" but on a single-line attribution string
-Changeset.subattribution = function(astr, start, optEnd)
-{
- var iter = Changeset.opIterator(astr, 0);
- var assem = Changeset.smartOpAssembler();
- var attOp = Changeset.newOp();
- var csOp = Changeset.newOp();
- var opOut = Changeset.newOp();
-
- function doCsOp()
- {
- if (csOp.chars)
- {
- while (csOp.opcode && (attOp.opcode || iter.hasNext()))
- {
+exports.subattribution = function (astr, start, optEnd) {
+ var iter = exports.opIterator(astr, 0);
+ var assem = exports.smartOpAssembler();
+ var attOp = exports.newOp();
+ var csOp = exports.newOp();
+ var opOut = exports.newOp();
+
+ function doCsOp() {
+ if (csOp.chars) {
+ while (csOp.opcode && (attOp.opcode || iter.hasNext())) {
if (!attOp.opcode) iter.next(attOp);
- if (csOp.opcode && attOp.opcode && csOp.chars >= attOp.chars && attOp.lines > 0 && csOp.lines <= 0)
- {
+ if (csOp.opcode && attOp.opcode && csOp.chars >= attOp.chars && attOp.lines > 0 && csOp.lines <= 0) {
csOp.lines++;
}
- Changeset._slicerZipperFunc(attOp, csOp, opOut, null);
- if (opOut.opcode)
- {
+ exports._slicerZipperFunc(attOp, csOp, opOut, null);
+ if (opOut.opcode) {
assem.append(opOut);
opOut.opcode = '';
}
@@ -2020,20 +1594,15 @@ Changeset.subattribution = function(astr, start, optEnd)
doCsOp();
- if (optEnd === undefined)
- {
- if (attOp.opcode)
- {
+ if (optEnd === undefined) {
+ if (attOp.opcode) {
assem.append(attOp);
}
- while (iter.hasNext())
- {
+ while (iter.hasNext()) {
iter.next(attOp);
assem.append(attOp);
}
- }
- else
- {
+ } else {
csOp.opcode = '=';
csOp.chars = optEnd - start;
doCsOp();
@@ -2042,57 +1611,39 @@ Changeset.subattribution = function(astr, start, optEnd)
return assem.toString();
};
-Changeset.inverse = function(cs, lines, alines, pool)
-{
- // lines and alines are what the changeset is meant to apply to.
+exports.inverse = function (cs, lines, alines, pool) {
+ // lines and alines are what the exports is meant to apply to.
// They may be arrays or objects with .get(i) and .length methods.
// They include final newlines on lines.
-
- function lines_get(idx)
- {
- if (lines.get)
- {
+ function lines_get(idx) {
+ if (lines.get) {
return lines.get(idx);
- }
- else
- {
+ } else {
return lines[idx];
}
}
- function lines_length()
- {
- if ((typeof lines.length) == "number")
- {
+ function lines_length() {
+ if ((typeof lines.length) == "number") {
return lines.length;
- }
- else
- {
+ } else {
return lines.length();
}
}
- function alines_get(idx)
- {
- if (alines.get)
- {
+ function alines_get(idx) {
+ if (alines.get) {
return alines.get(idx);
- }
- else
- {
+ } else {
return alines[idx];
}
}
- function alines_length()
- {
- if ((typeof alines.length) == "number")
- {
+ function alines_length() {
+ if ((typeof alines.length) == "number") {
return alines.length;
- }
- else
- {
+ } else {
return alines.length();
}
}
@@ -2101,49 +1652,40 @@ Changeset.inverse = function(cs, lines, alines, pool)
var curChar = 0;
var curLineOpIter = null;
var curLineOpIterLine;
- var curLineNextOp = Changeset.newOp('+');
+ var curLineNextOp = exports.newOp('+');
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var builder = Changeset.builder(unpacked.newLen);
+ var unpacked = exports.unpack(cs);
+ var csIter = exports.opIterator(unpacked.ops);
+ var builder = exports.builder(unpacked.newLen);
- function consumeAttribRuns(numChars, func /*(len, attribs, endsLine)*/ )
- {
+ function consumeAttribRuns(numChars, func /*(len, attribs, endsLine)*/ ) {
- if ((!curLineOpIter) || (curLineOpIterLine != curLine))
- {
+ if ((!curLineOpIter) || (curLineOpIterLine != curLine)) {
// create curLineOpIter and advance it to curChar
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
+ curLineOpIter = exports.opIterator(alines_get(curLine));
curLineOpIterLine = curLine;
var indexIntoLine = 0;
var done = false;
- while (!done)
- {
+ while (!done) {
curLineOpIter.next(curLineNextOp);
- if (indexIntoLine + curLineNextOp.chars >= curChar)
- {
+ if (indexIntoLine + curLineNextOp.chars >= curChar) {
curLineNextOp.chars -= (curChar - indexIntoLine);
done = true;
- }
- else
- {
+ } else {
indexIntoLine += curLineNextOp.chars;
}
}
}
- while (numChars > 0)
- {
- if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext()))
- {
+ while (numChars > 0) {
+ if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext())) {
curLine++;
curChar = 0;
curLineOpIterLine = curLine;
curLineNextOp.chars = 0;
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
+ curLineOpIter = exports.opIterator(alines_get(curLine));
}
- if (!curLineNextOp.chars)
- {
+ if (!curLineNextOp.chars) {
curLineOpIter.next(curLineNextOp);
}
var charsToUse = Math.min(numChars, curLineNextOp.chars);
@@ -2153,45 +1695,34 @@ Changeset.inverse = function(cs, lines, alines, pool)
curChar += charsToUse;
}
- if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext()))
- {
+ if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext())) {
curLine++;
curChar = 0;
}
}
- function skip(N, L)
- {
- if (L)
- {
+ function skip(N, L) {
+ if (L) {
curLine += L;
curChar = 0;
- }
- else
- {
- if (curLineOpIter && curLineOpIterLine == curLine)
- {
- consumeAttribRuns(N, function()
- {});
- }
- else
- {
+ } else {
+ if (curLineOpIter && curLineOpIterLine == curLine) {
+ consumeAttribRuns(N, function () {});
+ } else {
curChar += N;
}
}
}
- function nextText(numChars)
- {
+ function nextText(numChars) {
var len = 0;
- var assem = Changeset.stringAssembler();
+ var assem = exports.stringAssembler();
var firstString = lines_get(curLine).substring(curChar);
len += firstString.length;
assem.append(firstString);
var lineNum = curLine + 1;
- while (len < numChars)
- {
+ while (len < numChars) {
var nextString = lines_get(lineNum);
len += nextString.length;
assem.append(nextString);
@@ -2201,13 +1732,10 @@ Changeset.inverse = function(cs, lines, alines, pool)
return assem.toString().substring(0, numChars);
}
- function cachedStrFunc(func)
- {
+ function cachedStrFunc(func) {
var cache = {};
- return function(s)
- {
- if (!cache[s])
- {
+ return function (s) {
+ if (!cache[s]) {
cache[s] = func(s);
}
return cache[s];
@@ -2216,192 +1744,140 @@ Changeset.inverse = function(cs, lines, alines, pool)
var attribKeys = [];
var attribValues = [];
- while (csIter.hasNext())
- {
+ while (csIter.hasNext()) {
var csOp = csIter.next();
- if (csOp.opcode == '=')
- {
- if (csOp.attribs)
- {
+ if (csOp.opcode == '=') {
+ if (csOp.attribs) {
attribKeys.length = 0;
attribValues.length = 0;
- Changeset.eachAttribNumber(csOp.attribs, function(n)
- {
+ exports.eachAttribNumber(csOp.attribs, function (n) {
attribKeys.push(pool.getAttribKey(n));
attribValues.push(pool.getAttribValue(n));
});
- var undoBackToAttribs = cachedStrFunc(function(attribs)
- {
+ var undoBackToAttribs = cachedStrFunc(function (attribs) {
var backAttribs = [];
- for (var i = 0; i < attribKeys.length; i++)
- {
+ for (var i = 0; i < attribKeys.length; i++) {
var appliedKey = attribKeys[i];
var appliedValue = attribValues[i];
- var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, pool);
- if (appliedValue != oldValue)
- {
+ var oldValue = exports.attribsAttributeValue(attribs, appliedKey, pool);
+ if (appliedValue != oldValue) {
backAttribs.push([appliedKey, oldValue]);
}
}
- return Changeset.makeAttribsString('=', backAttribs, pool);
+ return exports.makeAttribsString('=', backAttribs, pool);
});
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine)
- {
+ consumeAttribRuns(csOp.chars, function (len, attribs, endsLine) {
builder.keep(len, endsLine ? 1 : 0, undoBackToAttribs(attribs));
});
- }
- else
- {
+ } else {
skip(csOp.chars, csOp.lines);
builder.keep(csOp.chars, csOp.lines);
}
- }
- else if (csOp.opcode == '+')
- {
+ } else if (csOp.opcode == '+') {
builder.remove(csOp.chars, csOp.lines);
- }
- else if (csOp.opcode == '-')
- {
+ } else if (csOp.opcode == '-') {
var textBank = nextText(csOp.chars);
var textBankIndex = 0;
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine)
- {
+ consumeAttribRuns(csOp.chars, function (len, attribs, endsLine) {
builder.insert(textBank.substr(textBankIndex, len), attribs);
textBankIndex += len;
});
}
}
- return Changeset.checkRep(builder.toString());
+ return exports.checkRep(builder.toString());
};
// %CLIENT FILE ENDS HERE%
-Changeset.follow = function(cs1, cs2, reverseInsertOrder, pool)
-{
- var unpacked1 = Changeset.unpack(cs1);
- var unpacked2 = Changeset.unpack(cs2);
+exports.follow = function (cs1, cs2, reverseInsertOrder, pool) {
+ var unpacked1 = exports.unpack(cs1);
+ var unpacked2 = exports.unpack(cs2);
var len1 = unpacked1.oldLen;
var len2 = unpacked2.oldLen;
- Changeset.assert(len1 == len2, "mismatched follow");
- var chars1 = Changeset.stringIterator(unpacked1.charBank);
- var chars2 = Changeset.stringIterator(unpacked2.charBank);
+ exports.assert(len1 == len2, "mismatched follow");
+ var chars1 = exports.stringIterator(unpacked1.charBank);
+ var chars2 = exports.stringIterator(unpacked2.charBank);
var oldLen = unpacked1.newLen;
var oldPos = 0;
var newLen = 0;
- var hasInsertFirst = Changeset.attributeTester(['insertorder', 'first'], pool);
+ var hasInsertFirst = exports.attributeTester(['insertorder', 'first'], pool);
- var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut)
- {
- if (op1.opcode == '+' || op2.opcode == '+')
- {
+ var newOps = exports.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function (op1, op2, opOut) {
+ if (op1.opcode == '+' || op2.opcode == '+') {
var whichToDo;
- if (op2.opcode != '+')
- {
+ if (op2.opcode != '+') {
whichToDo = 1;
- }
- else if (op1.opcode != '+')
- {
+ } else if (op1.opcode != '+') {
whichToDo = 2;
- }
- else
- {
+ } else {
// both +
var firstChar1 = chars1.peek(1);
var firstChar2 = chars2.peek(1);
var insertFirst1 = hasInsertFirst(op1.attribs);
var insertFirst2 = hasInsertFirst(op2.attribs);
- if (insertFirst1 && !insertFirst2)
- {
+ if (insertFirst1 && !insertFirst2) {
whichToDo = 1;
- }
- else if (insertFirst2 && !insertFirst1)
- {
+ } else if (insertFirst2 && !insertFirst1) {
whichToDo = 2;
}
// insert string that doesn't start with a newline first so as not to break up lines
- else if (firstChar1 == '\n' && firstChar2 != '\n')
- {
+ else if (firstChar1 == '\n' && firstChar2 != '\n') {
whichToDo = 2;
- }
- else if (firstChar1 != '\n' && firstChar2 == '\n')
- {
+ } else if (firstChar1 != '\n' && firstChar2 == '\n') {
whichToDo = 1;
}
// break symmetry:
- else if (reverseInsertOrder)
- {
+ else if (reverseInsertOrder) {
whichToDo = 2;
- }
- else
- {
+ } else {
whichToDo = 1;
}
}
- if (whichToDo == 1)
- {
+ if (whichToDo == 1) {
chars1.skip(op1.chars);
opOut.opcode = '=';
opOut.lines = op1.lines;
opOut.chars = op1.chars;
opOut.attribs = '';
op1.opcode = '';
- }
- else
- {
+ } else {
// whichToDo == 2
chars2.skip(op2.chars);
- Changeset.copyOp(op2, opOut);
+ exports.copyOp(op2, opOut);
op2.opcode = '';
}
- }
- else if (op1.opcode == '-')
- {
- if (!op2.opcode)
- {
+ } else if (op1.opcode == '-') {
+ if (!op2.opcode) {
op1.opcode = '';
- }
- else
- {
- if (op1.chars <= op2.chars)
- {
+ } else {
+ if (op1.chars <= op2.chars) {
op2.chars -= op1.chars;
op2.lines -= op1.lines;
op1.opcode = '';
- if (!op2.chars)
- {
+ if (!op2.chars) {
op2.opcode = '';
}
- }
- else
- {
+ } else {
op1.chars -= op2.chars;
op1.lines -= op2.lines;
op2.opcode = '';
}
}
- }
- else if (op2.opcode == '-')
- {
- Changeset.copyOp(op2, opOut);
- if (!op1.opcode)
- {
+ } else if (op2.opcode == '-') {
+ exports.copyOp(op2, opOut);
+ if (!op1.opcode) {
op2.opcode = '';
- }
- else if (op2.chars <= op1.chars)
- {
+ } else if (op2.chars <= op1.chars) {
// delete part or all of a keep
op1.chars -= op2.chars;
op1.lines -= op2.lines;
op2.opcode = '';
- if (!op1.chars)
- {
+ if (!op1.chars) {
op1.opcode = '';
}
- }
- else
- {
+ } else {
// delete all of a keep, and keep going
opOut.lines = op1.lines;
opOut.chars = op1.chars;
@@ -2409,36 +1885,26 @@ Changeset.follow = function(cs1, cs2, reverseInsertOrder, pool)
op2.chars -= op1.chars;
op1.opcode = '';
}
- }
- else if (!op1.opcode)
- {
- Changeset.copyOp(op2, opOut);
+ } else if (!op1.opcode) {
+ exports.copyOp(op2, opOut);
op2.opcode = '';
- }
- else if (!op2.opcode)
- {
- Changeset.copyOp(op1, opOut);
+ } else if (!op2.opcode) {
+ exports.copyOp(op1, opOut);
op1.opcode = '';
- }
- else
- {
+ } else {
// both keeps
opOut.opcode = '=';
- opOut.attribs = Changeset.followAttributes(op1.attribs, op2.attribs, pool);
- if (op1.chars <= op2.chars)
- {
+ opOut.attribs = exports.followAttributes(op1.attribs, op2.attribs, pool);
+ if (op1.chars <= op2.chars) {
opOut.chars = op1.chars;
opOut.lines = op1.lines;
op2.chars -= op1.chars;
op2.lines -= op1.lines;
op1.opcode = '';
- if (!op2.chars)
- {
+ if (!op2.chars) {
op2.opcode = '';
}
- }
- else
- {
+ } else {
opOut.chars = op2.chars;
opOut.lines = op2.lines;
op1.chars -= op2.chars;
@@ -2446,8 +1912,7 @@ Changeset.follow = function(cs1, cs2, reverseInsertOrder, pool)
op2.opcode = '';
}
}
- switch (opOut.opcode)
- {
+ switch (opOut.opcode) {
case '=':
oldPos += opOut.chars;
newLen += opOut.chars;
@@ -2462,11 +1927,10 @@ Changeset.follow = function(cs1, cs2, reverseInsertOrder, pool)
});
newLen += oldLen - oldPos;
- return Changeset.pack(oldLen, newLen, newOps, unpacked2.charBank);
+ return exports.pack(oldLen, newLen, newOps, unpacked2.charBank);
};
-Changeset.followAttributes = function(att1, att2, pool)
-{
+exports.followAttributes = function (att1, att2, pool) {
// The merge of two sets of attribute changes to the same text
// takes the lexically-earlier value if there are two values
// for the same key. Otherwise, all key/value changes from
@@ -2476,21 +1940,16 @@ Changeset.followAttributes = function(att1, att2, pool)
if ((!att2) || (!pool)) return '';
if (!att1) return att2;
var atts = [];
- att2.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- atts.push(pool.getAttrib(Changeset.parseNum(a)));
+ att2.replace(/\*([0-9a-z]+)/g, function (_, a) {
+ atts.push(pool.getAttrib(exports.parseNum(a)));
return '';
});
- att1.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- var pair1 = pool.getAttrib(Changeset.parseNum(a));
- for (var i = 0; i < atts.length; i++)
- {
+ att1.replace(/\*([0-9a-z]+)/g, function (_, a) {
+ var pair1 = pool.getAttrib(exports.parseNum(a));
+ for (var i = 0; i < atts.length; i++) {
var pair2 = atts[i];
- if (pair1[0] == pair2[0])
- {
- if (pair1[1] <= pair2[1])
- {
+ if (pair1[0] == pair2[0]) {
+ if (pair1[1] <= pair2[1]) {
// winner of merge is pair1, delete this attribute
atts.splice(i, 1);
}
@@ -2500,14 +1959,10 @@ Changeset.followAttributes = function(att1, att2, pool)
return '';
});
// we've only removed attributes, so they're already sorted
- var buf = Changeset.stringAssembler();
- for (var i = 0; i < atts.length; i++)
- {
+ var buf = exports.stringAssembler();
+ for (var i = 0; i < atts.length; i++) {
buf.append('*');
- buf.append(Changeset.numToString(pool.putAttrib(atts[i])));
+ buf.append(exports.numToString(pool.putAttrib(atts[i])));
}
return buf.toString();
};
-
-exports.Changeset = Changeset;
-exports.AttribPool = AttribPool;
diff --git a/static/js/ace2_common.js b/static/js/ace2_common.js
index 1ce7810a..b4c72a92 100644
--- a/static/js/ace2_common.js
+++ b/static/js/ace2_common.js
@@ -20,6 +20,7 @@
* limitations under the License.
*/
+var Security = require('/security');
function isNodeText(node)
{
@@ -137,14 +138,7 @@ function binarySearchInfinite(expectedLength, func)
function htmlPrettyEscape(str)
{
- return str.replace(/[&"<>]/g, function (c) {
- return {
- '&': '&amp;',
- '"': '&quot;',
- '<': '&lt;',
- '>': '&gt;'
- }[c] || c;
- }).replace(/\r?\n/g, '\\n');
+ return Security.escapeHTML(str).replace(/\r?\n/g, '\\n');
}
exports.isNodeText = isNodeText;
diff --git a/static/js/ace2_inner.js b/static/js/ace2_inner.js
index 31d4dac9..d2113574 100644
--- a/static/js/ace2_inner.js
+++ b/static/js/ace2_inner.js
@@ -42,8 +42,8 @@ var colorutils = require('/colorutils').colorutils;
var makeContentCollector = require('/contentcollector').makeContentCollector;
var makeCSSManager = require('/cssmanager').makeCSSManager;
var domline = require('/domline').domline;
-var AttribPool = require('/easysync2').AttribPool;
-var Changeset = require('/easysync2').Changeset;
+var AttribPool = require('/AttributePoolFactory').createAttributePool;
+var Changeset = require('/Changeset');
var linestylefilter = require('/linestylefilter').linestylefilter;
var newSkipList = require('/skiplist').newSkipList;
var undoModule = require('/undomodule').undoModule;
diff --git a/static/js/broadcast.js b/static/js/broadcast.js
index 020f47e7..4a7b0168 100644
--- a/static/js/broadcast.js
+++ b/static/js/broadcast.js
@@ -20,11 +20,11 @@
* limitations under the License.
*/
-var makeCSSManager = require('/cssmanager_client').makeCSSManager;
-var domline = require('/domline_client').domline;
-var Changeset = require('/easysync2_client').Changeset;
-var AttribPool = require('/easysync2_client').AttribPool;
-var linestylefilter = require('/linestylefilter_client').linestylefilter;
+var makeCSSManager = require('/cssmanager').makeCSSManager;
+var domline = require('/domline').domline;
+var AttribPool = require('/AttributePoolFactory').createAttributePool;
+var Changeset = require('/Changeset');
+var linestylefilter = require('/linestylefilter').linestylefilter;
var colorutils = require('/colorutils').colorutils;
// These parameters were global, now they are injected. A reference to the
diff --git a/static/js/changesettracker.js b/static/js/changesettracker.js
index 7b0fb3e4..e34dc107 100644
--- a/static/js/changesettracker.js
+++ b/static/js/changesettracker.js
@@ -20,8 +20,8 @@
* limitations under the License.
*/
-var Changeset = require('/easysync2').Changeset;
-var AttribPool = require('/easysync2').AttribPool;
+var AttribPool = require('/AttributePoolFactory').createAttributePool;
+var Changeset = require('/Changeset');
function makeChangesetTracker(scheduler, apool, aceCallbacksProvider)
{
diff --git a/static/js/contentcollector.js b/static/js/contentcollector.js
index 0437ccd7..96dc4b7d 100644
--- a/static/js/contentcollector.js
+++ b/static/js/contentcollector.js
@@ -25,7 +25,7 @@
var _MAX_LIST_LEVEL = 8;
-var Changeset = require('/easysync2').Changeset
+var Changeset = require('/Changeset');
var plugins = require('/plugins').plugins;
function sanitizeUnicode(s)
diff --git a/static/js/cssmanager_client.js b/static/js/cssmanager_client.js
deleted file mode 100644
index 6d9d989e..00000000
--- a/static/js/cssmanager_client.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * This code is mostly from the old Etherpad. Please help us to comment this code.
- * This helps other people to understand this code better and helps them to improve it.
- * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
- */
-
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/cssmanager.js
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS-IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-function makeCSSManager(emptyStylesheetTitle)
-{
-
- function getSheetByTitle(title)
- {
- var allSheets = document.styleSheets;
- for (var i = 0; i < allSheets.length; i++)
- {
- var s = allSheets[i];
- if (s.title == title)
- {
- return s;
- }
- }
- return null;
- }
-
-/*function getSheetTagByTitle(title) {
- var allStyleTags = document.getElementsByTagName("style");
- for(var i=0;i<allStyleTags.length;i++) {
- var t = allStyleTags[i];
- if (t.title == title) {
- return t;
- }
- }
- return null;
- }*/
-
- var browserSheet = getSheetByTitle(emptyStylesheetTitle);
- //var browserTag = getSheetTagByTitle(emptyStylesheetTitle);
-
- function browserRules()
- {
- return (browserSheet.cssRules || browserSheet.rules);
- }
-
- function browserDeleteRule(i)
- {
- if (browserSheet.deleteRule) browserSheet.deleteRule(i);
- else browserSheet.removeRule(i);
- }
-
- function browserInsertRule(i, selector)
- {
- if (browserSheet.insertRule) browserSheet.insertRule(selector + ' {}', i);
- else browserSheet.addRule(selector, null, i);
- }
- var selectorList = [];
-
- function indexOfSelector(selector)
- {
- for (var i = 0; i < selectorList.length; i++)
- {
- if (selectorList[i] == selector)
- {
- return i;
- }
- }
- return -1;
- }
-
- function selectorStyle(selector)
- {
- var i = indexOfSelector(selector);
- if (i < 0)
- {
- // add selector
- browserInsertRule(0, selector);
- selectorList.splice(0, 0, selector);
- i = 0;
- }
- return browserRules().item(i).style;
- }
-
- function removeSelectorStyle(selector)
- {
- var i = indexOfSelector(selector);
- if (i >= 0)
- {
- browserDeleteRule(i);
- selectorList.splice(i, 1);
- }
- }
-
- return {
- selectorStyle: selectorStyle,
- removeSelectorStyle: removeSelectorStyle,
- info: function()
- {
- return selectorList.length + ":" + browserRules().length;
- }
- };
-}
-
-exports.makeCSSManager = makeCSSManager;
diff --git a/static/js/domline.js b/static/js/domline.js
index 8d8c2ea9..15528bf7 100644
--- a/static/js/domline.js
+++ b/static/js/domline.js
@@ -26,6 +26,7 @@
// requires: plugins
// requires: undefined
+var Security = require('/security');
var plugins = require('/plugins').plugins;
var map = require('/ace2_common').map;
@@ -103,17 +104,17 @@ domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
if (listType)
{
listType = listType[1];
- start = start?'start="'+start[1]+'"':'';
+ start = start?'start="'+Security.escapeHTMLAttribute(start[1])+'"':'';
if (listType)
{
if(listType.indexOf("number") < 0)
{
- preHtml = '<ul class="list-' + listType + '"><li>';
+ preHtml = '<ul class="list-' + Security.escapeHTMLAttribute(listType) + '"><li>';
postHtml = '</li></ul>';
}
else
{
- preHtml = '<ol '+start+' class="list-' + listType + '"><li>';
+ preHtml = '<ol '+start+' class="list-' + Security.escapeHTMLAttribute(listType) + '"><li>';
postHtml = '</li></ol>';
}
}
@@ -168,7 +169,7 @@ domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
{
href = "http://"+href;
}
- extraOpenTags = extraOpenTags + '<a href="' + domline.escapeHTML(href) + '">';
+ extraOpenTags = extraOpenTags + '<a href="' + Security.escapeHTMLAttribute(href) + '">';
extraCloseTags = '</a>' + extraCloseTags;
}
if (simpleTags)
@@ -178,7 +179,7 @@ domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
simpleTags.reverse();
extraCloseTags = '</' + simpleTags.join('></') + '>' + extraCloseTags;
}
- html.push('<span class="', cls || '', '">', extraOpenTags, perTextNodeProcess(domline.escapeHTML(txt)), extraCloseTags, '</span>');
+ html.push('<span class="', Security.escapeHTMLAttribute(cls || ''), '">', extraOpenTags, perTextNodeProcess(Security.escapeHTML(txt)), extraCloseTags, '</span>');
}
};
result.clearSpans = function()
@@ -224,27 +225,6 @@ domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
return result;
};
-domline.escapeHTML = function(s)
-{
- var re = /[&<>'"]/g;
- /']/; // stupid indentation thing
- if (!re.MAP)
- {
- // persisted across function calls!
- re.MAP = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&quot;',
- "'": '&#39;'
- };
- }
- return s.replace(re, function(c)
- {
- return re.MAP[c];
- });
-};
-
domline.processSpaces = function(s, doesWrap)
{
if (s.indexOf("<") < 0 && !doesWrap)
diff --git a/static/js/domline_client.js b/static/js/domline_client.js
deleted file mode 100644
index 87b6ed55..00000000
--- a/static/js/domline_client.js
+++ /dev/null
@@ -1,309 +0,0 @@
-/**
- * This code is mostly from the old Etherpad. Please help us to comment this code.
- * This helps other people to understand this code better and helps them to improve it.
- * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
- */
-
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/domline.js
-// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.domline
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS-IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// requires: top
-// requires: plugins
-// requires: undefined
-
-var plugins = require('/plugins').plugins;
-var map = require('/ace2_common').map;
-
-var domline = {};
-domline.noop = function()
-{};
-domline.identity = function(x)
-{
- return x;
-};
-
-domline.addToLineClass = function(lineClass, cls)
-{
- // an "empty span" at any point can be used to add classes to
- // the line, using line:className. otherwise, we ignore
- // the span.
- cls.replace(/\S+/g, function(c)
- {
- if (c.indexOf("line:") == 0)
- {
- // add class to line
- lineClass = (lineClass ? lineClass + ' ' : '') + c.substring(5);
- }
- });
- return lineClass;
-}
-
-// if "document" is falsy we don't create a DOM node, just
-// an object with innerHTML and className
-domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
-{
- var result = {
- node: null,
- appendSpan: domline.noop,
- prepareForAdd: domline.noop,
- notifyAdded: domline.noop,
- clearSpans: domline.noop,
- finishUpdate: domline.noop,
- lineMarker: 0
- };
-
- var browser = (optBrowser || {});
- var document = optDocument;
-
- if (document)
- {
- result.node = document.createElement("div");
- }
- else
- {
- result.node = {
- innerHTML: '',
- className: ''
- };
- }
-
- var html = [];
- var preHtml, postHtml;
- var curHTML = null;
-
- function processSpaces(s)
- {
- return domline.processSpaces(s, doesWrap);
- }
- var identity = domline.identity;
- var perTextNodeProcess = (doesWrap ? identity : processSpaces);
- var perHtmlLineProcess = (doesWrap ? processSpaces : identity);
- var lineClass = 'ace-line';
- result.appendSpan = function(txt, cls)
- {
- if (cls.indexOf('list') >= 0)
- {
- var listType = /(?:^| )list:(\S+)/.exec(cls);
- var start = /(?:^| )start:(\S+)/.exec(cls);
- if (listType)
- {
- listType = listType[1];
- start = start?'start="'+start[1]+'"':'';
- if (listType)
- {
- if(listType.indexOf("number") < 0)
- {
- preHtml = '<ul class="list-' + listType + '"><li>';
- postHtml = '</li></ul>';
- }
- else
- {
- preHtml = '<ol '+start+' class="list-' + listType + '"><li>';
- postHtml = '</li></ol>';
- }
- }
- result.lineMarker += txt.length;
- return; // don't append any text
- }
- }
- var href = null;
- var simpleTags = null;
- if (cls.indexOf('url') >= 0)
- {
- cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url)
- {
- href = url;
- return space + "url";
- });
- }
- if (cls.indexOf('tag') >= 0)
- {
- cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag)
- {
- if (!simpleTags) simpleTags = [];
- simpleTags.push(tag.toLowerCase());
- return space + tag;
- });
- }
-
- var extraOpenTags = "";
- var extraCloseTags = "";
-
- var plugins_ = plugins;
-
- map(plugins_.callHook("aceCreateDomLine", {
- domline: domline,
- cls: cls
- }), function(modifier)
- {
- cls = modifier.cls;
- extraOpenTags = extraOpenTags + modifier.extraOpenTags;
- extraCloseTags = modifier.extraCloseTags + extraCloseTags;
- });
-
- if ((!txt) && cls)
- {
- lineClass = domline.addToLineClass(lineClass, cls);
- }
- else if (txt)
- {
- if (href)
- {
- if(!~href.indexOf("http")) // if the url doesn't include http or https etc prefix it.
- {
- href = "http://"+href;
- }
- extraOpenTags = extraOpenTags + '<a href="' + href.replace(/\"/g, '&quot;') + '">';
- extraCloseTags = '</a>' + extraCloseTags;
- }
- if (simpleTags)
- {
- simpleTags.sort();
- extraOpenTags = extraOpenTags + '<' + simpleTags.join('><') + '>';
- simpleTags.reverse();
- extraCloseTags = '</' + simpleTags.join('></') + '>' + extraCloseTags;
- }
- html.push('<span class="', cls || '', '">', extraOpenTags, perTextNodeProcess(domline.escapeHTML(txt)), extraCloseTags, '</span>');
- }
- };
- result.clearSpans = function()
- {
- html = [];
- lineClass = ''; // non-null to cause update
- result.lineMarker = 0;
- };
-
- function writeHTML()
- {
- var newHTML = perHtmlLineProcess(html.join(''));
- if (!newHTML)
- {
- if ((!document) || (!optBrowser))
- {
- newHTML += '&nbsp;';
- }
- else if (!browser.msie)
- {
- newHTML += '<br/>';
- }
- }
- if (nonEmpty)
- {
- newHTML = (preHtml || '') + newHTML + (postHtml || '');
- }
- html = preHtml = postHtml = null; // free memory
- if (newHTML !== curHTML)
- {
- curHTML = newHTML;
- result.node.innerHTML = curHTML;
- }
- if (lineClass !== null) result.node.className = lineClass;
- }
- result.prepareForAdd = writeHTML;
- result.finishUpdate = writeHTML;
- result.getInnerHTML = function()
- {
- return curHTML || '';
- };
-
- return result;
-};
-
-domline.escapeHTML = function(s)
-{
- var re = /[&<>'"]/g;
- /']/; // stupid indentation thing
- if (!re.MAP)
- {
- // persisted across function calls!
- re.MAP = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&#34;',
- "'": '&#39;'
- };
- }
- return s.replace(re, function(c)
- {
- return re.MAP[c];
- });
-};
-
-domline.processSpaces = function(s, doesWrap)
-{
- if (s.indexOf("<") < 0 && !doesWrap)
- {
- // short-cut
- return s.replace(/ /g, '&nbsp;');
- }
- var parts = [];
- s.replace(/<[^>]*>?| |[^ <]+/g, function(m)
- {
- parts.push(m);
- });
- if (doesWrap)
- {
- var endOfLine = true;
- var beforeSpace = false;
- // last space in a run is normal, others are nbsp,
- // end of line is nbsp
- for (var i = parts.length - 1; i >= 0; i--)
- {
- var p = parts[i];
- if (p == " ")
- {
- if (endOfLine || beforeSpace) parts[i] = '&nbsp;';
- endOfLine = false;
- beforeSpace = true;
- }
- else if (p.charAt(0) != "<")
- {
- endOfLine = false;
- beforeSpace = false;
- }
- }
- // beginning of line is nbsp
- for (var i = 0; i < parts.length; i++)
- {
- var p = parts[i];
- if (p == " ")
- {
- parts[i] = '&nbsp;';
- break;
- }
- else if (p.charAt(0) != "<")
- {
- break;
- }
- }
- }
- else
- {
- for (var i = 0; i < parts.length; i++)
- {
- var p = parts[i];
- if (p == " ")
- {
- parts[i] = '&nbsp;';
- }
- }
- }
- return parts.join('');
-};
-
-exports.domline = domline;
diff --git a/static/js/easysync2_client.js b/static/js/easysync2_client.js
deleted file mode 100644
index f4f3d08f..00000000
--- a/static/js/easysync2_client.js
+++ /dev/null
@@ -1,2274 +0,0 @@
-/**
- * This code is mostly from the old Etherpad. Please help us to comment this code.
- * This helps other people to understand this code better and helps them to improve it.
- * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
- */
-
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/easysync2.js
-// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.easysync2
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS-IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//var _opt = (this.Easysync2Support || null);
-var _opt = null; // disable optimization for now
-
-function AttribPool()
-{
- var p = {};
- p.numToAttrib = {}; // e.g. {0: ['foo','bar']}
- p.attribToNum = {}; // e.g. {'foo,bar': 0}
- p.nextNum = 0;
-
- p.putAttrib = function(attrib, dontAddIfAbsent)
- {
- var str = String(attrib);
- if (str in p.attribToNum)
- {
- return p.attribToNum[str];
- }
- if (dontAddIfAbsent)
- {
- return -1;
- }
- var num = p.nextNum++;
- p.attribToNum[str] = num;
- p.numToAttrib[num] = [String(attrib[0] || ''), String(attrib[1] || '')];
- return num;
- };
-
- p.getAttrib = function(num)
- {
- var pair = p.numToAttrib[num];
- if (!pair) return pair;
- return [pair[0], pair[1]]; // return a mutable copy
- };
-
- p.getAttribKey = function(num)
- {
- var pair = p.numToAttrib[num];
- if (!pair) return '';
- return pair[0];
- };
-
- p.getAttribValue = function(num)
- {
- var pair = p.numToAttrib[num];
- if (!pair) return '';
- return pair[1];
- };
-
- p.eachAttrib = function(func)
- {
- for (var n in p.numToAttrib)
- {
- var pair = p.numToAttrib[n];
- func(pair[0], pair[1]);
- }
- };
-
- p.toJsonable = function()
- {
- return {
- numToAttrib: p.numToAttrib,
- nextNum: p.nextNum
- };
- };
-
- p.fromJsonable = function(obj)
- {
- p.numToAttrib = obj.numToAttrib;
- p.nextNum = obj.nextNum;
- p.attribToNum = {};
- for (var n in p.numToAttrib)
- {
- p.attribToNum[String(p.numToAttrib[n])] = Number(n);
- }
- return p;
- };
-
- return p;
-}
-
-var Changeset = {};
-
-Changeset.error = function error(msg)
-{
- var e = new Error(msg);
- e.easysync = true;
- throw e;
-};
-Changeset.assert = function assert(b, msgParts)
-{
- if (!b)
- {
- var msg = Array.prototype.slice.call(arguments, 1).join('');
- Changeset.error("Changeset: " + msg);
- }
-};
-
-Changeset.parseNum = function(str)
-{
- return parseInt(str, 36);
-};
-Changeset.numToString = function(num)
-{
- return num.toString(36).toLowerCase();
-};
-Changeset.toBaseTen = function(cs)
-{
- var dollarIndex = cs.indexOf('$');
- var beforeDollar = cs.substring(0, dollarIndex);
- var fromDollar = cs.substring(dollarIndex);
- return beforeDollar.replace(/[0-9a-z]+/g, function(s)
- {
- return String(Changeset.parseNum(s));
- }) + fromDollar;
-};
-
-Changeset.oldLen = function(cs)
-{
- return Changeset.unpack(cs).oldLen;
-};
-Changeset.newLen = function(cs)
-{
- return Changeset.unpack(cs).newLen;
-};
-
-Changeset.opIterator = function(opsStr, optStartIndex)
-{
- //print(opsStr);
- var regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|\?|/g;
- var startIndex = (optStartIndex || 0);
- var curIndex = startIndex;
- var prevIndex = curIndex;
-
- function nextRegexMatch()
- {
- prevIndex = curIndex;
- var result;
- if (_opt)
- {
- result = _opt.nextOpInString(opsStr, curIndex);
- if (result)
- {
- if (result.opcode() == '?')
- {
- Changeset.error("Hit error opcode in op stream");
- }
- curIndex = result.lastIndex();
- }
- }
- else
- {
- regex.lastIndex = curIndex;
- result = regex.exec(opsStr);
- curIndex = regex.lastIndex;
- if (result[0] == '?')
- {
- Changeset.error("Hit error opcode in op stream");
- }
- }
- return result;
- }
- var regexResult = nextRegexMatch();
- var obj = Changeset.newOp();
-
- function next(optObj)
- {
- var op = (optObj || obj);
- if (_opt && regexResult)
- {
- op.attribs = regexResult.attribs();
- op.lines = regexResult.lines();
- op.chars = regexResult.chars();
- op.opcode = regexResult.opcode();
- regexResult = nextRegexMatch();
- }
- else if ((!_opt) && regexResult[0])
- {
- op.attribs = regexResult[1];
- op.lines = Changeset.parseNum(regexResult[2] || 0);
- op.opcode = regexResult[3];
- op.chars = Changeset.parseNum(regexResult[4]);
- regexResult = nextRegexMatch();
- }
- else
- {
- Changeset.clearOp(op);
- }
- return op;
- }
-
- function hasNext()
- {
- return !!(_opt ? regexResult : regexResult[0]);
- }
-
- function lastIndex()
- {
- return prevIndex;
- }
- return {
- next: next,
- hasNext: hasNext,
- lastIndex: lastIndex
- };
-};
-
-Changeset.clearOp = function(op)
-{
- op.opcode = '';
- op.chars = 0;
- op.lines = 0;
- op.attribs = '';
-};
-Changeset.newOp = function(optOpcode)
-{
- return {
- opcode: (optOpcode || ''),
- chars: 0,
- lines: 0,
- attribs: ''
- };
-};
-Changeset.cloneOp = function(op)
-{
- return {
- opcode: op.opcode,
- chars: op.chars,
- lines: op.lines,
- attribs: op.attribs
- };
-};
-Changeset.copyOp = function(op1, op2)
-{
- op2.opcode = op1.opcode;
- op2.chars = op1.chars;
- op2.lines = op1.lines;
- op2.attribs = op1.attribs;
-};
-Changeset.opString = function(op)
-{
- // just for debugging
- if (!op.opcode) return 'null';
- var assem = Changeset.opAssembler();
- assem.append(op);
- return assem.toString();
-};
-Changeset.stringOp = function(str)
-{
- // just for debugging
- return Changeset.opIterator(str).next();
-};
-
-Changeset.checkRep = function(cs)
-{
- // doesn't check things that require access to attrib pool (e.g. attribute order)
- // or original string (e.g. newline positions)
- var unpacked = Changeset.unpack(cs);
- var oldLen = unpacked.oldLen;
- var newLen = unpacked.newLen;
- var ops = unpacked.ops;
- var charBank = unpacked.charBank;
-
- var assem = Changeset.smartOpAssembler();
- var oldPos = 0;
- var calcNewLen = 0;
- var numInserted = 0;
- var iter = Changeset.opIterator(ops);
- while (iter.hasNext())
- {
- var o = iter.next();
- switch (o.opcode)
- {
- case '=':
- oldPos += o.chars;
- calcNewLen += o.chars;
- break;
- case '-':
- oldPos += o.chars;
- Changeset.assert(oldPos < oldLen, oldPos, " >= ", oldLen, " in ", cs);
- break;
- case '+':
- {
- calcNewLen += o.chars;
- numInserted += o.chars;
- Changeset.assert(calcNewLen < newLen, calcNewLen, " >= ", newLen, " in ", cs);
- break;
- }
- }
- assem.append(o);
- }
-
- calcNewLen += oldLen - oldPos;
- charBank = charBank.substring(0, numInserted);
- while (charBank.length < numInserted)
- {
- charBank += "?";
- }
-
- assem.endDocument();
- var normalized = Changeset.pack(oldLen, calcNewLen, assem.toString(), charBank);
- Changeset.assert(normalized == cs, normalized, ' != ', cs);
-
- return cs;
-}
-
-Changeset.smartOpAssembler = function()
-{
- // Like opAssembler but able to produce conforming changesets
- // from slightly looser input, at the cost of speed.
- // Specifically:
- // - merges consecutive operations that can be merged
- // - strips final "="
- // - ignores 0-length changes
- // - reorders consecutive + and - (which margingOpAssembler doesn't do)
- var minusAssem = Changeset.mergingOpAssembler();
- var plusAssem = Changeset.mergingOpAssembler();
- var keepAssem = Changeset.mergingOpAssembler();
- var assem = Changeset.stringAssembler();
- var lastOpcode = '';
- var lengthChange = 0;
-
- function flushKeeps()
- {
- assem.append(keepAssem.toString());
- keepAssem.clear();
- }
-
- function flushPlusMinus()
- {
- assem.append(minusAssem.toString());
- minusAssem.clear();
- assem.append(plusAssem.toString());
- plusAssem.clear();
- }
-
- function append(op)
- {
- if (!op.opcode) return;
- if (!op.chars) return;
-
- if (op.opcode == '-')
- {
- if (lastOpcode == '=')
- {
- flushKeeps();
- }
- minusAssem.append(op);
- lengthChange -= op.chars;
- }
- else if (op.opcode == '+')
- {
- if (lastOpcode == '=')
- {
- flushKeeps();
- }
- plusAssem.append(op);
- lengthChange += op.chars;
- }
- else if (op.opcode == '=')
- {
- if (lastOpcode != '=')
- {
- flushPlusMinus();
- }
- keepAssem.append(op);
- }
- lastOpcode = op.opcode;
- }
-
- function appendOpWithText(opcode, text, attribs, pool)
- {
- var op = Changeset.newOp(opcode);
- op.attribs = Changeset.makeAttribsString(opcode, attribs, pool);
- var lastNewlinePos = text.lastIndexOf('\n');
- if (lastNewlinePos < 0)
- {
- op.chars = text.length;
- op.lines = 0;
- append(op);
- }
- else
- {
- op.chars = lastNewlinePos + 1;
- op.lines = text.match(/\n/g).length;
- append(op);
- op.chars = text.length - (lastNewlinePos + 1);
- op.lines = 0;
- append(op);
- }
- }
-
- function toString()
- {
- flushPlusMinus();
- flushKeeps();
- return assem.toString();
- }
-
- function clear()
- {
- minusAssem.clear();
- plusAssem.clear();
- keepAssem.clear();
- assem.clear();
- lengthChange = 0;
- }
-
- function endDocument()
- {
- keepAssem.endDocument();
- }
-
- function getLengthChange()
- {
- return lengthChange;
- }
-
- return {
- append: append,
- toString: toString,
- clear: clear,
- endDocument: endDocument,
- appendOpWithText: appendOpWithText,
- getLengthChange: getLengthChange
- };
-};
-
-if (_opt)
-{
- Changeset.mergingOpAssembler = function()
- {
- var assem = _opt.mergingOpAssembler();
-
- function append(op)
- {
- assem.append(op.opcode, op.chars, op.lines, op.attribs);
- }
-
- function toString()
- {
- return assem.toString();
- }
-
- function clear()
- {
- assem.clear();
- }
-
- function endDocument()
- {
- assem.endDocument();
- }
-
- return {
- append: append,
- toString: toString,
- clear: clear,
- endDocument: endDocument
- };
- };
-}
-else
-{
- Changeset.mergingOpAssembler = function()
- {
- // This assembler can be used in production; it efficiently
- // merges consecutive operations that are mergeable, ignores
- // no-ops, and drops final pure "keeps". It does not re-order
- // operations.
- var assem = Changeset.opAssembler();
- var bufOp = Changeset.newOp();
-
- // If we get, for example, insertions [xxx\n,yyy], those don't merge,
- // but if we get [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n].
- // This variable stores the length of yyy and any other newline-less
- // ops immediately after it.
- var bufOpAdditionalCharsAfterNewline = 0;
-
- function flush(isEndDocument)
- {
- if (bufOp.opcode)
- {
- if (isEndDocument && bufOp.opcode == '=' && !bufOp.attribs)
- {
- // final merged keep, leave it implicit
- }
- else
- {
- assem.append(bufOp);
- if (bufOpAdditionalCharsAfterNewline)
- {
- bufOp.chars = bufOpAdditionalCharsAfterNewline;
- bufOp.lines = 0;
- assem.append(bufOp);
- bufOpAdditionalCharsAfterNewline = 0;
- }
- }
- bufOp.opcode = '';
- }
- }
-
- function append(op)
- {
- if (op.chars > 0)
- {
- if (bufOp.opcode == op.opcode && bufOp.attribs == op.attribs)
- {
- if (op.lines > 0)
- {
- // bufOp and additional chars are all mergeable into a multi-line op
- bufOp.chars += bufOpAdditionalCharsAfterNewline + op.chars;
- bufOp.lines += op.lines;
- bufOpAdditionalCharsAfterNewline = 0;
- }
- else if (bufOp.lines == 0)
- {
- // both bufOp and op are in-line
- bufOp.chars += op.chars;
- }
- else
- {
- // append in-line text to multi-line bufOp
- bufOpAdditionalCharsAfterNewline += op.chars;
- }
- }
- else
- {
- flush();
- Changeset.copyOp(op, bufOp);
- }
- }
- }
-
- function endDocument()
- {
- flush(true);
- }
-
- function toString()
- {
- flush();
- return assem.toString();
- }
-
- function clear()
- {
- assem.clear();
- Changeset.clearOp(bufOp);
- }
- return {
- append: append,
- toString: toString,
- clear: clear,
- endDocument: endDocument
- };
- };
-}
-
-if (_opt)
-{
- Changeset.opAssembler = function()
- {
- var assem = _opt.opAssembler();
- // this function allows op to be mutated later (doesn't keep a ref)
-
- function append(op)
- {
- assem.append(op.opcode, op.chars, op.lines, op.attribs);
- }
-
- function toString()
- {
- return assem.toString();
- }
-
- function clear()
- {
- assem.clear();
- }
- return {
- append: append,
- toString: toString,
- clear: clear
- };
- };
-}
-else
-{
- Changeset.opAssembler = function()
- {
- var pieces = [];
- // this function allows op to be mutated later (doesn't keep a ref)
-
- function append(op)
- {
- pieces.push(op.attribs);
- if (op.lines)
- {
- pieces.push('|', Changeset.numToString(op.lines));
- }
- pieces.push(op.opcode);
- pieces.push(Changeset.numToString(op.chars));
- }
-
- function toString()
- {
- return pieces.join('');
- }
-
- function clear()
- {
- pieces.length = 0;
- }
- return {
- append: append,
- toString: toString,
- clear: clear
- };
- };
-}
-
-Changeset.stringIterator = function(str)
-{
- var curIndex = 0;
-
- function assertRemaining(n)
- {
- Changeset.assert(n <= remaining(), "!(", n, " <= ", remaining(), ")");
- }
-
- function take(n)
- {
- assertRemaining(n);
- var s = str.substr(curIndex, n);
- curIndex += n;
- return s;
- }
-
- function peek(n)
- {
- assertRemaining(n);
- var s = str.substr(curIndex, n);
- return s;
- }
-
- function skip(n)
- {
- assertRemaining(n);
- curIndex += n;
- }
-
- function remaining()
- {
- return str.length - curIndex;
- }
- return {
- take: take,
- skip: skip,
- remaining: remaining,
- peek: peek
- };
-};
-
-Changeset.stringAssembler = function()
-{
- var pieces = [];
-
- function append(x)
- {
- pieces.push(String(x));
- }
-
- function toString()
- {
- return pieces.join('');
- }
- return {
- append: append,
- toString: toString
- };
-};
-
-// "lines" need not be an array as long as it supports certain calls (lines_foo inside).
-Changeset.textLinesMutator = function(lines)
-{
- // Mutates lines, an array of strings, in place.
- // Mutation operations have the same constraints as changeset operations
- // with respect to newlines, but not the other additional constraints
- // (i.e. ins/del ordering, forbidden no-ops, non-mergeability, final newline).
- // Can be used to mutate lists of strings where the last char of each string
- // is not actually a newline, but for the purposes of N and L values,
- // the caller should pretend it is, and for things to work right in that case, the input
- // to insert() should be a single line with no newlines.
- var curSplice = [0, 0];
- var inSplice = false;
- // position in document after curSplice is applied:
- var curLine = 0,
- curCol = 0;
- // invariant: if (inSplice) then (curLine is in curSplice[0] + curSplice.length - {2,3}) &&
- // curLine >= curSplice[0]
- // invariant: if (inSplice && (curLine >= curSplice[0] + curSplice.length - 2)) then
- // curCol == 0
-
- function lines_applySplice(s)
- {
- lines.splice.apply(lines, s);
- }
-
- function lines_toSource()
- {
- return lines.toSource();
- }
-
- function lines_get(idx)
- {
- if (lines.get)
- {
- return lines.get(idx);
- }
- else
- {
- return lines[idx];
- }
- }
- // can be unimplemented if removeLines's return value not needed
-
- function lines_slice(start, end)
- {
- if (lines.slice)
- {
- return lines.slice(start, end);
- }
- else
- {
- return [];
- }
- }
-
- function lines_length()
- {
- if ((typeof lines.length) == "number")
- {
- return lines.length;
- }
- else
- {
- return lines.length();
- }
- }
-
- function enterSplice()
- {
- curSplice[0] = curLine;
- curSplice[1] = 0;
- if (curCol > 0)
- {
- putCurLineInSplice();
- }
- inSplice = true;
- }
-
- function leaveSplice()
- {
- lines_applySplice(curSplice);
- curSplice.length = 2;
- curSplice[0] = curSplice[1] = 0;
- inSplice = false;
- }
-
- function isCurLineInSplice()
- {
- return (curLine - curSplice[0] < (curSplice.length - 2));
- }
-
- function debugPrint(typ)
- {
- print(typ + ": " + curSplice.toSource() + " / " + curLine + "," + curCol + " / " + lines_toSource());
- }
-
- function putCurLineInSplice()
- {
- if (!isCurLineInSplice())
- {
- curSplice.push(lines_get(curSplice[0] + curSplice[1]));
- curSplice[1]++;
- }
- return 2 + curLine - curSplice[0];
- }
-
- function skipLines(L, includeInSplice)
- {
- if (L)
- {
- if (includeInSplice)
- {
- if (!inSplice)
- {
- enterSplice();
- }
- for (var i = 0; i < L; i++)
- {
- curCol = 0;
- putCurLineInSplice();
- curLine++;
- }
- }
- else
- {
- if (inSplice)
- {
- if (L > 1)
- {
- leaveSplice();
- }
- else
- {
- putCurLineInSplice();
- }
- }
- curLine += L;
- curCol = 0;
- }
- //print(inSplice+" / "+isCurLineInSplice()+" / "+curSplice[0]+" / "+curSplice[1]+" / "+lines.length);
-/*if (inSplice && (! isCurLineInSplice()) && (curSplice[0] + curSplice[1] < lines.length)) {
- print("BLAH");
- putCurLineInSplice();
- }*/
- // tests case foo in remove(), which isn't otherwise covered in current impl
- }
- //debugPrint("skip");
- }
-
- function skip(N, L, includeInSplice)
- {
- if (N)
- {
- if (L)
- {
- skipLines(L, includeInSplice);
- }
- else
- {
- if (includeInSplice && !inSplice)
- {
- enterSplice();
- }
- if (inSplice)
- {
- putCurLineInSplice();
- }
- curCol += N;
- //debugPrint("skip");
- }
- }
- }
-
- function removeLines(L)
- {
- var removed = '';
- if (L)
- {
- if (!inSplice)
- {
- enterSplice();
- }
-
- function nextKLinesText(k)
- {
- var m = curSplice[0] + curSplice[1];
- return lines_slice(m, m + k).join('');
- }
- if (isCurLineInSplice())
- {
- //print(curCol);
- if (curCol == 0)
- {
- removed = curSplice[curSplice.length - 1];
- // print("FOO"); // case foo
- curSplice.length--;
- removed += nextKLinesText(L - 1);
- curSplice[1] += L - 1;
- }
- else
- {
- removed = nextKLinesText(L - 1);
- curSplice[1] += L - 1;
- var sline = curSplice.length - 1;
- removed = curSplice[sline].substring(curCol) + removed;
- curSplice[sline] = curSplice[sline].substring(0, curCol) + lines_get(curSplice[0] + curSplice[1]);
- curSplice[1] += 1;
- }
- }
- else
- {
- removed = nextKLinesText(L);
- curSplice[1] += L;
- }
- //debugPrint("remove");
- }
- return removed;
- }
-
- function remove(N, L)
- {
- var removed = '';
- if (N)
- {
- if (L)
- {
- return removeLines(L);
- }
- else
- {
- if (!inSplice)
- {
- enterSplice();
- }
- var sline = putCurLineInSplice();
- removed = curSplice[sline].substring(curCol, curCol + N);
- curSplice[sline] = curSplice[sline].substring(0, curCol) + curSplice[sline].substring(curCol + N);
- //debugPrint("remove");
- }
- }
- return removed;
- }
-
- function insert(text, L)
- {
- if (text)
- {
- if (!inSplice)
- {
- enterSplice();
- }
- if (L)
- {
- var newLines = Changeset.splitTextLines(text);
- if (isCurLineInSplice())
- {
- //if (curCol == 0) {
- //curSplice.length--;
- //curSplice[1]--;
- //Array.prototype.push.apply(curSplice, newLines);
- //curLine += newLines.length;
- //}
- //else {
- var sline = curSplice.length - 1;
- var theLine = curSplice[sline];
- var lineCol = curCol;
- curSplice[sline] = theLine.substring(0, lineCol) + newLines[0];
- curLine++;
- newLines.splice(0, 1);
- Array.prototype.push.apply(curSplice, newLines);
- curLine += newLines.length;
- curSplice.push(theLine.substring(lineCol));
- curCol = 0;
- //}
- }
- else
- {
- Array.prototype.push.apply(curSplice, newLines);
- curLine += newLines.length;
- }
- }
- else
- {
- var sline = putCurLineInSplice();
- curSplice[sline] = curSplice[sline].substring(0, curCol) + text + curSplice[sline].substring(curCol);
- curCol += text.length;
- }
- //debugPrint("insert");
- }
- }
-
- function hasMore()
- {
- //print(lines.length+" / "+inSplice+" / "+(curSplice.length - 2)+" / "+curSplice[1]);
- var docLines = lines_length();
- if (inSplice)
- {
- docLines += curSplice.length - 2 - curSplice[1];
- }
- return curLine < docLines;
- }
-
- function close()
- {
- if (inSplice)
- {
- leaveSplice();
- }
- //debugPrint("close");
- }
-
- var self = {
- skip: skip,
- remove: remove,
- insert: insert,
- close: close,
- hasMore: hasMore,
- removeLines: removeLines,
- skipLines: skipLines
- };
- return self;
-};
-
-Changeset.applyZip = function(in1, idx1, in2, idx2, func)
-{
- var iter1 = Changeset.opIterator(in1, idx1);
- var iter2 = Changeset.opIterator(in2, idx2);
- var assem = Changeset.smartOpAssembler();
- var op1 = Changeset.newOp();
- var op2 = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (op1.opcode || iter1.hasNext() || op2.opcode || iter2.hasNext())
- {
- if ((!op1.opcode) && iter1.hasNext()) iter1.next(op1);
- if ((!op2.opcode) && iter2.hasNext()) iter2.next(op2);
- func(op1, op2, opOut);
- if (opOut.opcode)
- {
- //print(opOut.toSource());
- assem.append(opOut);
- opOut.opcode = '';
- }
- }
- assem.endDocument();
- return assem.toString();
-};
-
-Changeset.unpack = function(cs)
-{
- var headerRegex = /Z:([0-9a-z]+)([><])([0-9a-z]+)|/;
- var headerMatch = headerRegex.exec(cs);
- if ((!headerMatch) || (!headerMatch[0]))
- {
- Changeset.error("Not a changeset: " + cs);
- }
- var oldLen = Changeset.parseNum(headerMatch[1]);
- var changeSign = (headerMatch[2] == '>') ? 1 : -1;
- var changeMag = Changeset.parseNum(headerMatch[3]);
- var newLen = oldLen + changeSign * changeMag;
- var opsStart = headerMatch[0].length;
- var opsEnd = cs.indexOf("$");
- if (opsEnd < 0) opsEnd = cs.length;
- return {
- oldLen: oldLen,
- newLen: newLen,
- ops: cs.substring(opsStart, opsEnd),
- charBank: cs.substring(opsEnd + 1)
- };
-};
-
-Changeset.pack = function(oldLen, newLen, opsStr, bank)
-{
- var lenDiff = newLen - oldLen;
- var lenDiffStr = (lenDiff >= 0 ? '>' + Changeset.numToString(lenDiff) : '<' + Changeset.numToString(-lenDiff));
- var a = [];
- a.push('Z:', Changeset.numToString(oldLen), lenDiffStr, opsStr, '$', bank);
- return a.join('');
-};
-
-Changeset.applyToText = function(cs, str)
-{
- var unpacked = Changeset.unpack(cs);
- Changeset.assert(str.length == unpacked.oldLen, "mismatched apply: ", str.length, " / ", unpacked.oldLen);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var strIter = Changeset.stringIterator(str);
- var assem = Changeset.stringAssembler();
- while (csIter.hasNext())
- {
- var op = csIter.next();
- switch (op.opcode)
- {
- case '+':
- assem.append(bankIter.take(op.chars));
- break;
- case '-':
- strIter.skip(op.chars);
- break;
- case '=':
- assem.append(strIter.take(op.chars));
- break;
- }
- }
- assem.append(strIter.take(strIter.remaining()));
- return assem.toString();
-};
-
-Changeset.mutateTextLines = function(cs, lines)
-{
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var bankIter = Changeset.stringIterator(unpacked.charBank);
- var mut = Changeset.textLinesMutator(lines);
- while (csIter.hasNext())
- {
- var op = csIter.next();
- switch (op.opcode)
- {
- case '+':
- mut.insert(bankIter.take(op.chars), op.lines);
- break;
- case '-':
- mut.remove(op.chars, op.lines);
- break;
- case '=':
- mut.skip(op.chars, op.lines, ( !! op.attribs));
- break;
- }
- }
- mut.close();
-};
-
-Changeset.composeAttributes = function(att1, att2, resultIsMutation, pool)
-{
- // att1 and att2 are strings like "*3*f*1c", asMutation is a boolean.
- // Sometimes attribute (key,value) pairs are treated as attribute presence
- // information, while other times they are treated as operations that
- // mutate a set of attributes, and this affects whether an empty value
- // is a deletion or a change.
- // Examples, of the form (att1Items, att2Items, resultIsMutation) -> result
- // ([], [(bold, )], true) -> [(bold, )]
- // ([], [(bold, )], false) -> []
- // ([], [(bold, true)], true) -> [(bold, true)]
- // ([], [(bold, true)], false) -> [(bold, true)]
- // ([(bold, true)], [(bold, )], true) -> [(bold, )]
- // ([(bold, true)], [(bold, )], false) -> []
- // pool can be null if att2 has no attributes.
- if ((!att1) && resultIsMutation)
- {
- // In the case of a mutation (i.e. composing two changesets),
- // an att2 composed with an empy att1 is just att2. If att1
- // is part of an attribution string, then att2 may remove
- // attributes that are already gone, so don't do this optimization.
- return att2;
- }
- if (!att2) return att1;
- var atts = [];
- att1.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- atts.push(pool.getAttrib(Changeset.parseNum(a)));
- return '';
- });
- att2.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- var pair = pool.getAttrib(Changeset.parseNum(a));
- var found = false;
- for (var i = 0; i < atts.length; i++)
- {
- var oldPair = atts[i];
- if (oldPair[0] == pair[0])
- {
- if (pair[1] || resultIsMutation)
- {
- oldPair[1] = pair[1];
- }
- else
- {
- atts.splice(i, 1);
- }
- found = true;
- break;
- }
- }
- if ((!found) && (pair[1] || resultIsMutation))
- {
- atts.push(pair);
- }
- return '';
- });
- atts.sort();
- var buf = Changeset.stringAssembler();
- for (var i = 0; i < atts.length; i++)
- {
- buf.append('*');
- buf.append(Changeset.numToString(pool.putAttrib(atts[i])));
- }
- //print(att1+" / "+att2+" / "+buf.toString());
- return buf.toString();
-};
-
-Changeset._slicerZipperFunc = function(attOp, csOp, opOut, pool)
-{
- // attOp is the op from the sequence that is being operated on, either an
- // attribution string or the earlier of two changesets being composed.
- // pool can be null if definitely not needed.
- //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- if (attOp.opcode == '-')
- {
- Changeset.copyOp(attOp, opOut);
- attOp.opcode = '';
- }
- else if (!attOp.opcode)
- {
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- }
- else
- {
- switch (csOp.opcode)
- {
- case '-':
- {
- if (csOp.chars <= attOp.chars)
- {
- // delete or delete part
- if (attOp.opcode == '=')
- {
- opOut.opcode = '-';
- opOut.chars = csOp.chars;
- opOut.lines = csOp.lines;
- opOut.attribs = '';
- }
- attOp.chars -= csOp.chars;
- attOp.lines -= csOp.lines;
- csOp.opcode = '';
- if (!attOp.chars)
- {
- attOp.opcode = '';
- }
- }
- else
- {
- // delete and keep going
- if (attOp.opcode == '=')
- {
- opOut.opcode = '-';
- opOut.chars = attOp.chars;
- opOut.lines = attOp.lines;
- opOut.attribs = '';
- }
- csOp.chars -= attOp.chars;
- csOp.lines -= attOp.lines;
- attOp.opcode = '';
- }
- break;
- }
- case '+':
- {
- // insert
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- break;
- }
- case '=':
- {
- if (csOp.chars <= attOp.chars)
- {
- // keep or keep part
- opOut.opcode = attOp.opcode;
- opOut.chars = csOp.chars;
- opOut.lines = csOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
- csOp.opcode = '';
- attOp.chars -= csOp.chars;
- attOp.lines -= csOp.lines;
- if (!attOp.chars)
- {
- attOp.opcode = '';
- }
- }
- else
- {
- // keep and keep going
- opOut.opcode = attOp.opcode;
- opOut.chars = attOp.chars;
- opOut.lines = attOp.lines;
- opOut.attribs = Changeset.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
- attOp.opcode = '';
- csOp.chars -= attOp.chars;
- csOp.lines -= attOp.lines;
- }
- break;
- }
- case '':
- {
- Changeset.copyOp(attOp, opOut);
- attOp.opcode = '';
- break;
- }
- }
- }
-};
-
-Changeset.applyToAttribution = function(cs, astr, pool)
-{
- var unpacked = Changeset.unpack(cs);
-
- return Changeset.applyZip(astr, 0, unpacked.ops, 0, function(op1, op2, opOut)
- {
- return Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- });
-};
-
-/*Changeset.oneInsertedLineAtATimeOpIterator = function(opsStr, optStartIndex, charBank) {
- var iter = Changeset.opIterator(opsStr, optStartIndex);
- var bankIndex = 0;
-
-};*/
-
-Changeset.mutateAttributionLines = function(cs, lines, pool)
-{
- //dmesg(cs);
- //dmesg(lines.toSource()+" ->");
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var csBank = unpacked.charBank;
- var csBankIndex = 0;
- // treat the attribution lines as text lines, mutating a line at a time
- var mut = Changeset.textLinesMutator(lines);
-
- var lineIter = null;
-
- function isNextMutOp()
- {
- return (lineIter && lineIter.hasNext()) || mut.hasMore();
- }
-
- function nextMutOp(destOp)
- {
- if ((!(lineIter && lineIter.hasNext())) && mut.hasMore())
- {
- var line = mut.removeLines(1);
- lineIter = Changeset.opIterator(line);
- }
- if (lineIter && lineIter.hasNext())
- {
- lineIter.next(destOp);
- }
- else
- {
- destOp.opcode = '';
- }
- }
- var lineAssem = null;
-
- function outputMutOp(op)
- {
- //print("outputMutOp: "+op.toSource());
- if (!lineAssem)
- {
- lineAssem = Changeset.mergingOpAssembler();
- }
- lineAssem.append(op);
- if (op.lines > 0)
- {
- Changeset.assert(op.lines == 1, "Can't have op.lines of ", op.lines, " in attribution lines");
- // ship it to the mut
- mut.insert(lineAssem.toString(), 1);
- lineAssem = null;
- }
- }
-
- var csOp = Changeset.newOp();
- var attOp = Changeset.newOp();
- var opOut = Changeset.newOp();
- while (csOp.opcode || csIter.hasNext() || attOp.opcode || isNextMutOp())
- {
- if ((!csOp.opcode) && csIter.hasNext())
- {
- csIter.next(csOp);
- }
- //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource());
- //print(csOp.opcode+"/"+csOp.lines+"/"+csOp.attribs+"/"+lineAssem+"/"+lineIter+"/"+(lineIter?lineIter.hasNext():null));
- //print("csOp: "+csOp.toSource());
- if ((!csOp.opcode) && (!attOp.opcode) && (!lineAssem) && (!(lineIter && lineIter.hasNext())))
- {
- break; // done
- }
- else if (csOp.opcode == '=' && csOp.lines > 0 && (!csOp.attribs) && (!attOp.opcode) && (!lineAssem) && (!(lineIter && lineIter.hasNext())))
- {
- // skip multiple lines; this is what makes small changes not order of the document size
- mut.skipLines(csOp.lines);
- //print("skipped: "+csOp.lines);
- csOp.opcode = '';
- }
- else if (csOp.opcode == '+')
- {
- if (csOp.lines > 1)
- {
- var firstLineLen = csBank.indexOf('\n', csBankIndex) + 1 - csBankIndex;
- Changeset.copyOp(csOp, opOut);
- csOp.chars -= firstLineLen;
- csOp.lines--;
- opOut.lines = 1;
- opOut.chars = firstLineLen;
- }
- else
- {
- Changeset.copyOp(csOp, opOut);
- csOp.opcode = '';
- }
- outputMutOp(opOut);
- csBankIndex += opOut.chars;
- opOut.opcode = '';
- }
- else
- {
- if ((!attOp.opcode) && isNextMutOp())
- {
- nextMutOp(attOp);
- }
- //print("attOp: "+attOp.toSource());
- Changeset._slicerZipperFunc(attOp, csOp, opOut, pool);
- if (opOut.opcode)
- {
- outputMutOp(opOut);
- opOut.opcode = '';
- }
- }
- }
-
- Changeset.assert(!lineAssem, "line assembler not finished");
- mut.close();
-
- //dmesg("-> "+lines.toSource());
-};
-
-Changeset.joinAttributionLines = function(theAlines)
-{
- var assem = Changeset.mergingOpAssembler();
- for (var i = 0; i < theAlines.length; i++)
- {
- var aline = theAlines[i];
- var iter = Changeset.opIterator(aline);
- while (iter.hasNext())
- {
- assem.append(iter.next());
- }
- }
- return assem.toString();
-};
-
-Changeset.splitAttributionLines = function(attrOps, text)
-{
- var iter = Changeset.opIterator(attrOps);
- var assem = Changeset.mergingOpAssembler();
- var lines = [];
- var pos = 0;
-
- function appendOp(op)
- {
- assem.append(op);
- if (op.lines > 0)
- {
- lines.push(assem.toString());
- assem.clear();
- }
- pos += op.chars;
- }
-
- while (iter.hasNext())
- {
- var op = iter.next();
- var numChars = op.chars;
- var numLines = op.lines;
- while (numLines > 1)
- {
- var newlineEnd = text.indexOf('\n', pos) + 1;
- Changeset.assert(newlineEnd > 0, "newlineEnd <= 0 in splitAttributionLines");
- op.chars = newlineEnd - pos;
- op.lines = 1;
- appendOp(op);
- numChars -= op.chars;
- numLines -= op.lines;
- }
- if (numLines == 1)
- {
- op.chars = numChars;
- op.lines = 1;
- }
- appendOp(op);
- }
-
- return lines;
-};
-
-Changeset.splitTextLines = function(text)
-{
- return text.match(/[^\n]*(?:\n|[^\n]$)/g);
-};
-
-Changeset.compose = function(cs1, cs2, pool)
-{
- var unpacked1 = Changeset.unpack(cs1);
- var unpacked2 = Changeset.unpack(cs2);
- var len1 = unpacked1.oldLen;
- var len2 = unpacked1.newLen;
- Changeset.assert(len2 == unpacked2.oldLen, "mismatched composition");
- var len3 = unpacked2.newLen;
- var bankIter1 = Changeset.stringIterator(unpacked1.charBank);
- var bankIter2 = Changeset.stringIterator(unpacked2.charBank);
- var bankAssem = Changeset.stringAssembler();
-
- var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut)
- {
- //var debugBuilder = Changeset.stringAssembler();
- //debugBuilder.append(Changeset.opString(op1));
- //debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
- //debugBuilder.append(' / ');
- var op1code = op1.opcode;
- var op2code = op2.opcode;
- if (op1code == '+' && op2code == '-')
- {
- bankIter1.skip(Math.min(op1.chars, op2.chars));
- }
- Changeset._slicerZipperFunc(op1, op2, opOut, pool);
- if (opOut.opcode == '+')
- {
- if (op2code == '+')
- {
- bankAssem.append(bankIter2.take(opOut.chars));
- }
- else
- {
- bankAssem.append(bankIter1.take(opOut.chars));
- }
- }
-
- //debugBuilder.append(Changeset.opString(op1));
- //debugBuilder.append(',');
- //debugBuilder.append(Changeset.opString(op2));
- //debugBuilder.append(' -> ');
- //debugBuilder.append(Changeset.opString(opOut));
- //print(debugBuilder.toString());
- });
-
- return Changeset.pack(len1, len3, newOps, bankAssem.toString());
-};
-
-Changeset.attributeTester = function(attribPair, pool)
-{
- // returns a function that tests if a string of attributes
- // (e.g. *3*4) contains a given attribute key,value that
- // is already present in the pool.
- if (!pool)
- {
- return never;
- }
- var attribNum = pool.putAttrib(attribPair, true);
- if (attribNum < 0)
- {
- return never;
- }
- else
- {
- var re = new RegExp('\\*' + Changeset.numToString(attribNum) + '(?!\\w)');
- return function(attribs)
- {
- return re.test(attribs);
- };
- }
-
- function never(attribs)
- {
- return false;
- }
-};
-
-Changeset.identity = function(N)
-{
- return Changeset.pack(N, N, "", "");
-};
-
-Changeset.makeSplice = function(oldFullText, spliceStart, numRemoved, newText, optNewTextAPairs, pool)
-{
- var oldLen = oldFullText.length;
-
- if (spliceStart >= oldLen)
- {
- spliceStart = oldLen - 1;
- }
- if (numRemoved > oldFullText.length - spliceStart - 1)
- {
- numRemoved = oldFullText.length - spliceStart - 1;
- }
- var oldText = oldFullText.substring(spliceStart, spliceStart + numRemoved);
- var newLen = oldLen + newText.length - oldText.length;
-
- var assem = Changeset.smartOpAssembler();
- assem.appendOpWithText('=', oldFullText.substring(0, spliceStart));
- assem.appendOpWithText('-', oldText);
- assem.appendOpWithText('+', newText, optNewTextAPairs, pool);
- assem.endDocument();
- return Changeset.pack(oldLen, newLen, assem.toString(), newText);
-};
-
-Changeset.toSplices = function(cs)
-{
- // get a list of splices, [startChar, endChar, newText]
- var unpacked = Changeset.unpack(cs);
- var splices = [];
-
- var oldPos = 0;
- var iter = Changeset.opIterator(unpacked.ops);
- var charIter = Changeset.stringIterator(unpacked.charBank);
- var inSplice = false;
- while (iter.hasNext())
- {
- var op = iter.next();
- if (op.opcode == '=')
- {
- oldPos += op.chars;
- inSplice = false;
- }
- else
- {
- if (!inSplice)
- {
- splices.push([oldPos, oldPos, ""]);
- inSplice = true;
- }
- if (op.opcode == '-')
- {
- oldPos += op.chars;
- splices[splices.length - 1][1] += op.chars;
- }
- else if (op.opcode == '+')
- {
- splices[splices.length - 1][2] += charIter.take(op.chars);
- }
- }
- }
-
- return splices;
-};
-
-Changeset.characterRangeFollow = function(cs, startChar, endChar, insertionsAfter)
-{
- var newStartChar = startChar;
- var newEndChar = endChar;
- var splices = Changeset.toSplices(cs);
- var lengthChangeSoFar = 0;
- for (var i = 0; i < splices.length; i++)
- {
- var splice = splices[i];
- var spliceStart = splice[0] + lengthChangeSoFar;
- var spliceEnd = splice[1] + lengthChangeSoFar;
- var newTextLength = splice[2].length;
- var thisLengthChange = newTextLength - (spliceEnd - spliceStart);
-
- if (spliceStart <= newStartChar && spliceEnd >= newEndChar)
- {
- // splice fully replaces/deletes range
- // (also case that handles insertion at a collapsed selection)
- if (insertionsAfter)
- {
- newStartChar = newEndChar = spliceStart;
- }
- else
- {
- newStartChar = newEndChar = spliceStart + newTextLength;
- }
- }
- else if (spliceEnd <= newStartChar)
- {
- // splice is before range
- newStartChar += thisLengthChange;
- newEndChar += thisLengthChange;
- }
- else if (spliceStart >= newEndChar)
- {
- // splice is after range
- }
- else if (spliceStart >= newStartChar && spliceEnd <= newEndChar)
- {
- // splice is inside range
- newEndChar += thisLengthChange;
- }
- else if (spliceEnd < newEndChar)
- {
- // splice overlaps beginning of range
- newStartChar = spliceStart + newTextLength;
- newEndChar += thisLengthChange;
- }
- else
- {
- // splice overlaps end of range
- newEndChar = spliceStart;
- }
-
- lengthChangeSoFar += thisLengthChange;
- }
-
- return [newStartChar, newEndChar];
-};
-
-Changeset.moveOpsToNewPool = function(cs, oldPool, newPool)
-{
- // works on changeset or attribution string
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0)
- {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
- var fromDollar = cs.substring(dollarPos);
- // order of attribs stays the same
- return upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- var oldNum = Changeset.parseNum(a);
- var pair = oldPool.getAttrib(oldNum);
- var newNum = newPool.putAttrib(pair);
- return '*' + Changeset.numToString(newNum);
- }) + fromDollar;
-};
-
-Changeset.makeAttribution = function(text)
-{
- var assem = Changeset.smartOpAssembler();
- assem.appendOpWithText('+', text);
- return assem.toString();
-};
-
-// callable on a changeset, attribution string, or attribs property of an op
-Changeset.eachAttribNumber = function(cs, func)
-{
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0)
- {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
-
- upToDollar.replace(/\*([0-9a-z]+)/g, function(_, a)
- {
- func(Changeset.parseNum(a));
- return '';
- });
-};
-
-// callable on a changeset, attribution string, or attribs property of an op,
-// though it may easily create adjacent ops that can be merged.
-Changeset.filterAttribNumbers = function(cs, filter)
-{
- return Changeset.mapAttribNumbers(cs, filter);
-};
-
-Changeset.mapAttribNumbers = function(cs, func)
-{
- var dollarPos = cs.indexOf('$');
- if (dollarPos < 0)
- {
- dollarPos = cs.length;
- }
- var upToDollar = cs.substring(0, dollarPos);
-
- var newUpToDollar = upToDollar.replace(/\*([0-9a-z]+)/g, function(s, a)
- {
- var n = func(Changeset.parseNum(a));
- if (n === true)
- {
- return s;
- }
- else if ((typeof n) === "number")
- {
- return '*' + Changeset.numToString(n);
- }
- else
- {
- return '';
- }
- });
-
- return newUpToDollar + cs.substring(dollarPos);
-};
-
-Changeset.makeAText = function(text, attribs)
-{
- return {
- text: text,
- attribs: (attribs || Changeset.makeAttribution(text))
- };
-};
-
-Changeset.applyToAText = function(cs, atext, pool)
-{
- return {
- text: Changeset.applyToText(cs, atext.text),
- attribs: Changeset.applyToAttribution(cs, atext.attribs, pool)
- };
-};
-
-Changeset.cloneAText = function(atext)
-{
- return {
- text: atext.text,
- attribs: atext.attribs
- };
-};
-
-Changeset.copyAText = function(atext1, atext2)
-{
- atext2.text = atext1.text;
- atext2.attribs = atext1.attribs;
-};
-
-Changeset.appendATextToAssembler = function(atext, assem)
-{
- // intentionally skips last newline char of atext
- var iter = Changeset.opIterator(atext.attribs);
- var op = Changeset.newOp();
- while (iter.hasNext())
- {
- iter.next(op);
- if (!iter.hasNext())
- {
- // last op, exclude final newline
- if (op.lines <= 1)
- {
- op.lines = 0;
- op.chars--;
- if (op.chars)
- {
- assem.append(op);
- }
- }
- else
- {
- var nextToLastNewlineEnd = atext.text.lastIndexOf('\n', atext.text.length - 2) + 1;
- var lastLineLength = atext.text.length - nextToLastNewlineEnd - 1;
- op.lines--;
- op.chars -= (lastLineLength + 1);
- assem.append(op);
- op.lines = 0;
- op.chars = lastLineLength;
- if (op.chars)
- {
- assem.append(op);
- }
- }
- }
- else
- {
- assem.append(op);
- }
- }
-};
-
-Changeset.prepareForWire = function(cs, pool)
-{
- var newPool = new AttribPool();
- var newCs = Changeset.moveOpsToNewPool(cs, pool, newPool);
- return {
- translated: newCs,
- pool: newPool
- };
-};
-
-Changeset.isIdentity = function(cs)
-{
- var unpacked = Changeset.unpack(cs);
- return unpacked.ops == "" && unpacked.oldLen == unpacked.newLen;
-};
-
-Changeset.opAttributeValue = function(op, key, pool)
-{
- return Changeset.attribsAttributeValue(op.attribs, key, pool);
-};
-
-Changeset.attribsAttributeValue = function(attribs, key, pool)
-{
- var value = '';
- if (attribs)
- {
- Changeset.eachAttribNumber(attribs, function(n)
- {
- if (pool.getAttribKey(n) == key)
- {
- value = pool.getAttribValue(n);
- }
- });
- }
- return value;
-};
-
-Changeset.builder = function(oldLen)
-{
- var assem = Changeset.smartOpAssembler();
- var o = Changeset.newOp();
- var charBank = Changeset.stringAssembler();
-
- var self = {
- // attribs are [[key1,value1],[key2,value2],...] or '*0*1...' (no pool needed in latter case)
- keep: function(N, L, attribs, pool)
- {
- o.opcode = '=';
- o.attribs = (attribs && Changeset.makeAttribsString('=', attribs, pool)) || '';
- o.chars = N;
- o.lines = (L || 0);
- assem.append(o);
- return self;
- },
- keepText: function(text, attribs, pool)
- {
- assem.appendOpWithText('=', text, attribs, pool);
- return self;
- },
- insert: function(text, attribs, pool)
- {
- assem.appendOpWithText('+', text, attribs, pool);
- charBank.append(text);
- return self;
- },
- remove: function(N, L)
- {
- o.opcode = '-';
- o.attribs = '';
- o.chars = N;
- o.lines = (L || 0);
- assem.append(o);
- return self;
- },
- toString: function()
- {
- assem.endDocument();
- var newLen = oldLen + assem.getLengthChange();
- return Changeset.pack(oldLen, newLen, assem.toString(), charBank.toString());
- }
- };
-
- return self;
-};
-
-Changeset.makeAttribsString = function(opcode, attribs, pool)
-{
- // makeAttribsString(opcode, '*3') or makeAttribsString(opcode, [['foo','bar']], myPool) work
- if (!attribs)
- {
- return '';
- }
- else if ((typeof attribs) == "string")
- {
- return attribs;
- }
- else if (pool && attribs && attribs.length)
- {
- if (attribs.length > 1)
- {
- attribs = attribs.slice();
- attribs.sort();
- }
- var result = [];
- for (var i = 0; i < attribs.length; i++)
- {
- var pair = attribs[i];
- if (opcode == '=' || (opcode == '+' && pair[1]))
- {
- result.push('*' + Changeset.numToString(pool.putAttrib(pair)));
- }
- }
- return result.join('');
- }
-};
-
-// like "substring" but on a single-line attribution string
-Changeset.subattribution = function(astr, start, optEnd)
-{
- var iter = Changeset.opIterator(astr, 0);
- var assem = Changeset.smartOpAssembler();
- var attOp = Changeset.newOp();
- var csOp = Changeset.newOp();
- var opOut = Changeset.newOp();
-
- function doCsOp()
- {
- if (csOp.chars)
- {
- while (csOp.opcode && (attOp.opcode || iter.hasNext()))
- {
- if (!attOp.opcode) iter.next(attOp);
-
- if (csOp.opcode && attOp.opcode && csOp.chars >= attOp.chars && attOp.lines > 0 && csOp.lines <= 0)
- {
- csOp.lines++;
- }
-
- Changeset._slicerZipperFunc(attOp, csOp, opOut, null);
- if (opOut.opcode)
- {
- assem.append(opOut);
- opOut.opcode = '';
- }
- }
- }
- }
-
- csOp.opcode = '-';
- csOp.chars = start;
-
- doCsOp();
-
- if (optEnd === undefined)
- {
- if (attOp.opcode)
- {
- assem.append(attOp);
- }
- while (iter.hasNext())
- {
- iter.next(attOp);
- assem.append(attOp);
- }
- }
- else
- {
- csOp.opcode = '=';
- csOp.chars = optEnd - start;
- doCsOp();
- }
-
- return assem.toString();
-};
-
-Changeset.inverse = function(cs, lines, alines, pool)
-{
- // lines and alines are what the changeset is meant to apply to.
- // They may be arrays or objects with .get(i) and .length methods.
- // They include final newlines on lines.
-
- function lines_get(idx)
- {
- if (lines.get)
- {
- return lines.get(idx);
- }
- else
- {
- return lines[idx];
- }
- }
-
- function lines_length()
- {
- if ((typeof lines.length) == "number")
- {
- return lines.length;
- }
- else
- {
- return lines.length();
- }
- }
-
- function alines_get(idx)
- {
- if (alines.get)
- {
- return alines.get(idx);
- }
- else
- {
- return alines[idx];
- }
- }
-
- function alines_length()
- {
- if ((typeof alines.length) == "number")
- {
- return alines.length;
- }
- else
- {
- return alines.length();
- }
- }
-
- var curLine = 0;
- var curChar = 0;
- var curLineOpIter = null;
- var curLineOpIterLine;
- var curLineNextOp = Changeset.newOp('+');
-
- var unpacked = Changeset.unpack(cs);
- var csIter = Changeset.opIterator(unpacked.ops);
- var builder = Changeset.builder(unpacked.newLen);
-
- function consumeAttribRuns(numChars, func /*(len, attribs, endsLine)*/ )
- {
-
- if ((!curLineOpIter) || (curLineOpIterLine != curLine))
- {
- // create curLineOpIter and advance it to curChar
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
- curLineOpIterLine = curLine;
- var indexIntoLine = 0;
- var done = false;
- while (!done)
- {
- curLineOpIter.next(curLineNextOp);
- if (indexIntoLine + curLineNextOp.chars >= curChar)
- {
- curLineNextOp.chars -= (curChar - indexIntoLine);
- done = true;
- }
- else
- {
- indexIntoLine += curLineNextOp.chars;
- }
- }
- }
-
- while (numChars > 0)
- {
- if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext()))
- {
- curLine++;
- curChar = 0;
- curLineOpIterLine = curLine;
- curLineNextOp.chars = 0;
- curLineOpIter = Changeset.opIterator(alines_get(curLine));
- }
- if (!curLineNextOp.chars)
- {
- curLineOpIter.next(curLineNextOp);
- }
- var charsToUse = Math.min(numChars, curLineNextOp.chars);
- func(charsToUse, curLineNextOp.attribs, charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0);
- numChars -= charsToUse;
- curLineNextOp.chars -= charsToUse;
- curChar += charsToUse;
- }
-
- if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext()))
- {
- curLine++;
- curChar = 0;
- }
- }
-
- function skip(N, L)
- {
- if (L)
- {
- curLine += L;
- curChar = 0;
- }
- else
- {
- if (curLineOpIter && curLineOpIterLine == curLine)
- {
- consumeAttribRuns(N, function()
- {});
- }
- else
- {
- curChar += N;
- }
- }
- }
-
- function nextText(numChars)
- {
- var len = 0;
- var assem = Changeset.stringAssembler();
- var firstString = lines_get(curLine).substring(curChar);
- len += firstString.length;
- assem.append(firstString);
-
- var lineNum = curLine + 1;
- while (len < numChars)
- {
- var nextString = lines_get(lineNum);
- len += nextString.length;
- assem.append(nextString);
- lineNum++;
- }
-
- return assem.toString().substring(0, numChars);
- }
-
- function cachedStrFunc(func)
- {
- var cache = {};
- return function(s)
- {
- if (!cache[s])
- {
- cache[s] = func(s);
- }
- return cache[s];
- };
- }
-
- var attribKeys = [];
- var attribValues = [];
- while (csIter.hasNext())
- {
- var csOp = csIter.next();
- if (csOp.opcode == '=')
- {
- if (csOp.attribs)
- {
- attribKeys.length = 0;
- attribValues.length = 0;
- Changeset.eachAttribNumber(csOp.attribs, function(n)
- {
- attribKeys.push(pool.getAttribKey(n));
- attribValues.push(pool.getAttribValue(n));
- });
- var undoBackToAttribs = cachedStrFunc(function(attribs)
- {
- var backAttribs = [];
- for (var i = 0; i < attribKeys.length; i++)
- {
- var appliedKey = attribKeys[i];
- var appliedValue = attribValues[i];
- var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, pool);
- if (appliedValue != oldValue)
- {
- backAttribs.push([appliedKey, oldValue]);
- }
- }
- return Changeset.makeAttribsString('=', backAttribs, pool);
- });
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine)
- {
- builder.keep(len, endsLine ? 1 : 0, undoBackToAttribs(attribs));
- });
- }
- else
- {
- skip(csOp.chars, csOp.lines);
- builder.keep(csOp.chars, csOp.lines);
- }
- }
- else if (csOp.opcode == '+')
- {
- builder.remove(csOp.chars, csOp.lines);
- }
- else if (csOp.opcode == '-')
- {
- var textBank = nextText(csOp.chars);
- var textBankIndex = 0;
- consumeAttribRuns(csOp.chars, function(len, attribs, endsLine)
- {
- builder.insert(textBank.substr(textBankIndex, len), attribs);
- textBankIndex += len;
- });
- }
- }
-
- return Changeset.checkRep(builder.toString());
-};
-
-exports.Changeset = Changeset;
-exports.AttribPool = AttribPool;
diff --git a/static/js/linestylefilter.js b/static/js/linestylefilter.js
index d0b5bc6e..4b455724 100644
--- a/static/js/linestylefilter.js
+++ b/static/js/linestylefilter.js
@@ -28,7 +28,7 @@
// requires: plugins
// requires: undefined
-var Changeset = require('/easysync2').Changeset
+var Changeset = require('/Changeset');
var plugins = require('/plugins').plugins;
var map = require('/ace2_common').map;
diff --git a/static/js/linestylefilter_client.js b/static/js/linestylefilter_client.js
deleted file mode 100644
index f057e21a..00000000
--- a/static/js/linestylefilter_client.js
+++ /dev/null
@@ -1,343 +0,0 @@
-/**
- * This code is mostly from the old Etherpad. Please help us to comment this code.
- * This helps other people to understand this code better and helps them to improve it.
- * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
- */
-
-// DO NOT EDIT THIS FILE, edit infrastructure/ace/www/linestylefilter.js
-// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.linestylefilter
-/**
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS-IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// requires: easysync2.Changeset
-// requires: top
-// requires: plugins
-// requires: undefined
-
-var Changeset = require('/easysync2_client').Changeset
-var plugins = require('/plugins').plugins;
-var map = require('/ace2_common').map;
-
-var linestylefilter = {};
-
-linestylefilter.ATTRIB_CLASSES = {
- 'bold': 'tag:b',
- 'italic': 'tag:i',
- 'underline': 'tag:u',
- 'strikethrough': 'tag:s'
-};
-
-linestylefilter.getAuthorClassName = function(author)
-{
- return "author-" + author.replace(/[^a-y0-9]/g, function(c)
- {
- if (c == ".") return "-";
- return 'z' + c.charCodeAt(0) + 'z';
- });
-};
-
-// lineLength is without newline; aline includes newline,
-// but may be falsy if lineLength == 0
-linestylefilter.getLineStyleFilter = function(lineLength, aline, textAndClassFunc, apool)
-{
-
- var plugins_ = plugins;
-
- if (lineLength == 0) return textAndClassFunc;
-
- var nextAfterAuthorColors = textAndClassFunc;
-
- var authorColorFunc = (function()
- {
- var lineEnd = lineLength;
- var curIndex = 0;
- var extraClasses;
- var leftInAuthor;
-
- function attribsToClasses(attribs)
- {
- var classes = '';
- Changeset.eachAttribNumber(attribs, function(n)
- {
- var key = apool.getAttribKey(n);
- if (key)
- {
- var value = apool.getAttribValue(n);
- if (value)
- {
- if (key == 'author')
- {
- classes += ' ' + linestylefilter.getAuthorClassName(value);
- }
- else if (key == 'list')
- {
- classes += ' list:' + value;
- }
- else if (key == 'start')
- {
- classes += ' start:' + value;
- }
- else if (linestylefilter.ATTRIB_CLASSES[key])
- {
- classes += ' ' + linestylefilter.ATTRIB_CLASSES[key];
- }
- else
- {
- classes += plugins_.callHookStr("aceAttribsToClasses", {
- linestylefilter: linestylefilter,
- key: key,
- value: value
- }, " ", " ", "");
- }
- }
- }
- });
- return classes.substring(1);
- }
-
- var attributionIter = Changeset.opIterator(aline);
- var nextOp, nextOpClasses;
-
- function goNextOp()
- {
- nextOp = attributionIter.next();
- nextOpClasses = (nextOp.opcode && attribsToClasses(nextOp.attribs));
- }
- goNextOp();
-
- function nextClasses()
- {
- if (curIndex < lineEnd)
- {
- extraClasses = nextOpClasses;
- leftInAuthor = nextOp.chars;
- goNextOp();
- while (nextOp.opcode && nextOpClasses == extraClasses)
- {
- leftInAuthor += nextOp.chars;
- goNextOp();
- }
- }
- }
- nextClasses();
-
- return function(txt, cls)
- {
- while (txt.length > 0)
- {
- if (leftInAuthor <= 0)
- {
- // prevent infinite loop if something funny's going on
- return nextAfterAuthorColors(txt, cls);
- }
- var spanSize = txt.length;
- if (spanSize > leftInAuthor)
- {
- spanSize = leftInAuthor;
- }
- var curTxt = txt.substring(0, spanSize);
- txt = txt.substring(spanSize);
- nextAfterAuthorColors(curTxt, (cls && cls + " ") + extraClasses);
- curIndex += spanSize;
- leftInAuthor -= spanSize;
- if (leftInAuthor == 0)
- {
- nextClasses();
- }
- }
- };
- })();
- return authorColorFunc;
-};
-
-linestylefilter.getAtSignSplitterFilter = function(lineText, textAndClassFunc)
-{
- var at = /@/g;
- at.lastIndex = 0;
- var splitPoints = null;
- var execResult;
- while ((execResult = at.exec(lineText)))
- {
- if (!splitPoints)
- {
- splitPoints = [];
- }
- splitPoints.push(execResult.index);
- }
-
- if (!splitPoints) return textAndClassFunc;
-
- return linestylefilter.textAndClassFuncSplitter(textAndClassFunc, splitPoints);
-};
-
-linestylefilter.getRegexpFilter = function(regExp, tag)
-{
- return function(lineText, textAndClassFunc)
- {
- regExp.lastIndex = 0;
- var regExpMatchs = null;
- var splitPoints = null;
- var execResult;
- while ((execResult = regExp.exec(lineText)))
- {
- if (!regExpMatchs)
- {
- regExpMatchs = [];
- splitPoints = [];
- }
- var startIndex = execResult.index;
- var regExpMatch = execResult[0];
- regExpMatchs.push([startIndex, regExpMatch]);
- splitPoints.push(startIndex, startIndex + regExpMatch.length);
- }
-
- if (!regExpMatchs) return textAndClassFunc;
-
- function regExpMatchForIndex(idx)
- {
- for (var k = 0; k < regExpMatchs.length; k++)
- {
- var u = regExpMatchs[k];
- if (idx >= u[0] && idx < u[0] + u[1].length)
- {
- return u[1];
- }
- }
- return false;
- }
-
- var handleRegExpMatchsAfterSplit = (function()
- {
- var curIndex = 0;
- return function(txt, cls)
- {
- var txtlen = txt.length;
- var newCls = cls;
- var regExpMatch = regExpMatchForIndex(curIndex);
- if (regExpMatch)
- {
- newCls += " " + tag + ":" + regExpMatch;
- }
- textAndClassFunc(txt, newCls);
- curIndex += txtlen;
- };
- })();
-
- return linestylefilter.textAndClassFuncSplitter(handleRegExpMatchsAfterSplit, splitPoints);
- };
-};
-
-
-linestylefilter.REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
-linestylefilter.REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source + '|' + linestylefilter.REGEX_WORDCHAR.source + ')');
-linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:|www\.)/.source + linestylefilter.REGEX_URLCHAR.source + '*(?![:.,;])' + linestylefilter.REGEX_URLCHAR.source, 'g');
-linestylefilter.getURLFilter = linestylefilter.getRegexpFilter(
-linestylefilter.REGEX_URL, 'url');
-
-linestylefilter.textAndClassFuncSplitter = function(func, splitPointsOpt)
-{
- var nextPointIndex = 0;
- var idx = 0;
-
- // don't split at 0
- while (splitPointsOpt && nextPointIndex < splitPointsOpt.length && splitPointsOpt[nextPointIndex] == 0)
- {
- nextPointIndex++;
- }
-
- function spanHandler(txt, cls)
- {
- if ((!splitPointsOpt) || nextPointIndex >= splitPointsOpt.length)
- {
- func(txt, cls);
- idx += txt.length;
- }
- else
- {
- var splitPoints = splitPointsOpt;
- var pointLocInSpan = splitPoints[nextPointIndex] - idx;
- var txtlen = txt.length;
- if (pointLocInSpan >= txtlen)
- {
- func(txt, cls);
- idx += txt.length;
- if (pointLocInSpan == txtlen)
- {
- nextPointIndex++;
- }
- }
- else
- {
- if (pointLocInSpan > 0)
- {
- func(txt.substring(0, pointLocInSpan), cls);
- idx += pointLocInSpan;
- }
- nextPointIndex++;
- // recurse
- spanHandler(txt.substring(pointLocInSpan), cls);
- }
- }
- }
- return spanHandler;
-};
-
-linestylefilter.getFilterStack = function(lineText, textAndClassFunc, browser)
-{
- var func = linestylefilter.getURLFilter(lineText, textAndClassFunc);
-
- var plugins_ = plugins;
-
- var hookFilters = plugins_.callHook("aceGetFilterStack", {
- linestylefilter: linestylefilter,
- browser: browser
- });
- map(hookFilters, function(hookFilter)
- {
- func = hookFilter(lineText, func);
- });
-
- if (browser !== undefined && browser.msie)
- {
- // IE7+ will take an e-mail address like <foo@bar.com> and linkify it to foo@bar.com.
- // We then normalize it back to text with no angle brackets. It's weird. So always
- // break spans at an "at" sign.
- func = linestylefilter.getAtSignSplitterFilter(
- lineText, func);
- }
- return func;
-};
-
-// domLineObj is like that returned by domline.createDomLine
-linestylefilter.populateDomLine = function(textLine, aline, apool, domLineObj)
-{
- // remove final newline from text if any
- var text = textLine;
- if (text.slice(-1) == '\n')
- {
- text = text.substring(0, text.length - 1);
- }
-
- function textAndClassFunc(tokenText, tokenClass)
- {
- domLineObj.appendSpan(tokenText, tokenClass);
- }
-
- var func = linestylefilter.getFilterStack(text, textAndClassFunc);
- func = linestylefilter.getLineStyleFilter(text.length, aline, func, apool);
- func(text, '');
-};
-
-exports.linestylefilter = linestylefilter;
diff --git a/static/js/pad.js b/static/js/pad.js
index 9dab9c61..eb480080 100644
--- a/static/js/pad.js
+++ b/static/js/pad.js
@@ -46,47 +46,9 @@ var padsavedrevs = require('/pad_savedrevs').padsavedrevs;
var paduserlist = require('/pad_userlist').paduserlist;
var padutils = require('/pad_utils').padutils;
-function createCookie(name, value, days, path)
-{
- if (days)
- {
- var date = new Date();
- date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
- var expires = "; expires=" + date.toGMTString();
- }
- else var expires = "";
-
- if(!path)
- path = "/";
-
- document.cookie = name + "=" + value + expires + "; path=" + path;
-}
-
-function readCookie(name)
-{
- var nameEQ = name + "=";
- var ca = document.cookie.split(';');
- for (var i = 0; i < ca.length; i++)
- {
- var c = ca[i];
- while (c.charAt(0) == ' ') c = c.substring(1, c.length);
- if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
- }
- return null;
-}
-
-function randomString()
-{
- var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- var string_length = 20;
- var randomstring = '';
- for (var i = 0; i < string_length; i++)
- {
- var rnum = Math.floor(Math.random() * chars.length);
- randomstring += chars.substring(rnum, rnum + 1);
- }
- return "t." + randomstring;
-}
+var createCookie = require('/pad_utils').createCookie;
+var readCookie = require('/pad_utils').readCookie;
+var randomString = require('/pad_utils').randomString;
function getParams()
{
@@ -210,7 +172,7 @@ function handshake()
var token = readCookie("token");
if (token == null)
{
- token = randomString();
+ token = "t." + randomString();
createCookie("token", token, 60);
}
diff --git a/static/js/pad_utils.js b/static/js/pad_utils.js
index 071185a8..fb538211 100644
--- a/static/js/pad_utils.js
+++ b/static/js/pad_utils.js
@@ -20,17 +20,58 @@
* limitations under the License.
*/
+var Security = require('/security');
+
+/**
+ * Generates a random String with the given length. Is needed to generate the Author, Group, readonly, session Ids
+ */
+
+function randomString(len)
+{
+ var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ var randomstring = '';
+ len = len || 20
+ for (var i = 0; i < len; i++)
+ {
+ var rnum = Math.floor(Math.random() * chars.length);
+ randomstring += chars.substring(rnum, rnum + 1);
+ }
+ return randomstring;
+}
+
+function createCookie(name, value, days, path)
+{
+ if (days)
+ {
+ var date = new Date();
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
+ var expires = "; expires=" + date.toGMTString();
+ }
+ else var expires = "";
+
+ if(!path)
+ path = "/";
+
+ document.cookie = name + "=" + value + expires + "; path=" + path;
+}
+
+function readCookie(name)
+{
+ var nameEQ = name + "=";
+ var ca = document.cookie.split(';');
+ for (var i = 0; i < ca.length; i++)
+ {
+ var c = ca[i];
+ while (c.charAt(0) == ' ') c = c.substring(1, c.length);
+ if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
+ }
+ return null;
+}
+
var padutils = {
escapeHtml: function(x)
{
- return String(x).replace(/[&"<>]/g, function (c) {
- return {
- '&': '&amp;',
- '"': '&quot;',
- '<': '&lt;',
- '>': '&gt;'
- }[c] || c;
- });
+ return Security.escapeHTML(String(x));
},
uniqueId: function()
{
@@ -159,7 +200,7 @@ var padutils = {
{
if (i > idx)
{
- pieces.push(padutils.escapeHtml(text.substring(idx, i)));
+ pieces.push(Security.escapeHTML(text.substring(idx, i)));
idx = i;
}
}
@@ -170,7 +211,7 @@ var padutils = {
var startIndex = urls[j][0];
var href = urls[j][1];
advanceTo(startIndex);
- pieces.push('<a ', (target ? 'target="' + target + '" ' : ''), 'href="', padutils.escapeHtml(href), '">');
+ pieces.push('<a ', (target ? 'target="' + Security.escapeHTMLAttribute(target) + '" ' : ''), 'href="', Security.escapeHTMLAttribute(href), '">');
advanceTo(startIndex + href.length);
pieces.push('</a>');
}
@@ -481,4 +522,7 @@ padutils.setupGlobalExceptionHandler = setupGlobalExceptionHandler;
padutils.binarySearch = require('/ace2_common').binarySearch;
+exports.randomString = randomString;
+exports.createCookie = createCookie;
+exports.readCookie = readCookie;
exports.padutils = padutils;
diff --git a/static/js/security.js b/static/js/security.js
new file mode 100644
index 00000000..6f42d051
--- /dev/null
+++ b/static/js/security.js
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var HTML_ENTITY_MAP = {
+ '&': '&amp;'
+, '<': '&lt;'
+, '>': '&gt;'
+, '"': '&quot;'
+, "'": '&#x27;'
+, '/': '&#x2F;'
+};
+
+// OSWASP Guidlines: &, <, >, ", ' plus forward slash.
+var HTML_CHARACTERS_EXPRESSION = /[&"'<>\/]/g;
+function escapeHTML(text) {
+ return text && text.replace(HTML_CHARACTERS_EXPRESSION, function (c) {
+ return HTML_ENTITY_MAP[c] || c;
+ });
+}
+
+// OSWASP Guidlines: escape all non alphanumeric characters in ASCII space.
+var HTML_ATTRIBUTE_CHARACTERS_EXPRESSION =
+ /[\x00-\x2F\x3A-\x40\5B-\x60\x7B-\xFF]/g;
+function escapeHTMLAttribute(text) {
+ return text && text.replace(HTML_ATTRIBUTE_CHARACTERS_EXPRESSION, function (c) {
+ return "&#x" + ('00' + c.charCodeAt(0).toString(16)).slice(-2) + ";";
+ });
+};
+
+// OSWASP Guidlines: escape all non alphanumeric characters in ASCII space.
+var JAVASCRIPT_CHARACTERS_EXPRESSION =
+ /[\x00-\x2F\x3A-\x40\5B-\x60\x7B-\xFF]/g;
+function escapeJavaScriptData(text) {
+ return text && text.replace(JAVASCRIPT_CHARACTERS_EXPRESSION, function (c) {
+ return "\\x" + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+ });
+}
+
+exports.escapeHTML = escapeHTML;
+exports.escapeHTMLAttribute = escapeHTMLAttribute;
+exports.escapeJavaScriptData = escapeJavaScriptData;
diff --git a/static/js/timeslider.js b/static/js/timeslider.js
index d2fce8fd..143ef328 100644
--- a/static/js/timeslider.js
+++ b/static/js/timeslider.js
@@ -26,39 +26,9 @@ require('/jquery');
JSON = require('/json2');
require('/undo-xpopup');
-function createCookie(name,value,days)
-{
- if (days) {
- var date = new Date();
- date.setTime(date.getTime()+(days*24*60*60*1000));
- var expires = "; expires="+date.toGMTString();
- }
- else var expires = "";
- document.cookie = name+"="+value+expires+"; path=/";
-}
-
-function readCookie(name)
-{
- var nameEQ = name + "=";
- var ca = document.cookie.split(';');
- for(var i=0;i < ca.length;i++) {
- var c = ca[i];
- while (c.charAt(0)==' ') c = c.substring(1,c.length);
- if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
- }
- return null;
-}
-
-function randomString() {
- var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- var string_length = 20;
- var randomstring = '';
- for (var i=0; i<string_length; i++) {
- var rnum = Math.floor(Math.random() * chars.length);
- randomstring += chars.substring(rnum,rnum+1);
- }
- return "t." + randomstring;
-}
+var createCookie = require('/pad_utils').createCookie;
+var readCookie = require('/pad_utils').readCookie;
+var randomString = require('/pad_utils').randomString;
var socket, token, padId, export_links;
@@ -79,7 +49,7 @@ function init() {
token = readCookie("token");
if(token == null)
{
- token = randomString();
+ token = "t." + randomString();
createCookie("token", token, 60);
}
diff --git a/static/js/undomodule.js b/static/js/undomodule.js
index aff41a70..886cbdf0 100644
--- a/static/js/undomodule.js
+++ b/static/js/undomodule.js
@@ -20,7 +20,7 @@
* limitations under the License.
*/
-var Changeset = require('/easysync2').Changeset;
+var Changeset = require('/Changeset');
var extend = require('/ace2_common').extend;
var undoModule = (function()