From 89bda83e0570ab87c6e449f5955613d5385e90b3 Mon Sep 17 00:00:00 2001 From: "alexanders@b2ef00c0-3703-41da-baef-cfe82387ac0c" Date: Wed, 3 Feb 2010 00:50:41 +0000 Subject: removed obsolete svn folder from hg tree --HG-- extra : convert_revision : svn%3Ab2ef00c0-3703-41da-baef-cfe82387ac0c/trunk%408 --- infrastructure/ace/www/contentcollector.js | 509 +++++++++++++++++++++++++++++ 1 file changed, 509 insertions(+) create mode 100644 infrastructure/ace/www/contentcollector.js (limited to 'infrastructure/ace/www/contentcollector.js') diff --git a/infrastructure/ace/www/contentcollector.js b/infrastructure/ace/www/contentcollector.js new file mode 100644 index 0000000..c5d8ddb --- /dev/null +++ b/infrastructure/ace/www/contentcollector.js @@ -0,0 +1,509 @@ +// THIS FILE IS ALSO AN APPJET MODULE: etherpad.collab.ace.contentcollector +// %APPJET%: import("etherpad.collab.ace.easysync2.Changeset") + +/** + * 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 _MAX_LIST_LEVEL = 8; + +function sanitizeUnicode(s) { + return s.replace(/[\uffff\ufffe\ufeff\ufdd0-\ufdef\ud800-\udfff]/g, '?'); +} + +function makeContentCollector(collectStyles, browser, apool, domInterface, + className2Author) { + browser = browser || {}; + + var dom = domInterface || { + isNodeText: function(n) { + return (n.nodeType == 3); + }, + nodeTagName: function(n) { + return n.tagName; + }, + nodeValue: function(n) { + return n.nodeValue; + }, + nodeNumChildren: function(n) { + return n.childNodes.length; + }, + nodeChild: function(n, i) { + return n.childNodes.item(i); + }, + nodeProp: function(n, p) { + return n[p]; + }, + nodeAttr: function(n, a) { + return n.getAttribute(a); + }, + optNodeInnerHTML: function(n) { + return n.innerHTML; + } + }; + + var _blockElems = { "div":1, "p":1, "pre":1, "li":1 }; + function isBlockElement(n) { + return !!_blockElems[(dom.nodeTagName(n) || "").toLowerCase()]; + } + function textify(str) { + return sanitizeUnicode( + str.replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ')); + } + function getAssoc(node, name) { + return dom.nodeProp(node, "_magicdom_"+name); + } + + var lines = (function() { + var textArray = []; + var attribsArray = []; + var attribsBuilder = null; + var op = Changeset.newOp('+'); + var self = { + length: function() { return textArray.length; }, + atColumnZero: function() { + return textArray[textArray.length-1] === ""; + }, + startNew: function() { + textArray.push(""); + self.flush(true); + attribsBuilder = Changeset.smartOpAssembler(); + }, + textOfLine: function(i) { return textArray[i]; }, + appendText: function(txt, attrString) { + textArray[textArray.length-1] += txt; + //dmesg(txt+" / "+attrString); + op.attribs = attrString; + op.chars = txt.length; + attribsBuilder.append(op); + }, + textLines: function() { return textArray.slice(); }, + attribLines: function() { return attribsArray; }, + // call flush only when you're done + flush: function(withNewline) { + if (attribsBuilder) { + attribsArray.push(attribsBuilder.toString()); + attribsBuilder = null; + } + } + }; + self.startNew(); + return self; + }()); + var cc = {}; + function _ensureColumnZero(state) { + if (! lines.atColumnZero()) { + _startNewLine(state); + } + } + var selection, startPoint, endPoint; + var selStart = [-1,-1], selEnd = [-1,-1]; + var blockElems = { "div":1, "p":1, "pre":1 }; + function _isEmpty(node, state) { + // consider clean blank lines pasted in IE to be empty + if (dom.nodeNumChildren(node) == 0) return true; + if (dom.nodeNumChildren(node) == 1 && + getAssoc(node, "shouldBeEmpty") && dom.optNodeInnerHTML(node) == " " + && ! getAssoc(node, "unpasted")) { + if (state) { + var child = dom.nodeChild(node, 0); + _reachPoint(child, 0, state); + _reachPoint(child, 1, state); + } + return true; + } + return false; + } + function _pointHere(charsAfter, state) { + var ln = lines.length()-1; + var chr = lines.textOfLine(ln).length; + if (chr == 0 && state.listType && state.listType != 'none') { + chr += 1; // listMarker + } + chr += charsAfter; + return [ln, chr]; + } + function _reachBlockPoint(nd, idx, state) { + if (! dom.isNodeText(nd)) _reachPoint(nd, idx, state); + } + function _reachPoint(nd, idx, state) { + if (startPoint && nd == startPoint.node && startPoint.index == idx) { + selStart = _pointHere(0, state); + } + if (endPoint && nd == endPoint.node && endPoint.index == idx) { + selEnd = _pointHere(0, state); + } + } + function _incrementFlag(state, flagName) { + state.flags[flagName] = (state.flags[flagName] || 0)+1; + } + function _decrementFlag(state, flagName) { + state.flags[flagName]--; + } + function _incrementAttrib(state, attribName) { + if (! state.attribs[attribName]) { + state.attribs[attribName] = 1; + } + else { + state.attribs[attribName]++; + } + _recalcAttribString(state); + } + function _decrementAttrib(state, attribName) { + state.attribs[attribName]--; + _recalcAttribString(state); + } + function _enterList(state, listType) { + var oldListType = state.listType; + state.listLevel = (state.listLevel || 0)+1; + if (listType != 'none') { + state.listNesting = (state.listNesting || 0)+1; + } + state.listType = listType; + _recalcAttribString(state); + return oldListType; + } + function _exitList(state, oldListType) { + state.listLevel--; + if (state.listType != 'none') { + state.listNesting--; + } + state.listType = oldListType; + _recalcAttribString(state); + } + function _enterAuthor(state, author) { + var oldAuthor = state.author; + state.authorLevel = (state.authorLevel || 0)+1; + state.author = author; + _recalcAttribString(state); + return oldAuthor; + } + function _exitAuthor(state, oldAuthor) { + state.authorLevel--; + state.author = oldAuthor; + _recalcAttribString(state); + } + function _recalcAttribString(state) { + var lst = []; + for(var a in state.attribs) { + if (state.attribs[a]) { + lst.push([a,'true']); + } + } + if (state.authorLevel > 0) { + var authorAttrib = ['author', state.author]; + if (apool.putAttrib(authorAttrib, true) >= 0) { + // require that author already be in pool + // (don't add authors from other documents, etc.) + lst.push(authorAttrib); + } + } + state.attribString = Changeset.makeAttribsString('+', lst, apool); + } + function _produceListMarker(state) { + lines.appendText('*', Changeset.makeAttribsString( + '+', [['list', state.listType], + ['insertorder', 'first']], + apool)); + } + function _startNewLine(state) { + if (state) { + var atBeginningOfLine = lines.textOfLine(lines.length()-1).length == 0; + if (atBeginningOfLine && state.listType && state.listType != 'none') { + _produceListMarker(state); + } + } + lines.startNew(); + } + cc.notifySelection = function (sel) { + if (sel) { + selection = sel; + startPoint = selection.startPoint; + endPoint = selection.endPoint; + } + }; + cc.collectContent = function (node, state) { + if (! state) { + state = {flags: {/*name -> nesting counter*/}, + attribs: {/*name -> nesting counter*/}, + attribString: ''}; + } + var isBlock = isBlockElement(node); + var isEmpty = _isEmpty(node, state); + if (isBlock) _ensureColumnZero(state); + var startLine = lines.length()-1; + _reachBlockPoint(node, 0, state); + if (dom.isNodeText(node)) { + var txt = dom.nodeValue(node); + var rest = ''; + var x = 0; // offset into original text + if (txt.length == 0) { + if (startPoint && node == startPoint.node) { + selStart = _pointHere(0, state); + } + if (endPoint && node == endPoint.node) { + selEnd = _pointHere(0, state); + } + } + while (txt.length > 0) { + var consumed = 0; + if (state.flags.preMode) { + var firstLine = txt.split('\n',1)[0]; + consumed = firstLine.length+1; + rest = txt.substring(consumed); + txt = firstLine; + } + else { /* will only run this loop body once */ } + if (startPoint && node == startPoint.node && + startPoint.index-x <= txt.length) { + selStart = _pointHere(startPoint.index-x, state); + } + if (endPoint && node == endPoint.node && + endPoint.index-x <= txt.length) { + selEnd = _pointHere(endPoint.index-x, state); + } + var txt2 = txt; + if ((! state.flags.preMode) && /^[\r\n]*$/.exec(txt)) { + // prevents textnodes containing just "\n" from being significant + // in safari when pasting text, now that we convert them to + // spaces instead of removing them, because in other cases + // removing "\n" from pasted HTML will collapse words together. + txt2 = ""; + } + var atBeginningOfLine = lines.textOfLine(lines.length()-1).length == 0; + if (atBeginningOfLine) { + // newlines in the source mustn't become spaces at beginning of line box + txt2 = txt2.replace(/^\n*/, ''); + } + if (atBeginningOfLine && state.listType && state.listType != 'none') { + _produceListMarker(state); + } + lines.appendText(textify(txt2), state.attribString); + x += consumed; + txt = rest; + if (txt.length > 0) { + _startNewLine(state); + } + } + } + else { + var tname = (dom.nodeTagName(node) || "").toLowerCase(); + if (tname == "br") { + _startNewLine(state); + } + else if (tname == "script" || tname == "style") { + // ignore + } + else if (! isEmpty) { + var styl = dom.nodeAttr(node, "style"); + var cls = dom.nodeProp(node, "className"); + + var isPre = (tname == "pre"); + if ((! isPre) && browser.safari) { + isPre = (styl && /\bwhite-space:\s*pre\b/i.exec(styl)); + } + if (isPre) _incrementFlag(state, 'preMode'); + var attribs = null; + var oldListTypeOrNull = null; + var oldAuthorOrNull = null; + if (collectStyles) { + function doAttrib(na) { + attribs = (attribs || []); + attribs.push(na); + _incrementAttrib(state, na); + } + if (tname == "b" || (styl && /\bfont-weight:\s*bold\b/i.exec(styl)) || + tname == "strong") { + doAttrib("bold"); + } + if (tname == "i" || (styl && /\bfont-style:\s*italic\b/i.exec(styl)) || + tname == "em") { + doAttrib("italic"); + } + if (tname == "u" || (styl && /\btext-decoration:\s*underline\b/i.exec(styl)) || + tname == "ins") { + doAttrib("underline"); + } + if (tname == "s" || (styl && /\btext-decoration:\s*line-through\b/i.exec(styl)) || + tname == "del") { + doAttrib("strikethrough"); + } + if (tname == "ul") { + var type; + var rr = cls && /(?:^| )list-(bullet[12345678])\b/.exec(cls); + type = rr && rr[1] || "bullet"+ + String(Math.min(_MAX_LIST_LEVEL, (state.listNesting||0)+1)); + oldListTypeOrNull = (_enterList(state, type) || 'none'); + } + else if ((tname == "div" || tname == "p") && cls && + cls.match(/(?:^| )ace-line\b/)) { + oldListTypeOrNull = (_enterList(state, type) || 'none'); + } + if (className2Author && cls) { + var classes = cls.match(/\S+/g); + if (classes && classes.length > 0) { + for(var i=0;i=0; i--) { + var oldString = lineStrings[i]; + var oldAttribString = lineAttribs[i]; + if (oldString.length > lineLimit+buffer) { + var newStrings = []; + var newAttribStrings = []; + while (oldString.length > lineLimit) { + //var semiloc = oldString.lastIndexOf(';', lineLimit-1); + //var lengthToTake = (semiloc >= 0 ? (semiloc+1) : lineLimit); + lengthToTake = lineLimit; + newStrings.push(oldString.substring(0, lengthToTake)); + oldString = oldString.substring(lengthToTake); + newAttribStrings.push(Changeset.subattribution(oldAttribString, + 0, lengthToTake)); + oldAttribString = Changeset.subattribution(oldAttribString, + lengthToTake); + } + if (oldString.length > 0) { + newStrings.push(oldString); + newAttribStrings.push(oldAttribString); + } + function fixLineNumber(lineChar) { + if (lineChar[0] < 0) return; + var n = lineChar[0]; + var c = lineChar[1]; + if (n > i) { + n += (newStrings.length-1); + } + else if (n == i) { + var a = 0; + while (c > newStrings[a].length) { + c -= newStrings[a].length; + a++; + } + n += a; + } + lineChar[0] = n; + lineChar[1] = c; + } + fixLineNumber(ss); + fixLineNumber(se); + linesWrapped++; + numLinesAfter += newStrings.length; + + newStrings.unshift(i, 1); + lineStrings.splice.apply(lineStrings, newStrings); + newAttribStrings.unshift(i, 1); + lineAttribs.splice.apply(lineAttribs, newAttribStrings); + } + } + return {linesWrapped:linesWrapped, numLinesAfter:numLinesAfter}; + } + var wrapData = fixLongLines(); + + return { selStart: ss, selEnd: se, linesWrapped: wrapData.linesWrapped, + numLinesAfter: wrapData.numLinesAfter, + lines: lineStrings, lineAttribs: lineAttribs }; + } + + return cc; +} -- cgit v1.2.3