aboutsummaryrefslogtreecommitdiffstats
path: root/infrastructure/ace/www/domline.js
diff options
context:
space:
mode:
Diffstat (limited to 'infrastructure/ace/www/domline.js')
-rw-r--r--infrastructure/ace/www/domline.js210
1 files changed, 210 insertions, 0 deletions
diff --git a/infrastructure/ace/www/domline.js b/infrastructure/ace/www/domline.js
new file mode 100644
index 0000000..70f86cc
--- /dev/null
+++ b/infrastructure/ace/www/domline.js
@@ -0,0 +1,210 @@
+// 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.
+ */
+
+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);
+ if (listType) {
+ listType = listType[1];
+ if (listType) {
+ preHtml = '<ul class="list-'+listType+'"><li>';
+ postHtml = '</li></ul>';
+ }
+ 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;
+ });
+ }
+ if ((! txt) && cls) {
+ lineClass = domline.addToLineClass(lineClass, cls);
+ }
+ else if (txt) {
+ var extraOpenTags = "";
+ var extraCloseTags = "";
+ if (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('');
+};