overleaf/services/web/public/js/ace/mode/folding/xml.js
2014-02-12 10:23:40 +00:00

254 lines
8.6 KiB
JavaScript
Executable file

/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../../lib/oop");
var lang = require("../../lib/lang");
var Range = require("../../range").Range;
var BaseFoldMode = require("./fold_mode").FoldMode;
var TokenIterator = require("../../token_iterator").TokenIterator;
var FoldMode = exports.FoldMode = function(voidElements) {
BaseFoldMode.call(this);
this.voidElements = voidElements || {};
};
oop.inherits(FoldMode, BaseFoldMode);
(function() {
this.getFoldWidget = function(session, foldStyle, row) {
var tag = this._getFirstTagInLine(session, row);
if (tag.closing)
return foldStyle == "markbeginend" ? "end" : "";
if (!tag.tagName || this.voidElements[tag.tagName.toLowerCase()])
return "";
if (tag.selfClosing)
return "";
if (tag.value.indexOf("/" + tag.tagName) !== -1)
return "";
return "start";
};
this._getFirstTagInLine = function(session, row) {
var tokens = session.getTokens(row);
var value = "";
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (token.type.lastIndexOf("meta.tag", 0) === 0)
value += token.value;
else
value += lang.stringRepeat(" ", token.value.length);
}
return this._parseTag(value);
};
this.tagRe = /^(\s*)(<?(\/?)([-_a-zA-Z0-9:!]*)\s*(\/?)>?)/;
this._parseTag = function(tag) {
var match = tag.match(this.tagRe);
var column = 0;
return {
value: tag,
match: match ? match[2] : "",
closing: match ? !!match[3] : false,
selfClosing: match ? !!match[5] || match[2] == "/>" : false,
tagName: match ? match[4] : "",
column: match[1] ? column + match[1].length : column
};
};
/*
* reads a full tag and places the iterator after the tag
*/
this._readTagForward = function(iterator) {
var token = iterator.getCurrentToken();
if (!token)
return null;
var value = "";
var start;
do {
if (token.type.lastIndexOf("meta.tag", 0) === 0) {
if (!start) {
var start = {
row: iterator.getCurrentTokenRow(),
column: iterator.getCurrentTokenColumn()
};
}
value += token.value;
if (value.indexOf(">") !== -1) {
var tag = this._parseTag(value);
tag.start = start;
tag.end = {
row: iterator.getCurrentTokenRow(),
column: iterator.getCurrentTokenColumn() + token.value.length
};
iterator.stepForward();
return tag;
}
}
} while(token = iterator.stepForward());
return null;
};
this._readTagBackward = function(iterator) {
var token = iterator.getCurrentToken();
if (!token)
return null;
var value = "";
var end;
do {
if (token.type.lastIndexOf("meta.tag", 0) === 0) {
if (!end) {
end = {
row: iterator.getCurrentTokenRow(),
column: iterator.getCurrentTokenColumn() + token.value.length
};
}
value = token.value + value;
if (value.indexOf("<") !== -1) {
var tag = this._parseTag(value);
tag.end = end;
tag.start = {
row: iterator.getCurrentTokenRow(),
column: iterator.getCurrentTokenColumn()
};
iterator.stepBackward();
return tag;
}
}
} while(token = iterator.stepBackward());
return null;
};
this._pop = function(stack, tag) {
while (stack.length) {
var top = stack[stack.length-1];
if (!tag || top.tagName == tag.tagName) {
return stack.pop();
}
else if (this.voidElements[tag.tagName]) {
return;
}
else if (this.voidElements[top.tagName]) {
stack.pop();
continue;
} else {
return null;
}
}
};
this.getFoldWidgetRange = function(session, foldStyle, row) {
var firstTag = this._getFirstTagInLine(session, row);
if (!firstTag.match)
return null;
var isBackward = firstTag.closing || firstTag.selfClosing;
var stack = [];
var tag;
if (!isBackward) {
var iterator = new TokenIterator(session, row, firstTag.column);
var start = {
row: row,
column: firstTag.column + firstTag.tagName.length + 2
};
while (tag = this._readTagForward(iterator)) {
if (tag.selfClosing) {
if (!stack.length) {
tag.start.column += tag.tagName.length + 2;
tag.end.column -= 2;
return Range.fromPoints(tag.start, tag.end);
} else
continue;
}
if (tag.closing) {
this._pop(stack, tag);
if (stack.length == 0)
return Range.fromPoints(start, tag.start);
}
else {
stack.push(tag)
}
}
}
else {
var iterator = new TokenIterator(session, row, firstTag.column + firstTag.match.length);
var end = {
row: row,
column: firstTag.column
};
while (tag = this._readTagBackward(iterator)) {
if (tag.selfClosing) {
if (!stack.length) {
tag.start.column += tag.tagName.length + 2;
tag.end.column -= 2;
return Range.fromPoints(tag.start, tag.end);
} else
continue;
}
if (!tag.closing) {
this._pop(stack, tag);
if (stack.length == 0) {
tag.start.column += tag.tagName.length + 2;
return Range.fromPoints(tag.start, end);
}
}
else {
stack.push(tag)
}
}
}
};
}).call(FoldMode.prototype);
});