blob: f123423e78aa88894ca10f0097aaf27a1b50d182 [file] [log] [blame]
// 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 Main_getLanguage;
var Main_setLanguage;
var Main_setGenerator;
var Main_isEmptyDocument;
var Main_prepareForSave;
var Main_getHTML;
var Main_getErrorReportingInfo;
var Main_removeUnsupportedInput;
var Main_removeSpecial;
var Main_execute;
var Main_init;
var Main_clientRectsBug;
(function() {
// public
Main_getLanguage = function()
{
var lang = document.documentElement.getAttribute("lang");
if (lang != null)
lang = lang.replace(/-/g,"_");
return lang;
}
// public
Main_setLanguage = function(lang)
{
if ((lang == null) || (lang == "")) {
DOM_removeAttribute(document.documentElement,"lang");
}
else {
lang = lang.replace(/_/g,"-");
DOM_setAttribute(document.documentElement,"lang",lang);
}
}
// public
Main_removeUnsupportedInput = function()
{
recurse(document.documentElement);
function recurse(node)
{
// Delete comments and processing instructions
if ((node.nodeType != Node.TEXT_NODE) &&
(node.nodeType != Node.ELEMENT_NODE)) {
DOM_deleteNode(node);
}
else {
var next;
for (var child = node.firstChild; child != null; child = next) {
next = child.nextSibling;
recurse(child);
}
}
}
}
// private
function addMetaCharset()
{
var head = DOM_documentHead(document);
var next;
for (var child = head.firstChild; child != null; child = next) {
next = child.nextSibling;
if ((child._type == HTML_META) && (child.hasAttribute("charset"))) {
DOM_deleteNode(child);
}
else if ((child._type == HTML_META) && child.hasAttribute("http-equiv") &&
(child.getAttribute("http-equiv").toLowerCase() == "content-type")) {
DOM_deleteNode(child);
}
}
var meta = DOM_createElement(document,"META");
DOM_setAttribute(meta,"charset","utf-8");
DOM_insertBefore(head,meta,head.firstChild);
}
// public
Main_setGenerator = function(generator)
{
return UndoManager_disableWhileExecuting(function() {
var head = DOM_documentHead(document);
for (var child = head.firstChild; child != null; child = child.nextSibling) {
if ((child._type == HTML_META) &&
child.hasAttribute("name") &&
(child.getAttribute("name").toLowerCase() == "generator")) {
var origGenerator = DOM_getAttribute(child,"content");
DOM_setAttribute(child,"content",generator);
if (origGenerator == null)
return "";
else
return origGenerator;
}
}
var meta = DOM_createElement(document,"META");
DOM_setAttribute(meta,"name","generator");
DOM_setAttribute(meta,"content",generator);
DOM_insertBefore(head,meta,head.firstChild);
return "";
});
}
// public
Main_isEmptyDocument = function()
{
return !nodeHasContent(document.body);
}
// public
Main_prepareForSave = function()
{
// Force any end-of-group actions to be performed
UndoManager_newGroup();
return true;
}
// public
Main_getHTML = function()
{
return document.documentElement.outerHTML;
}
// public
Main_getErrorReportingInfo = function()
{
if (document.documentElement == null)
return "(document.documentElement is null)";
try {
var html = htmlWithSelection();
cleanse(html);
return html.outerHTML;
}
catch (e) {
try {
var html = DOM_cloneNode(document.documentElement,true);
cleanse(html);
return html.outerHTML+"\n[Error getting selection: "+e+"]";
}
catch (e2) {
return "[Error getting HTML: "+e2+"]";
}
}
function cleanse(node)
{
switch (node._type) {
case HTML_TEXT:
case HTML_COMMENT:
DOM_setNodeValue(node,cleanseString(node.nodeValue));
break;
case HTML_STYLE:
case HTML_SCRIPT:
return;
default:
if (node.nodeType == Node.ELEMENT_NODE) {
cleanseAttribute(node,"original");
if (node.hasAttribute("href") && !node.getAttribute("href").match(/^#/))
cleanseAttribute(node,"href");
for (var child = node.firstChild; child != null; child = child.nextSibling)
cleanse(child);
}
break;
}
}
function cleanseAttribute(node,name)
{
if (node.hasAttribute(name)) {
var value = node.getAttribute(name);
value = cleanseString(value);
DOM_setAttribute(node,name,value);
}
}
function cleanseString(str)
{
return str.replace(/[^\s\.\@\^]/g,"X");
}
function htmlWithSelection()
{
var selectionRange = Selection_get();
if (selectionRange != null) {
selectionRange = Range_forwards(selectionRange);
var startSave = new Object();
var endSave = new Object();
var html = null;
Range_trackWhileExecuting(selectionRange,function() {
// We use the strings @@^^ and ^^@@ to represent the selection
// start and end, respectively. The reason for this is that after we have
// cloned the tree, all text will be removed. We keeping the @ and ^
// characters so we have some way to identifiy the selection markers;
// leaving these in is not going to reveal any confidential information.
addPositionMarker(selectionRange.end,"^^@@",endSave);
addPositionMarker(selectionRange.start,"@@^^",startSave);
html = DOM_cloneNode(document.documentElement,true);
removePositionMarker(selectionRange.start,startSave);
removePositionMarker(selectionRange.end,endSave);
});
return html;
}
else {
return DOM_cloneNode(document.documentElement,true);
}
}
function addPositionMarker(pos,name,save)
{
var node = pos.node;
var offset = pos.offset;
if (node.nodeType == Node.ELEMENT_NODE) {
save.tempNode = DOM_createTextNode(document,name);
DOM_insertBefore(node,save.tempNode,node.childNodes[offset]);
}
else if (node.nodeType == Node.TEXT_NODE) {
save.originalNodeValue = node.nodeValue;
node.nodeValue = node.nodeValue.slice(0,offset) + name + node.nodeValue.slice(offset);
}
}
function removePositionMarker(pos,save)
{
var node = pos.node;
var offset = pos.offset;
if (pos.node.nodeType == Node.ELEMENT_NODE) {
DOM_deleteNode(save.tempNode);
}
else if (pos.node.nodeType == Node.TEXT_NODE) {
node.nodeValue = save.originalNodeValue;
}
}
}
// public
Main_removeSpecial = function(node)
{
// We process the children first, so that if there are any nested removable elements (e.g.
// a selection span inside of an autocorrect span), all levels of nesting are taken care of
var next;
for (var child = node.firstChild; child != null; child = next) {
next = child.nextSibling;
Main_removeSpecial(child);
}
var cssClass = null;
if ((node.nodeType == Node.ELEMENT_NODE) && node.hasAttribute("class"))
cssClass = node.getAttribute("class");
if ((cssClass == Keys.HEADING_NUMBER) ||
(cssClass == Keys.FIGURE_NUMBER) ||
(cssClass == Keys.TABLE_NUMBER) ||
(cssClass == Keys.AUTOCORRECT_CLASS) ||
(cssClass == Keys.SELECTION_CLASS) ||
(cssClass == Keys.SELECTION_HIGHLIGHT)) {
DOM_removeNodeButKeepChildren(node);
}
else if ((node._type == HTML_META) &&
node.hasAttribute("name") &&
(node.getAttribute("name").toLowerCase() == "viewport")) {
DOM_deleteNode(node);
}
else if (node._type == HTML_LINK) {
if ((node.getAttribute("rel") == "stylesheet") &&
(node.getAttribute("href") == Styles_getBuiltinCSSURL())) {
DOM_deleteNode(node);
}
}
}
function simplifyStackString(e)
{
if (e.stack == null)
return "";
var lines = e.stack.toString().split(/\n/);
for (var i = 0; i < lines.length; i++) {
var nameMatch = lines[i].match(/^(.*)@/);
var name = (nameMatch != null) ? nameMatch[1] : "(anonymous function)";
var locMatch = lines[i].match(/:([0-9]+:[0-9]+)$/);
var loc = (locMatch != null) ? locMatch[1] : "?";
lines[i] = "stack["+(lines.length-i-1)+"] = "+name+"@"+loc;
}
return lines.join("\n");
}
// public
Main_execute = function(fun)
{
try {
var res = fun();
PostponedActions_perform();
return res;
}
catch (e) {
var message = (e.message != null) ? e.message : e.toString();
var stack = simplifyStackString(e);
Editor_error(message+"\n"+stack);
}
}
function fixEmptyBody()
{
for (var child = document.body.firstChild; child != null; child = child.nextSibling) {
if (nodeHasContent(child))
return;
}
for (var child = document.body.firstChild; child != null; child = child.nextSibling) {
if (child._type == HTML_P) {
Cursor_updateBRAtEndOfParagraph(child);
return;
}
}
var p = DOM_createElement(document,"P");
var br = DOM_createElement(document,"BR");
DOM_appendChild(p,br);
DOM_appendChild(document.body,p);
}
// public
Main_init = function(width,textScale,cssURL,clientRectsBug)
{
try {
Main_clientRectsBug = clientRectsBug;
if (document.documentElement == null)
throw new Error("document.documentElement is null");
if (document.body == null)
throw new Error("document.body is null");
var timing = new TimingInfo();
timing.start();
DOM_assignNodeIds(document);
timing.addEntry("DOM_assignNodeIds");
Main_removeUnsupportedInput();
timing.addEntry("Main_removeUnsupportedInput");
addMetaCharset();
timing.addEntry("addMetaCharset");
fixEmptyBody();
timing.addEntry("fixEmptyBody");
Outline_init();
timing.addEntry("Outline_init");
Styles_init(cssURL);
timing.addEntry("Styles_init");
Viewport_init(width,textScale);
timing.addEntry("Viewport_init");
AutoCorrect_init();
timing.addEntry("AutoCorrect_init");
PostponedActions_perform();
timing.addEntry("PostponedActions_perform");
Cursor_moveToStartOfDocument();
timing.addEntry("Cursor_moveToStartOfDocument");
UndoManager_clear();
timing.addEntry("UndoManager_clear");
// timing.print();
return true;
}
catch (e) {
return e.toString();
}
}
})();