You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@corinthia.apache.org by ja...@apache.org on 2015/08/17 10:50:12 UTC
[20/28] incubator-corinthia git commit: included MOC compiler for Qt
implementation
http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9bf02bb2/experiments/editorFramework/src/Javascript_Layer_0/Selection.js
----------------------------------------------------------------------
diff --git a/experiments/editorFramework/src/Javascript_Layer_0/Selection.js b/experiments/editorFramework/src/Javascript_Layer_0/Selection.js
new file mode 100644
index 0000000..c4f8efb
--- /dev/null
+++ b/experiments/editorFramework/src/Javascript_Layer_0/Selection.js
@@ -0,0 +1,1430 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+// FIXME: cursor does not display correctly if it is after a space at the end of the line
+
+var Selection_isMarked;
+var Selection_get;
+var Selection_set;
+var Selection_clear;
+
+var Selection_update;
+var Selection_selectAll;
+var Selection_selectParagraph;
+var Selection_selectWordAtCursor;
+var Selection_dragSelectionBegin;
+var Selection_dragSelectionUpdate;
+var Selection_moveStartLeft;
+var Selection_moveStartRight;
+var Selection_moveEndLeft;
+var Selection_moveEndRight;
+var Selection_setSelectionStartAtCoords;
+var Selection_setSelectionEndAtCoords;
+var Selection_setTableSelectionEdgeAtCoords;
+var Selection_setEmptySelectionAt;
+var Selection_deleteRangeContents;
+var Selection_deleteContents;
+var Selection_clearSelection;
+var Selection_preserveWhileExecuting;
+var Selection_posAtStartOfWord;
+var Selection_posAtEndOfWord;
+var Selection_preferElementPositions;
+var Selection_print;
+
+(function() {
+
+ var HANDLE_NONE = 0;
+ var HANDLE_START = 1;
+ var HANDLE_END = 2;
+
+ var activeHandle = HANDLE_NONE;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // //
+ // Selection getter and setter //
+ // //
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ var Selection_setInternal;
+
+ (function() {
+
+ var selection = new Object();
+
+ Selection_isMarked = function()
+ {
+ if (selection.value == null)
+ return null;
+ else
+ return selection.value.isMarked;
+ }
+
+ // public
+ Selection_get = function()
+ {
+ if (selection.value == null)
+ return null;
+ else
+ return new Range(selection.value.startNode,selection.value.startOffset,
+ selection.value.endNode,selection.value.endOffset);
+ }
+
+ // public
+ Selection_setInternal =
+ function(newStartNode,newStartOffset,newEndNode,newEndOffset,isMarked)
+ {
+ var range = new Range(newStartNode,newStartOffset,newEndNode,newEndOffset);
+ if (!Range_isForwards(range))
+ range = new Range(newEndNode,newEndOffset,newStartNode,newStartOffset);
+ range = boundaryCompliantRange(range);
+
+ UndoManager_setProperty(selection,"value",
+ { startNode: range.start.node,
+ startOffset: range.start.offset,
+ endNode: range.end.node,
+ endOffset: range.end.offset,
+ isMarked: isMarked });
+ }
+
+ Selection_set = function(newStartNode,newStartOffset,newEndNode,newEndOffset,
+ keepActiveHandle,isMarked)
+ {
+ Selection_setInternal(newStartNode,newStartOffset,newEndNode,newEndOffset,isMarked);
+ Selection_update();
+ if (!keepActiveHandle)
+ activeHandle = HANDLE_NONE;
+ }
+
+ // public
+ Selection_clear = function()
+ {
+ UndoManager_setProperty(selection,"value",null);
+ Selection_update();
+ }
+ })();
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // //
+ // Other selection functions //
+ // //
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ var selectionDivs = new Array();
+ var selectionHighlights = new Array();
+ var tableSelection = null;
+
+ // private
+ updateTableSelection = function(selRange)
+ {
+ tableSelection = Tables_regionFromRange(selRange);
+ if (tableSelection == null)
+ return false;
+
+ Range_trackWhileExecuting(selRange,function() {
+
+ removeSelectionHighlights(getRangeData(null));
+
+ var sel = tableSelection;
+
+ var topLeftTD = Table_get(sel.structure,sel.top,sel.left);
+ var bottomRightTD = Table_get(sel.structure,sel.bottom,sel.right);
+
+ var topLeftRect = topLeftTD.element.getBoundingClientRect();
+ var bottomRightRect = bottomRightTD.element.getBoundingClientRect();
+
+ var left = topLeftRect.left;
+ var top = topLeftRect.top;
+
+ var bottom = bottomRightRect.bottom;
+ var right = bottomRightRect.right;
+
+ var x = left;
+ var y = top;
+ var width = right - left;
+ var height = bottom - top;
+
+ x += window.scrollX;
+ y += window.scrollY;
+
+ var div = makeSelectionDiv();
+ DOM_setAttribute(div,"class",Keys.SELECTION_HIGHLIGHT);
+ DOM_setStyleProperties(div,{ "position": "absolute",
+ "left": x+"px",
+ "top": y+"px",
+ "width": width+"px",
+ "height": height+"px",
+ "background-color": "rgb(201,221,238)",
+ "z-index": -1 });
+
+ setTableEdges(x,y,width,height);
+ setEditorHandles({ type: "table", x: x, y: y, width: width, height: height });
+ });
+
+ Selection_setInternal(selRange.start.node,selRange.start.offset,
+ selRange.end.node,selRange.end.offset);
+
+ return true;
+ }
+
+ function makeSelectionDiv()
+ {
+ var div = DOM_createElement(document,"DIV");
+ DOM_appendChild(document.body,div);
+ selectionDivs.push(div);
+ return div;
+ }
+
+ function setTableEdges(x,y,width,height)
+ {
+ var left = makeSelectionDiv();
+ var right = makeSelectionDiv();
+ var top = makeSelectionDiv();
+ var bottom = makeSelectionDiv();
+
+ var thick = 2;
+ width++;
+ height++;
+ setBoxCoords(left,x-thick,y-thick,thick,height+2*thick);
+ setBoxCoords(right,x+width,y-thick,thick,height+2*thick);
+ setBoxCoords(top,x-thick,y-thick,width+2*thick,thick);
+ setBoxCoords(bottom,x-thick,y+height,width+2*thick,thick);
+
+ function setBoxCoords(box,x,y,width,height)
+ {
+ DOM_setStyleProperties(box,{ "position": "absolute",
+ "left": x+"px",
+ "top": y+"px",
+ "width": width+"px",
+ "height": height+"px",
+ "background-color": "blue",
+ "z-index": 1 });
+ }
+ }
+
+ var editorHandles = { type: "none" };
+ function setEditorHandles(info)
+ {
+ var oldEditorHandles = editorHandles;
+ editorHandles = info;
+ UndoManager_addAction(function() {
+ setEditorHandles(oldEditorHandles);
+ });
+ if (info.type == "cursor") {
+ Editor_setCursor(info.left,info.top,info.width,info.height);
+ }
+ else if (info.type == "selection") {
+ if (!Selection_isMarked()) {
+ Editor_setSelectionHandles(info.x1,info.y1,
+ info.height1,info.x2,info.y2,info.height2);
+ }
+ Editor_setSelectionBounds(info.boundsLeft,info.boundsTop,
+ info.boundsRight,info.boundsBottom);
+ }
+ else if (info.type == "none") {
+ Editor_clearSelectionHandlesAndCursor();
+ }
+ else if (info.type == "table") {
+ Editor_setTableSelection(info.x,info.y,info.width,info.height);
+ }
+ else {
+ throw new Error("setEditorHandles: unknown type "+type);
+ }
+ }
+
+ function getPrevHighlightText(node)
+ {
+ if ((node.previousSibling != null) &&
+ isSelectionHighlight(node.previousSibling) &&
+ (node.previousSibling.lastChild != null) &&
+ (node.previousSibling.lastChild.nodeType == Node.TEXT_NODE))
+ return node.previousSibling.lastChild;
+ else
+ return null;
+ }
+
+ function getNextHighlightText(node)
+ {
+ if ((node.nextSibling != null) &&
+ isSelectionHighlight(node.nextSibling) &&
+ (node.nextSibling.firstChild != null) &&
+ (node.nextSibling.firstChild.nodeType == Node.TEXT_NODE))
+ return node.nextSibling.firstChild;
+ else
+ return null;
+ }
+
+ function getTextNodeBefore(node)
+ {
+ var prev = node.previousSibling;
+ if ((prev != null) && (prev.nodeType == Node.TEXT_NODE)) {
+ return prev;
+ }
+ else {
+ var text = DOM_createTextNode(document,"");
+ DOM_insertBefore(node.parentNode,text,node);
+ return text;
+ }
+ }
+
+ function getTextNodeAfter(node)
+ {
+ var next = node.nextSibling;
+ if ((next != null) && (next.nodeType == Node.TEXT_NODE)) {
+ return next;
+ }
+ else {
+ var text = DOM_createTextNode(document,"");
+ DOM_insertBefore(node.parentNode,text,node.nextSibling);
+ return text;
+ }
+ }
+
+ function setSelectionHighlights(highlights)
+ {
+ UndoManager_addAction(setSelectionHighlights,selectionHighlights);
+ selectionHighlights = highlights;
+ }
+
+ function createSelectionHighlights(data)
+ {
+ var newHighlights = arrayCopy(selectionHighlights);
+
+ var outermost = data.outermost;
+ for (var i = 0; i < outermost.length; i++) {
+ recurse(outermost[i]);
+ }
+
+ setSelectionHighlights(newHighlights);
+
+ function recurse(node)
+ {
+ if (isSpecialBlockNode(node)) {
+ if (!isSelectionHighlight(node.parentNode)) {
+ var wrapped = DOM_wrapNode(node,"DIV");
+ DOM_setAttribute(wrapped,"class",Keys.SELECTION_CLASS);
+ newHighlights.push(wrapped);
+ }
+ }
+ else if (isNoteNode(node)) {
+ if (!isSelectionHighlight(node.parentNode)) {
+ var wrapped = DOM_wrapNode(node,"SPAN");
+ DOM_setAttribute(wrapped,"class",Keys.SELECTION_CLASS);
+ newHighlights.push(wrapped);
+ }
+ }
+ else if (node.nodeType == Node.TEXT_NODE) {
+ createTextHighlight(node,data,newHighlights);
+ }
+ else {
+ var next;
+ for (var child = node.firstChild; child != null; child = next) {
+ next = child.nextSibling;
+ recurse(child);
+ }
+ }
+ }
+ }
+
+ function createTextHighlight(node,data,newHighlights)
+ {
+ var selRange = data.range;
+ if (isSelectionHighlight(node.parentNode)) {
+
+ if ((node == selRange.end.node) && (node.nodeValue.length > selRange.end.offset)) {
+ var destTextNode = getTextNodeAfter(node.parentNode);
+ DOM_moveCharacters(node,
+ selRange.end.offset,
+ node.nodeValue.length,
+ destTextNode,0,
+ true,false);
+ }
+ if ((node == selRange.start.node) && (selRange.start.offset > 0)) {
+ var destTextNode = getTextNodeBefore(node.parentNode);
+ DOM_moveCharacters(node,
+ 0,
+ selRange.start.offset,
+ destTextNode,destTextNode.nodeValue.length,
+ false,true);
+ }
+
+ return;
+ }
+
+ var anext;
+ for (var a = node; a != null; a = anext) {
+ anext = a.parentNode;
+ if (isSelectionHighlight(a))
+ DOM_removeNodeButKeepChildren(a);
+ }
+
+ if (node == selRange.end.node) {
+ if (isWhitespaceString(node.nodeValue.substring(0,selRange.end.offset)))
+ return;
+ Formatting_splitTextAfter(selRange.end,
+ function() { return true; });a
+ }
+
+
+ if (node == selRange.start.node) {
+ if (isWhitespaceString(node.nodeValue.substring(selRange.start.offset)))
+ return;
+ Formatting_splitTextBefore(selRange.start,
+ function() { return true; });
+ }
+
+ var prevText = getPrevHighlightText(node);
+ var nextText = getNextHighlightText(node);
+
+ if ((prevText != null) && containsSelection(data.nodeSet,prevText)) {
+ DOM_moveCharacters(node,0,node.nodeValue.length,
+ prevText,prevText.nodeValue.length,true,false);
+ DOM_deleteNode(node);
+ }
+ else if ((nextText != null) && containsSelection(data.nodeSet,nextText)) {
+ DOM_moveCharacters(node,0,node.nodeValue.length,
+ nextText,0,false,true);
+ DOM_deleteNode(node);
+ }
+ else if (!isWhitespaceTextNode(node)) {
+ // Call moveCharacters() with an empty range, to force any tracked positions
+ // that are at the end of prevText or the start of nextText to move into this
+ // node
+ if (prevText != null) {
+ DOM_moveCharacters(prevText,
+ prevText.nodeValue.length,prevText.nodeValue.length,
+ node,0);
+ }
+ if (nextText != null) {
+ DOM_moveCharacters(nextText,0,0,node,node.nodeValue.length);
+ }
+
+ var wrapped = DOM_wrapNode(node,"SPAN");
+ DOM_setAttribute(wrapped,"class",Keys.SELECTION_CLASS);
+ newHighlights.push(wrapped);
+ }
+ }
+
+ function getRangeData(selRange)
+ {
+ var nodeSet = new NodeSet();
+ var nodes;
+ var outermost;
+ if (selRange != null) {
+ outermost = Range_getOutermostNodes(selRange);
+ nodes = Range_getAllNodes(selRange);
+ for (var i = 0; i < nodes.length; i++)
+ nodeSet.add(nodes[i]);
+ }
+ else {
+ nodes = new Array();
+ outermost = new Array();
+ }
+ return { range: selRange, nodeSet: nodeSet, nodes: nodes, outermost: outermost };
+ }
+
+ function removeSelectionHighlights(data,force)
+ {
+ var selectedSet = data.nodeSet;
+
+ var remainingHighlights = new Array();
+ var checkMerge = new Array();
+ for (var i = 0; i < selectionHighlights.length; i++) {
+ var span = selectionHighlights[i];
+ if ((span.parentNode != null) && (force || !containsSelection(selectedSet,span))) {
+ if (span.firstChild != null)
+ checkMerge.push(span.firstChild);
+ if (span.lastChild != null)
+ checkMerge.push(span.lastChild);
+
+ DOM_removeNodeButKeepChildren(span);
+ }
+ else if (span.parentNode != null) {
+ remainingHighlights.push(span);
+ }
+ }
+ setSelectionHighlights(remainingHighlights);
+
+ for (var i = 0; i < checkMerge.length; i++) {
+ // if not already merged
+ if ((checkMerge[i] != null) && (checkMerge[i].parentNode != null)) {
+ Formatting_mergeWithNeighbours(checkMerge[i],{});
+ }
+ }
+ }
+
+ function containsSelection(selectedSet,node)
+ {
+ if (selectedSet.contains(node))
+ return true;
+ for (var child = node.firstChild; child != null; child = child.nextSibling) {
+ if (containsSelection(selectedSet,child))
+ return true;
+ }
+ return false;
+ }
+
+ Selection_update = function()
+ {
+ var selRange = Selection_get();
+ var selMarked = Selection_isMarked();
+
+ Range_trackWhileExecuting(selRange,function() {
+ // Remove table selection DIVs
+ for (var i = 0; i < selectionDivs.length; i++)
+ DOM_deleteNode(selectionDivs[i]);
+ selectionDivs = new Array();
+ });
+
+ if (selRange == null) {
+ DOM_ignoreMutationsWhileExecuting(function() {
+ removeSelectionHighlights(getRangeData(null));
+ });
+ return;
+ }
+
+ Range_assertValid(selRange,"Selection");
+
+ if (Range_isEmpty(selRange)) {
+ // We just have a cursor
+
+ Range_trackWhileExecuting(selRange,function() {
+ DOM_ignoreMutationsWhileExecuting(function() {
+ removeSelectionHighlights(getRangeData(selRange));
+ });
+ });
+ // Selection may have changed as a result of removeSelectionHighlights()
+ Selection_setInternal(selRange.start.node,selRange.start.offset,
+ selRange.end.node,selRange.end.offset,
+ selMarked);
+ selRange = Selection_get(); // since setInternal can theoretically change it
+
+ // If we can't find the cursor rect for some reason, just don't update the position.
+ // This is better than using an incorrect position or throwing an exception.
+ var rect = Position_displayRectAtPos(selRange.end);
+ if (rect != null) {
+ var left = rect.left + window.scrollX;
+ var top = rect.top + window.scrollY;
+ var height = rect.height;
+ var width = rect.width ? rect.width : 2;
+ setEditorHandles({ type: "cursor",
+ left: left,
+ top: top,
+ width: width,
+ height: height});
+ }
+ return;
+ }
+
+ if (updateTableSelection(selRange))
+ return;
+
+ var rects = Range_getClientRects(selRange);
+
+ if ((rects != null) && (rects.length > 0)) {
+ var boundsLeft = null;
+ var boundsRight = null;
+ var boundsTop = null;
+ var boundsBottom = null
+
+ for (var i = 0; i < rects.length; i++) {
+ var left = rects[i].left + window.scrollX;
+ var top = rects[i].top + window.scrollY;
+ var width = rects[i].width;
+ var height = rects[i].height;
+ var right = left + width;
+ var bottom = top + height;
+
+ if (boundsLeft == null) {
+ boundsLeft = left;
+ boundsTop = top;
+ boundsRight = right;
+ boundsBottom = bottom;
+ }
+ else {
+ if (boundsLeft > left)
+ boundsLeft = left;
+ if (boundsRight < right)
+ boundsRight = right;
+ if (boundsTop > top)
+ boundsTop = top;
+ if (boundsBottom < bottom)
+ boundsBottom = bottom;
+ }
+ }
+
+ Range_trackWhileExecuting(selRange,function() {
+ DOM_ignoreMutationsWhileExecuting(function() {
+ var data = getRangeData(selRange);
+ createSelectionHighlights(data);
+ removeSelectionHighlights(data);
+ });
+ });
+
+ // Selection may have changed as a result of create/removeSelectionHighlights()
+ Selection_setInternal(selRange.start.node,selRange.start.offset,
+ selRange.end.node,selRange.end.offset,
+ selMarked);
+
+ var firstRect = rects[0];
+ var lastRect = rects[rects.length-1];
+
+ var x1 = firstRect.left + window.scrollX;
+ var y1 = firstRect.top + window.scrollY;
+ var height1 = firstRect.height;
+ var x2 = lastRect.right + window.scrollX;
+ var y2 = lastRect.top + window.scrollY;
+ var height2 = lastRect.height;
+
+ setEditorHandles({ type: "selection",
+ x1: x1,
+ y1: y1,
+ height1: height1,
+ x2: x2,
+ y2: y2,
+ height2: height2,
+ boundsLeft: boundsLeft,
+ boundsTop: boundsTop,
+ boundsRight: boundsRight,
+ boundsBottom: boundsBottom });;
+
+ }
+ else {
+ setEditorHandles({ type: "none" });
+ }
+ return;
+
+ function getAbsoluteOffset(node)
+ {
+ var offsetLeft = 0;
+ var offsetTop = 0;
+ for (; node != null; node = node.parentNode) {
+ if (node.offsetLeft != null)
+ offsetLeft += node.offsetLeft;
+ if (node.offsetTop != null)
+ offsetTop += node.offsetTop;
+ }
+ return { offsetLeft: offsetLeft, offsetTop: offsetTop };
+ }
+ }
+
+ // public
+ Selection_selectAll = function()
+ {
+ Selection_set(document.body,0,document.body,document.body.childNodes.length);
+ }
+
+ // public
+ Selection_selectParagraph = function()
+ {
+ var selRange = Selection_get();
+ if (selRange == null)
+ return;
+ var startNode = Position_closestActualNode(selRange.start);
+ while (!isParagraphNode(startNode) && !isContainerNode(startNode))
+ startNode = startNode.parentNode;
+
+ var endNode = Position_closestActualNode(selRange.end);
+ while (!isParagraphNode(endNode) && !isContainerNode(endNode))
+ endNode = endNode.parentNode;
+
+ var startPos = new Position(startNode,0);
+ var endPos = new Position(endNode,DOM_maxChildOffset(endNode));
+ startPos = Position_closestMatchForwards(startPos,Position_okForMovement);
+ endPos = Position_closestMatchBackwards(endPos,Position_okForMovement);
+
+ Selection_set(startPos.node,startPos.offset,endPos.node,endPos.offset);
+ }
+
+ // private
+ function getPunctuationCharsForRegex()
+ {
+ var escaped = "^$\\.*+?()[]{}|"; // From ECMAScript regexp spec (PatternCharacter)
+ var unescaped = "";
+ for (var i = 32; i <= 127; i++) {
+ var c = String.fromCharCode(i);
+ if ((escaped.indexOf(c) < 0) && !c.match(/[\w\d]/))
+ unescaped += c;
+ }
+ return unescaped + escaped.replace(/(.)/g,"\\$1");
+ }
+
+ // The following regular expressions are used by selectWordAtCursor(). We initialise them at
+ // startup to avoid repeatedly initialising them.
+ var punctuation = getPunctuationCharsForRegex();
+ var wsPunctuation = "\\s"+punctuation;
+
+ // Note: We use a blacklist of punctuation characters here instead of a whitelist of "word"
+ // characters, as the \w character class in javascript regular expressions only matches
+ // characters in english words. By using a blacklist, and assuming every other character is
+ // part of a word, we can select words containing non-english characters. This isn't a perfect
+ // solution, because there are many unicode characters that represent punctuation as well, but
+ // at least we handle the common ones here.
+
+ var reOtherEnd = new RegExp("["+wsPunctuation+"]*$");
+ var reOtherStart = new RegExp("^["+wsPunctuation+"]*");
+ var reWordOtherEnd = new RegExp("[^"+wsPunctuation+"]*["+wsPunctuation+"]*$");
+ var reWordOtherStart = new RegExp("^["+wsPunctuation+"]*[^"+wsPunctuation+"]*");
+
+ var reWordStart = new RegExp("^[^"+wsPunctuation+"]+");
+ var reWordEnd = new RegExp("[^"+wsPunctuation+"]+$");
+
+ Selection_posAtStartOfWord = function(pos)
+ {
+ var node = pos.node;
+ var offset = pos.offset;
+
+ if (node.nodeType == Node.TEXT_NODE) {
+ var before = node.nodeValue.substring(0,offset);
+ var matches = before.match(reWordEnd);
+ if (matches) {
+ var wordStart = offset - matches[0].length;
+ return new Position(node,wordStart);
+ }
+ }
+
+ return pos;
+ }
+
+ Selection_posAtEndOfWord = function(pos)
+ {
+ var node = pos.node;
+ var offset = pos.offset;
+
+ if (node.nodeType == Node.TEXT_NODE) {
+ var after = node.nodeValue.substring(offset);
+ var matches = after.match(reWordStart);
+ if (matches) {
+ var wordEnd = offset + matches[0].length;
+ return new Position(node,wordEnd);
+ }
+ }
+
+ return pos;
+ }
+
+ function rangeOfWordAtPos(pos)
+ {
+ var node = pos.node;
+ var offset = pos.offset;
+
+ if (node.nodeType == Node.TEXT_NODE) {
+ var before = node.nodeValue.substring(0,offset);
+ var after = node.nodeValue.substring(offset);
+
+ var otherBefore = before.match(reOtherEnd)[0];
+ var otherAfter = after.match(reOtherStart)[0];
+
+ var wordOtherBefore = before.match(reWordOtherEnd)[0];
+ var wordOtherAfter = after.match(reWordOtherStart)[0];
+
+ var startOffset = offset;
+ var endOffset = offset;
+
+ var haveWordBefore = (wordOtherBefore.length != otherBefore.length);
+ var haveWordAfter = (wordOtherAfter.length != otherAfter.length);
+
+ if ((otherBefore.length == 0) && (otherAfter.length == 0)) {
+ startOffset = offset - wordOtherBefore.length;
+ endOffset = offset + wordOtherAfter.length;
+ }
+ else if (haveWordBefore && !haveWordAfter) {
+ startOffset = offset - wordOtherBefore.length;
+ }
+ else if (haveWordAfter && !haveWordBefore) {
+ endOffset = offset + wordOtherAfter.length;
+ }
+ else if (otherBefore.length <= otherAfter.length) {
+ startOffset = offset - wordOtherBefore.length;
+ }
+ else {
+ endOffset = offset + wordOtherAfter.length;
+ }
+
+ return new Range(node,startOffset,node,endOffset);
+ }
+ else if (node.nodeType == Node.ELEMENT_NODE) {
+ var nodeBefore = node.childNodes[offset-1];
+ var nodeAfter = node.childNodes[offset];
+
+ if ((nodeBefore != null) && !isWhitespaceTextNode(nodeBefore))
+ return new Range(node,offset-1,node,offset);
+ else if ((nodeAfter != null) && !isWhitespaceTextNode(nodeAfter))
+ return new Range(node,offset,node,offset+1);
+ }
+
+ return null;
+ }
+
+ // public
+ Selection_selectWordAtCursor = function()
+ {
+ var selRange = Selection_get();
+ if (selRange == null)
+ return;
+
+ var pos = Position_closestMatchBackwards(selRange.end,Position_okForMovement);
+ var range = rangeOfWordAtPos(pos);
+ if (range != null) {
+ Selection_set(range.start.node,range.start.offset,range.end.node,range.end.offset);
+ }
+ }
+
+ // public
+ Selection_dragSelectionBegin = function(x,y,selectWord)
+ {
+ var pos = Position_closestMatchForwards(Position_atPoint(x,y),Position_okForMovement);
+
+ if (pos == null) {
+ Selection_clear();
+ return "error";
+ }
+
+ Selection_set(pos.node,pos.offset,pos.node,pos.offset);
+
+ if (selectWord)
+ Selection_selectWordAtCursor();
+
+ return "end";
+ }
+
+ var selectionHandleEnd = true;
+
+ function toStartOfWord(pos)
+ {
+ if (Input_isAtWordBoundary(pos,"backward"))
+ return pos;
+ var boundary = Input_toWordBoundary(pos,"backward");
+ return (boundary != null) ? boundary : pos;
+ }
+
+ function toEndOfWord(pos)
+ {
+ if (Input_isAtWordBoundary(pos,"forward"))
+ return pos;
+ var boundary = Input_toWordBoundary(pos,"forward");
+ return (boundary != null) ? boundary : pos;
+ }
+
+ // public
+ Selection_dragSelectionUpdate = function(x,y,selectWord)
+ {
+ y = Cursor_scrollDocumentForY(y);
+
+ var pos = Position_closestMatchForwards(Position_atPoint(x,y),Position_okForMovement);
+ var selRange = Selection_get();
+ if ((pos == null) || (selRange == null))
+ return "none";
+
+ var start = selRange.start;
+ var end = selRange.end;
+
+ if (selectionHandleEnd) {
+ if (Position_compare(pos,start) < 0) {
+ if (selectWord)
+ pos = toStartOfWord(pos);
+ selectionHandleEnd = false;
+ }
+ else {
+ if (selectWord)
+ pos = toEndOfWord(pos);
+ }
+ Selection_set(start.node,start.offset,pos.node,pos.offset);
+ }
+ else {
+ if (Position_compare(pos,end) > 0) {
+ if (selectWord)
+ pos = toEndOfWord(pos);
+ selectionHandleEnd = true;
+ }
+ else {
+ if (selectWord)
+ pos = toStartOfWord(pos);
+ }
+ Selection_set(pos.node,pos.offset,end.node,end.offset);
+ }
+
+ return selectionHandleEnd ? "end" : "start";
+ }
+
+ function moveBoundary(command)
+ {
+ var range = Selection_get();
+ if (range == null)
+ return;
+
+ var pos = null;
+ if (command == "start-left")
+ range.start = pos = Position_prevMatch(range.start,Position_okForMovement);
+ else if (command == "start-right")
+ range.start = pos = Position_nextMatch(range.start,Position_okForMovement);
+ else if (command == "end-left")
+ range.end = pos = Position_prevMatch(range.end,Position_okForMovement);
+ else if (command == "end-right")
+ range.end = pos = Position_nextMatch(range.end,Position_okForMovement);
+
+ if ((range.start != null) && (range.end != null)) {
+ var result;
+ range = Range_forwards(range);
+ Selection_set(range.start.node,range.start.offset,range.end.node,range.end.offset);
+ if (range.end == pos)
+ return "end";
+ else if (range.end == pos)
+ return "start";
+ }
+ return null;
+ }
+
+ // public
+ Selection_moveStartLeft = function()
+ {
+ return moveBoundary("start-left");
+ }
+
+ // public
+ Selection_moveStartRight = function()
+ {
+ return moveBoundary("start-right");
+ }
+
+ // public
+ Selection_moveEndLeft = function()
+ {
+ return moveBoundary("end-left");
+ }
+
+ // public
+ Selection_moveEndRight = function()
+ {
+ return moveBoundary("end-right");
+ }
+
+ // public
+ Selection_setSelectionStartAtCoords = function(x,y)
+ {
+ var position = Position_closestMatchForwards(Position_atPoint(x,y),Position_okForMovement);
+ if (position != null) {
+ position = Position_closestMatchBackwards(position,Position_okForMovement);
+ var selRange = Selection_get();
+ var newRange = new Range(position.node,position.offset,
+ selRange.end.node,selRange.end.offset);
+ if (Range_isForwards(newRange)) {
+ Selection_set(newRange.start.node,newRange.start.offset,
+ newRange.end.node,newRange.end.offset);
+ }
+ }
+ }
+
+ // public
+ Selection_setSelectionEndAtCoords = function(x,y)
+ {
+ var position = Position_closestMatchForwards(Position_atPoint(x,y),Position_okForMovement);
+ if (position != null) {
+ position = Position_closestMatchBackwards(position,Position_okForMovement);
+ var selRange = Selection_get();
+ var newRange = new Range(selRange.start.node,selRange.start.offset,
+ position.node,position.offset);
+ if (Range_isForwards(newRange)) {
+ Selection_set(newRange.start.node,newRange.start.offset,
+ newRange.end.node,newRange.end.offset);
+ }
+ }
+ }
+
+ // public
+ Selection_setTableSelectionEdgeAtCoords = function(edge,x,y)
+ {
+ if (tableSelection == null)
+ return;
+
+ var structure = tableSelection.structure;
+ var pointInfo = findCellInTable(structure,x,y);
+ if (pointInfo == null)
+ return;
+
+ if (edge == "topLeft") {
+ if (pointInfo.row <= tableSelection.bottom)
+ tableSelection.top = pointInfo.row;
+ if (pointInfo.col <= tableSelection.right)
+ tableSelection.left = pointInfo.col;
+ }
+ else if (edge == "bottomRight") {
+ if (pointInfo.row >= tableSelection.top)
+ tableSelection.bottom = pointInfo.row;
+ if (pointInfo.col >= tableSelection.left)
+ tableSelection.right = pointInfo.col;
+ }
+
+ // FIXME: handle the case where there is no cell at the specified row and column
+ var topLeftCell = Table_get(structure,tableSelection.top,tableSelection.left);
+ var bottomRightCell = Table_get(structure,tableSelection.bottom,tableSelection.right);
+
+ var topLeftNode = topLeftCell.element.parentNode;
+ var topLeftOffset = DOM_nodeOffset(topLeftCell.element);
+ var bottomRightNode = bottomRightCell.element.parentNode;
+ var bottomRightOffset = DOM_nodeOffset(bottomRightCell.element)+1;
+
+ Selection_set(topLeftNode,topLeftOffset,bottomRightNode,bottomRightOffset);
+
+ // FIXME: this could possibly be optimised
+ function findCellInTable(structure,x,y)
+ {
+ for (var r = 0; r < structure.numRows; r++) {
+ for (var c = 0; c < structure.numCols; c++) {
+ var cell = Table_get(structure,r,c);
+ if (cell != null) {
+ var rect = cell.element.getBoundingClientRect();
+ if ((x >= rect.left) && (x <= rect.right) &&
+ (y >= rect.top) && (y <= rect.bottom))
+ return cell;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ // public
+ Selection_setEmptySelectionAt = function(node,offset)
+ {
+ Selection_set(node,offset,node,offset);
+ }
+
+ // private
+ function deleteTextSelection(selRange,keepEmpty)
+ {
+ var nodes = Range_getOutermostNodes(selRange);
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+
+ var removeWholeNode = false;
+
+ if ((node == selRange.start.node) &&
+ (node == selRange.end.node)) {
+ var startOffset = selRange.start.offset;
+ var endOffset = selRange.end.offset;
+ if ((node.nodeType == Node.TEXT_NODE) &&
+ ((startOffset > 0) || (endOffset < node.nodeValue.length))) {
+ DOM_deleteCharacters(node,startOffset,endOffset);
+ }
+ else {
+ removeWholeNode = true;
+ }
+ }
+ else if (node == selRange.start.node) {
+ var offset = selRange.start.offset;
+ if ((node.nodeType == Node.TEXT_NODE) && (offset > 0)) {
+ DOM_deleteCharacters(node,offset);
+ }
+ else {
+ removeWholeNode = true;
+ }
+ }
+ else if (node == selRange.end.node) {
+ var offset = selRange.end.offset;
+ if ((node.nodeType == Node.TEXT_NODE) && (offset < node.nodeValue.length)) {
+ DOM_deleteCharacters(node,0,offset);
+ }
+ else {
+ removeWholeNode = true;
+ }
+ }
+ else {
+ removeWholeNode = true;
+ }
+
+ if (removeWholeNode) {
+ switch (node._type) {
+ case HTML_TD:
+ case HTML_TH:
+ DOM_deleteAllChildren(node);
+ break;
+ default:
+ DOM_deleteNode(node);
+ break;
+ }
+ }
+ }
+
+ var detail = Range_detail(selRange);
+
+ var sameTextNode = (selRange.start.node == selRange.end.node) &&
+ (selRange.start.node.nodeType == Node.TEXT_NODE);
+
+ if ((detail.startAncestor != null) && (detail.endAncestor != null) &&
+ (detail.startAncestor.nextSibling == detail.endAncestor) &&
+ !sameTextNode) {
+ prepareForMerge(detail);
+ DOM_mergeWithNextSibling(detail.startAncestor,
+ Formatting_MERGEABLE_BLOCK_AND_INLINE);
+ if (isParagraphNode(detail.startAncestor) &&
+ (detail.startAncestor._type != HTML_DIV))
+ removeParagraphDescendants(detail.startAncestor);
+ }
+
+ if (!keepEmpty) {
+ var startNode = selRange.start.node;
+ var endNode = selRange.end.node;
+ if (startNode.parentNode != null)
+ delEmpty(selRange,startNode);
+ if (endNode.parentNode != null)
+ delEmpty(selRange,endNode);
+ }
+
+ Cursor_updateBRAtEndOfParagraph(Range_singleNode(selRange));
+ }
+
+ function delEmpty(selRange,node)
+ {
+ while ((node != document.body) &&
+ (node.nodeType == Node.ELEMENT_NODE) &&
+ (node.firstChild == null)) {
+
+ if (isTableCell(node) || isTableCell(node.parentNode))
+ return;
+
+ if (!fixPositionOutside(selRange.start,node))
+ break;
+ if (!fixPositionOutside(selRange.end,node))
+ break;
+
+ var parent = node.parentNode;
+ Range_trackWhileExecuting(selRange,function() {
+ DOM_deleteNode(node);
+ });
+ node = parent;
+ }
+ }
+
+ function fixPositionOutside(pos,node)
+ {
+ if (pos.node == node) {
+ var before = new Position(node.parentNode,DOM_nodeOffset(node));
+ var after = new Position(node.parentNode,DOM_nodeOffset(node)+1);
+ before = Position_prevMatch(before,Position_okForMovement);
+ after = Position_nextMatch(after,Position_okForMovement);
+
+ if (before != null) {
+ pos.node = before.node;
+ pos.offset = before.offset;
+ }
+ else if (after != null) {
+ pos.node = after.node;
+ pos.offset = after.offset;
+ }
+ else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ Selection_deleteRangeContents = function(range,keepEmpty)
+ {
+ Range_trackWhileExecuting(range,function() {
+ DOM_ignoreMutationsWhileExecuting(function() {
+ removeSelectionHighlights(getRangeData(range),true);
+ });
+
+ var region = Tables_regionFromRange(range);
+ if (region != null)
+ Tables_deleteRegion(region);
+ else
+ deleteTextSelection(range,keepEmpty);
+ });
+
+ Selection_set(range.start.node,range.start.offset,range.start.node,range.start.offset);
+ }
+
+ Selection_deleteContents = function(keepEmpty)
+ {
+ var range = Selection_get();
+ if (range == null)
+ return;
+ Selection_deleteRangeContents(range,keepEmpty);
+ }
+
+ // private
+ function removeParagraphDescendants(parent)
+ {
+ var next;
+ for (var child = parent.firstChild; child != null; child = next) {
+ next = child.nextSibling;
+ removeParagraphDescendants(child);
+ if (isParagraphNode(child))
+ DOM_removeNodeButKeepChildren(child);
+ }
+ }
+
+ // private
+ function findFirstParagraph(node)
+ {
+ if (isParagraphNode(node))
+ return node;
+ if (node._type == HTML_LI) {
+ var nonWhitespaceInline = false;
+
+ for (var child = node.firstChild; child != null; child = child.nextSibling) {
+ if (isInlineNode(child) && !isWhitespaceTextNode(child))
+ nonWhitespaceInline = true;
+
+ if (isParagraphNode(child)) {
+ if (nonWhitespaceInline)
+ return putPrecedingSiblingsInParagraph(node,child);
+ return child;
+ }
+ else if (isListNode(child)) {
+ if (nonWhitespaceInline)
+ return putPrecedingSiblingsInParagraph(node,child);
+ return findFirstParagraph(child);
+ }
+ }
+ if (nonWhitespaceInline)
+ return putPrecedingSiblingsInParagraph(node,null);
+ }
+ return null;
+
+ function putPrecedingSiblingsInParagraph(parent,node)
+ {
+ var p = DOM_createElement(document,"P");
+ while (parent.firstChild != node)
+ DOM_appendChild(p,parent.firstChild);
+ return p;
+ }
+ }
+
+ // private
+ function prepareForMerge(detail)
+ {
+ if (isParagraphNode(detail.startAncestor) && isInlineNode(detail.endAncestor)) {
+ var name = detail.startAncestor.nodeName; // check-ok
+ var newParagraph = DOM_createElement(document,name);
+ DOM_insertBefore(detail.endAncestor.parentNode,newParagraph,detail.endAncestor);
+ DOM_appendChild(newParagraph,detail.endAncestor);
+ detail.endAncestor = newParagraph;
+ }
+ else if (isInlineNode(detail.startAncestor) && isParagraphNode(detail.endAncestor)) {
+ var name = detail.endAncestor.nodeName; // check-ok
+ var newParagraph = DOM_createElement(document,name);
+ DOM_insertBefore(detail.startAncestor.parentNode,newParagraph,
+ detail.startAncestor.nextSibling);
+ DOM_appendChild(newParagraph,detail.startAncestor);
+ detail.startAncestor = newParagraph;
+ }
+ else if (isParagraphNode(detail.startAncestor) &&
+ isListNode(detail.endAncestor) &&
+ (detail.endAncestor.firstChild._type == HTML_LI)) {
+ var list = detail.endAncestor;
+ var li = detail.endAncestor.firstChild;
+
+ var paragraph = findFirstParagraph(li);
+ if (paragraph != null) {
+ DOM_insertBefore(list.parentNode,paragraph,list);
+ var name = detail.startAncestor.nodeName; // check-ok
+ DOM_replaceElement(paragraph,name);
+ }
+ if (!nodeHasContent(li))
+ DOM_deleteNode(li);
+ if (firstChildElement(list) == null)
+ DOM_deleteNode(list);
+ }
+ else if (isParagraphNode(detail.endAncestor) &&
+ isListNode(detail.startAncestor) &&
+ (detail.startAncestor.lastChild._type == HTML_LI)) {
+ var list = detail.startAncestor;
+ var li = detail.startAncestor.lastChild;
+ var p = detail.endAncestor;
+ var oldLastChild = li.lastChild;
+ while (p.firstChild != null)
+ DOM_insertBefore(li,p.firstChild,null);
+ DOM_deleteNode(p);
+ if (oldLastChild != null) {
+ DOM_mergeWithNextSibling(oldLastChild,
+ Formatting_MERGEABLE_BLOCK_AND_INLINE);
+ }
+ }
+
+ if ((detail.startAncestor.lastChild != null) && (detail.endAncestor.firstChild != null)) {
+ var childDetail = new Object();
+ childDetail.startAncestor = detail.startAncestor.lastChild;
+ childDetail.endAncestor = detail.endAncestor.firstChild;
+ prepareForMerge(childDetail);
+ }
+ }
+
+ // public
+ Selection_clearSelection = function()
+ {
+ Selection_clear();
+ }
+
+ // public
+ Selection_preserveWhileExecuting = function(fun)
+ {
+ var range = Selection_get();
+
+ // Since the selection may have changed as a result of changes to the document, we
+ // have to call clear() or set() so that undo history is saved
+ if (range == null) {
+ result = fun();
+ Selection_clear();
+ }
+ else {
+ result = Range_trackWhileExecuting(range,fun);
+ Selection_set(range.start.node,range.start.offset,range.end.node,range.end.offset);
+ }
+ return result;
+ }
+
+ Selection_preferElementPositions = function()
+ {
+ var range = Selection_get();
+ if (range == null)
+ return;
+ range.start = Position_preferElementPosition(range.start);
+ range.end = Position_preferElementPosition(range.end);
+ Selection_set(range.start.node,range.start.offset,
+ range.end.node,range.end.offset);
+ }
+
+ function getBoundaryContainer(node,topAncestor)
+ {
+ var container = document.body;
+ for (; node != topAncestor.parentNode; node = node.parentNode) {
+ switch (node._type) {
+ case HTML_FIGURE:
+ case HTML_TABLE:
+ container = node;
+ break;
+ }
+ }
+ return container;
+ }
+
+ function boundaryCompliantRange(range)
+ {
+ if (range == null)
+ return null;
+
+ var detail = Range_detail(range);
+ var start = range.start;
+ var end = range.end;
+ var startNode = Position_closestActualNode(start);
+ var endNode = Position_closestActualNode(end);
+ var startContainer = getBoundaryContainer(startNode.parentNode,detail.commonAncestor);
+ var endContainer = getBoundaryContainer(endNode.parentNode,detail.commonAncestor);
+
+ if (startContainer != endContainer) {
+
+ var doStart = false;
+ var doEnd = false;
+
+ if (nodeHasAncestor(startContainer,endContainer)) {
+ doStart = true;
+ }
+ else if (nodeHasAncestor(endContainer,startContainer)) {
+ doEnd = true;
+ }
+ else {
+ doStart = true;
+ doEnd = true;
+ }
+
+ if (doStart && (startContainer != document.body))
+ start = new Position(startContainer.parentNode,DOM_nodeOffset(startContainer));
+ if (doEnd && (endContainer != document.body))
+ end = new Position(endContainer.parentNode,DOM_nodeOffset(endContainer)+1);
+ }
+ return new Range(start.node,start.offset,end.node,end.offset);
+
+ function nodeHasAncestor(node,ancestor)
+ {
+ for (; node != null; node = node.parentNode) {
+ if (node == ancestor)
+ return true;
+ }
+ return false;
+ }
+ }
+
+ Selection_print = function()
+ {
+ debug("");
+ debug("");
+ debug("");
+ debug("================================================================================");
+
+ var sel = Selection_get();
+ if (sel == null) {
+ debug("No selection");
+ return;
+ }
+
+ printSelectionElement(document.body,"");
+
+ function printSelectionElement(node,indent)
+ {
+ var className = DOM_getAttribute(node,"class");
+ if (className != null)
+ debug(indent+node.nodeName+" ("+className+")");
+ else
+ debug(indent+node.nodeName);
+
+ var child = node.firstChild;
+ var offset = 0;
+ while (true) {
+
+ var isStart = ((sel.start.node == node) && (sel.start.offset == offset));
+ var isEnd = ((sel.end.node == node) && (sel.end.offset == offset));
+ if (isStart && isEnd)
+ debug(indent+" []");
+ else if (isStart)
+ debug(indent+" [");
+ else if (isEnd)
+ debug(indent+" ]");
+
+ if (child == null)
+ break;
+
+ if (child.nodeType == Node.ELEMENT_NODE)
+ printSelectionElement(child,indent+" ");
+ else
+ printSelectionText(child,indent+" ");
+
+ child = child.nextSibling;
+ offset++;
+ }
+ }
+
+ function printSelectionText(node,indent)
+ {
+ var value = node.nodeValue;
+
+ if (sel.end.node == node) {
+ var afterSelection = value.substring(sel.end.offset);
+ value = value.substring(0,sel.end.offset) + "]" + afterSelection;
+ }
+
+ if (sel.start.node == node) {
+ var beforeSelection = value.substring(0,sel.start.offset);
+ value = beforeSelection + "[" + value.substring(sel.start.offset);
+ }
+
+ debug(indent+JSON.stringify(value));
+ }
+ }
+
+})();
http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9bf02bb2/experiments/editorFramework/src/Javascript_Layer_0/StringBuilder.js
----------------------------------------------------------------------
diff --git a/experiments/editorFramework/src/Javascript_Layer_0/StringBuilder.js b/experiments/editorFramework/src/Javascript_Layer_0/StringBuilder.js
new file mode 100644
index 0000000..9332b79
--- /dev/null
+++ b/experiments/editorFramework/src/Javascript_Layer_0/StringBuilder.js
@@ -0,0 +1,21 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 StringBuilder()
+{
+ this.str = "";
+}
http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9bf02bb2/experiments/editorFramework/src/Javascript_Layer_0/Styles.js
----------------------------------------------------------------------
diff --git a/experiments/editorFramework/src/Javascript_Layer_0/Styles.js b/experiments/editorFramework/src/Javascript_Layer_0/Styles.js
new file mode 100644
index 0000000..c09f41d
--- /dev/null
+++ b/experiments/editorFramework/src/Javascript_Layer_0/Styles.js
@@ -0,0 +1,179 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 Styles_getRule;
+var Styles_nextSelectorAfter;
+var Styles_getParagraphClass;
+var Styles_setParagraphClass;
+var Styles_headingNumbering;
+var Styles_getCSSText;
+var Styles_setCSSText;
+var Styles_getBuiltinCSSURL;
+var Styles_init;
+
+(function() {
+
+ var rules = new Object();
+ var paragraphClass = null;
+
+ Styles_getRule = function(selector)
+ {
+ return rules[selector];
+ }
+
+ Styles_nextSelectorAfter = function(element)
+ {
+ var selector = element.nodeName.toLowerCase();
+ var className = DOM_getAttribute(element,"class");
+ if (className != null)
+ selector = selector+"."+className;
+
+ var nextElementName = null;
+ var nextClassName = null;
+
+ var rule = Styles_getRule(selector);
+ if (rule != null) {
+ var nextSelector = rule["-uxwrite-next"];
+ if (nextSelector != null) {
+ try {
+ nextSelector = JSON.parse(nextSelector);
+ if (typeof(nextSelector) != "string")
+ nextSelector = null;
+ }
+ catch (e) {
+ nextSelector = null;
+ }
+ }
+ if (nextSelector != null) {
+ var dotIndex = nextSelector.indexOf(".");
+ if (dotIndex >= 0) {
+ nextElementName = nextSelector.substring(0,dotIndex);
+ nextClassName = nextSelector.substring(dotIndex+1);
+ }
+ else {
+ nextElementName = nextSelector;
+ }
+ }
+ }
+
+ if ((nextElementName == null) ||
+ (ElementTypes[nextElementName] == null) ||
+ (!PARAGRAPH_ELEMENTS[ElementTypes[nextElementName]])) {
+ nextElementName = null;
+ nextClassName = null;
+ }
+
+ if (isHeadingNode(element)) {
+ nextElementName = "p";
+ nextClassName = Styles_getParagraphClass();
+ }
+
+ if (nextElementName == null)
+ return null;
+ else if (nextClassName == null)
+ return nextElementName;
+ else
+ return nextElementName+"."+nextClassName;
+ }
+
+ Styles_getParagraphClass = function()
+ {
+ return paragraphClass;
+ }
+
+ Styles_setParagraphClass = function(cls)
+ {
+ paragraphClass = cls;
+ }
+
+ Styles_headingNumbering = function()
+ {
+ return ((rules["h1::before"] != null) &&
+ (rules["h1::before"]["content"] != null));
+ }
+
+ Styles_getCSSText = function()
+ {
+ var head = DOM_documentHead(document);
+ var cssText = "";
+ for (var child = head.firstChild; child != null; child = child.nextSibling) {
+ if (child._type == HTML_STYLE) {
+ for (var t = child.firstChild; t != null; t = t.nextSibling) {
+ if (t._type == HTML_TEXT)
+ cssText += t.nodeValue;
+ }
+ }
+ }
+ return cssText;
+ }
+
+ Styles_setCSSText = function(cssText,cssRules)
+ {
+ UndoManager_newGroup("Update styles");
+ var head = DOM_documentHead(document);
+ var next;
+ for (var child = head.firstChild; child != null; child = next) {
+ next = child.nextSibling;
+ if (child._type == HTML_STYLE)
+ DOM_deleteNode(child);
+ }
+ var style = DOM_createElement(document,"STYLE");
+ DOM_appendChild(style,DOM_createTextNode(document,cssText));
+ DOM_appendChild(head,style);
+ rules = cssRules; // FIXME: undo support? (must coordinate with ObjC code)
+ Outline_scheduleUpdateStructure();
+ return {}; // Objective C caller expects JSON result
+ }
+
+ function addBuiltinStylesheet(cssURL)
+ {
+ var head = DOM_documentHead(document);
+ for (var child = head.firstChild; child != null; child = child.nextSibling) {
+ if ((child._type == HTML_LINK) &&
+ (child.getAttribute("rel") == "stylesheet") &&
+ (child.getAttribute("href") == cssURL)) {
+ // Link element was already added by HTMLInjectionProtocol
+ return;
+ }
+ }
+
+ // HTMLInjectionProtocol was unable to find <head> element and insert the stylesheet link,
+ // so add it ourselves
+ var link = DOM_createElement(document,"LINK");
+ DOM_setAttribute(link,"rel","stylesheet");
+ DOM_setAttribute(link,"href",cssURL);
+ DOM_insertBefore(head,link,head.firstChild);
+ }
+
+ var builtinCSSURL = null;
+
+ Styles_getBuiltinCSSURL = function()
+ {
+ return builtinCSSURL;
+ }
+
+ // public
+ Styles_init = function(cssURL)
+ {
+ if (cssURL != null)
+ builtinCSSURL = cssURL;
+
+ if (builtinCSSURL != null)
+ addBuiltinStylesheet(builtinCSSURL);
+ }
+
+})();