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/16 12:58:21 UTC

[46/51] [partial] incubator-corinthia git commit: Added editorFramework in experiments.

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/26f461e7/experiments/Editor/src/Outline.js
----------------------------------------------------------------------
diff --git a/experiments/Editor/src/Outline.js b/experiments/Editor/src/Outline.js
deleted file mode 100644
index 9812041..0000000
--- a/experiments/Editor/src/Outline.js
+++ /dev/null
@@ -1,1434 +0,0 @@
-// 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: The TOC/ItemList stuff won't work with Undo, because we're making DOM mutations in
-// response to other DOM mutations, so at undo time the changes will be made twice
-
-var Outline_init;
-var Outline_removeListeners;
-var Outline_moveSection;
-var Outline_deleteItem;
-var Outline_goToItem;
-var Outline_setTitle;
-var Outline_setNumbered;
-var Outline_getItemElement;
-var Outline_getOutline;
-var Outline_plainText;
-var Outline_insertTableOfContents;
-var Outline_insertListOfFigures;
-var Outline_insertListOfTables;
-var Outline_setPrintMode;
-var Outline_examinePrintLayout;
-var Outline_setReferenceTarget;
-var Outline_detectSectionNumbering;
-var Outline_findUsedStyles;
-var Outline_scheduleUpdateStructure;
-
-(function() {
-
-    var itemsByNode = null;
-    var refsById = null;
-    var nextItemId = 1;
-    var outlineDirty = false;
-    var ignoreModifications = 0;
-    var sectionNumberRegex = /^\s*(Chapter\s+)?\d+(\.\d+)*\.?\s+/i;
-    var figureNumberRegex = /^\s*Figure\s+\d+(\.\d+)*:?\s*/i;
-    var tableNumberRegex = /^\s*Table\s+\d+(\.\d+)*:?\s*/i;
-    var sections = null;
-    var figures = null;
-    var tables = null;
-    var doneInit = false;
-    var printMode = false;
-
-    function Category(type,nodeFilter,numberRegex)
-    {
-        this.type = type;
-        this.nodeFilter = nodeFilter;
-        this.numberRegex = numberRegex;
-        this.list = new DoublyLinkedList();
-        this.tocs = new NodeMap();
-    }
-
-    function addItemInternal(category,item,prevItem,title)
-    {
-        UndoManager_addAction(removeItemInternal,category,item);
-        category.list.insertAfter(item,prevItem);
-        item.title = title;
-        category.tocs.forEach(function(node,toc) { TOC_addOutlineItem(toc,item.id); });
-        Editor_addOutlineItem(item.id,category.type,title);
-    }
-
-    function removeItemInternal(category,item)
-    {
-        UndoManager_addAction(addItemInternal,category,item,item.prev,item.title);
-        category.list.remove(item);
-        category.tocs.forEach(function(node,toc) { TOC_removeOutlineItem(toc,item.id); });
-        item.title = null;
-        Editor_removeOutlineItem(item.id);
-    }
-
-    function Category_add(category,node)
-    {
-        var item = itemsByNode.get(node);
-        if (item == null)
-            item = new OutlineItem(category,node);
-
-        var prevItem = findPrevItemOfType(node,category.nodeFilter);
-        addItemInternal(category,item,prevItem,null);
-
-        // Register for notifications to changes to this item's node content. We may need to
-        // update the title when such a modification occurs.
-        node.addEventListener("DOMSubtreeModified",item.modificationListener);
-
-        OutlineItem_updateItemTitle(item);
-        scheduleUpdateStructure();
-        return item;
-
-        function findPrevItemOfType(node,typeFun)
-        {
-            do node = prevNode(node);
-            while ((node != null) && !typeFun(node));
-            return (node == null) ? null : itemsByNode.get(node);
-        }
-    }
-
-    function findFirstTextDescendant(node)
-    {
-        if (isWhitespaceTextNode(node))
-            return;
-        if (node.nodeType == Node.TEXT_NODE)
-            return node;
-        for (var child = node.firstChild; child != null; child = child.nextSibling) {
-            var result = findFirstTextDescendant(child);
-            if (result != null)
-                return result;
-        }
-        return null;
-    }
-
-    function Category_remove(category,node)
-    {
-        var item = itemsByNode.get(node);
-        if (item == null) {
-            throw new Error("Attempt to remove non-existant "+node.nodeName+
-                            " item "+node.getAttribute("id"));
-        }
-        removeItemInternal(category,item);
-        item.node.removeEventListener("DOMSubtreeModified",item.modificationListener);
-        var titleNode = OutlineItem_getTitleNode(item,false);
-        if ((titleNode != null) &&
-            ((item.type == "figure") || (item.type == "table")) &&
-            (titleNode.firstChild == null) &&
-            (titleNode.lastChild == null)) {
-            DOM_deleteNode(titleNode);
-        }
-        scheduleUpdateStructure();
-    }
-
-    function addTOCInternal(category,node,toc)
-    {
-        UndoManager_addAction(removeTOCInternal,category,node);
-        category.tocs.put(node,toc);
-    }
-
-    function removeTOCInternal(category,node)
-    {
-        var toc = category.tocs.get(node);
-        if (toc == null)
-            throw new Error("Attempt to remove ItemList that doesn't exist");
-
-        UndoManager_addAction(addTOCInternal,category,node,toc);
-
-        category.tocs.remove(node);
-    }
-
-    function Category_addTOC(category,node)
-    {
-        var toc = new TOC(node);
-        addTOCInternal(category,node,toc);
-
-        for (var item = category.list.first; item != null; item = item.next) {
-            TOC_addOutlineItem(toc,item.id);
-            TOC_updateOutlineItem(toc,item.id,item.title);
-        }
-
-        scheduleUpdateStructure();
-    }
-
-    function Category_removeTOC(category,node)
-    {
-        removeTOCInternal(category,node);
-    }
-
-    function TOC(node)
-    {
-        this.node = node;
-        this.textNodes = new Object();
-    }
-
-    function TOC_addOutlineItem(toc,id)
-    {
-        toc.textNodes[id] = DOM_createTextNode(document,"");
-    }
-
-    function TOC_removeOutlineItem(toc,id)
-    {
-        delete toc.textNodes[id];
-    }
-
-    function TOC_updateOutlineItem(toc,id,title)
-    {
-        DOM_setNodeValue(toc.textNodes[id],title);
-    }
-
-    function TOC_updateStructure(toc,structure,toplevelShadows,pageNumbers)
-    {
-        Hierarchy_ensureValidHierarchy(toc.node);
-        DOM_deleteAllChildren(toc.node);
-
-        var cls = toc.node.getAttribute("class");
-
-        if (toplevelShadows.length == 0) {
-            createEmptyTOC(toc.node);
-        }
-        else {
-            recurse(toplevelShadows,toc.node,1);
-        }
-
-        if (printMode) {
-            var brk = DOM_createElement(document,"DIV");
-            DOM_setStyleProperties(brk,{ "clear": "both" });
-            DOM_appendChild(toc.node,brk);
-        }
-
-        function createEmptyTOC(parent)
-        {
-            if (!printMode) {
-                var str = "";
-
-                if (cls == Keys.SECTION_TOC)
-                    str = "[No sections defined]";
-                else if (cls == Keys.FIGURE_TOC)
-                    str = "[No figures defined]";
-                else if (cls == Keys.TABLE_TOC)
-                    str = "[No tables defined]";
-
-                var text = DOM_createTextNode(document,str);
-
-                var div = DOM_createElement(document,"P");
-                DOM_setAttribute(div,"class","toc1");
-                DOM_appendChild(div,text);
-                DOM_appendChild(parent,div);
-            }
-        }
-
-        function recurse(shadows,parent,level)
-        {
-            if (level > 3)
-                return;
-
-            for (var i = 0; i < shadows.length; i++) {
-                var shadow = shadows[i];
-                var item = shadow.item;
-
-                if (printMode) {
-                    var div = DOM_createElement(document,"P");
-                    DOM_setAttribute(div,"class","toc"+level+"-print");
-                    DOM_appendChild(parent,div);
-
-                    var leftSpan = DOM_createElement(document,"SPAN");
-                    DOM_setAttribute(leftSpan,"class","toctitle");
-
-                    var rightSpan = DOM_createElement(document,"SPAN");
-                    DOM_setAttribute(rightSpan,"class","tocpageno");
-
-                    DOM_appendChild(div,leftSpan);
-                    DOM_appendChild(div,rightSpan);
-
-                    if (item.computedNumber != null) {
-                        var text = DOM_createTextNode(document,item.computedNumber+" ");
-                        DOM_appendChild(leftSpan,text);
-                    }
-
-                    DOM_appendChild(leftSpan,toc.textNodes[item.id]);
-                    var pageNo = pageNumbers ? pageNumbers.get(item.node) : null;
-                    if (pageNo == null)
-                        DOM_appendChild(rightSpan,DOM_createTextNode(document,"XXXX"));
-                    else
-                        DOM_appendChild(rightSpan,DOM_createTextNode(document,pageNo));
-                }
-                else {
-                    var div = DOM_createElement(document,"P");
-                    DOM_setAttribute(div,"class","toc"+level);
-                    DOM_appendChild(parent,div);
-
-                    var a = DOM_createElement(document,"A");
-                    DOM_setAttribute(a,"href","#"+item.id);
-                    DOM_appendChild(div,a);
-
-                    if (item.computedNumber != null)
-                        DOM_appendChild(a,DOM_createTextNode(document,item.computedNumber+" "));
-                    DOM_appendChild(a,toc.textNodes[item.id]);
-                }
-
-                recurse(shadow.children,parent,level+1);
-            }
-        }
-    }
-
-    function OutlineItem(category,node)
-    {
-        var type = category.type;
-        var item = this;
-        if ((node != null) && (node.hasAttribute("id"))) {
-            this.id = node.getAttribute("id");
-        }
-        else {
-            this.id = generateItemId();
-            if (node != null)
-                DOM_setAttribute(node,"id",this.id);
-        }
-        this.category = category;
-        this.type = type;
-        this.node = node;
-        this.title = null;
-        this.computedNumber = null;
-
-        this.spareSpan = DOM_createElement(document,"SPAN");
-        DOM_appendChild(this.spareSpan,DOM_createTextNode(document,""));
-        var spanClass = null;
-        if (this.type == "section")
-            spanClass = Keys.HEADING_NUMBER;
-        else if (this.type == "figure")
-            spanClass = Keys.FIGURE_NUMBER;
-        else if (this.type == "table")
-            spanClass = Keys.TABLE_NUMBER;
-        DOM_setAttribute(this.spareSpan,"class",spanClass);
-
-        // titleNode
-        if (this.type == "figure") {
-            this.spareTitle = DOM_createElement(document,"FIGCAPTION");
-        }
-        else if (this.type == "table") {
-            this.spareTitle = DOM_createElement(document,"CAPTION");
-        }
-
-        this.prev = null;
-        this.next = null;
-        this.modificationListener = function(event) { itemModified(item); }
-
-        itemsByNode.put(this.node,this);
-
-        Object.seal(this);
-        return;
-
-        function generateItemId()
-        {
-            var id;
-            do {
-                id = "item"+(nextItemId++);
-            } while (document.getElementById(id) != null);
-            return id;
-        }
-    }
-
-    function OutlineItem_getTitleNode(item,create)
-    {
-        if (item.type == "section") {
-            return item.node;
-        }
-        else if (item.type == "figure") {
-            var titleNode = findChild(item.node,HTML_FIGCAPTION);
-            if ((titleNode == null) && create) {
-                titleNode = item.spareTitle;
-                DOM_appendChild(item.node,titleNode);
-            }
-            return titleNode;
-        }
-        else if (item.type == "table") {
-            var titleNode = findChild(item.node,HTML_CAPTION);
-            if ((titleNode == null) && create) {
-                titleNode = item.spareTitle;
-                DOM_insertBefore(item.node,titleNode,item.node.firstChild);
-            }
-            return titleNode;
-        }
-
-        function findChild(node,type)
-        {
-            for (var child = node.firstChild; child != null; child = child.nextSibling) {
-                if (child._type == type)
-                    return child;
-            }
-            return null;
-        }
-    }
-
-    function OutlineItem_updateItemTitle(item)
-    {
-        var titleNode = OutlineItem_getTitleNode(item,false);
-        if (titleNode != null)
-            newTitle = normalizeWhitespace(getNodeText(titleNode));
-        else
-            newTitle = "";
-
-        if (item.title != newTitle) {
-            UndoManager_addAction(Editor_updateOutlineItem,item.id,item.title);
-            Editor_updateOutlineItem(item.id,newTitle);
-            item.title = newTitle;
-            item.category.tocs.forEach(function(node,toc) {
-                TOC_updateOutlineItem(toc,item.id,item.title);
-            });
-        }
-    }
-
-    function getNodeTextAfter(node)
-    {
-        var text = "";
-        for (var child = node.nextSibling; child != null; child = child.nextSibling)
-            text += getNodeText(child);
-        return text;
-    }
-
-    // private
-    function itemModified(item)
-    {
-        if (UndoManager_isActive())
-            return;
-        if (ignoreModifications > 0)
-            return;
-        OutlineItem_updateItemTitle(item);
-        updateRefsForItem(item);
-    }
-
-    function addRefForId(id,node)
-    {
-        UndoManager_addAction(removeRefForId,id,node);
-        if (refsById[id] == null)
-            refsById[id] = new Array();
-        refsById[id].push(node);
-    }
-
-    function removeRefForId(id,node)
-    {
-        UndoManager_addAction(addRefForId,id,node);
-        if (refsById[id] == null)
-            throw new Error("refRemoved: refsById["+id+"] is null");
-        var index = refsById[id].indexOf(node);
-        if (index < 0)
-            throw new Error("refRemoved: refsById["+id+"] does not contain node");
-        refsById[id].splice(index,1);
-        if (refsById[id] == null)
-            delete refsById[id];
-    }
-
-    // private
-    function refInserted(node)
-    {
-        var href = node.getAttribute("href");
-        if (href.charAt(0) != "#")
-            throw new Error("refInserted: not a # reference");
-        var id = href.substring(1);
-        addRefForId(id,node);
-        scheduleUpdateStructure();
-    }
-
-    // private
-    function refRemoved(node)
-    {
-        var href = node.getAttribute("href");
-        if (href.charAt(0) != "#")
-            throw new Error("refInserted: not a # reference");
-        var id = href.substring(1);
-        removeRefForId(id,node);
-    }
-
-    // private
-    function acceptNode(node)
-    {
-        for (var p = node; p != null; p = p.parentNode) {
-            if ((p._type == HTML_SPAN) && (p.getAttribute("class") == Keys.HEADING_NUMBER))
-                return false;
-        }
-        return true;
-    }
-
-    // private
-    function docNodeInserted(event)
-    {
-        if (UndoManager_isActive())
-            return;
-        if (DOM_getIgnoreMutations())
-            return;
-        try {
-            if (!acceptNode(event.target))
-                return;
-            recurse(event.target);
-        }
-        catch (e) {
-            Editor_error(e);
-        }
-
-        function recurse(node)
-        {
-            switch (node._type) {
-            case HTML_H1:
-            case HTML_H2:
-            case HTML_H3:
-            case HTML_H4:
-            case HTML_H5:
-            case HTML_H6: {
-                if (!isInTOC(node))
-                    Category_add(sections,node);
-                break;
-            }
-            case HTML_FIGURE:
-                Category_add(figures,node);
-                break;
-            case HTML_TABLE:
-                Category_add(tables,node);
-                break;
-            case HTML_A: {
-                if (isRefNode(node) && !isInTOC(node)) {
-                    refInserted(node);
-                }
-                break;
-            }
-            case HTML_NAV: {
-                var cls = node.getAttribute("class");
-                if (cls == Keys.SECTION_TOC)
-                    Category_addTOC(sections,node);
-                else if (cls == Keys.FIGURE_TOC)
-                    Category_addTOC(figures,node);
-                else if (cls == Keys.TABLE_TOC)
-                    Category_addTOC(tables,node);
-                break;
-            }
-            }
-
-            var next;
-            for (var child = node.firstChild; child != null; child = next) {
-                next = child.nextSibling;
-                recurse(child);
-            }
-        }
-    }
-
-    // private
-    function docNodeRemoved(event)
-    {
-        if (UndoManager_isActive())
-            return;
-        if (DOM_getIgnoreMutations())
-            return;
-        try {
-            if (!acceptNode(event.target))
-                return;
-            recurse(event.target);
-        }
-        catch (e) {
-            Editor_error(e);
-        }
-
-        function recurse(node)
-        {
-            switch (node._type) {
-            case HTML_H1:
-            case HTML_H2:
-            case HTML_H3:
-            case HTML_H4:
-            case HTML_H5:
-            case HTML_H6:
-                if (!isInTOC(node))
-                    Category_remove(sections,node);
-                break;
-            case HTML_FIGURE:
-                Category_remove(figures,node);
-                break;
-            case HTML_TABLE:
-                Category_remove(tables,node);
-                break;
-            case HTML_A:
-                if (isRefNode(node) && !isInTOC(node))
-                    refRemoved(node);
-                break;
-            case HTML_NAV:
-                var cls = node.getAttribute("class");
-                if (cls == Keys.SECTION_TOC)
-                    Category_removeTOC(sections,node);
-                else if (cls == Keys.FIGURE_TOC)
-                    Category_removeTOC(figures,node);
-                else if (cls == Keys.TABLE_TOC)
-                    Category_removeTOC(tables,node);
-                break;
-            }
-
-            for (var child = node.firstChild; child != null; child = child.nextSibling)
-                recurse(child);
-        }
-    }
-
-    // private
-    function scheduleUpdateStructure()
-    {
-        if (UndoManager_isActive())
-            return;
-        if (!outlineDirty) {
-            outlineDirty = true;
-            PostponedActions_add(updateStructure);
-        }
-    }
-
-    Outline_scheduleUpdateStructure = scheduleUpdateStructure;
-
-    // private
-    function updateStructure()
-    {
-        if (!outlineDirty)
-            return;
-        outlineDirty = false;
-        if (UndoManager_isActive())
-            throw new Error("Structure update event while undo or redo active");
-        Selection_preserveWhileExecuting(function() {
-            updateStructureReal();
-        });
-    }
-
-    function Shadow(node)
-    {
-        this.node = node;
-        this.item = itemsByNode.get(node);
-        this.children = [];
-        this.parent = null;
-
-        switch (node._type) {
-        case HTML_H1:
-            this.level = 1;
-            break;
-        case HTML_H2:
-            this.level = 2;
-            break;
-        case HTML_H3:
-            this.level = 3;
-            break;
-        case HTML_H4:
-            this.level = 4;
-            break;
-        case HTML_H5:
-            this.level = 5;
-            break;
-        case HTML_H6:
-            this.level = 6;
-            break;
-        default:
-            this.level = 0;
-            break;
-        }
-    }
-
-    function Shadow_last(shadow)
-    {
-        if (shadow.children.length == 0)
-            return shadow;
-        else
-            return Shadow_last(shadow.children[shadow.children.length-1]);
-    }
-
-    function Shadow_outerNext(shadow,structure)
-    {
-        var last = Shadow_last(shadow);
-        if (last == null)
-            return null;
-        else if (last.item.next == null)
-            return null;
-        else
-            return structure.shadowsByNode.get(last.item.next.node);
-    }
-
-    function firstTextDescendant(node)
-    {
-        if (node.nodeType == Node.TEXT_NODE)
-            return node;
-        for (var child = node.firstChild; child != null; child = child.nextSibling) {
-            var result = firstTextDescendant(child);
-            if (result != null)
-                return result;
-        }
-        return null;
-    }
-
-    function Structure()
-    {
-        this.toplevelSections = new Array();
-        this.toplevelFigures = new Array();
-        this.toplevelTables = new Array();
-        this.shadowsByNode = new NodeMap();
-    }
-
-    function discoverStructure()
-    {
-        var structure = new Structure();
-        var nextToplevelSectionNumber = 1;
-        var nextFigureNumber = 1;
-        var nextTableNumber = 1;
-        var headingNumbering = Styles_headingNumbering();
-
-        var counters = { h1: 0, h2: 0, h3: 0, h4: 0, h5: 0, h6: 0, table: 0, figure: 0 };
-
-        var current = null;
-
-        for (var section = sections.list.first; section != null; section = section.next) {
-            structure.shadowsByNode.put(section.node,new Shadow(section.node));
-        }
-        for (var figure = figures.list.first; figure != null; figure = figure.next) {
-            structure.shadowsByNode.put(figure.node,new Shadow(figure.node));
-        }
-        for (var table = tables.list.first; table != null; table = table.next) {
-            structure.shadowsByNode.put(table.node,new Shadow(table.node));
-        }
-
-        for (var section = sections.list.first; section != null; section = section.next) {
-            var shadow = structure.shadowsByNode.get(section.node);
-            shadow.parent = null;
-            shadow.children = [];
-            shadow.nextChildSectionNumber = 1;
-        }
-
-        ignoreModifications++;
-
-        for (var section = sections.list.first; section != null; section = section.next) {
-            var shadow = structure.shadowsByNode.get(section.node);
-            var node = section.node;
-            var item = shadow.item;
-
-            if (!headingNumbering || (DOM_getAttribute(item.node,"class") == "Unnumbered")) {
-                item.computedNumber = null;
-            }
-            else {
-                var level = parseInt(node.nodeName.charAt(1));
-                counters[node.nodeName.toLowerCase()]++;
-                for (var inner = level+1; inner <= 6; inner++)
-                    counters["h"+inner] = 0;
-                item.computedNumber = "";
-                for (var i = 1; i <= level; i++) {
-                    if (i == 1)
-                        item.computedNumber += counters["h"+i];
-                    else
-                        item.computedNumber += "." + counters["h"+i];
-                }
-            }
-
-            while ((current != null) && (shadow.level < current.level+1))
-                current = current.parent;
-
-            shadow.parent = current;
-            if (current == null)
-                structure.toplevelSections.push(shadow);
-            else
-                current.children.push(shadow);
-
-            current = shadow;
-        }
-
-        for (var figure = figures.list.first; figure != null; figure = figure.next) {
-            var shadow = structure.shadowsByNode.get(figure.node);
-            var item = shadow.item;
-
-            var titleNode = OutlineItem_getTitleNode(item,false);
-            if ((titleNode == null) || DOM_getAttribute(titleNode,"class") == "Unnumbered") {
-                item.computedNumber = null;
-            }
-            else {
-                counters.figure++;
-                item.computedNumber = ""+counters.figure;
-            }
-
-            structure.toplevelFigures.push(shadow);
-        }
-
-        for (var table = tables.list.first; table != null; table = table.next) {
-            var shadow = structure.shadowsByNode.get(table.node);
-            var item = shadow.item;
-
-            var titleNode = OutlineItem_getTitleNode(item,false);
-            if ((titleNode == null) || DOM_getAttribute(titleNode,"class") == "Unnumbered") {
-                item.computedNumber = null;
-            }
-            else {
-                counters.table++;
-                item.computedNumber = ""+counters.table;
-            }
-
-            structure.toplevelTables.push(shadow);
-        }
-
-        ignoreModifications--;
-
-        return structure;
-    }
-
-    function updateStructureReal(pageNumbers)
-    {
-        var structure = discoverStructure();
-
-        for (var section = sections.list.first; section != null; section = section.next) {
-            var shadow = structure.shadowsByNode.get(section.node);
-            updateRefsForItem(shadow.item);
-        }
-
-        for (var figure = figures.list.first; figure != null; figure = figure.next) {
-            var shadow = structure.shadowsByNode.get(figure.node);
-            updateRefsForItem(shadow.item);
-        }
-
-        for (var table = tables.list.first; table != null; table = table.next) {
-            var shadow = structure.shadowsByNode.get(table.node);
-            updateRefsForItem(shadow.item);
-        }
-
-        sections.tocs.forEach(function (node,toc) {
-            TOC_updateStructure(toc,structure,structure.toplevelSections,pageNumbers);
-        });
-        figures.tocs.forEach(function (node,toc) {
-            TOC_updateStructure(toc,structure,structure.toplevelFigures,pageNumbers);
-        });
-        tables.tocs.forEach(function (node,toc) {
-            TOC_updateStructure(toc,structure,structure.toplevelTables,pageNumbers);
-        });
-
-        Editor_outlineUpdated();
-    }
-
-    Outline_getOutline = function()
-    {
-        var structure = discoverStructure();
-        var encSections = new Array();
-        var encFigures = new Array();
-        var encTables = new Array();
-
-        for (var i = 0; i < structure.toplevelSections.length; i++)
-            encodeShadow(structure.toplevelSections[i],encSections);
-        for (var i = 0; i < structure.toplevelFigures.length; i++)
-            encodeShadow(structure.toplevelFigures[i],encFigures);
-        for (var i = 0; i < structure.toplevelTables.length; i++)
-            encodeShadow(structure.toplevelTables[i],encTables);
-
-        return { sections: encSections,
-                 figures: encFigures,
-                 tables: encTables };
-
-        function encodeShadow(shadow,result)
-        {
-            var encChildren = new Array();
-            for (var i = 0; i < shadow.children.length; i++)
-                encodeShadow(shadow.children[i],encChildren);
-
-            var obj = { id: shadow.item.id,
-                        number: shadow.item.computedNumber ? shadow.item.computedNumber : "",
-                        children: encChildren };
-            result.push(obj);
-        }
-    }
-
-    function updateRefsForItem(item)
-    {
-        var id = item.node.getAttribute("id");
-        var refs = refsById[id];
-        if (refs == null)
-            return;
-        for (var i = 0; i < refs.length; i++) {
-            DOM_deleteAllChildren(refs[i]);
-            var text = null;
-
-            var className = DOM_getAttribute(refs[i],"class");
-            if (className == "uxwrite-ref-num") {
-                text = item.computedNumber;
-            }
-            else if (className == "uxwrite-ref-text") {
-                if (item.type == "section") {
-                    if (item.numberSpan != null)
-                        text = getNodeTextAfter(item.numberSpan);
-                    else
-                        text = normalizeWhitespace(getNodeText(item.node));
-                }
-                else if ((item.type == "figure") || (item.type == "table")) {
-                    var titleNode = OutlineItem_getTitleNode(item,false);
-                    if (titleNode != null) {
-                        text = getNodeText(titleNode);
-
-                        if ((item.computedNumber != null) && (item.type == "figure"))
-                            text = "Figure "+item.computedNumber+": "+text;
-                        else if ((item.computedNumber != null) && (item.type == "table"))
-                            text = "Table "+item.computedNumber+": "+text;
-                    }
-                }
-            }
-            else if (className == "uxwrite-ref-caption-text") {
-                if (item.type == "section") {
-                    if (item.numberSpan != null)
-                        text = getNodeTextAfter(item.numberSpan);
-                    else
-                        text = normalizeWhitespace(getNodeText(item.node));
-                }
-                else if ((item.type == "figure") || (item.type == "table")) {
-                    var titleNode = OutlineItem_getTitleNode(item,false);
-                    if (titleNode != null) {
-                        if (item.numberSpan != null)
-                            text = getNodeTextAfter(item.numberSpan);
-                        else
-                            text = normalizeWhitespace(getNodeText(titleNode));
-                    }
-                }
-            }
-            else if (className == "uxwrite-ref-label-num") {
-                if (item.computedNumber != null) {
-                    if (item.type == "section")
-                        text = "Section "+item.computedNumber;
-                    else if (item.type == "figure")
-                        text = "Figure "+item.computedNumber;
-                    else if (item.type == "table")
-                        text = "Table "+item.computedNumber;
-                }
-            }
-            else {
-                if (item.computedNumber != null)
-                    text = item.computedNumber;
-                else
-                    text = item.title;
-            }
-
-            if (text == null)
-                text = "?";
-
-            DOM_appendChild(refs[i],DOM_createTextNode(document,text));
-        }
-    }
-
-    Outline_plainText = function()
-    {
-        var strings = new Array();
-        var structure = discoverStructure();
-
-        strings.push("Sections:\n");
-        for (var section = sections.list.first; section != null; section = section.next) {
-            var shadow = structure.shadowsByNode.get(section.node);
-            if (shadow.level == 1)
-                printSectionRecursive(shadow,"    ");
-        }
-        strings.push("Figures:\n");
-        for (var figure = figures.list.first; figure != null; figure = figure.next) {
-            var shadow = structure.shadowsByNode.get(figure.node);
-            var titleNode = OutlineItem_getTitleNode(figure,false);
-            var title = titleNode ? getNodeText(titleNode) : "[no caption]";
-            if (shadow.item.computedNumber != null) {
-                if (title.length > 0)
-                    title = shadow.item.computedNumber+" "+title;
-                else
-                    title = shadow.item.computedNumber;
-            }
-            strings.push("    "+title+" ("+figure.id+")\n");
-        }
-        strings.push("Tables:\n");
-        for (var table = tables.list.first; table != null; table = table.next) {
-            var shadow = structure.shadowsByNode.get(table.node);
-            var titleNode = OutlineItem_getTitleNode(table,false);
-            var title = titleNode ? getNodeText(titleNode) : "[no caption]";
-            if (shadow.item.computedNumber != null) {
-                if (title.length > 0)
-                    title = shadow.item.computedNumber+" "+title;
-                else
-                    title = shadow.item.computedNumber;
-            }
-            strings.push("    "+title+" ("+table.id+")\n");
-        }
-        return strings.join("");
-
-        function printSectionRecursive(shadow,indent)
-        {
-            var titleNode = OutlineItem_getTitleNode(shadow.item,false);
-            var content = getNodeText(titleNode);
-            if (shadow.item.computedNumber != null)
-                content = shadow.item.computedNumber+" "+content;
-            if (isWhitespaceString(content))
-                content = "[empty]";
-            strings.push(indent+content+" ("+shadow.item.id+")\n");
-            for (var i = 0; i < shadow.children.length; i++)
-                printSectionRecursive(shadow.children[i],indent+"    ");
-        }
-    }
-
-    // public
-    Outline_init = function()
-    {
-        Selection_preserveWhileExecuting(function() {
-
-            function isTableNode(node)
-            {
-                return (node._type == HTML_TABLE);
-            }
-
-            function isFigureNode(node)
-            {
-                return (node._type == HTML_FIGURE);
-            }
-
-            function isNonTOCHeadingNode(node)
-            {
-                return (HEADING_ELEMENTS[node._type] && !isInTOC(node));
-            }
-
-            sections = new Category("section",isNonTOCHeadingNode,sectionNumberRegex);
-            figures = new Category("figure",isFigureNode,figureNumberRegex);
-            tables = new Category("table",isTableNode,tableNumberRegex);
-            itemsByNode = new NodeMap();
-            refsById = new Object();
-
-            DOM_ensureUniqueIds(document.documentElement);
-            document.addEventListener("DOMNodeInserted",docNodeInserted);
-            document.addEventListener("DOMNodeRemoved",docNodeRemoved);
-
-            docNodeInserted({target:document});
-        });
-        doneInit = true;
-    }
-
-    // public (for the undo tests, when they report results)
-    Outline_removeListeners = function()
-    {
-        document.removeEventListener("DOMNodeInserted",docNodeInserted);
-        document.removeEventListener("DOMNodeRemoved",docNodeRemoved);
-
-        removeCategoryListeners(sections);
-        removeCategoryListeners(figures);
-        removeCategoryListeners(tables);
-
-        function removeCategoryListeners(category)
-        {
-            for (var item = category.list.first; item != null; item = item.next)
-                item.node.removeEventListener("DOMSubtreeModified",item.modificationListener);
-        }
-    }
-
-    // private
-    function getShadowNodes(structure,shadow,result)
-    {
-        var endShadow = Shadow_outerNext(shadow,structure);
-        var endNode = endShadow ? endShadow.item.node : null;
-        for (var n = shadow.item.node; (n != null) && (n != endNode); n = n.nextSibling)
-            result.push(n);
-    }
-
-    // public
-    Outline_moveSection = function(sectionId,parentId,nextId)
-    {
-        UndoManager_newGroup("Move section");
-        Selection_clear();
-
-        updateStructure(); // make sure pointers are valid
-        // FIXME: I don't think we'll need the updateStructure() call now that we have
-        // discoverStructure(). In fact this function is a perfect illustration of why
-        // waiting till after the postponed action has been performed before relying on the
-        // pointer validity was a problem.
-
-
-        var structure = discoverStructure();
-
-        var node = document.getElementById(sectionId);
-        var section = itemsByNode.get(node);
-        var shadow = structure.shadowsByNode.get(node);
-
-        // FIXME: We should throw an exception if a parentId or nextId which does not exist
-        // in the document is specified. However there are currently some tests (like
-        // moveSection-nested*) which rely us interpreting such parameters as null.
-        var parentNode = parentId ? document.getElementById(parentId) : null;
-        var nextNode = nextId ? document.getElementById(nextId) : null;
-        var parent = parentNode ? structure.shadowsByNode.get(parentNode) : null;
-        var next = nextNode ? structure.shadowsByNode.get(nextNode) : null;
-
-        var sectionNodes = new Array();
-        getShadowNodes(structure,shadow,sectionNodes);
-
-        if ((next == null) && (parent != null))
-            next = Shadow_outerNext(parent,structure);
-
-        if (next == null) {
-            for (var i = 0; i < sectionNodes.length; i++)
-                DOM_appendChild(document.body,sectionNodes[i]);
-        }
-        else {
-            for (var i = 0; i < sectionNodes.length; i++)
-                DOM_insertBefore(next.item.node.parentNode,sectionNodes[i],next.item.node);
-        }
-
-        var pos = new Position(node,0,node,0);
-        pos = Position_closestMatchForwards(pos,Position_okForInsertion);
-        Selection_set(pos.node,pos.offset,pos.node,pos.offset);
-
-        scheduleUpdateStructure();
-        PostponedActions_add(UndoManager_newGroup);
-    }
-
-    // public
-    Outline_deleteItem = function(itemId)
-    {
-        UndoManager_newGroup("Delete outline item");
-        var structure = discoverStructure();
-        Selection_preserveWhileExecuting(function() {
-            var node = document.getElementById(itemId);
-            var item = itemsByNode.get(node);
-            var shadow = structure.shadowsByNode.get(item.node);
-            if (item.type == "section") {
-                var sectionNodes = new Array();
-                getShadowNodes(structure,shadow,sectionNodes);
-                for (var i = 0; i < sectionNodes.length; i++)
-                    DOM_deleteNode(sectionNodes[i]);
-            }
-            else {
-                DOM_deleteNode(item.node);
-            }
-        });
-
-        // Ensure the cursor or selection start/end positions are valid positions that the
-        // user is allowed to move to. This ensures we get an accurate rect for each position,
-        // avoiding an ugly effect where the cursor occupies the entire height of the document
-        // and is displayed on the far-left edge of the editing area.
-        var selRange = Selection_get();
-        if (selRange != null) {
-            var start = Position_closestMatchForwards(selRange.start,Position_okForMovement);
-            var end = Position_closestMatchForwards(selRange.end,Position_okForMovement);
-            Selection_set(start.node,start.offset,end.node,end.offset);
-        }
-
-        scheduleUpdateStructure();
-        PostponedActions_add(Cursor_ensureCursorVisible);
-        PostponedActions_add(UndoManager_newGroup);
-    }
-
-    // public
-    Outline_goToItem = function(itemId)
-    {
-        if (itemId == null) {
-            window.scrollTo(0);
-        }
-        else {
-            var node = document.getElementById(itemId);
-            if (node == null) {
-                // FIXME: this can happen if the user added some headings, pressed undo one or
-                // more times (in which case the editor's view of the outline structure fails to
-                // be updated), and then they click on an item. This is really an error but we
-                // handle it gracefully for now rather than causing a null pointer exception to
-                // be thrown.
-                return;
-            }
-            var position = new Position(node,0);
-            position = Position_closestMatchForwards(position,Position_okForMovement);
-            Selection_set(position.node,position.offset,position.node,position.offset);
-
-            var section = document.getElementById(itemId);
-            var location = webkitConvertPointFromNodeToPage(section,new WebKitPoint(0,0));
-            window.scrollTo(0,location.y);
-        }
-    }
-
-    // public
-    Outline_getItemElement = function(itemId)
-    {
-        return document.getElementById(itemId);
-    }
-
-    // public
-    Outline_setNumbered = function(itemId,numbered)
-    {
-        var node = document.getElementById(itemId);
-        var item = itemsByNode.get(node);
-
-        Selection_preserveWhileExecuting(function() {
-            if (item.type == "section") {
-                if (numbered)
-                    DOM_removeAttribute(node,"class");
-                else
-                    DOM_setAttribute(node,"class","Unnumbered");
-            }
-            else if ((item.type == "figure") || (item.type == "table")) {
-                if (numbered) {
-                    var caption = OutlineItem_getTitleNode(item,true);
-                    DOM_removeAttribute(caption,"class");
-                }
-                else {
-                    var caption = OutlineItem_getTitleNode(item,false);
-                    if (caption != null) {
-                        if (nodeHasContent(caption))
-                            DOM_setAttribute(caption,"class","Unnumbered");
-                        else
-                            DOM_deleteNode(caption);
-                    }
-                }
-            }
-        });
-
-        scheduleUpdateStructure();
-    }
-
-    // public
-    Outline_setTitle = function(itemId,title)
-    {
-        var node = document.getElementById(itemId);
-        var item = itemsByNode.get(node);
-        Selection_preserveWhileExecuting(function() {
-            var titleNode = OutlineItem_getTitleNode(item,true);
-            var oldEmpty = (item.title == "");
-            var newEmpty = (title == "");
-            if (oldEmpty != newEmpty) {
-                // Add or remove the : at the end of table and figure numbers
-                scheduleUpdateStructure();
-            }
-            if (item.numberSpan != null) {
-                while (item.numberSpan.nextSibling != null)
-                    DOM_deleteNode(item.numberSpan.nextSibling);
-            }
-            else {
-                DOM_deleteAllChildren(titleNode);
-            }
-            DOM_appendChild(titleNode,DOM_createTextNode(document,title));
-            OutlineItem_updateItemTitle(item);
-        });
-    }
-
-    // private
-    // FIXME: prevent a TOC from being inserted inside a heading, figure, or table
-    function insertTOC(key,initialText)
-    {
-        var div = DOM_createElement(document,"NAV");
-        DOM_setAttribute(div,"class",key);
-        Cursor_makeContainerInsertionPoint();
-        Clipboard_pasteNodes([div]);
-    }
-
-    // public
-    Outline_insertTableOfContents = function()
-    {
-        insertTOC(Keys.SECTION_TOC);
-    }
-
-    // public
-    Outline_insertListOfFigures = function()
-    {
-        insertTOC(Keys.FIGURE_TOC);
-    }
-
-    // public
-    Outline_insertListOfTables = function()
-    {
-        insertTOC(Keys.TABLE_TOC);
-    }
-
-    // public
-    Outline_setPrintMode = function(newPrintMode)
-    {
-        printMode = newPrintMode;
-        scheduleUpdateStructure();
-    }
-
-    // public
-    Outline_examinePrintLayout = function(pageHeight)
-    {
-        var result = new Object();
-        var structure = discoverStructure();
-        var pageNumbers = new NodeMap();
-
-        result.destsByPage = new Object();
-        result.linksByPage = new Object();
-        result.leafRectsByPage = new Object();
-
-        itemsByNode.forEach(function(node,item) {
-            var rect = node.getBoundingClientRect();
-            var pageNo = 1+Math.floor(rect.top/pageHeight);
-            var pageTop = (pageNo-1)*pageHeight;
-            var id = node.getAttribute("id");
-            pageNumbers.put(node,pageNo);
-
-            if (result.destsByPage[pageNo] == null)
-                result.destsByPage[pageNo] = new Array();
-            result.destsByPage[pageNo].push({ itemId: id,
-                                              x: rect.left,
-                                              y: rect.top - pageTop});
-        });
-
-        var links = document.getElementsByTagName("A");
-        for (var i = 0; i < links.length; i++) {
-            var a = links[i];
-
-            if (!a.hasAttribute("href"))
-                continue;
-
-            var offset = DOM_nodeOffset(a);
-            var range = new Range(a.parentNode,offset,a.parentNode,offset+1);
-            var rects = Range_getClientRects(range);
-            for (var rectIndex = 0; rectIndex < rects.length; rectIndex++) {
-                var rect = rects[rectIndex];
-                var pageNo = 1+Math.floor(rect.top/pageHeight);
-                var pageTop = (pageNo-1)*pageHeight;
-
-                if (result.linksByPage[pageNo] == null)
-                    result.linksByPage[pageNo] = new Array();
-                result.linksByPage[pageNo].push({ pageNo: pageNo,
-                                                  left: rect.left,
-                                                  top: rect.top - pageTop,
-                                                  width: rect.width,
-                                                  height: rect.height,
-                                                  href: a.getAttribute("href"), });
-            }
-        }
-
-        recurse(document.body);
-
-        updateStructureReal(pageNumbers);
-        return result;
-
-
-        function recurse(node)
-        {
-            if (node.firstChild == null) {
-                var offset = DOM_nodeOffset(node);
-                var range = new Range(node.parentNode,offset,node.parentNode,offset+1);
-                var rects = Range_getClientRects(range);
-                for (var i = 0; i < rects.length; i++) {
-                    var rect = rects[i];
-
-                    var pageNo = 1+Math.floor(rect.top/pageHeight);
-                    var pageTop = (pageNo-1)*pageHeight;
-
-                    if (result.leafRectsByPage[pageNo] == null)
-                        result.leafRectsByPage[pageNo] = new Array();
-                    result.leafRectsByPage[pageNo].push({ left: rect.left,
-                                                          top: rect.top - pageTop,
-                                                          width: rect.width,
-                                                          height: rect.height });
-                }
-            }
-
-            for (var child = node.firstChild; child != null; child = child.nextSibling)
-                recurse(child);
-        }
-    }
-
-    Outline_setReferenceTarget = function(node,itemId)
-    {
-        Selection_preserveWhileExecuting(function() {
-            refRemoved(node);
-            DOM_setAttribute(node,"href","#"+itemId);
-            refInserted(node);
-        });
-    }
-
-    Outline_detectSectionNumbering = function()
-    {
-        var sectionNumbering = detectNumbering(sections);
-        if (sectionNumbering)
-            makeNumberingExplicit(sections);
-        makeNumberingExplicit(figures);
-        makeNumberingExplicit(tables);
-        return sectionNumbering;
-    }
-
-    function detectNumbering(category)
-    {
-        for (var item = category.list.first; item != null; item = item.next) {
-
-            var firstText = null;
-            var titleNode = OutlineItem_getTitleNode(item);
-
-            if (titleNode != null)
-                firstText = findFirstTextDescendant(titleNode);
-            if (firstText != null) {
-                var regex = category.numberRegex;
-                var str = firstText.nodeValue;
-                if (str.match(category.numberRegex))
-                    return true;
-            }
-        }
-    }
-
-    function makeNumberingExplicit(category)
-    {
-        for (var item = category.list.first; item != null; item = item.next) {
-            var firstText = null;
-            var titleNode = OutlineItem_getTitleNode(item);
-
-            if (titleNode != null)
-                firstText = findFirstTextDescendant(titleNode);
-            if (firstText != null) {
-                var regex = category.numberRegex;
-                var str = firstText.nodeValue;
-                if (str.match(category.numberRegex)) {
-                    var oldValue = str;
-                    var newValue = str.replace(category.numberRegex,"");
-                    DOM_setNodeValue(firstText,newValue);
-                }
-                else {
-                    var titleNode = OutlineItem_getTitleNode(item,true);
-                    if (titleNode != null)
-                        DOM_setAttribute(titleNode,"class","Unnumbered");
-                }
-            }
-        }
-    }
-
-    // Search through the document for any elements corresponding to built-in styles that are
-    // normally latent (i.e. only included in the stylesheet if used)
-    Outline_findUsedStyles = function()
-    {
-        var used = new Object();
-        recurse(document.body);
-        return used;
-
-        function recurse(node)
-        {
-            switch (node._type) {
-            case HTML_NAV: {
-                var className = DOM_getAttribute(node,"class");
-                if ((className == "tableofcontents") ||
-                    (className == "listoffigures") ||
-                    (className == "listoftables")) {
-                    used["nav."+className] = true;
-                }
-                break;
-            }
-            case HTML_FIGCAPTION:
-            case HTML_CAPTION:
-            case HTML_H1:
-            case HTML_H2:
-            case HTML_H3:
-            case HTML_H4:
-            case HTML_H5:
-            case HTML_H6: {
-                var elementName = node.nodeName.toLowerCase();
-                var className = DOM_getAttribute(node,"class");
-                if ((className == null) || (className == ""))
-                    used[elementName] = true;
-                else if (className == "Unnumbered")
-                    used[elementName+".Unnumbered"] = true;
-                break;
-            }
-            }
-
-            for (var child = node.firstChild; child != null; child = child.nextSibling)
-                recurse(child);
-        }
-    }
-
-})();