18754 lines
		
	
	
		
			771 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			18754 lines
		
	
	
		
			771 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
| 
 | |
|  This is a generated file. DO NOT EDIT.
 | |
| 
 | |
|  Copyright (C) 2010-2015 KO GmbH <copyright@kogmbh.com>
 | |
| 
 | |
|  @licstart
 | |
|  This file is the compiled version of the WebODF library.
 | |
| 
 | |
|  WebODF is free software: you can redistribute it and/or modify it
 | |
|  under the terms of the GNU Affero General Public License (GNU AGPL)
 | |
|  as published by the Free Software Foundation, either version 3 of
 | |
|  the License, or (at your option) any later version.
 | |
| 
 | |
|  WebODF is distributed in the hope that it will be useful, but
 | |
|  WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  GNU Affero General Public License for more details.
 | |
| 
 | |
|  You should have received a copy of the GNU Affero General Public License
 | |
|  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  @licend
 | |
| 
 | |
|  @source: http://www.webodf.org/
 | |
|  @source: https://github.com/kogmbh/WebODF/
 | |
| */
 | |
| var webodf_version = "0.5.7-66-g25bf592";
 | |
| function Runtime() {
 | |
| }
 | |
| Runtime.prototype.getVariable = function(name) {
 | |
| };
 | |
| Runtime.prototype.toJson = function(anything) {
 | |
| };
 | |
| Runtime.prototype.fromJson = function(jsonstr) {
 | |
| };
 | |
| Runtime.prototype.byteArrayFromString = function(string, encoding) {
 | |
| };
 | |
| Runtime.prototype.byteArrayToString = function(bytearray, encoding) {
 | |
| };
 | |
| Runtime.prototype.read = function(path, offset, length, callback) {
 | |
| };
 | |
| Runtime.prototype.readFile = function(path, encoding, callback) {
 | |
| };
 | |
| Runtime.prototype.readFileSync = function(path, encoding) {
 | |
| };
 | |
| Runtime.prototype.loadXML = function(path, callback) {
 | |
| };
 | |
| Runtime.prototype.writeFile = function(path, data, callback) {
 | |
| };
 | |
| Runtime.prototype.deleteFile = function(path, callback) {
 | |
| };
 | |
| Runtime.prototype.log = function(msgOrCategory, msg) {
 | |
| };
 | |
| Runtime.prototype.setTimeout = function(callback, milliseconds) {
 | |
| };
 | |
| Runtime.prototype.clearTimeout = function(timeoutID) {
 | |
| };
 | |
| Runtime.prototype.libraryPaths = function() {
 | |
| };
 | |
| Runtime.prototype.currentDirectory = function() {
 | |
| };
 | |
| Runtime.prototype.setCurrentDirectory = function(dir) {
 | |
| };
 | |
| Runtime.prototype.type = function() {
 | |
| };
 | |
| Runtime.prototype.getDOMImplementation = function() {
 | |
| };
 | |
| Runtime.prototype.parseXML = function(xml) {
 | |
| };
 | |
| Runtime.prototype.exit = function(exitCode) {
 | |
| };
 | |
| Runtime.prototype.getWindow = function() {
 | |
| };
 | |
| Runtime.prototype.requestAnimationFrame = function(callback) {
 | |
| };
 | |
| Runtime.prototype.cancelAnimationFrame = function(requestId) {
 | |
| };
 | |
| Runtime.prototype.assert = function(condition, message) {
 | |
| };
 | |
| var IS_COMPILED_CODE = true;
 | |
| Runtime.byteArrayToString = function(bytearray, encoding) {
 | |
|   function byteArrayToString(bytearray) {
 | |
|     var s = "", i, l = bytearray.length;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       s += String.fromCharCode(bytearray[i] & 255);
 | |
|     }
 | |
|     return s;
 | |
|   }
 | |
|   function utf8ByteArrayToString(bytearray) {
 | |
|     var s = "", startPos, i, l = bytearray.length, chars = [], c0, c1, c2, c3, codepoint;
 | |
|     if (l >= 3 && bytearray[0] === 239 && bytearray[1] === 187 && bytearray[2] === 191) {
 | |
|       startPos = 3;
 | |
|     } else {
 | |
|       startPos = 0;
 | |
|     }
 | |
|     for (i = startPos;i < l;i += 1) {
 | |
|       c0 = (bytearray[i]);
 | |
|       if (c0 < 128) {
 | |
|         chars.push(c0);
 | |
|       } else {
 | |
|         i += 1;
 | |
|         c1 = (bytearray[i]);
 | |
|         if (c0 >= 194 && c0 < 224) {
 | |
|           chars.push((c0 & 31) << 6 | c1 & 63);
 | |
|         } else {
 | |
|           i += 1;
 | |
|           c2 = (bytearray[i]);
 | |
|           if (c0 >= 224 && c0 < 240) {
 | |
|             chars.push((c0 & 15) << 12 | (c1 & 63) << 6 | c2 & 63);
 | |
|           } else {
 | |
|             i += 1;
 | |
|             c3 = (bytearray[i]);
 | |
|             if (c0 >= 240 && c0 < 245) {
 | |
|               codepoint = (c0 & 7) << 18 | (c1 & 63) << 12 | (c2 & 63) << 6 | c3 & 63;
 | |
|               codepoint -= 65536;
 | |
|               chars.push((codepoint >> 10) + 55296, (codepoint & 1023) + 56320);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (chars.length >= 1E3) {
 | |
|         s += String.fromCharCode.apply(null, chars);
 | |
|         chars.length = 0;
 | |
|       }
 | |
|     }
 | |
|     return s + String.fromCharCode.apply(null, chars);
 | |
|   }
 | |
|   var result;
 | |
|   if (encoding === "utf8") {
 | |
|     result = utf8ByteArrayToString(bytearray);
 | |
|   } else {
 | |
|     if (encoding !== "binary") {
 | |
|       this.log("Unsupported encoding: " + encoding);
 | |
|     }
 | |
|     result = byteArrayToString(bytearray);
 | |
|   }
 | |
|   return result;
 | |
| };
 | |
| Runtime.getVariable = function(name) {
 | |
|   try {
 | |
|     return eval(name);
 | |
|   } catch (e) {
 | |
|     return undefined;
 | |
|   }
 | |
| };
 | |
| Runtime.toJson = function(anything) {
 | |
|   return JSON.stringify(anything);
 | |
| };
 | |
| Runtime.fromJson = function(jsonstr) {
 | |
|   return JSON.parse(jsonstr);
 | |
| };
 | |
| Runtime.getFunctionName = function getFunctionName(f) {
 | |
|   var m;
 | |
|   if (f.name === undefined) {
 | |
|     m = (new RegExp("function\\s+(\\w+)")).exec(f);
 | |
|     return m && m[1];
 | |
|   }
 | |
|   return f.name;
 | |
| };
 | |
| Runtime.assert = function(condition, message) {
 | |
|   if (!condition) {
 | |
|     this.log("alert", "ASSERTION FAILED:\n" + message);
 | |
|     throw new Error(message);
 | |
|   }
 | |
| };
 | |
| function BrowserRuntime() {
 | |
|   var self = this;
 | |
|   function getUtf8LengthForString(string) {
 | |
|     var l = string.length, i, n, j = 0;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       n = string.charCodeAt(i);
 | |
|       j += 1 + (n > 128) + (n > 2048);
 | |
|       if (n > 55040 && n < 57344) {
 | |
|         j += 1;
 | |
|         i += 1;
 | |
|       }
 | |
|     }
 | |
|     return j;
 | |
|   }
 | |
|   function utf8ByteArrayFromString(string, length, addBOM) {
 | |
|     var l = string.length, bytearray, i, n, j;
 | |
|     bytearray = new Uint8Array(new ArrayBuffer(length));
 | |
|     if (addBOM) {
 | |
|       bytearray[0] = 239;
 | |
|       bytearray[1] = 187;
 | |
|       bytearray[2] = 191;
 | |
|       j = 3;
 | |
|     } else {
 | |
|       j = 0;
 | |
|     }
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       n = string.charCodeAt(i);
 | |
|       if (n < 128) {
 | |
|         bytearray[j] = n;
 | |
|         j += 1;
 | |
|       } else {
 | |
|         if (n < 2048) {
 | |
|           bytearray[j] = 192 | n >>> 6;
 | |
|           bytearray[j + 1] = 128 | n & 63;
 | |
|           j += 2;
 | |
|         } else {
 | |
|           if (n <= 55040 || n >= 57344) {
 | |
|             bytearray[j] = 224 | n >>> 12 & 15;
 | |
|             bytearray[j + 1] = 128 | n >>> 6 & 63;
 | |
|             bytearray[j + 2] = 128 | n & 63;
 | |
|             j += 3;
 | |
|           } else {
 | |
|             i += 1;
 | |
|             n = (n - 55296 << 10 | string.charCodeAt(i) - 56320) + 65536;
 | |
|             bytearray[j] = 240 | n >>> 18 & 7;
 | |
|             bytearray[j + 1] = 128 | n >>> 12 & 63;
 | |
|             bytearray[j + 2] = 128 | n >>> 6 & 63;
 | |
|             bytearray[j + 3] = 128 | n & 63;
 | |
|             j += 4;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return bytearray;
 | |
|   }
 | |
|   function utf8ByteArrayFromXHRString(string, wishLength) {
 | |
|     var addBOM = false, length = getUtf8LengthForString(string);
 | |
|     if (typeof wishLength === "number") {
 | |
|       if (wishLength !== length && wishLength !== length + 3) {
 | |
|         return undefined;
 | |
|       }
 | |
|       addBOM = length + 3 === wishLength;
 | |
|       length = wishLength;
 | |
|     }
 | |
|     return utf8ByteArrayFromString(string, length, addBOM);
 | |
|   }
 | |
|   function byteArrayFromString(string) {
 | |
|     var l = string.length, a = new Uint8Array(new ArrayBuffer(l)), i;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       a[i] = string.charCodeAt(i) & 255;
 | |
|     }
 | |
|     return a;
 | |
|   }
 | |
|   this.byteArrayFromString = function(string, encoding) {
 | |
|     var result;
 | |
|     if (encoding === "utf8") {
 | |
|       result = utf8ByteArrayFromString(string, getUtf8LengthForString(string), false);
 | |
|     } else {
 | |
|       if (encoding !== "binary") {
 | |
|         self.log("unknown encoding: " + encoding);
 | |
|       }
 | |
|       result = byteArrayFromString(string);
 | |
|     }
 | |
|     return result;
 | |
|   };
 | |
|   this.byteArrayToString = Runtime.byteArrayToString;
 | |
|   this.getVariable = Runtime.getVariable;
 | |
|   this.fromJson = Runtime.fromJson;
 | |
|   this.toJson = Runtime.toJson;
 | |
|   function log(msgOrCategory, msg) {
 | |
|     var category;
 | |
|     if (msg !== undefined) {
 | |
|       category = msgOrCategory;
 | |
|     } else {
 | |
|       msg = msgOrCategory;
 | |
|     }
 | |
|     console.log(msg);
 | |
|     if (self.enableAlerts && category === "alert") {
 | |
|       alert(msg);
 | |
|     }
 | |
|   }
 | |
|   function arrayToUint8Array(buffer) {
 | |
|     var l = buffer.length, i, a = new Uint8Array(new ArrayBuffer(l));
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       a[i] = buffer[i];
 | |
|     }
 | |
|     return a;
 | |
|   }
 | |
|   function stringToBinaryWorkaround(xhr) {
 | |
|     var cl, data;
 | |
|     cl = xhr.getResponseHeader("Content-Length");
 | |
|     if (cl) {
 | |
|       cl = parseInt(cl, 10);
 | |
|     }
 | |
|     if (cl && cl !== xhr.responseText.length) {
 | |
|       data = utf8ByteArrayFromXHRString(xhr.responseText, cl);
 | |
|     }
 | |
|     if (data === undefined) {
 | |
|       data = byteArrayFromString(xhr.responseText);
 | |
|     }
 | |
|     return data;
 | |
|   }
 | |
|   function handleXHRResult(path, encoding, xhr) {
 | |
|     var r, d, a, data;
 | |
|     if (xhr.status === 0 && !xhr.responseText) {
 | |
|       r = {err:"File " + path + " is empty.", data:null};
 | |
|     } else {
 | |
|       if (xhr.status === 200 || xhr.status === 0) {
 | |
|         if (xhr.response && typeof xhr.response !== "string") {
 | |
|           if (encoding === "binary") {
 | |
|             d = (xhr.response);
 | |
|             data = new Uint8Array(d);
 | |
|           } else {
 | |
|             data = String(xhr.response);
 | |
|           }
 | |
|         } else {
 | |
|           if (encoding === "binary") {
 | |
|             if (xhr.responseBody !== null && String(typeof VBArray) !== "undefined") {
 | |
|               a = (new VBArray(xhr.responseBody)).toArray();
 | |
|               data = arrayToUint8Array(a);
 | |
|             } else {
 | |
|               data = stringToBinaryWorkaround(xhr);
 | |
|             }
 | |
|           } else {
 | |
|             data = xhr.responseText;
 | |
|           }
 | |
|         }
 | |
|         r = {err:null, data:data};
 | |
|       } else {
 | |
|         r = {err:xhr.responseText || xhr.statusText, data:null};
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   function createXHR(path, encoding, async) {
 | |
|     var xhr = new XMLHttpRequest;
 | |
|     xhr.open("GET", path, async);
 | |
|     if (xhr.overrideMimeType) {
 | |
|       if (encoding !== "binary") {
 | |
|         xhr.overrideMimeType("text/plain; charset=" + encoding);
 | |
|       } else {
 | |
|         xhr.overrideMimeType("text/plain; charset=x-user-defined");
 | |
|       }
 | |
|     }
 | |
|     return xhr;
 | |
|   }
 | |
|   function readFile(path, encoding, callback) {
 | |
|     var xhr = createXHR(path, encoding, true);
 | |
|     function handleResult() {
 | |
|       var r;
 | |
|       if (xhr.readyState === 4) {
 | |
|         r = handleXHRResult(path, encoding, xhr);
 | |
|         callback(r.err, r.data);
 | |
|       }
 | |
|     }
 | |
|     xhr.onreadystatechange = handleResult;
 | |
|     try {
 | |
|       xhr.send(null);
 | |
|     } catch (e) {
 | |
|       callback(e.message, null);
 | |
|     }
 | |
|   }
 | |
|   function read(path, offset, length, callback) {
 | |
|     readFile(path, "binary", function(err, result) {
 | |
|       var r = null;
 | |
|       if (result) {
 | |
|         if (typeof result === "string") {
 | |
|           throw "This should not happen.";
 | |
|         }
 | |
|         r = (result.subarray(offset, offset + length));
 | |
|       }
 | |
|       callback(err, r);
 | |
|     });
 | |
|   }
 | |
|   function readFileSync(path, encoding) {
 | |
|     var xhr = createXHR(path, encoding, false), r;
 | |
|     try {
 | |
|       xhr.send(null);
 | |
|       r = handleXHRResult(path, encoding, xhr);
 | |
|       if (r.err) {
 | |
|         throw r.err;
 | |
|       }
 | |
|       if (r.data === null) {
 | |
|         throw "No data read from " + path + ".";
 | |
|       }
 | |
|     } catch (e) {
 | |
|       throw e;
 | |
|     }
 | |
|     return r.data;
 | |
|   }
 | |
|   function writeFile(path, data, callback) {
 | |
|     var xhr = new XMLHttpRequest, d;
 | |
|     function handleResult() {
 | |
|       if (xhr.readyState === 4) {
 | |
|         if (xhr.status === 0 && !xhr.responseText) {
 | |
|           callback("File " + path + " is empty.");
 | |
|         } else {
 | |
|           if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 0) {
 | |
|             callback(null);
 | |
|           } else {
 | |
|             callback("Status " + String(xhr.status) + ": " + xhr.responseText || xhr.statusText);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     xhr.open("PUT", path, true);
 | |
|     xhr.onreadystatechange = handleResult;
 | |
|     if (data.buffer && !xhr.sendAsBinary) {
 | |
|       d = data.buffer;
 | |
|     } else {
 | |
|       d = self.byteArrayToString(data, "binary");
 | |
|     }
 | |
|     try {
 | |
|       if (xhr.sendAsBinary) {
 | |
|         xhr.sendAsBinary(d);
 | |
|       } else {
 | |
|         xhr.send(d);
 | |
|       }
 | |
|     } catch (e) {
 | |
|       self.log("HUH? " + e + " " + data);
 | |
|       callback(e.message);
 | |
|     }
 | |
|   }
 | |
|   function deleteFile(path, callback) {
 | |
|     var xhr = new XMLHttpRequest;
 | |
|     xhr.open("DELETE", path, true);
 | |
|     xhr.onreadystatechange = function() {
 | |
|       if (xhr.readyState === 4) {
 | |
|         if (xhr.status < 200 && xhr.status >= 300) {
 | |
|           callback(xhr.responseText);
 | |
|         } else {
 | |
|           callback(null);
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     xhr.send(null);
 | |
|   }
 | |
|   function loadXML(path, callback) {
 | |
|     var xhr = new XMLHttpRequest;
 | |
|     function handleResult() {
 | |
|       if (xhr.readyState === 4) {
 | |
|         if (xhr.status === 0 && !xhr.responseText) {
 | |
|           callback("File " + path + " is empty.", null);
 | |
|         } else {
 | |
|           if (xhr.status === 200 || xhr.status === 0) {
 | |
|             callback(null, xhr.responseXML);
 | |
|           } else {
 | |
|             callback(xhr.responseText, null);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     xhr.open("GET", path, true);
 | |
|     if (xhr.overrideMimeType) {
 | |
|       xhr.overrideMimeType("text/xml");
 | |
|     }
 | |
|     xhr.onreadystatechange = handleResult;
 | |
|     try {
 | |
|       xhr.send(null);
 | |
|     } catch (e) {
 | |
|       callback(e.message, null);
 | |
|     }
 | |
|   }
 | |
|   this.readFile = readFile;
 | |
|   this.read = read;
 | |
|   this.readFileSync = readFileSync;
 | |
|   this.writeFile = writeFile;
 | |
|   this.deleteFile = deleteFile;
 | |
|   this.loadXML = loadXML;
 | |
|   this.log = log;
 | |
|   this.enableAlerts = true;
 | |
|   this.assert = Runtime.assert;
 | |
|   this.setTimeout = function(f, msec) {
 | |
|     return setTimeout(function() {
 | |
|       f();
 | |
|     }, msec);
 | |
|   };
 | |
|   this.clearTimeout = function(timeoutID) {
 | |
|     clearTimeout(timeoutID);
 | |
|   };
 | |
|   this.libraryPaths = function() {
 | |
|     return ["lib"];
 | |
|   };
 | |
|   this.setCurrentDirectory = function() {
 | |
|   };
 | |
|   this.currentDirectory = function() {
 | |
|     return "";
 | |
|   };
 | |
|   this.type = function() {
 | |
|     return "BrowserRuntime";
 | |
|   };
 | |
|   this.getDOMImplementation = function() {
 | |
|     return window.document.implementation;
 | |
|   };
 | |
|   this.parseXML = function(xml) {
 | |
|     var parser = new DOMParser;
 | |
|     return parser.parseFromString(xml, "text/xml");
 | |
|   };
 | |
|   this.exit = function(exitCode) {
 | |
|     log("Calling exit with code " + String(exitCode) + ", but exit() is not implemented.");
 | |
|   };
 | |
|   this.getWindow = function() {
 | |
|     return window;
 | |
|   };
 | |
|   this.requestAnimationFrame = function(callback) {
 | |
|     var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame, requestId = 0;
 | |
|     if (rAF) {
 | |
|       rAF.bind(window);
 | |
|       requestId = (rAF)(callback);
 | |
|     } else {
 | |
|       return setTimeout(callback, 15);
 | |
|     }
 | |
|     return requestId;
 | |
|   };
 | |
|   this.cancelAnimationFrame = function(requestId) {
 | |
|     var cAF = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame;
 | |
|     if (cAF) {
 | |
|       cAF.bind(window);
 | |
|       (cAF)(requestId);
 | |
|     } else {
 | |
|       clearTimeout(requestId);
 | |
|     }
 | |
|   };
 | |
| }
 | |
| function NodeJSRuntime() {
 | |
|   var self = this, fs = require("fs"), pathmod = require("path"), currentDirectory = "", parser, domImplementation;
 | |
|   function bufferToUint8Array(buffer) {
 | |
|     var l = buffer.length, i, a = new Uint8Array(new ArrayBuffer(l));
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       a[i] = buffer[i];
 | |
|     }
 | |
|     return a;
 | |
|   }
 | |
|   this.byteArrayFromString = function(string, encoding) {
 | |
|     var buf = new Buffer(string, encoding), i, l = buf.length, a = new Uint8Array(new ArrayBuffer(l));
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       a[i] = buf[i];
 | |
|     }
 | |
|     return a;
 | |
|   };
 | |
|   this.byteArrayToString = Runtime.byteArrayToString;
 | |
|   this.getVariable = Runtime.getVariable;
 | |
|   this.fromJson = Runtime.fromJson;
 | |
|   this.toJson = Runtime.toJson;
 | |
|   function readFile(path, encoding, callback) {
 | |
|     function convert(err, data) {
 | |
|       if (err) {
 | |
|         return callback(err, null);
 | |
|       }
 | |
|       if (!data) {
 | |
|         return callback("No data for " + path + ".", null);
 | |
|       }
 | |
|       var d;
 | |
|       if (typeof data === "string") {
 | |
|         d = (data);
 | |
|         return callback(err, d);
 | |
|       }
 | |
|       d = (data);
 | |
|       callback(err, bufferToUint8Array(d));
 | |
|     }
 | |
|     path = pathmod.resolve(currentDirectory, path);
 | |
|     if (encoding !== "binary") {
 | |
|       fs.readFile(path, encoding, convert);
 | |
|     } else {
 | |
|       fs.readFile(path, null, convert);
 | |
|     }
 | |
|   }
 | |
|   this.readFile = readFile;
 | |
|   function loadXML(path, callback) {
 | |
|     readFile(path, "utf-8", function(err, data) {
 | |
|       if (err) {
 | |
|         return callback(err, null);
 | |
|       }
 | |
|       if (!data) {
 | |
|         return callback("No data for " + path + ".", null);
 | |
|       }
 | |
|       var d = (data);
 | |
|       callback(null, self.parseXML(d));
 | |
|     });
 | |
|   }
 | |
|   this.loadXML = loadXML;
 | |
|   this.writeFile = function(path, data, callback) {
 | |
|     var buf = new Buffer(data);
 | |
|     path = pathmod.resolve(currentDirectory, path);
 | |
|     fs.writeFile(path, buf, "binary", function(err) {
 | |
|       callback(err || null);
 | |
|     });
 | |
|   };
 | |
|   this.deleteFile = function(path, callback) {
 | |
|     path = pathmod.resolve(currentDirectory, path);
 | |
|     fs.unlink(path, callback);
 | |
|   };
 | |
|   this.read = function(path, offset, length, callback) {
 | |
|     path = pathmod.resolve(currentDirectory, path);
 | |
|     fs.open(path, "r+", 666, function(err, fd) {
 | |
|       if (err) {
 | |
|         callback(err, null);
 | |
|         return;
 | |
|       }
 | |
|       var buffer = new Buffer(length);
 | |
|       fs.read(fd, buffer, 0, length, offset, function(err) {
 | |
|         fs.close(fd);
 | |
|         callback(err, bufferToUint8Array(buffer));
 | |
|       });
 | |
|     });
 | |
|   };
 | |
|   this.readFileSync = function(path, encoding) {
 | |
|     var s, enc = encoding === "binary" ? null : encoding, r = fs.readFileSync(path, enc);
 | |
|     if (r === null) {
 | |
|       throw "File " + path + " could not be read.";
 | |
|     }
 | |
|     if (encoding === "binary") {
 | |
|       s = (r);
 | |
|       s = bufferToUint8Array(s);
 | |
|     } else {
 | |
|       s = (r);
 | |
|     }
 | |
|     return s;
 | |
|   };
 | |
|   function log(msgOrCategory, msg) {
 | |
|     var category;
 | |
|     if (msg !== undefined) {
 | |
|       category = msgOrCategory;
 | |
|     } else {
 | |
|       msg = msgOrCategory;
 | |
|     }
 | |
|     if (category === "alert") {
 | |
|       process.stderr.write("\n!!!!! ALERT !!!!!" + "\n");
 | |
|     }
 | |
|     process.stderr.write(msg + "\n");
 | |
|     if (category === "alert") {
 | |
|       process.stderr.write("!!!!! ALERT !!!!!" + "\n");
 | |
|     }
 | |
|   }
 | |
|   this.log = log;
 | |
|   this.assert = Runtime.assert;
 | |
|   this.setTimeout = function(f, msec) {
 | |
|     return setTimeout(function() {
 | |
|       f();
 | |
|     }, msec);
 | |
|   };
 | |
|   this.clearTimeout = function(timeoutID) {
 | |
|     clearTimeout(timeoutID);
 | |
|   };
 | |
|   this.libraryPaths = function() {
 | |
|     return [__dirname];
 | |
|   };
 | |
|   this.setCurrentDirectory = function(dir) {
 | |
|     currentDirectory = dir;
 | |
|   };
 | |
|   this.currentDirectory = function() {
 | |
|     return currentDirectory;
 | |
|   };
 | |
|   this.type = function() {
 | |
|     return "NodeJSRuntime";
 | |
|   };
 | |
|   this.getDOMImplementation = function() {
 | |
|     return domImplementation;
 | |
|   };
 | |
|   this.parseXML = function(xml) {
 | |
|     return parser.parseFromString(xml, "text/xml");
 | |
|   };
 | |
|   this.exit = process.exit;
 | |
|   this.getWindow = function() {
 | |
|     return null;
 | |
|   };
 | |
|   this.requestAnimationFrame = function(callback) {
 | |
|     return setTimeout(callback, 15);
 | |
|   };
 | |
|   this.cancelAnimationFrame = function(requestId) {
 | |
|     clearTimeout(requestId);
 | |
|   };
 | |
|   function init() {
 | |
|     var DOMParser = require("xmldom").DOMParser;
 | |
|     parser = new DOMParser;
 | |
|     domImplementation = self.parseXML("<a/>").implementation;
 | |
|   }
 | |
|   init();
 | |
| }
 | |
| function RhinoRuntime() {
 | |
|   var self = this, Packages = {}, dom = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance(), builder, entityresolver, currentDirectory = "";
 | |
|   dom.setValidating(false);
 | |
|   dom.setNamespaceAware(true);
 | |
|   dom.setExpandEntityReferences(false);
 | |
|   dom.setSchema(null);
 | |
|   entityresolver = Packages.org.xml.sax.EntityResolver({resolveEntity:function(publicId, systemId) {
 | |
|     var file;
 | |
|     function open(path) {
 | |
|       var reader = new Packages.java.io.FileReader(path), source = new Packages.org.xml.sax.InputSource(reader);
 | |
|       return source;
 | |
|     }
 | |
|     file = systemId;
 | |
|     return open(file);
 | |
|   }});
 | |
|   builder = dom.newDocumentBuilder();
 | |
|   builder.setEntityResolver(entityresolver);
 | |
|   this.byteArrayFromString = function(string, encoding) {
 | |
|     var i, l = string.length, a = new Uint8Array(new ArrayBuffer(l));
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       a[i] = string.charCodeAt(i) & 255;
 | |
|     }
 | |
|     return a;
 | |
|   };
 | |
|   this.byteArrayToString = Runtime.byteArrayToString;
 | |
|   this.getVariable = Runtime.getVariable;
 | |
|   this.fromJson = Runtime.fromJson;
 | |
|   this.toJson = Runtime.toJson;
 | |
|   function loadXML(path, callback) {
 | |
|     var file = new Packages.java.io.File(path), xmlDocument = null;
 | |
|     try {
 | |
|       xmlDocument = builder.parse(file);
 | |
|     } catch (err) {
 | |
|       print(err);
 | |
|       return callback(err, null);
 | |
|     }
 | |
|     callback(null, xmlDocument);
 | |
|   }
 | |
|   function runtimeReadFile(path, encoding, callback) {
 | |
|     if (currentDirectory) {
 | |
|       path = currentDirectory + "/" + path;
 | |
|     }
 | |
|     var file = new Packages.java.io.File(path), data, rhinoencoding = encoding === "binary" ? "latin1" : encoding;
 | |
|     if (!file.isFile()) {
 | |
|       callback(path + " is not a file.", null);
 | |
|     } else {
 | |
|       data = readFile(path, rhinoencoding);
 | |
|       if (data && encoding === "binary") {
 | |
|         data = self.byteArrayFromString(data, "binary");
 | |
|       }
 | |
|       callback(null, data);
 | |
|     }
 | |
|   }
 | |
|   function runtimeReadFileSync(path, encoding) {
 | |
|     var file = new Packages.java.io.File(path);
 | |
|     if (!file.isFile()) {
 | |
|       return null;
 | |
|     }
 | |
|     if (encoding === "binary") {
 | |
|       encoding = "latin1";
 | |
|     }
 | |
|     return readFile(path, encoding);
 | |
|   }
 | |
|   this.loadXML = loadXML;
 | |
|   this.readFile = runtimeReadFile;
 | |
|   this.writeFile = function(path, data, callback) {
 | |
|     if (currentDirectory) {
 | |
|       path = currentDirectory + "/" + path;
 | |
|     }
 | |
|     var out = new Packages.java.io.FileOutputStream(path), i, l = data.length;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       out.write(data[i]);
 | |
|     }
 | |
|     out.close();
 | |
|     callback(null);
 | |
|   };
 | |
|   this.deleteFile = function(path, callback) {
 | |
|     if (currentDirectory) {
 | |
|       path = currentDirectory + "/" + path;
 | |
|     }
 | |
|     var file = new Packages.java.io.File(path), otherPath = path + Math.random(), other = new Packages.java.io.File(otherPath);
 | |
|     if (file.rename(other)) {
 | |
|       other.deleteOnExit();
 | |
|       callback(null);
 | |
|     } else {
 | |
|       callback("Could not delete " + path);
 | |
|     }
 | |
|   };
 | |
|   this.read = function(path, offset, length, callback) {
 | |
|     if (currentDirectory) {
 | |
|       path = currentDirectory + "/" + path;
 | |
|     }
 | |
|     var data = runtimeReadFileSync(path, "binary");
 | |
|     if (data) {
 | |
|       callback(null, this.byteArrayFromString(data.substring(offset, offset + length), "binary"));
 | |
|     } else {
 | |
|       callback("Cannot read " + path, null);
 | |
|     }
 | |
|   };
 | |
|   this.readFileSync = function(path, encoding) {
 | |
|     if (!encoding) {
 | |
|       return "";
 | |
|     }
 | |
|     var s = readFile(path, encoding);
 | |
|     if (s === null) {
 | |
|       throw "File could not be read.";
 | |
|     }
 | |
|     return s;
 | |
|   };
 | |
|   function log(msgOrCategory, msg) {
 | |
|     var category;
 | |
|     if (msg !== undefined) {
 | |
|       category = msgOrCategory;
 | |
|     } else {
 | |
|       msg = msgOrCategory;
 | |
|     }
 | |
|     if (category === "alert") {
 | |
|       print("\n!!!!! ALERT !!!!!");
 | |
|     }
 | |
|     print(msg);
 | |
|     if (category === "alert") {
 | |
|       print("!!!!! ALERT !!!!!");
 | |
|     }
 | |
|   }
 | |
|   this.log = log;
 | |
|   this.assert = Runtime.assert;
 | |
|   this.setTimeout = function(f) {
 | |
|     f();
 | |
|     return 0;
 | |
|   };
 | |
|   this.clearTimeout = function() {
 | |
|   };
 | |
|   this.libraryPaths = function() {
 | |
|     return ["lib"];
 | |
|   };
 | |
|   this.setCurrentDirectory = function(dir) {
 | |
|     currentDirectory = dir;
 | |
|   };
 | |
|   this.currentDirectory = function() {
 | |
|     return currentDirectory;
 | |
|   };
 | |
|   this.type = function() {
 | |
|     return "RhinoRuntime";
 | |
|   };
 | |
|   this.getDOMImplementation = function() {
 | |
|     return builder.getDOMImplementation();
 | |
|   };
 | |
|   this.parseXML = function(xml) {
 | |
|     var reader = new Packages.java.io.StringReader(xml), source = new Packages.org.xml.sax.InputSource(reader);
 | |
|     return builder.parse(source);
 | |
|   };
 | |
|   this.exit = quit;
 | |
|   this.getWindow = function() {
 | |
|     return null;
 | |
|   };
 | |
|   this.requestAnimationFrame = function(callback) {
 | |
|     callback();
 | |
|     return 0;
 | |
|   };
 | |
|   this.cancelAnimationFrame = function() {
 | |
|   };
 | |
| }
 | |
| Runtime.create = function create() {
 | |
|   var result;
 | |
|   if (String(typeof window) !== "undefined") {
 | |
|     result = new BrowserRuntime;
 | |
|   } else {
 | |
|     if (String(typeof require) !== "undefined") {
 | |
|       result = new NodeJSRuntime;
 | |
|     } else {
 | |
|       result = new RhinoRuntime;
 | |
|     }
 | |
|   }
 | |
|   return result;
 | |
| };
 | |
| var runtime = Runtime.create();
 | |
| var core = {};
 | |
| var gui = {};
 | |
| var xmldom = {};
 | |
| var odf = {};
 | |
| var ops = {};
 | |
| var webodf = {};
 | |
| (function() {
 | |
|   function getWebODFVersion() {
 | |
|     var version = String(typeof webodf_version) !== "undefined" ? webodf_version : "From Source";
 | |
|     return version;
 | |
|   }
 | |
|   webodf.Version = getWebODFVersion();
 | |
| })();
 | |
| (function() {
 | |
|   function loadDependenciesFromManifest(dir, dependencies, expectFail) {
 | |
|     var path = dir + "/manifest.json", content, list, manifest, m;
 | |
|     runtime.log("Loading manifest: " + path);
 | |
|     try {
 | |
|       content = runtime.readFileSync(path, "utf-8");
 | |
|     } catch (e) {
 | |
|       if (expectFail) {
 | |
|         runtime.log("No loadable manifest found.");
 | |
|       } else {
 | |
|         console.log(String(e));
 | |
|         throw e;
 | |
|       }
 | |
|       return;
 | |
|     }
 | |
|     list = JSON.parse((content));
 | |
|     manifest = (list);
 | |
|     for (m in manifest) {
 | |
|       if (manifest.hasOwnProperty(m)) {
 | |
|         dependencies[m] = {dir:dir, deps:manifest[m]};
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function loadDependenciesFromManifests() {
 | |
|     var dependencies = [], paths = runtime.libraryPaths(), i;
 | |
|     if (runtime.currentDirectory() && paths.indexOf(runtime.currentDirectory()) === -1) {
 | |
|       loadDependenciesFromManifest(runtime.currentDirectory(), dependencies, true);
 | |
|     }
 | |
|     for (i = 0;i < paths.length;i += 1) {
 | |
|       loadDependenciesFromManifest(paths[i], dependencies);
 | |
|     }
 | |
|     return dependencies;
 | |
|   }
 | |
|   function getPath(dir, className) {
 | |
|     return dir + "/" + className.replace(".", "/") + ".js";
 | |
|   }
 | |
|   function getLoadList(classNames, dependencies, isDefined) {
 | |
|     var loadList = [], stack = {}, visited = {};
 | |
|     function visit(n) {
 | |
|       if (visited[n] || isDefined(n)) {
 | |
|         return;
 | |
|       }
 | |
|       if (stack[n]) {
 | |
|         throw "Circular dependency detected for " + n + ".";
 | |
|       }
 | |
|       stack[n] = true;
 | |
|       if (!dependencies[n]) {
 | |
|         throw "Missing dependency information for class " + n + ".";
 | |
|       }
 | |
|       var d = dependencies[n], deps = d.deps, i, l = deps.length;
 | |
|       for (i = 0;i < l;i += 1) {
 | |
|         visit(deps[i]);
 | |
|       }
 | |
|       stack[n] = false;
 | |
|       visited[n] = true;
 | |
|       loadList.push(getPath(d.dir, n));
 | |
|     }
 | |
|     classNames.forEach(visit);
 | |
|     return loadList;
 | |
|   }
 | |
|   function addContent(path, content) {
 | |
|     content += "\n//# sourceURL=" + path;
 | |
|     return content;
 | |
|   }
 | |
|   function loadFiles(paths) {
 | |
|     var i, content;
 | |
|     for (i = 0;i < paths.length;i += 1) {
 | |
|       content = runtime.readFileSync(paths[i], "utf-8");
 | |
|       content = addContent(paths[i], (content));
 | |
|       eval(content);
 | |
|     }
 | |
|   }
 | |
|   function loadFilesInBrowser(paths, callback) {
 | |
|     var e = document.currentScript || document.documentElement.lastChild, df = document.createDocumentFragment(), script, i;
 | |
|     for (i = 0;i < paths.length;i += 1) {
 | |
|       script = document.createElement("script");
 | |
|       script.type = "text/javascript";
 | |
|       script.charset = "utf-8";
 | |
|       script.async = false;
 | |
|       script.setAttribute("src", paths[i]);
 | |
|       df.appendChild(script);
 | |
|     }
 | |
|     if (callback) {
 | |
|       script.onload = callback;
 | |
|     }
 | |
|     e.parentNode.insertBefore(df, e);
 | |
|   }
 | |
|   var dependencies, packages = {core:core, gui:gui, xmldom:xmldom, odf:odf, ops:ops};
 | |
|   function isDefined(classname) {
 | |
|     var parts = classname.split("."), i, p = packages, l = parts.length;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       if (!p.hasOwnProperty(parts[i])) {
 | |
|         return false;
 | |
|       }
 | |
|       p = (p[parts[i]]);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   runtime.loadClasses = function(classnames, callback) {
 | |
|     if (IS_COMPILED_CODE || classnames.length === 0) {
 | |
|       return callback && callback();
 | |
|     }
 | |
|     dependencies = dependencies || loadDependenciesFromManifests();
 | |
|     classnames = getLoadList(classnames, dependencies, isDefined);
 | |
|     if (classnames.length === 0) {
 | |
|       return callback && callback();
 | |
|     }
 | |
|     if (runtime.type() === "BrowserRuntime" && callback) {
 | |
|       loadFilesInBrowser(classnames, callback);
 | |
|     } else {
 | |
|       loadFiles(classnames);
 | |
|       if (callback) {
 | |
|         callback();
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   runtime.loadClass = function(classname, callback) {
 | |
|     runtime.loadClasses([classname], callback);
 | |
|   };
 | |
| })();
 | |
| (function() {
 | |
|   var translator = function(string) {
 | |
|     return string;
 | |
|   };
 | |
|   function tr(original) {
 | |
|     var result = translator(original);
 | |
|     if (!result || String(typeof result) !== "string") {
 | |
|       return original;
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   runtime.getTranslator = function() {
 | |
|     return translator;
 | |
|   };
 | |
|   runtime.setTranslator = function(translatorFunction) {
 | |
|     translator = translatorFunction;
 | |
|   };
 | |
|   runtime.tr = tr;
 | |
| })();
 | |
| (function(args) {
 | |
|   if (args) {
 | |
|     args = Array.prototype.slice.call((args));
 | |
|   } else {
 | |
|     args = [];
 | |
|   }
 | |
|   function run(argv) {
 | |
|     if (!argv.length) {
 | |
|       return;
 | |
|     }
 | |
|     var script = argv[0];
 | |
|     runtime.readFile(script, "utf8", function(err, code) {
 | |
|       var path = "", pathEndIndex = script.lastIndexOf("/"), codestring = (code);
 | |
|       if (pathEndIndex !== -1) {
 | |
|         path = script.substring(0, pathEndIndex);
 | |
|       } else {
 | |
|         path = ".";
 | |
|       }
 | |
|       runtime.setCurrentDirectory(path);
 | |
|       function inner_run() {
 | |
|         var script, path, args, argv, result;
 | |
|         result = (eval(codestring));
 | |
|         if (result) {
 | |
|           runtime.exit(result);
 | |
|         }
 | |
|         return;
 | |
|       }
 | |
|       if (err) {
 | |
|         runtime.log(err);
 | |
|         runtime.exit(1);
 | |
|       } else {
 | |
|         if (codestring === null) {
 | |
|           runtime.log("No code found for " + script);
 | |
|           runtime.exit(1);
 | |
|         } else {
 | |
|           inner_run.apply(null, argv);
 | |
|         }
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   if (runtime.type() === "NodeJSRuntime") {
 | |
|     run(process.argv.slice(2));
 | |
|   } else {
 | |
|     if (runtime.type() === "RhinoRuntime") {
 | |
|       run(args);
 | |
|     } else {
 | |
|       run(args.slice(1));
 | |
|     }
 | |
|   }
 | |
| })(String(typeof arguments) !== "undefined" && arguments);
 | |
| (function() {
 | |
|   function createASyncSingleton() {
 | |
|     function forEach(items, f, callback) {
 | |
|       var i, l = items.length, itemsDone = 0;
 | |
|       function end(err) {
 | |
|         if (itemsDone !== l) {
 | |
|           if (err) {
 | |
|             itemsDone = l;
 | |
|             callback(err);
 | |
|           } else {
 | |
|             itemsDone += 1;
 | |
|             if (itemsDone === l) {
 | |
|               callback(null);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       for (i = 0;i < l;i += 1) {
 | |
|         f(items[i], end);
 | |
|       }
 | |
|     }
 | |
|     function destroyAll(items, callback) {
 | |
|       function destroy(itemIndex, err) {
 | |
|         if (err) {
 | |
|           callback(err);
 | |
|         } else {
 | |
|           if (itemIndex < items.length) {
 | |
|             items[itemIndex](function(err) {
 | |
|               destroy(itemIndex + 1, err);
 | |
|             });
 | |
|           } else {
 | |
|             callback();
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       destroy(0, undefined);
 | |
|     }
 | |
|     return {forEach:forEach, destroyAll:destroyAll};
 | |
|   }
 | |
|   core.Async = createASyncSingleton();
 | |
| })();
 | |
| function makeBase64() {
 | |
|   function makeB64tab(bin) {
 | |
|     var t = {}, i, l;
 | |
|     for (i = 0, l = bin.length;i < l;i += 1) {
 | |
|       t[bin.charAt(i)] = i;
 | |
|     }
 | |
|     return t;
 | |
|   }
 | |
|   var b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", b64tab = makeB64tab(b64chars), convertUTF16StringToBase64, convertBase64ToUTF16String, window = runtime.getWindow(), btoa, atob;
 | |
|   function stringToArray(s) {
 | |
|     var i, l = s.length, a = new Uint8Array(new ArrayBuffer(l));
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       a[i] = s.charCodeAt(i) & 255;
 | |
|     }
 | |
|     return a;
 | |
|   }
 | |
|   function convertUTF8ArrayToBase64(bin) {
 | |
|     var n, b64 = "", i, l = bin.length - 2;
 | |
|     for (i = 0;i < l;i += 3) {
 | |
|       n = bin[i] << 16 | bin[i + 1] << 8 | bin[i + 2];
 | |
|       b64 += (b64chars[n >>> 18]);
 | |
|       b64 += (b64chars[n >>> 12 & 63]);
 | |
|       b64 += (b64chars[n >>> 6 & 63]);
 | |
|       b64 += (b64chars[n & 63]);
 | |
|     }
 | |
|     if (i === l + 1) {
 | |
|       n = bin[i] << 4;
 | |
|       b64 += (b64chars[n >>> 6]);
 | |
|       b64 += (b64chars[n & 63]);
 | |
|       b64 += "==";
 | |
|     } else {
 | |
|       if (i === l) {
 | |
|         n = bin[i] << 10 | bin[i + 1] << 2;
 | |
|         b64 += (b64chars[n >>> 12]);
 | |
|         b64 += (b64chars[n >>> 6 & 63]);
 | |
|         b64 += (b64chars[n & 63]);
 | |
|         b64 += "=";
 | |
|       }
 | |
|     }
 | |
|     return b64;
 | |
|   }
 | |
|   function convertBase64ToUTF8Array(b64) {
 | |
|     b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, "");
 | |
|     var l = b64.length, bin = new Uint8Array(new ArrayBuffer(3 * l)), padlen = b64.length % 4, o = 0, i, n, a = [0, 0, 2, 1];
 | |
|     for (i = 0;i < l;i += 4) {
 | |
|       n = (b64tab[b64.charAt(i)] || 0) << 18 | (b64tab[b64.charAt(i + 1)] || 0) << 12 | (b64tab[b64.charAt(i + 2)] || 0) << 6 | (b64tab[b64.charAt(i + 3)] || 0);
 | |
|       bin[o] = n >> 16;
 | |
|       bin[o + 1] = n >> 8 & 255;
 | |
|       bin[o + 2] = n & 255;
 | |
|       o += 3;
 | |
|     }
 | |
|     l = 3 * l - a[padlen];
 | |
|     return bin.subarray(0, l);
 | |
|   }
 | |
|   function convertUTF16ArrayToUTF8Array(uni) {
 | |
|     var i, n, l = uni.length, o = 0, bin = new Uint8Array(new ArrayBuffer(3 * l));
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       n = (uni[i]);
 | |
|       if (n < 128) {
 | |
|         bin[o++] = n;
 | |
|       } else {
 | |
|         if (n < 2048) {
 | |
|           bin[o++] = 192 | n >>> 6;
 | |
|           bin[o++] = 128 | n & 63;
 | |
|         } else {
 | |
|           bin[o++] = 224 | n >>> 12 & 15;
 | |
|           bin[o++] = 128 | n >>> 6 & 63;
 | |
|           bin[o++] = 128 | n & 63;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return bin.subarray(0, o);
 | |
|   }
 | |
|   function convertUTF8ArrayToUTF16Array(bin) {
 | |
|     var i, c0, c1, c2, l = bin.length, uni = new Uint8Array(new ArrayBuffer(l)), o = 0;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       c0 = (bin[i]);
 | |
|       if (c0 < 128) {
 | |
|         uni[o++] = c0;
 | |
|       } else {
 | |
|         i += 1;
 | |
|         c1 = (bin[i]);
 | |
|         if (c0 < 224) {
 | |
|           uni[o++] = (c0 & 31) << 6 | c1 & 63;
 | |
|         } else {
 | |
|           i += 1;
 | |
|           c2 = (bin[i]);
 | |
|           uni[o++] = (c0 & 15) << 12 | (c1 & 63) << 6 | c2 & 63;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return uni.subarray(0, o);
 | |
|   }
 | |
|   function convertUTF8StringToBase64(bin) {
 | |
|     return convertUTF8ArrayToBase64(stringToArray(bin));
 | |
|   }
 | |
|   function convertBase64ToUTF8String(b64) {
 | |
|     return String.fromCharCode.apply(String, convertBase64ToUTF8Array(b64));
 | |
|   }
 | |
|   function convertUTF8StringToUTF16Array(bin) {
 | |
|     return convertUTF8ArrayToUTF16Array(stringToArray(bin));
 | |
|   }
 | |
|   function convertUTF8ArrayToUTF16String(bin) {
 | |
|     var b = convertUTF8ArrayToUTF16Array(bin), r = "", i = 0, chunksize = 45E3;
 | |
|     while (i < b.length) {
 | |
|       r += String.fromCharCode.apply(String, b.subarray(i, i + chunksize));
 | |
|       i += chunksize;
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   function convertUTF8StringToUTF16String_internal(bin, i, end) {
 | |
|     var c0, c1, c2, j, str = "";
 | |
|     for (j = i;j < end;j += 1) {
 | |
|       c0 = bin.charCodeAt(j) & 255;
 | |
|       if (c0 < 128) {
 | |
|         str += String.fromCharCode(c0);
 | |
|       } else {
 | |
|         j += 1;
 | |
|         c1 = bin.charCodeAt(j) & 255;
 | |
|         if (c0 < 224) {
 | |
|           str += String.fromCharCode((c0 & 31) << 6 | c1 & 63);
 | |
|         } else {
 | |
|           j += 1;
 | |
|           c2 = bin.charCodeAt(j) & 255;
 | |
|           str += String.fromCharCode((c0 & 15) << 12 | (c1 & 63) << 6 | c2 & 63);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return str;
 | |
|   }
 | |
|   function convertUTF8StringToUTF16String(bin, callback) {
 | |
|     var partsize = 1E5, str = "", pos = 0;
 | |
|     if (bin.length < partsize) {
 | |
|       callback(convertUTF8StringToUTF16String_internal(bin, 0, bin.length), true);
 | |
|       return;
 | |
|     }
 | |
|     if (typeof bin !== "string") {
 | |
|       bin = bin.slice();
 | |
|     }
 | |
|     function f() {
 | |
|       var end = pos + partsize;
 | |
|       if (end > bin.length) {
 | |
|         end = bin.length;
 | |
|       }
 | |
|       str += convertUTF8StringToUTF16String_internal(bin, pos, end);
 | |
|       pos = end;
 | |
|       end = pos === bin.length;
 | |
|       if (callback(str, end) && !end) {
 | |
|         runtime.setTimeout(f, 0);
 | |
|       }
 | |
|     }
 | |
|     f();
 | |
|   }
 | |
|   function convertUTF16StringToUTF8Array(uni) {
 | |
|     return convertUTF16ArrayToUTF8Array(stringToArray(uni));
 | |
|   }
 | |
|   function convertUTF16ArrayToUTF8String(uni) {
 | |
|     return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(uni));
 | |
|   }
 | |
|   function convertUTF16StringToUTF8String(uni) {
 | |
|     return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(stringToArray(uni)));
 | |
|   }
 | |
|   if (window && window.btoa) {
 | |
|     btoa = window.btoa;
 | |
|     convertUTF16StringToBase64 = function(uni) {
 | |
|       return btoa(convertUTF16StringToUTF8String(uni));
 | |
|     };
 | |
|   } else {
 | |
|     btoa = convertUTF8StringToBase64;
 | |
|     convertUTF16StringToBase64 = function(uni) {
 | |
|       return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni));
 | |
|     };
 | |
|   }
 | |
|   if (window && window.atob) {
 | |
|     atob = window.atob;
 | |
|     convertBase64ToUTF16String = function(b64) {
 | |
|       var b = atob(b64);
 | |
|       return convertUTF8StringToUTF16String_internal(b, 0, b.length);
 | |
|     };
 | |
|   } else {
 | |
|     atob = convertBase64ToUTF8String;
 | |
|     convertBase64ToUTF16String = function(b64) {
 | |
|       return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64));
 | |
|     };
 | |
|   }
 | |
|   core.Base64 = function Base64() {
 | |
|     this.convertUTF8ArrayToBase64 = convertUTF8ArrayToBase64;
 | |
|     this.convertByteArrayToBase64 = convertUTF8ArrayToBase64;
 | |
|     this.convertBase64ToUTF8Array = convertBase64ToUTF8Array;
 | |
|     this.convertBase64ToByteArray = convertBase64ToUTF8Array;
 | |
|     this.convertUTF16ArrayToUTF8Array = convertUTF16ArrayToUTF8Array;
 | |
|     this.convertUTF16ArrayToByteArray = convertUTF16ArrayToUTF8Array;
 | |
|     this.convertUTF8ArrayToUTF16Array = convertUTF8ArrayToUTF16Array;
 | |
|     this.convertByteArrayToUTF16Array = convertUTF8ArrayToUTF16Array;
 | |
|     this.convertUTF8StringToBase64 = convertUTF8StringToBase64;
 | |
|     this.convertBase64ToUTF8String = convertBase64ToUTF8String;
 | |
|     this.convertUTF8StringToUTF16Array = convertUTF8StringToUTF16Array;
 | |
|     this.convertUTF8ArrayToUTF16String = convertUTF8ArrayToUTF16String;
 | |
|     this.convertByteArrayToUTF16String = convertUTF8ArrayToUTF16String;
 | |
|     this.convertUTF8StringToUTF16String = convertUTF8StringToUTF16String;
 | |
|     this.convertUTF16StringToUTF8Array = convertUTF16StringToUTF8Array;
 | |
|     this.convertUTF16StringToByteArray = convertUTF16StringToUTF8Array;
 | |
|     this.convertUTF16ArrayToUTF8String = convertUTF16ArrayToUTF8String;
 | |
|     this.convertUTF16StringToUTF8String = convertUTF16StringToUTF8String;
 | |
|     this.convertUTF16StringToBase64 = convertUTF16StringToBase64;
 | |
|     this.convertBase64ToUTF16String = convertBase64ToUTF16String;
 | |
|     this.fromBase64 = convertBase64ToUTF8String;
 | |
|     this.toBase64 = convertUTF8StringToBase64;
 | |
|     this.atob = atob;
 | |
|     this.btoa = btoa;
 | |
|     this.utob = convertUTF16StringToUTF8String;
 | |
|     this.btou = convertUTF8StringToUTF16String;
 | |
|     this.encode = convertUTF16StringToBase64;
 | |
|     this.encodeURI = function(u) {
 | |
|       return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0) {
 | |
|         return m0 === "+" ? "-" : "_";
 | |
|       }).replace(/\\=+$/, "");
 | |
|     };
 | |
|     this.decode = function(a) {
 | |
|       return convertBase64ToUTF16String(a.replace(/[\-_]/g, function(m0) {
 | |
|         return m0 === "-" ? "+" : "/";
 | |
|       }));
 | |
|     };
 | |
|     return this;
 | |
|   };
 | |
|   return core.Base64;
 | |
| }
 | |
| core.Base64 = makeBase64();
 | |
| core.ByteArray = function ByteArray(data) {
 | |
|   this.pos = 0;
 | |
|   this.data = data;
 | |
|   this.readUInt32LE = function() {
 | |
|     this.pos += 4;
 | |
|     var d = this.data, pos = this.pos;
 | |
|     return d[--pos] << 24 | d[--pos] << 16 | d[--pos] << 8 | d[--pos];
 | |
|   };
 | |
|   this.readUInt16LE = function() {
 | |
|     this.pos += 2;
 | |
|     var d = this.data, pos = this.pos;
 | |
|     return d[--pos] << 8 | d[--pos];
 | |
|   };
 | |
| };
 | |
| core.ByteArrayWriter = function ByteArrayWriter(encoding) {
 | |
|   var self = this, length = 0, bufferSize = 1024, data = new Uint8Array(new ArrayBuffer(bufferSize));
 | |
|   function expand(extraLength) {
 | |
|     var newData;
 | |
|     if (extraLength > bufferSize - length) {
 | |
|       bufferSize = Math.max(2 * bufferSize, length + extraLength);
 | |
|       newData = new Uint8Array(new ArrayBuffer(bufferSize));
 | |
|       newData.set(data);
 | |
|       data = newData;
 | |
|     }
 | |
|   }
 | |
|   this.appendByteArrayWriter = function(writer) {
 | |
|     self.appendByteArray(writer.getByteArray());
 | |
|   };
 | |
|   this.appendByteArray = function(array) {
 | |
|     var l = array.length;
 | |
|     expand(l);
 | |
|     data.set(array, length);
 | |
|     length += l;
 | |
|   };
 | |
|   this.appendArray = function(array) {
 | |
|     var l = array.length;
 | |
|     expand(l);
 | |
|     data.set(array, length);
 | |
|     length += l;
 | |
|   };
 | |
|   this.appendUInt16LE = function(value) {
 | |
|     self.appendArray([value & 255, value >> 8 & 255]);
 | |
|   };
 | |
|   this.appendUInt32LE = function(value) {
 | |
|     self.appendArray([value & 255, value >> 8 & 255, value >> 16 & 255, value >> 24 & 255]);
 | |
|   };
 | |
|   this.appendString = function(string) {
 | |
|     self.appendByteArray(runtime.byteArrayFromString(string, encoding));
 | |
|   };
 | |
|   this.getLength = function() {
 | |
|     return length;
 | |
|   };
 | |
|   this.getByteArray = function() {
 | |
|     var a = new Uint8Array(new ArrayBuffer(length));
 | |
|     a.set(data.subarray(0, length));
 | |
|     return a;
 | |
|   };
 | |
| };
 | |
| core.CSSUnits = function CSSUnits() {
 | |
|   var self = this, sizemap = {"in":1, "cm":2.54, "mm":25.4, "pt":72, "pc":12, "px":96};
 | |
|   this.convert = function(value, oldUnit, newUnit) {
 | |
|     return value * sizemap[newUnit] / sizemap[oldUnit];
 | |
|   };
 | |
|   this.convertMeasure = function(measure, newUnit) {
 | |
|     var value, oldUnit, newMeasure;
 | |
|     if (measure && newUnit) {
 | |
|       value = parseFloat(measure);
 | |
|       oldUnit = measure.replace(value.toString(), "");
 | |
|       newMeasure = self.convert(value, oldUnit, newUnit);
 | |
|     }
 | |
|     return newMeasure;
 | |
|   };
 | |
|   this.getUnits = function(measure) {
 | |
|     return measure.substr(measure.length - 2, measure.length);
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   var browserQuirks;
 | |
|   function getBrowserQuirks() {
 | |
|     var range, directBoundingRect, rangeBoundingRect, testContainer, testElement, detectedQuirks, window, document, docElement, body, docOverflow, bodyOverflow, bodyHeight, bodyScroll;
 | |
|     if (browserQuirks === undefined) {
 | |
|       window = runtime.getWindow();
 | |
|       document = window && window.document;
 | |
|       docElement = document.documentElement;
 | |
|       body = document.body;
 | |
|       browserQuirks = {rangeBCRIgnoresElementBCR:false, unscaledRangeClientRects:false, elementBCRIgnoresBodyScroll:false};
 | |
|       if (document) {
 | |
|         testContainer = document.createElement("div");
 | |
|         testContainer.style.position = "absolute";
 | |
|         testContainer.style.left = "-99999px";
 | |
|         testContainer.style.transform = "scale(2)";
 | |
|         testContainer.style["-webkit-transform"] = "scale(2)";
 | |
|         testElement = document.createElement("div");
 | |
|         testContainer.appendChild(testElement);
 | |
|         body.appendChild(testContainer);
 | |
|         range = document.createRange();
 | |
|         range.selectNode(testElement);
 | |
|         browserQuirks.rangeBCRIgnoresElementBCR = range.getClientRects().length === 0;
 | |
|         testElement.appendChild(document.createTextNode("Rect transform test"));
 | |
|         directBoundingRect = testElement.getBoundingClientRect();
 | |
|         rangeBoundingRect = range.getBoundingClientRect();
 | |
|         browserQuirks.unscaledRangeClientRects = Math.abs(directBoundingRect.height - rangeBoundingRect.height) > 2;
 | |
|         testContainer.style.transform = "";
 | |
|         testContainer.style["-webkit-transform"] = "";
 | |
|         docOverflow = docElement.style.overflow;
 | |
|         bodyOverflow = body.style.overflow;
 | |
|         bodyHeight = body.style.height;
 | |
|         bodyScroll = body.scrollTop;
 | |
|         docElement.style.overflow = "visible";
 | |
|         body.style.overflow = "visible";
 | |
|         body.style.height = "200%";
 | |
|         body.scrollTop = body.scrollHeight;
 | |
|         browserQuirks.elementBCRIgnoresBodyScroll = range.getBoundingClientRect().top !== testElement.getBoundingClientRect().top;
 | |
|         body.scrollTop = bodyScroll;
 | |
|         body.style.height = bodyHeight;
 | |
|         body.style.overflow = bodyOverflow;
 | |
|         docElement.style.overflow = docOverflow;
 | |
|         range.detach();
 | |
|         body.removeChild(testContainer);
 | |
|         detectedQuirks = Object.keys(browserQuirks).map(function(quirk) {
 | |
|           return quirk + ":" + String(browserQuirks[quirk]);
 | |
|         }).join(", ");
 | |
|         runtime.log("Detected browser quirks - " + detectedQuirks);
 | |
|       }
 | |
|     }
 | |
|     return browserQuirks;
 | |
|   }
 | |
|   function getDirectChild(parent, ns, name) {
 | |
|     var node = parent ? parent.firstElementChild : null;
 | |
|     while (node) {
 | |
|       if (node.localName === name && node.namespaceURI === ns) {
 | |
|         return (node);
 | |
|       }
 | |
|       node = node.nextElementSibling;
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   core.DomUtilsImpl = function DomUtilsImpl() {
 | |
|     var sharedRange = null;
 | |
|     function getSharedRange(doc) {
 | |
|       var range;
 | |
|       if (sharedRange) {
 | |
|         range = sharedRange;
 | |
|       } else {
 | |
|         sharedRange = range = (doc.createRange());
 | |
|       }
 | |
|       return range;
 | |
|     }
 | |
|     function findStablePoint(container, offset) {
 | |
|       var c = container;
 | |
|       if (offset < c.childNodes.length) {
 | |
|         c = c.childNodes.item(offset);
 | |
|         offset = 0;
 | |
|         while (c.firstChild) {
 | |
|           c = c.firstChild;
 | |
|         }
 | |
|       } else {
 | |
|         while (c.lastChild) {
 | |
|           c = c.lastChild;
 | |
|           offset = c.nodeType === Node.TEXT_NODE ? c.textContent.length : c.childNodes.length;
 | |
|         }
 | |
|       }
 | |
|       return {container:c, offset:offset};
 | |
|     }
 | |
|     function getPositionInContainingNode(node, container) {
 | |
|       var offset = 0, n;
 | |
|       while (node.parentNode !== container) {
 | |
|         runtime.assert(node.parentNode !== null, "parent is null");
 | |
|         node = (node.parentNode);
 | |
|       }
 | |
|       n = container.firstChild;
 | |
|       while (n !== node) {
 | |
|         offset += 1;
 | |
|         n = n.nextSibling;
 | |
|       }
 | |
|       return offset;
 | |
|     }
 | |
|     function splitBoundaries(range) {
 | |
|       var modifiedNodes = [], originalEndContainer, resetToContainerLength, end, splitStart, node, text, offset;
 | |
|       if (range.startContainer.nodeType === Node.TEXT_NODE || range.endContainer.nodeType === Node.TEXT_NODE) {
 | |
|         originalEndContainer = range.endContainer;
 | |
|         resetToContainerLength = range.endContainer.nodeType !== Node.TEXT_NODE ? range.endOffset === range.endContainer.childNodes.length : false;
 | |
|         end = findStablePoint(range.endContainer, range.endOffset);
 | |
|         if (end.container === originalEndContainer) {
 | |
|           originalEndContainer = null;
 | |
|         }
 | |
|         range.setEnd(end.container, end.offset);
 | |
|         node = range.endContainer;
 | |
|         if (range.endOffset !== 0 && node.nodeType === Node.TEXT_NODE) {
 | |
|           text = (node);
 | |
|           if (range.endOffset !== text.length) {
 | |
|             modifiedNodes.push(text.splitText(range.endOffset));
 | |
|             modifiedNodes.push(text);
 | |
|           }
 | |
|         }
 | |
|         node = range.startContainer;
 | |
|         if (range.startOffset !== 0 && node.nodeType === Node.TEXT_NODE) {
 | |
|           text = (node);
 | |
|           if (range.startOffset !== text.length) {
 | |
|             splitStart = text.splitText(range.startOffset);
 | |
|             modifiedNodes.push(text);
 | |
|             modifiedNodes.push(splitStart);
 | |
|             range.setStart(splitStart, 0);
 | |
|           }
 | |
|         }
 | |
|         if (originalEndContainer !== null) {
 | |
|           node = range.endContainer;
 | |
|           while (node.parentNode && node.parentNode !== originalEndContainer) {
 | |
|             node = node.parentNode;
 | |
|           }
 | |
|           if (resetToContainerLength) {
 | |
|             offset = originalEndContainer.childNodes.length;
 | |
|           } else {
 | |
|             offset = getPositionInContainingNode(node, originalEndContainer);
 | |
|           }
 | |
|           range.setEnd(originalEndContainer, offset);
 | |
|         }
 | |
|       }
 | |
|       return modifiedNodes;
 | |
|     }
 | |
|     this.splitBoundaries = splitBoundaries;
 | |
|     function containsRange(container, insideRange) {
 | |
|       return container.compareBoundaryPoints(Range.START_TO_START, insideRange) <= 0 && container.compareBoundaryPoints(Range.END_TO_END, insideRange) >= 0;
 | |
|     }
 | |
|     this.containsRange = containsRange;
 | |
|     function rangesIntersect(range1, range2) {
 | |
|       return range1.compareBoundaryPoints(Range.END_TO_START, range2) <= 0 && range1.compareBoundaryPoints(Range.START_TO_END, range2) >= 0;
 | |
|     }
 | |
|     this.rangesIntersect = rangesIntersect;
 | |
|     function rangeIntersection(range1, range2) {
 | |
|       var newRange;
 | |
|       if (rangesIntersect(range1, range2)) {
 | |
|         newRange = (range1.cloneRange());
 | |
|         if (range1.compareBoundaryPoints(Range.START_TO_START, range2) === -1) {
 | |
|           newRange.setStart(range2.startContainer, range2.startOffset);
 | |
|         }
 | |
|         if (range1.compareBoundaryPoints(Range.END_TO_END, range2) === 1) {
 | |
|           newRange.setEnd(range2.endContainer, range2.endOffset);
 | |
|         }
 | |
|       }
 | |
|       return newRange;
 | |
|     }
 | |
|     this.rangeIntersection = rangeIntersection;
 | |
|     function maximumOffset(node) {
 | |
|       return node.nodeType === Node.TEXT_NODE ? (node).length : node.childNodes.length;
 | |
|     }
 | |
|     function moveToNonRejectedNode(walker, root, nodeFilter) {
 | |
|       var node = walker.currentNode;
 | |
|       if (node !== root) {
 | |
|         node = node.parentNode;
 | |
|         while (node && node !== root) {
 | |
|           if (nodeFilter(node) === NodeFilter.FILTER_REJECT) {
 | |
|             walker.currentNode = node;
 | |
|           }
 | |
|           node = node.parentNode;
 | |
|         }
 | |
|       }
 | |
|       return walker.currentNode;
 | |
|     }
 | |
|     function getNodesInRange(range, nodeFilter, whatToShow) {
 | |
|       var document = range.startContainer.ownerDocument, elements = [], rangeRoot = range.commonAncestorContainer, root = (rangeRoot.nodeType === Node.TEXT_NODE ? rangeRoot.parentNode : rangeRoot), treeWalker = document.createTreeWalker(root, whatToShow, nodeFilter, false), currentNode, lastNodeInRange, endNodeCompareFlags, comparePositionResult;
 | |
|       if (range.endContainer.childNodes[range.endOffset - 1]) {
 | |
|         lastNodeInRange = (range.endContainer.childNodes[range.endOffset - 1]);
 | |
|         endNodeCompareFlags = Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINED_BY;
 | |
|       } else {
 | |
|         lastNodeInRange = (range.endContainer);
 | |
|         endNodeCompareFlags = Node.DOCUMENT_POSITION_PRECEDING;
 | |
|       }
 | |
|       if (range.startContainer.childNodes[range.startOffset]) {
 | |
|         currentNode = (range.startContainer.childNodes[range.startOffset]);
 | |
|         treeWalker.currentNode = currentNode;
 | |
|       } else {
 | |
|         if (range.startOffset === maximumOffset(range.startContainer)) {
 | |
|           currentNode = (range.startContainer);
 | |
|           treeWalker.currentNode = currentNode;
 | |
|           treeWalker.lastChild();
 | |
|           currentNode = treeWalker.nextNode();
 | |
|         } else {
 | |
|           currentNode = (range.startContainer);
 | |
|           treeWalker.currentNode = currentNode;
 | |
|         }
 | |
|       }
 | |
|       if (currentNode) {
 | |
|         currentNode = moveToNonRejectedNode(treeWalker, root, nodeFilter);
 | |
|         switch(nodeFilter((currentNode))) {
 | |
|           case NodeFilter.FILTER_REJECT:
 | |
|             currentNode = treeWalker.nextSibling();
 | |
|             while (!currentNode && treeWalker.parentNode()) {
 | |
|               currentNode = treeWalker.nextSibling();
 | |
|             }
 | |
|             break;
 | |
|           case NodeFilter.FILTER_SKIP:
 | |
|             currentNode = treeWalker.nextNode();
 | |
|             break;
 | |
|           default:
 | |
|             break;
 | |
|         }
 | |
|         while (currentNode) {
 | |
|           comparePositionResult = lastNodeInRange.compareDocumentPosition(currentNode);
 | |
|           if (comparePositionResult !== 0 && (comparePositionResult & endNodeCompareFlags) === 0) {
 | |
|             break;
 | |
|           }
 | |
|           elements.push(currentNode);
 | |
|           currentNode = treeWalker.nextNode();
 | |
|         }
 | |
|       }
 | |
|       return elements;
 | |
|     }
 | |
|     this.getNodesInRange = getNodesInRange;
 | |
|     function mergeTextNodes(node, nextNode) {
 | |
|       var mergedNode = null, text, nextText;
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         text = (node);
 | |
|         if (text.length === 0) {
 | |
|           text.parentNode.removeChild(text);
 | |
|           if (nextNode.nodeType === Node.TEXT_NODE) {
 | |
|             mergedNode = nextNode;
 | |
|           }
 | |
|         } else {
 | |
|           if (nextNode.nodeType === Node.TEXT_NODE) {
 | |
|             nextText = (nextNode);
 | |
|             text.appendData(nextText.data);
 | |
|             nextNode.parentNode.removeChild(nextNode);
 | |
|           }
 | |
|           mergedNode = node;
 | |
|         }
 | |
|       }
 | |
|       return mergedNode;
 | |
|     }
 | |
|     function normalizeTextNodes(node) {
 | |
|       if (node && node.nextSibling) {
 | |
|         node = mergeTextNodes(node, node.nextSibling);
 | |
|       }
 | |
|       if (node && node.previousSibling) {
 | |
|         mergeTextNodes(node.previousSibling, node);
 | |
|       }
 | |
|     }
 | |
|     this.normalizeTextNodes = normalizeTextNodes;
 | |
|     function rangeContainsNode(limits, node) {
 | |
|       var range = node.ownerDocument.createRange(), nodeRange = node.ownerDocument.createRange(), result;
 | |
|       range.setStart(limits.startContainer, limits.startOffset);
 | |
|       range.setEnd(limits.endContainer, limits.endOffset);
 | |
|       nodeRange.selectNodeContents(node);
 | |
|       result = containsRange(range, nodeRange);
 | |
|       range.detach();
 | |
|       nodeRange.detach();
 | |
|       return result;
 | |
|     }
 | |
|     this.rangeContainsNode = rangeContainsNode;
 | |
|     function mergeIntoParent(targetNode) {
 | |
|       var parent = targetNode.parentNode;
 | |
|       while (targetNode.firstChild) {
 | |
|         parent.insertBefore(targetNode.firstChild, targetNode);
 | |
|       }
 | |
|       parent.removeChild(targetNode);
 | |
|       return parent;
 | |
|     }
 | |
|     this.mergeIntoParent = mergeIntoParent;
 | |
|     function removeUnwantedNodes(targetNode, nodeFilter) {
 | |
|       var parent = targetNode.parentNode, node = targetNode.firstChild, filterResult = nodeFilter(targetNode), next;
 | |
|       if (filterResult === NodeFilter.FILTER_SKIP) {
 | |
|         return parent;
 | |
|       }
 | |
|       while (node) {
 | |
|         next = node.nextSibling;
 | |
|         removeUnwantedNodes(node, nodeFilter);
 | |
|         node = next;
 | |
|       }
 | |
|       if (parent && filterResult === NodeFilter.FILTER_REJECT) {
 | |
|         mergeIntoParent(targetNode);
 | |
|       }
 | |
|       return parent;
 | |
|     }
 | |
|     this.removeUnwantedNodes = removeUnwantedNodes;
 | |
|     this.removeAllChildNodes = function(node) {
 | |
|       while (node.firstChild) {
 | |
|         node.removeChild(node.firstChild);
 | |
|       }
 | |
|     };
 | |
|     function getElementsByTagNameNS(node, namespace, tagName) {
 | |
|       var e = [], list, i, l;
 | |
|       list = node.getElementsByTagNameNS(namespace, tagName);
 | |
|       e.length = l = list.length;
 | |
|       for (i = 0;i < l;i += 1) {
 | |
|         e[i] = (list.item(i));
 | |
|       }
 | |
|       return e;
 | |
|     }
 | |
|     this.getElementsByTagNameNS = getElementsByTagNameNS;
 | |
|     function getElementsByTagName(node, tagName) {
 | |
|       var e = [], list, i, l;
 | |
|       list = node.getElementsByTagName(tagName);
 | |
|       e.length = l = list.length;
 | |
|       for (i = 0;i < l;i += 1) {
 | |
|         e[i] = (list.item(i));
 | |
|       }
 | |
|       return e;
 | |
|     }
 | |
|     this.getElementsByTagName = getElementsByTagName;
 | |
|     function containsNode(parent, descendant) {
 | |
|       return parent === descendant || (parent).contains((descendant));
 | |
|     }
 | |
|     this.containsNode = containsNode;
 | |
|     function containsNodeForBrokenWebKit(parent, descendant) {
 | |
|       return parent === descendant || Boolean(parent.compareDocumentPosition(descendant) & Node.DOCUMENT_POSITION_CONTAINED_BY);
 | |
|     }
 | |
|     function comparePoints(c1, o1, c2, o2) {
 | |
|       if (c1 === c2) {
 | |
|         return o2 - o1;
 | |
|       }
 | |
|       var comparison = c1.compareDocumentPosition(c2);
 | |
|       if (comparison === 2) {
 | |
|         comparison = -1;
 | |
|       } else {
 | |
|         if (comparison === 4) {
 | |
|           comparison = 1;
 | |
|         } else {
 | |
|           if (comparison === 10) {
 | |
|             o1 = getPositionInContainingNode(c1, c2);
 | |
|             comparison = o1 < o2 ? 1 : -1;
 | |
|           } else {
 | |
|             o2 = getPositionInContainingNode(c2, c1);
 | |
|             comparison = o2 < o1 ? -1 : 1;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       return comparison;
 | |
|     }
 | |
|     this.comparePoints = comparePoints;
 | |
|     function adaptRangeDifferenceToZoomLevel(inputNumber, zoomLevel) {
 | |
|       if (getBrowserQuirks().unscaledRangeClientRects) {
 | |
|         return inputNumber;
 | |
|       }
 | |
|       return inputNumber / zoomLevel;
 | |
|     }
 | |
|     this.adaptRangeDifferenceToZoomLevel = adaptRangeDifferenceToZoomLevel;
 | |
|     this.translateRect = function(child, parent, zoomLevel) {
 | |
|       return {top:adaptRangeDifferenceToZoomLevel(child.top - parent.top, zoomLevel), left:adaptRangeDifferenceToZoomLevel(child.left - parent.left, zoomLevel), bottom:adaptRangeDifferenceToZoomLevel(child.bottom - parent.top, zoomLevel), right:adaptRangeDifferenceToZoomLevel(child.right - parent.left, zoomLevel), width:adaptRangeDifferenceToZoomLevel(child.width, zoomLevel), height:adaptRangeDifferenceToZoomLevel(child.height, zoomLevel)};
 | |
|     };
 | |
|     function getBoundingClientRect(node) {
 | |
|       var doc = (node.ownerDocument), quirks = getBrowserQuirks(), range, element, rect, body = doc.body;
 | |
|       if (quirks.unscaledRangeClientRects === false || quirks.rangeBCRIgnoresElementBCR) {
 | |
|         if (node.nodeType === Node.ELEMENT_NODE) {
 | |
|           element = (node);
 | |
|           rect = element.getBoundingClientRect();
 | |
|           if (quirks.elementBCRIgnoresBodyScroll) {
 | |
|             return ({left:rect.left + body.scrollLeft, right:rect.right + body.scrollLeft, top:rect.top + body.scrollTop, bottom:rect.bottom + body.scrollTop, width:rect.width, height:rect.height});
 | |
|           }
 | |
|           return rect;
 | |
|         }
 | |
|       }
 | |
|       range = getSharedRange(doc);
 | |
|       range.selectNode(node);
 | |
|       return range.getBoundingClientRect();
 | |
|     }
 | |
|     this.getBoundingClientRect = getBoundingClientRect;
 | |
|     function mapKeyValObjOntoNode(node, properties, nsResolver) {
 | |
|       Object.keys(properties).forEach(function(key) {
 | |
|         var parts = key.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), value = properties[key], element;
 | |
|         if (ns) {
 | |
|           element = (node.getElementsByTagNameNS(ns, localName)[0]);
 | |
|           if (!element) {
 | |
|             element = node.ownerDocument.createElementNS(ns, key);
 | |
|             node.appendChild(element);
 | |
|           }
 | |
|           element.textContent = value;
 | |
|         } else {
 | |
|           runtime.log("Key ignored: " + key);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     this.mapKeyValObjOntoNode = mapKeyValObjOntoNode;
 | |
|     function removeKeyElementsFromNode(node, propertyNames, nsResolver) {
 | |
|       propertyNames.forEach(function(propertyName) {
 | |
|         var parts = propertyName.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), element;
 | |
|         if (ns) {
 | |
|           element = (node.getElementsByTagNameNS(ns, localName)[0]);
 | |
|           if (element) {
 | |
|             element.parentNode.removeChild(element);
 | |
|           } else {
 | |
|             runtime.log("Element for " + propertyName + " not found.");
 | |
|           }
 | |
|         } else {
 | |
|           runtime.log("Property Name ignored: " + propertyName);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     this.removeKeyElementsFromNode = removeKeyElementsFromNode;
 | |
|     function getKeyValRepresentationOfNode(node, prefixResolver) {
 | |
|       var properties = {}, currentSibling = node.firstElementChild, prefix;
 | |
|       while (currentSibling) {
 | |
|         prefix = prefixResolver(currentSibling.namespaceURI);
 | |
|         if (prefix) {
 | |
|           properties[prefix + ":" + currentSibling.localName] = currentSibling.textContent;
 | |
|         }
 | |
|         currentSibling = currentSibling.nextElementSibling;
 | |
|       }
 | |
|       return properties;
 | |
|     }
 | |
|     this.getKeyValRepresentationOfNode = getKeyValRepresentationOfNode;
 | |
|     function mapObjOntoNode(node, properties, nsResolver) {
 | |
|       Object.keys(properties).forEach(function(key) {
 | |
|         var parts = key.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), value = properties[key], valueType = typeof value, element;
 | |
|         if (valueType === "object") {
 | |
|           if (Object.keys((value)).length) {
 | |
|             if (ns) {
 | |
|               element = (node.getElementsByTagNameNS(ns, localName)[0]) || node.ownerDocument.createElementNS(ns, key);
 | |
|             } else {
 | |
|               element = (node.getElementsByTagName(localName)[0]) || node.ownerDocument.createElement(key);
 | |
|             }
 | |
|             node.appendChild(element);
 | |
|             mapObjOntoNode(element, (value), nsResolver);
 | |
|           }
 | |
|         } else {
 | |
|           if (ns) {
 | |
|             runtime.assert(valueType === "number" || valueType === "string", "attempting to map unsupported type '" + valueType + "' (key: " + key + ")");
 | |
|             node.setAttributeNS(ns, key, String(value));
 | |
|           }
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     this.mapObjOntoNode = mapObjOntoNode;
 | |
|     function cloneEvent(event) {
 | |
|       var e = Object.create(null);
 | |
|       Object.keys((event)).forEach(function(x) {
 | |
|         e[x] = event[x];
 | |
|       });
 | |
|       e.prototype = event.constructor.prototype;
 | |
|       return (e);
 | |
|     }
 | |
|     this.cloneEvent = cloneEvent;
 | |
|     this.getDirectChild = getDirectChild;
 | |
|     function init(self) {
 | |
|       var appVersion, webKitOrSafari, ie, window = runtime.getWindow();
 | |
|       if (window === null) {
 | |
|         return;
 | |
|       }
 | |
|       appVersion = window.navigator.appVersion.toLowerCase();
 | |
|       webKitOrSafari = appVersion.indexOf("chrome") === -1 && (appVersion.indexOf("applewebkit") !== -1 || appVersion.indexOf("safari") !== -1);
 | |
|       ie = appVersion.indexOf("msie") !== -1 || appVersion.indexOf("trident") !== -1;
 | |
|       if (webKitOrSafari || ie) {
 | |
|         self.containsNode = containsNodeForBrokenWebKit;
 | |
|       }
 | |
|     }
 | |
|     init(this);
 | |
|   };
 | |
|   core.DomUtils = new core.DomUtilsImpl;
 | |
| })();
 | |
| core.Cursor = function Cursor(document, memberId) {
 | |
|   var cursorns = "urn:webodf:names:cursor", cursorNode = document.createElementNS(cursorns, "cursor"), anchorNode = document.createElementNS(cursorns, "anchor"), forwardSelection, recentlyModifiedNodes = [], selectedRange = (document.createRange()), isCollapsed, domUtils = core.DomUtils;
 | |
|   function putIntoTextNode(node, container, offset) {
 | |
|     runtime.assert(Boolean(container), "putCursorIntoTextNode: invalid container");
 | |
|     var parent = container.parentNode;
 | |
|     runtime.assert(Boolean(parent), "putCursorIntoTextNode: container without parent");
 | |
|     runtime.assert(offset >= 0 && offset <= container.length, "putCursorIntoTextNode: offset is out of bounds");
 | |
|     if (offset === 0) {
 | |
|       parent.insertBefore(node, container);
 | |
|     } else {
 | |
|       if (offset === container.length) {
 | |
|         parent.insertBefore(node, container.nextSibling);
 | |
|       } else {
 | |
|         container.splitText(offset);
 | |
|         parent.insertBefore(node, container.nextSibling);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function removeNode(node) {
 | |
|     if (node.parentNode) {
 | |
|       recentlyModifiedNodes.push(node.previousSibling);
 | |
|       recentlyModifiedNodes.push(node.nextSibling);
 | |
|       node.parentNode.removeChild(node);
 | |
|     }
 | |
|   }
 | |
|   function putNode(node, container, offset) {
 | |
|     if (container.nodeType === Node.TEXT_NODE) {
 | |
|       putIntoTextNode(node, (container), offset);
 | |
|     } else {
 | |
|       if (container.nodeType === Node.ELEMENT_NODE) {
 | |
|         container.insertBefore(node, container.childNodes.item(offset));
 | |
|       }
 | |
|     }
 | |
|     recentlyModifiedNodes.push(node.previousSibling);
 | |
|     recentlyModifiedNodes.push(node.nextSibling);
 | |
|   }
 | |
|   function getStartNode() {
 | |
|     return forwardSelection ? anchorNode : cursorNode;
 | |
|   }
 | |
|   function getEndNode() {
 | |
|     return forwardSelection ? cursorNode : anchorNode;
 | |
|   }
 | |
|   this.getNode = function() {
 | |
|     return cursorNode;
 | |
|   };
 | |
|   this.getAnchorNode = function() {
 | |
|     return anchorNode.parentNode ? anchorNode : cursorNode;
 | |
|   };
 | |
|   this.getSelectedRange = function() {
 | |
|     if (isCollapsed) {
 | |
|       selectedRange.setStartBefore(cursorNode);
 | |
|       selectedRange.collapse(true);
 | |
|     } else {
 | |
|       selectedRange.setStartAfter(getStartNode());
 | |
|       selectedRange.setEndBefore(getEndNode());
 | |
|     }
 | |
|     return selectedRange;
 | |
|   };
 | |
|   this.setSelectedRange = function(range, isForwardSelection) {
 | |
|     if (selectedRange && selectedRange !== range) {
 | |
|       selectedRange.detach();
 | |
|     }
 | |
|     selectedRange = range;
 | |
|     forwardSelection = isForwardSelection !== false;
 | |
|     isCollapsed = range.collapsed;
 | |
|     if (range.collapsed) {
 | |
|       removeNode(anchorNode);
 | |
|       removeNode(cursorNode);
 | |
|       putNode(cursorNode, (range.startContainer), range.startOffset);
 | |
|     } else {
 | |
|       removeNode(anchorNode);
 | |
|       removeNode(cursorNode);
 | |
|       putNode(getEndNode(), (range.endContainer), range.endOffset);
 | |
|       putNode(getStartNode(), (range.startContainer), range.startOffset);
 | |
|     }
 | |
|     recentlyModifiedNodes.forEach(domUtils.normalizeTextNodes);
 | |
|     recentlyModifiedNodes.length = 0;
 | |
|   };
 | |
|   this.hasForwardSelection = function() {
 | |
|     return forwardSelection;
 | |
|   };
 | |
|   this.remove = function() {
 | |
|     removeNode(cursorNode);
 | |
|     recentlyModifiedNodes.forEach(domUtils.normalizeTextNodes);
 | |
|     recentlyModifiedNodes.length = 0;
 | |
|   };
 | |
|   function init() {
 | |
|     cursorNode.setAttributeNS(cursorns, "memberId", memberId);
 | |
|     anchorNode.setAttributeNS(cursorns, "memberId", memberId);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| core.Destroyable = function Destroyable() {
 | |
| };
 | |
| core.Destroyable.prototype.destroy = function(callback) {
 | |
| };
 | |
| core.EventSource = function() {
 | |
| };
 | |
| core.EventSource.prototype.subscribe = function(eventId, cb) {
 | |
| };
 | |
| core.EventSource.prototype.unsubscribe = function(eventId, cb) {
 | |
| };
 | |
| core.EventNotifier = function EventNotifier(eventIds) {
 | |
|   var eventListener = {};
 | |
|   this.emit = function(eventId, args) {
 | |
|     var i, subscribers;
 | |
|     runtime.assert(eventListener.hasOwnProperty(eventId), 'unknown event fired "' + eventId + '"');
 | |
|     subscribers = eventListener[eventId];
 | |
|     for (i = 0;i < subscribers.length;i += 1) {
 | |
|       subscribers[i](args);
 | |
|     }
 | |
|   };
 | |
|   this.subscribe = function(eventId, cb) {
 | |
|     runtime.assert(eventListener.hasOwnProperty(eventId), 'tried to subscribe to unknown event "' + eventId + '"');
 | |
|     eventListener[eventId].push(cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventId, cb) {
 | |
|     var cbIndex;
 | |
|     runtime.assert(eventListener.hasOwnProperty(eventId), 'tried to unsubscribe from unknown event "' + eventId + '"');
 | |
|     cbIndex = eventListener[eventId].indexOf(cb);
 | |
|     runtime.assert(cbIndex !== -1, 'tried to unsubscribe unknown callback from event "' + eventId + '"');
 | |
|     if (cbIndex !== -1) {
 | |
|       eventListener[eventId].splice(cbIndex, 1);
 | |
|     }
 | |
|   };
 | |
|   function register(eventId) {
 | |
|     runtime.assert(!eventListener.hasOwnProperty(eventId), 'Duplicated event ids: "' + eventId + '" registered more than once.');
 | |
|     eventListener[eventId] = [];
 | |
|   }
 | |
|   this.register = register;
 | |
|   function init() {
 | |
|     if (eventIds) {
 | |
|       eventIds.forEach(register);
 | |
|     }
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| core.ScheduledTask = function ScheduledTask(fn, scheduleTask, cancelTask) {
 | |
|   var timeoutId, scheduled = false, args = [], destroyed = false;
 | |
|   function cancel() {
 | |
|     if (scheduled) {
 | |
|       cancelTask(timeoutId);
 | |
|       scheduled = false;
 | |
|     }
 | |
|   }
 | |
|   function execute() {
 | |
|     cancel();
 | |
|     fn.apply(undefined, args);
 | |
|     args = null;
 | |
|   }
 | |
|   this.trigger = function() {
 | |
|     runtime.assert(destroyed === false, "Can't trigger destroyed ScheduledTask instance");
 | |
|     args = Array.prototype.slice.call(arguments);
 | |
|     if (!scheduled) {
 | |
|       scheduled = true;
 | |
|       timeoutId = scheduleTask(execute);
 | |
|     }
 | |
|   };
 | |
|   this.triggerImmediate = function() {
 | |
|     runtime.assert(destroyed === false, "Can't trigger destroyed ScheduledTask instance");
 | |
|     args = Array.prototype.slice.call(arguments);
 | |
|     execute();
 | |
|   };
 | |
|   this.processRequests = function() {
 | |
|     if (scheduled) {
 | |
|       execute();
 | |
|     }
 | |
|   };
 | |
|   this.cancel = cancel;
 | |
|   this.restart = function() {
 | |
|     runtime.assert(destroyed === false, "Can't trigger destroyed ScheduledTask instance");
 | |
|     cancel();
 | |
|     scheduled = true;
 | |
|     timeoutId = scheduleTask(execute);
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     cancel();
 | |
|     destroyed = true;
 | |
|     callback();
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   var redrawTasks;
 | |
|   function RedrawTasks() {
 | |
|     var callbacks = {};
 | |
|     this.requestRedrawTask = function(callback) {
 | |
|       var id = runtime.requestAnimationFrame(function() {
 | |
|         callback();
 | |
|         delete callbacks[id];
 | |
|       });
 | |
|       callbacks[id] = callback;
 | |
|       return id;
 | |
|     };
 | |
|     this.performRedraw = function() {
 | |
|       Object.keys(callbacks).forEach(function(id) {
 | |
|         callbacks[id]();
 | |
|         runtime.cancelAnimationFrame(parseInt(id, 10));
 | |
|       });
 | |
|       callbacks = {};
 | |
|     };
 | |
|     this.cancelRedrawTask = function(id) {
 | |
|       runtime.cancelAnimationFrame(id);
 | |
|       delete callbacks[id];
 | |
|     };
 | |
|   }
 | |
|   core.Task = {};
 | |
|   core.Task.SUPPRESS_MANUAL_PROCESSING = false;
 | |
|   core.Task.processTasks = function() {
 | |
|     if (!core.Task.SUPPRESS_MANUAL_PROCESSING) {
 | |
|       redrawTasks.performRedraw();
 | |
|     }
 | |
|   };
 | |
|   core.Task.createRedrawTask = function(callback) {
 | |
|     return new core.ScheduledTask(callback, redrawTasks.requestRedrawTask, redrawTasks.cancelRedrawTask);
 | |
|   };
 | |
|   core.Task.createTimeoutTask = function(callback, delay) {
 | |
|     return new core.ScheduledTask(callback, function(callback) {
 | |
|       return runtime.setTimeout(callback, delay);
 | |
|     }, runtime.clearTimeout);
 | |
|   };
 | |
|   function init() {
 | |
|     redrawTasks = new RedrawTasks;
 | |
|   }
 | |
|   init();
 | |
| })();
 | |
| core.EventSubscriptions = function() {
 | |
|   var subscriptions = [], frameEventNotifier = new core.EventNotifier, frameSubscriptions = {}, nextFrameEventId = 0;
 | |
|   function addSubscription(eventSource, eventid, callback) {
 | |
|     eventSource.subscribe(eventid, callback);
 | |
|     subscriptions.push({eventSource:eventSource, eventid:eventid, callback:callback});
 | |
|   }
 | |
|   this.addSubscription = addSubscription;
 | |
|   this.addFrameSubscription = function(eventSource, eventid, callback) {
 | |
|     var frameSubscription, frameEventId, eventFrameSubscriptions, i;
 | |
|     if (!frameSubscriptions.hasOwnProperty(eventid)) {
 | |
|       frameSubscriptions[eventid] = [];
 | |
|     }
 | |
|     eventFrameSubscriptions = frameSubscriptions[eventid];
 | |
|     for (i = 0;i < eventFrameSubscriptions.length;i += 1) {
 | |
|       if (eventFrameSubscriptions[i].eventSource === eventSource) {
 | |
|         frameSubscription = eventFrameSubscriptions[i];
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (!frameSubscription) {
 | |
|       frameEventId = "s" + nextFrameEventId;
 | |
|       nextFrameEventId += 1;
 | |
|       frameEventNotifier.register(frameEventId);
 | |
|       frameSubscription = {frameEventId:frameEventId, eventSource:eventSource, task:core.Task.createRedrawTask(function() {
 | |
|         frameEventNotifier.emit(frameEventId, undefined);
 | |
|       })};
 | |
|       eventFrameSubscriptions.push(frameSubscription);
 | |
|       addSubscription(eventSource, eventid, frameSubscription.task.trigger);
 | |
|     }
 | |
|     frameEventNotifier.subscribe(frameSubscription.frameEventId, callback);
 | |
|   };
 | |
|   function unsubscribeAll() {
 | |
|     var cleanup = [];
 | |
|     subscriptions.forEach(function(subscription) {
 | |
|       subscription.eventSource.unsubscribe(subscription.eventid, subscription.callback);
 | |
|     });
 | |
|     subscriptions.length = 0;
 | |
|     Object.keys(frameSubscriptions).forEach(function(eventId) {
 | |
|       frameSubscriptions[eventId].forEach(function(subscriber) {
 | |
|         cleanup.push(subscriber.task.destroy);
 | |
|       });
 | |
|       delete frameSubscriptions[eventId];
 | |
|     });
 | |
|     core.Async.destroyAll(cleanup, function() {
 | |
|     });
 | |
|     frameEventNotifier = new core.EventNotifier;
 | |
|   }
 | |
|   this.unsubscribeAll = unsubscribeAll;
 | |
|   this.destroy = function(callback) {
 | |
|     unsubscribeAll();
 | |
|     callback();
 | |
|   };
 | |
| };
 | |
| core.LazyProperty = function(valueLoader) {
 | |
|   var cachedValue, valueLoaded = false;
 | |
|   this.value = function() {
 | |
|     if (!valueLoaded) {
 | |
|       cachedValue = valueLoader();
 | |
|       valueLoaded = true;
 | |
|     }
 | |
|     return cachedValue;
 | |
|   };
 | |
|   this.reset = function() {
 | |
|     valueLoaded = false;
 | |
|   };
 | |
| };
 | |
| core.LoopWatchDog = function LoopWatchDog(timeout, maxChecks) {
 | |
|   var startTime = Date.now(), checks = 0;
 | |
|   function check() {
 | |
|     var t;
 | |
|     if (timeout) {
 | |
|       t = Date.now();
 | |
|       if (t - startTime > timeout) {
 | |
|         runtime.log("alert", "watchdog timeout");
 | |
|         throw "timeout!";
 | |
|       }
 | |
|     }
 | |
|     if (maxChecks > 0) {
 | |
|       checks += 1;
 | |
|       if (checks > maxChecks) {
 | |
|         runtime.log("alert", "watchdog loop overflow");
 | |
|         throw "loop overflow";
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   this.check = check;
 | |
| };
 | |
| core.NodeFilterChain = function(filters) {
 | |
|   var FILTER_REJECT = NodeFilter.FILTER_REJECT, FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT;
 | |
|   this.acceptNode = function(node) {
 | |
|     var i;
 | |
|     for (i = 0;i < filters.length;i += 1) {
 | |
|       if (filters[i].acceptNode(node) === FILTER_REJECT) {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|     }
 | |
|     return FILTER_ACCEPT;
 | |
|   };
 | |
| };
 | |
| core.PositionIterator = function PositionIterator(root, whatToShow, filter, expandEntityReferences) {
 | |
|   var self = this, walker, currentPos, nodeFilter, TEXT_NODE = Node.TEXT_NODE, ELEMENT_NODE = Node.ELEMENT_NODE, FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT, FILTER_REJECT = NodeFilter.FILTER_REJECT;
 | |
|   function EmptyTextNodeFilter() {
 | |
|     this.acceptNode = function(node) {
 | |
|       var text = (node);
 | |
|       if (!node || node.nodeType === TEXT_NODE && text.length === 0) {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|       return FILTER_ACCEPT;
 | |
|     };
 | |
|   }
 | |
|   function FilteredEmptyTextNodeFilter(filter) {
 | |
|     this.acceptNode = function(node) {
 | |
|       var text = (node);
 | |
|       if (!node || node.nodeType === TEXT_NODE && text.length === 0) {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|       return filter.acceptNode(node);
 | |
|     };
 | |
|   }
 | |
|   this.nextPosition = function() {
 | |
|     var currentNode = walker.currentNode, nodeType = currentNode.nodeType, text = (currentNode);
 | |
|     if (currentNode === root) {
 | |
|       return false;
 | |
|     }
 | |
|     if (currentPos === 0 && nodeType === ELEMENT_NODE) {
 | |
|       if (walker.firstChild() === null) {
 | |
|         currentPos = 1;
 | |
|       }
 | |
|     } else {
 | |
|       if (nodeType === TEXT_NODE && currentPos + 1 < text.length) {
 | |
|         currentPos += 1;
 | |
|       } else {
 | |
|         if (walker.nextSibling() !== null) {
 | |
|           currentPos = 0;
 | |
|         } else {
 | |
|           if (walker.parentNode()) {
 | |
|             currentPos = 1;
 | |
|           } else {
 | |
|             return false;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return true;
 | |
|   };
 | |
|   function setAtEnd() {
 | |
|     var text = (walker.currentNode), type = text.nodeType;
 | |
|     if (type === TEXT_NODE) {
 | |
|       currentPos = text.length - 1;
 | |
|     } else {
 | |
|       currentPos = type === ELEMENT_NODE ? 1 : 0;
 | |
|     }
 | |
|   }
 | |
|   function previousNode() {
 | |
|     if (walker.previousSibling() === null) {
 | |
|       if (!walker.parentNode() || walker.currentNode === root) {
 | |
|         walker.firstChild();
 | |
|         return false;
 | |
|       }
 | |
|       currentPos = 0;
 | |
|     } else {
 | |
|       setAtEnd();
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   this.previousPosition = function() {
 | |
|     var moved = true, currentNode = walker.currentNode;
 | |
|     if (currentPos === 0) {
 | |
|       moved = previousNode();
 | |
|     } else {
 | |
|       if (currentNode.nodeType === TEXT_NODE) {
 | |
|         currentPos -= 1;
 | |
|       } else {
 | |
|         if (walker.lastChild() !== null) {
 | |
|           setAtEnd();
 | |
|         } else {
 | |
|           if (currentNode === root) {
 | |
|             moved = false;
 | |
|           } else {
 | |
|             currentPos = 0;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return moved;
 | |
|   };
 | |
|   this.previousNode = previousNode;
 | |
|   this.container = function() {
 | |
|     var n = (walker.currentNode), t = n.nodeType;
 | |
|     if (currentPos === 0 && t !== TEXT_NODE) {
 | |
|       n = (n.parentNode);
 | |
|     }
 | |
|     return n;
 | |
|   };
 | |
|   this.rightNode = function() {
 | |
|     var n = walker.currentNode, text = (n), nodeType = n.nodeType;
 | |
|     if (nodeType === TEXT_NODE && currentPos === text.length) {
 | |
|       n = n.nextSibling;
 | |
|       while (n && nodeFilter(n) !== FILTER_ACCEPT) {
 | |
|         n = n.nextSibling;
 | |
|       }
 | |
|     } else {
 | |
|       if (nodeType === ELEMENT_NODE && currentPos === 1) {
 | |
|         n = null;
 | |
|       }
 | |
|     }
 | |
|     return n;
 | |
|   };
 | |
|   this.leftNode = function() {
 | |
|     var n = walker.currentNode;
 | |
|     if (currentPos === 0) {
 | |
|       n = n.previousSibling;
 | |
|       while (n && nodeFilter(n) !== FILTER_ACCEPT) {
 | |
|         n = n.previousSibling;
 | |
|       }
 | |
|     } else {
 | |
|       if (n.nodeType === ELEMENT_NODE) {
 | |
|         n = n.lastChild;
 | |
|         while (n && nodeFilter(n) !== FILTER_ACCEPT) {
 | |
|           n = n.previousSibling;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return n;
 | |
|   };
 | |
|   this.getCurrentNode = function() {
 | |
|     var n = (walker.currentNode);
 | |
|     return n;
 | |
|   };
 | |
|   this.unfilteredDomOffset = function() {
 | |
|     if (walker.currentNode.nodeType === TEXT_NODE) {
 | |
|       return currentPos;
 | |
|     }
 | |
|     var c = 0, n = walker.currentNode;
 | |
|     if (currentPos === 1) {
 | |
|       n = n.lastChild;
 | |
|     } else {
 | |
|       n = n.previousSibling;
 | |
|     }
 | |
|     while (n) {
 | |
|       c += 1;
 | |
|       n = n.previousSibling;
 | |
|     }
 | |
|     return c;
 | |
|   };
 | |
|   this.getPreviousSibling = function() {
 | |
|     var currentNode = walker.currentNode, sibling = walker.previousSibling();
 | |
|     walker.currentNode = currentNode;
 | |
|     return sibling;
 | |
|   };
 | |
|   this.getNextSibling = function() {
 | |
|     var currentNode = walker.currentNode, sibling = walker.nextSibling();
 | |
|     walker.currentNode = currentNode;
 | |
|     return sibling;
 | |
|   };
 | |
|   function moveToAcceptedNode() {
 | |
|     var node = walker.currentNode, filterResult, moveResult;
 | |
|     filterResult = nodeFilter(node);
 | |
|     if (node !== root) {
 | |
|       node = node.parentNode;
 | |
|       while (node && node !== root) {
 | |
|         if (nodeFilter(node) === FILTER_REJECT) {
 | |
|           walker.currentNode = node;
 | |
|           filterResult = FILTER_REJECT;
 | |
|         }
 | |
|         node = node.parentNode;
 | |
|       }
 | |
|     }
 | |
|     if (filterResult === FILTER_REJECT) {
 | |
|       currentPos = walker.currentNode.nodeType === TEXT_NODE ? (node).length : 1;
 | |
|       moveResult = self.nextPosition();
 | |
|     } else {
 | |
|       if (filterResult === FILTER_ACCEPT) {
 | |
|         moveResult = true;
 | |
|       } else {
 | |
|         moveResult = self.nextPosition();
 | |
|       }
 | |
|     }
 | |
|     if (moveResult) {
 | |
|       runtime.assert(nodeFilter(walker.currentNode) === FILTER_ACCEPT, "moveToAcceptedNode did not result in walker being on an accepted node");
 | |
|     }
 | |
|     return moveResult;
 | |
|   }
 | |
|   this.setPositionBeforeElement = function(element) {
 | |
|     runtime.assert(Boolean(element), "setPositionBeforeElement called without element");
 | |
|     walker.currentNode = element;
 | |
|     currentPos = 0;
 | |
|     return moveToAcceptedNode();
 | |
|   };
 | |
|   this.setUnfilteredPosition = function(container, offset) {
 | |
|     var text;
 | |
|     runtime.assert(Boolean(container), "PositionIterator.setUnfilteredPosition called without container");
 | |
|     walker.currentNode = container;
 | |
|     if (container.nodeType === TEXT_NODE) {
 | |
|       currentPos = offset;
 | |
|       text = (container);
 | |
|       runtime.assert(offset <= text.length, "Error in setPosition: " + offset + " > " + text.length);
 | |
|       runtime.assert(offset >= 0, "Error in setPosition: " + offset + " < 0");
 | |
|       if (offset === text.length) {
 | |
|         if (walker.nextSibling()) {
 | |
|           currentPos = 0;
 | |
|         } else {
 | |
|           if (walker.parentNode()) {
 | |
|             currentPos = 1;
 | |
|           } else {
 | |
|             runtime.assert(false, "Error in setUnfilteredPosition: position not valid.");
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       if (offset < container.childNodes.length) {
 | |
|         walker.currentNode = (container.childNodes.item(offset));
 | |
|         currentPos = 0;
 | |
|       } else {
 | |
|         currentPos = 1;
 | |
|       }
 | |
|     }
 | |
|     return moveToAcceptedNode();
 | |
|   };
 | |
|   this.moveToEnd = function() {
 | |
|     walker.currentNode = root;
 | |
|     currentPos = 1;
 | |
|   };
 | |
|   this.moveToEndOfNode = function(node) {
 | |
|     var text;
 | |
|     if (node.nodeType === TEXT_NODE) {
 | |
|       text = (node);
 | |
|       self.setUnfilteredPosition(text, text.length);
 | |
|     } else {
 | |
|       walker.currentNode = node;
 | |
|       currentPos = 1;
 | |
|     }
 | |
|   };
 | |
|   this.isBeforeNode = function() {
 | |
|     return currentPos === 0;
 | |
|   };
 | |
|   this.getNodeFilter = function() {
 | |
|     return nodeFilter;
 | |
|   };
 | |
|   function init() {
 | |
|     var f;
 | |
|     if (filter) {
 | |
|       f = new FilteredEmptyTextNodeFilter(filter);
 | |
|     } else {
 | |
|       f = new EmptyTextNodeFilter;
 | |
|     }
 | |
|     nodeFilter = (f.acceptNode);
 | |
|     nodeFilter.acceptNode = nodeFilter;
 | |
|     whatToShow = whatToShow || NodeFilter.SHOW_ALL;
 | |
|     runtime.assert(root.nodeType !== Node.TEXT_NODE, "Internet Explorer doesn't allow tree walker roots to be text nodes");
 | |
|     walker = root.ownerDocument.createTreeWalker(root, whatToShow, nodeFilter, expandEntityReferences);
 | |
|     currentPos = 0;
 | |
|     if (walker.firstChild() === null) {
 | |
|       currentPos = 1;
 | |
|     }
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| core.PositionFilter = function PositionFilter() {
 | |
| };
 | |
| core.PositionFilter.FilterResult = {FILTER_ACCEPT:1, FILTER_REJECT:2, FILTER_SKIP:3};
 | |
| core.PositionFilter.prototype.acceptPosition = function(point) {
 | |
| };
 | |
| core.PositionFilterChain = function PositionFilterChain() {
 | |
|   var filterChain = [], FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
 | |
|   this.acceptPosition = function(iterator) {
 | |
|     var i;
 | |
|     for (i = 0;i < filterChain.length;i += 1) {
 | |
|       if (filterChain[i].acceptPosition(iterator) === FILTER_REJECT) {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|     }
 | |
|     return FILTER_ACCEPT;
 | |
|   };
 | |
|   this.addFilter = function(filterInstance) {
 | |
|     filterChain.push(filterInstance);
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   function createRawInflateSingleton() {
 | |
|     var pako;
 | |
|     (function(e) {
 | |
|       pako = e();
 | |
|     })(function() {
 | |
|       var module, exports;
 | |
|       return function e(t, n, r) {
 | |
|         function s(o, u) {
 | |
|           if (!n[o]) {
 | |
|             if (!t[o]) {
 | |
|               throw new Error("Cannot find module '" + o + "'");
 | |
|             }
 | |
|             var f = n[o] = {exports:{}};
 | |
|             t[o][0].call(f.exports, function(e) {
 | |
|               var n = t[o][1][e];
 | |
|               return s(n ? n : e);
 | |
|             }, f, f.exports, e, t, n, r);
 | |
|           }
 | |
|           return n[o].exports;
 | |
|         }
 | |
|         for (var o = 0;o < r.length;o++) {
 | |
|           s(r[o]);
 | |
|         }
 | |
|         return s;
 | |
|       }({1:[function(_dereq_, module, exports) {
 | |
|         var zlib_inflate = _dereq_("./zlib/inflate.js");
 | |
|         var utils = _dereq_("./utils/common");
 | |
|         var strings = _dereq_("./utils/strings");
 | |
|         var c = _dereq_("./zlib/constants");
 | |
|         var msg = _dereq_("./zlib/messages");
 | |
|         var zstream = _dereq_("./zlib/zstream");
 | |
|         var gzheader = _dereq_("./zlib/gzheader");
 | |
|         var Inflate = function(options) {
 | |
|           this.options = utils.assign({chunkSize:16384, windowBits:0, to:""}, options || {});
 | |
|           var opt = this.options;
 | |
|           if (opt.raw && opt.windowBits >= 0 && opt.windowBits < 16) {
 | |
|             opt.windowBits = -opt.windowBits;
 | |
|             if (opt.windowBits === 0) {
 | |
|               opt.windowBits = -15;
 | |
|             }
 | |
|           }
 | |
|           if (opt.windowBits >= 0 && opt.windowBits < 16 && !(options && options.windowBits)) {
 | |
|             opt.windowBits += 32;
 | |
|           }
 | |
|           if (opt.windowBits > 15 && opt.windowBits < 48) {
 | |
|             if ((opt.windowBits & 15) === 0) {
 | |
|               opt.windowBits |= 15;
 | |
|             }
 | |
|           }
 | |
|           this.err = 0;
 | |
|           this.msg = "";
 | |
|           this.ended = false;
 | |
|           this.chunks = [];
 | |
|           this.strm = new zstream;
 | |
|           this.strm.avail_out = 0;
 | |
|           var status = zlib_inflate.inflateInit2(this.strm, opt.windowBits);
 | |
|           if (status !== c.Z_OK) {
 | |
|             throw new Error(msg[status]);
 | |
|           }
 | |
|           this.header = new gzheader;
 | |
|           zlib_inflate.inflateGetHeader(this.strm, this.header);
 | |
|         };
 | |
|         Inflate.prototype.push = function(data, mode) {
 | |
|           var strm = this.strm;
 | |
|           var chunkSize = this.options.chunkSize;
 | |
|           var status, _mode;
 | |
|           var next_out_utf8, tail, utf8str;
 | |
|           if (this.ended) {
 | |
|             return false;
 | |
|           }
 | |
|           _mode = mode === ~~mode ? mode : mode === true ? c.Z_FINISH : c.Z_NO_FLUSH;
 | |
|           if (typeof data === "string") {
 | |
|             strm.input = strings.binstring2buf(data);
 | |
|           } else {
 | |
|             strm.input = data;
 | |
|           }
 | |
|           strm.next_in = 0;
 | |
|           strm.avail_in = strm.input.length;
 | |
|           do {
 | |
|             if (strm.avail_out === 0) {
 | |
|               strm.output = new utils.Buf8(chunkSize);
 | |
|               strm.next_out = 0;
 | |
|               strm.avail_out = chunkSize;
 | |
|             }
 | |
|             status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);
 | |
|             if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
 | |
|               this.onEnd(status);
 | |
|               this.ended = true;
 | |
|               return false;
 | |
|             }
 | |
|             if (strm.next_out) {
 | |
|               if (strm.avail_out === 0 || status === c.Z_STREAM_END || strm.avail_in === 0 && _mode === c.Z_FINISH) {
 | |
|                 if (this.options.to === "string") {
 | |
|                   next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
 | |
|                   tail = strm.next_out - next_out_utf8;
 | |
|                   utf8str = strings.buf2string(strm.output, next_out_utf8);
 | |
|                   strm.next_out = tail;
 | |
|                   strm.avail_out = chunkSize - tail;
 | |
|                   if (tail) {
 | |
|                     utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0);
 | |
|                   }
 | |
|                   this.onData(utf8str);
 | |
|                 } else {
 | |
|                   this.onData(utils.shrinkBuf(strm.output, strm.next_out));
 | |
|                 }
 | |
|               }
 | |
|             }
 | |
|           } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);
 | |
|           if (status === c.Z_STREAM_END) {
 | |
|             _mode = c.Z_FINISH;
 | |
|           }
 | |
|           if (_mode === c.Z_FINISH) {
 | |
|             status = zlib_inflate.inflateEnd(this.strm);
 | |
|             this.onEnd(status);
 | |
|             this.ended = true;
 | |
|             return status === c.Z_OK;
 | |
|           }
 | |
|           return true;
 | |
|         };
 | |
|         Inflate.prototype.onData = function(chunk) {
 | |
|           this.chunks.push(chunk);
 | |
|         };
 | |
|         Inflate.prototype.onEnd = function(status) {
 | |
|           if (status === c.Z_OK) {
 | |
|             if (this.options.to === "string") {
 | |
|               this.result = this.chunks.join("");
 | |
|             } else {
 | |
|               this.result = utils.flattenChunks(this.chunks);
 | |
|             }
 | |
|           }
 | |
|           this.chunks = [];
 | |
|           this.err = status;
 | |
|           this.msg = this.strm.msg;
 | |
|         };
 | |
|         function inflate(input, options) {
 | |
|           var inflator = new Inflate(options);
 | |
|           inflator.push(input, true);
 | |
|           if (inflator.err) {
 | |
|             throw inflator.msg;
 | |
|           }
 | |
|           return inflator.result;
 | |
|         }
 | |
|         function inflateRaw(input, options) {
 | |
|           options = options || {};
 | |
|           options.raw = true;
 | |
|           return inflate(input, options);
 | |
|         }
 | |
|         exports.Inflate = Inflate;
 | |
|         exports.inflate = inflate;
 | |
|         exports.inflateRaw = inflateRaw;
 | |
|         exports.ungzip = inflate;
 | |
|       }, {"./utils/common":2, "./utils/strings":3, "./zlib/constants":5, "./zlib/gzheader":7, "./zlib/inflate.js":9, "./zlib/messages":11, "./zlib/zstream":12}], 2:[function(_dereq_, module, exports) {
 | |
|         var TYPED_OK = typeof Uint8Array !== "undefined" && typeof Uint16Array !== "undefined" && typeof Int32Array !== "undefined";
 | |
|         exports.assign = function(obj) {
 | |
|           var sources = Array.prototype.slice.call(arguments, 1);
 | |
|           while (sources.length) {
 | |
|             var source = sources.shift();
 | |
|             if (!source) {
 | |
|               continue;
 | |
|             }
 | |
|             if (typeof source !== "object") {
 | |
|               throw new TypeError(source + "must be non-object");
 | |
|             }
 | |
|             for (var p in source) {
 | |
|               if (source.hasOwnProperty(p)) {
 | |
|                 obj[p] = source[p];
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           return obj;
 | |
|         };
 | |
|         exports.shrinkBuf = function(buf, size) {
 | |
|           if (buf.length === size) {
 | |
|             return buf;
 | |
|           }
 | |
|           if (buf.subarray) {
 | |
|             return buf.subarray(0, size);
 | |
|           }
 | |
|           buf.length = size;
 | |
|           return buf;
 | |
|         };
 | |
|         var fnTyped = {arraySet:function(dest, src, src_offs, len, dest_offs) {
 | |
|           if (src.subarray && dest.subarray) {
 | |
|             dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
 | |
|             return;
 | |
|           }
 | |
|           for (var i = 0;i < len;i++) {
 | |
|             dest[dest_offs + i] = src[src_offs + i];
 | |
|           }
 | |
|         }, flattenChunks:function(chunks) {
 | |
|           var i, l, len, pos, chunk, result;
 | |
|           len = 0;
 | |
|           for (i = 0, l = chunks.length;i < l;i++) {
 | |
|             len += chunks[i].length;
 | |
|           }
 | |
|           result = new Uint8Array(len);
 | |
|           pos = 0;
 | |
|           for (i = 0, l = chunks.length;i < l;i++) {
 | |
|             chunk = chunks[i];
 | |
|             result.set(chunk, pos);
 | |
|             pos += chunk.length;
 | |
|           }
 | |
|           return result;
 | |
|         }};
 | |
|         var fnUntyped = {arraySet:function(dest, src, src_offs, len, dest_offs) {
 | |
|           for (var i = 0;i < len;i++) {
 | |
|             dest[dest_offs + i] = src[src_offs + i];
 | |
|           }
 | |
|         }, flattenChunks:function(chunks) {
 | |
|           return [].concat.apply([], chunks);
 | |
|         }};
 | |
|         exports.setTyped = function(on) {
 | |
|           if (on) {
 | |
|             exports.Buf8 = Uint8Array;
 | |
|             exports.Buf16 = Uint16Array;
 | |
|             exports.Buf32 = Int32Array;
 | |
|             exports.assign(exports, fnTyped);
 | |
|           } else {
 | |
|             exports.Buf8 = Array;
 | |
|             exports.Buf16 = Array;
 | |
|             exports.Buf32 = Array;
 | |
|             exports.assign(exports, fnUntyped);
 | |
|           }
 | |
|         };
 | |
|         exports.setTyped(TYPED_OK);
 | |
|       }, {}], 3:[function(_dereq_, module, exports) {
 | |
|         var utils = _dereq_("./common");
 | |
|         var STR_APPLY_OK = true;
 | |
|         var STR_APPLY_UIA_OK = true;
 | |
|         try {
 | |
|           String.fromCharCode.apply(null, [0]);
 | |
|         } catch (__) {
 | |
|           STR_APPLY_OK = false;
 | |
|         }
 | |
|         try {
 | |
|           String.fromCharCode.apply(null, new Uint8Array(1));
 | |
|         } catch (__) {
 | |
|           STR_APPLY_UIA_OK = false;
 | |
|         }
 | |
|         var _utf8len = new utils.Buf8(256);
 | |
|         for (var i = 0;i < 256;i++) {
 | |
|           _utf8len[i] = i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1;
 | |
|         }
 | |
|         _utf8len[254] = _utf8len[254] = 1;
 | |
|         exports.string2buf = function(str) {
 | |
|           var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
 | |
|           for (m_pos = 0;m_pos < str_len;m_pos++) {
 | |
|             c = str.charCodeAt(m_pos);
 | |
|             if ((c & 64512) === 55296 && m_pos + 1 < str_len) {
 | |
|               c2 = str.charCodeAt(m_pos + 1);
 | |
|               if ((c2 & 64512) === 56320) {
 | |
|                 c = 65536 + (c - 55296 << 10) + (c2 - 56320);
 | |
|                 m_pos++;
 | |
|               }
 | |
|             }
 | |
|             buf_len += c < 128 ? 1 : c < 2048 ? 2 : c < 65536 ? 3 : 4;
 | |
|           }
 | |
|           buf = new utils.Buf8(buf_len);
 | |
|           for (i = 0, m_pos = 0;i < buf_len;m_pos++) {
 | |
|             c = str.charCodeAt(m_pos);
 | |
|             if ((c & 64512) === 55296 && m_pos + 1 < str_len) {
 | |
|               c2 = str.charCodeAt(m_pos + 1);
 | |
|               if ((c2 & 64512) === 56320) {
 | |
|                 c = 65536 + (c - 55296 << 10) + (c2 - 56320);
 | |
|                 m_pos++;
 | |
|               }
 | |
|             }
 | |
|             if (c < 128) {
 | |
|               buf[i++] = c;
 | |
|             } else {
 | |
|               if (c < 2048) {
 | |
|                 buf[i++] = 192 | c >>> 6;
 | |
|                 buf[i++] = 128 | c & 63;
 | |
|               } else {
 | |
|                 if (c < 65536) {
 | |
|                   buf[i++] = 224 | c >>> 12;
 | |
|                   buf[i++] = 128 | c >>> 6 & 63;
 | |
|                   buf[i++] = 128 | c & 63;
 | |
|                 } else {
 | |
|                   buf[i++] = 240 | c >>> 18;
 | |
|                   buf[i++] = 128 | c >>> 12 & 63;
 | |
|                   buf[i++] = 128 | c >>> 6 & 63;
 | |
|                   buf[i++] = 128 | c & 63;
 | |
|                 }
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           return buf;
 | |
|         };
 | |
|         function buf2binstring(buf, len) {
 | |
|           if (len < 65537) {
 | |
|             if (buf.subarray && STR_APPLY_UIA_OK || !buf.subarray && STR_APPLY_OK) {
 | |
|               return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
 | |
|             }
 | |
|           }
 | |
|           var result = "";
 | |
|           for (var i = 0;i < len;i++) {
 | |
|             result += String.fromCharCode(buf[i]);
 | |
|           }
 | |
|           return result;
 | |
|         }
 | |
|         exports.buf2binstring = function(buf) {
 | |
|           return buf2binstring(buf, buf.length);
 | |
|         };
 | |
|         exports.binstring2buf = function(str) {
 | |
|           var buf = new utils.Buf8(str.length);
 | |
|           for (var i = 0, len = buf.length;i < len;i++) {
 | |
|             buf[i] = str.charCodeAt(i);
 | |
|           }
 | |
|           return buf;
 | |
|         };
 | |
|         exports.buf2string = function(buf, max) {
 | |
|           var i, out, c, c_len;
 | |
|           var len = max || buf.length;
 | |
|           var utf16buf = new Array(len * 2);
 | |
|           for (out = 0, i = 0;i < len;) {
 | |
|             c = buf[i++];
 | |
|             if (c < 128) {
 | |
|               utf16buf[out++] = c;
 | |
|               continue;
 | |
|             }
 | |
|             c_len = _utf8len[c];
 | |
|             if (c_len > 4) {
 | |
|               utf16buf[out++] = 65533;
 | |
|               i += c_len - 1;
 | |
|               continue;
 | |
|             }
 | |
|             c &= c_len === 2 ? 31 : c_len === 3 ? 15 : 7;
 | |
|             while (c_len > 1 && i < len) {
 | |
|               c = c << 6 | buf[i++] & 63;
 | |
|               c_len--;
 | |
|             }
 | |
|             if (c_len > 1) {
 | |
|               utf16buf[out++] = 65533;
 | |
|               continue;
 | |
|             }
 | |
|             if (c < 65536) {
 | |
|               utf16buf[out++] = c;
 | |
|             } else {
 | |
|               c -= 65536;
 | |
|               utf16buf[out++] = 55296 | c >> 10 & 1023;
 | |
|               utf16buf[out++] = 56320 | c & 1023;
 | |
|             }
 | |
|           }
 | |
|           return buf2binstring(utf16buf, out);
 | |
|         };
 | |
|         exports.utf8border = function(buf, max) {
 | |
|           var pos;
 | |
|           max = max || buf.length;
 | |
|           if (max > buf.length) {
 | |
|             max = buf.length;
 | |
|           }
 | |
|           pos = max - 1;
 | |
|           while (pos >= 0 && (buf[pos] & 192) === 128) {
 | |
|             pos--;
 | |
|           }
 | |
|           if (pos < 0) {
 | |
|             return max;
 | |
|           }
 | |
|           if (pos === 0) {
 | |
|             return max;
 | |
|           }
 | |
|           return pos + _utf8len[buf[pos]] > max ? pos : max;
 | |
|         };
 | |
|       }, {"./common":2}], 4:[function(_dereq_, module, exports) {
 | |
|         function adler32(adler, buf, len, pos) {
 | |
|           var s1 = adler & 65535 | 0, s2 = adler >>> 16 & 65535 | 0, n = 0;
 | |
|           while (len !== 0) {
 | |
|             n = len > 2E3 ? 2E3 : len;
 | |
|             len -= n;
 | |
|             do {
 | |
|               s1 = s1 + buf[pos++] | 0;
 | |
|               s2 = s2 + s1 | 0;
 | |
|             } while (--n);
 | |
|             s1 %= 65521;
 | |
|             s2 %= 65521;
 | |
|           }
 | |
|           return s1 | s2 << 16 | 0;
 | |
|         }
 | |
|         module.exports = adler32;
 | |
|       }, {}], 5:[function(_dereq_, module, exports) {
 | |
|         module.exports = {Z_NO_FLUSH:0, Z_PARTIAL_FLUSH:1, Z_SYNC_FLUSH:2, Z_FULL_FLUSH:3, Z_FINISH:4, Z_BLOCK:5, Z_TREES:6, Z_OK:0, Z_STREAM_END:1, Z_NEED_DICT:2, Z_ERRNO:-1, Z_STREAM_ERROR:-2, Z_DATA_ERROR:-3, Z_BUF_ERROR:-5, Z_NO_COMPRESSION:0, Z_BEST_SPEED:1, Z_BEST_COMPRESSION:9, Z_DEFAULT_COMPRESSION:-1, Z_FILTERED:1, Z_HUFFMAN_ONLY:2, Z_RLE:3, Z_FIXED:4, Z_DEFAULT_STRATEGY:0, Z_BINARY:0, Z_TEXT:1, Z_UNKNOWN:2, Z_DEFLATED:8};
 | |
|       }, {}], 6:[function(_dereq_, module, exports) {
 | |
|         function makeTable() {
 | |
|           var c, table = [];
 | |
|           for (var n = 0;n < 256;n++) {
 | |
|             c = n;
 | |
|             for (var k = 0;k < 8;k++) {
 | |
|               c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
 | |
|             }
 | |
|             table[n] = c;
 | |
|           }
 | |
|           return table;
 | |
|         }
 | |
|         var crcTable = makeTable();
 | |
|         function crc32(crc, buf, len, pos) {
 | |
|           var t = crcTable, end = pos + len;
 | |
|           crc = crc ^ -1;
 | |
|           for (var i = pos;i < end;i++) {
 | |
|             crc = crc >>> 8 ^ t[(crc ^ buf[i]) & 255];
 | |
|           }
 | |
|           return crc ^ -1;
 | |
|         }
 | |
|         module.exports = crc32;
 | |
|       }, {}], 7:[function(_dereq_, module, exports) {
 | |
|         function GZheader() {
 | |
|           this.text = 0;
 | |
|           this.time = 0;
 | |
|           this.xflags = 0;
 | |
|           this.os = 0;
 | |
|           this.extra = null;
 | |
|           this.extra_len = 0;
 | |
|           this.name = "";
 | |
|           this.comment = "";
 | |
|           this.hcrc = 0;
 | |
|           this.done = false;
 | |
|         }
 | |
|         module.exports = GZheader;
 | |
|       }, {}], 8:[function(_dereq_, module, exports) {
 | |
|         var BAD = 30;
 | |
|         var TYPE = 12;
 | |
|         module.exports = function inflate_fast(strm, start) {
 | |
|           var state;
 | |
|           var _in;
 | |
|           var last;
 | |
|           var _out;
 | |
|           var beg;
 | |
|           var end;
 | |
|           var dmax;
 | |
|           var wsize;
 | |
|           var whave;
 | |
|           var wnext;
 | |
|           var window;
 | |
|           var hold;
 | |
|           var bits;
 | |
|           var lcode;
 | |
|           var dcode;
 | |
|           var lmask;
 | |
|           var dmask;
 | |
|           var here;
 | |
|           var op;
 | |
|           var len;
 | |
|           var dist;
 | |
|           var from;
 | |
|           var from_source;
 | |
|           var input, output;
 | |
|           state = strm.state;
 | |
|           _in = strm.next_in;
 | |
|           input = strm.input;
 | |
|           last = _in + (strm.avail_in - 5);
 | |
|           _out = strm.next_out;
 | |
|           output = strm.output;
 | |
|           beg = _out - (start - strm.avail_out);
 | |
|           end = _out + (strm.avail_out - 257);
 | |
|           dmax = state.dmax;
 | |
|           wsize = state.wsize;
 | |
|           whave = state.whave;
 | |
|           wnext = state.wnext;
 | |
|           window = state.window;
 | |
|           hold = state.hold;
 | |
|           bits = state.bits;
 | |
|           lcode = state.lencode;
 | |
|           dcode = state.distcode;
 | |
|           lmask = (1 << state.lenbits) - 1;
 | |
|           dmask = (1 << state.distbits) - 1;
 | |
|           top: do {
 | |
|             if (bits < 15) {
 | |
|               hold += input[_in++] << bits;
 | |
|               bits += 8;
 | |
|               hold += input[_in++] << bits;
 | |
|               bits += 8;
 | |
|             }
 | |
|             here = lcode[hold & lmask];
 | |
|             dolen: for (;;) {
 | |
|               op = here >>> 24;
 | |
|               hold >>>= op;
 | |
|               bits -= op;
 | |
|               op = here >>> 16 & 255;
 | |
|               if (op === 0) {
 | |
|                 output[_out++] = here & 65535;
 | |
|               } else {
 | |
|                 if (op & 16) {
 | |
|                   len = here & 65535;
 | |
|                   op &= 15;
 | |
|                   if (op) {
 | |
|                     if (bits < op) {
 | |
|                       hold += input[_in++] << bits;
 | |
|                       bits += 8;
 | |
|                     }
 | |
|                     len += hold & (1 << op) - 1;
 | |
|                     hold >>>= op;
 | |
|                     bits -= op;
 | |
|                   }
 | |
|                   if (bits < 15) {
 | |
|                     hold += input[_in++] << bits;
 | |
|                     bits += 8;
 | |
|                     hold += input[_in++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   here = dcode[hold & dmask];
 | |
|                   dodist: for (;;) {
 | |
|                     op = here >>> 24;
 | |
|                     hold >>>= op;
 | |
|                     bits -= op;
 | |
|                     op = here >>> 16 & 255;
 | |
|                     if (op & 16) {
 | |
|                       dist = here & 65535;
 | |
|                       op &= 15;
 | |
|                       if (bits < op) {
 | |
|                         hold += input[_in++] << bits;
 | |
|                         bits += 8;
 | |
|                         if (bits < op) {
 | |
|                           hold += input[_in++] << bits;
 | |
|                           bits += 8;
 | |
|                         }
 | |
|                       }
 | |
|                       dist += hold & (1 << op) - 1;
 | |
|                       if (dist > dmax) {
 | |
|                         strm.msg = "invalid distance too far back";
 | |
|                         state.mode = BAD;
 | |
|                         break top;
 | |
|                       }
 | |
|                       hold >>>= op;
 | |
|                       bits -= op;
 | |
|                       op = _out - beg;
 | |
|                       if (dist > op) {
 | |
|                         op = dist - op;
 | |
|                         if (op > whave) {
 | |
|                           if (state.sane) {
 | |
|                             strm.msg = "invalid distance too far back";
 | |
|                             state.mode = BAD;
 | |
|                             break top;
 | |
|                           }
 | |
|                         }
 | |
|                         from = 0;
 | |
|                         from_source = window;
 | |
|                         if (wnext === 0) {
 | |
|                           from += wsize - op;
 | |
|                           if (op < len) {
 | |
|                             len -= op;
 | |
|                             do {
 | |
|                               output[_out++] = window[from++];
 | |
|                             } while (--op);
 | |
|                             from = _out - dist;
 | |
|                             from_source = output;
 | |
|                           }
 | |
|                         } else {
 | |
|                           if (wnext < op) {
 | |
|                             from += wsize + wnext - op;
 | |
|                             op -= wnext;
 | |
|                             if (op < len) {
 | |
|                               len -= op;
 | |
|                               do {
 | |
|                                 output[_out++] = window[from++];
 | |
|                               } while (--op);
 | |
|                               from = 0;
 | |
|                               if (wnext < len) {
 | |
|                                 op = wnext;
 | |
|                                 len -= op;
 | |
|                                 do {
 | |
|                                   output[_out++] = window[from++];
 | |
|                                 } while (--op);
 | |
|                                 from = _out - dist;
 | |
|                                 from_source = output;
 | |
|                               }
 | |
|                             }
 | |
|                           } else {
 | |
|                             from += wnext - op;
 | |
|                             if (op < len) {
 | |
|                               len -= op;
 | |
|                               do {
 | |
|                                 output[_out++] = window[from++];
 | |
|                               } while (--op);
 | |
|                               from = _out - dist;
 | |
|                               from_source = output;
 | |
|                             }
 | |
|                           }
 | |
|                         }
 | |
|                         while (len > 2) {
 | |
|                           output[_out++] = from_source[from++];
 | |
|                           output[_out++] = from_source[from++];
 | |
|                           output[_out++] = from_source[from++];
 | |
|                           len -= 3;
 | |
|                         }
 | |
|                         if (len) {
 | |
|                           output[_out++] = from_source[from++];
 | |
|                           if (len > 1) {
 | |
|                             output[_out++] = from_source[from++];
 | |
|                           }
 | |
|                         }
 | |
|                       } else {
 | |
|                         from = _out - dist;
 | |
|                         do {
 | |
|                           output[_out++] = output[from++];
 | |
|                           output[_out++] = output[from++];
 | |
|                           output[_out++] = output[from++];
 | |
|                           len -= 3;
 | |
|                         } while (len > 2);
 | |
|                         if (len) {
 | |
|                           output[_out++] = output[from++];
 | |
|                           if (len > 1) {
 | |
|                             output[_out++] = output[from++];
 | |
|                           }
 | |
|                         }
 | |
|                       }
 | |
|                     } else {
 | |
|                       if ((op & 64) === 0) {
 | |
|                         here = dcode[(here & 65535) + (hold & (1 << op) - 1)];
 | |
|                         continue dodist;
 | |
|                       } else {
 | |
|                         strm.msg = "invalid distance code";
 | |
|                         state.mode = BAD;
 | |
|                         break top;
 | |
|                       }
 | |
|                     }
 | |
|                     break;
 | |
|                   }
 | |
|                 } else {
 | |
|                   if ((op & 64) === 0) {
 | |
|                     here = lcode[(here & 65535) + (hold & (1 << op) - 1)];
 | |
|                     continue dolen;
 | |
|                   } else {
 | |
|                     if (op & 32) {
 | |
|                       state.mode = TYPE;
 | |
|                       break top;
 | |
|                     } else {
 | |
|                       strm.msg = "invalid literal/length code";
 | |
|                       state.mode = BAD;
 | |
|                       break top;
 | |
|                     }
 | |
|                   }
 | |
|                 }
 | |
|               }
 | |
|               break;
 | |
|             }
 | |
|           } while (_in < last && _out < end);
 | |
|           len = bits >> 3;
 | |
|           _in -= len;
 | |
|           bits -= len << 3;
 | |
|           hold &= (1 << bits) - 1;
 | |
|           strm.next_in = _in;
 | |
|           strm.next_out = _out;
 | |
|           strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last);
 | |
|           strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end);
 | |
|           state.hold = hold;
 | |
|           state.bits = bits;
 | |
|           return;
 | |
|         };
 | |
|       }, {}], 9:[function(_dereq_, module, exports) {
 | |
|         var utils = _dereq_("../utils/common");
 | |
|         var adler32 = _dereq_("./adler32");
 | |
|         var crc32 = _dereq_("./crc32");
 | |
|         var inflate_fast = _dereq_("./inffast");
 | |
|         var inflate_table = _dereq_("./inftrees");
 | |
|         var CODES = 0;
 | |
|         var LENS = 1;
 | |
|         var DISTS = 2;
 | |
|         var Z_FINISH = 4;
 | |
|         var Z_BLOCK = 5;
 | |
|         var Z_TREES = 6;
 | |
|         var Z_OK = 0;
 | |
|         var Z_STREAM_END = 1;
 | |
|         var Z_NEED_DICT = 2;
 | |
|         var Z_STREAM_ERROR = -2;
 | |
|         var Z_DATA_ERROR = -3;
 | |
|         var Z_MEM_ERROR = -4;
 | |
|         var Z_BUF_ERROR = -5;
 | |
|         var Z_DEFLATED = 8;
 | |
|         var HEAD = 1;
 | |
|         var FLAGS = 2;
 | |
|         var TIME = 3;
 | |
|         var OS = 4;
 | |
|         var EXLEN = 5;
 | |
|         var EXTRA = 6;
 | |
|         var NAME = 7;
 | |
|         var COMMENT = 8;
 | |
|         var HCRC = 9;
 | |
|         var DICTID = 10;
 | |
|         var DICT = 11;
 | |
|         var TYPE = 12;
 | |
|         var TYPEDO = 13;
 | |
|         var STORED = 14;
 | |
|         var COPY_ = 15;
 | |
|         var COPY = 16;
 | |
|         var TABLE = 17;
 | |
|         var LENLENS = 18;
 | |
|         var CODELENS = 19;
 | |
|         var LEN_ = 20;
 | |
|         var LEN = 21;
 | |
|         var LENEXT = 22;
 | |
|         var DIST = 23;
 | |
|         var DISTEXT = 24;
 | |
|         var MATCH = 25;
 | |
|         var LIT = 26;
 | |
|         var CHECK = 27;
 | |
|         var LENGTH = 28;
 | |
|         var DONE = 29;
 | |
|         var BAD = 30;
 | |
|         var MEM = 31;
 | |
|         var SYNC = 32;
 | |
|         var ENOUGH_LENS = 852;
 | |
|         var ENOUGH_DISTS = 592;
 | |
|         var MAX_WBITS = 15;
 | |
|         var DEF_WBITS = MAX_WBITS;
 | |
|         function ZSWAP32(q) {
 | |
|           return (q >>> 24 & 255) + (q >>> 8 & 65280) + ((q & 65280) << 8) + ((q & 255) << 24);
 | |
|         }
 | |
|         function InflateState() {
 | |
|           this.mode = 0;
 | |
|           this.last = false;
 | |
|           this.wrap = 0;
 | |
|           this.havedict = false;
 | |
|           this.flags = 0;
 | |
|           this.dmax = 0;
 | |
|           this.check = 0;
 | |
|           this.total = 0;
 | |
|           this.head = null;
 | |
|           this.wbits = 0;
 | |
|           this.wsize = 0;
 | |
|           this.whave = 0;
 | |
|           this.wnext = 0;
 | |
|           this.window = null;
 | |
|           this.hold = 0;
 | |
|           this.bits = 0;
 | |
|           this.length = 0;
 | |
|           this.offset = 0;
 | |
|           this.extra = 0;
 | |
|           this.lencode = null;
 | |
|           this.distcode = null;
 | |
|           this.lenbits = 0;
 | |
|           this.distbits = 0;
 | |
|           this.ncode = 0;
 | |
|           this.nlen = 0;
 | |
|           this.ndist = 0;
 | |
|           this.have = 0;
 | |
|           this.next = null;
 | |
|           this.lens = new utils.Buf16(320);
 | |
|           this.work = new utils.Buf16(288);
 | |
|           this.lendyn = null;
 | |
|           this.distdyn = null;
 | |
|           this.sane = 0;
 | |
|           this.back = 0;
 | |
|           this.was = 0;
 | |
|         }
 | |
|         function inflateResetKeep(strm) {
 | |
|           var state;
 | |
|           if (!strm || !strm.state) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state = strm.state;
 | |
|           strm.total_in = strm.total_out = state.total = 0;
 | |
|           strm.msg = "";
 | |
|           if (state.wrap) {
 | |
|             strm.adler = state.wrap & 1;
 | |
|           }
 | |
|           state.mode = HEAD;
 | |
|           state.last = 0;
 | |
|           state.havedict = 0;
 | |
|           state.dmax = 32768;
 | |
|           state.head = null;
 | |
|           state.hold = 0;
 | |
|           state.bits = 0;
 | |
|           state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
 | |
|           state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
 | |
|           state.sane = 1;
 | |
|           state.back = -1;
 | |
|           return Z_OK;
 | |
|         }
 | |
|         function inflateReset(strm) {
 | |
|           var state;
 | |
|           if (!strm || !strm.state) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state = strm.state;
 | |
|           state.wsize = 0;
 | |
|           state.whave = 0;
 | |
|           state.wnext = 0;
 | |
|           return inflateResetKeep(strm);
 | |
|         }
 | |
|         function inflateReset2(strm, windowBits) {
 | |
|           var wrap;
 | |
|           var state;
 | |
|           if (!strm || !strm.state) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state = strm.state;
 | |
|           if (windowBits < 0) {
 | |
|             wrap = 0;
 | |
|             windowBits = -windowBits;
 | |
|           } else {
 | |
|             wrap = (windowBits >> 4) + 1;
 | |
|             if (windowBits < 48) {
 | |
|               windowBits &= 15;
 | |
|             }
 | |
|           }
 | |
|           if (windowBits && (windowBits < 8 || windowBits > 15)) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           if (state.window !== null && state.wbits !== windowBits) {
 | |
|             state.window = null;
 | |
|           }
 | |
|           state.wrap = wrap;
 | |
|           state.wbits = windowBits;
 | |
|           return inflateReset(strm);
 | |
|         }
 | |
|         function inflateInit2(strm, windowBits) {
 | |
|           var ret;
 | |
|           var state;
 | |
|           if (!strm) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state = new InflateState;
 | |
|           strm.state = state;
 | |
|           state.window = null;
 | |
|           ret = inflateReset2(strm, windowBits);
 | |
|           if (ret !== Z_OK) {
 | |
|             strm.state = null;
 | |
|           }
 | |
|           return ret;
 | |
|         }
 | |
|         function inflateInit(strm) {
 | |
|           return inflateInit2(strm, DEF_WBITS);
 | |
|         }
 | |
|         var virgin = true;
 | |
|         var lenfix, distfix;
 | |
|         function fixedtables(state) {
 | |
|           if (virgin) {
 | |
|             var sym;
 | |
|             lenfix = new utils.Buf32(512);
 | |
|             distfix = new utils.Buf32(32);
 | |
|             sym = 0;
 | |
|             while (sym < 144) {
 | |
|               state.lens[sym++] = 8;
 | |
|             }
 | |
|             while (sym < 256) {
 | |
|               state.lens[sym++] = 9;
 | |
|             }
 | |
|             while (sym < 280) {
 | |
|               state.lens[sym++] = 7;
 | |
|             }
 | |
|             while (sym < 288) {
 | |
|               state.lens[sym++] = 8;
 | |
|             }
 | |
|             inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits:9});
 | |
|             sym = 0;
 | |
|             while (sym < 32) {
 | |
|               state.lens[sym++] = 5;
 | |
|             }
 | |
|             inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits:5});
 | |
|             virgin = false;
 | |
|           }
 | |
|           state.lencode = lenfix;
 | |
|           state.lenbits = 9;
 | |
|           state.distcode = distfix;
 | |
|           state.distbits = 5;
 | |
|         }
 | |
|         function updatewindow(strm, src, end, copy) {
 | |
|           var dist;
 | |
|           var state = strm.state;
 | |
|           if (state.window === null) {
 | |
|             state.wsize = 1 << state.wbits;
 | |
|             state.wnext = 0;
 | |
|             state.whave = 0;
 | |
|             state.window = new utils.Buf8(state.wsize);
 | |
|           }
 | |
|           if (copy >= state.wsize) {
 | |
|             utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);
 | |
|             state.wnext = 0;
 | |
|             state.whave = state.wsize;
 | |
|           } else {
 | |
|             dist = state.wsize - state.wnext;
 | |
|             if (dist > copy) {
 | |
|               dist = copy;
 | |
|             }
 | |
|             utils.arraySet(state.window, src, end - copy, dist, state.wnext);
 | |
|             copy -= dist;
 | |
|             if (copy) {
 | |
|               utils.arraySet(state.window, src, end - copy, copy, 0);
 | |
|               state.wnext = copy;
 | |
|               state.whave = state.wsize;
 | |
|             } else {
 | |
|               state.wnext += dist;
 | |
|               if (state.wnext === state.wsize) {
 | |
|                 state.wnext = 0;
 | |
|               }
 | |
|               if (state.whave < state.wsize) {
 | |
|                 state.whave += dist;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           return 0;
 | |
|         }
 | |
|         function inflate(strm, flush) {
 | |
|           var state;
 | |
|           var input, output;
 | |
|           var next;
 | |
|           var put;
 | |
|           var have, left;
 | |
|           var hold;
 | |
|           var bits;
 | |
|           var _in, _out;
 | |
|           var copy;
 | |
|           var from;
 | |
|           var from_source;
 | |
|           var here = 0;
 | |
|           var here_bits, here_op, here_val;
 | |
|           var last_bits, last_op, last_val;
 | |
|           var len;
 | |
|           var ret;
 | |
|           var hbuf = new utils.Buf8(4);
 | |
|           var opts;
 | |
|           var n;
 | |
|           var order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
 | |
|           if (!strm || !strm.state || !strm.output || !strm.input && strm.avail_in !== 0) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state = strm.state;
 | |
|           if (state.mode === TYPE) {
 | |
|             state.mode = TYPEDO;
 | |
|           }
 | |
|           put = strm.next_out;
 | |
|           output = strm.output;
 | |
|           left = strm.avail_out;
 | |
|           next = strm.next_in;
 | |
|           input = strm.input;
 | |
|           have = strm.avail_in;
 | |
|           hold = state.hold;
 | |
|           bits = state.bits;
 | |
|           _in = have;
 | |
|           _out = left;
 | |
|           ret = Z_OK;
 | |
|           inf_leave: for (;;) {
 | |
|             switch(state.mode) {
 | |
|               case HEAD:
 | |
|                 if (state.wrap === 0) {
 | |
|                   state.mode = TYPEDO;
 | |
|                   break;
 | |
|                 }
 | |
|                 while (bits < 16) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 if (state.wrap & 2 && hold === 35615) {
 | |
|                   state.check = 0;
 | |
|                   hbuf[0] = hold & 255;
 | |
|                   hbuf[1] = hold >>> 8 & 255;
 | |
|                   state.check = crc32(state.check, hbuf, 2, 0);
 | |
|                   hold = 0;
 | |
|                   bits = 0;
 | |
|                   state.mode = FLAGS;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.flags = 0;
 | |
|                 if (state.head) {
 | |
|                   state.head.done = false;
 | |
|                 }
 | |
|                 if (!(state.wrap & 1) || (((hold & 255) << 8) + (hold >> 8)) % 31) {
 | |
|                   strm.msg = "incorrect header check";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 if ((hold & 15) !== Z_DEFLATED) {
 | |
|                   strm.msg = "unknown compression method";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 hold >>>= 4;
 | |
|                 bits -= 4;
 | |
|                 len = (hold & 15) + 8;
 | |
|                 if (state.wbits === 0) {
 | |
|                   state.wbits = len;
 | |
|                 } else {
 | |
|                   if (len > state.wbits) {
 | |
|                     strm.msg = "invalid window size";
 | |
|                     state.mode = BAD;
 | |
|                     break;
 | |
|                   }
 | |
|                 }
 | |
|                 state.dmax = 1 << len;
 | |
|                 strm.adler = state.check = 1;
 | |
|                 state.mode = hold & 512 ? DICTID : TYPE;
 | |
|                 hold = 0;
 | |
|                 bits = 0;
 | |
|                 break;
 | |
|               case FLAGS:
 | |
|                 while (bits < 16) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 state.flags = hold;
 | |
|                 if ((state.flags & 255) !== Z_DEFLATED) {
 | |
|                   strm.msg = "unknown compression method";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 if (state.flags & 57344) {
 | |
|                   strm.msg = "unknown header flags set";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 if (state.head) {
 | |
|                   state.head.text = hold >> 8 & 1;
 | |
|                 }
 | |
|                 if (state.flags & 512) {
 | |
|                   hbuf[0] = hold & 255;
 | |
|                   hbuf[1] = hold >>> 8 & 255;
 | |
|                   state.check = crc32(state.check, hbuf, 2, 0);
 | |
|                 }
 | |
|                 hold = 0;
 | |
|                 bits = 0;
 | |
|                 state.mode = TIME;
 | |
|               case TIME:
 | |
|                 while (bits < 32) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 if (state.head) {
 | |
|                   state.head.time = hold;
 | |
|                 }
 | |
|                 if (state.flags & 512) {
 | |
|                   hbuf[0] = hold & 255;
 | |
|                   hbuf[1] = hold >>> 8 & 255;
 | |
|                   hbuf[2] = hold >>> 16 & 255;
 | |
|                   hbuf[3] = hold >>> 24 & 255;
 | |
|                   state.check = crc32(state.check, hbuf, 4, 0);
 | |
|                 }
 | |
|                 hold = 0;
 | |
|                 bits = 0;
 | |
|                 state.mode = OS;
 | |
|               case OS:
 | |
|                 while (bits < 16) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 if (state.head) {
 | |
|                   state.head.xflags = hold & 255;
 | |
|                   state.head.os = hold >> 8;
 | |
|                 }
 | |
|                 if (state.flags & 512) {
 | |
|                   hbuf[0] = hold & 255;
 | |
|                   hbuf[1] = hold >>> 8 & 255;
 | |
|                   state.check = crc32(state.check, hbuf, 2, 0);
 | |
|                 }
 | |
|                 hold = 0;
 | |
|                 bits = 0;
 | |
|                 state.mode = EXLEN;
 | |
|               case EXLEN:
 | |
|                 if (state.flags & 1024) {
 | |
|                   while (bits < 16) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   state.length = hold;
 | |
|                   if (state.head) {
 | |
|                     state.head.extra_len = hold;
 | |
|                   }
 | |
|                   if (state.flags & 512) {
 | |
|                     hbuf[0] = hold & 255;
 | |
|                     hbuf[1] = hold >>> 8 & 255;
 | |
|                     state.check = crc32(state.check, hbuf, 2, 0);
 | |
|                   }
 | |
|                   hold = 0;
 | |
|                   bits = 0;
 | |
|                 } else {
 | |
|                   if (state.head) {
 | |
|                     state.head.extra = null;
 | |
|                   }
 | |
|                 }
 | |
|                 state.mode = EXTRA;
 | |
|               case EXTRA:
 | |
|                 if (state.flags & 1024) {
 | |
|                   copy = state.length;
 | |
|                   if (copy > have) {
 | |
|                     copy = have;
 | |
|                   }
 | |
|                   if (copy) {
 | |
|                     if (state.head) {
 | |
|                       len = state.head.extra_len - state.length;
 | |
|                       if (!state.head.extra) {
 | |
|                         state.head.extra = new Array(state.head.extra_len);
 | |
|                       }
 | |
|                       utils.arraySet(state.head.extra, input, next, copy, len);
 | |
|                     }
 | |
|                     if (state.flags & 512) {
 | |
|                       state.check = crc32(state.check, input, copy, next);
 | |
|                     }
 | |
|                     have -= copy;
 | |
|                     next += copy;
 | |
|                     state.length -= copy;
 | |
|                   }
 | |
|                   if (state.length) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                 }
 | |
|                 state.length = 0;
 | |
|                 state.mode = NAME;
 | |
|               case NAME:
 | |
|                 if (state.flags & 2048) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   copy = 0;
 | |
|                   do {
 | |
|                     len = input[next + copy++];
 | |
|                     if (state.head && len && state.length < 65536) {
 | |
|                       state.head.name += String.fromCharCode(len);
 | |
|                     }
 | |
|                   } while (len && copy < have);
 | |
|                   if (state.flags & 512) {
 | |
|                     state.check = crc32(state.check, input, copy, next);
 | |
|                   }
 | |
|                   have -= copy;
 | |
|                   next += copy;
 | |
|                   if (len) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                 } else {
 | |
|                   if (state.head) {
 | |
|                     state.head.name = null;
 | |
|                   }
 | |
|                 }
 | |
|                 state.length = 0;
 | |
|                 state.mode = COMMENT;
 | |
|               case COMMENT:
 | |
|                 if (state.flags & 4096) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   copy = 0;
 | |
|                   do {
 | |
|                     len = input[next + copy++];
 | |
|                     if (state.head && len && state.length < 65536) {
 | |
|                       state.head.comment += String.fromCharCode(len);
 | |
|                     }
 | |
|                   } while (len && copy < have);
 | |
|                   if (state.flags & 512) {
 | |
|                     state.check = crc32(state.check, input, copy, next);
 | |
|                   }
 | |
|                   have -= copy;
 | |
|                   next += copy;
 | |
|                   if (len) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                 } else {
 | |
|                   if (state.head) {
 | |
|                     state.head.comment = null;
 | |
|                   }
 | |
|                 }
 | |
|                 state.mode = HCRC;
 | |
|               case HCRC:
 | |
|                 if (state.flags & 512) {
 | |
|                   while (bits < 16) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   if (hold !== (state.check & 65535)) {
 | |
|                     strm.msg = "header crc mismatch";
 | |
|                     state.mode = BAD;
 | |
|                     break;
 | |
|                   }
 | |
|                   hold = 0;
 | |
|                   bits = 0;
 | |
|                 }
 | |
|                 if (state.head) {
 | |
|                   state.head.hcrc = state.flags >> 9 & 1;
 | |
|                   state.head.done = true;
 | |
|                 }
 | |
|                 strm.adler = state.check = 0;
 | |
|                 state.mode = TYPE;
 | |
|                 break;
 | |
|               case DICTID:
 | |
|                 while (bits < 32) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 strm.adler = state.check = ZSWAP32(hold);
 | |
|                 hold = 0;
 | |
|                 bits = 0;
 | |
|                 state.mode = DICT;
 | |
|               case DICT:
 | |
|                 if (state.havedict === 0) {
 | |
|                   strm.next_out = put;
 | |
|                   strm.avail_out = left;
 | |
|                   strm.next_in = next;
 | |
|                   strm.avail_in = have;
 | |
|                   state.hold = hold;
 | |
|                   state.bits = bits;
 | |
|                   return Z_NEED_DICT;
 | |
|                 }
 | |
|                 strm.adler = state.check = 1;
 | |
|                 state.mode = TYPE;
 | |
|               case TYPE:
 | |
|                 if (flush === Z_BLOCK || flush === Z_TREES) {
 | |
|                   break inf_leave;
 | |
|                 }
 | |
|               ;
 | |
|               case TYPEDO:
 | |
|                 if (state.last) {
 | |
|                   hold >>>= bits & 7;
 | |
|                   bits -= bits & 7;
 | |
|                   state.mode = CHECK;
 | |
|                   break;
 | |
|                 }
 | |
|                 while (bits < 3) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 state.last = hold & 1;
 | |
|                 hold >>>= 1;
 | |
|                 bits -= 1;
 | |
|                 switch(hold & 3) {
 | |
|                   case 0:
 | |
|                     state.mode = STORED;
 | |
|                     break;
 | |
|                   case 1:
 | |
|                     fixedtables(state);
 | |
|                     state.mode = LEN_;
 | |
|                     if (flush === Z_TREES) {
 | |
|                       hold >>>= 2;
 | |
|                       bits -= 2;
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     break;
 | |
|                   case 2:
 | |
|                     state.mode = TABLE;
 | |
|                     break;
 | |
|                   case 3:
 | |
|                     strm.msg = "invalid block type";
 | |
|                     state.mode = BAD;
 | |
|                 }
 | |
|                 hold >>>= 2;
 | |
|                 bits -= 2;
 | |
|                 break;
 | |
|               case STORED:
 | |
|                 hold >>>= bits & 7;
 | |
|                 bits -= bits & 7;
 | |
|                 while (bits < 32) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 if ((hold & 65535) !== (hold >>> 16 ^ 65535)) {
 | |
|                   strm.msg = "invalid stored block lengths";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.length = hold & 65535;
 | |
|                 hold = 0;
 | |
|                 bits = 0;
 | |
|                 state.mode = COPY_;
 | |
|                 if (flush === Z_TREES) {
 | |
|                   break inf_leave;
 | |
|                 }
 | |
|               ;
 | |
|               case COPY_:
 | |
|                 state.mode = COPY;
 | |
|               case COPY:
 | |
|                 copy = state.length;
 | |
|                 if (copy) {
 | |
|                   if (copy > have) {
 | |
|                     copy = have;
 | |
|                   }
 | |
|                   if (copy > left) {
 | |
|                     copy = left;
 | |
|                   }
 | |
|                   if (copy === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   utils.arraySet(output, input, next, copy, put);
 | |
|                   have -= copy;
 | |
|                   next += copy;
 | |
|                   left -= copy;
 | |
|                   put += copy;
 | |
|                   state.length -= copy;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.mode = TYPE;
 | |
|                 break;
 | |
|               case TABLE:
 | |
|                 while (bits < 14) {
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 state.nlen = (hold & 31) + 257;
 | |
|                 hold >>>= 5;
 | |
|                 bits -= 5;
 | |
|                 state.ndist = (hold & 31) + 1;
 | |
|                 hold >>>= 5;
 | |
|                 bits -= 5;
 | |
|                 state.ncode = (hold & 15) + 4;
 | |
|                 hold >>>= 4;
 | |
|                 bits -= 4;
 | |
|                 if (state.nlen > 286 || state.ndist > 30) {
 | |
|                   strm.msg = "too many length or distance symbols";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.have = 0;
 | |
|                 state.mode = LENLENS;
 | |
|               case LENLENS:
 | |
|                 while (state.have < state.ncode) {
 | |
|                   while (bits < 3) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   state.lens[order[state.have++]] = hold & 7;
 | |
|                   hold >>>= 3;
 | |
|                   bits -= 3;
 | |
|                 }
 | |
|                 while (state.have < 19) {
 | |
|                   state.lens[order[state.have++]] = 0;
 | |
|                 }
 | |
|                 state.lencode = state.lendyn;
 | |
|                 state.lenbits = 7;
 | |
|                 opts = {bits:state.lenbits};
 | |
|                 ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
 | |
|                 state.lenbits = opts.bits;
 | |
|                 if (ret) {
 | |
|                   strm.msg = "invalid code lengths set";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.have = 0;
 | |
|                 state.mode = CODELENS;
 | |
|               case CODELENS:
 | |
|                 while (state.have < state.nlen + state.ndist) {
 | |
|                   for (;;) {
 | |
|                     here = state.lencode[hold & (1 << state.lenbits) - 1];
 | |
|                     here_bits = here >>> 24;
 | |
|                     here_op = here >>> 16 & 255;
 | |
|                     here_val = here & 65535;
 | |
|                     if (here_bits <= bits) {
 | |
|                       break;
 | |
|                     }
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   if (here_val < 16) {
 | |
|                     hold >>>= here_bits;
 | |
|                     bits -= here_bits;
 | |
|                     state.lens[state.have++] = here_val;
 | |
|                   } else {
 | |
|                     if (here_val === 16) {
 | |
|                       n = here_bits + 2;
 | |
|                       while (bits < n) {
 | |
|                         if (have === 0) {
 | |
|                           break inf_leave;
 | |
|                         }
 | |
|                         have--;
 | |
|                         hold += input[next++] << bits;
 | |
|                         bits += 8;
 | |
|                       }
 | |
|                       hold >>>= here_bits;
 | |
|                       bits -= here_bits;
 | |
|                       if (state.have === 0) {
 | |
|                         strm.msg = "invalid bit length repeat";
 | |
|                         state.mode = BAD;
 | |
|                         break;
 | |
|                       }
 | |
|                       len = state.lens[state.have - 1];
 | |
|                       copy = 3 + (hold & 3);
 | |
|                       hold >>>= 2;
 | |
|                       bits -= 2;
 | |
|                     } else {
 | |
|                       if (here_val === 17) {
 | |
|                         n = here_bits + 3;
 | |
|                         while (bits < n) {
 | |
|                           if (have === 0) {
 | |
|                             break inf_leave;
 | |
|                           }
 | |
|                           have--;
 | |
|                           hold += input[next++] << bits;
 | |
|                           bits += 8;
 | |
|                         }
 | |
|                         hold >>>= here_bits;
 | |
|                         bits -= here_bits;
 | |
|                         len = 0;
 | |
|                         copy = 3 + (hold & 7);
 | |
|                         hold >>>= 3;
 | |
|                         bits -= 3;
 | |
|                       } else {
 | |
|                         n = here_bits + 7;
 | |
|                         while (bits < n) {
 | |
|                           if (have === 0) {
 | |
|                             break inf_leave;
 | |
|                           }
 | |
|                           have--;
 | |
|                           hold += input[next++] << bits;
 | |
|                           bits += 8;
 | |
|                         }
 | |
|                         hold >>>= here_bits;
 | |
|                         bits -= here_bits;
 | |
|                         len = 0;
 | |
|                         copy = 11 + (hold & 127);
 | |
|                         hold >>>= 7;
 | |
|                         bits -= 7;
 | |
|                       }
 | |
|                     }
 | |
|                     if (state.have + copy > state.nlen + state.ndist) {
 | |
|                       strm.msg = "invalid bit length repeat";
 | |
|                       state.mode = BAD;
 | |
|                       break;
 | |
|                     }
 | |
|                     while (copy--) {
 | |
|                       state.lens[state.have++] = len;
 | |
|                     }
 | |
|                   }
 | |
|                 }
 | |
|                 if (state.mode === BAD) {
 | |
|                   break;
 | |
|                 }
 | |
|                 if (state.lens[256] === 0) {
 | |
|                   strm.msg = "invalid code -- missing end-of-block";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.lenbits = 9;
 | |
|                 opts = {bits:state.lenbits};
 | |
|                 ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
 | |
|                 state.lenbits = opts.bits;
 | |
|                 if (ret) {
 | |
|                   strm.msg = "invalid literal/lengths set";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.distbits = 6;
 | |
|                 state.distcode = state.distdyn;
 | |
|                 opts = {bits:state.distbits};
 | |
|                 ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
 | |
|                 state.distbits = opts.bits;
 | |
|                 if (ret) {
 | |
|                   strm.msg = "invalid distances set";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.mode = LEN_;
 | |
|                 if (flush === Z_TREES) {
 | |
|                   break inf_leave;
 | |
|                 }
 | |
|               ;
 | |
|               case LEN_:
 | |
|                 state.mode = LEN;
 | |
|               case LEN:
 | |
|                 if (have >= 6 && left >= 258) {
 | |
|                   strm.next_out = put;
 | |
|                   strm.avail_out = left;
 | |
|                   strm.next_in = next;
 | |
|                   strm.avail_in = have;
 | |
|                   state.hold = hold;
 | |
|                   state.bits = bits;
 | |
|                   inflate_fast(strm, _out);
 | |
|                   put = strm.next_out;
 | |
|                   output = strm.output;
 | |
|                   left = strm.avail_out;
 | |
|                   next = strm.next_in;
 | |
|                   input = strm.input;
 | |
|                   have = strm.avail_in;
 | |
|                   hold = state.hold;
 | |
|                   bits = state.bits;
 | |
|                   if (state.mode === TYPE) {
 | |
|                     state.back = -1;
 | |
|                   }
 | |
|                   break;
 | |
|                 }
 | |
|                 state.back = 0;
 | |
|                 for (;;) {
 | |
|                   here = state.lencode[hold & (1 << state.lenbits) - 1];
 | |
|                   here_bits = here >>> 24;
 | |
|                   here_op = here >>> 16 & 255;
 | |
|                   here_val = here & 65535;
 | |
|                   if (here_bits <= bits) {
 | |
|                     break;
 | |
|                   }
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 if (here_op && (here_op & 240) === 0) {
 | |
|                   last_bits = here_bits;
 | |
|                   last_op = here_op;
 | |
|                   last_val = here_val;
 | |
|                   for (;;) {
 | |
|                     here = state.lencode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)];
 | |
|                     here_bits = here >>> 24;
 | |
|                     here_op = here >>> 16 & 255;
 | |
|                     here_val = here & 65535;
 | |
|                     if (last_bits + here_bits <= bits) {
 | |
|                       break;
 | |
|                     }
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   hold >>>= last_bits;
 | |
|                   bits -= last_bits;
 | |
|                   state.back += last_bits;
 | |
|                 }
 | |
|                 hold >>>= here_bits;
 | |
|                 bits -= here_bits;
 | |
|                 state.back += here_bits;
 | |
|                 state.length = here_val;
 | |
|                 if (here_op === 0) {
 | |
|                   state.mode = LIT;
 | |
|                   break;
 | |
|                 }
 | |
|                 if (here_op & 32) {
 | |
|                   state.back = -1;
 | |
|                   state.mode = TYPE;
 | |
|                   break;
 | |
|                 }
 | |
|                 if (here_op & 64) {
 | |
|                   strm.msg = "invalid literal/length code";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.extra = here_op & 15;
 | |
|                 state.mode = LENEXT;
 | |
|               case LENEXT:
 | |
|                 if (state.extra) {
 | |
|                   n = state.extra;
 | |
|                   while (bits < n) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   state.length += hold & (1 << state.extra) - 1;
 | |
|                   hold >>>= state.extra;
 | |
|                   bits -= state.extra;
 | |
|                   state.back += state.extra;
 | |
|                 }
 | |
|                 state.was = state.length;
 | |
|                 state.mode = DIST;
 | |
|               case DIST:
 | |
|                 for (;;) {
 | |
|                   here = state.distcode[hold & (1 << state.distbits) - 1];
 | |
|                   here_bits = here >>> 24;
 | |
|                   here_op = here >>> 16 & 255;
 | |
|                   here_val = here & 65535;
 | |
|                   if (here_bits <= bits) {
 | |
|                     break;
 | |
|                   }
 | |
|                   if (have === 0) {
 | |
|                     break inf_leave;
 | |
|                   }
 | |
|                   have--;
 | |
|                   hold += input[next++] << bits;
 | |
|                   bits += 8;
 | |
|                 }
 | |
|                 if ((here_op & 240) === 0) {
 | |
|                   last_bits = here_bits;
 | |
|                   last_op = here_op;
 | |
|                   last_val = here_val;
 | |
|                   for (;;) {
 | |
|                     here = state.distcode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)];
 | |
|                     here_bits = here >>> 24;
 | |
|                     here_op = here >>> 16 & 255;
 | |
|                     here_val = here & 65535;
 | |
|                     if (last_bits + here_bits <= bits) {
 | |
|                       break;
 | |
|                     }
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   hold >>>= last_bits;
 | |
|                   bits -= last_bits;
 | |
|                   state.back += last_bits;
 | |
|                 }
 | |
|                 hold >>>= here_bits;
 | |
|                 bits -= here_bits;
 | |
|                 state.back += here_bits;
 | |
|                 if (here_op & 64) {
 | |
|                   strm.msg = "invalid distance code";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.offset = here_val;
 | |
|                 state.extra = here_op & 15;
 | |
|                 state.mode = DISTEXT;
 | |
|               case DISTEXT:
 | |
|                 if (state.extra) {
 | |
|                   n = state.extra;
 | |
|                   while (bits < n) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   state.offset += hold & (1 << state.extra) - 1;
 | |
|                   hold >>>= state.extra;
 | |
|                   bits -= state.extra;
 | |
|                   state.back += state.extra;
 | |
|                 }
 | |
|                 if (state.offset > state.dmax) {
 | |
|                   strm.msg = "invalid distance too far back";
 | |
|                   state.mode = BAD;
 | |
|                   break;
 | |
|                 }
 | |
|                 state.mode = MATCH;
 | |
|               case MATCH:
 | |
|                 if (left === 0) {
 | |
|                   break inf_leave;
 | |
|                 }
 | |
|                 copy = _out - left;
 | |
|                 if (state.offset > copy) {
 | |
|                   copy = state.offset - copy;
 | |
|                   if (copy > state.whave) {
 | |
|                     if (state.sane) {
 | |
|                       strm.msg = "invalid distance too far back";
 | |
|                       state.mode = BAD;
 | |
|                       break;
 | |
|                     }
 | |
|                   }
 | |
|                   if (copy > state.wnext) {
 | |
|                     copy -= state.wnext;
 | |
|                     from = state.wsize - copy;
 | |
|                   } else {
 | |
|                     from = state.wnext - copy;
 | |
|                   }
 | |
|                   if (copy > state.length) {
 | |
|                     copy = state.length;
 | |
|                   }
 | |
|                   from_source = state.window;
 | |
|                 } else {
 | |
|                   from_source = output;
 | |
|                   from = put - state.offset;
 | |
|                   copy = state.length;
 | |
|                 }
 | |
|                 if (copy > left) {
 | |
|                   copy = left;
 | |
|                 }
 | |
|                 left -= copy;
 | |
|                 state.length -= copy;
 | |
|                 do {
 | |
|                   output[put++] = from_source[from++];
 | |
|                 } while (--copy);
 | |
|                 if (state.length === 0) {
 | |
|                   state.mode = LEN;
 | |
|                 }
 | |
|                 break;
 | |
|               case LIT:
 | |
|                 if (left === 0) {
 | |
|                   break inf_leave;
 | |
|                 }
 | |
|                 output[put++] = state.length;
 | |
|                 left--;
 | |
|                 state.mode = LEN;
 | |
|                 break;
 | |
|               case CHECK:
 | |
|                 if (state.wrap) {
 | |
|                   while (bits < 32) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold |= input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   _out -= left;
 | |
|                   strm.total_out += _out;
 | |
|                   state.total += _out;
 | |
|                   if (_out) {
 | |
|                     strm.adler = state.check = state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out);
 | |
|                   }
 | |
|                   _out = left;
 | |
|                   if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {
 | |
|                     strm.msg = "incorrect data check";
 | |
|                     state.mode = BAD;
 | |
|                     break;
 | |
|                   }
 | |
|                   hold = 0;
 | |
|                   bits = 0;
 | |
|                 }
 | |
|                 state.mode = LENGTH;
 | |
|               case LENGTH:
 | |
|                 if (state.wrap && state.flags) {
 | |
|                   while (bits < 32) {
 | |
|                     if (have === 0) {
 | |
|                       break inf_leave;
 | |
|                     }
 | |
|                     have--;
 | |
|                     hold += input[next++] << bits;
 | |
|                     bits += 8;
 | |
|                   }
 | |
|                   if (hold !== (state.total & 4294967295)) {
 | |
|                     strm.msg = "incorrect length check";
 | |
|                     state.mode = BAD;
 | |
|                     break;
 | |
|                   }
 | |
|                   hold = 0;
 | |
|                   bits = 0;
 | |
|                 }
 | |
|                 state.mode = DONE;
 | |
|               case DONE:
 | |
|                 ret = Z_STREAM_END;
 | |
|                 break inf_leave;
 | |
|               case BAD:
 | |
|                 ret = Z_DATA_ERROR;
 | |
|                 break inf_leave;
 | |
|               case MEM:
 | |
|                 return Z_MEM_ERROR;
 | |
|               case SYNC:
 | |
|               ;
 | |
|               default:
 | |
|                 return Z_STREAM_ERROR;
 | |
|             }
 | |
|           }
 | |
|           strm.next_out = put;
 | |
|           strm.avail_out = left;
 | |
|           strm.next_in = next;
 | |
|           strm.avail_in = have;
 | |
|           state.hold = hold;
 | |
|           state.bits = bits;
 | |
|           if (state.wsize || _out !== strm.avail_out && state.mode < BAD && (state.mode < CHECK || flush !== Z_FINISH)) {
 | |
|             if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
 | |
|               state.mode = MEM;
 | |
|               return Z_MEM_ERROR;
 | |
|             }
 | |
|           }
 | |
|           _in -= strm.avail_in;
 | |
|           _out -= strm.avail_out;
 | |
|           strm.total_in += _in;
 | |
|           strm.total_out += _out;
 | |
|           state.total += _out;
 | |
|           if (state.wrap && _out) {
 | |
|             strm.adler = state.check = state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out);
 | |
|           }
 | |
|           strm.data_type = state.bits + (state.last ? 64 : 0) + (state.mode === TYPE ? 128 : 0) + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
 | |
|           if ((_in === 0 && _out === 0 || flush === Z_FINISH) && ret === Z_OK) {
 | |
|             ret = Z_BUF_ERROR;
 | |
|           }
 | |
|           return ret;
 | |
|         }
 | |
|         function inflateEnd(strm) {
 | |
|           if (!strm || !strm.state) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           var state = strm.state;
 | |
|           if (state.window) {
 | |
|             state.window = null;
 | |
|           }
 | |
|           strm.state = null;
 | |
|           return Z_OK;
 | |
|         }
 | |
|         function inflateGetHeader(strm, head) {
 | |
|           var state;
 | |
|           if (!strm || !strm.state) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state = strm.state;
 | |
|           if ((state.wrap & 2) === 0) {
 | |
|             return Z_STREAM_ERROR;
 | |
|           }
 | |
|           state.head = head;
 | |
|           head.done = false;
 | |
|           return Z_OK;
 | |
|         }
 | |
|         exports.inflateReset = inflateReset;
 | |
|         exports.inflateReset2 = inflateReset2;
 | |
|         exports.inflateResetKeep = inflateResetKeep;
 | |
|         exports.inflateInit = inflateInit;
 | |
|         exports.inflateInit2 = inflateInit2;
 | |
|         exports.inflate = inflate;
 | |
|         exports.inflateEnd = inflateEnd;
 | |
|         exports.inflateGetHeader = inflateGetHeader;
 | |
|         exports.inflateInfo = "pako inflate (from Nodeca project)";
 | |
|       }, {"../utils/common":2, "./adler32":4, "./crc32":6, "./inffast":8, "./inftrees":10}], 10:[function(_dereq_, module, exports) {
 | |
|         var utils = _dereq_("../utils/common");
 | |
|         var MAXBITS = 15;
 | |
|         var ENOUGH_LENS = 852;
 | |
|         var ENOUGH_DISTS = 592;
 | |
|         var CODES = 0;
 | |
|         var LENS = 1;
 | |
|         var DISTS = 2;
 | |
|         var lbase = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0];
 | |
|         var lext = [16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78];
 | |
|         var dbase = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0];
 | |
|         var dext = [16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64];
 | |
|         module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) {
 | |
|           var bits = opts.bits;
 | |
|           var len = 0;
 | |
|           var sym = 0;
 | |
|           var min = 0, max = 0;
 | |
|           var root = 0;
 | |
|           var curr = 0;
 | |
|           var drop = 0;
 | |
|           var left = 0;
 | |
|           var used = 0;
 | |
|           var huff = 0;
 | |
|           var incr;
 | |
|           var fill;
 | |
|           var low;
 | |
|           var mask;
 | |
|           var next;
 | |
|           var base = null;
 | |
|           var base_index = 0;
 | |
|           var end;
 | |
|           var count = new utils.Buf16(MAXBITS + 1);
 | |
|           var offs = new utils.Buf16(MAXBITS + 1);
 | |
|           var extra = null;
 | |
|           var extra_index = 0;
 | |
|           var here_bits, here_op, here_val;
 | |
|           for (len = 0;len <= MAXBITS;len++) {
 | |
|             count[len] = 0;
 | |
|           }
 | |
|           for (sym = 0;sym < codes;sym++) {
 | |
|             count[lens[lens_index + sym]]++;
 | |
|           }
 | |
|           root = bits;
 | |
|           for (max = MAXBITS;max >= 1;max--) {
 | |
|             if (count[max] !== 0) {
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|           if (root > max) {
 | |
|             root = max;
 | |
|           }
 | |
|           if (max === 0) {
 | |
|             table[table_index++] = 1 << 24 | 64 << 16 | 0;
 | |
|             table[table_index++] = 1 << 24 | 64 << 16 | 0;
 | |
|             opts.bits = 1;
 | |
|             return 0;
 | |
|           }
 | |
|           for (min = 1;min < max;min++) {
 | |
|             if (count[min] !== 0) {
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|           if (root < min) {
 | |
|             root = min;
 | |
|           }
 | |
|           left = 1;
 | |
|           for (len = 1;len <= MAXBITS;len++) {
 | |
|             left <<= 1;
 | |
|             left -= count[len];
 | |
|             if (left < 0) {
 | |
|               return -1;
 | |
|             }
 | |
|           }
 | |
|           if (left > 0 && (type === CODES || max !== 1)) {
 | |
|             return -1;
 | |
|           }
 | |
|           offs[1] = 0;
 | |
|           for (len = 1;len < MAXBITS;len++) {
 | |
|             offs[len + 1] = offs[len] + count[len];
 | |
|           }
 | |
|           for (sym = 0;sym < codes;sym++) {
 | |
|             if (lens[lens_index + sym] !== 0) {
 | |
|               work[offs[lens[lens_index + sym]]++] = sym;
 | |
|             }
 | |
|           }
 | |
|           switch(type) {
 | |
|             case CODES:
 | |
|               base = extra = work;
 | |
|               end = 19;
 | |
|               break;
 | |
|             case LENS:
 | |
|               base = lbase;
 | |
|               base_index -= 257;
 | |
|               extra = lext;
 | |
|               extra_index -= 257;
 | |
|               end = 256;
 | |
|               break;
 | |
|             default:
 | |
|               base = dbase;
 | |
|               extra = dext;
 | |
|               end = -1;
 | |
|           }
 | |
|           huff = 0;
 | |
|           sym = 0;
 | |
|           len = min;
 | |
|           next = table_index;
 | |
|           curr = root;
 | |
|           drop = 0;
 | |
|           low = -1;
 | |
|           used = 1 << root;
 | |
|           mask = used - 1;
 | |
|           if (type === LENS && used > ENOUGH_LENS || type === DISTS && used > ENOUGH_DISTS) {
 | |
|             return 1;
 | |
|           }
 | |
|           var i = 0;
 | |
|           for (;;) {
 | |
|             i++;
 | |
|             here_bits = len - drop;
 | |
|             if (work[sym] < end) {
 | |
|               here_op = 0;
 | |
|               here_val = work[sym];
 | |
|             } else {
 | |
|               if (work[sym] > end) {
 | |
|                 here_op = extra[extra_index + work[sym]];
 | |
|                 here_val = base[base_index + work[sym]];
 | |
|               } else {
 | |
|                 here_op = 32 + 64;
 | |
|                 here_val = 0;
 | |
|               }
 | |
|             }
 | |
|             incr = 1 << len - drop;
 | |
|             fill = 1 << curr;
 | |
|             min = fill;
 | |
|             do {
 | |
|               fill -= incr;
 | |
|               table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val | 0;
 | |
|             } while (fill !== 0);
 | |
|             incr = 1 << len - 1;
 | |
|             while (huff & incr) {
 | |
|               incr >>= 1;
 | |
|             }
 | |
|             if (incr !== 0) {
 | |
|               huff &= incr - 1;
 | |
|               huff += incr;
 | |
|             } else {
 | |
|               huff = 0;
 | |
|             }
 | |
|             sym++;
 | |
|             if (--count[len] === 0) {
 | |
|               if (len === max) {
 | |
|                 break;
 | |
|               }
 | |
|               len = lens[lens_index + work[sym]];
 | |
|             }
 | |
|             if (len > root && (huff & mask) !== low) {
 | |
|               if (drop === 0) {
 | |
|                 drop = root;
 | |
|               }
 | |
|               next += min;
 | |
|               curr = len - drop;
 | |
|               left = 1 << curr;
 | |
|               while (curr + drop < max) {
 | |
|                 left -= count[curr + drop];
 | |
|                 if (left <= 0) {
 | |
|                   break;
 | |
|                 }
 | |
|                 curr++;
 | |
|                 left <<= 1;
 | |
|               }
 | |
|               used += 1 << curr;
 | |
|               if (type === LENS && used > ENOUGH_LENS || type === DISTS && used > ENOUGH_DISTS) {
 | |
|                 return 1;
 | |
|               }
 | |
|               low = huff & mask;
 | |
|               table[low] = root << 24 | curr << 16 | next - table_index | 0;
 | |
|             }
 | |
|           }
 | |
|           if (huff !== 0) {
 | |
|             table[next + huff] = len - drop << 24 | 64 << 16 | 0;
 | |
|           }
 | |
|           opts.bits = root;
 | |
|           return 0;
 | |
|         };
 | |
|       }, {"../utils/common":2}], 11:[function(_dereq_, module, exports) {
 | |
|         module.exports = {2:"need dictionary", 1:"stream end", 0:"", "-1":"file error", "-2":"stream error", "-3":"data error", "-4":"insufficient memory", "-5":"buffer error", "-6":"incompatible version"};
 | |
|       }, {}], 12:[function(_dereq_, module, exports) {
 | |
|         function ZStream() {
 | |
|           this.input = null;
 | |
|           this.next_in = 0;
 | |
|           this.avail_in = 0;
 | |
|           this.total_in = 0;
 | |
|           this.output = null;
 | |
|           this.next_out = 0;
 | |
|           this.avail_out = 0;
 | |
|           this.total_out = 0;
 | |
|           this.msg = "";
 | |
|           this.state = null;
 | |
|           this.data_type = 2;
 | |
|           this.adler = 0;
 | |
|         }
 | |
|         module.exports = ZStream;
 | |
|       }, {}]}, {}, [1])(1);
 | |
|     });
 | |
|     function zip_inflate(data, size) {
 | |
|       return pako.inflateRaw(data);
 | |
|     }
 | |
|     return {inflate:zip_inflate};
 | |
|   }
 | |
|   core.RawInflate = createRawInflateSingleton();
 | |
| })();
 | |
| core.StepDirection = {PREVIOUS:1, NEXT:2};
 | |
| core.StepIterator = function StepIterator(filter, iterator) {
 | |
|   var FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, NEXT = core.StepDirection.NEXT, cachedContainer, cachedOffset, cachedFilterResult;
 | |
|   function resetCache() {
 | |
|     cachedContainer = null;
 | |
|     cachedOffset = undefined;
 | |
|     cachedFilterResult = undefined;
 | |
|   }
 | |
|   function isStep() {
 | |
|     if (cachedFilterResult === undefined) {
 | |
|       cachedFilterResult = filter.acceptPosition(iterator) === FILTER_ACCEPT;
 | |
|     }
 | |
|     return (cachedFilterResult);
 | |
|   }
 | |
|   this.isStep = isStep;
 | |
|   function setPosition(newContainer, newOffset) {
 | |
|     resetCache();
 | |
|     return iterator.setUnfilteredPosition(newContainer, newOffset);
 | |
|   }
 | |
|   this.setPosition = setPosition;
 | |
|   function container() {
 | |
|     if (!cachedContainer) {
 | |
|       cachedContainer = iterator.container();
 | |
|     }
 | |
|     return cachedContainer;
 | |
|   }
 | |
|   this.container = container;
 | |
|   function offset() {
 | |
|     if (cachedOffset === undefined) {
 | |
|       cachedOffset = iterator.unfilteredDomOffset();
 | |
|     }
 | |
|     return (cachedOffset);
 | |
|   }
 | |
|   this.offset = offset;
 | |
|   function nextStep() {
 | |
|     resetCache();
 | |
|     while (iterator.nextPosition()) {
 | |
|       resetCache();
 | |
|       if (isStep()) {
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   this.nextStep = nextStep;
 | |
|   function previousStep() {
 | |
|     resetCache();
 | |
|     while (iterator.previousPosition()) {
 | |
|       resetCache();
 | |
|       if (isStep()) {
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   this.previousStep = previousStep;
 | |
|   this.advanceStep = function(direction) {
 | |
|     return direction === NEXT ? nextStep() : previousStep();
 | |
|   };
 | |
|   this.roundToClosestStep = function() {
 | |
|     var currentContainer, currentOffset, isAtStep = isStep();
 | |
|     if (!isAtStep) {
 | |
|       currentContainer = container();
 | |
|       currentOffset = offset();
 | |
|       isAtStep = previousStep();
 | |
|       if (!isAtStep) {
 | |
|         setPosition(currentContainer, currentOffset);
 | |
|         isAtStep = nextStep();
 | |
|       }
 | |
|     }
 | |
|     return isAtStep;
 | |
|   };
 | |
|   this.roundToPreviousStep = function() {
 | |
|     var isAtStep = isStep();
 | |
|     if (!isAtStep) {
 | |
|       isAtStep = previousStep();
 | |
|     }
 | |
|     return isAtStep;
 | |
|   };
 | |
|   this.roundToNextStep = function() {
 | |
|     var isAtStep = isStep();
 | |
|     if (!isAtStep) {
 | |
|       isAtStep = nextStep();
 | |
|     }
 | |
|     return isAtStep;
 | |
|   };
 | |
|   this.leftNode = function() {
 | |
|     return iterator.leftNode();
 | |
|   };
 | |
|   this.snapshot = function() {
 | |
|     return new core.StepIterator.StepSnapshot(container(), offset());
 | |
|   };
 | |
|   this.restore = function(snapshot) {
 | |
|     setPosition(snapshot.container, snapshot.offset);
 | |
|   };
 | |
| };
 | |
| core.StepIterator.StepSnapshot = function(container, offset) {
 | |
|   this.container = container;
 | |
|   this.offset = offset;
 | |
| };
 | |
| core.Utils = function Utils() {
 | |
|   function hashString(value) {
 | |
|     var hash = 0, i, l;
 | |
|     for (i = 0, l = value.length;i < l;i += 1) {
 | |
|       hash = (hash << 5) - hash + value.charCodeAt(i);
 | |
|       hash |= 0;
 | |
|     }
 | |
|     return hash;
 | |
|   }
 | |
|   this.hashString = hashString;
 | |
|   var mergeObjects;
 | |
|   function mergeItems(destination, source) {
 | |
|     if (source && Array.isArray(source)) {
 | |
|       destination = destination || [];
 | |
|       if (!Array.isArray(destination)) {
 | |
|         throw "Destination is not an array.";
 | |
|       }
 | |
|       destination = (destination).concat((source).map(function(obj) {
 | |
|         return mergeItems(null, obj);
 | |
|       }));
 | |
|     } else {
 | |
|       if (source && typeof source === "object") {
 | |
|         destination = destination || {};
 | |
|         if (typeof destination !== "object") {
 | |
|           throw "Destination is not an object.";
 | |
|         }
 | |
|         Object.keys((source)).forEach(function(p) {
 | |
|           destination[p] = mergeItems(destination[p], source[p]);
 | |
|         });
 | |
|       } else {
 | |
|         destination = source;
 | |
|       }
 | |
|     }
 | |
|     return destination;
 | |
|   }
 | |
|   mergeObjects = function(destination, source) {
 | |
|     Object.keys(source).forEach(function(p) {
 | |
|       destination[p] = mergeItems(destination[p], source[p]);
 | |
|     });
 | |
|     return destination;
 | |
|   };
 | |
|   this.mergeObjects = mergeObjects;
 | |
| };
 | |
| core.Zip = function Zip(url, entriesReadCallback) {
 | |
|   var entries, fileData, filesize, nEntries, inflate = core.RawInflate.inflate, zip = this, base64 = new core.Base64;
 | |
|   function read(offset, length, callback) {
 | |
|     if (fileData) {
 | |
|       callback(null, fileData.subarray(offset, offset + length));
 | |
|     } else {
 | |
|       callback("File data not loaded", null);
 | |
|     }
 | |
|   }
 | |
|   function crc32(data) {
 | |
|     var table = [0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 
 | |
|     3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 
 | |
|     453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 
 | |
|     3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 
 | |
|     1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 
 | |
|     1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918E3, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117], crc = 
 | |
|     0, i, iTop = data.length, x = 0, y = 0;
 | |
|     crc = crc ^ -1;
 | |
|     for (i = 0;i < iTop;i += 1) {
 | |
|       y = (crc ^ data[i]) & 255;
 | |
|       x = table[y];
 | |
|       crc = crc >>> 8 ^ x;
 | |
|     }
 | |
|     return crc ^ -1;
 | |
|   }
 | |
|   function dosTime2Date(dostime) {
 | |
|     var year = (dostime >> 25 & 127) + 1980, month = (dostime >> 21 & 15) - 1, mday = dostime >> 16 & 31, hour = dostime >> 11 & 15, min = dostime >> 5 & 63, sec = (dostime & 31) << 1, d = new Date(year, month, mday, hour, min, sec);
 | |
|     return d;
 | |
|   }
 | |
|   function date2DosTime(date) {
 | |
|     var y = date.getFullYear();
 | |
|     return y < 1980 ? 0 : y - 1980 << 25 | date.getMonth() + 1 << 21 | date.getDate() << 16 | date.getHours() << 11 | date.getMinutes() << 5 | date.getSeconds() >> 1;
 | |
|   }
 | |
|   function ZipEntry(url, stream) {
 | |
|     var sig, namelen, extralen, commentlen, compressionMethod, compressedSize, uncompressedSize, offset, entry = this;
 | |
|     function handleEntryData(data, callback) {
 | |
|       var estream = new core.ByteArray(data), esig = estream.readUInt32LE(), filenamelen, eextralen;
 | |
|       if (esig !== 67324752) {
 | |
|         callback("File entry signature is wrong." + esig.toString() + " " + data.length.toString(), null);
 | |
|         return;
 | |
|       }
 | |
|       estream.pos += 22;
 | |
|       filenamelen = estream.readUInt16LE();
 | |
|       eextralen = estream.readUInt16LE();
 | |
|       estream.pos += filenamelen + eextralen;
 | |
|       if (compressionMethod) {
 | |
|         data = data.subarray(estream.pos, estream.pos + compressedSize);
 | |
|         if (compressedSize !== data.length) {
 | |
|           callback("The amount of compressed bytes read was " + data.length.toString() + " instead of " + compressedSize.toString() + " for " + entry.filename + " in " + url + ".", null);
 | |
|           return;
 | |
|         }
 | |
|         data = inflate(data, uncompressedSize);
 | |
|       } else {
 | |
|         data = data.subarray(estream.pos, estream.pos + uncompressedSize);
 | |
|       }
 | |
|       if (uncompressedSize !== data.length) {
 | |
|         callback("The amount of bytes read was " + data.length.toString() + " instead of " + uncompressedSize.toString() + " for " + entry.filename + " in " + url + ".", null);
 | |
|         return;
 | |
|       }
 | |
|       entry.data = data;
 | |
|       callback(null, data);
 | |
|     }
 | |
|     function load(callback) {
 | |
|       if (entry.data !== null) {
 | |
|         callback(null, entry.data);
 | |
|         return;
 | |
|       }
 | |
|       var size = compressedSize + 34 + namelen + extralen + 256;
 | |
|       if (size + offset > filesize) {
 | |
|         size = filesize - offset;
 | |
|       }
 | |
|       read(offset, size, function(err, data) {
 | |
|         if (err || data === null) {
 | |
|           callback(err, data);
 | |
|         } else {
 | |
|           handleEntryData(data, callback);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     this.load = load;
 | |
|     function set(filename, data, compressed, date) {
 | |
|       entry.filename = filename;
 | |
|       entry.data = data;
 | |
|       entry.compressed = compressed;
 | |
|       entry.date = date;
 | |
|     }
 | |
|     this.set = set;
 | |
|     this.error = null;
 | |
|     if (!stream) {
 | |
|       return;
 | |
|     }
 | |
|     sig = stream.readUInt32LE();
 | |
|     if (sig !== 33639248) {
 | |
|       this.error = "Central directory entry has wrong signature at position " + (stream.pos - 4).toString() + ' for file "' + url + '": ' + stream.data.length.toString();
 | |
|       return;
 | |
|     }
 | |
|     stream.pos += 6;
 | |
|     compressionMethod = stream.readUInt16LE();
 | |
|     this.date = dosTime2Date(stream.readUInt32LE());
 | |
|     stream.readUInt32LE();
 | |
|     compressedSize = stream.readUInt32LE();
 | |
|     uncompressedSize = stream.readUInt32LE();
 | |
|     namelen = stream.readUInt16LE();
 | |
|     extralen = stream.readUInt16LE();
 | |
|     commentlen = stream.readUInt16LE();
 | |
|     stream.pos += 8;
 | |
|     offset = stream.readUInt32LE();
 | |
|     this.filename = runtime.byteArrayToString(stream.data.subarray(stream.pos, stream.pos + namelen), "utf8");
 | |
|     this.data = null;
 | |
|     stream.pos += namelen + extralen + commentlen;
 | |
|   }
 | |
|   function handleCentralDirectory(data, callback) {
 | |
|     var stream = new core.ByteArray(data), i, e;
 | |
|     entries = [];
 | |
|     for (i = 0;i < nEntries;i += 1) {
 | |
|       e = new ZipEntry(url, stream);
 | |
|       if (e.error) {
 | |
|         callback(e.error, zip);
 | |
|         return;
 | |
|       }
 | |
|       entries[entries.length] = e;
 | |
|     }
 | |
|     callback(null, zip);
 | |
|   }
 | |
|   function handleCentralDirectoryEnd(data, callback) {
 | |
|     if (data.length !== 22) {
 | |
|       callback("Central directory length should be 22.", zip);
 | |
|       return;
 | |
|     }
 | |
|     var stream = new core.ByteArray(data), sig, disk, cddisk, diskNEntries, cdsSize, cdsOffset;
 | |
|     sig = stream.readUInt32LE();
 | |
|     if (sig !== 101010256) {
 | |
|       callback("Central directory signature is wrong: " + sig.toString(), zip);
 | |
|       return;
 | |
|     }
 | |
|     disk = stream.readUInt16LE();
 | |
|     if (disk !== 0) {
 | |
|       callback("Zip files with non-zero disk numbers are not supported.", zip);
 | |
|       return;
 | |
|     }
 | |
|     cddisk = stream.readUInt16LE();
 | |
|     if (cddisk !== 0) {
 | |
|       callback("Zip files with non-zero disk numbers are not supported.", zip);
 | |
|       return;
 | |
|     }
 | |
|     diskNEntries = stream.readUInt16LE();
 | |
|     nEntries = stream.readUInt16LE();
 | |
|     if (diskNEntries !== nEntries) {
 | |
|       callback("Number of entries is inconsistent.", zip);
 | |
|       return;
 | |
|     }
 | |
|     cdsSize = stream.readUInt32LE();
 | |
|     cdsOffset = stream.readUInt16LE();
 | |
|     cdsOffset = filesize - 22 - cdsSize;
 | |
|     read(cdsOffset, filesize - cdsOffset, function(err, data) {
 | |
|       if (err || data === null) {
 | |
|         callback(err, zip);
 | |
|       } else {
 | |
|         handleCentralDirectory(data, callback);
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   function load(filename, callback) {
 | |
|     var entry = null, e, i;
 | |
|     for (i = 0;i < entries.length;i += 1) {
 | |
|       e = entries[i];
 | |
|       if (e.filename === filename) {
 | |
|         entry = e;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (entry) {
 | |
|       if (entry.data) {
 | |
|         callback(null, entry.data);
 | |
|       } else {
 | |
|         entry.load(callback);
 | |
|       }
 | |
|     } else {
 | |
|       callback(filename + " not found.", null);
 | |
|     }
 | |
|   }
 | |
|   function loadAsString(filename, callback) {
 | |
|     load(filename, function(err, data) {
 | |
|       if (err || data === null) {
 | |
|         return callback(err, null);
 | |
|       }
 | |
|       var d = runtime.byteArrayToString(data, "utf8");
 | |
|       callback(null, d);
 | |
|     });
 | |
|   }
 | |
|   function loadContentXmlAsFragments(filename, handler) {
 | |
|     zip.loadAsString(filename, function(err, data) {
 | |
|       if (err) {
 | |
|         return handler.rootElementReady(err);
 | |
|       }
 | |
|       handler.rootElementReady(null, data, true);
 | |
|     });
 | |
|   }
 | |
|   function loadAsDataURL(filename, mimetype, callback) {
 | |
|     load(filename, function(err, data) {
 | |
|       if (err || !data) {
 | |
|         return callback(err, null);
 | |
|       }
 | |
|       var p = data, chunksize = 45E3, i = 0, dataurl;
 | |
|       if (!mimetype) {
 | |
|         if (p[1] === 80 && p[2] === 78 && p[3] === 71) {
 | |
|           mimetype = "image/png";
 | |
|         } else {
 | |
|           if (p[0] === 255 && p[1] === 216 && p[2] === 255) {
 | |
|             mimetype = "image/jpeg";
 | |
|           } else {
 | |
|             if (p[0] === 71 && p[1] === 73 && p[2] === 70) {
 | |
|               mimetype = "image/gif";
 | |
|             } else {
 | |
|               mimetype = "";
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       dataurl = "data:" + mimetype + ";base64,";
 | |
|       while (i < data.length) {
 | |
|         dataurl += base64.convertUTF8ArrayToBase64(p.subarray(i, Math.min(i + chunksize, p.length)));
 | |
|         i += chunksize;
 | |
|       }
 | |
|       callback(null, dataurl);
 | |
|     });
 | |
|   }
 | |
|   function loadAsDOM(filename, callback) {
 | |
|     zip.loadAsString(filename, function(err, xmldata) {
 | |
|       if (err || xmldata === null) {
 | |
|         callback(err, null);
 | |
|         return;
 | |
|       }
 | |
|       var parser = new DOMParser, dom = parser.parseFromString(xmldata, "text/xml");
 | |
|       callback(null, dom);
 | |
|     });
 | |
|   }
 | |
|   function save(filename, data, compressed, date) {
 | |
|     var i, entry;
 | |
|     for (i = 0;i < entries.length;i += 1) {
 | |
|       entry = entries[i];
 | |
|       if (entry.filename === filename) {
 | |
|         entry.set(filename, data, compressed, date);
 | |
|         return;
 | |
|       }
 | |
|     }
 | |
|     entry = new ZipEntry(url);
 | |
|     entry.set(filename, data, compressed, date);
 | |
|     entries.push(entry);
 | |
|   }
 | |
|   function remove(filename) {
 | |
|     var i, entry;
 | |
|     for (i = 0;i < entries.length;i += 1) {
 | |
|       entry = entries[i];
 | |
|       if (entry.filename === filename) {
 | |
|         entries.splice(i, 1);
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function writeEntry(entry) {
 | |
|     var data = new core.ByteArrayWriter("utf8"), length = 0;
 | |
|     data.appendArray([80, 75, 3, 4, 20, 0, 0, 0, 0, 0]);
 | |
|     if (entry.data) {
 | |
|       length = entry.data.length;
 | |
|     }
 | |
|     data.appendUInt32LE(date2DosTime(entry.date));
 | |
|     data.appendUInt32LE(entry.data ? crc32(entry.data) : 0);
 | |
|     data.appendUInt32LE(length);
 | |
|     data.appendUInt32LE(length);
 | |
|     data.appendUInt16LE(entry.filename.length);
 | |
|     data.appendUInt16LE(0);
 | |
|     data.appendString(entry.filename);
 | |
|     if (entry.data) {
 | |
|       data.appendByteArray(entry.data);
 | |
|     }
 | |
|     return data;
 | |
|   }
 | |
|   function writeCODEntry(entry, offset) {
 | |
|     var data = new core.ByteArrayWriter("utf8"), length = 0;
 | |
|     data.appendArray([80, 75, 1, 2, 20, 0, 20, 0, 0, 0, 0, 0]);
 | |
|     if (entry.data) {
 | |
|       length = entry.data.length;
 | |
|     }
 | |
|     data.appendUInt32LE(date2DosTime(entry.date));
 | |
|     data.appendUInt32LE(entry.data ? crc32(entry.data) : 0);
 | |
|     data.appendUInt32LE(length);
 | |
|     data.appendUInt32LE(length);
 | |
|     data.appendUInt16LE(entry.filename.length);
 | |
|     data.appendArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 | |
|     data.appendUInt32LE(offset);
 | |
|     data.appendString(entry.filename);
 | |
|     return data;
 | |
|   }
 | |
|   function loadAllEntries(position, callback) {
 | |
|     if (position === entries.length) {
 | |
|       callback(null);
 | |
|       return;
 | |
|     }
 | |
|     var entry = entries[position];
 | |
|     if (entry.data !== null) {
 | |
|       loadAllEntries(position + 1, callback);
 | |
|       return;
 | |
|     }
 | |
|     entry.load(function(err) {
 | |
|       if (err) {
 | |
|         callback(err);
 | |
|         return;
 | |
|       }
 | |
|       loadAllEntries(position + 1, callback);
 | |
|     });
 | |
|   }
 | |
|   function createByteArray(successCallback, errorCallback) {
 | |
|     loadAllEntries(0, function(err) {
 | |
|       if (err) {
 | |
|         errorCallback(err);
 | |
|         return;
 | |
|       }
 | |
|       var i, e, codoffset, codsize, data = new core.ByteArrayWriter("utf8"), offsets = [0];
 | |
|       for (i = 0;i < entries.length;i += 1) {
 | |
|         data.appendByteArrayWriter(writeEntry(entries[i]));
 | |
|         offsets.push(data.getLength());
 | |
|       }
 | |
|       codoffset = data.getLength();
 | |
|       for (i = 0;i < entries.length;i += 1) {
 | |
|         e = entries[i];
 | |
|         data.appendByteArrayWriter(writeCODEntry(e, offsets[i]));
 | |
|       }
 | |
|       codsize = data.getLength() - codoffset;
 | |
|       data.appendArray([80, 75, 5, 6, 0, 0, 0, 0]);
 | |
|       data.appendUInt16LE(entries.length);
 | |
|       data.appendUInt16LE(entries.length);
 | |
|       data.appendUInt32LE(codsize);
 | |
|       data.appendUInt32LE(codoffset);
 | |
|       data.appendArray([0, 0]);
 | |
|       successCallback(data.getByteArray());
 | |
|     });
 | |
|   }
 | |
|   function writeAs(newurl, callback) {
 | |
|     createByteArray(function(data) {
 | |
|       runtime.writeFile(newurl, data, function(err) {
 | |
|         if (!err) {
 | |
|           fileData = data;
 | |
|           filesize = fileData.length;
 | |
|         }
 | |
|         callback(err);
 | |
|       });
 | |
|     }, callback);
 | |
|   }
 | |
|   function write(callback) {
 | |
|     writeAs(url, callback);
 | |
|   }
 | |
|   this.load = load;
 | |
|   this.save = save;
 | |
|   this.remove = remove;
 | |
|   this.write = write;
 | |
|   this.writeAs = writeAs;
 | |
|   this.createByteArray = createByteArray;
 | |
|   this.loadContentXmlAsFragments = loadContentXmlAsFragments;
 | |
|   this.loadAsString = loadAsString;
 | |
|   this.loadAsDOM = loadAsDOM;
 | |
|   this.loadAsDataURL = loadAsDataURL;
 | |
|   this.getEntries = function() {
 | |
|     return entries.slice();
 | |
|   };
 | |
|   filesize = -1;
 | |
|   if (entriesReadCallback === null) {
 | |
|     entries = [];
 | |
|     return;
 | |
|   }
 | |
|   runtime.readFile(url, "binary", function(err, result) {
 | |
|     if (typeof result === "string") {
 | |
|       err = "file was read as a string. Should be Uint8Array.";
 | |
|     }
 | |
|     if (err || !result || result.length === 0) {
 | |
|       entriesReadCallback("File '" + url + "' cannot be read. Err: " + (err || "[none]"), zip);
 | |
|     } else {
 | |
|       fileData = (result);
 | |
|       filesize = fileData.length;
 | |
|       read(filesize - 22, 22, function(err, data) {
 | |
|         if (err || data === null) {
 | |
|           entriesReadCallback(err, zip);
 | |
|         } else {
 | |
|           handleCentralDirectoryEnd(data, (entriesReadCallback));
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|   });
 | |
| };
 | |
| core.SimpleClientRect = null;
 | |
| gui.CommonConstraints = {EDIT:{ANNOTATIONS:{ONLY_DELETE_OWN:"onlyDeleteOwn"}, REVIEW_MODE:"reviewMode"}};
 | |
| gui.SessionConstraints = function SessionConstraints() {
 | |
|   var constraints = {}, constraintNotifier = new core.EventNotifier;
 | |
|   function registerConstraint(constraint) {
 | |
|     if (!constraints.hasOwnProperty(constraint)) {
 | |
|       constraints[constraint] = false;
 | |
|       constraintNotifier.register(constraint);
 | |
|     }
 | |
|   }
 | |
|   this.registerConstraint = registerConstraint;
 | |
|   this.subscribe = function(constraint, callback) {
 | |
|     registerConstraint(constraint);
 | |
|     constraintNotifier.subscribe(constraint, callback);
 | |
|   };
 | |
|   this.unsubscribe = function(constraint, callback) {
 | |
|     constraintNotifier.unsubscribe(constraint, callback);
 | |
|   };
 | |
|   this.setState = function(constraint, enabled) {
 | |
|     runtime.assert(constraints.hasOwnProperty(constraint) === true, "No such constraint");
 | |
|     if (constraints[constraint] !== enabled) {
 | |
|       constraints[constraint] = enabled;
 | |
|       constraintNotifier.emit(constraint, enabled);
 | |
|     }
 | |
|   };
 | |
|   this.getState = function(constraint) {
 | |
|     runtime.assert(constraints.hasOwnProperty(constraint) === true, "No such constraint");
 | |
|     return constraints[constraint];
 | |
|   };
 | |
| };
 | |
| gui.BlacklistNamespaceNodeFilter = function(excludedNamespaces) {
 | |
|   var excludedNamespacesObj = {}, FILTER_REJECT = NodeFilter.FILTER_REJECT, FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT;
 | |
|   this.acceptNode = function(node) {
 | |
|     if (!node || excludedNamespacesObj.hasOwnProperty(node.namespaceURI)) {
 | |
|       return FILTER_REJECT;
 | |
|     }
 | |
|     return FILTER_ACCEPT;
 | |
|   };
 | |
|   function init() {
 | |
|     excludedNamespaces.forEach(function(ns) {
 | |
|       excludedNamespacesObj[ns] = true;
 | |
|     });
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.Namespaces = {namespaceMap:{config:"urn:oasis:names:tc:opendocument:xmlns:config:1.0", db:"urn:oasis:names:tc:opendocument:xmlns:database:1.0", dc:"http://purl.org/dc/elements/1.1/", dr3d:"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0", draw:"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", chart:"urn:oasis:names:tc:opendocument:xmlns:chart:1.0", fo:"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", form:"urn:oasis:names:tc:opendocument:xmlns:form:1.0", math:"http://www.w3.org/1998/Math/MathML", 
 | |
| meta:"urn:oasis:names:tc:opendocument:xmlns:meta:1.0", number:"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0", office:"urn:oasis:names:tc:opendocument:xmlns:office:1.0", presentation:"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0", style:"urn:oasis:names:tc:opendocument:xmlns:style:1.0", svg:"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", table:"urn:oasis:names:tc:opendocument:xmlns:table:1.0", text:"urn:oasis:names:tc:opendocument:xmlns:text:1.0", xforms:"http://www.w3.org/2002/xforms", 
 | |
| xlink:"http://www.w3.org/1999/xlink", xml:"http://www.w3.org/XML/1998/namespace"}, prefixMap:{}, configns:"urn:oasis:names:tc:opendocument:xmlns:config:1.0", dbns:"urn:oasis:names:tc:opendocument:xmlns:database:1.0", dcns:"http://purl.org/dc/elements/1.1/", dr3dns:"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0", drawns:"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", chartns:"urn:oasis:names:tc:opendocument:xmlns:chart:1.0", fons:"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", 
 | |
| formns:"urn:oasis:names:tc:opendocument:xmlns:form:1.0", mathns:"http://www.w3.org/1998/Math/MathML", metans:"urn:oasis:names:tc:opendocument:xmlns:meta:1.0", numberns:"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0", officens:"urn:oasis:names:tc:opendocument:xmlns:office:1.0", presentationns:"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0", stylens:"urn:oasis:names:tc:opendocument:xmlns:style:1.0", svgns:"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", tablens:"urn:oasis:names:tc:opendocument:xmlns:table:1.0", 
 | |
| textns:"urn:oasis:names:tc:opendocument:xmlns:text:1.0", xformsns:"http://www.w3.org/2002/xforms", xlinkns:"http://www.w3.org/1999/xlink", xmlns:"http://www.w3.org/XML/1998/namespace"};
 | |
| (function() {
 | |
|   var map = odf.Namespaces.namespaceMap, pmap = odf.Namespaces.prefixMap, prefix;
 | |
|   for (prefix in map) {
 | |
|     if (map.hasOwnProperty(prefix)) {
 | |
|       pmap[map[prefix]] = prefix;
 | |
|     }
 | |
|   }
 | |
| })();
 | |
| odf.Namespaces.forEachPrefix = function forEachPrefix(cb) {
 | |
|   var ns = odf.Namespaces.namespaceMap, prefix;
 | |
|   for (prefix in ns) {
 | |
|     if (ns.hasOwnProperty(prefix)) {
 | |
|       cb(prefix, ns[prefix]);
 | |
|     }
 | |
|   }
 | |
| };
 | |
| odf.Namespaces.lookupNamespaceURI = function lookupNamespaceURI(prefix) {
 | |
|   var r = null;
 | |
|   if (odf.Namespaces.namespaceMap.hasOwnProperty(prefix)) {
 | |
|     r = (odf.Namespaces.namespaceMap[prefix]);
 | |
|   }
 | |
|   return r;
 | |
| };
 | |
| odf.Namespaces.lookupPrefix = function lookupPrefix(namespaceURI) {
 | |
|   var map = odf.Namespaces.prefixMap;
 | |
|   return map.hasOwnProperty(namespaceURI) ? map[namespaceURI] : null;
 | |
| };
 | |
| odf.Namespaces.lookupNamespaceURI.lookupNamespaceURI = odf.Namespaces.lookupNamespaceURI;
 | |
| (function() {
 | |
|   odf.OdfSchemaImpl = function() {
 | |
|     var TEXT = "text", FIELD = "field", OBJECT = "object", STYLE = "style", DEPRECATED = "deprecated", UNKNOWN = "uncategorized", containers = [["config:config-item", UNKNOWN], ["form:item", OBJECT], ["form:option", UNKNOWN], ["math:math", FIELD], ["meta:user-defined", UNKNOWN], ["number:currency-symbol", UNKNOWN], ["number:embedded-text", UNKNOWN], ["number:text", UNKNOWN], ["presentation:date-time-decl", UNKNOWN], ["presentation:footer-decl", UNKNOWN], ["presentation:header-decl", UNKNOWN], ["svg:desc", 
 | |
|     TEXT], ["svg:title", TEXT], ["table:desc", UNKNOWN], ["table:title", UNKNOWN], ["text:a", TEXT], ["text:author-initials", FIELD], ["text:author-name", FIELD], ["text:bibliography-mark", FIELD], ["text:bookmark-ref", FIELD], ["text:chapter", FIELD], ["text:character-count", FIELD], ["text:conditional-text", FIELD], ["text:creation-date", FIELD], ["text:creation-time", FIELD], ["text:creator", FIELD], ["text:database-display", FIELD], ["text:database-name", FIELD], ["text:database-row-number", 
 | |
|     FIELD], ["text:date", FIELD], ["text:dde-connection", FIELD], ["text:description", FIELD], ["text:editing-cycles", FIELD], ["text:editing-duration", FIELD], ["text:execute-macro", UNKNOWN], ["text:expression", UNKNOWN], ["text:file-name", FIELD], ["text:h", TEXT], ["text:hidden-paragraph", TEXT], ["text:hidden-text", TEXT], ["text:image-count", FIELD], ["text:index-entry-span", UNKNOWN], ["text:index-title-template", UNKNOWN], ["text:initial-creator", FIELD], ["text:keywords", FIELD], ["text:linenumbering-separator", 
 | |
|     STYLE], ["text:measure", UNKNOWN], ["text:meta", UNKNOWN], ["text:meta-field", UNKNOWN], ["text:modification-date", FIELD], ["text:modification-time", FIELD], ["text:note-citation", FIELD], ["text:note-continuation-notice-backward", STYLE], ["text:note-continuation-notice-forward", STYLE], ["text:note-ref", FIELD], ["text:object-count", FIELD], ["text:p", TEXT], ["text:page-continuation", UNKNOWN], ["text:page-count", FIELD], ["text:page-number", FIELD], ["text:page-variable-get", FIELD], ["text:page-variable-set", 
 | |
|     FIELD], ["text:paragraph-count", FIELD], ["text:placeholder", FIELD], ["text:print-date", FIELD], ["text:print-time", FIELD], ["text:printed-by", FIELD], ["text:reference-ref", FIELD], ["text:ruby-base", TEXT], ["text:ruby-text", TEXT], ["text:script", TEXT], ["text:sender-city", FIELD], ["text:sender-company", FIELD], ["text:sender-country", FIELD], ["text:sender-email", FIELD], ["text:sender-fax", FIELD], ["text:sender-firstname", FIELD], ["text:sender-initials", FIELD], ["text:sender-lastname", 
 | |
|     FIELD], ["text:sender-phone-private", FIELD], ["text:sender-phone-work", FIELD], ["text:sender-position", FIELD], ["text:sender-postal-code", FIELD], ["text:sender-state-or-province", FIELD], ["text:sender-street", FIELD], ["text:sender-title", FIELD], ["text:sequence", UNKNOWN], ["text:sequence-ref", UNKNOWN], ["text:sheet-name", UNKNOWN], ["text:span", TEXT], ["text:subject", FIELD], ["text:table-count", FIELD], ["text:table-formula", DEPRECATED], ["text:template-name", UNKNOWN], ["text:text-input", 
 | |
|     FIELD], ["text:time", FIELD], ["text:title", FIELD], ["text:user-defined", FIELD], ["text:user-field-get", FIELD], ["text:user-field-input", FIELD], ["text:variable-get", FIELD], ["text:variable-input", FIELD], ["text:variable-set", FIELD], ["text:word-count", FIELD], ["xforms:model", UNKNOWN]], cache = {};
 | |
|     this.isTextContainer = function(namespaceURI, localName) {
 | |
|       return cache[namespaceURI + ":" + localName] === TEXT;
 | |
|     };
 | |
|     this.isField = function(namespaceURI, localName) {
 | |
|       return cache[namespaceURI + ":" + localName] === FIELD;
 | |
|     };
 | |
|     this.getFields = function() {
 | |
|       return containers.filter(function(containerInfo) {
 | |
|         return containerInfo[1] === FIELD;
 | |
|       }).map(function(containerInfo) {
 | |
|         return containerInfo[0];
 | |
|       });
 | |
|     };
 | |
|     function init() {
 | |
|       containers.forEach(function(containerInfo) {
 | |
|         var name = containerInfo[0], type = containerInfo[1], nameParts = name.split(":"), prefix = nameParts[0], localName = nameParts[1], namespaceURI = odf.Namespaces.lookupNamespaceURI(prefix);
 | |
|         if (namespaceURI) {
 | |
|           cache[namespaceURI + ":" + localName] = type;
 | |
|         } else {
 | |
|           runtime.log("DEBUG: OdfSchema - unknown prefix '" + prefix + "'");
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
|   odf.OdfSchema = new odf.OdfSchemaImpl;
 | |
| })();
 | |
| odf.OdfUtilsImpl = function OdfUtilsImpl() {
 | |
|   var textns = odf.Namespaces.textns, drawns = odf.Namespaces.drawns, xlinkns = odf.Namespaces.xlinkns, domUtils = core.DomUtils, odfNodeNamespaceMap = [odf.Namespaces.dbns, odf.Namespaces.dcns, odf.Namespaces.dr3dns, odf.Namespaces.drawns, odf.Namespaces.chartns, odf.Namespaces.formns, odf.Namespaces.numberns, odf.Namespaces.officens, odf.Namespaces.presentationns, odf.Namespaces.stylens, odf.Namespaces.svgns, odf.Namespaces.tablens, odf.Namespaces.textns], odfSchema = odf.OdfSchema;
 | |
|   function isImage(e) {
 | |
|     var name = e && e.localName;
 | |
|     return name === "image" && e.namespaceURI === drawns;
 | |
|   }
 | |
|   this.isImage = isImage;
 | |
|   function isCharacterFrame(e) {
 | |
|     return e !== null && e.nodeType === Node.ELEMENT_NODE && e.localName === "frame" && e.namespaceURI === drawns && (e).getAttributeNS(textns, "anchor-type") === "as-char";
 | |
|   }
 | |
|   this.isCharacterFrame = isCharacterFrame;
 | |
|   function isAnnotation(e) {
 | |
|     var name = e && e.localName;
 | |
|     return name === "annotation" && e.namespaceURI === odf.Namespaces.officens;
 | |
|   }
 | |
|   function isAnnotationWrapper(e) {
 | |
|     var name = e && e.localName;
 | |
|     return name === "div" && (e).className === "annotationWrapper";
 | |
|   }
 | |
|   function isInlineRoot(e) {
 | |
|     return isAnnotation(e) || isAnnotationWrapper(e);
 | |
|   }
 | |
|   this.isInlineRoot = isInlineRoot;
 | |
|   this.isTextSpan = function(e) {
 | |
|     var name = e && e.localName;
 | |
|     return name === "span" && e.namespaceURI === textns;
 | |
|   };
 | |
|   function isHyperlink(node) {
 | |
|     var name = node && node.localName;
 | |
|     return name === "a" && node.namespaceURI === textns;
 | |
|   }
 | |
|   this.isHyperlink = isHyperlink;
 | |
|   this.getHyperlinkTarget = function(element) {
 | |
|     return element.getAttributeNS(xlinkns, "href") || "";
 | |
|   };
 | |
|   function isParagraph(e) {
 | |
|     var name = e && e.localName;
 | |
|     return (name === "p" || name === "h") && e.namespaceURI === textns;
 | |
|   }
 | |
|   this.isParagraph = isParagraph;
 | |
|   function getParagraphElement(node, offset) {
 | |
|     if (node && offset !== undefined && !isParagraph(node) && node.childNodes.item(offset)) {
 | |
|       node = node.childNodes.item(offset);
 | |
|     }
 | |
|     while (node && !isParagraph(node)) {
 | |
|       node = node.parentNode;
 | |
|     }
 | |
|     return (node);
 | |
|   }
 | |
|   this.getParagraphElement = getParagraphElement;
 | |
|   function getParentAnnotation(node, container) {
 | |
|     while (node && node !== container) {
 | |
|       if (node.namespaceURI === odf.Namespaces.officens && node.localName === "annotation") {
 | |
|         return (node);
 | |
|       }
 | |
|       node = node.parentNode;
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   this.getParentAnnotation = getParentAnnotation;
 | |
|   this.isWithinAnnotation = function(node, container) {
 | |
|     return Boolean(getParentAnnotation(node, container));
 | |
|   };
 | |
|   this.getAnnotationCreator = function(annotationElement) {
 | |
|     var creatorElement = (annotationElement.getElementsByTagNameNS(odf.Namespaces.dcns, "creator")[0]);
 | |
|     return creatorElement.textContent;
 | |
|   };
 | |
|   this.isListItem = function(e) {
 | |
|     var name = e && e.localName;
 | |
|     return name === "list-item" && e.namespaceURI === textns;
 | |
|   };
 | |
|   this.isLineBreak = function(e) {
 | |
|     var name = e && e.localName;
 | |
|     return name === "line-break" && e.namespaceURI === textns;
 | |
|   };
 | |
|   function isODFWhitespace(text) {
 | |
|     return /^[ \t\r\n]+$/.test(text);
 | |
|   }
 | |
|   this.isODFWhitespace = isODFWhitespace;
 | |
|   function isGroupingElement(n) {
 | |
|     if (n === null || n.nodeType !== Node.ELEMENT_NODE) {
 | |
|       return false;
 | |
|     }
 | |
|     var e = (n), localName = e.localName;
 | |
|     return odfSchema.isTextContainer(e.namespaceURI, localName) || localName === "span" && e.className === "webodf-annotationHighlight";
 | |
|   }
 | |
|   this.isGroupingElement = isGroupingElement;
 | |
|   function isFieldElement(n) {
 | |
|     if (n === null || n.nodeType !== Node.ELEMENT_NODE) {
 | |
|       return false;
 | |
|     }
 | |
|     var e = (n), localName = e.localName;
 | |
|     return odfSchema.isField(e.namespaceURI, localName);
 | |
|   }
 | |
|   this.isFieldElement = isFieldElement;
 | |
|   function isCharacterElement(e) {
 | |
|     var n = e && e.localName, ns, r = false;
 | |
|     if (n) {
 | |
|       ns = e.namespaceURI;
 | |
|       if (ns === textns) {
 | |
|         r = n === "s" || n === "tab" || n === "line-break";
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.isCharacterElement = isCharacterElement;
 | |
|   function isAnchoredAsCharacterElement(e) {
 | |
|     return isCharacterElement(e) || isFieldElement(e) || isCharacterFrame(e) || isInlineRoot(e);
 | |
|   }
 | |
|   this.isAnchoredAsCharacterElement = isAnchoredAsCharacterElement;
 | |
|   function isSpaceElement(e) {
 | |
|     var n = e && e.localName, ns, r = false;
 | |
|     if (n) {
 | |
|       ns = e.namespaceURI;
 | |
|       if (ns === textns) {
 | |
|         r = n === "s";
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.isSpaceElement = isSpaceElement;
 | |
|   function isODFNode(node) {
 | |
|     return odfNodeNamespaceMap.indexOf(node.namespaceURI) !== -1;
 | |
|   }
 | |
|   this.isODFNode = isODFNode;
 | |
|   function hasNoODFContent(node) {
 | |
|     var childNode;
 | |
|     if (isCharacterElement(node) || isFieldElement(node)) {
 | |
|       return false;
 | |
|     }
 | |
|     if (isGroupingElement((node.parentNode)) && node.nodeType === Node.TEXT_NODE) {
 | |
|       return node.textContent.length === 0;
 | |
|     }
 | |
|     childNode = node.firstChild;
 | |
|     while (childNode) {
 | |
|       if (isODFNode(childNode) || !hasNoODFContent(childNode)) {
 | |
|         return false;
 | |
|       }
 | |
|       childNode = childNode.nextSibling;
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   this.hasNoODFContent = hasNoODFContent;
 | |
|   function firstChild(node) {
 | |
|     while (node.firstChild !== null && isGroupingElement(node)) {
 | |
|       node = node.firstChild;
 | |
|     }
 | |
|     return node;
 | |
|   }
 | |
|   this.firstChild = firstChild;
 | |
|   function lastChild(node) {
 | |
|     while (node.lastChild !== null && isGroupingElement(node)) {
 | |
|       node = node.lastChild;
 | |
|     }
 | |
|     return node;
 | |
|   }
 | |
|   this.lastChild = lastChild;
 | |
|   function previousNode(node) {
 | |
|     while (!isParagraph(node) && node.previousSibling === null) {
 | |
|       node = (node.parentNode);
 | |
|     }
 | |
|     return isParagraph(node) ? null : lastChild((node.previousSibling));
 | |
|   }
 | |
|   this.previousNode = previousNode;
 | |
|   function nextNode(node) {
 | |
|     while (!isParagraph(node) && node.nextSibling === null) {
 | |
|       node = (node.parentNode);
 | |
|     }
 | |
|     return isParagraph(node) ? null : firstChild((node.nextSibling));
 | |
|   }
 | |
|   this.nextNode = nextNode;
 | |
|   function scanLeftForNonSpace(node) {
 | |
|     var r = false, text;
 | |
|     while (node) {
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         text = (node);
 | |
|         if (text.length === 0) {
 | |
|           node = previousNode(text);
 | |
|         } else {
 | |
|           return !isODFWhitespace(text.data.substr(text.length - 1, 1));
 | |
|         }
 | |
|       } else {
 | |
|         if (isAnchoredAsCharacterElement(node)) {
 | |
|           r = isSpaceElement(node) === false;
 | |
|           node = null;
 | |
|         } else {
 | |
|           node = previousNode(node);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.scanLeftForNonSpace = scanLeftForNonSpace;
 | |
|   function lookLeftForCharacter(node) {
 | |
|     var text, r = 0, tl = 0;
 | |
|     if (node.nodeType === Node.TEXT_NODE) {
 | |
|       tl = (node).length;
 | |
|     }
 | |
|     if (tl > 0) {
 | |
|       text = (node).data;
 | |
|       if (!isODFWhitespace(text.substr(tl - 1, 1))) {
 | |
|         r = 1;
 | |
|       } else {
 | |
|         if (tl === 1) {
 | |
|           r = scanLeftForNonSpace(previousNode(node)) ? 2 : 0;
 | |
|         } else {
 | |
|           r = isODFWhitespace(text.substr(tl - 2, 1)) ? 0 : 2;
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       if (isAnchoredAsCharacterElement(node)) {
 | |
|         r = 1;
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.lookLeftForCharacter = lookLeftForCharacter;
 | |
|   function lookRightForCharacter(node) {
 | |
|     var r = false, l = 0;
 | |
|     if (node && node.nodeType === Node.TEXT_NODE) {
 | |
|       l = (node).length;
 | |
|     }
 | |
|     if (l > 0) {
 | |
|       r = !isODFWhitespace((node).data.substr(0, 1));
 | |
|     } else {
 | |
|       if (isAnchoredAsCharacterElement(node)) {
 | |
|         r = true;
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.lookRightForCharacter = lookRightForCharacter;
 | |
|   function scanLeftForAnyCharacter(node) {
 | |
|     var r = false, l;
 | |
|     node = node && lastChild(node);
 | |
|     while (node) {
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         l = (node).length;
 | |
|       } else {
 | |
|         l = 0;
 | |
|       }
 | |
|       if (l > 0 && !isODFWhitespace((node).data)) {
 | |
|         r = true;
 | |
|         break;
 | |
|       }
 | |
|       if (isAnchoredAsCharacterElement(node)) {
 | |
|         r = true;
 | |
|         break;
 | |
|       }
 | |
|       node = previousNode(node);
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.scanLeftForAnyCharacter = scanLeftForAnyCharacter;
 | |
|   function scanRightForAnyCharacter(node) {
 | |
|     var r = false, l;
 | |
|     node = node && firstChild(node);
 | |
|     while (node) {
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         l = (node).length;
 | |
|       } else {
 | |
|         l = 0;
 | |
|       }
 | |
|       if (l > 0 && !isODFWhitespace((node).data)) {
 | |
|         r = true;
 | |
|         break;
 | |
|       }
 | |
|       if (isAnchoredAsCharacterElement(node)) {
 | |
|         r = true;
 | |
|         break;
 | |
|       }
 | |
|       node = nextNode(node);
 | |
|     }
 | |
|     return r;
 | |
|   }
 | |
|   this.scanRightForAnyCharacter = scanRightForAnyCharacter;
 | |
|   function isTrailingWhitespace(textnode, offset) {
 | |
|     if (!isODFWhitespace(textnode.data.substr(offset))) {
 | |
|       return false;
 | |
|     }
 | |
|     return !scanRightForAnyCharacter(nextNode(textnode));
 | |
|   }
 | |
|   this.isTrailingWhitespace = isTrailingWhitespace;
 | |
|   function isSignificantWhitespace(textNode, offset) {
 | |
|     var text = textNode.data, result;
 | |
|     if (!isODFWhitespace(text[offset])) {
 | |
|       return false;
 | |
|     }
 | |
|     if (isAnchoredAsCharacterElement(textNode.parentNode)) {
 | |
|       return false;
 | |
|     }
 | |
|     if (offset > 0) {
 | |
|       if (!isODFWhitespace(text[offset - 1])) {
 | |
|         result = true;
 | |
|       }
 | |
|     } else {
 | |
|       if (scanLeftForNonSpace(previousNode(textNode))) {
 | |
|         result = true;
 | |
|       }
 | |
|     }
 | |
|     if (result === true) {
 | |
|       return isTrailingWhitespace(textNode, offset) ? false : true;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   this.isSignificantWhitespace = isSignificantWhitespace;
 | |
|   this.isDowngradableSpaceElement = function(node) {
 | |
|     if (isSpaceElement(node)) {
 | |
|       return scanLeftForNonSpace(previousNode(node)) && scanRightForAnyCharacter(nextNode(node));
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
|   function parseLength(length) {
 | |
|     var re = /(-?[0-9]*[0-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px)|(%))/, m = re.exec(length);
 | |
|     if (!m) {
 | |
|       return null;
 | |
|     }
 | |
|     return {value:parseFloat(m[1]), unit:m[3]};
 | |
|   }
 | |
|   this.parseLength = parseLength;
 | |
|   function parsePositiveLength(length) {
 | |
|     var result = parseLength(length);
 | |
|     if (result && (result.value <= 0 || result.unit === "%")) {
 | |
|       return null;
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   function parseNonNegativeLength(length) {
 | |
|     var result = parseLength(length);
 | |
|     if (result && (result.value < 0 || result.unit === "%")) {
 | |
|       return null;
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   this.parseNonNegativeLength = parseNonNegativeLength;
 | |
|   function parsePercentage(length) {
 | |
|     var result = parseLength(length);
 | |
|     if (result && result.unit !== "%") {
 | |
|       return null;
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   function parseFoFontSize(fontSize) {
 | |
|     return parsePositiveLength(fontSize) || parsePercentage(fontSize);
 | |
|   }
 | |
|   this.parseFoFontSize = parseFoFontSize;
 | |
|   function parseFoLineHeight(lineHeight) {
 | |
|     return parseNonNegativeLength(lineHeight) || parsePercentage(lineHeight);
 | |
|   }
 | |
|   this.parseFoLineHeight = parseFoLineHeight;
 | |
|   function isTextContentContainingNode(node) {
 | |
|     switch(node.namespaceURI) {
 | |
|       case odf.Namespaces.drawns:
 | |
|       ;
 | |
|       case odf.Namespaces.svgns:
 | |
|       ;
 | |
|       case odf.Namespaces.dr3dns:
 | |
|         return false;
 | |
|       case odf.Namespaces.textns:
 | |
|         switch(node.localName) {
 | |
|           case "note-body":
 | |
|           ;
 | |
|           case "ruby-text":
 | |
|             return false;
 | |
|         }
 | |
|         break;
 | |
|       case odf.Namespaces.officens:
 | |
|         switch(node.localName) {
 | |
|           case "annotation":
 | |
|           ;
 | |
|           case "binary-data":
 | |
|           ;
 | |
|           case "event-listeners":
 | |
|             return false;
 | |
|         }
 | |
|         break;
 | |
|       default:
 | |
|         switch(node.localName) {
 | |
|           case "cursor":
 | |
|           ;
 | |
|           case "editinfo":
 | |
|             return false;
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   this.isTextContentContainingNode = isTextContentContainingNode;
 | |
|   function isSignificantTextContent(textNode) {
 | |
|     return Boolean(getParagraphElement(textNode) && (!isODFWhitespace(textNode.textContent) || isSignificantWhitespace(textNode, 0)));
 | |
|   }
 | |
|   function removePartiallyContainedNodes(range, nodes) {
 | |
|     while (nodes.length > 0 && !domUtils.rangeContainsNode(range, (nodes[0]))) {
 | |
|       nodes.shift();
 | |
|     }
 | |
|     while (nodes.length > 0 && !domUtils.rangeContainsNode(range, (nodes[nodes.length - 1]))) {
 | |
|       nodes.pop();
 | |
|     }
 | |
|   }
 | |
|   function getTextNodes(range, includePartial) {
 | |
|     var textNodes;
 | |
|     function nodeFilter(node) {
 | |
|       var result = NodeFilter.FILTER_REJECT;
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         if (isSignificantTextContent((node))) {
 | |
|           result = NodeFilter.FILTER_ACCEPT;
 | |
|         }
 | |
|       } else {
 | |
|         if (isTextContentContainingNode(node)) {
 | |
|           result = NodeFilter.FILTER_SKIP;
 | |
|         }
 | |
|       }
 | |
|       return result;
 | |
|     }
 | |
|     textNodes = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
 | |
|     if (!includePartial) {
 | |
|       removePartiallyContainedNodes(range, textNodes);
 | |
|     }
 | |
|     return textNodes;
 | |
|   }
 | |
|   this.getTextNodes = getTextNodes;
 | |
|   function getTextElements(range, includePartial, includeInsignificantWhitespace) {
 | |
|     var elements;
 | |
|     function nodeFilter(node) {
 | |
|       var result = NodeFilter.FILTER_REJECT;
 | |
|       if (isCharacterElement(node.parentNode) || isFieldElement(node.parentNode) || isInlineRoot(node)) {
 | |
|         result = NodeFilter.FILTER_REJECT;
 | |
|       } else {
 | |
|         if (node.nodeType === Node.TEXT_NODE) {
 | |
|           if (includeInsignificantWhitespace || isSignificantTextContent((node))) {
 | |
|             result = NodeFilter.FILTER_ACCEPT;
 | |
|           }
 | |
|         } else {
 | |
|           if (isAnchoredAsCharacterElement(node)) {
 | |
|             result = NodeFilter.FILTER_ACCEPT;
 | |
|           } else {
 | |
|             if (isTextContentContainingNode(node) || isGroupingElement(node)) {
 | |
|               result = NodeFilter.FILTER_SKIP;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       return result;
 | |
|     }
 | |
|     elements = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
 | |
|     if (!includePartial) {
 | |
|       removePartiallyContainedNodes(range, elements);
 | |
|     }
 | |
|     return elements;
 | |
|   }
 | |
|   this.getTextElements = getTextElements;
 | |
|   function prependParentContainers(startContainer, elements, filter) {
 | |
|     var container = startContainer;
 | |
|     while (container) {
 | |
|       if (filter(container)) {
 | |
|         if (elements[0] !== container) {
 | |
|           elements.unshift(container);
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       if (isInlineRoot(container)) {
 | |
|         break;
 | |
|       }
 | |
|       container = container.parentNode;
 | |
|     }
 | |
|   }
 | |
|   this.getParagraphElements = function(range) {
 | |
|     var elements;
 | |
|     function nodeFilter(node) {
 | |
|       var result = NodeFilter.FILTER_REJECT;
 | |
|       if (isParagraph(node)) {
 | |
|         result = NodeFilter.FILTER_ACCEPT;
 | |
|       } else {
 | |
|         if (isTextContentContainingNode(node) || isGroupingElement(node)) {
 | |
|           result = NodeFilter.FILTER_SKIP;
 | |
|         }
 | |
|       }
 | |
|       return result;
 | |
|     }
 | |
|     elements = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT);
 | |
|     prependParentContainers((range.startContainer), elements, isParagraph);
 | |
|     return elements;
 | |
|   };
 | |
|   this.getImageElements = function(range) {
 | |
|     var elements;
 | |
|     function nodeFilter(node) {
 | |
|       var result = NodeFilter.FILTER_SKIP;
 | |
|       if (isImage(node)) {
 | |
|         result = NodeFilter.FILTER_ACCEPT;
 | |
|       }
 | |
|       return result;
 | |
|     }
 | |
|     elements = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT);
 | |
|     prependParentContainers((range.startContainer), elements, isImage);
 | |
|     return elements;
 | |
|   };
 | |
|   function getRightNode(container, offset) {
 | |
|     var node = container;
 | |
|     if (offset < node.childNodes.length - 1) {
 | |
|       node = (node.childNodes[offset + 1]);
 | |
|     } else {
 | |
|       while (!node.nextSibling) {
 | |
|         node = node.parentNode;
 | |
|       }
 | |
|       node = node.nextSibling;
 | |
|     }
 | |
|     while (node.firstChild) {
 | |
|       node = node.firstChild;
 | |
|     }
 | |
|     return node;
 | |
|   }
 | |
|   this.getHyperlinkElements = function(range) {
 | |
|     var links = [], newRange = (range.cloneRange()), node, textNodes;
 | |
|     if (range.collapsed && range.endContainer.nodeType === Node.ELEMENT_NODE) {
 | |
|       node = getRightNode(range.endContainer, range.endOffset);
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         newRange.setEnd(node, 1);
 | |
|       }
 | |
|     }
 | |
|     textNodes = getTextElements(newRange, true, false);
 | |
|     textNodes.forEach(function(node) {
 | |
|       var parent = node.parentNode;
 | |
|       while (!isParagraph(parent)) {
 | |
|         if (isHyperlink(parent) && links.indexOf(parent) === -1) {
 | |
|           links.push(parent);
 | |
|           break;
 | |
|         }
 | |
|         parent = parent.parentNode;
 | |
|       }
 | |
|     });
 | |
|     newRange.detach();
 | |
|     return links;
 | |
|   };
 | |
|   this.getNormalizedFontFamilyName = function(fontFamilyName) {
 | |
|     if (!/^(["'])(?:.|[\n\r])*?\1$/.test(fontFamilyName)) {
 | |
|       fontFamilyName = fontFamilyName.replace(/^[ \t\r\n\f]*((?:.|[\n\r])*?)[ \t\r\n\f]*$/, "$1");
 | |
|       if (/[ \t\r\n\f]/.test(fontFamilyName)) {
 | |
|         fontFamilyName = "'" + fontFamilyName.replace(/[ \t\r\n\f]+/g, " ") + "'";
 | |
|       }
 | |
|     }
 | |
|     return fontFamilyName;
 | |
|   };
 | |
| };
 | |
| odf.OdfUtils = new odf.OdfUtilsImpl;
 | |
| gui.OdfTextBodyNodeFilter = function() {
 | |
|   var odfUtils = odf.OdfUtils, TEXT_NODE = Node.TEXT_NODE, FILTER_REJECT = NodeFilter.FILTER_REJECT, FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT, textns = odf.Namespaces.textns;
 | |
|   this.acceptNode = function(node) {
 | |
|     if (node.nodeType === TEXT_NODE) {
 | |
|       if (!odfUtils.isGroupingElement(node.parentNode)) {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|     } else {
 | |
|       if (node.namespaceURI === textns && node.localName === "tracked-changes") {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|     }
 | |
|     return FILTER_ACCEPT;
 | |
|   };
 | |
| };
 | |
| xmldom.LSSerializerFilter = function LSSerializerFilter() {
 | |
| };
 | |
| xmldom.LSSerializerFilter.prototype.acceptNode = function(node) {
 | |
| };
 | |
| odf.OdfNodeFilter = function OdfNodeFilter() {
 | |
|   this.acceptNode = function(node) {
 | |
|     var result;
 | |
|     if (node.namespaceURI === "http://www.w3.org/1999/xhtml") {
 | |
|       result = NodeFilter.FILTER_SKIP;
 | |
|     } else {
 | |
|       if (node.namespaceURI && node.namespaceURI.match(/^urn:webodf:/)) {
 | |
|         result = NodeFilter.FILTER_REJECT;
 | |
|       } else {
 | |
|         result = NodeFilter.FILTER_ACCEPT;
 | |
|       }
 | |
|     }
 | |
|     return result;
 | |
|   };
 | |
| };
 | |
| xmldom.XPathIterator = function XPathIterator() {
 | |
| };
 | |
| xmldom.XPathIterator.prototype.next = function() {
 | |
| };
 | |
| xmldom.XPathIterator.prototype.reset = function() {
 | |
| };
 | |
| xmldom.XPathAtom;
 | |
| function createXPathSingleton() {
 | |
|   var createXPathPathIterator, parsePredicates;
 | |
|   function isSmallestPositive(a, b, c) {
 | |
|     return a !== -1 && (a < b || b === -1) && (a < c || c === -1);
 | |
|   }
 | |
|   function parseXPathStep(xpath, pos, end, steps) {
 | |
|     var location = "", predicates = [], brapos = xpath.indexOf("[", pos), slapos = xpath.indexOf("/", pos), eqpos = xpath.indexOf("=", pos);
 | |
|     if (isSmallestPositive(slapos, brapos, eqpos)) {
 | |
|       location = xpath.substring(pos, slapos);
 | |
|       pos = slapos + 1;
 | |
|     } else {
 | |
|       if (isSmallestPositive(brapos, slapos, eqpos)) {
 | |
|         location = xpath.substring(pos, brapos);
 | |
|         pos = parsePredicates(xpath, brapos, predicates);
 | |
|       } else {
 | |
|         if (isSmallestPositive(eqpos, slapos, brapos)) {
 | |
|           location = xpath.substring(pos, eqpos);
 | |
|           pos = eqpos;
 | |
|         } else {
 | |
|           location = xpath.substring(pos, end);
 | |
|           pos = end;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     steps.push({location:location, predicates:predicates});
 | |
|     return pos;
 | |
|   }
 | |
|   function parseXPath(xpath) {
 | |
|     var steps = [], p = 0, end = xpath.length, value;
 | |
|     while (p < end) {
 | |
|       p = parseXPathStep(xpath, p, end, steps);
 | |
|       if (p < end && xpath[p] === "=") {
 | |
|         value = xpath.substring(p + 1, end);
 | |
|         if (value.length > 2 && (value[0] === "'" || value[0] === '"')) {
 | |
|           value = value.slice(1, value.length - 1);
 | |
|         } else {
 | |
|           try {
 | |
|             value = parseInt(value, 10);
 | |
|           } catch (ignore) {
 | |
|           }
 | |
|         }
 | |
|         p = end;
 | |
|       }
 | |
|     }
 | |
|     return {steps:steps, value:value};
 | |
|   }
 | |
|   parsePredicates = function parsePredicates(xpath, start, predicates) {
 | |
|     var pos = start, l = xpath.length, depth = 0;
 | |
|     while (pos < l) {
 | |
|       if (xpath[pos] === "]") {
 | |
|         depth -= 1;
 | |
|         if (depth <= 0) {
 | |
|           predicates.push(parseXPath(xpath.substring(start, pos)));
 | |
|         }
 | |
|       } else {
 | |
|         if (xpath[pos] === "[") {
 | |
|           if (depth <= 0) {
 | |
|             start = pos + 1;
 | |
|           }
 | |
|           depth += 1;
 | |
|         }
 | |
|       }
 | |
|       pos += 1;
 | |
|     }
 | |
|     return pos;
 | |
|   };
 | |
|   function XPathNodeIterator() {
 | |
|     var node = null, done = false;
 | |
|     this.setNode = function setNode(n) {
 | |
|       node = n;
 | |
|     };
 | |
|     this.reset = function() {
 | |
|       done = false;
 | |
|     };
 | |
|     this.next = function next() {
 | |
|       var val = done ? null : node;
 | |
|       done = true;
 | |
|       return val;
 | |
|     };
 | |
|   }
 | |
|   function AttributeIterator(it, namespace, localName) {
 | |
|     this.reset = function reset() {
 | |
|       it.reset();
 | |
|     };
 | |
|     this.next = function next() {
 | |
|       var node = it.next();
 | |
|       while (node) {
 | |
|         if (node.nodeType === Node.ELEMENT_NODE) {
 | |
|           node = (node).getAttributeNodeNS(namespace, localName);
 | |
|         }
 | |
|         if (node) {
 | |
|           return node;
 | |
|         }
 | |
|         node = it.next();
 | |
|       }
 | |
|       return node;
 | |
|     };
 | |
|   }
 | |
|   function AllChildElementIterator(it, recurse) {
 | |
|     var root = it.next(), node = null;
 | |
|     this.reset = function reset() {
 | |
|       it.reset();
 | |
|       root = it.next();
 | |
|       node = null;
 | |
|     };
 | |
|     this.next = function next() {
 | |
|       while (root) {
 | |
|         if (node) {
 | |
|           if (recurse && node.firstChild) {
 | |
|             node = node.firstChild;
 | |
|           } else {
 | |
|             while (!node.nextSibling && node !== root) {
 | |
|               node = node.parentNode;
 | |
|             }
 | |
|             if (node === root) {
 | |
|               root = it.next();
 | |
|             } else {
 | |
|               node = node.nextSibling;
 | |
|             }
 | |
|           }
 | |
|         } else {
 | |
|           do {
 | |
|             node = root.firstChild;
 | |
|             if (!node) {
 | |
|               root = it.next();
 | |
|             }
 | |
|           } while (root && !node);
 | |
|         }
 | |
|         if (node && node.nodeType === Node.ELEMENT_NODE) {
 | |
|           return node;
 | |
|         }
 | |
|       }
 | |
|       return null;
 | |
|     };
 | |
|   }
 | |
|   function ConditionIterator(it, condition) {
 | |
|     this.reset = function reset() {
 | |
|       it.reset();
 | |
|     };
 | |
|     this.next = function next() {
 | |
|       var n = it.next();
 | |
|       while (n && !condition(n)) {
 | |
|         n = it.next();
 | |
|       }
 | |
|       return n;
 | |
|     };
 | |
|   }
 | |
|   function createNodenameFilter(it, name, namespaceResolver) {
 | |
|     var s = name.split(":", 2), namespace = namespaceResolver(s[0]), localName = s[1];
 | |
|     return new ConditionIterator(it, function(node) {
 | |
|       return node.localName === localName && node.namespaceURI === namespace;
 | |
|     });
 | |
|   }
 | |
|   function createPredicateFilteredIterator(it, p, namespaceResolver) {
 | |
|     var nit = new XPathNodeIterator, pit = createXPathPathIterator(nit, p, namespaceResolver), value = p.value;
 | |
|     if (value === undefined) {
 | |
|       return new ConditionIterator(it, function(node) {
 | |
|         nit.setNode(node);
 | |
|         pit.reset();
 | |
|         return pit.next() !== null;
 | |
|       });
 | |
|     }
 | |
|     return new ConditionIterator(it, function(node) {
 | |
|       nit.setNode(node);
 | |
|       pit.reset();
 | |
|       var n = pit.next();
 | |
|       return n ? n.nodeValue === value : false;
 | |
|     });
 | |
|   }
 | |
|   function item(p, i) {
 | |
|     return p[i];
 | |
|   }
 | |
|   createXPathPathIterator = function createXPathPathIterator(it, xpath, namespaceResolver) {
 | |
|     var i, j, step, location, s, p, ns;
 | |
|     for (i = 0;i < xpath.steps.length;i += 1) {
 | |
|       step = xpath.steps[i];
 | |
|       location = step.location;
 | |
|       if (location === "") {
 | |
|         it = new AllChildElementIterator(it, false);
 | |
|       } else {
 | |
|         if (location[0] === "@") {
 | |
|           s = location.substr(1).split(":", 2);
 | |
|           ns = namespaceResolver(s[0]);
 | |
|           if (!ns) {
 | |
|             throw "No namespace associated with the prefix " + s[0];
 | |
|           }
 | |
|           it = new AttributeIterator(it, ns, s[1]);
 | |
|         } else {
 | |
|           if (location !== ".") {
 | |
|             it = new AllChildElementIterator(it, false);
 | |
|             if (location.indexOf(":") !== -1) {
 | |
|               it = createNodenameFilter(it, location, namespaceResolver);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       for (j = 0;j < step.predicates.length;j += 1) {
 | |
|         p = item(step.predicates, j);
 | |
|         it = createPredicateFilteredIterator(it, p, namespaceResolver);
 | |
|       }
 | |
|     }
 | |
|     return it;
 | |
|   };
 | |
|   function fallback(node, xpath, namespaceResolver) {
 | |
|     var it = new XPathNodeIterator, i, nodelist, parsedXPath;
 | |
|     it.setNode(node);
 | |
|     parsedXPath = parseXPath(xpath);
 | |
|     it = createXPathPathIterator(it, parsedXPath, namespaceResolver);
 | |
|     nodelist = [];
 | |
|     i = it.next();
 | |
|     while (i) {
 | |
|       nodelist.push(i);
 | |
|       i = it.next();
 | |
|     }
 | |
|     return nodelist;
 | |
|   }
 | |
|   function getODFElementsWithXPath(node, xpath, namespaceResolver) {
 | |
|     var doc = node.ownerDocument, nodes, elements = [], n = null;
 | |
|     if (!doc || typeof doc.evaluate !== "function") {
 | |
|       elements = fallback(node, xpath, namespaceResolver);
 | |
|     } else {
 | |
|       nodes = doc.evaluate(xpath, node, namespaceResolver, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
 | |
|       n = nodes.iterateNext();
 | |
|       while (n !== null) {
 | |
|         if (n.nodeType === Node.ELEMENT_NODE) {
 | |
|           elements.push(n);
 | |
|         }
 | |
|         n = nodes.iterateNext();
 | |
|       }
 | |
|     }
 | |
|     return elements;
 | |
|   }
 | |
|   return {getODFElementsWithXPath:getODFElementsWithXPath};
 | |
| }
 | |
| xmldom.XPath = createXPathSingleton();
 | |
| odf.StyleInfo = function StyleInfo() {
 | |
|   var chartns = odf.Namespaces.chartns, dbns = odf.Namespaces.dbns, dr3dns = odf.Namespaces.dr3dns, drawns = odf.Namespaces.drawns, formns = odf.Namespaces.formns, numberns = odf.Namespaces.numberns, officens = odf.Namespaces.officens, presentationns = odf.Namespaces.presentationns, stylens = odf.Namespaces.stylens, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, nsprefixes = {"urn:oasis:names:tc:opendocument:xmlns:chart:1.0":"chart:", "urn:oasis:names:tc:opendocument:xmlns:database:1.0":"db:", 
 | |
|   "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0":"dr3d:", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0":"draw:", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0":"fo:", "urn:oasis:names:tc:opendocument:xmlns:form:1.0":"form:", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":"number:", "urn:oasis:names:tc:opendocument:xmlns:office:1.0":"office:", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0":"presentation:", "urn:oasis:names:tc:opendocument:xmlns:style:1.0":"style:", 
 | |
|   "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0":"svg:", "urn:oasis:names:tc:opendocument:xmlns:table:1.0":"table:", "urn:oasis:names:tc:opendocument:xmlns:text:1.0":"chart:", "http://www.w3.org/XML/1998/namespace":"xml:"}, elementstyles = {"text":[{ens:stylens, en:"tab-stop", ans:stylens, a:"leader-text-style"}, {ens:stylens, en:"drop-cap", ans:stylens, a:"style-name"}, {ens:textns, en:"notes-configuration", ans:textns, a:"citation-body-style-name"}, {ens:textns, en:"notes-configuration", 
 | |
|   ans:textns, a:"citation-style-name"}, {ens:textns, en:"a", ans:textns, a:"style-name"}, {ens:textns, en:"alphabetical-index", ans:textns, a:"style-name"}, {ens:textns, en:"linenumbering-configuration", ans:textns, a:"style-name"}, {ens:textns, en:"list-level-style-number", ans:textns, a:"style-name"}, {ens:textns, en:"ruby-text", ans:textns, a:"style-name"}, {ens:textns, en:"span", ans:textns, a:"style-name"}, {ens:textns, en:"a", ans:textns, a:"visited-style-name"}, {ens:stylens, en:"text-properties", 
 | |
|   ans:stylens, a:"text-line-through-text-style"}, {ens:textns, en:"alphabetical-index-source", ans:textns, a:"main-entry-style-name"}, {ens:textns, en:"index-entry-bibliography", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-chapter", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-link-end", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-link-start", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-page-number", ans:textns, a:"style-name"}, {ens:textns, 
 | |
|   en:"index-entry-span", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-tab-stop", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-text", ans:textns, a:"style-name"}, {ens:textns, en:"index-title-template", ans:textns, a:"style-name"}, {ens:textns, en:"list-level-style-bullet", ans:textns, a:"style-name"}, {ens:textns, en:"outline-level-style", ans:textns, a:"style-name"}], "paragraph":[{ens:drawns, en:"caption", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"circle", ans:drawns, 
 | |
|   a:"text-style-name"}, {ens:drawns, en:"connector", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"control", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"custom-shape", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"ellipse", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"frame", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"line", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"measure", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"path", ans:drawns, a:"text-style-name"}, 
 | |
|   {ens:drawns, en:"polygon", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"polyline", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"rect", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"regular-polygon", ans:drawns, a:"text-style-name"}, {ens:officens, en:"annotation", ans:drawns, a:"text-style-name"}, {ens:formns, en:"column", ans:formns, a:"text-style-name"}, {ens:stylens, en:"style", ans:stylens, a:"next-style-name"}, {ens:tablens, en:"body", ans:tablens, a:"paragraph-style-name"}, 
 | |
|   {ens:tablens, en:"even-columns", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"even-rows", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"first-column", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"first-row", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"last-column", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"last-row", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"odd-columns", ans:tablens, a:"paragraph-style-name"}, 
 | |
|   {ens:tablens, en:"odd-rows", ans:tablens, a:"paragraph-style-name"}, {ens:textns, en:"notes-configuration", ans:textns, a:"default-style-name"}, {ens:textns, en:"alphabetical-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"bibliography-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"h", ans:textns, a:"style-name"}, {ens:textns, en:"illustration-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"index-source-style", ans:textns, a:"style-name"}, 
 | |
|   {ens:textns, en:"object-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"p", ans:textns, a:"style-name"}, {ens:textns, en:"table-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"table-of-content-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"table-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"user-index-entry-template", ans:textns, a:"style-name"}, {ens:stylens, en:"page-layout-properties", ans:stylens, a:"register-truth-ref-style-name"}], 
 | |
|   "chart":[{ens:chartns, en:"axis", ans:chartns, a:"style-name"}, {ens:chartns, en:"chart", ans:chartns, a:"style-name"}, {ens:chartns, en:"data-label", ans:chartns, a:"style-name"}, {ens:chartns, en:"data-point", ans:chartns, a:"style-name"}, {ens:chartns, en:"equation", ans:chartns, a:"style-name"}, {ens:chartns, en:"error-indicator", ans:chartns, a:"style-name"}, {ens:chartns, en:"floor", ans:chartns, a:"style-name"}, {ens:chartns, en:"footer", ans:chartns, a:"style-name"}, {ens:chartns, en:"grid", 
 | |
|   ans:chartns, a:"style-name"}, {ens:chartns, en:"legend", ans:chartns, a:"style-name"}, {ens:chartns, en:"mean-value", ans:chartns, a:"style-name"}, {ens:chartns, en:"plot-area", ans:chartns, a:"style-name"}, {ens:chartns, en:"regression-curve", ans:chartns, a:"style-name"}, {ens:chartns, en:"series", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-gain-marker", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-loss-marker", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-range-line", 
 | |
|   ans:chartns, a:"style-name"}, {ens:chartns, en:"subtitle", ans:chartns, a:"style-name"}, {ens:chartns, en:"title", ans:chartns, a:"style-name"}, {ens:chartns, en:"wall", ans:chartns, a:"style-name"}], "section":[{ens:textns, en:"alphabetical-index", ans:textns, a:"style-name"}, {ens:textns, en:"bibliography", ans:textns, a:"style-name"}, {ens:textns, en:"illustration-index", ans:textns, a:"style-name"}, {ens:textns, en:"index-title", ans:textns, a:"style-name"}, {ens:textns, en:"object-index", 
 | |
|   ans:textns, a:"style-name"}, {ens:textns, en:"section", ans:textns, a:"style-name"}, {ens:textns, en:"table-of-content", ans:textns, a:"style-name"}, {ens:textns, en:"table-index", ans:textns, a:"style-name"}, {ens:textns, en:"user-index", ans:textns, a:"style-name"}], "ruby":[{ens:textns, en:"ruby", ans:textns, a:"style-name"}], "table":[{ens:dbns, en:"query", ans:dbns, a:"style-name"}, {ens:dbns, en:"table-representation", ans:dbns, a:"style-name"}, {ens:tablens, en:"background", ans:tablens, 
 | |
|   a:"style-name"}, {ens:tablens, en:"table", ans:tablens, a:"style-name"}], "table-column":[{ens:dbns, en:"column", ans:dbns, a:"style-name"}, {ens:tablens, en:"table-column", ans:tablens, a:"style-name"}], "table-row":[{ens:dbns, en:"query", ans:dbns, a:"default-row-style-name"}, {ens:dbns, en:"table-representation", ans:dbns, a:"default-row-style-name"}, {ens:tablens, en:"table-row", ans:tablens, a:"style-name"}], "table-cell":[{ens:dbns, en:"column", ans:dbns, a:"default-cell-style-name"}, {ens:tablens, 
 | |
|   en:"table-column", ans:tablens, a:"default-cell-style-name"}, {ens:tablens, en:"table-row", ans:tablens, a:"default-cell-style-name"}, {ens:tablens, en:"body", ans:tablens, a:"style-name"}, {ens:tablens, en:"covered-table-cell", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"covered-table-cell", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-rows", ans:tablens, a:"style-name"}, 
 | |
|   {ens:tablens, en:"first-column", ans:tablens, a:"style-name"}, {ens:tablens, en:"first-row", ans:tablens, a:"style-name"}, {ens:tablens, en:"last-column", ans:tablens, a:"style-name"}, {ens:tablens, en:"last-row", ans:tablens, a:"style-name"}, {ens:tablens, en:"odd-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"odd-rows", ans:tablens, a:"style-name"}, {ens:tablens, en:"table-cell", ans:tablens, a:"style-name"}], "graphic":[{ens:dr3dns, en:"cube", ans:drawns, a:"style-name"}, {ens:dr3dns, 
 | |
|   en:"extrude", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"rotate", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"scene", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"sphere", ans:drawns, a:"style-name"}, {ens:drawns, en:"caption", ans:drawns, a:"style-name"}, {ens:drawns, en:"circle", ans:drawns, a:"style-name"}, {ens:drawns, en:"connector", ans:drawns, a:"style-name"}, {ens:drawns, en:"control", ans:drawns, a:"style-name"}, {ens:drawns, en:"custom-shape", ans:drawns, a:"style-name"}, {ens:drawns, 
 | |
|   en:"ellipse", ans:drawns, a:"style-name"}, {ens:drawns, en:"frame", ans:drawns, a:"style-name"}, {ens:drawns, en:"g", ans:drawns, a:"style-name"}, {ens:drawns, en:"line", ans:drawns, a:"style-name"}, {ens:drawns, en:"measure", ans:drawns, a:"style-name"}, {ens:drawns, en:"page-thumbnail", ans:drawns, a:"style-name"}, {ens:drawns, en:"path", ans:drawns, a:"style-name"}, {ens:drawns, en:"polygon", ans:drawns, a:"style-name"}, {ens:drawns, en:"polyline", ans:drawns, a:"style-name"}, {ens:drawns, en:"rect", 
 | |
|   ans:drawns, a:"style-name"}, {ens:drawns, en:"regular-polygon", ans:drawns, a:"style-name"}, {ens:officens, en:"annotation", ans:drawns, a:"style-name"}], "presentation":[{ens:dr3dns, en:"cube", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"extrude", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"rotate", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"scene", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"sphere", ans:presentationns, a:"style-name"}, {ens:drawns, en:"caption", 
 | |
|   ans:presentationns, a:"style-name"}, {ens:drawns, en:"circle", ans:presentationns, a:"style-name"}, {ens:drawns, en:"connector", ans:presentationns, a:"style-name"}, {ens:drawns, en:"control", ans:presentationns, a:"style-name"}, {ens:drawns, en:"custom-shape", ans:presentationns, a:"style-name"}, {ens:drawns, en:"ellipse", ans:presentationns, a:"style-name"}, {ens:drawns, en:"frame", ans:presentationns, a:"style-name"}, {ens:drawns, en:"g", ans:presentationns, a:"style-name"}, {ens:drawns, en:"line", 
 | |
|   ans:presentationns, a:"style-name"}, {ens:drawns, en:"measure", ans:presentationns, a:"style-name"}, {ens:drawns, en:"page-thumbnail", ans:presentationns, a:"style-name"}, {ens:drawns, en:"path", ans:presentationns, a:"style-name"}, {ens:drawns, en:"polygon", ans:presentationns, a:"style-name"}, {ens:drawns, en:"polyline", ans:presentationns, a:"style-name"}, {ens:drawns, en:"rect", ans:presentationns, a:"style-name"}, {ens:drawns, en:"regular-polygon", ans:presentationns, a:"style-name"}, {ens:officens, 
 | |
|   en:"annotation", ans:presentationns, a:"style-name"}], "drawing-page":[{ens:drawns, en:"page", ans:drawns, a:"style-name"}, {ens:presentationns, en:"notes", ans:drawns, a:"style-name"}, {ens:stylens, en:"handout-master", ans:drawns, a:"style-name"}, {ens:stylens, en:"master-page", ans:drawns, a:"style-name"}], "list-style":[{ens:textns, en:"list", ans:textns, a:"style-name"}, {ens:textns, en:"numbered-paragraph", ans:textns, a:"style-name"}, {ens:textns, en:"list-item", ans:textns, a:"style-override"}, 
 | |
|   {ens:stylens, en:"style", ans:stylens, a:"list-style-name"}], "data":[{ens:stylens, en:"style", ans:stylens, a:"data-style-name"}, {ens:stylens, en:"style", ans:stylens, a:"percentage-data-style-name"}, {ens:presentationns, en:"date-time-decl", ans:stylens, a:"data-style-name"}, {ens:textns, en:"creation-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"creation-time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"database-display", ans:stylens, a:"data-style-name"}, {ens:textns, 
 | |
|   en:"date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"editing-duration", ans:stylens, a:"data-style-name"}, {ens:textns, en:"expression", ans:stylens, a:"data-style-name"}, {ens:textns, en:"meta-field", ans:stylens, a:"data-style-name"}, {ens:textns, en:"modification-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"modification-time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"print-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"print-time", ans:stylens, 
 | |
|   a:"data-style-name"}, {ens:textns, en:"table-formula", ans:stylens, a:"data-style-name"}, {ens:textns, en:"time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-defined", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-field-get", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-field-input", ans:stylens, a:"data-style-name"}, {ens:textns, en:"variable-get", ans:stylens, a:"data-style-name"}, {ens:textns, en:"variable-input", ans:stylens, a:"data-style-name"}, {ens:textns, 
 | |
|   en:"variable-set", ans:stylens, a:"data-style-name"}], "page-layout":[{ens:presentationns, en:"notes", ans:stylens, a:"page-layout-name"}, {ens:stylens, en:"handout-master", ans:stylens, a:"page-layout-name"}, {ens:stylens, en:"master-page", ans:stylens, a:"page-layout-name"}]}, elements, xpath = xmldom.XPath;
 | |
|   function hasDerivedStyles(odfbody, nsResolver, styleElement) {
 | |
|     var nodes, xp, styleName = styleElement.getAttributeNS(stylens, "name"), styleFamily = styleElement.getAttributeNS(stylens, "family");
 | |
|     xp = '//style:*[@style:parent-style-name="' + styleName + '"][@style:family="' + styleFamily + '"]';
 | |
|     nodes = xpath.getODFElementsWithXPath(odfbody, xp, nsResolver);
 | |
|     if (nodes.length) {
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function prefixUsedStyleNames(element, prefix) {
 | |
|     var i, stylename, a, e, ns, elname, elns, localName, length = 0;
 | |
|     elname = elements[element.localName];
 | |
|     if (elname) {
 | |
|       elns = elname[element.namespaceURI];
 | |
|       if (elns) {
 | |
|         length = elns.length;
 | |
|       }
 | |
|     }
 | |
|     for (i = 0;i < length;i += 1) {
 | |
|       a = (elns[i]);
 | |
|       ns = a.ns;
 | |
|       localName = a.localname;
 | |
|       stylename = element.getAttributeNS(ns, localName);
 | |
|       if (stylename) {
 | |
|         element.setAttributeNS(ns, nsprefixes[ns] + localName, prefix + stylename);
 | |
|       }
 | |
|     }
 | |
|     e = element.firstElementChild;
 | |
|     while (e) {
 | |
|       prefixUsedStyleNames(e, prefix);
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|   }
 | |
|   function prefixStyleName(styleElement, prefix) {
 | |
|     var stylename = styleElement.getAttributeNS(drawns, "name"), ns;
 | |
|     if (stylename) {
 | |
|       ns = drawns;
 | |
|     } else {
 | |
|       stylename = styleElement.getAttributeNS(stylens, "name");
 | |
|       if (stylename) {
 | |
|         ns = stylens;
 | |
|       }
 | |
|     }
 | |
|     if (ns) {
 | |
|       styleElement.setAttributeNS(ns, nsprefixes[ns] + "name", prefix + stylename);
 | |
|     }
 | |
|   }
 | |
|   function prefixStyleNames(styleElementsRoot, prefix, styleUsingElementsRoot) {
 | |
|     var s;
 | |
|     if (styleElementsRoot) {
 | |
|       s = styleElementsRoot.firstChild;
 | |
|       while (s) {
 | |
|         if (s.nodeType === Node.ELEMENT_NODE) {
 | |
|           prefixStyleName((s), prefix);
 | |
|         }
 | |
|         s = s.nextSibling;
 | |
|       }
 | |
|       prefixUsedStyleNames(styleElementsRoot, prefix);
 | |
|       if (styleUsingElementsRoot) {
 | |
|         prefixUsedStyleNames(styleUsingElementsRoot, prefix);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function removeRegExpFromUsedStyleNames(element, regExp) {
 | |
|     var i, stylename, e, elname, elns, a, ns, localName, length = 0;
 | |
|     elname = elements[element.localName];
 | |
|     if (elname) {
 | |
|       elns = elname[element.namespaceURI];
 | |
|       if (elns) {
 | |
|         length = elns.length;
 | |
|       }
 | |
|     }
 | |
|     for (i = 0;i < length;i += 1) {
 | |
|       a = (elns[i]);
 | |
|       ns = a.ns;
 | |
|       localName = a.localname;
 | |
|       stylename = element.getAttributeNS(ns, localName);
 | |
|       if (stylename) {
 | |
|         stylename = stylename.replace(regExp, "");
 | |
|         element.setAttributeNS(ns, nsprefixes[ns] + localName, stylename);
 | |
|       }
 | |
|     }
 | |
|     e = element.firstElementChild;
 | |
|     while (e) {
 | |
|       removeRegExpFromUsedStyleNames(e, regExp);
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|   }
 | |
|   function removeRegExpFromStyleName(styleElement, regExp) {
 | |
|     var stylename = styleElement.getAttributeNS(drawns, "name"), ns;
 | |
|     if (stylename) {
 | |
|       ns = drawns;
 | |
|     } else {
 | |
|       stylename = styleElement.getAttributeNS(stylens, "name");
 | |
|       if (stylename) {
 | |
|         ns = stylens;
 | |
|       }
 | |
|     }
 | |
|     if (ns) {
 | |
|       stylename = stylename.replace(regExp, "");
 | |
|       styleElement.setAttributeNS(ns, nsprefixes[ns] + "name", stylename);
 | |
|     }
 | |
|   }
 | |
|   function removePrefixFromStyleNames(styleElementsRoot, prefix, styleUsingElementsRoot) {
 | |
|     var s, regExp = new RegExp("^" + prefix);
 | |
|     if (styleElementsRoot) {
 | |
|       s = styleElementsRoot.firstChild;
 | |
|       while (s) {
 | |
|         if (s.nodeType === Node.ELEMENT_NODE) {
 | |
|           removeRegExpFromStyleName((s), regExp);
 | |
|         }
 | |
|         s = s.nextSibling;
 | |
|       }
 | |
|       removeRegExpFromUsedStyleNames(styleElementsRoot, regExp);
 | |
|       if (styleUsingElementsRoot) {
 | |
|         removeRegExpFromUsedStyleNames(styleUsingElementsRoot, regExp);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function determineStylesForNode(element, usedStyles) {
 | |
|     var i, stylename, elname, elns, a, ns, localName, keyname, length = 0, map;
 | |
|     elname = elements[element.localName];
 | |
|     if (elname) {
 | |
|       elns = elname[element.namespaceURI];
 | |
|       if (elns) {
 | |
|         length = elns.length;
 | |
|       }
 | |
|     }
 | |
|     for (i = 0;i < length;i += 1) {
 | |
|       a = (elns[i]);
 | |
|       ns = a.ns;
 | |
|       localName = a.localname;
 | |
|       stylename = element.getAttributeNS(ns, localName);
 | |
|       if (stylename) {
 | |
|         usedStyles = usedStyles || {};
 | |
|         keyname = a.keyname;
 | |
|         if (usedStyles.hasOwnProperty(keyname)) {
 | |
|           usedStyles[keyname][stylename] = 1;
 | |
|         } else {
 | |
|           map = {};
 | |
|           map[stylename] = 1;
 | |
|           usedStyles[keyname] = map;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return usedStyles;
 | |
|   }
 | |
|   function determineUsedStyles(styleUsingElementsRoot, usedStyles) {
 | |
|     var i, e;
 | |
|     determineStylesForNode(styleUsingElementsRoot, usedStyles);
 | |
|     i = styleUsingElementsRoot.firstChild;
 | |
|     while (i) {
 | |
|       if (i.nodeType === Node.ELEMENT_NODE) {
 | |
|         e = (i);
 | |
|         determineUsedStyles(e, usedStyles);
 | |
|       }
 | |
|       i = i.nextSibling;
 | |
|     }
 | |
|   }
 | |
|   function StyleDefinition(key, name, family) {
 | |
|     this.key = key;
 | |
|     this.name = name;
 | |
|     this.family = family;
 | |
|     this.requires = {};
 | |
|   }
 | |
|   function getStyleDefinition(stylename, stylefamily, knownStyles) {
 | |
|     var styleKey = stylename + '"' + stylefamily, styleDefinition = knownStyles[styleKey];
 | |
|     if (!styleDefinition) {
 | |
|       styleDefinition = knownStyles[styleKey] = new StyleDefinition(styleKey, stylename, stylefamily);
 | |
|     }
 | |
|     return styleDefinition;
 | |
|   }
 | |
|   function determineDependentStyles(element, styleScope, knownStyles) {
 | |
|     var i, stylename, elname, elns, a, ns, localName, e, referencedStyleFamily, referencedStyleDef, length = 0, newScopeName = element.getAttributeNS(stylens, "name"), newScopeFamily = element.getAttributeNS(stylens, "family");
 | |
|     if (newScopeName && newScopeFamily) {
 | |
|       styleScope = getStyleDefinition(newScopeName, newScopeFamily, knownStyles);
 | |
|     }
 | |
|     if (styleScope) {
 | |
|       elname = elements[element.localName];
 | |
|       if (elname) {
 | |
|         elns = elname[element.namespaceURI];
 | |
|         if (elns) {
 | |
|           length = elns.length;
 | |
|         }
 | |
|       }
 | |
|       for (i = 0;i < length;i += 1) {
 | |
|         a = (elns[i]);
 | |
|         ns = a.ns;
 | |
|         localName = a.localname;
 | |
|         stylename = element.getAttributeNS(ns, localName);
 | |
|         if (stylename) {
 | |
|           referencedStyleFamily = a.keyname;
 | |
|           referencedStyleDef = getStyleDefinition(stylename, referencedStyleFamily, knownStyles);
 | |
|           styleScope.requires[referencedStyleDef.key] = referencedStyleDef;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     e = element.firstElementChild;
 | |
|     while (e) {
 | |
|       determineDependentStyles(e, styleScope, knownStyles);
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|     return knownStyles;
 | |
|   }
 | |
|   function inverse() {
 | |
|     var i, l, keyname, list, item, e = {}, map, array, en, ens;
 | |
|     for (keyname in elementstyles) {
 | |
|       if (elementstyles.hasOwnProperty(keyname)) {
 | |
|         list = elementstyles[keyname];
 | |
|         l = list.length;
 | |
|         for (i = 0;i < l;i += 1) {
 | |
|           item = list[i];
 | |
|           en = item.en;
 | |
|           ens = item.ens;
 | |
|           if (e.hasOwnProperty(en)) {
 | |
|             map = e[en];
 | |
|           } else {
 | |
|             e[en] = map = {};
 | |
|           }
 | |
|           if (map.hasOwnProperty(ens)) {
 | |
|             array = map[ens];
 | |
|           } else {
 | |
|             map[ens] = array = [];
 | |
|           }
 | |
|           array.push({ns:item.ans, localname:item.a, keyname:keyname});
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return e;
 | |
|   }
 | |
|   function mergeRequiredStyles(styleDependency, usedStyles) {
 | |
|     var family = usedStyles[styleDependency.family];
 | |
|     if (!family) {
 | |
|       family = usedStyles[styleDependency.family] = {};
 | |
|     }
 | |
|     family[styleDependency.name] = 1;
 | |
|     Object.keys((styleDependency.requires)).forEach(function(requiredStyleKey) {
 | |
|       mergeRequiredStyles((styleDependency.requires[requiredStyleKey]), usedStyles);
 | |
|     });
 | |
|   }
 | |
|   function mergeUsedAutomaticStyles(automaticStylesRoot, usedStyles) {
 | |
|     var automaticStyles = determineDependentStyles(automaticStylesRoot, null, {});
 | |
|     Object.keys(automaticStyles).forEach(function(styleKey) {
 | |
|       var automaticStyleDefinition = automaticStyles[styleKey], usedFamily = usedStyles[automaticStyleDefinition.family];
 | |
|       if (usedFamily && usedFamily.hasOwnProperty(automaticStyleDefinition.name)) {
 | |
|         mergeRequiredStyles(automaticStyleDefinition, usedStyles);
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   function collectUsedFontFaces(usedFontFaceDeclMap, styleElement) {
 | |
|     var localNames = ["font-name", "font-name-asian", "font-name-complex"], e, currentElement;
 | |
|     function collectByAttribute(localName) {
 | |
|       var fontFaceName = currentElement.getAttributeNS(stylens, localName);
 | |
|       if (fontFaceName) {
 | |
|         usedFontFaceDeclMap[fontFaceName] = true;
 | |
|       }
 | |
|     }
 | |
|     e = styleElement && styleElement.firstElementChild;
 | |
|     while (e) {
 | |
|       currentElement = e;
 | |
|       localNames.forEach(collectByAttribute);
 | |
|       collectUsedFontFaces(usedFontFaceDeclMap, currentElement);
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|   }
 | |
|   this.collectUsedFontFaces = collectUsedFontFaces;
 | |
|   function changeFontFaceNames(styleElement, fontFaceNameChangeMap) {
 | |
|     var localNames = ["font-name", "font-name-asian", "font-name-complex"], e, currentElement;
 | |
|     function changeFontFaceNameByAttribute(localName) {
 | |
|       var fontFaceName = currentElement.getAttributeNS(stylens, localName);
 | |
|       if (fontFaceName && fontFaceNameChangeMap.hasOwnProperty(fontFaceName)) {
 | |
|         currentElement.setAttributeNS(stylens, "style:" + localName, fontFaceNameChangeMap[fontFaceName]);
 | |
|       }
 | |
|     }
 | |
|     e = styleElement && styleElement.firstElementChild;
 | |
|     while (e) {
 | |
|       currentElement = e;
 | |
|       localNames.forEach(changeFontFaceNameByAttribute);
 | |
|       changeFontFaceNames(currentElement, fontFaceNameChangeMap);
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|   }
 | |
|   this.changeFontFaceNames = changeFontFaceNames;
 | |
|   this.UsedStyleList = function(styleUsingElementsRoot, automaticStylesRoot) {
 | |
|     var usedStyles = {};
 | |
|     this.uses = function(element) {
 | |
|       var localName = element.localName, name = element.getAttributeNS(drawns, "name") || element.getAttributeNS(stylens, "name"), keyName, map;
 | |
|       if (localName === "style") {
 | |
|         keyName = element.getAttributeNS(stylens, "family");
 | |
|       } else {
 | |
|         if (element.namespaceURI === numberns) {
 | |
|           keyName = "data";
 | |
|         } else {
 | |
|           keyName = localName;
 | |
|         }
 | |
|       }
 | |
|       map = usedStyles[keyName];
 | |
|       return map ? map[name] > 0 : false;
 | |
|     };
 | |
|     determineUsedStyles(styleUsingElementsRoot, usedStyles);
 | |
|     if (automaticStylesRoot) {
 | |
|       mergeUsedAutomaticStyles(automaticStylesRoot, usedStyles);
 | |
|     }
 | |
|   };
 | |
|   function getStyleName(family, element) {
 | |
|     var stylename, i, map = elements[element.localName];
 | |
|     if (map) {
 | |
|       map = map[element.namespaceURI];
 | |
|       if (map) {
 | |
|         for (i = 0;i < map.length;i += 1) {
 | |
|           if (map[i].keyname === family) {
 | |
|             map = map[i];
 | |
|             if (element.hasAttributeNS(map.ns, map.localname)) {
 | |
|               stylename = element.getAttributeNS(map.ns, map.localname);
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return stylename;
 | |
|   }
 | |
|   this.getStyleName = getStyleName;
 | |
|   this.hasDerivedStyles = hasDerivedStyles;
 | |
|   this.prefixStyleNames = prefixStyleNames;
 | |
|   this.removePrefixFromStyleNames = removePrefixFromStyleNames;
 | |
|   this.determineStylesForNode = determineStylesForNode;
 | |
|   elements = inverse();
 | |
| };
 | |
| if (typeof Object.create !== "function") {
 | |
|   Object["create"] = function(o) {
 | |
|     var F = function() {
 | |
|     };
 | |
|     F.prototype = o;
 | |
|     return new F;
 | |
|   };
 | |
| }
 | |
| xmldom.LSSerializer = function LSSerializer() {
 | |
|   var self = this;
 | |
|   function Namespaces(nsmap) {
 | |
|     function invertMap(map) {
 | |
|       var m = {}, i;
 | |
|       for (i in map) {
 | |
|         if (map.hasOwnProperty(i)) {
 | |
|           m[map[i]] = i;
 | |
|         }
 | |
|       }
 | |
|       return m;
 | |
|     }
 | |
|     var current = nsmap || {}, currentrev = invertMap(nsmap), levels = [current], levelsrev = [currentrev], level = 0;
 | |
|     this.push = function() {
 | |
|       level += 1;
 | |
|       current = levels[level] = Object.create(current);
 | |
|       currentrev = levelsrev[level] = Object.create(currentrev);
 | |
|     };
 | |
|     this.pop = function() {
 | |
|       levels.pop();
 | |
|       levelsrev.pop();
 | |
|       level -= 1;
 | |
|       current = levels[level];
 | |
|       currentrev = levelsrev[level];
 | |
|     };
 | |
|     this.getLocalNamespaceDefinitions = function() {
 | |
|       return currentrev;
 | |
|     };
 | |
|     this.getQName = function(node) {
 | |
|       var ns = node.namespaceURI, i = 0, p;
 | |
|       if (!ns) {
 | |
|         return node.localName;
 | |
|       }
 | |
|       p = currentrev[ns];
 | |
|       if (p) {
 | |
|         return p + ":" + node.localName;
 | |
|       }
 | |
|       do {
 | |
|         if (p || !node.prefix) {
 | |
|           p = "ns" + i;
 | |
|           i += 1;
 | |
|         } else {
 | |
|           p = node.prefix;
 | |
|         }
 | |
|         if (current[p] === ns) {
 | |
|           break;
 | |
|         }
 | |
|         if (!current[p]) {
 | |
|           current[p] = ns;
 | |
|           currentrev[ns] = p;
 | |
|           break;
 | |
|         }
 | |
|         p = null;
 | |
|       } while (p === null);
 | |
|       return p + ":" + node.localName;
 | |
|     };
 | |
|   }
 | |
|   function escapeContent(value) {
 | |
|     return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'").replace(/"/g, """);
 | |
|   }
 | |
|   function serializeAttribute(qname, attr) {
 | |
|     var escapedValue = typeof attr.value === "string" ? escapeContent(attr.value) : attr.value, s = qname + '="' + escapedValue + '"';
 | |
|     return s;
 | |
|   }
 | |
|   function startElement(ns, qname, element) {
 | |
|     var s = "", atts = (element.attributes), length, i, attr, attstr = "", accept, prefix, nsmap;
 | |
|     s += "<" + qname;
 | |
|     length = atts.length;
 | |
|     for (i = 0;i < length;i += 1) {
 | |
|       attr = (atts.item(i));
 | |
|       if (attr.namespaceURI !== "http://www.w3.org/2000/xmlns/") {
 | |
|         accept = self.filter ? self.filter.acceptNode(attr) : NodeFilter.FILTER_ACCEPT;
 | |
|         if (accept === NodeFilter.FILTER_ACCEPT) {
 | |
|           attstr += " " + serializeAttribute(ns.getQName(attr), attr);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     nsmap = ns.getLocalNamespaceDefinitions();
 | |
|     for (i in nsmap) {
 | |
|       if (nsmap.hasOwnProperty(i)) {
 | |
|         prefix = nsmap[i];
 | |
|         if (!prefix) {
 | |
|           s += ' xmlns="' + i + '"';
 | |
|         } else {
 | |
|           if (prefix !== "xmlns") {
 | |
|             s += " xmlns:" + nsmap[i] + '="' + i + '"';
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     s += attstr + ">";
 | |
|     return s;
 | |
|   }
 | |
|   function serializeNode(ns, node) {
 | |
|     var s = "", accept = self.filter ? self.filter.acceptNode(node) : NodeFilter.FILTER_ACCEPT, child, qname;
 | |
|     if (accept === NodeFilter.FILTER_ACCEPT && node.nodeType === Node.ELEMENT_NODE) {
 | |
|       ns.push();
 | |
|       qname = ns.getQName(node);
 | |
|       s += startElement(ns, qname, node);
 | |
|     }
 | |
|     if (accept === NodeFilter.FILTER_ACCEPT || accept === NodeFilter.FILTER_SKIP) {
 | |
|       child = node.firstChild;
 | |
|       while (child) {
 | |
|         s += serializeNode(ns, child);
 | |
|         child = child.nextSibling;
 | |
|       }
 | |
|       if (node.nodeValue) {
 | |
|         s += escapeContent(node.nodeValue);
 | |
|       }
 | |
|     }
 | |
|     if (qname) {
 | |
|       s += "</" + qname + ">";
 | |
|       ns.pop();
 | |
|     }
 | |
|     return s;
 | |
|   }
 | |
|   this.filter = null;
 | |
|   this.writeToString = function(node, nsmap) {
 | |
|     if (!node) {
 | |
|       return "";
 | |
|     }
 | |
|     var ns = new Namespaces(nsmap);
 | |
|     return serializeNode(ns, node);
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   var styleInfo = new odf.StyleInfo, domUtils = core.DomUtils, officens = "urn:oasis:names:tc:opendocument:xmlns:office:1.0", manifestns = "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", webodfns = "urn:webodf:names:scope", stylens = odf.Namespaces.stylens, nodeorder = ["meta", "settings", "scripts", "font-face-decls", "styles", "automatic-styles", "master-styles", "body"], automaticStylePrefix = Date.now() + "_webodf_", base64 = new core.Base64, documentStylesScope = "document-styles", documentContentScope = 
 | |
|   "document-content";
 | |
|   function getNodePosition(child) {
 | |
|     var i, l = nodeorder.length;
 | |
|     for (i = 0;i < l;i += 1) {
 | |
|       if (child.namespaceURI === officens && child.localName === nodeorder[i]) {
 | |
|         return i;
 | |
|       }
 | |
|     }
 | |
|     return -1;
 | |
|   }
 | |
|   function OdfStylesFilter(styleUsingElementsRoot, automaticStyles) {
 | |
|     var usedStyleList = new styleInfo.UsedStyleList(styleUsingElementsRoot, automaticStyles), odfNodeFilter = new odf.OdfNodeFilter;
 | |
|     this.acceptNode = function(node) {
 | |
|       var result = odfNodeFilter.acceptNode(node);
 | |
|       if (result === NodeFilter.FILTER_ACCEPT && node.parentNode === automaticStyles && node.nodeType === Node.ELEMENT_NODE) {
 | |
|         if (usedStyleList.uses((node))) {
 | |
|           result = NodeFilter.FILTER_ACCEPT;
 | |
|         } else {
 | |
|           result = NodeFilter.FILTER_REJECT;
 | |
|         }
 | |
|       }
 | |
|       return result;
 | |
|     };
 | |
|   }
 | |
|   function OdfContentFilter(styleUsingElementsRoot, automaticStyles) {
 | |
|     var odfStylesFilter = new OdfStylesFilter(styleUsingElementsRoot, automaticStyles);
 | |
|     this.acceptNode = function(node) {
 | |
|       var result = odfStylesFilter.acceptNode(node);
 | |
|       if (result === NodeFilter.FILTER_ACCEPT && node.parentNode && node.parentNode.namespaceURI === odf.Namespaces.textns && (node.parentNode.localName === "s" || node.parentNode.localName === "tab")) {
 | |
|         result = NodeFilter.FILTER_REJECT;
 | |
|       }
 | |
|       return result;
 | |
|     };
 | |
|   }
 | |
|   function setChild(node, child) {
 | |
|     if (!child) {
 | |
|       return;
 | |
|     }
 | |
|     var childpos = getNodePosition(child), pos, c = node.firstChild;
 | |
|     if (childpos === -1) {
 | |
|       return;
 | |
|     }
 | |
|     while (c) {
 | |
|       pos = getNodePosition(c);
 | |
|       if (pos !== -1 && pos > childpos) {
 | |
|         break;
 | |
|       }
 | |
|       c = c.nextSibling;
 | |
|     }
 | |
|     node.insertBefore(child, c);
 | |
|   }
 | |
|   odf.ODFElement = function ODFElement() {
 | |
|   };
 | |
|   odf.ODFDocumentElement = function ODFDocumentElement() {
 | |
|   };
 | |
|   odf.ODFDocumentElement.prototype = new odf.ODFElement;
 | |
|   odf.ODFDocumentElement.prototype.constructor = odf.ODFDocumentElement;
 | |
|   odf.ODFDocumentElement.prototype.automaticStyles;
 | |
|   odf.ODFDocumentElement.prototype.body;
 | |
|   odf.ODFDocumentElement.prototype.fontFaceDecls = null;
 | |
|   odf.ODFDocumentElement.prototype.manifest = null;
 | |
|   odf.ODFDocumentElement.prototype.masterStyles;
 | |
|   odf.ODFDocumentElement.prototype.meta;
 | |
|   odf.ODFDocumentElement.prototype.settings = null;
 | |
|   odf.ODFDocumentElement.prototype.styles;
 | |
|   odf.ODFDocumentElement.namespaceURI = officens;
 | |
|   odf.ODFDocumentElement.localName = "document";
 | |
|   odf.AnnotationElement = function AnnotationElement() {
 | |
|   };
 | |
|   odf.AnnotationElement.prototype.annotationEndElement;
 | |
|   odf.OdfPart = function OdfPart(name, mimetype, container, zip) {
 | |
|     var self = this;
 | |
|     this.size = 0;
 | |
|     this.type = null;
 | |
|     this.name = name;
 | |
|     this.container = container;
 | |
|     this.url = null;
 | |
|     this.mimetype = mimetype;
 | |
|     this.document = null;
 | |
|     this.onstatereadychange = null;
 | |
|     this.onchange;
 | |
|     this.EMPTY = 0;
 | |
|     this.LOADING = 1;
 | |
|     this.DONE = 2;
 | |
|     this.state = this.EMPTY;
 | |
|     this.data = "";
 | |
|     this.load = function() {
 | |
|       if (zip === null) {
 | |
|         return;
 | |
|       }
 | |
|       this.mimetype = mimetype;
 | |
|       zip.loadAsDataURL(name, mimetype, function(err, url) {
 | |
|         if (err) {
 | |
|           runtime.log(err);
 | |
|         }
 | |
|         self.url = url;
 | |
|         if (self.onchange) {
 | |
|           self.onchange(self);
 | |
|         }
 | |
|         if (self.onstatereadychange) {
 | |
|           self.onstatereadychange(self);
 | |
|         }
 | |
|       });
 | |
|     };
 | |
|   };
 | |
|   odf.OdfPart.prototype.load = function() {
 | |
|   };
 | |
|   odf.OdfPart.prototype.getUrl = function() {
 | |
|     if (this.data) {
 | |
|       return "data:;base64," + base64.toBase64(this.data);
 | |
|     }
 | |
|     return null;
 | |
|   };
 | |
|   odf.OdfContainer = function OdfContainer(urlOrType, onstatereadychange) {
 | |
|     var self = this, zip, partMimetypes = {}, contentElement, url = "";
 | |
|     this.onstatereadychange = onstatereadychange;
 | |
|     this.onchange = null;
 | |
|     this.state = null;
 | |
|     this.rootElement;
 | |
|     function removeProcessingInstructions(element) {
 | |
|       var n = element.firstChild, next, e;
 | |
|       while (n) {
 | |
|         next = n.nextSibling;
 | |
|         if (n.nodeType === Node.ELEMENT_NODE) {
 | |
|           e = (n);
 | |
|           removeProcessingInstructions(e);
 | |
|         } else {
 | |
|           if (n.nodeType === Node.PROCESSING_INSTRUCTION_NODE) {
 | |
|             element.removeChild(n);
 | |
|           }
 | |
|         }
 | |
|         n = next;
 | |
|       }
 | |
|     }
 | |
|     function linkAnnotationStartAndEndElements(rootElement) {
 | |
|       var document = rootElement.ownerDocument, annotationStarts = {}, n, name, annotationStart, nodeIterator = document.createNodeIterator(rootElement, NodeFilter.SHOW_ELEMENT, null, false);
 | |
|       n = (nodeIterator.nextNode());
 | |
|       while (n) {
 | |
|         if (n.namespaceURI === officens) {
 | |
|           if (n.localName === "annotation") {
 | |
|             name = n.getAttributeNS(officens, "name");
 | |
|             if (name) {
 | |
|               if (annotationStarts.hasOwnProperty(name)) {
 | |
|                 runtime.log("Warning: annotation name used more than once with <office:annotation/>: '" + name + "'");
 | |
|               } else {
 | |
|                 annotationStarts[name] = n;
 | |
|               }
 | |
|             }
 | |
|           } else {
 | |
|             if (n.localName === "annotation-end") {
 | |
|               name = n.getAttributeNS(officens, "name");
 | |
|               if (name) {
 | |
|                 if (annotationStarts.hasOwnProperty(name)) {
 | |
|                   annotationStart = (annotationStarts[name]);
 | |
|                   if (!annotationStart.annotationEndElement) {
 | |
|                     annotationStart.annotationEndElement = n;
 | |
|                   } else {
 | |
|                     runtime.log("Warning: annotation name used more than once with <office:annotation-end/>: '" + name + "'");
 | |
|                   }
 | |
|                 } else {
 | |
|                   runtime.log("Warning: annotation end without an annotation start, name: '" + name + "'");
 | |
|                 }
 | |
|               } else {
 | |
|                 runtime.log("Warning: annotation end without a name found");
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         n = (nodeIterator.nextNode());
 | |
|       }
 | |
|     }
 | |
|     function setAutomaticStylesScope(stylesRootElement, scope) {
 | |
|       var n = stylesRootElement && stylesRootElement.firstChild;
 | |
|       while (n) {
 | |
|         if (n.nodeType === Node.ELEMENT_NODE) {
 | |
|           (n).setAttributeNS(webodfns, "scope", scope);
 | |
|         }
 | |
|         n = n.nextSibling;
 | |
|       }
 | |
|     }
 | |
|     function getEnsuredMetaElement() {
 | |
|       var root = self.rootElement, meta = root.meta;
 | |
|       if (!meta) {
 | |
|         root.meta = meta = document.createElementNS(officens, "meta");
 | |
|         setChild(root, meta);
 | |
|       }
 | |
|       return meta;
 | |
|     }
 | |
|     function getMetadata(metadataNs, metadataLocalName) {
 | |
|       var node = self.rootElement.meta, textNode;
 | |
|       node = node && node.firstChild;
 | |
|       while (node && (node.namespaceURI !== metadataNs || node.localName !== metadataLocalName)) {
 | |
|         node = node.nextSibling;
 | |
|       }
 | |
|       node = node && node.firstChild;
 | |
|       while (node && node.nodeType !== Node.TEXT_NODE) {
 | |
|         node = node.nextSibling;
 | |
|       }
 | |
|       if (node) {
 | |
|         textNode = (node);
 | |
|         return textNode.data;
 | |
|       }
 | |
|       return null;
 | |
|     }
 | |
|     this.getMetadata = getMetadata;
 | |
|     function unusedKey(key, map1, map2) {
 | |
|       var i = 0, postFixedKey;
 | |
|       key = key.replace(/\d+$/, "");
 | |
|       postFixedKey = key;
 | |
|       while (map1.hasOwnProperty(postFixedKey) || map2.hasOwnProperty(postFixedKey)) {
 | |
|         i += 1;
 | |
|         postFixedKey = key + i;
 | |
|       }
 | |
|       return postFixedKey;
 | |
|     }
 | |
|     function mapByFontFaceName(fontFaceDecls) {
 | |
|       var fn, result = {}, fontname;
 | |
|       fn = fontFaceDecls.firstChild;
 | |
|       while (fn) {
 | |
|         if (fn.nodeType === Node.ELEMENT_NODE && fn.namespaceURI === stylens && fn.localName === "font-face") {
 | |
|           fontname = (fn).getAttributeNS(stylens, "name");
 | |
|           result[fontname] = fn;
 | |
|         }
 | |
|         fn = fn.nextSibling;
 | |
|       }
 | |
|       return result;
 | |
|     }
 | |
|     function mergeFontFaceDecls(targetFontFaceDeclsRootElement, sourceFontFaceDeclsRootElement) {
 | |
|       var e, s, fontFaceName, newFontFaceName, targetFontFaceDeclsMap, sourceFontFaceDeclsMap, fontFaceNameChangeMap = {};
 | |
|       targetFontFaceDeclsMap = mapByFontFaceName(targetFontFaceDeclsRootElement);
 | |
|       sourceFontFaceDeclsMap = mapByFontFaceName(sourceFontFaceDeclsRootElement);
 | |
|       e = sourceFontFaceDeclsRootElement.firstElementChild;
 | |
|       while (e) {
 | |
|         s = e.nextElementSibling;
 | |
|         if (e.namespaceURI === stylens && e.localName === "font-face") {
 | |
|           fontFaceName = e.getAttributeNS(stylens, "name");
 | |
|           if (targetFontFaceDeclsMap.hasOwnProperty(fontFaceName)) {
 | |
|             if (!e.isEqualNode(targetFontFaceDeclsMap[fontFaceName])) {
 | |
|               newFontFaceName = unusedKey(fontFaceName, targetFontFaceDeclsMap, sourceFontFaceDeclsMap);
 | |
|               e.setAttributeNS(stylens, "style:name", newFontFaceName);
 | |
|               targetFontFaceDeclsRootElement.appendChild(e);
 | |
|               targetFontFaceDeclsMap[newFontFaceName] = e;
 | |
|               delete sourceFontFaceDeclsMap[fontFaceName];
 | |
|               fontFaceNameChangeMap[fontFaceName] = newFontFaceName;
 | |
|             }
 | |
|           } else {
 | |
|             targetFontFaceDeclsRootElement.appendChild(e);
 | |
|             targetFontFaceDeclsMap[fontFaceName] = e;
 | |
|             delete sourceFontFaceDeclsMap[fontFaceName];
 | |
|           }
 | |
|         }
 | |
|         e = s;
 | |
|       }
 | |
|       return fontFaceNameChangeMap;
 | |
|     }
 | |
|     function cloneStylesInScope(stylesRootElement, scope) {
 | |
|       var copy = null, e, s, scopeAttrValue;
 | |
|       if (stylesRootElement) {
 | |
|         copy = stylesRootElement.cloneNode(true);
 | |
|         e = copy.firstElementChild;
 | |
|         while (e) {
 | |
|           s = e.nextElementSibling;
 | |
|           scopeAttrValue = e.getAttributeNS(webodfns, "scope");
 | |
|           if (scopeAttrValue && scopeAttrValue !== scope) {
 | |
|             copy.removeChild(e);
 | |
|           }
 | |
|           e = s;
 | |
|         }
 | |
|       }
 | |
|       return copy;
 | |
|     }
 | |
|     function cloneFontFaceDeclsUsedInStyles(fontFaceDeclsRootElement, stylesRootElementList) {
 | |
|       var e, nextSibling, fontFaceName, copy = null, usedFontFaceDeclMap = {};
 | |
|       if (fontFaceDeclsRootElement) {
 | |
|         stylesRootElementList.forEach(function(stylesRootElement) {
 | |
|           styleInfo.collectUsedFontFaces(usedFontFaceDeclMap, stylesRootElement);
 | |
|         });
 | |
|         copy = fontFaceDeclsRootElement.cloneNode(true);
 | |
|         e = copy.firstElementChild;
 | |
|         while (e) {
 | |
|           nextSibling = e.nextElementSibling;
 | |
|           fontFaceName = e.getAttributeNS(stylens, "name");
 | |
|           if (!usedFontFaceDeclMap[fontFaceName]) {
 | |
|             copy.removeChild(e);
 | |
|           }
 | |
|           e = nextSibling;
 | |
|         }
 | |
|       }
 | |
|       return copy;
 | |
|     }
 | |
|     function importRootNode(xmldoc) {
 | |
|       var doc = self.rootElement.ownerDocument, node;
 | |
|       if (xmldoc) {
 | |
|         removeProcessingInstructions(xmldoc.documentElement);
 | |
|         try {
 | |
|           node = (doc.importNode(xmldoc.documentElement, true));
 | |
|         } catch (ignore) {
 | |
|         }
 | |
|       }
 | |
|       return node;
 | |
|     }
 | |
|     function setState(state) {
 | |
|       self.state = state;
 | |
|       if (self.onchange) {
 | |
|         self.onchange(self);
 | |
|       }
 | |
|       if (self.onstatereadychange) {
 | |
|         self.onstatereadychange(self);
 | |
|       }
 | |
|     }
 | |
|     function setRootElement(root) {
 | |
|       contentElement = null;
 | |
|       self.rootElement = (root);
 | |
|       root.fontFaceDecls = domUtils.getDirectChild(root, officens, "font-face-decls");
 | |
|       root.styles = domUtils.getDirectChild(root, officens, "styles");
 | |
|       root.automaticStyles = domUtils.getDirectChild(root, officens, "automatic-styles");
 | |
|       root.masterStyles = domUtils.getDirectChild(root, officens, "master-styles");
 | |
|       root.body = domUtils.getDirectChild(root, officens, "body");
 | |
|       root.meta = domUtils.getDirectChild(root, officens, "meta");
 | |
|       root.settings = domUtils.getDirectChild(root, officens, "settings");
 | |
|       root.scripts = domUtils.getDirectChild(root, officens, "scripts");
 | |
|       linkAnnotationStartAndEndElements(root);
 | |
|     }
 | |
|     function handleFlatXml(xmldoc) {
 | |
|       var root = importRootNode(xmldoc);
 | |
|       if (!root || root.localName !== "document" || root.namespaceURI !== officens) {
 | |
|         setState(OdfContainer.INVALID);
 | |
|         return;
 | |
|       }
 | |
|       setRootElement((root));
 | |
|       setState(OdfContainer.DONE);
 | |
|     }
 | |
|     function handleStylesXml(xmldoc) {
 | |
|       var node = importRootNode(xmldoc), root = self.rootElement, n;
 | |
|       if (!node || node.localName !== "document-styles" || node.namespaceURI !== officens) {
 | |
|         setState(OdfContainer.INVALID);
 | |
|         return;
 | |
|       }
 | |
|       root.fontFaceDecls = domUtils.getDirectChild(node, officens, "font-face-decls");
 | |
|       setChild(root, root.fontFaceDecls);
 | |
|       n = domUtils.getDirectChild(node, officens, "styles");
 | |
|       root.styles = n || xmldoc.createElementNS(officens, "styles");
 | |
|       setChild(root, root.styles);
 | |
|       n = domUtils.getDirectChild(node, officens, "automatic-styles");
 | |
|       root.automaticStyles = n || xmldoc.createElementNS(officens, "automatic-styles");
 | |
|       setAutomaticStylesScope(root.automaticStyles, documentStylesScope);
 | |
|       setChild(root, root.automaticStyles);
 | |
|       node = domUtils.getDirectChild(node, officens, "master-styles");
 | |
|       root.masterStyles = node || xmldoc.createElementNS(officens, "master-styles");
 | |
|       setChild(root, root.masterStyles);
 | |
|       styleInfo.prefixStyleNames(root.automaticStyles, automaticStylePrefix, root.masterStyles);
 | |
|     }
 | |
|     function handleContentXml(xmldoc) {
 | |
|       var node = importRootNode(xmldoc), root, automaticStyles, fontFaceDecls, fontFaceNameChangeMap, c;
 | |
|       if (!node || node.localName !== "document-content" || node.namespaceURI !== officens) {
 | |
|         setState(OdfContainer.INVALID);
 | |
|         return;
 | |
|       }
 | |
|       root = self.rootElement;
 | |
|       fontFaceDecls = domUtils.getDirectChild(node, officens, "font-face-decls");
 | |
|       if (root.fontFaceDecls && fontFaceDecls) {
 | |
|         fontFaceNameChangeMap = mergeFontFaceDecls(root.fontFaceDecls, fontFaceDecls);
 | |
|       } else {
 | |
|         if (fontFaceDecls) {
 | |
|           root.fontFaceDecls = fontFaceDecls;
 | |
|           setChild(root, fontFaceDecls);
 | |
|         }
 | |
|       }
 | |
|       automaticStyles = domUtils.getDirectChild(node, officens, "automatic-styles");
 | |
|       setAutomaticStylesScope(automaticStyles, documentContentScope);
 | |
|       if (fontFaceNameChangeMap) {
 | |
|         styleInfo.changeFontFaceNames(automaticStyles, fontFaceNameChangeMap);
 | |
|       }
 | |
|       if (root.automaticStyles && automaticStyles) {
 | |
|         c = automaticStyles.firstChild;
 | |
|         while (c) {
 | |
|           root.automaticStyles.appendChild(c);
 | |
|           c = automaticStyles.firstChild;
 | |
|         }
 | |
|       } else {
 | |
|         if (automaticStyles) {
 | |
|           root.automaticStyles = automaticStyles;
 | |
|           setChild(root, automaticStyles);
 | |
|         }
 | |
|       }
 | |
|       node = domUtils.getDirectChild(node, officens, "body");
 | |
|       if (node === null) {
 | |
|         throw "<office:body/> tag is mising.";
 | |
|       }
 | |
|       root.body = node;
 | |
|       setChild(root, root.body);
 | |
|     }
 | |
|     function handleMetaXml(xmldoc) {
 | |
|       var node = importRootNode(xmldoc), root;
 | |
|       if (!node || node.localName !== "document-meta" || node.namespaceURI !== officens) {
 | |
|         return;
 | |
|       }
 | |
|       root = self.rootElement;
 | |
|       root.meta = domUtils.getDirectChild(node, officens, "meta");
 | |
|       setChild(root, root.meta);
 | |
|     }
 | |
|     function handleSettingsXml(xmldoc) {
 | |
|       var node = importRootNode(xmldoc), root;
 | |
|       if (!node || node.localName !== "document-settings" || node.namespaceURI !== officens) {
 | |
|         return;
 | |
|       }
 | |
|       root = self.rootElement;
 | |
|       root.settings = domUtils.getDirectChild(node, officens, "settings");
 | |
|       setChild(root, root.settings);
 | |
|     }
 | |
|     function handleManifestXml(xmldoc) {
 | |
|       var node = importRootNode(xmldoc), root, e;
 | |
|       if (!node || node.localName !== "manifest" || node.namespaceURI !== manifestns) {
 | |
|         return;
 | |
|       }
 | |
|       root = self.rootElement;
 | |
|       root.manifest = (node);
 | |
|       e = root.manifest.firstElementChild;
 | |
|       while (e) {
 | |
|         if (e.localName === "file-entry" && e.namespaceURI === manifestns) {
 | |
|           partMimetypes[e.getAttributeNS(manifestns, "full-path")] = e.getAttributeNS(manifestns, "media-type");
 | |
|         }
 | |
|         e = e.nextElementSibling;
 | |
|       }
 | |
|     }
 | |
|     function removeElements(xmldoc, localName, allowedNamespaces) {
 | |
|       var elements = domUtils.getElementsByTagName(xmldoc, localName), element, i;
 | |
|       for (i = 0;i < elements.length;i += 1) {
 | |
|         element = elements[i];
 | |
|         if (!allowedNamespaces.hasOwnProperty(element.namespaceURI)) {
 | |
|           element.parentNode.removeChild(element);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function removeDangerousElements(xmldoc) {
 | |
|       removeElements(xmldoc, "script", {"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":true, "urn:oasis:names:tc:opendocument:xmlns:office:1.0":true, "urn:oasis:names:tc:opendocument:xmlns:table:1.0":true, "urn:oasis:names:tc:opendocument:xmlns:text:1.0":true, "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0":true});
 | |
|       removeElements(xmldoc, "style", {"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":true, "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0":true, "urn:oasis:names:tc:opendocument:xmlns:style:1.0":true});
 | |
|     }
 | |
|     function removeDangerousAttributes(element) {
 | |
|       var e = element.firstElementChild, as = [], i, n, a, atts = element.attributes, l = atts.length;
 | |
|       for (i = 0;i < l;i += 1) {
 | |
|         a = atts.item(i);
 | |
|         n = a.localName.substr(0, 2).toLowerCase();
 | |
|         if (a.namespaceURI === null && n === "on") {
 | |
|           as.push(a);
 | |
|         }
 | |
|       }
 | |
|       l = as.length;
 | |
|       for (i = 0;i < l;i += 1) {
 | |
|         element.removeAttributeNode(as[i]);
 | |
|       }
 | |
|       while (e) {
 | |
|         removeDangerousAttributes(e);
 | |
|         e = e.nextElementSibling;
 | |
|       }
 | |
|     }
 | |
|     function loadNextComponent(remainingComponents) {
 | |
|       var component = remainingComponents.shift();
 | |
|       if (component) {
 | |
|         zip.loadAsDOM(component.path, function(err, xmldoc) {
 | |
|           if (xmldoc) {
 | |
|             removeDangerousElements(xmldoc);
 | |
|             removeDangerousAttributes(xmldoc.documentElement);
 | |
|           }
 | |
|           component.handler(xmldoc);
 | |
|           if (self.state === OdfContainer.INVALID) {
 | |
|             if (err) {
 | |
|               runtime.log("ERROR: Unable to load " + component.path + " - " + err);
 | |
|             } else {
 | |
|               runtime.log("ERROR: Unable to load " + component.path);
 | |
|             }
 | |
|             return;
 | |
|           }
 | |
|           if (err) {
 | |
|             runtime.log("DEBUG: Unable to load " + component.path + " - " + err);
 | |
|           }
 | |
|           loadNextComponent(remainingComponents);
 | |
|         });
 | |
|       } else {
 | |
|         linkAnnotationStartAndEndElements(self.rootElement);
 | |
|         setState(OdfContainer.DONE);
 | |
|       }
 | |
|     }
 | |
|     function loadComponents() {
 | |
|       var componentOrder = [{path:"styles.xml", handler:handleStylesXml}, {path:"content.xml", handler:handleContentXml}, {path:"meta.xml", handler:handleMetaXml}, {path:"settings.xml", handler:handleSettingsXml}, {path:"META-INF/manifest.xml", handler:handleManifestXml}];
 | |
|       loadNextComponent(componentOrder);
 | |
|     }
 | |
|     function createDocumentElement(name) {
 | |
|       var s = "";
 | |
|       function defineNamespace(prefix, ns) {
 | |
|         s += " xmlns:" + prefix + '="' + ns + '"';
 | |
|       }
 | |
|       odf.Namespaces.forEachPrefix(defineNamespace);
 | |
|       return '<?xml version="1.0" encoding="UTF-8"?><office:' + name + " " + s + ' office:version="1.2">';
 | |
|     }
 | |
|     function serializeMetaXml() {
 | |
|       var serializer = new xmldom.LSSerializer, s = createDocumentElement("document-meta");
 | |
|       serializer.filter = new odf.OdfNodeFilter;
 | |
|       s += serializer.writeToString(self.rootElement.meta, odf.Namespaces.namespaceMap);
 | |
|       s += "</office:document-meta>";
 | |
|       return s;
 | |
|     }
 | |
|     function createManifestEntry(fullPath, mediaType) {
 | |
|       var element = document.createElementNS(manifestns, "manifest:file-entry");
 | |
|       element.setAttributeNS(manifestns, "manifest:full-path", fullPath);
 | |
|       element.setAttributeNS(manifestns, "manifest:media-type", mediaType);
 | |
|       return element;
 | |
|     }
 | |
|     function serializeManifestXml() {
 | |
|       var header = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n', xml = '<manifest:manifest xmlns:manifest="' + manifestns + '" manifest:version="1.2"></manifest:manifest>', manifest = (runtime.parseXML(xml)), manifestRoot = manifest.documentElement, serializer = new xmldom.LSSerializer, fullPath;
 | |
|       for (fullPath in partMimetypes) {
 | |
|         if (partMimetypes.hasOwnProperty(fullPath)) {
 | |
|           manifestRoot.appendChild(createManifestEntry(fullPath, partMimetypes[fullPath]));
 | |
|         }
 | |
|       }
 | |
|       serializer.filter = new odf.OdfNodeFilter;
 | |
|       return header + serializer.writeToString(manifest, odf.Namespaces.namespaceMap);
 | |
|     }
 | |
|     function serializeSettingsXml() {
 | |
|       var serializer, s = "";
 | |
|       if (self.rootElement.settings && self.rootElement.settings.firstElementChild) {
 | |
|         serializer = new xmldom.LSSerializer;
 | |
|         s = createDocumentElement("document-settings");
 | |
|         serializer.filter = new odf.OdfNodeFilter;
 | |
|         s += serializer.writeToString(self.rootElement.settings, odf.Namespaces.namespaceMap);
 | |
|         s += "</office:document-settings>";
 | |
|       }
 | |
|       return s;
 | |
|     }
 | |
|     function serializeStylesXml() {
 | |
|       var fontFaceDecls, automaticStyles, masterStyles, nsmap = odf.Namespaces.namespaceMap, serializer = new xmldom.LSSerializer, s = createDocumentElement("document-styles");
 | |
|       automaticStyles = cloneStylesInScope(self.rootElement.automaticStyles, documentStylesScope);
 | |
|       masterStyles = (self.rootElement.masterStyles.cloneNode(true));
 | |
|       fontFaceDecls = cloneFontFaceDeclsUsedInStyles(self.rootElement.fontFaceDecls, [masterStyles, self.rootElement.styles, automaticStyles]);
 | |
|       styleInfo.removePrefixFromStyleNames(automaticStyles, automaticStylePrefix, masterStyles);
 | |
|       serializer.filter = new OdfStylesFilter(masterStyles, automaticStyles);
 | |
|       s += serializer.writeToString(fontFaceDecls, nsmap);
 | |
|       s += serializer.writeToString(self.rootElement.styles, nsmap);
 | |
|       s += serializer.writeToString(automaticStyles, nsmap);
 | |
|       s += serializer.writeToString(masterStyles, nsmap);
 | |
|       s += "</office:document-styles>";
 | |
|       return s;
 | |
|     }
 | |
|     function serializeContentXml() {
 | |
|       var fontFaceDecls, automaticStyles, nsmap = odf.Namespaces.namespaceMap, serializer = new xmldom.LSSerializer, s = createDocumentElement("document-content");
 | |
|       automaticStyles = cloneStylesInScope(self.rootElement.automaticStyles, documentContentScope);
 | |
|       fontFaceDecls = cloneFontFaceDeclsUsedInStyles(self.rootElement.fontFaceDecls, [automaticStyles]);
 | |
|       serializer.filter = new OdfContentFilter(self.rootElement.body, automaticStyles);
 | |
|       s += serializer.writeToString(fontFaceDecls, nsmap);
 | |
|       s += serializer.writeToString(automaticStyles, nsmap);
 | |
|       s += serializer.writeToString(self.rootElement.body, nsmap);
 | |
|       s += "</office:document-content>";
 | |
|       return s;
 | |
|     }
 | |
|     function createElement(type) {
 | |
|       var original = document.createElementNS(type.namespaceURI, type.localName), method, iface = new type.Type;
 | |
|       for (method in iface) {
 | |
|         if (iface.hasOwnProperty(method)) {
 | |
|           original[method] = iface[method];
 | |
|         }
 | |
|       }
 | |
|       return original;
 | |
|     }
 | |
|     function loadFromXML(url, callback) {
 | |
|       function handler(err, dom) {
 | |
|         if (err) {
 | |
|           callback(err);
 | |
|         } else {
 | |
|           if (!dom) {
 | |
|             callback("No DOM was loaded.");
 | |
|           } else {
 | |
|             removeDangerousElements(dom);
 | |
|             removeDangerousAttributes(dom.documentElement);
 | |
|             handleFlatXml(dom);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       runtime.loadXML(url, handler);
 | |
|     }
 | |
|     this.setRootElement = setRootElement;
 | |
|     this.getContentElement = function() {
 | |
|       var body;
 | |
|       if (!contentElement) {
 | |
|         body = self.rootElement.body;
 | |
|         contentElement = domUtils.getDirectChild(body, officens, "text") || domUtils.getDirectChild(body, officens, "presentation") || domUtils.getDirectChild(body, officens, "spreadsheet");
 | |
|       }
 | |
|       if (!contentElement) {
 | |
|         throw "Could not find content element in <office:body/>.";
 | |
|       }
 | |
|       return contentElement;
 | |
|     };
 | |
|     this.getDocumentType = function() {
 | |
|       var content = self.getContentElement();
 | |
|       return content && content.localName;
 | |
|     };
 | |
|     this.isTemplate = function() {
 | |
|       var docMimetype = partMimetypes["/"];
 | |
|       return docMimetype.substr(-9) === "-template";
 | |
|     };
 | |
|     this.setIsTemplate = function(isTemplate) {
 | |
|       var docMimetype = partMimetypes["/"], oldIsTemplate = docMimetype.substr(-9) === "-template", data;
 | |
|       if (isTemplate === oldIsTemplate) {
 | |
|         return;
 | |
|       }
 | |
|       if (isTemplate) {
 | |
|         docMimetype = docMimetype + "-template";
 | |
|       } else {
 | |
|         docMimetype = docMimetype.substr(0, docMimetype.length - 9);
 | |
|       }
 | |
|       partMimetypes["/"] = docMimetype;
 | |
|       data = runtime.byteArrayFromString(docMimetype, "utf8");
 | |
|       zip.save("mimetype", data, false, new Date);
 | |
|     };
 | |
|     this.getPart = function(partname) {
 | |
|       return new odf.OdfPart(partname, partMimetypes[partname], self, zip);
 | |
|     };
 | |
|     this.getPartData = function(url, callback) {
 | |
|       zip.load(url, callback);
 | |
|     };
 | |
|     function setMetadata(setProperties, removedPropertyNames) {
 | |
|       var metaElement = getEnsuredMetaElement();
 | |
|       if (setProperties) {
 | |
|         domUtils.mapKeyValObjOntoNode(metaElement, setProperties, odf.Namespaces.lookupNamespaceURI);
 | |
|       }
 | |
|       if (removedPropertyNames) {
 | |
|         domUtils.removeKeyElementsFromNode(metaElement, removedPropertyNames, odf.Namespaces.lookupNamespaceURI);
 | |
|       }
 | |
|     }
 | |
|     this.setMetadata = setMetadata;
 | |
|     this.incrementEditingCycles = function() {
 | |
|       var currentValueString = getMetadata(odf.Namespaces.metans, "editing-cycles"), currentCycles = currentValueString ? parseInt(currentValueString, 10) : 0;
 | |
|       if (isNaN(currentCycles)) {
 | |
|         currentCycles = 0;
 | |
|       }
 | |
|       setMetadata({"meta:editing-cycles":currentCycles + 1}, null);
 | |
|       return currentCycles + 1;
 | |
|     };
 | |
|     function updateMetadataForSaving() {
 | |
|       var generatorString, window = runtime.getWindow();
 | |
|       generatorString = "WebODF/" + webodf.Version;
 | |
|       if (window) {
 | |
|         generatorString = generatorString + " " + window.navigator.userAgent;
 | |
|       }
 | |
|       setMetadata({"meta:generator":generatorString}, null);
 | |
|     }
 | |
|     function createEmptyDocument(type, isTemplate) {
 | |
|       var emptyzip = new core.Zip("", null), mimetype = "application/vnd.oasis.opendocument." + type + (isTemplate === true ? "-template" : ""), data = runtime.byteArrayFromString(mimetype, "utf8"), root = self.rootElement, content = document.createElementNS(officens, type);
 | |
|       emptyzip.save("mimetype", data, false, new Date);
 | |
|       function addToplevelElement(memberName, realLocalName) {
 | |
|         var element;
 | |
|         if (!realLocalName) {
 | |
|           realLocalName = memberName;
 | |
|         }
 | |
|         element = document.createElementNS(officens, realLocalName);
 | |
|         root[memberName] = element;
 | |
|         root.appendChild(element);
 | |
|       }
 | |
|       addToplevelElement("meta");
 | |
|       addToplevelElement("settings");
 | |
|       addToplevelElement("scripts");
 | |
|       addToplevelElement("fontFaceDecls", "font-face-decls");
 | |
|       addToplevelElement("styles");
 | |
|       addToplevelElement("automaticStyles", "automatic-styles");
 | |
|       addToplevelElement("masterStyles", "master-styles");
 | |
|       addToplevelElement("body");
 | |
|       root.body.appendChild(content);
 | |
|       partMimetypes["/"] = mimetype;
 | |
|       partMimetypes["settings.xml"] = "text/xml";
 | |
|       partMimetypes["meta.xml"] = "text/xml";
 | |
|       partMimetypes["styles.xml"] = "text/xml";
 | |
|       partMimetypes["content.xml"] = "text/xml";
 | |
|       setState(OdfContainer.DONE);
 | |
|       return emptyzip;
 | |
|     }
 | |
|     function fillZip() {
 | |
|       var data, date = new Date, settings;
 | |
|       settings = serializeSettingsXml();
 | |
|       if (settings) {
 | |
|         data = runtime.byteArrayFromString(settings, "utf8");
 | |
|         zip.save("settings.xml", data, true, date);
 | |
|       } else {
 | |
|         zip.remove("settings.xml");
 | |
|       }
 | |
|       updateMetadataForSaving();
 | |
|       data = runtime.byteArrayFromString(serializeMetaXml(), "utf8");
 | |
|       zip.save("meta.xml", data, true, date);
 | |
|       data = runtime.byteArrayFromString(serializeStylesXml(), "utf8");
 | |
|       zip.save("styles.xml", data, true, date);
 | |
|       data = runtime.byteArrayFromString(serializeContentXml(), "utf8");
 | |
|       zip.save("content.xml", data, true, date);
 | |
|       data = runtime.byteArrayFromString(serializeManifestXml(), "utf8");
 | |
|       zip.save("META-INF/manifest.xml", data, true, date);
 | |
|     }
 | |
|     function createByteArray(successCallback, errorCallback) {
 | |
|       fillZip();
 | |
|       zip.createByteArray(successCallback, errorCallback);
 | |
|     }
 | |
|     this.createByteArray = createByteArray;
 | |
|     function saveAs(newurl, callback) {
 | |
|       fillZip();
 | |
|       zip.writeAs(newurl, function(err) {
 | |
|         callback(err);
 | |
|       });
 | |
|     }
 | |
|     this.saveAs = saveAs;
 | |
|     this.save = function(callback) {
 | |
|       saveAs(url, callback);
 | |
|     };
 | |
|     this.getUrl = function() {
 | |
|       return url;
 | |
|     };
 | |
|     this.setBlob = function(filename, mimetype, content) {
 | |
|       var data = base64.convertBase64ToByteArray(content), date = new Date;
 | |
|       zip.save(filename, data, false, date);
 | |
|       if (partMimetypes.hasOwnProperty(filename)) {
 | |
|         runtime.log(filename + " has been overwritten.");
 | |
|       }
 | |
|       partMimetypes[filename] = mimetype;
 | |
|     };
 | |
|     this.removeBlob = function(filename) {
 | |
|       var foundAndRemoved = zip.remove(filename);
 | |
|       runtime.assert(foundAndRemoved, "file is not found: " + filename);
 | |
|       delete partMimetypes[filename];
 | |
|     };
 | |
|     this.state = OdfContainer.LOADING;
 | |
|     this.rootElement = (createElement({Type:odf.ODFDocumentElement, namespaceURI:odf.ODFDocumentElement.namespaceURI, localName:odf.ODFDocumentElement.localName}));
 | |
|     if (urlOrType === odf.OdfContainer.DocumentType.TEXT) {
 | |
|       zip = createEmptyDocument("text");
 | |
|     } else {
 | |
|       if (urlOrType === odf.OdfContainer.DocumentType.TEXT_TEMPLATE) {
 | |
|         zip = createEmptyDocument("text", true);
 | |
|       } else {
 | |
|         if (urlOrType === odf.OdfContainer.DocumentType.PRESENTATION) {
 | |
|           zip = createEmptyDocument("presentation");
 | |
|         } else {
 | |
|           if (urlOrType === odf.OdfContainer.DocumentType.PRESENTATION_TEMPLATE) {
 | |
|             zip = createEmptyDocument("presentation", true);
 | |
|           } else {
 | |
|             if (urlOrType === odf.OdfContainer.DocumentType.SPREADSHEET) {
 | |
|               zip = createEmptyDocument("spreadsheet");
 | |
|             } else {
 | |
|               if (urlOrType === odf.OdfContainer.DocumentType.SPREADSHEET_TEMPLATE) {
 | |
|                 zip = createEmptyDocument("spreadsheet", true);
 | |
|               } else {
 | |
|                 url = (urlOrType);
 | |
|                 zip = new core.Zip(url, function(err, zipobject) {
 | |
|                   zip = zipobject;
 | |
|                   if (err) {
 | |
|                     loadFromXML(url, function(xmlerr) {
 | |
|                       if (err) {
 | |
|                         zip.error = err + "\n" + xmlerr;
 | |
|                         setState(OdfContainer.INVALID);
 | |
|                       }
 | |
|                     });
 | |
|                   } else {
 | |
|                     loadComponents();
 | |
|                   }
 | |
|                 });
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   odf.OdfContainer.EMPTY = 0;
 | |
|   odf.OdfContainer.LOADING = 1;
 | |
|   odf.OdfContainer.DONE = 2;
 | |
|   odf.OdfContainer.INVALID = 3;
 | |
|   odf.OdfContainer.SAVING = 4;
 | |
|   odf.OdfContainer.MODIFIED = 5;
 | |
|   odf.OdfContainer.getContainer = function(url) {
 | |
|     return new odf.OdfContainer(url, null);
 | |
|   };
 | |
| })();
 | |
| odf.OdfContainer.DocumentType = {TEXT:1, TEXT_TEMPLATE:2, PRESENTATION:3, PRESENTATION_TEMPLATE:4, SPREADSHEET:5, SPREADSHEET_TEMPLATE:6};
 | |
| gui.AnnotatableCanvas = function AnnotatableCanvas() {
 | |
| };
 | |
| gui.AnnotatableCanvas.prototype.refreshSize = function() {
 | |
| };
 | |
| gui.AnnotatableCanvas.prototype.getZoomLevel = function() {
 | |
| };
 | |
| gui.AnnotatableCanvas.prototype.getSizer = function() {
 | |
| };
 | |
| gui.AnnotationViewManager = function AnnotationViewManager(canvas, odfFragment, annotationsPane, showAnnotationRemoveButton) {
 | |
|   var annotations = [], doc = odfFragment.ownerDocument, odfUtils = odf.OdfUtils, CONNECTOR_MARGIN = 30, NOTE_MARGIN = 20, window = runtime.getWindow(), htmlns = "http://www.w3.org/1999/xhtml";
 | |
|   runtime.assert(Boolean(window), "Expected to be run in an environment which has a global window, like a browser.");
 | |
|   function wrapAnnotation(annotation) {
 | |
|     var annotationWrapper = doc.createElement("div"), annotationNote = doc.createElement("div"), connectorHorizontal = doc.createElement("div"), connectorAngular = doc.createElement("div"), removeButton;
 | |
|     annotationWrapper.className = "annotationWrapper";
 | |
|     annotationWrapper.setAttribute("creator", odfUtils.getAnnotationCreator(annotation));
 | |
|     annotation.parentNode.insertBefore(annotationWrapper, annotation);
 | |
|     annotationNote.className = "annotationNote";
 | |
|     annotationNote.appendChild(annotation);
 | |
|     if (showAnnotationRemoveButton) {
 | |
|       removeButton = doc.createElement("div");
 | |
|       removeButton.className = "annotationRemoveButton";
 | |
|       annotationNote.appendChild(removeButton);
 | |
|     }
 | |
|     connectorHorizontal.className = "annotationConnector horizontal";
 | |
|     connectorAngular.className = "annotationConnector angular";
 | |
|     annotationWrapper.appendChild(annotationNote);
 | |
|     annotationWrapper.appendChild(connectorHorizontal);
 | |
|     annotationWrapper.appendChild(connectorAngular);
 | |
|   }
 | |
|   function unwrapAnnotation(annotation) {
 | |
|     var annotationWrapper = annotation.parentNode.parentNode;
 | |
|     if (annotationWrapper.localName === "div") {
 | |
|       annotationWrapper.parentNode.insertBefore(annotation, annotationWrapper);
 | |
|       annotationWrapper.parentNode.removeChild(annotationWrapper);
 | |
|     }
 | |
|   }
 | |
|   function isNodeWithinAnnotationHighlight(node, annotationName) {
 | |
|     var iteratingNode = node.parentNode;
 | |
|     while (!(iteratingNode.namespaceURI === odf.Namespaces.officens && iteratingNode.localName === "body")) {
 | |
|       if (iteratingNode.namespaceURI === htmlns && (iteratingNode).className === "webodf-annotationHighlight" && (iteratingNode).getAttribute("annotation") === annotationName) {
 | |
|         return true;
 | |
|       }
 | |
|       iteratingNode = iteratingNode.parentNode;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function highlightAnnotation(annotation) {
 | |
|     var annotationEnd = annotation.annotationEndElement, range = doc.createRange(), annotationName = annotation.getAttributeNS(odf.Namespaces.officens, "name"), textNodes;
 | |
|     if (annotationEnd) {
 | |
|       range.setStart(annotation, annotation.childNodes.length);
 | |
|       range.setEnd(annotationEnd, 0);
 | |
|       textNodes = odfUtils.getTextNodes(range, false);
 | |
|       textNodes.forEach(function(n) {
 | |
|         if (!isNodeWithinAnnotationHighlight(n, annotationName)) {
 | |
|           var container = doc.createElement("span");
 | |
|           container.className = "webodf-annotationHighlight";
 | |
|           container.setAttribute("annotation", annotationName);
 | |
|           n.parentNode.replaceChild(container, n);
 | |
|           container.appendChild(n);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     range.detach();
 | |
|   }
 | |
|   function unhighlightAnnotation(annotation) {
 | |
|     var annotationName = annotation.getAttributeNS(odf.Namespaces.officens, "name"), highlightSpans = doc.querySelectorAll('span.webodf-annotationHighlight[annotation="' + annotationName + '"]'), i, container;
 | |
|     for (i = 0;i < highlightSpans.length;i += 1) {
 | |
|       container = highlightSpans.item(i);
 | |
|       while (container.firstChild) {
 | |
|         container.parentNode.insertBefore(container.firstChild, container);
 | |
|       }
 | |
|       container.parentNode.removeChild(container);
 | |
|     }
 | |
|   }
 | |
|   function lineDistance(point1, point2) {
 | |
|     var xs = 0, ys = 0;
 | |
|     xs = point2.x - point1.x;
 | |
|     xs = xs * xs;
 | |
|     ys = point2.y - point1.y;
 | |
|     ys = ys * ys;
 | |
|     return Math.sqrt(xs + ys);
 | |
|   }
 | |
|   function renderAnnotation(annotation) {
 | |
|     var annotationNote = (annotation.parentNode), connectorHorizontal = annotationNote.nextElementSibling, connectorAngular = connectorHorizontal.nextElementSibling, annotationWrapper = (annotationNote.parentNode), connectorAngle = 0, previousAnnotation = annotations[annotations.indexOf(annotation) - 1], previousRect, zoomLevel = canvas.getZoomLevel();
 | |
|     annotationNote.style.left = (annotationsPane.getBoundingClientRect().left - annotationWrapper.getBoundingClientRect().left) / zoomLevel + "px";
 | |
|     annotationNote.style.width = annotationsPane.getBoundingClientRect().width / zoomLevel + "px";
 | |
|     connectorHorizontal.style.width = parseFloat(annotationNote.style.left) - CONNECTOR_MARGIN + "px";
 | |
|     if (previousAnnotation) {
 | |
|       previousRect = (previousAnnotation.parentNode).getBoundingClientRect();
 | |
|       if ((annotationWrapper.getBoundingClientRect().top - previousRect.bottom) / zoomLevel <= NOTE_MARGIN) {
 | |
|         annotationNote.style.top = Math.abs(annotationWrapper.getBoundingClientRect().top - previousRect.bottom) / zoomLevel + NOTE_MARGIN + "px";
 | |
|       } else {
 | |
|         annotationNote.style.top = "0px";
 | |
|       }
 | |
|     } else {
 | |
|       annotationNote.style.top = "0px";
 | |
|     }
 | |
|     connectorAngular.style.left = connectorHorizontal.getBoundingClientRect().width / zoomLevel + "px";
 | |
|     connectorAngular.style.width = lineDistance({x:connectorAngular.getBoundingClientRect().left / zoomLevel, y:connectorAngular.getBoundingClientRect().top / zoomLevel}, {x:annotationNote.getBoundingClientRect().left / zoomLevel, y:annotationNote.getBoundingClientRect().top / zoomLevel}) + "px";
 | |
|     connectorAngle = Math.asin((annotationNote.getBoundingClientRect().top - connectorAngular.getBoundingClientRect().top) / (zoomLevel * parseFloat(connectorAngular.style.width)));
 | |
|     connectorAngular.style.transform = "rotate(" + connectorAngle + "rad)";
 | |
|     connectorAngular.style.MozTransform = "rotate(" + connectorAngle + "rad)";
 | |
|     connectorAngular.style.WebkitTransform = "rotate(" + connectorAngle + "rad)";
 | |
|     connectorAngular.style.msTransform = "rotate(" + connectorAngle + "rad)";
 | |
|   }
 | |
|   function showAnnotationsPane(show) {
 | |
|     var sizer = canvas.getSizer();
 | |
|     if (show) {
 | |
|       annotationsPane.style.display = "inline-block";
 | |
|       sizer.style.paddingRight = window.getComputedStyle(annotationsPane).width;
 | |
|     } else {
 | |
|       annotationsPane.style.display = "none";
 | |
|       sizer.style.paddingRight = 0;
 | |
|     }
 | |
|     canvas.refreshSize();
 | |
|   }
 | |
|   function sortAnnotations() {
 | |
|     annotations.sort(function(a, b) {
 | |
|       if ((a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0) {
 | |
|         return -1;
 | |
|       }
 | |
|       return 1;
 | |
|     });
 | |
|   }
 | |
|   function rerenderAnnotations() {
 | |
|     var i;
 | |
|     for (i = 0;i < annotations.length;i += 1) {
 | |
|       renderAnnotation(annotations[i]);
 | |
|     }
 | |
|   }
 | |
|   this.rerenderAnnotations = rerenderAnnotations;
 | |
|   function rehighlightAnnotations() {
 | |
|     annotations.forEach(function(annotation) {
 | |
|       highlightAnnotation(annotation);
 | |
|     });
 | |
|   }
 | |
|   this.rehighlightAnnotations = rehighlightAnnotations;
 | |
|   function getMinimumHeightForAnnotationPane() {
 | |
|     if (annotationsPane.style.display !== "none" && annotations.length > 0) {
 | |
|       return ((annotations[annotations.length - 1].parentNode).getBoundingClientRect().bottom - annotationsPane.getBoundingClientRect().top) / canvas.getZoomLevel() + "px";
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   this.getMinimumHeightForAnnotationPane = getMinimumHeightForAnnotationPane;
 | |
|   function addAnnotations(annotationElements) {
 | |
|     if (annotationElements.length === 0) {
 | |
|       return;
 | |
|     }
 | |
|     showAnnotationsPane(true);
 | |
|     annotationElements.forEach(function(annotation) {
 | |
|       annotations.push(annotation);
 | |
|       wrapAnnotation(annotation);
 | |
|       if (annotation.annotationEndElement) {
 | |
|         highlightAnnotation(annotation);
 | |
|       }
 | |
|     });
 | |
|     sortAnnotations();
 | |
|     rerenderAnnotations();
 | |
|   }
 | |
|   this.addAnnotations = addAnnotations;
 | |
|   function forgetAnnotation(annotation) {
 | |
|     var index = annotations.indexOf(annotation);
 | |
|     unwrapAnnotation(annotation);
 | |
|     unhighlightAnnotation(annotation);
 | |
|     if (index !== -1) {
 | |
|       annotations.splice(index, 1);
 | |
|     }
 | |
|     if (annotations.length === 0) {
 | |
|       showAnnotationsPane(false);
 | |
|     }
 | |
|   }
 | |
|   this.forgetAnnotation = forgetAnnotation;
 | |
|   function forgetAnnotations() {
 | |
|     while (annotations.length) {
 | |
|       forgetAnnotation(annotations[0]);
 | |
|     }
 | |
|   }
 | |
|   this.forgetAnnotations = forgetAnnotations;
 | |
| };
 | |
| gui.Viewport = function Viewport() {
 | |
| };
 | |
| gui.Viewport.prototype.scrollIntoView = function(clientRect, alignWithTop) {
 | |
| };
 | |
| gui.SingleScrollViewport = function(scrollPane) {
 | |
|   var VIEW_PADDING_PX = 5;
 | |
|   function shrinkClientRectByMargin(clientRect, margin) {
 | |
|     return {left:clientRect.left + margin.left, top:clientRect.top + margin.top, right:clientRect.right - margin.right, bottom:clientRect.bottom - margin.bottom};
 | |
|   }
 | |
|   function height(clientRect) {
 | |
|     return clientRect.bottom - clientRect.top;
 | |
|   }
 | |
|   function width(clientRect) {
 | |
|     return clientRect.right - clientRect.left;
 | |
|   }
 | |
|   this.scrollIntoView = function(clientRect, alignWithTop) {
 | |
|     var verticalScrollbarHeight = scrollPane.offsetHeight - scrollPane.clientHeight, horizontalScrollbarWidth = scrollPane.offsetWidth - scrollPane.clientWidth, nonNullClientRect, scrollPaneRect = scrollPane.getBoundingClientRect(), paneRect;
 | |
|     if (!clientRect || !scrollPaneRect) {
 | |
|       return;
 | |
|     }
 | |
|     nonNullClientRect = (clientRect);
 | |
|     paneRect = shrinkClientRectByMargin((scrollPaneRect), {top:VIEW_PADDING_PX, bottom:verticalScrollbarHeight + VIEW_PADDING_PX, left:VIEW_PADDING_PX, right:horizontalScrollbarWidth + VIEW_PADDING_PX});
 | |
|     if (alignWithTop || nonNullClientRect.top < paneRect.top) {
 | |
|       scrollPane.scrollTop -= paneRect.top - nonNullClientRect.top;
 | |
|     } else {
 | |
|       if (nonNullClientRect.top > paneRect.bottom || nonNullClientRect.bottom > paneRect.bottom) {
 | |
|         if (height(nonNullClientRect) <= height(paneRect)) {
 | |
|           scrollPane.scrollTop += nonNullClientRect.bottom - paneRect.bottom;
 | |
|         } else {
 | |
|           scrollPane.scrollTop += nonNullClientRect.top - paneRect.top;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (nonNullClientRect.left < paneRect.left) {
 | |
|       scrollPane.scrollLeft -= paneRect.left - nonNullClientRect.left;
 | |
|     } else {
 | |
|       if (nonNullClientRect.right > paneRect.right) {
 | |
|         if (width(nonNullClientRect) <= width(paneRect)) {
 | |
|           scrollPane.scrollLeft += nonNullClientRect.right - paneRect.right;
 | |
|         } else {
 | |
|           scrollPane.scrollLeft -= paneRect.left - nonNullClientRect.left;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   var xpath = xmldom.XPath, odfUtils = odf.OdfUtils, base64 = new core.Base64;
 | |
|   function getEmbeddedFontDeclarations(fontFaceDecls) {
 | |
|     var decls = {}, fonts, i, font, name, uris, href, family;
 | |
|     if (!fontFaceDecls) {
 | |
|       return decls;
 | |
|     }
 | |
|     fonts = xpath.getODFElementsWithXPath(fontFaceDecls, "style:font-face[svg:font-face-src]", odf.Namespaces.lookupNamespaceURI);
 | |
|     for (i = 0;i < fonts.length;i += 1) {
 | |
|       font = fonts[i];
 | |
|       name = font.getAttributeNS(odf.Namespaces.stylens, "name");
 | |
|       family = odfUtils.getNormalizedFontFamilyName(font.getAttributeNS(odf.Namespaces.svgns, "font-family"));
 | |
|       uris = xpath.getODFElementsWithXPath(font, "svg:font-face-src/svg:font-face-uri", odf.Namespaces.lookupNamespaceURI);
 | |
|       if (uris.length > 0) {
 | |
|         href = uris[0].getAttributeNS(odf.Namespaces.xlinkns, "href");
 | |
|         decls[name] = {href:href, family:family};
 | |
|       }
 | |
|     }
 | |
|     return decls;
 | |
|   }
 | |
|   function addFontToCSS(name, font, fontdata, stylesheet) {
 | |
|     var cssFamily = font.family || name, rule = "@font-face { font-family: " + cssFamily + "; src: " + "url(data:application/x-font-ttf;charset=binary;base64," + base64.convertUTF8ArrayToBase64(fontdata) + ') format("truetype"); }';
 | |
|     try {
 | |
|       stylesheet.insertRule(rule, stylesheet.cssRules.length);
 | |
|     } catch (e) {
 | |
|       runtime.log("Problem inserting rule in CSS: " + runtime.toJson(e) + "\nRule: " + rule);
 | |
|     }
 | |
|   }
 | |
|   function loadFontIntoCSS(embeddedFontDeclarations, odfContainer, pos, stylesheet, callback) {
 | |
|     var name, i = 0, n;
 | |
|     for (n in embeddedFontDeclarations) {
 | |
|       if (embeddedFontDeclarations.hasOwnProperty(n)) {
 | |
|         if (i === pos) {
 | |
|           name = n;
 | |
|           break;
 | |
|         }
 | |
|         i += 1;
 | |
|       }
 | |
|     }
 | |
|     if (!name) {
 | |
|       if (callback) {
 | |
|         callback();
 | |
|       }
 | |
|       return;
 | |
|     }
 | |
|     odfContainer.getPartData(embeddedFontDeclarations[name].href, function(err, fontdata) {
 | |
|       if (err) {
 | |
|         runtime.log(err);
 | |
|       } else {
 | |
|         if (!fontdata) {
 | |
|           runtime.log("missing font data for " + embeddedFontDeclarations[name].href);
 | |
|         } else {
 | |
|           addFontToCSS(name, embeddedFontDeclarations[name], fontdata, stylesheet);
 | |
|         }
 | |
|       }
 | |
|       loadFontIntoCSS(embeddedFontDeclarations, odfContainer, pos + 1, stylesheet, callback);
 | |
|     });
 | |
|   }
 | |
|   function loadFontsIntoCSS(embeddedFontDeclarations, odfContainer, stylesheet) {
 | |
|     loadFontIntoCSS(embeddedFontDeclarations, odfContainer, 0, stylesheet);
 | |
|   }
 | |
|   odf.FontLoader = function FontLoader() {
 | |
|     this.loadFonts = function(odfContainer, stylesheet) {
 | |
|       var embeddedFontDeclarations, fontFaceDecls = odfContainer.rootElement.fontFaceDecls;
 | |
|       while (stylesheet.cssRules.length) {
 | |
|         stylesheet.deleteRule(stylesheet.cssRules.length - 1);
 | |
|       }
 | |
|       if (fontFaceDecls) {
 | |
|         embeddedFontDeclarations = getEmbeddedFontDeclarations(fontFaceDecls);
 | |
|         loadFontsIntoCSS(embeddedFontDeclarations, odfContainer, stylesheet);
 | |
|       }
 | |
|     };
 | |
|   };
 | |
| })();
 | |
| odf.Formatting = function Formatting() {
 | |
|   var odfContainer, styleInfo = new odf.StyleInfo, svgns = odf.Namespaces.svgns, stylens = odf.Namespaces.stylens, textns = odf.Namespaces.textns, numberns = odf.Namespaces.numberns, fons = odf.Namespaces.fons, odfUtils = odf.OdfUtils, domUtils = core.DomUtils, utils = new core.Utils, cssUnits = new core.CSSUnits, builtInDefaultStyleAttributesByFamily = {"paragraph":{"style:paragraph-properties":{"fo:text-align":"left"}}}, defaultPageFormatSettings = {width:"21.001cm", height:"29.7cm", margin:"2cm", 
 | |
|   padding:"0cm"};
 | |
|   function getSystemDefaultStyleAttributes(styleFamily) {
 | |
|     var result, builtInDefaultStyleAttributes = builtInDefaultStyleAttributesByFamily[styleFamily];
 | |
|     if (builtInDefaultStyleAttributes) {
 | |
|       result = utils.mergeObjects({}, builtInDefaultStyleAttributes);
 | |
|     } else {
 | |
|       result = {};
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   this.getSystemDefaultStyleAttributes = getSystemDefaultStyleAttributes;
 | |
|   this.setOdfContainer = function(odfcontainer) {
 | |
|     odfContainer = odfcontainer;
 | |
|   };
 | |
|   function getFontMap() {
 | |
|     var fontFaceDecls = odfContainer.rootElement.fontFaceDecls, fontFaceDeclsMap = {}, node, name, family;
 | |
|     node = fontFaceDecls && fontFaceDecls.firstElementChild;
 | |
|     while (node) {
 | |
|       name = node.getAttributeNS(stylens, "name");
 | |
|       if (name) {
 | |
|         family = node.getAttributeNS(svgns, "font-family");
 | |
|         if (family || node.getElementsByTagNameNS(svgns, "font-face-uri").length > 0) {
 | |
|           fontFaceDeclsMap[name] = family;
 | |
|         }
 | |
|       }
 | |
|       node = node.nextElementSibling;
 | |
|     }
 | |
|     return fontFaceDeclsMap;
 | |
|   }
 | |
|   this.getFontMap = getFontMap;
 | |
|   this.getAvailableParagraphStyles = function() {
 | |
|     var node = odfContainer.rootElement.styles, p_family, p_name, p_displayName, paragraphStyles = [];
 | |
|     node = node && node.firstElementChild;
 | |
|     while (node) {
 | |
|       if (node.localName === "style" && node.namespaceURI === stylens) {
 | |
|         p_family = node.getAttributeNS(stylens, "family");
 | |
|         if (p_family === "paragraph") {
 | |
|           p_name = node.getAttributeNS(stylens, "name");
 | |
|           p_displayName = node.getAttributeNS(stylens, "display-name") || p_name;
 | |
|           if (p_name && p_displayName) {
 | |
|             paragraphStyles.push({name:p_name, displayName:p_displayName});
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       node = node.nextElementSibling;
 | |
|     }
 | |
|     return paragraphStyles;
 | |
|   };
 | |
|   this.isStyleUsed = function(styleElement) {
 | |
|     var hasDerivedStyles, isUsed, root = odfContainer.rootElement;
 | |
|     hasDerivedStyles = styleInfo.hasDerivedStyles(root, odf.Namespaces.lookupNamespaceURI, styleElement);
 | |
|     isUsed = (new styleInfo.UsedStyleList(root.styles)).uses(styleElement) || (new styleInfo.UsedStyleList(root.automaticStyles)).uses(styleElement) || (new styleInfo.UsedStyleList(root.body)).uses(styleElement);
 | |
|     return hasDerivedStyles || isUsed;
 | |
|   };
 | |
|   function getDefaultStyleElement(family) {
 | |
|     var node = odfContainer.rootElement.styles.firstElementChild;
 | |
|     while (node) {
 | |
|       if (node.namespaceURI === stylens && node.localName === "default-style" && node.getAttributeNS(stylens, "family") === family) {
 | |
|         return node;
 | |
|       }
 | |
|       node = node.nextElementSibling;
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   this.getDefaultStyleElement = getDefaultStyleElement;
 | |
|   function getStyleElement(styleName, family, styleElements) {
 | |
|     var node, nodeStyleName, styleListElement, i;
 | |
|     styleElements = styleElements || [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles];
 | |
|     for (i = 0;i < styleElements.length;i += 1) {
 | |
|       styleListElement = (styleElements[i]);
 | |
|       node = styleListElement.firstElementChild;
 | |
|       while (node) {
 | |
|         nodeStyleName = node.getAttributeNS(stylens, "name");
 | |
|         if (node.namespaceURI === stylens && node.localName === "style" && node.getAttributeNS(stylens, "family") === family && nodeStyleName === styleName) {
 | |
|           return node;
 | |
|         }
 | |
|         if (family === "list-style" && node.namespaceURI === textns && node.localName === "list-style" && nodeStyleName === styleName) {
 | |
|           return node;
 | |
|         }
 | |
|         if (family === "data" && node.namespaceURI === numberns && nodeStyleName === styleName) {
 | |
|           return node;
 | |
|         }
 | |
|         node = node.nextElementSibling;
 | |
|       }
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   this.getStyleElement = getStyleElement;
 | |
|   function getStyleAttributes(styleNode) {
 | |
|     var i, a, map, ai, propertiesMap = {}, propertiesNode = styleNode.firstElementChild;
 | |
|     while (propertiesNode) {
 | |
|       if (propertiesNode.namespaceURI === stylens) {
 | |
|         map = propertiesMap[propertiesNode.nodeName] = {};
 | |
|         a = propertiesNode.attributes;
 | |
|         for (i = 0;i < a.length;i += 1) {
 | |
|           ai = (a.item(i));
 | |
|           map[ai.name] = ai.value;
 | |
|         }
 | |
|       }
 | |
|       propertiesNode = propertiesNode.nextElementSibling;
 | |
|     }
 | |
|     a = styleNode.attributes;
 | |
|     for (i = 0;i < a.length;i += 1) {
 | |
|       ai = (a.item(i));
 | |
|       propertiesMap[ai.name] = ai.value;
 | |
|     }
 | |
|     return propertiesMap;
 | |
|   }
 | |
|   this.getStyleAttributes = getStyleAttributes;
 | |
|   function getInheritedStyleAttributes(styleNode, includeSystemDefault) {
 | |
|     var styleListElement = odfContainer.rootElement.styles, parentStyleName, propertiesMap, inheritedPropertiesMap = {}, styleFamily = styleNode.getAttributeNS(stylens, "family"), node = styleNode;
 | |
|     while (node) {
 | |
|       propertiesMap = getStyleAttributes(node);
 | |
|       inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
 | |
|       parentStyleName = node.getAttributeNS(stylens, "parent-style-name");
 | |
|       if (parentStyleName) {
 | |
|         node = getStyleElement(parentStyleName, styleFamily, [styleListElement]);
 | |
|       } else {
 | |
|         node = null;
 | |
|       }
 | |
|     }
 | |
|     node = getDefaultStyleElement(styleFamily);
 | |
|     if (node) {
 | |
|       propertiesMap = getStyleAttributes(node);
 | |
|       inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
 | |
|     }
 | |
|     if (includeSystemDefault !== false) {
 | |
|       propertiesMap = getSystemDefaultStyleAttributes(styleFamily);
 | |
|       inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
 | |
|     }
 | |
|     return inheritedPropertiesMap;
 | |
|   }
 | |
|   this.getInheritedStyleAttributes = getInheritedStyleAttributes;
 | |
|   this.getFirstCommonParentStyleNameOrSelf = function(styleName) {
 | |
|     var automaticStyleElementList = odfContainer.rootElement.automaticStyles, styleElementList = odfContainer.rootElement.styles, styleElement;
 | |
|     styleElement = getStyleElement(styleName, "paragraph", [automaticStyleElementList]);
 | |
|     if (styleElement) {
 | |
|       styleName = styleElement.getAttributeNS(stylens, "parent-style-name");
 | |
|       if (!styleName) {
 | |
|         return null;
 | |
|       }
 | |
|     }
 | |
|     styleElement = getStyleElement(styleName, "paragraph", [styleElementList]);
 | |
|     if (!styleElement) {
 | |
|       return null;
 | |
|     }
 | |
|     return styleName;
 | |
|   };
 | |
|   this.hasParagraphStyle = function(styleName) {
 | |
|     return Boolean(getStyleElement(styleName, "paragraph"));
 | |
|   };
 | |
|   function buildStyleChain(node, collectedChains) {
 | |
|     var parent = (node.nodeType === Node.TEXT_NODE ? node.parentNode : node), nodeStyles, appliedStyles = [], chainKey = "", foundContainer = false;
 | |
|     while (parent && !odfUtils.isInlineRoot(parent) && parent.parentNode !== odfContainer.rootElement) {
 | |
|       if (!foundContainer && odfUtils.isGroupingElement(parent)) {
 | |
|         foundContainer = true;
 | |
|       }
 | |
|       nodeStyles = styleInfo.determineStylesForNode(parent);
 | |
|       if (nodeStyles) {
 | |
|         appliedStyles.push(nodeStyles);
 | |
|       }
 | |
|       parent = (parent.parentNode);
 | |
|     }
 | |
|     function chainStyles(usedStyleMap) {
 | |
|       Object.keys(usedStyleMap).forEach(function(styleFamily) {
 | |
|         Object.keys(usedStyleMap[styleFamily]).forEach(function(styleName) {
 | |
|           chainKey += "|" + styleFamily + ":" + styleName + "|";
 | |
|         });
 | |
|       });
 | |
|     }
 | |
|     if (foundContainer) {
 | |
|       appliedStyles.forEach(chainStyles);
 | |
|       if (collectedChains) {
 | |
|         collectedChains[chainKey] = appliedStyles;
 | |
|       }
 | |
|     }
 | |
|     return foundContainer ? appliedStyles : undefined;
 | |
|   }
 | |
|   function isCommonStyleElement(styleNode) {
 | |
|     return styleNode.parentNode === odfContainer.rootElement.styles;
 | |
|   }
 | |
|   function calculateAppliedStyle(styleChain) {
 | |
|     var mergedChildStyle = {orderedStyles:[], styleProperties:{}};
 | |
|     styleChain.forEach(function(elementStyleSet) {
 | |
|       Object.keys((elementStyleSet)).forEach(function(styleFamily) {
 | |
|         var styleName = Object.keys(elementStyleSet[styleFamily])[0], styleSummary = {name:styleName, family:styleFamily, displayName:undefined, isCommonStyle:false}, styleElement, parentStyle;
 | |
|         styleElement = getStyleElement(styleName, styleFamily);
 | |
|         if (styleElement) {
 | |
|           parentStyle = getInheritedStyleAttributes((styleElement));
 | |
|           mergedChildStyle.styleProperties = utils.mergeObjects(parentStyle, mergedChildStyle.styleProperties);
 | |
|           styleSummary.displayName = styleElement.getAttributeNS(stylens, "display-name") || undefined;
 | |
|           styleSummary.isCommonStyle = isCommonStyleElement(styleElement);
 | |
|         } else {
 | |
|           runtime.log("No style element found for '" + styleName + "' of family '" + styleFamily + "'");
 | |
|         }
 | |
|         mergedChildStyle.orderedStyles.push(styleSummary);
 | |
|       });
 | |
|     });
 | |
|     return mergedChildStyle;
 | |
|   }
 | |
|   function getAppliedStyles(nodes, calculatedStylesCache) {
 | |
|     var styleChains = {}, styles = [];
 | |
|     if (!calculatedStylesCache) {
 | |
|       calculatedStylesCache = {};
 | |
|     }
 | |
|     nodes.forEach(function(n) {
 | |
|       buildStyleChain(n, styleChains);
 | |
|     });
 | |
|     Object.keys(styleChains).forEach(function(key) {
 | |
|       if (!calculatedStylesCache[key]) {
 | |
|         calculatedStylesCache[key] = calculateAppliedStyle(styleChains[key]);
 | |
|       }
 | |
|       styles.push(calculatedStylesCache[key]);
 | |
|     });
 | |
|     return styles;
 | |
|   }
 | |
|   this.getAppliedStyles = getAppliedStyles;
 | |
|   this.getAppliedStylesForElement = function(node, calculatedStylesCache) {
 | |
|     return getAppliedStyles([node], calculatedStylesCache)[0];
 | |
|   };
 | |
|   this.updateStyle = function(styleNode, properties) {
 | |
|     var fontName, fontFaceNode, textProperties;
 | |
|     domUtils.mapObjOntoNode(styleNode, properties, odf.Namespaces.lookupNamespaceURI);
 | |
|     textProperties = (properties["style:text-properties"]);
 | |
|     fontName = (textProperties && textProperties["style:font-name"]);
 | |
|     if (fontName && !getFontMap().hasOwnProperty(fontName)) {
 | |
|       fontFaceNode = styleNode.ownerDocument.createElementNS(stylens, "style:font-face");
 | |
|       fontFaceNode.setAttributeNS(stylens, "style:name", fontName);
 | |
|       fontFaceNode.setAttributeNS(svgns, "svg:font-family", fontName);
 | |
|       odfContainer.rootElement.fontFaceDecls.appendChild(fontFaceNode);
 | |
|     }
 | |
|   };
 | |
|   this.createDerivedStyleObject = function(parentStyleName, family, overrides) {
 | |
|     var originalStyleElement = (getStyleElement(parentStyleName, family)), newStyleObject;
 | |
|     runtime.assert(Boolean(originalStyleElement), "No style element found for '" + parentStyleName + "' of family '" + family + "'");
 | |
|     if (isCommonStyleElement(originalStyleElement)) {
 | |
|       newStyleObject = {"style:parent-style-name":parentStyleName};
 | |
|     } else {
 | |
|       newStyleObject = getStyleAttributes(originalStyleElement);
 | |
|     }
 | |
|     newStyleObject["style:family"] = family;
 | |
|     utils.mergeObjects(newStyleObject, overrides);
 | |
|     return newStyleObject;
 | |
|   };
 | |
|   this.getDefaultTabStopDistance = function() {
 | |
|     var defaultParagraph = getDefaultStyleElement("paragraph"), paragraphProperties = defaultParagraph && defaultParagraph.firstElementChild, tabStopDistance;
 | |
|     while (paragraphProperties) {
 | |
|       if (paragraphProperties.namespaceURI === stylens && paragraphProperties.localName === "paragraph-properties") {
 | |
|         tabStopDistance = paragraphProperties.getAttributeNS(stylens, "tab-stop-distance");
 | |
|       }
 | |
|       paragraphProperties = paragraphProperties.nextElementSibling;
 | |
|     }
 | |
|     if (!tabStopDistance) {
 | |
|       tabStopDistance = "1.25cm";
 | |
|     }
 | |
|     return odfUtils.parseNonNegativeLength(tabStopDistance);
 | |
|   };
 | |
|   function getMasterPageElement(pageName) {
 | |
|     var node = odfContainer.rootElement.masterStyles.firstElementChild;
 | |
|     while (node) {
 | |
|       if (node.namespaceURI === stylens && node.localName === "master-page" && node.getAttributeNS(stylens, "name") === pageName) {
 | |
|         break;
 | |
|       }
 | |
|       node = node.nextElementSibling;
 | |
|     }
 | |
|     return node;
 | |
|   }
 | |
|   this.getMasterPageElement = getMasterPageElement;
 | |
|   function getPageLayoutStyleElement(styleName, styleFamily) {
 | |
|     var masterPageName, layoutName, pageLayoutElements, node, i, styleElement = getStyleElement(styleName, styleFamily);
 | |
|     runtime.assert(styleFamily === "paragraph" || styleFamily === "table", "styleFamily must be either paragraph or table");
 | |
|     if (styleElement) {
 | |
|       masterPageName = styleElement.getAttributeNS(stylens, "master-page-name");
 | |
|       if (masterPageName) {
 | |
|         node = getMasterPageElement(masterPageName);
 | |
|         if (!node) {
 | |
|           runtime.log("WARN: No master page definition found for " + masterPageName);
 | |
|         }
 | |
|       }
 | |
|       if (!node) {
 | |
|         node = getMasterPageElement("Standard");
 | |
|       }
 | |
|       if (!node) {
 | |
|         node = (odfContainer.rootElement.masterStyles.getElementsByTagNameNS(stylens, "master-page")[0]);
 | |
|         if (!node) {
 | |
|           runtime.log("WARN: Document has no master pages defined");
 | |
|         }
 | |
|       }
 | |
|       if (node) {
 | |
|         layoutName = node.getAttributeNS(stylens, "page-layout-name");
 | |
|         pageLayoutElements = odfContainer.rootElement.automaticStyles.getElementsByTagNameNS(stylens, "page-layout");
 | |
|         for (i = 0;i < pageLayoutElements.length;i += 1) {
 | |
|           node = (pageLayoutElements.item(i));
 | |
|           if (node.getAttributeNS(stylens, "name") === layoutName) {
 | |
|             return node;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   function lengthInPx(length, defaultValue) {
 | |
|     var measure;
 | |
|     if (length) {
 | |
|       measure = cssUnits.convertMeasure(length, "px");
 | |
|     }
 | |
|     if (measure === undefined && defaultValue) {
 | |
|       measure = cssUnits.convertMeasure(defaultValue, "px");
 | |
|     }
 | |
|     return measure;
 | |
|   }
 | |
|   this.getContentSize = function(styleName, styleFamily) {
 | |
|     var pageLayoutElement, props, defaultOrientedPageWidth, defaultOrientedPageHeight, pageWidth, pageHeight, margin, marginLeft, marginRight, marginTop, marginBottom, padding, paddingLeft, paddingRight, paddingTop, paddingBottom;
 | |
|     pageLayoutElement = getPageLayoutStyleElement(styleName, styleFamily);
 | |
|     if (!pageLayoutElement) {
 | |
|       pageLayoutElement = domUtils.getDirectChild(odfContainer.rootElement.styles, stylens, "default-page-layout");
 | |
|     }
 | |
|     props = domUtils.getDirectChild(pageLayoutElement, stylens, "page-layout-properties");
 | |
|     if (props) {
 | |
|       if (props.getAttributeNS(stylens, "print-orientation") === "landscape") {
 | |
|         defaultOrientedPageWidth = defaultPageFormatSettings.height;
 | |
|         defaultOrientedPageHeight = defaultPageFormatSettings.width;
 | |
|       } else {
 | |
|         defaultOrientedPageWidth = defaultPageFormatSettings.width;
 | |
|         defaultOrientedPageHeight = defaultPageFormatSettings.height;
 | |
|       }
 | |
|       pageWidth = lengthInPx(props.getAttributeNS(fons, "page-width"), defaultOrientedPageWidth);
 | |
|       pageHeight = lengthInPx(props.getAttributeNS(fons, "page-height"), defaultOrientedPageHeight);
 | |
|       margin = lengthInPx(props.getAttributeNS(fons, "margin"));
 | |
|       if (margin === undefined) {
 | |
|         marginLeft = lengthInPx(props.getAttributeNS(fons, "margin-left"), defaultPageFormatSettings.margin);
 | |
|         marginRight = lengthInPx(props.getAttributeNS(fons, "margin-right"), defaultPageFormatSettings.margin);
 | |
|         marginTop = lengthInPx(props.getAttributeNS(fons, "margin-top"), defaultPageFormatSettings.margin);
 | |
|         marginBottom = lengthInPx(props.getAttributeNS(fons, "margin-bottom"), defaultPageFormatSettings.margin);
 | |
|       } else {
 | |
|         marginLeft = marginRight = marginTop = marginBottom = margin;
 | |
|       }
 | |
|       padding = lengthInPx(props.getAttributeNS(fons, "padding"));
 | |
|       if (padding === undefined) {
 | |
|         paddingLeft = lengthInPx(props.getAttributeNS(fons, "padding-left"), defaultPageFormatSettings.padding);
 | |
|         paddingRight = lengthInPx(props.getAttributeNS(fons, "padding-right"), defaultPageFormatSettings.padding);
 | |
|         paddingTop = lengthInPx(props.getAttributeNS(fons, "padding-top"), defaultPageFormatSettings.padding);
 | |
|         paddingBottom = lengthInPx(props.getAttributeNS(fons, "padding-bottom"), defaultPageFormatSettings.padding);
 | |
|       } else {
 | |
|         paddingLeft = paddingRight = paddingTop = paddingBottom = padding;
 | |
|       }
 | |
|     } else {
 | |
|       pageWidth = lengthInPx(defaultPageFormatSettings.width);
 | |
|       pageHeight = lengthInPx(defaultPageFormatSettings.height);
 | |
|       margin = lengthInPx(defaultPageFormatSettings.margin);
 | |
|       marginLeft = marginRight = marginTop = marginBottom = margin;
 | |
|       padding = lengthInPx(defaultPageFormatSettings.padding);
 | |
|       paddingLeft = paddingRight = paddingTop = paddingBottom = padding;
 | |
|     }
 | |
|     return {width:pageWidth - marginLeft - marginRight - paddingLeft - paddingRight, height:pageHeight - marginTop - marginBottom - paddingTop - paddingBottom};
 | |
|   };
 | |
| };
 | |
| odf.Formatting.StyleMetadata;
 | |
| odf.Formatting.StyleData;
 | |
| odf.Formatting.AppliedStyle;
 | |
| (function() {
 | |
|   var stylens = odf.Namespaces.stylens, textns = odf.Namespaces.textns, familyNamespacePrefixes = {"graphic":"draw", "drawing-page":"draw", "paragraph":"text", "presentation":"presentation", "ruby":"text", "section":"text", "table":"table", "table-cell":"table", "table-column":"table", "table-row":"table", "text":"text", "list":"text", "page":"office"};
 | |
|   odf.StyleTreeNode = function StyleTreeNode(element) {
 | |
|     this.derivedStyles = {};
 | |
|     this.element = element;
 | |
|   };
 | |
|   odf.StyleTree = function StyleTree(styles, autoStyles) {
 | |
|     var tree = {};
 | |
|     function getStyleMap(stylesNode) {
 | |
|       var node, name, family, style, styleMap = {};
 | |
|       if (!stylesNode) {
 | |
|         return styleMap;
 | |
|       }
 | |
|       node = stylesNode.firstElementChild;
 | |
|       while (node) {
 | |
|         if (node.namespaceURI === stylens && (node.localName === "style" || node.localName === "default-style")) {
 | |
|           family = node.getAttributeNS(stylens, "family");
 | |
|         } else {
 | |
|           if (node.namespaceURI === textns && node.localName === "list-style") {
 | |
|             family = "list";
 | |
|           } else {
 | |
|             if (node.namespaceURI === stylens && (node.localName === "page-layout" || node.localName === "default-page-layout")) {
 | |
|               family = "page";
 | |
|             } else {
 | |
|               family = undefined;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         if (family) {
 | |
|           name = node.getAttributeNS(stylens, "name");
 | |
|           if (!name) {
 | |
|             name = "";
 | |
|           }
 | |
|           if (styleMap.hasOwnProperty(family)) {
 | |
|             style = styleMap[family];
 | |
|           } else {
 | |
|             styleMap[family] = style = {};
 | |
|           }
 | |
|           style[name] = node;
 | |
|         }
 | |
|         node = node.nextElementSibling;
 | |
|       }
 | |
|       return styleMap;
 | |
|     }
 | |
|     function findStyleTreeNode(stylesTree, name) {
 | |
|       if (stylesTree.hasOwnProperty(name)) {
 | |
|         return stylesTree[name];
 | |
|       }
 | |
|       var style = null, styleNames = Object.keys(stylesTree), i;
 | |
|       for (i = 0;i < styleNames.length;i += 1) {
 | |
|         style = findStyleTreeNode(stylesTree[styleNames[i]].derivedStyles, name);
 | |
|         if (style) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       return style;
 | |
|     }
 | |
|     function createStyleTreeNode(styleName, stylesMap, stylesTree) {
 | |
|       var style, parentname, parentstyle;
 | |
|       if (!stylesMap.hasOwnProperty(styleName)) {
 | |
|         return null;
 | |
|       }
 | |
|       style = new odf.StyleTreeNode(stylesMap[styleName]);
 | |
|       parentname = style.element.getAttributeNS(stylens, "parent-style-name");
 | |
|       parentstyle = null;
 | |
|       if (parentname) {
 | |
|         parentstyle = findStyleTreeNode(stylesTree, parentname) || createStyleTreeNode(parentname, stylesMap, stylesTree);
 | |
|       }
 | |
|       if (parentstyle) {
 | |
|         parentstyle.derivedStyles[styleName] = style;
 | |
|       } else {
 | |
|         stylesTree[styleName] = style;
 | |
|       }
 | |
|       delete stylesMap[styleName];
 | |
|       return style;
 | |
|     }
 | |
|     function addStyleMapToStyleTree(stylesMap, stylesTree) {
 | |
|       if (stylesMap) {
 | |
|         Object.keys(stylesMap).forEach(function(styleName) {
 | |
|           createStyleTreeNode(styleName, stylesMap, stylesTree);
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|     this.getStyleTree = function() {
 | |
|       return tree;
 | |
|     };
 | |
|     function init() {
 | |
|       var subTree, styleNodes, autoStyleNodes;
 | |
|       styleNodes = getStyleMap(styles);
 | |
|       autoStyleNodes = getStyleMap(autoStyles);
 | |
|       Object.keys(familyNamespacePrefixes).forEach(function(family) {
 | |
|         subTree = tree[family] = {};
 | |
|         addStyleMapToStyleTree(styleNodes[family], subTree);
 | |
|         addStyleMapToStyleTree(autoStyleNodes[family], subTree);
 | |
|       });
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
| })();
 | |
| odf.StyleTree.Tree;
 | |
| (function() {
 | |
|   var fons = odf.Namespaces.fons, stylens = odf.Namespaces.stylens, textns = odf.Namespaces.textns, xmlns = odf.Namespaces.xmlns, helperns = "urn:webodf:names:helper", listCounterIdSuffix = "webodf-listLevel", stylemap = {1:"decimal", "a":"lower-latin", "A":"upper-latin", "i":"lower-roman", "I":"upper-roman"};
 | |
|   function appendRule(styleSheet, rule) {
 | |
|     try {
 | |
|       styleSheet.insertRule(rule, styleSheet.cssRules.length);
 | |
|     } catch (e) {
 | |
|       runtime.log("cannot load rule: " + rule + " - " + e);
 | |
|     }
 | |
|   }
 | |
|   function ParseState(contentRules, continuedCounterIdStack) {
 | |
|     this.listCounterCount = 0;
 | |
|     this.contentRules = contentRules;
 | |
|     this.counterIdStack = [];
 | |
|     this.continuedCounterIdStack = continuedCounterIdStack;
 | |
|   }
 | |
|   function UniqueListCounter(styleSheet) {
 | |
|     var customListIdIndex = 0, globalCounterResetRule = "", counterIdStacks = {};
 | |
|     function getCounterIdStack(list) {
 | |
|       var counterId, stack = [];
 | |
|       if (list) {
 | |
|         counterId = list.getAttributeNS(helperns, "counter-id");
 | |
|         stack = counterIdStacks[counterId].slice(0);
 | |
|       }
 | |
|       return stack;
 | |
|     }
 | |
|     function createCssRulesForList(topLevelListId, listElement, listLevel, parseState) {
 | |
|       var newListSelectorId, newListCounterId, newRule, contentRule, i;
 | |
|       parseState.listCounterCount += 1;
 | |
|       newListSelectorId = topLevelListId + "-level" + listLevel + "-" + parseState.listCounterCount;
 | |
|       listElement.setAttributeNS(helperns, "counter-id", newListSelectorId);
 | |
|       newListCounterId = parseState.continuedCounterIdStack.shift();
 | |
|       if (!newListCounterId) {
 | |
|         newListCounterId = newListSelectorId;
 | |
|         globalCounterResetRule += newListSelectorId + " 1 ";
 | |
|         newRule = 'text|list[webodfhelper|counter-id="' + newListSelectorId + '"]';
 | |
|         newRule += " > text|list-item:first-child > :not(text|list):first-child:before";
 | |
|         newRule += "{";
 | |
|         newRule += "counter-increment: " + newListCounterId + " 0;";
 | |
|         newRule += "}";
 | |
|         appendRule(styleSheet, newRule);
 | |
|       }
 | |
|       while (parseState.counterIdStack.length >= listLevel) {
 | |
|         parseState.counterIdStack.pop();
 | |
|       }
 | |
|       parseState.counterIdStack.push(newListCounterId);
 | |
|       contentRule = parseState.contentRules[listLevel.toString()] || "";
 | |
|       for (i = 1;i <= listLevel;i += 1) {
 | |
|         contentRule = contentRule.replace(i + listCounterIdSuffix, parseState.counterIdStack[i - 1]);
 | |
|       }
 | |
|       newRule = 'text|list[webodfhelper|counter-id="' + newListSelectorId + '"]';
 | |
|       newRule += " > text|list-item > :not(text|list):first-child:before";
 | |
|       newRule += "{";
 | |
|       newRule += contentRule;
 | |
|       newRule += "counter-increment: " + newListCounterId + ";";
 | |
|       newRule += "}";
 | |
|       appendRule(styleSheet, newRule);
 | |
|     }
 | |
|     function iterateOverChildListElements(topLevelListId, element, listLevel, parseState) {
 | |
|       var isListElement = element.namespaceURI === textns && element.localName === "list", isListItemElement = element.namespaceURI === textns && element.localName === "list-item", childElement;
 | |
|       if (!isListElement && !isListItemElement) {
 | |
|         parseState.continuedCounterIdStack = [];
 | |
|         return;
 | |
|       }
 | |
|       if (isListElement) {
 | |
|         listLevel += 1;
 | |
|         createCssRulesForList(topLevelListId, element, listLevel, parseState);
 | |
|       }
 | |
|       childElement = element.firstElementChild;
 | |
|       while (childElement) {
 | |
|         iterateOverChildListElements(topLevelListId, childElement, listLevel, parseState);
 | |
|         childElement = childElement.nextElementSibling;
 | |
|       }
 | |
|     }
 | |
|     this.createCounterRules = function(contentRules, list, continuedList) {
 | |
|       var listId = list.getAttributeNS(xmlns, "id"), currentParseState = new ParseState(contentRules, getCounterIdStack(continuedList));
 | |
|       if (!listId) {
 | |
|         customListIdIndex += 1;
 | |
|         listId = "X" + customListIdIndex;
 | |
|       } else {
 | |
|         listId = "Y" + listId;
 | |
|       }
 | |
|       iterateOverChildListElements(listId, list, 0, currentParseState);
 | |
|       counterIdStacks[listId + "-level1-1"] = currentParseState.counterIdStack;
 | |
|     };
 | |
|     this.initialiseCreatedCounters = function() {
 | |
|       var newRule;
 | |
|       newRule = "office|document";
 | |
|       newRule += "{";
 | |
|       newRule += "counter-reset: " + globalCounterResetRule + ";";
 | |
|       newRule += "}";
 | |
|       appendRule(styleSheet, newRule);
 | |
|     };
 | |
|   }
 | |
|   odf.ListStyleToCss = function ListStyleToCss() {
 | |
|     var cssUnits = new core.CSSUnits, odfUtils = odf.OdfUtils;
 | |
|     function convertToPxValue(value) {
 | |
|       var parsedLength = odfUtils.parseLength(value);
 | |
|       if (!parsedLength) {
 | |
|         runtime.log("Could not parse value '" + value + "'.");
 | |
|         return 0;
 | |
|       }
 | |
|       return cssUnits.convert(parsedLength.value, parsedLength.unit, "px");
 | |
|     }
 | |
|     function escapeCSSString(value) {
 | |
|       return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
 | |
|     }
 | |
|     function isMatchingListStyle(list, matchingStyleName) {
 | |
|       var styleName;
 | |
|       if (list) {
 | |
|         styleName = list.getAttributeNS(textns, "style-name");
 | |
|       }
 | |
|       return styleName === matchingStyleName;
 | |
|     }
 | |
|     function getNumberRule(node) {
 | |
|       var style = node.getAttributeNS(stylens, "num-format"), suffix = node.getAttributeNS(stylens, "num-suffix") || "", prefix = node.getAttributeNS(stylens, "num-prefix") || "", content = "", textLevel = node.getAttributeNS(textns, "level"), displayLevels = node.getAttributeNS(textns, "display-levels");
 | |
|       if (prefix) {
 | |
|         content += '"' + escapeCSSString(prefix) + '"\n';
 | |
|       }
 | |
|       if (stylemap.hasOwnProperty(style)) {
 | |
|         textLevel = textLevel ? parseInt(textLevel, 10) : 1;
 | |
|         displayLevels = displayLevels ? parseInt(displayLevels, 10) : 1;
 | |
|         while (displayLevels > 0) {
 | |
|           content += " counter(" + (textLevel - displayLevels + 1) + listCounterIdSuffix + "," + stylemap[style] + ")";
 | |
|           if (displayLevels > 1) {
 | |
|             content += '"."';
 | |
|           }
 | |
|           displayLevels -= 1;
 | |
|         }
 | |
|       } else {
 | |
|         if (style) {
 | |
|           content += ' "' + style + '"';
 | |
|         } else {
 | |
|           content += ' ""';
 | |
|         }
 | |
|       }
 | |
|       return "content:" + content + ' "' + escapeCSSString(suffix) + '"';
 | |
|     }
 | |
|     function getImageRule() {
 | |
|       return "content: none";
 | |
|     }
 | |
|     function getBulletRule(node) {
 | |
|       var bulletChar = node.getAttributeNS(textns, "bullet-char");
 | |
|       return 'content: "' + escapeCSSString(bulletChar) + '"';
 | |
|     }
 | |
|     function getContentRule(node) {
 | |
|       var contentRule = "", listLevelProps, listLevelPositionSpaceMode, listLevelLabelAlign, followedBy;
 | |
|       if (node.localName === "list-level-style-number") {
 | |
|         contentRule = getNumberRule(node);
 | |
|       } else {
 | |
|         if (node.localName === "list-level-style-image") {
 | |
|           contentRule = getImageRule();
 | |
|         } else {
 | |
|           if (node.localName === "list-level-style-bullet") {
 | |
|             contentRule = getBulletRule(node);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       listLevelProps = (node.getElementsByTagNameNS(stylens, "list-level-properties")[0]);
 | |
|       if (listLevelProps) {
 | |
|         listLevelPositionSpaceMode = listLevelProps.getAttributeNS(textns, "list-level-position-and-space-mode");
 | |
|         if (listLevelPositionSpaceMode === "label-alignment") {
 | |
|           listLevelLabelAlign = (listLevelProps.getElementsByTagNameNS(stylens, "list-level-label-alignment")[0]);
 | |
|           if (listLevelLabelAlign) {
 | |
|             followedBy = listLevelLabelAlign.getAttributeNS(textns, "label-followed-by");
 | |
|           }
 | |
|           if (followedBy === "space") {
 | |
|             contentRule += ' "\\a0"';
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       return "\n" + contentRule + ";\n";
 | |
|     }
 | |
|     function getAllContentRules(listStyleNode) {
 | |
|       var childNode = listStyleNode.firstElementChild, level, rules = {};
 | |
|       while (childNode) {
 | |
|         level = childNode.getAttributeNS(textns, "level");
 | |
|         level = level && parseInt(level, 10);
 | |
|         rules[level] = getContentRule(childNode);
 | |
|         childNode = childNode.nextElementSibling;
 | |
|       }
 | |
|       return rules;
 | |
|     }
 | |
|     function addListStyleRule(styleSheet, name, node) {
 | |
|       var selector = 'text|list[text|style-name="' + name + '"]', level = node.getAttributeNS(textns, "level"), selectorLevel, listItemRule, listLevelProps, listLevelPositionSpaceMode, listLevelLabelAlign, listIndent, textAlign, bulletWidth, labelDistance, bulletIndent, followedBy, leftOffset;
 | |
|       listLevelProps = (node.getElementsByTagNameNS(stylens, "list-level-properties")[0]);
 | |
|       listLevelPositionSpaceMode = listLevelProps && listLevelProps.getAttributeNS(textns, "list-level-position-and-space-mode");
 | |
|       listLevelLabelAlign = (listLevelProps) && (listLevelProps.getElementsByTagNameNS(stylens, "list-level-label-alignment")[0]);
 | |
|       level = level && parseInt(level, 10);
 | |
|       selectorLevel = level;
 | |
|       while (selectorLevel > 1) {
 | |
|         selector += " > text|list-item > text|list";
 | |
|         selectorLevel -= 1;
 | |
|       }
 | |
|       textAlign = listLevelProps && listLevelProps.getAttributeNS(fons, "text-align") || "left";
 | |
|       switch(textAlign) {
 | |
|         case "end":
 | |
|           textAlign = "right";
 | |
|           break;
 | |
|         case "start":
 | |
|           textAlign = "left";
 | |
|           break;
 | |
|       }
 | |
|       if (listLevelPositionSpaceMode === "label-alignment") {
 | |
|         listIndent = listLevelLabelAlign && listLevelLabelAlign.getAttributeNS(fons, "margin-left") || "0px";
 | |
|         bulletIndent = listLevelLabelAlign && listLevelLabelAlign.getAttributeNS(fons, "text-indent") || "0px";
 | |
|         followedBy = listLevelLabelAlign && listLevelLabelAlign.getAttributeNS(textns, "label-followed-by");
 | |
|         leftOffset = convertToPxValue(listIndent);
 | |
|       } else {
 | |
|         listIndent = listLevelProps && listLevelProps.getAttributeNS(textns, "space-before") || "0px";
 | |
|         bulletWidth = listLevelProps && listLevelProps.getAttributeNS(textns, "min-label-width") || "0px";
 | |
|         labelDistance = listLevelProps && listLevelProps.getAttributeNS(textns, "min-label-distance") || "0px";
 | |
|         leftOffset = convertToPxValue(listIndent) + convertToPxValue(bulletWidth);
 | |
|       }
 | |
|       listItemRule = selector + " > text|list-item";
 | |
|       listItemRule += "{";
 | |
|       listItemRule += "margin-left: " + leftOffset + "px;";
 | |
|       listItemRule += "}";
 | |
|       appendRule(styleSheet, listItemRule);
 | |
|       listItemRule = selector + " > text|list-item > text|list";
 | |
|       listItemRule += "{";
 | |
|       listItemRule += "margin-left: " + -leftOffset + "px;";
 | |
|       listItemRule += "}";
 | |
|       appendRule(styleSheet, listItemRule);
 | |
|       listItemRule = selector + " > text|list-item > :not(text|list):first-child:before";
 | |
|       listItemRule += "{";
 | |
|       listItemRule += "text-align: " + textAlign + ";";
 | |
|       listItemRule += "display: inline-block;";
 | |
|       if (listLevelPositionSpaceMode === "label-alignment") {
 | |
|         listItemRule += "margin-left: " + bulletIndent + ";";
 | |
|         if (followedBy === "listtab") {
 | |
|           listItemRule += "padding-right: 0.2cm;";
 | |
|         }
 | |
|       } else {
 | |
|         listItemRule += "min-width: " + bulletWidth + ";";
 | |
|         listItemRule += "margin-left: " + (parseFloat(bulletWidth) === 0 ? "" : "-") + bulletWidth + ";";
 | |
|         listItemRule += "padding-right: " + labelDistance + ";";
 | |
|       }
 | |
|       listItemRule += "}";
 | |
|       appendRule(styleSheet, listItemRule);
 | |
|     }
 | |
|     function addRule(styleSheet, name, node) {
 | |
|       var n = node.firstElementChild;
 | |
|       while (n) {
 | |
|         if (n.namespaceURI === textns) {
 | |
|           addListStyleRule(styleSheet, name, n);
 | |
|         }
 | |
|         n = n.nextElementSibling;
 | |
|       }
 | |
|     }
 | |
|     function applyContentBasedStyles(styleSheet, odfBody, listStyles) {
 | |
|       var lists = odfBody.getElementsByTagNameNS(textns, "list"), listCounter = new UniqueListCounter(styleSheet), list, previousList, continueNumbering, continueListXmlId, xmlId, styleName, contentRules, listsWithXmlId = {}, i;
 | |
|       for (i = 0;i < lists.length;i += 1) {
 | |
|         list = (lists.item(i));
 | |
|         styleName = list.getAttributeNS(textns, "style-name");
 | |
|         if (styleName) {
 | |
|           continueNumbering = list.getAttributeNS(textns, "continue-numbering");
 | |
|           continueListXmlId = list.getAttributeNS(textns, "continue-list");
 | |
|           xmlId = list.getAttributeNS(xmlns, "id");
 | |
|           if (xmlId) {
 | |
|             listsWithXmlId[xmlId] = list;
 | |
|           }
 | |
|           contentRules = getAllContentRules(listStyles[styleName].element);
 | |
|           if (continueNumbering && !continueListXmlId && isMatchingListStyle(previousList, styleName)) {
 | |
|             listCounter.createCounterRules(contentRules, list, previousList);
 | |
|           } else {
 | |
|             if (continueListXmlId && isMatchingListStyle(listsWithXmlId[continueListXmlId], styleName)) {
 | |
|               listCounter.createCounterRules(contentRules, list, listsWithXmlId[continueListXmlId]);
 | |
|             } else {
 | |
|               listCounter.createCounterRules(contentRules, list);
 | |
|             }
 | |
|           }
 | |
|           previousList = list;
 | |
|         }
 | |
|       }
 | |
|       listCounter.initialiseCreatedCounters();
 | |
|     }
 | |
|     this.applyListStyles = function(styleSheet, styleTree, odfBody) {
 | |
|       var styleFamilyTree, node;
 | |
|       styleFamilyTree = styleTree["list"];
 | |
|       if (styleFamilyTree) {
 | |
|         Object.keys(styleFamilyTree).forEach(function(styleName) {
 | |
|           node = (styleFamilyTree[styleName]);
 | |
|           addRule(styleSheet, styleName, node.element);
 | |
|         });
 | |
|       }
 | |
|       applyContentBasedStyles(styleSheet, odfBody, styleFamilyTree);
 | |
|     };
 | |
|   };
 | |
| })();
 | |
| odf.LazyStyleProperties = function(parent, getters) {
 | |
|   var data = {};
 | |
|   this.value = function(name) {
 | |
|     var v;
 | |
|     if (data.hasOwnProperty(name)) {
 | |
|       v = data[name];
 | |
|     } else {
 | |
|       v = getters[name]();
 | |
|       if (v === undefined && parent) {
 | |
|         v = parent.value(name);
 | |
|       }
 | |
|       data[name] = v;
 | |
|     }
 | |
|     return v;
 | |
|   };
 | |
|   this.reset = function(p) {
 | |
|     parent = p;
 | |
|     data = {};
 | |
|   };
 | |
| };
 | |
| odf.StyleParseUtils = function() {
 | |
|   var stylens = odf.Namespaces.stylens;
 | |
|   function splitLength(length) {
 | |
|     var re = /(-?[0-9]*[0-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px))/, m = re.exec(length);
 | |
|     if (!m) {
 | |
|       return null;
 | |
|     }
 | |
|     return {value:parseFloat(m[1]), unit:m[3]};
 | |
|   }
 | |
|   function parseLength(val) {
 | |
|     var n, length, unit;
 | |
|     length = splitLength(val);
 | |
|     unit = length && length.unit;
 | |
|     if (unit === "px") {
 | |
|       n = length.value;
 | |
|     } else {
 | |
|       if (unit === "cm") {
 | |
|         n = length.value / 2.54 * 96;
 | |
|       } else {
 | |
|         if (unit === "mm") {
 | |
|           n = length.value / 25.4 * 96;
 | |
|         } else {
 | |
|           if (unit === "in") {
 | |
|             n = length.value * 96;
 | |
|           } else {
 | |
|             if (unit === "pt") {
 | |
|               n = length.value / .75;
 | |
|             } else {
 | |
|               if (unit === "pc") {
 | |
|                 n = length.value * 16;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return n;
 | |
|   }
 | |
|   this.parseLength = parseLength;
 | |
|   function parsePercent(value) {
 | |
|     var v;
 | |
|     if (value) {
 | |
|       v = parseFloat(value.substr(0, value.indexOf("%")));
 | |
|       if (isNaN(v)) {
 | |
|         v = undefined;
 | |
|       }
 | |
|     }
 | |
|     return v;
 | |
|   }
 | |
|   function parsePositiveLengthOrPercent(value, name, parent) {
 | |
|     var v = parsePercent(value), parentValue;
 | |
|     if (v !== undefined) {
 | |
|       if (parent) {
 | |
|         parentValue = parent.value(name);
 | |
|       }
 | |
|       if (parentValue === undefined) {
 | |
|         v = undefined;
 | |
|       } else {
 | |
|         v *= (parentValue) / 100;
 | |
|       }
 | |
|     } else {
 | |
|       v = parseLength(value);
 | |
|     }
 | |
|     return v;
 | |
|   }
 | |
|   this.parsePositiveLengthOrPercent = parsePositiveLengthOrPercent;
 | |
|   function getPropertiesElement(name, styleElement, previousPropertyElement) {
 | |
|     var e = previousPropertyElement ? previousPropertyElement.nextElementSibling : styleElement.firstElementChild;
 | |
|     while (e !== null && (e.localName !== name || e.namespaceURI !== stylens)) {
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|     return e;
 | |
|   }
 | |
|   this.getPropertiesElement = getPropertiesElement;
 | |
|   function parseAttributeList(text) {
 | |
|     if (text) {
 | |
|       text = text.replace(/^\s*(.*?)\s*$/g, "$1");
 | |
|     }
 | |
|     return text && text.length > 0 ? text.split(/\s+/) : [];
 | |
|   }
 | |
|   this.parseAttributeList = parseAttributeList;
 | |
| };
 | |
| odf.Style2CSS = function Style2CSS() {
 | |
|   var drawns = odf.Namespaces.drawns, fons = odf.Namespaces.fons, officens = odf.Namespaces.officens, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, tablens = odf.Namespaces.tablens, xlinkns = odf.Namespaces.xlinkns, presentationns = odf.Namespaces.presentationns, webodfhelperns = "urn:webodf:names:helper", domUtils = core.DomUtils, styleParseUtils = new odf.StyleParseUtils, familynamespaceprefixes = {"graphic":"draw", "drawing-page":"draw", "paragraph":"text", "presentation":"presentation", 
 | |
|   "ruby":"text", "section":"text", "table":"table", "table-cell":"table", "table-column":"table", "table-row":"table", "text":"text", "list":"text", "page":"office"}, familytagnames = {"graphic":["circle", "connected", "control", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "paragraph":["alphabetical-index-entry-template", "h", "illustration-index-entry-template", "index-source-style", "object-index-entry-template", 
 | |
|   "p", "table-index-entry-template", "table-of-content-entry-template", "user-index-entry-template"], "presentation":["caption", "circle", "connector", "control", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "drawing-page":["caption", "circle", "connector", "control", "page", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], 
 | |
|   "ruby":["ruby", "ruby-text"], "section":["alphabetical-index", "bibliography", "illustration-index", "index-title", "object-index", "section", "table-of-content", "table-index", "user-index"], "table":["background", "table"], "table-cell":["body", "covered-table-cell", "even-columns", "even-rows", "first-column", "first-row", "last-column", "last-row", "odd-columns", "odd-rows", "table-cell"], "table-column":["table-column"], "table-row":["table-row"], "text":["a", "index-entry-chapter", "index-entry-link-end", 
 | |
|   "index-entry-link-start", "index-entry-page-number", "index-entry-span", "index-entry-tab-stop", "index-entry-text", "index-title-template", "linenumbering-configuration", "list-level-style-number", "list-level-style-bullet", "outline-level-style", "span"], "list":["list-item"]}, textPropertySimpleMapping = [[fons, "color", "color"], [fons, "background-color", "background-color"], [fons, "font-weight", "font-weight"], [fons, "font-style", "font-style"]], bgImageSimpleMapping = [[stylens, "repeat", 
 | |
|   "background-repeat"]], paragraphPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "text-align", "text-align"], [fons, "text-indent", "text-indent"], [fons, "padding", "padding"], [fons, "padding-left", "padding-left"], [fons, "padding-right", "padding-right"], [fons, "padding-top", "padding-top"], [fons, "padding-bottom", "padding-bottom"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", 
 | |
|   "border-bottom"], [fons, "margin", "margin"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"], [fons, "border", "border"]], graphicPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "min-height", "min-height"], [drawns, "stroke", "border"], [svgns, "stroke-color", "border-color"], [svgns, "stroke-width", "border-width"], [fons, "border", "border"], [fons, "border-left", 
 | |
|   "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"]], tablecellPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "border", "border"]], tablecolumnPropertySimpleMapping = [[stylens, "column-width", "width"]], tablerowPropertySimpleMapping = 
 | |
|   [[stylens, "row-height", "height"], [fons, "keep-together", null]], tablePropertySimpleMapping = [[stylens, "width", "width"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"]], pageContentPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "padding", "padding"], [fons, "padding-left", "padding-left"], [fons, "padding-right", "padding-right"], [fons, "padding-top", 
 | |
|   "padding-top"], [fons, "padding-bottom", "padding-bottom"], [fons, "border", "border"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "margin", "margin"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"]], pageSizePropertySimpleMapping = [[fons, "page-width", "width"], [fons, 
 | |
|   "page-height", "height"]], borderPropertyMap = {"border":true, "border-left":true, "border-right":true, "border-top":true, "border-bottom":true, "stroke-width":true}, marginPropertyMap = {"margin":true, "margin-left":true, "margin-right":true, "margin-top":true, "margin-bottom":true}, fontFaceDeclsMap = {}, utils = odf.OdfUtils, documentType, odfRoot, defaultFontSize, xpath = xmldom.XPath, cssUnits = new core.CSSUnits;
 | |
|   function createSelector(family, name) {
 | |
|     var prefix = familynamespaceprefixes[family], namepart, selector;
 | |
|     if (prefix === undefined) {
 | |
|       return null;
 | |
|     }
 | |
|     if (name) {
 | |
|       namepart = "[" + prefix + '|style-name="' + name + '"]';
 | |
|     } else {
 | |
|       namepart = "";
 | |
|     }
 | |
|     if (prefix === "presentation") {
 | |
|       prefix = "draw";
 | |
|       if (name) {
 | |
|         namepart = '[presentation|style-name="' + name + '"]';
 | |
|       } else {
 | |
|         namepart = "";
 | |
|       }
 | |
|     }
 | |
|     selector = prefix + "|" + familytagnames[family].join(namepart + "," + prefix + "|") + namepart;
 | |
|     return selector;
 | |
|   }
 | |
|   function getSelectors(family, name, node) {
 | |
|     var selectors = [], ss, derivedStyles = node.derivedStyles, n;
 | |
|     ss = createSelector(family, name);
 | |
|     if (ss !== null) {
 | |
|       selectors.push(ss);
 | |
|     }
 | |
|     for (n in derivedStyles) {
 | |
|       if (derivedStyles.hasOwnProperty(n)) {
 | |
|         ss = getSelectors(family, n, derivedStyles[n]);
 | |
|         selectors = selectors.concat(ss);
 | |
|       }
 | |
|     }
 | |
|     return selectors;
 | |
|   }
 | |
|   function fixBorderWidth(value) {
 | |
|     var index = value.indexOf(" "), width, theRestOfBorderAttributes;
 | |
|     if (index !== -1) {
 | |
|       width = value.substring(0, index);
 | |
|       theRestOfBorderAttributes = value.substring(index);
 | |
|     } else {
 | |
|       width = value;
 | |
|       theRestOfBorderAttributes = "";
 | |
|     }
 | |
|     width = utils.parseLength(width);
 | |
|     if (width && width.unit === "pt" && width.value < .75) {
 | |
|       value = "0.75pt" + theRestOfBorderAttributes;
 | |
|     }
 | |
|     return value;
 | |
|   }
 | |
|   function getParentStyleNode(styleNode) {
 | |
|     var parentStyleName = "", parentStyleFamily = "", parentStyleNode = null, xp;
 | |
|     if (styleNode.localName === "default-style") {
 | |
|       return null;
 | |
|     }
 | |
|     parentStyleName = styleNode.getAttributeNS(stylens, "parent-style-name");
 | |
|     parentStyleFamily = styleNode.getAttributeNS(stylens, "family");
 | |
|     if (parentStyleName) {
 | |
|       xp = "//style:*[@style:name='" + parentStyleName + "'][@style:family='" + parentStyleFamily + "']";
 | |
|     } else {
 | |
|       xp = "//style:default-style[@style:family='" + parentStyleFamily + "']";
 | |
|     }
 | |
|     parentStyleNode = xpath.getODFElementsWithXPath((odfRoot), xp, odf.Namespaces.lookupNamespaceURI)[0];
 | |
|     return parentStyleNode;
 | |
|   }
 | |
|   function fixMargin(props, namespace, name, value) {
 | |
|     var length = utils.parseLength(value), multiplier, parentStyle, parentLength, result, properties;
 | |
|     if (!length || length.unit !== "%") {
 | |
|       return value;
 | |
|     }
 | |
|     multiplier = length.value / 100;
 | |
|     parentStyle = getParentStyleNode((props.parentNode));
 | |
|     result = "0";
 | |
|     while (parentStyle) {
 | |
|       properties = domUtils.getDirectChild(parentStyle, stylens, "paragraph-properties");
 | |
|       if (properties) {
 | |
|         parentLength = utils.parseLength(properties.getAttributeNS(namespace, name));
 | |
|         if (parentLength) {
 | |
|           if (parentLength.unit !== "%") {
 | |
|             result = parentLength.value * multiplier + parentLength.unit;
 | |
|             break;
 | |
|           }
 | |
|           multiplier *= parentLength.value / 100;
 | |
|         }
 | |
|       }
 | |
|       parentStyle = getParentStyleNode(parentStyle);
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   function applySimpleMapping(props, mapping) {
 | |
|     var rule = "", i, r, value;
 | |
|     for (i = 0;i < mapping.length;i += 1) {
 | |
|       r = mapping[i];
 | |
|       value = props.getAttributeNS(r[0], r[1]);
 | |
|       if (value) {
 | |
|         value = value.trim();
 | |
|         if (borderPropertyMap.hasOwnProperty(r[1])) {
 | |
|           value = fixBorderWidth(value);
 | |
|         } else {
 | |
|           if (marginPropertyMap.hasOwnProperty(r[1])) {
 | |
|             value = fixMargin(props, r[0], r[1], value);
 | |
|           }
 | |
|         }
 | |
|         if (r[2]) {
 | |
|           rule += r[2] + ":" + value + ";";
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return rule;
 | |
|   }
 | |
|   function getFontSize(styleNode) {
 | |
|     var props = domUtils.getDirectChild(styleNode, stylens, "text-properties");
 | |
|     if (props) {
 | |
|       return utils.parseFoFontSize(props.getAttributeNS(fons, "font-size"));
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   function parseTextPosition(position) {
 | |
|     var parts = styleParseUtils.parseAttributeList(position);
 | |
|     return {verticalTextPosition:parts[0], fontHeight:parts[1]};
 | |
|   }
 | |
|   function getTextProperties(props) {
 | |
|     var rule = "", fontName, fontSize, value, textDecorationLine = "", textDecorationStyle = "", textPosition, fontSizeRule = "", sizeMultiplier = 1, textFamilyStyleNode;
 | |
|     rule += applySimpleMapping(props, textPropertySimpleMapping);
 | |
|     value = props.getAttributeNS(stylens, "text-underline-style");
 | |
|     if (value === "solid") {
 | |
|       textDecorationLine += " underline";
 | |
|     }
 | |
|     value = props.getAttributeNS(stylens, "text-line-through-style");
 | |
|     if (value === "solid") {
 | |
|       textDecorationLine += " line-through";
 | |
|     }
 | |
|     if (textDecorationLine.length) {
 | |
|       rule += "text-decoration:" + textDecorationLine + ";\n";
 | |
|       rule += "text-decoration-line:" + textDecorationLine + ";\n";
 | |
|       rule += "-moz-text-decoration-line:" + textDecorationLine + ";\n";
 | |
|     }
 | |
|     value = props.getAttributeNS(stylens, "text-line-through-type");
 | |
|     switch(value) {
 | |
|       case "double":
 | |
|         textDecorationStyle += " double";
 | |
|         break;
 | |
|       case "single":
 | |
|         textDecorationStyle += " single";
 | |
|         break;
 | |
|     }
 | |
|     if (textDecorationStyle) {
 | |
|       rule += "text-decoration-style:" + textDecorationStyle + ";\n";
 | |
|       rule += "-moz-text-decoration-style:" + textDecorationStyle + ";\n";
 | |
|     }
 | |
|     fontName = props.getAttributeNS(stylens, "font-name") || props.getAttributeNS(fons, "font-family");
 | |
|     if (fontName) {
 | |
|       value = fontFaceDeclsMap[fontName];
 | |
|       rule += "font-family: " + (value || fontName) + ";";
 | |
|     }
 | |
|     value = props.getAttributeNS(stylens, "text-position");
 | |
|     if (value) {
 | |
|       textPosition = parseTextPosition(value);
 | |
|       rule += "vertical-align: " + textPosition.verticalTextPosition + "\n; ";
 | |
|       if (textPosition.fontHeight) {
 | |
|         sizeMultiplier = parseFloat(textPosition.fontHeight) / 100;
 | |
|       }
 | |
|     }
 | |
|     if (props.hasAttributeNS(fons, "font-size") || sizeMultiplier !== 1) {
 | |
|       textFamilyStyleNode = (props.parentNode);
 | |
|       while (textFamilyStyleNode) {
 | |
|         fontSize = getFontSize(textFamilyStyleNode);
 | |
|         if (fontSize) {
 | |
|           if (fontSize.unit !== "%") {
 | |
|             fontSizeRule = "font-size: " + fontSize.value * sizeMultiplier + fontSize.unit + ";";
 | |
|             break;
 | |
|           }
 | |
|           sizeMultiplier *= fontSize.value / 100;
 | |
|         }
 | |
|         textFamilyStyleNode = getParentStyleNode(textFamilyStyleNode);
 | |
|       }
 | |
|       if (!fontSizeRule) {
 | |
|         fontSizeRule = "font-size: " + parseFloat(defaultFontSize) * sizeMultiplier + cssUnits.getUnits(defaultFontSize) + ";";
 | |
|       }
 | |
|     }
 | |
|     rule += fontSizeRule;
 | |
|     return rule;
 | |
|   }
 | |
|   function getParagraphProperties(props) {
 | |
|     var rule = "", bgimage, url, lineHeight;
 | |
|     rule += applySimpleMapping(props, paragraphPropertySimpleMapping);
 | |
|     bgimage = domUtils.getDirectChild(props, stylens, "background-image");
 | |
|     if (bgimage) {
 | |
|       url = bgimage.getAttributeNS(xlinkns, "href");
 | |
|       if (url) {
 | |
|         rule += "background-image: url('odfkit:" + url + "');";
 | |
|         rule += applySimpleMapping(bgimage, bgImageSimpleMapping);
 | |
|       }
 | |
|     }
 | |
|     lineHeight = props.getAttributeNS(fons, "line-height");
 | |
|     if (lineHeight && lineHeight !== "normal") {
 | |
|       lineHeight = utils.parseFoLineHeight(lineHeight);
 | |
|       if (lineHeight.unit !== "%") {
 | |
|         rule += "line-height: " + lineHeight.value + lineHeight.unit + ";";
 | |
|       } else {
 | |
|         rule += "line-height: " + lineHeight.value / 100 + ";";
 | |
|       }
 | |
|     }
 | |
|     return rule;
 | |
|   }
 | |
|   function matchToRgb(m, r, g, b) {
 | |
|     return r + r + g + g + b + b;
 | |
|   }
 | |
|   function hexToRgb(hex) {
 | |
|     var result, shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
 | |
|     hex = hex.replace(shorthandRegex, matchToRgb);
 | |
|     result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
 | |
|     return result ? {r:parseInt(result[1], 16), g:parseInt(result[2], 16), b:parseInt(result[3], 16)} : null;
 | |
|   }
 | |
|   function isNumber(n) {
 | |
|     return !isNaN(parseFloat(n));
 | |
|   }
 | |
|   function getGraphicProperties(props) {
 | |
|     var rule = "", alpha, bgcolor, fill;
 | |
|     rule += applySimpleMapping(props, graphicPropertySimpleMapping);
 | |
|     alpha = props.getAttributeNS(drawns, "opacity");
 | |
|     fill = props.getAttributeNS(drawns, "fill");
 | |
|     bgcolor = props.getAttributeNS(drawns, "fill-color");
 | |
|     if (fill === "solid" || fill === "hatch") {
 | |
|       if (bgcolor && bgcolor !== "none") {
 | |
|         alpha = isNumber(alpha) ? parseFloat(alpha) / 100 : 1;
 | |
|         bgcolor = hexToRgb(bgcolor);
 | |
|         if (bgcolor) {
 | |
|           rule += "background-color: rgba(" + bgcolor.r + "," + bgcolor.g + "," + bgcolor.b + "," + alpha + ");";
 | |
|         }
 | |
|       } else {
 | |
|         rule += "background: none;";
 | |
|       }
 | |
|     } else {
 | |
|       if (fill === "none") {
 | |
|         rule += "background: none;";
 | |
|       }
 | |
|     }
 | |
|     return rule;
 | |
|   }
 | |
|   function getDrawingPageProperties(props) {
 | |
|     var rule = "";
 | |
|     rule += applySimpleMapping(props, graphicPropertySimpleMapping);
 | |
|     if (props.getAttributeNS(presentationns, "background-visible") === "true") {
 | |
|       rule += "background: none;";
 | |
|     }
 | |
|     return rule;
 | |
|   }
 | |
|   function getTableCellProperties(props) {
 | |
|     var rule = "";
 | |
|     rule += applySimpleMapping(props, tablecellPropertySimpleMapping);
 | |
|     return rule;
 | |
|   }
 | |
|   function getTableRowProperties(props) {
 | |
|     var rule = "";
 | |
|     rule += applySimpleMapping(props, tablerowPropertySimpleMapping);
 | |
|     return rule;
 | |
|   }
 | |
|   function getTableColumnProperties(props) {
 | |
|     var rule = "";
 | |
|     rule += applySimpleMapping(props, tablecolumnPropertySimpleMapping);
 | |
|     return rule;
 | |
|   }
 | |
|   function getTableProperties(props) {
 | |
|     var rule = "", borderModel;
 | |
|     rule += applySimpleMapping(props, tablePropertySimpleMapping);
 | |
|     borderModel = props.getAttributeNS(tablens, "border-model");
 | |
|     if (borderModel === "collapsing") {
 | |
|       rule += "border-collapse:collapse;";
 | |
|     } else {
 | |
|       if (borderModel === "separating") {
 | |
|         rule += "border-collapse:separate;";
 | |
|       }
 | |
|     }
 | |
|     return rule;
 | |
|   }
 | |
|   function getDerivedStyleNames(styleName, node) {
 | |
|     var styleNames = [styleName], derivedStyles = node.derivedStyles;
 | |
|     Object.keys(derivedStyles).forEach(function(styleName) {
 | |
|       var dsn = getDerivedStyleNames(styleName, derivedStyles[styleName]);
 | |
|       styleNames = styleNames.concat(dsn);
 | |
|     });
 | |
|     return styleNames;
 | |
|   }
 | |
|   function addDrawPageFrameDisplayRules(sheet, styleName, properties, node) {
 | |
|     var frameClasses = ["page-number", "date-time", "header", "footer"], styleNames = getDerivedStyleNames(styleName, node), visibleFrameClasses = [], invisibleFrameClasses = [];
 | |
|     function insertFrameVisibilityRule(controlledFrameClasses, visibility) {
 | |
|       var selectors = [], rule;
 | |
|       controlledFrameClasses.forEach(function(frameClass) {
 | |
|         styleNames.forEach(function(styleName) {
 | |
|           selectors.push('draw|page[webodfhelper|page-style-name="' + styleName + '"] draw|frame[presentation|class="' + frameClass + '"]');
 | |
|         });
 | |
|       });
 | |
|       if (selectors.length > 0) {
 | |
|         rule = selectors.join(",") + "{visibility:" + visibility + ";}";
 | |
|         sheet.insertRule(rule, sheet.cssRules.length);
 | |
|       }
 | |
|     }
 | |
|     frameClasses.forEach(function(frameClass) {
 | |
|       var displayValue;
 | |
|       displayValue = properties.getAttributeNS(presentationns, "display-" + frameClass);
 | |
|       if (displayValue === "true") {
 | |
|         visibleFrameClasses.push(frameClass);
 | |
|       } else {
 | |
|         if (displayValue === "false") {
 | |
|           invisibleFrameClasses.push(frameClass);
 | |
|         }
 | |
|       }
 | |
|     });
 | |
|     insertFrameVisibilityRule(visibleFrameClasses, "visible");
 | |
|     insertFrameVisibilityRule(invisibleFrameClasses, "hidden");
 | |
|   }
 | |
|   function addStyleRule(sheet, family, name, node) {
 | |
|     var selectors = getSelectors(family, name, node), selector = selectors.join(","), rule = "", properties;
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "text-properties");
 | |
|     if (properties) {
 | |
|       rule += getTextProperties(properties);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "paragraph-properties");
 | |
|     if (properties) {
 | |
|       rule += getParagraphProperties(properties);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "graphic-properties");
 | |
|     if (properties) {
 | |
|       rule += getGraphicProperties(properties);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "drawing-page-properties");
 | |
|     if (properties) {
 | |
|       rule += getDrawingPageProperties(properties);
 | |
|       addDrawPageFrameDisplayRules(sheet, name, (properties), node);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "table-cell-properties");
 | |
|     if (properties) {
 | |
|       rule += getTableCellProperties(properties);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "table-row-properties");
 | |
|     if (properties) {
 | |
|       rule += getTableRowProperties(properties);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "table-column-properties");
 | |
|     if (properties) {
 | |
|       rule += getTableColumnProperties(properties);
 | |
|     }
 | |
|     properties = domUtils.getDirectChild(node.element, stylens, "table-properties");
 | |
|     if (properties) {
 | |
|       rule += getTableProperties(properties);
 | |
|     }
 | |
|     if (rule.length === 0) {
 | |
|       return;
 | |
|     }
 | |
|     rule = selector + "{" + rule + "}";
 | |
|     sheet.insertRule(rule, sheet.cssRules.length);
 | |
|   }
 | |
|   function addPageStyleRules(sheet, node) {
 | |
|     var rule = "", imageProps, url, contentLayoutRule = "", pageSizeRule = "", props = domUtils.getDirectChild(node, stylens, "page-layout-properties"), stylename, masterStyles, e, masterStyleName;
 | |
|     if (!props) {
 | |
|       return;
 | |
|     }
 | |
|     stylename = node.getAttributeNS(stylens, "name");
 | |
|     rule += applySimpleMapping(props, pageContentPropertySimpleMapping);
 | |
|     imageProps = domUtils.getDirectChild(props, stylens, "background-image");
 | |
|     if (imageProps) {
 | |
|       url = imageProps.getAttributeNS(xlinkns, "href");
 | |
|       if (url) {
 | |
|         rule += "background-image: url('odfkit:" + url + "');";
 | |
|         rule += applySimpleMapping(imageProps, bgImageSimpleMapping);
 | |
|       }
 | |
|     }
 | |
|     if (documentType === "presentation") {
 | |
|       masterStyles = domUtils.getDirectChild((node.parentNode.parentNode), officens, "master-styles");
 | |
|       e = masterStyles && masterStyles.firstElementChild;
 | |
|       while (e) {
 | |
|         if (e.namespaceURI === stylens && e.localName === "master-page" && e.getAttributeNS(stylens, "page-layout-name") === stylename) {
 | |
|           masterStyleName = e.getAttributeNS(stylens, "name");
 | |
|           contentLayoutRule = 'draw|page[draw|master-page-name="' + masterStyleName + '"] {' + rule + "}";
 | |
|           pageSizeRule = 'office|body, draw|page[draw|master-page-name="' + masterStyleName + '"] {' + applySimpleMapping(props, pageSizePropertySimpleMapping) + " }";
 | |
|           sheet.insertRule(contentLayoutRule, sheet.cssRules.length);
 | |
|           sheet.insertRule(pageSizeRule, sheet.cssRules.length);
 | |
|         }
 | |
|         e = e.nextElementSibling;
 | |
|       }
 | |
|     } else {
 | |
|       if (documentType === "text") {
 | |
|         contentLayoutRule = "office|text {" + rule + "}";
 | |
|         rule = "";
 | |
|         pageSizeRule = "office|body {" + "width: " + props.getAttributeNS(fons, "page-width") + ";" + "}";
 | |
|         sheet.insertRule(contentLayoutRule, sheet.cssRules.length);
 | |
|         sheet.insertRule(pageSizeRule, sheet.cssRules.length);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function addRule(sheet, family, name, node) {
 | |
|     if (family === "page") {
 | |
|       addPageStyleRules(sheet, node.element);
 | |
|     } else {
 | |
|       addStyleRule(sheet, family, name, node);
 | |
|     }
 | |
|   }
 | |
|   function addRules(sheet, family, name, node) {
 | |
|     addRule(sheet, family, name, node);
 | |
|     var n;
 | |
|     for (n in node.derivedStyles) {
 | |
|       if (node.derivedStyles.hasOwnProperty(n)) {
 | |
|         addRules(sheet, family, n, node.derivedStyles[n]);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   this.style2css = function(doctype, rootNode, stylesheet, fontFaceMap, styleTree) {
 | |
|     var tree, rule, name, family;
 | |
|     function insertCSSNamespace(prefix, ns) {
 | |
|       rule = "@namespace " + prefix + " url(" + ns + ");";
 | |
|       try {
 | |
|         stylesheet.insertRule(rule, stylesheet.cssRules.length);
 | |
|       } catch (ignore) {
 | |
|       }
 | |
|     }
 | |
|     odfRoot = rootNode;
 | |
|     while (stylesheet.cssRules.length) {
 | |
|       stylesheet.deleteRule(stylesheet.cssRules.length - 1);
 | |
|     }
 | |
|     odf.Namespaces.forEachPrefix(insertCSSNamespace);
 | |
|     insertCSSNamespace("webodfhelper", webodfhelperns);
 | |
|     fontFaceDeclsMap = fontFaceMap;
 | |
|     documentType = doctype;
 | |
|     defaultFontSize = runtime.getWindow().getComputedStyle(document.body, null).getPropertyValue("font-size") || "12pt";
 | |
|     for (family in familynamespaceprefixes) {
 | |
|       if (familynamespaceprefixes.hasOwnProperty(family)) {
 | |
|         tree = styleTree[family];
 | |
|         for (name in tree) {
 | |
|           if (tree.hasOwnProperty(name)) {
 | |
|             addRules(stylesheet, family, name, tree[name]);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   function Point(x, y) {
 | |
|     var self = this;
 | |
|     this.getDistance = function(point) {
 | |
|       var xOffset = self.x - point.x, yOffset = self.y - point.y;
 | |
|       return Math.sqrt(xOffset * xOffset + yOffset * yOffset);
 | |
|     };
 | |
|     this.getCenter = function(point) {
 | |
|       return new Point((self.x + point.x) / 2, (self.y + point.y) / 2);
 | |
|     };
 | |
|     this.x;
 | |
|     this.y;
 | |
|     function init() {
 | |
|       self.x = x;
 | |
|       self.y = y;
 | |
|     }
 | |
|     init();
 | |
|   }
 | |
|   gui.ZoomHelper = function() {
 | |
|     var zoomableElement, panPoint, previousPanPoint, firstPinchDistance, zoom, previousZoom, maxZoom = 4, offsetParent, parentElement, events = new core.EventNotifier([gui.ZoomHelper.signalZoomChanged]), gestures = {NONE:0, SCROLL:1, PINCH:2}, currentGesture = gestures.NONE, requiresCustomScrollBars = runtime.getWindow().hasOwnProperty("ontouchstart"), parentOverflow = "";
 | |
|     function applyCSSTransform(x, y, scale, is3D) {
 | |
|       var transformCommand;
 | |
|       if (is3D) {
 | |
|         transformCommand = "translate3d(" + x + "px, " + y + "px, 0) scale3d(" + scale + ", " + scale + ", 1)";
 | |
|       } else {
 | |
|         transformCommand = "translate(" + x + "px, " + y + "px) scale(" + scale + ")";
 | |
|       }
 | |
|       zoomableElement.style.WebkitTransform = transformCommand;
 | |
|       zoomableElement.style.MozTransform = transformCommand;
 | |
|       zoomableElement.style.msTransform = transformCommand;
 | |
|       zoomableElement.style.OTransform = transformCommand;
 | |
|       zoomableElement.style.transform = transformCommand;
 | |
|     }
 | |
|     function applyTransform(is3D) {
 | |
|       if (is3D) {
 | |
|         applyCSSTransform(-panPoint.x, -panPoint.y, zoom, true);
 | |
|       } else {
 | |
|         applyCSSTransform(0, 0, zoom, true);
 | |
|         applyCSSTransform(0, 0, zoom, false);
 | |
|       }
 | |
|     }
 | |
|     function applyFastTransform() {
 | |
|       applyTransform(true);
 | |
|     }
 | |
|     function applyDetailedTransform() {
 | |
|       applyTransform(false);
 | |
|     }
 | |
|     function enableScrollBars(enable) {
 | |
|       if (!offsetParent || !requiresCustomScrollBars) {
 | |
|         return;
 | |
|       }
 | |
|       var initialOverflow = offsetParent.style.overflow, enabled = offsetParent.classList.contains("webodf-customScrollbars");
 | |
|       if (enable && enabled || !enable && !enabled) {
 | |
|         return;
 | |
|       }
 | |
|       if (enable) {
 | |
|         offsetParent.classList.add("webodf-customScrollbars");
 | |
|         offsetParent.style.overflow = "hidden";
 | |
|         runtime.requestAnimationFrame(function() {
 | |
|           offsetParent.style.overflow = initialOverflow;
 | |
|         });
 | |
|       } else {
 | |
|         offsetParent.classList.remove("webodf-customScrollbars");
 | |
|       }
 | |
|     }
 | |
|     function removeScroll() {
 | |
|       applyCSSTransform(-panPoint.x, -panPoint.y, zoom, true);
 | |
|       offsetParent.scrollLeft = 0;
 | |
|       offsetParent.scrollTop = 0;
 | |
|       parentOverflow = parentElement.style.overflow;
 | |
|       parentElement.style.overflow = "visible";
 | |
|       enableScrollBars(false);
 | |
|     }
 | |
|     function restoreScroll() {
 | |
|       applyCSSTransform(0, 0, zoom, true);
 | |
|       offsetParent.scrollLeft = panPoint.x;
 | |
|       offsetParent.scrollTop = panPoint.y;
 | |
|       parentElement.style.overflow = parentOverflow || "";
 | |
|       enableScrollBars(true);
 | |
|     }
 | |
|     function getPoint(touch) {
 | |
|       return new Point(touch.pageX - zoomableElement.offsetLeft, touch.pageY - zoomableElement.offsetTop);
 | |
|     }
 | |
|     function sanitizePointForPan(point) {
 | |
|       return new Point(Math.min(Math.max(point.x, zoomableElement.offsetLeft), (zoomableElement.offsetLeft + zoomableElement.offsetWidth) * zoom - offsetParent.clientWidth), Math.min(Math.max(point.y, zoomableElement.offsetTop), (zoomableElement.offsetTop + zoomableElement.offsetHeight) * zoom - offsetParent.clientHeight));
 | |
|     }
 | |
|     function processPan(point) {
 | |
|       if (previousPanPoint) {
 | |
|         panPoint.x -= point.x - previousPanPoint.x;
 | |
|         panPoint.y -= point.y - previousPanPoint.y;
 | |
|         panPoint = sanitizePointForPan(panPoint);
 | |
|       }
 | |
|       previousPanPoint = point;
 | |
|     }
 | |
|     function processZoom(zoomPoint, incrementalZoom) {
 | |
|       var originalZoom = zoom, actuallyIncrementedZoom, minZoom = Math.min(maxZoom, zoomableElement.offsetParent.clientWidth / zoomableElement.offsetWidth);
 | |
|       zoom = previousZoom * incrementalZoom;
 | |
|       zoom = Math.min(Math.max(zoom, minZoom), maxZoom);
 | |
|       actuallyIncrementedZoom = zoom / originalZoom;
 | |
|       panPoint.x += (actuallyIncrementedZoom - 1) * (zoomPoint.x + panPoint.x);
 | |
|       panPoint.y += (actuallyIncrementedZoom - 1) * (zoomPoint.y + panPoint.y);
 | |
|     }
 | |
|     function processPinch(point1, point2) {
 | |
|       var zoomPoint = point1.getCenter(point2), pinchDistance = point1.getDistance(point2), incrementalZoom = pinchDistance / firstPinchDistance;
 | |
|       processPan(zoomPoint);
 | |
|       processZoom(zoomPoint, incrementalZoom);
 | |
|     }
 | |
|     function prepareGesture(event) {
 | |
|       var fingers = event.touches.length, point1 = fingers > 0 ? getPoint(event.touches[0]) : null, point2 = fingers > 1 ? getPoint(event.touches[1]) : null;
 | |
|       if (point1 && point2) {
 | |
|         firstPinchDistance = point1.getDistance(point2);
 | |
|         previousZoom = zoom;
 | |
|         previousPanPoint = point1.getCenter(point2);
 | |
|         removeScroll();
 | |
|         currentGesture = gestures.PINCH;
 | |
|       } else {
 | |
|         if (point1) {
 | |
|           previousPanPoint = point1;
 | |
|           currentGesture = gestures.SCROLL;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function processGesture(event) {
 | |
|       var fingers = event.touches.length, point1 = fingers > 0 ? getPoint(event.touches[0]) : null, point2 = fingers > 1 ? getPoint(event.touches[1]) : null;
 | |
|       if (point1 && point2) {
 | |
|         event.preventDefault();
 | |
|         if (currentGesture === gestures.SCROLL) {
 | |
|           currentGesture = gestures.PINCH;
 | |
|           removeScroll();
 | |
|           firstPinchDistance = point1.getDistance(point2);
 | |
|           return;
 | |
|         }
 | |
|         processPinch(point1, point2);
 | |
|         applyFastTransform();
 | |
|       } else {
 | |
|         if (point1) {
 | |
|           if (currentGesture === gestures.PINCH) {
 | |
|             currentGesture = gestures.SCROLL;
 | |
|             restoreScroll();
 | |
|             return;
 | |
|           }
 | |
|           processPan(point1);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function sanitizeGesture() {
 | |
|       if (currentGesture === gestures.PINCH) {
 | |
|         events.emit(gui.ZoomHelper.signalZoomChanged, zoom);
 | |
|         restoreScroll();
 | |
|         applyDetailedTransform();
 | |
|       }
 | |
|       currentGesture = gestures.NONE;
 | |
|     }
 | |
|     this.subscribe = function(eventid, cb) {
 | |
|       events.subscribe(eventid, cb);
 | |
|     };
 | |
|     this.unsubscribe = function(eventid, cb) {
 | |
|       events.unsubscribe(eventid, cb);
 | |
|     };
 | |
|     this.getZoomLevel = function() {
 | |
|       return zoom;
 | |
|     };
 | |
|     this.setZoomLevel = function(zoomLevel) {
 | |
|       if (zoomableElement) {
 | |
|         zoom = zoomLevel;
 | |
|         applyDetailedTransform();
 | |
|         events.emit(gui.ZoomHelper.signalZoomChanged, zoom);
 | |
|       }
 | |
|     };
 | |
|     function registerGestureListeners() {
 | |
|       if (offsetParent) {
 | |
|         offsetParent.addEventListener("touchstart", (prepareGesture), false);
 | |
|         offsetParent.addEventListener("touchmove", (processGesture), false);
 | |
|         offsetParent.addEventListener("touchend", (sanitizeGesture), false);
 | |
|       }
 | |
|     }
 | |
|     function unregisterGestureListeners() {
 | |
|       if (offsetParent) {
 | |
|         offsetParent.removeEventListener("touchstart", (prepareGesture), false);
 | |
|         offsetParent.removeEventListener("touchmove", (processGesture), false);
 | |
|         offsetParent.removeEventListener("touchend", (sanitizeGesture), false);
 | |
|       }
 | |
|     }
 | |
|     this.destroy = function(callback) {
 | |
|       unregisterGestureListeners();
 | |
|       enableScrollBars(false);
 | |
|       callback();
 | |
|     };
 | |
|     this.setZoomableElement = function(element) {
 | |
|       unregisterGestureListeners();
 | |
|       zoomableElement = element;
 | |
|       offsetParent = (zoomableElement.offsetParent);
 | |
|       parentElement = (zoomableElement.parentNode);
 | |
|       applyDetailedTransform();
 | |
|       registerGestureListeners();
 | |
|       enableScrollBars(true);
 | |
|     };
 | |
|     function init() {
 | |
|       zoom = 1;
 | |
|       previousZoom = 1;
 | |
|       panPoint = new Point(0, 0);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
|   gui.ZoomHelper.signalZoomChanged = "zoomChanged";
 | |
| })();
 | |
| ops.Canvas = function Canvas() {
 | |
| };
 | |
| ops.Canvas.prototype.getZoomLevel = function() {
 | |
| };
 | |
| ops.Canvas.prototype.getElement = function() {
 | |
| };
 | |
| ops.Canvas.prototype.getSizer = function() {
 | |
| };
 | |
| ops.Canvas.prototype.getZoomHelper = function() {
 | |
| };
 | |
| (function() {
 | |
|   function LoadingQueue() {
 | |
|     var queue = [], taskRunning = false;
 | |
|     function run(task) {
 | |
|       taskRunning = true;
 | |
|       runtime.setTimeout(function() {
 | |
|         try {
 | |
|           task();
 | |
|         } catch (e) {
 | |
|           runtime.log(String(e) + "\n" + e.stack);
 | |
|         }
 | |
|         taskRunning = false;
 | |
|         if (queue.length > 0) {
 | |
|           run(queue.pop());
 | |
|         }
 | |
|       }, 10);
 | |
|     }
 | |
|     this.clearQueue = function() {
 | |
|       queue.length = 0;
 | |
|     };
 | |
|     this.addToQueue = function(loadingTask) {
 | |
|       if (queue.length === 0 && !taskRunning) {
 | |
|         return run(loadingTask);
 | |
|       }
 | |
|       queue.push(loadingTask);
 | |
|     };
 | |
|   }
 | |
|   function PageSwitcher(css) {
 | |
|     var sheet = (css.sheet), position = 1;
 | |
|     function updateCSS() {
 | |
|       while (sheet.cssRules.length > 0) {
 | |
|         sheet.deleteRule(0);
 | |
|       }
 | |
|       sheet.insertRule("#shadowContent draw|page {display:none;}", 0);
 | |
|       sheet.insertRule("office|presentation draw|page {display:none;}", 1);
 | |
|       sheet.insertRule("#shadowContent draw|page:nth-of-type(" + position + ") {display:block;}", 2);
 | |
|       sheet.insertRule("office|presentation draw|page:nth-of-type(" + position + ") {display:block;}", 3);
 | |
|     }
 | |
|     this.showFirstPage = function() {
 | |
|       position = 1;
 | |
|       updateCSS();
 | |
|     };
 | |
|     this.showNextPage = function() {
 | |
|       position += 1;
 | |
|       updateCSS();
 | |
|     };
 | |
|     this.showPreviousPage = function() {
 | |
|       if (position > 1) {
 | |
|         position -= 1;
 | |
|         updateCSS();
 | |
|       }
 | |
|     };
 | |
|     this.showPage = function(n) {
 | |
|       if (n > 0) {
 | |
|         position = n;
 | |
|         updateCSS();
 | |
|       }
 | |
|     };
 | |
|     this.css = css;
 | |
|     this.destroy = function(callback) {
 | |
|       css.parentNode.removeChild(css);
 | |
|       callback();
 | |
|     };
 | |
|   }
 | |
|   function listenEvent(eventTarget, eventType, eventHandler) {
 | |
|     if (eventTarget.addEventListener) {
 | |
|       eventTarget.addEventListener(eventType, eventHandler, false);
 | |
|     } else {
 | |
|       if (eventTarget.attachEvent) {
 | |
|         eventType = "on" + eventType;
 | |
|         eventTarget.attachEvent(eventType, eventHandler);
 | |
|       } else {
 | |
|         eventTarget["on" + eventType] = eventHandler;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   var drawns = odf.Namespaces.drawns, fons = odf.Namespaces.fons, officens = odf.Namespaces.officens, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns, presentationns = odf.Namespaces.presentationns, webodfhelperns = "urn:webodf:names:helper", xpath = xmldom.XPath, domUtils = core.DomUtils;
 | |
|   function clearCSSStyleSheet(style) {
 | |
|     var stylesheet = (style.sheet), cssRules = stylesheet.cssRules;
 | |
|     while (cssRules.length) {
 | |
|       stylesheet.deleteRule(cssRules.length - 1);
 | |
|     }
 | |
|   }
 | |
|   function handleStyles(odfcontainer, formatting, stylesxmlcss) {
 | |
|     var style2css = new odf.Style2CSS, list2css = new odf.ListStyleToCss, styleSheet = (stylesxmlcss.sheet), styleTree = (new odf.StyleTree(odfcontainer.rootElement.styles, odfcontainer.rootElement.automaticStyles)).getStyleTree();
 | |
|     style2css.style2css(odfcontainer.getDocumentType(), odfcontainer.rootElement, styleSheet, formatting.getFontMap(), styleTree);
 | |
|     list2css.applyListStyles(styleSheet, styleTree, odfcontainer.rootElement.body);
 | |
|   }
 | |
|   function handleFonts(odfContainer, fontcss) {
 | |
|     var fontLoader = new odf.FontLoader;
 | |
|     fontLoader.loadFonts(odfContainer, (fontcss.sheet));
 | |
|   }
 | |
|   function dropTemplateDrawFrames(clonedNode) {
 | |
|     var i, element, presentationClass, clonedDrawFrameElements = domUtils.getElementsByTagNameNS(clonedNode, drawns, "frame");
 | |
|     for (i = 0;i < clonedDrawFrameElements.length;i += 1) {
 | |
|       element = (clonedDrawFrameElements[i]);
 | |
|       presentationClass = element.getAttributeNS(presentationns, "class");
 | |
|       if (presentationClass && !/^(date-time|footer|header|page-number)$/.test(presentationClass)) {
 | |
|         element.parentNode.removeChild(element);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function getHeaderFooter(odfContainer, frame, headerFooterId) {
 | |
|     var headerFooter = null, i, declElements = odfContainer.rootElement.body.getElementsByTagNameNS(presentationns, headerFooterId + "-decl"), headerFooterName = frame.getAttributeNS(presentationns, "use-" + headerFooterId + "-name"), element;
 | |
|     if (headerFooterName && declElements.length > 0) {
 | |
|       for (i = 0;i < declElements.length;i += 1) {
 | |
|         element = (declElements[i]);
 | |
|         if (element.getAttributeNS(presentationns, "name") === headerFooterName) {
 | |
|           headerFooter = element.textContent;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return headerFooter;
 | |
|   }
 | |
|   function setContainerValue(rootElement, ns, localName, value) {
 | |
|     var i, containerList, document = rootElement.ownerDocument, e;
 | |
|     containerList = domUtils.getElementsByTagNameNS(rootElement, ns, localName);
 | |
|     for (i = 0;i < containerList.length;i += 1) {
 | |
|       domUtils.removeAllChildNodes(containerList[i]);
 | |
|       if (value) {
 | |
|         e = (containerList[i]);
 | |
|         e.appendChild(document.createTextNode(value));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function setDrawElementPosition(styleid, frame, stylesheet) {
 | |
|     frame.setAttributeNS(webodfhelperns, "styleid", styleid);
 | |
|     var rule, anchor = frame.getAttributeNS(textns, "anchor-type"), x = frame.getAttributeNS(svgns, "x"), y = frame.getAttributeNS(svgns, "y"), width = frame.getAttributeNS(svgns, "width"), height = frame.getAttributeNS(svgns, "height"), minheight = frame.getAttributeNS(fons, "min-height"), minwidth = frame.getAttributeNS(fons, "min-width");
 | |
|     if (anchor === "as-char") {
 | |
|       rule = "display: inline-block;";
 | |
|     } else {
 | |
|       if (anchor || x || y) {
 | |
|         rule = "position: absolute;";
 | |
|       } else {
 | |
|         if (width || height || minheight || minwidth) {
 | |
|           rule = "display: block;";
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (x) {
 | |
|       rule += "left: " + x + ";";
 | |
|     }
 | |
|     if (y) {
 | |
|       rule += "top: " + y + ";";
 | |
|     }
 | |
|     if (width) {
 | |
|       rule += "width: " + width + ";";
 | |
|     }
 | |
|     if (height) {
 | |
|       rule += "height: " + height + ";";
 | |
|     }
 | |
|     if (minheight) {
 | |
|       rule += "min-height: " + minheight + ";";
 | |
|     }
 | |
|     if (minwidth) {
 | |
|       rule += "min-width: " + minwidth + ";";
 | |
|     }
 | |
|     if (rule) {
 | |
|       rule = "draw|" + frame.localName + '[webodfhelper|styleid="' + styleid + '"] {' + rule + "}";
 | |
|       stylesheet.insertRule(rule, stylesheet.cssRules.length);
 | |
|     }
 | |
|   }
 | |
|   function getUrlFromBinaryDataElement(image) {
 | |
|     var node = image.firstChild;
 | |
|     while (node) {
 | |
|       if (node.namespaceURI === officens && node.localName === "binary-data") {
 | |
|         return "data:image/png;base64," + node.textContent.replace(/[\r\n\s]/g, "");
 | |
|       }
 | |
|       node = node.nextSibling;
 | |
|     }
 | |
|     return "";
 | |
|   }
 | |
|   function setImage(id, container, image, stylesheet) {
 | |
|     image.setAttributeNS(webodfhelperns, "styleid", id);
 | |
|     var url = image.getAttributeNS(xlinkns, "href"), part;
 | |
|     function callback(url) {
 | |
|       var rule;
 | |
|       if (url) {
 | |
|         rule = "background-image: url(" + url + ");";
 | |
|         rule = 'draw|image[webodfhelper|styleid="' + id + '"] {' + rule + "}";
 | |
|         stylesheet.insertRule(rule, stylesheet.cssRules.length);
 | |
|       }
 | |
|     }
 | |
|     function onchange(p) {
 | |
|       callback(p.url);
 | |
|     }
 | |
|     if (url) {
 | |
|       try {
 | |
|         part = container.getPart(url);
 | |
|         part.onchange = onchange;
 | |
|         part.load();
 | |
|       } catch (e) {
 | |
|         runtime.log("slight problem: " + String(e));
 | |
|       }
 | |
|     } else {
 | |
|       url = getUrlFromBinaryDataElement(image);
 | |
|       callback(url);
 | |
|     }
 | |
|   }
 | |
|   function formatParagraphAnchors(odfbody) {
 | |
|     var n, i, nodes = xpath.getODFElementsWithXPath(odfbody, ".//*[*[@text:anchor-type='paragraph']]", odf.Namespaces.lookupNamespaceURI);
 | |
|     for (i = 0;i < nodes.length;i += 1) {
 | |
|       n = nodes[i];
 | |
|       if (n.setAttributeNS) {
 | |
|         n.setAttributeNS(webodfhelperns, "containsparagraphanchor", true);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function modifyTables(odffragment, documentns) {
 | |
|     var i, tableCells, node;
 | |
|     function modifyTableCell(node) {
 | |
|       if (node.hasAttributeNS(tablens, "number-columns-spanned")) {
 | |
|         node.setAttributeNS(documentns, "colspan", node.getAttributeNS(tablens, "number-columns-spanned"));
 | |
|       }
 | |
|       if (node.hasAttributeNS(tablens, "number-rows-spanned")) {
 | |
|         node.setAttributeNS(documentns, "rowspan", node.getAttributeNS(tablens, "number-rows-spanned"));
 | |
|       }
 | |
|     }
 | |
|     tableCells = domUtils.getElementsByTagNameNS(odffragment, tablens, "table-cell");
 | |
|     for (i = 0;i < tableCells.length;i += 1) {
 | |
|       node = (tableCells[i]);
 | |
|       modifyTableCell(node);
 | |
|     }
 | |
|   }
 | |
|   function modifyLineBreakElements(odffragment) {
 | |
|     var document = odffragment.ownerDocument, lineBreakElements = domUtils.getElementsByTagNameNS(odffragment, textns, "line-break");
 | |
|     lineBreakElements.forEach(function(lineBreak) {
 | |
|       if (!lineBreak.hasChildNodes()) {
 | |
|         lineBreak.appendChild(document.createElement("br"));
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   function expandSpaceElements(odffragment) {
 | |
|     var spaces, doc = odffragment.ownerDocument;
 | |
|     function expandSpaceElement(space) {
 | |
|       var j, count;
 | |
|       domUtils.removeAllChildNodes(space);
 | |
|       space.appendChild(doc.createTextNode(" "));
 | |
|       count = parseInt(space.getAttributeNS(textns, "c"), 10);
 | |
|       if (count > 1) {
 | |
|         space.removeAttributeNS(textns, "c");
 | |
|         for (j = 1;j < count;j += 1) {
 | |
|           space.parentNode.insertBefore(space.cloneNode(true), space);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     spaces = domUtils.getElementsByTagNameNS(odffragment, textns, "s");
 | |
|     spaces.forEach(expandSpaceElement);
 | |
|   }
 | |
|   function expandTabElements(odffragment) {
 | |
|     var tabs;
 | |
|     tabs = domUtils.getElementsByTagNameNS(odffragment, textns, "tab");
 | |
|     tabs.forEach(function(tab) {
 | |
|       tab.textContent = "\t";
 | |
|     });
 | |
|   }
 | |
|   function modifyDrawElements(odfbody, stylesheet) {
 | |
|     var node, drawElements = [], i;
 | |
|     node = odfbody.firstElementChild;
 | |
|     while (node && node !== odfbody) {
 | |
|       if (node.namespaceURI === drawns) {
 | |
|         drawElements[drawElements.length] = node;
 | |
|       }
 | |
|       if (node.firstElementChild) {
 | |
|         node = node.firstElementChild;
 | |
|       } else {
 | |
|         while (node && node !== odfbody && !node.nextElementSibling) {
 | |
|           node = (node.parentNode);
 | |
|         }
 | |
|         if (node && node.nextElementSibling) {
 | |
|           node = node.nextElementSibling;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     for (i = 0;i < drawElements.length;i += 1) {
 | |
|       node = drawElements[i];
 | |
|       setDrawElementPosition("frame" + String(i), node, stylesheet);
 | |
|     }
 | |
|     formatParagraphAnchors(odfbody);
 | |
|   }
 | |
|   function cloneMasterPages(formatting, odfContainer, shadowContent, odfbody, stylesheet) {
 | |
|     var masterPageName, masterPageElement, styleId, clonedPageElement, clonedElement, clonedDrawElements, pageNumber = 0, i, element, elementToClone, document = odfContainer.rootElement.ownerDocument;
 | |
|     element = odfbody.firstElementChild;
 | |
|     if (!(element && element.namespaceURI === officens && (element.localName === "presentation" || element.localName === "drawing"))) {
 | |
|       return;
 | |
|     }
 | |
|     element = element.firstElementChild;
 | |
|     while (element) {
 | |
|       masterPageName = element.getAttributeNS(drawns, "master-page-name");
 | |
|       masterPageElement = masterPageName ? formatting.getMasterPageElement(masterPageName) : null;
 | |
|       if (masterPageElement) {
 | |
|         styleId = element.getAttributeNS(webodfhelperns, "styleid");
 | |
|         clonedPageElement = document.createElementNS(drawns, "draw:page");
 | |
|         elementToClone = masterPageElement.firstElementChild;
 | |
|         i = 0;
 | |
|         while (elementToClone) {
 | |
|           if (elementToClone.getAttributeNS(presentationns, "placeholder") !== "true") {
 | |
|             clonedElement = (elementToClone.cloneNode(true));
 | |
|             clonedPageElement.appendChild(clonedElement);
 | |
|           }
 | |
|           elementToClone = elementToClone.nextElementSibling;
 | |
|           i += 1;
 | |
|         }
 | |
|         dropTemplateDrawFrames(clonedPageElement);
 | |
|         clonedDrawElements = domUtils.getElementsByTagNameNS(clonedPageElement, drawns, "*");
 | |
|         for (i = 0;i < clonedDrawElements.length;i += 1) {
 | |
|           setDrawElementPosition(styleId + "_" + i, clonedDrawElements[i], stylesheet);
 | |
|         }
 | |
|         shadowContent.appendChild(clonedPageElement);
 | |
|         pageNumber = String(shadowContent.getElementsByTagNameNS(drawns, "page").length);
 | |
|         setContainerValue(clonedPageElement, textns, "page-number", pageNumber);
 | |
|         setContainerValue(clonedPageElement, presentationns, "header", getHeaderFooter(odfContainer, (element), "header"));
 | |
|         setContainerValue(clonedPageElement, presentationns, "footer", getHeaderFooter(odfContainer, (element), "footer"));
 | |
|         setDrawElementPosition(styleId, clonedPageElement, stylesheet);
 | |
|         clonedPageElement.setAttributeNS(webodfhelperns, "page-style-name", element.getAttributeNS(drawns, "style-name"));
 | |
|         clonedPageElement.setAttributeNS(drawns, "draw:master-page-name", masterPageElement.getAttributeNS(stylens, "name"));
 | |
|       }
 | |
|       element = element.nextElementSibling;
 | |
|     }
 | |
|   }
 | |
|   function setVideo(container, plugin) {
 | |
|     var video, source, url, doc = plugin.ownerDocument, part;
 | |
|     url = plugin.getAttributeNS(xlinkns, "href");
 | |
|     function callback(url, mimetype) {
 | |
|       var ns = doc.documentElement.namespaceURI;
 | |
|       if (mimetype.substr(0, 6) === "video/") {
 | |
|         video = doc.createElementNS(ns, "video");
 | |
|         video.setAttribute("controls", "controls");
 | |
|         source = doc.createElementNS(ns, "source");
 | |
|         if (url) {
 | |
|           source.setAttribute("src", url);
 | |
|         }
 | |
|         source.setAttribute("type", mimetype);
 | |
|         video.appendChild(source);
 | |
|         plugin.parentNode.appendChild(video);
 | |
|       } else {
 | |
|         plugin.innerHtml = "Unrecognised Plugin";
 | |
|       }
 | |
|     }
 | |
|     function onchange(p) {
 | |
|       callback(p.url, p.mimetype);
 | |
|     }
 | |
|     if (url) {
 | |
|       try {
 | |
|         part = container.getPart(url);
 | |
|         part.onchange = onchange;
 | |
|         part.load();
 | |
|       } catch (e) {
 | |
|         runtime.log("slight problem: " + String(e));
 | |
|       }
 | |
|     } else {
 | |
|       runtime.log("using MP4 data fallback");
 | |
|       url = getUrlFromBinaryDataElement(plugin);
 | |
|       callback(url, "video/mp4");
 | |
|     }
 | |
|   }
 | |
|   function findWebODFStyleSheet(head) {
 | |
|     var style = head.firstElementChild;
 | |
|     while (style && !(style.localName === "style" && style.hasAttribute("webodfcss"))) {
 | |
|       style = style.nextElementSibling;
 | |
|     }
 | |
|     return (style);
 | |
|   }
 | |
|   function addWebODFStyleSheet(document) {
 | |
|     var head = (document.getElementsByTagName("head")[0]), css, style, href, count = document.styleSheets.length;
 | |
|     style = findWebODFStyleSheet(head);
 | |
|     if (style) {
 | |
|       count = parseInt(style.getAttribute("webodfcss"), 10);
 | |
|       style.setAttribute("webodfcss", count + 1);
 | |
|       return style;
 | |
|     }
 | |
|     if (String(typeof webodf_css) === "string") {
 | |
|       css = (webodf_css);
 | |
|     } else {
 | |
|       href = "webodf.css";
 | |
|       if (runtime.currentDirectory) {
 | |
|         href = runtime.currentDirectory();
 | |
|         if (href.length > 0 && href.substr(-1) !== "/") {
 | |
|           href += "/";
 | |
|         }
 | |
|         href += "../webodf.css";
 | |
|       }
 | |
|       css = (runtime.readFileSync(href, "utf-8"));
 | |
|     }
 | |
|     style = (document.createElementNS(head.namespaceURI, "style"));
 | |
|     style.setAttribute("media", "screen, print, handheld, projection");
 | |
|     style.setAttribute("type", "text/css");
 | |
|     style.setAttribute("webodfcss", "1");
 | |
|     style.appendChild(document.createTextNode(css));
 | |
|     head.appendChild(style);
 | |
|     return style;
 | |
|   }
 | |
|   function removeWebODFStyleSheet(webodfcss) {
 | |
|     var count = parseInt(webodfcss.getAttribute("webodfcss"), 10);
 | |
|     if (count === 1) {
 | |
|       webodfcss.parentNode.removeChild(webodfcss);
 | |
|     } else {
 | |
|       webodfcss.setAttribute("count", count - 1);
 | |
|     }
 | |
|   }
 | |
|   function addStyleSheet(document) {
 | |
|     var head = (document.getElementsByTagName("head")[0]), style = document.createElementNS(head.namespaceURI, "style"), text = "";
 | |
|     style.setAttribute("type", "text/css");
 | |
|     style.setAttribute("media", "screen, print, handheld, projection");
 | |
|     odf.Namespaces.forEachPrefix(function(prefix, ns) {
 | |
|       text += "@namespace " + prefix + " url(" + ns + ");\n";
 | |
|     });
 | |
|     text += "@namespace webodfhelper url(" + webodfhelperns + ");\n";
 | |
|     style.appendChild(document.createTextNode(text));
 | |
|     head.appendChild(style);
 | |
|     return (style);
 | |
|   }
 | |
|   odf.OdfCanvas = function OdfCanvas(element, viewport) {
 | |
|     runtime.assert(element !== null && element !== undefined, "odf.OdfCanvas constructor needs DOM element");
 | |
|     runtime.assert(element.ownerDocument !== null && element.ownerDocument !== undefined, "odf.OdfCanvas constructor needs DOM");
 | |
|     var self = this, doc = (element.ownerDocument), odfcontainer, formatting = new odf.Formatting, pageSwitcher, sizer = null, annotationsPane = null, allowAnnotations = false, showAnnotationRemoveButton = false, annotationViewManager = null, webodfcss, fontcss, stylesxmlcss, positioncss, shadowContent, eventHandlers = {}, waitingForDoneTimeoutId, redrawContainerTask, shouldRefreshCss = false, shouldRerenderAnnotations = false, loadingQueue = new LoadingQueue, zoomHelper = new gui.ZoomHelper, canvasViewport = 
 | |
|     viewport || new gui.SingleScrollViewport((element.parentNode));
 | |
|     function loadImages(container, odffragment, stylesheet) {
 | |
|       var i, images, node;
 | |
|       function loadImage(name, container, node, stylesheet) {
 | |
|         loadingQueue.addToQueue(function() {
 | |
|           setImage(name, container, node, stylesheet);
 | |
|         });
 | |
|       }
 | |
|       images = odffragment.getElementsByTagNameNS(drawns, "image");
 | |
|       for (i = 0;i < images.length;i += 1) {
 | |
|         node = (images.item(i));
 | |
|         loadImage("image" + String(i), container, node, stylesheet);
 | |
|       }
 | |
|     }
 | |
|     function loadVideos(container, odffragment) {
 | |
|       var i, plugins, node;
 | |
|       function loadVideo(container, node) {
 | |
|         loadingQueue.addToQueue(function() {
 | |
|           setVideo(container, node);
 | |
|         });
 | |
|       }
 | |
|       plugins = odffragment.getElementsByTagNameNS(drawns, "plugin");
 | |
|       for (i = 0;i < plugins.length;i += 1) {
 | |
|         node = (plugins.item(i));
 | |
|         loadVideo(container, node);
 | |
|       }
 | |
|     }
 | |
|     function addEventListener(eventType, eventHandler) {
 | |
|       var handlers;
 | |
|       if (eventHandlers.hasOwnProperty(eventType)) {
 | |
|         handlers = eventHandlers[eventType];
 | |
|       } else {
 | |
|         handlers = eventHandlers[eventType] = [];
 | |
|       }
 | |
|       if (eventHandler && handlers.indexOf(eventHandler) === -1) {
 | |
|         handlers.push(eventHandler);
 | |
|       }
 | |
|     }
 | |
|     function fireEvent(eventType, args) {
 | |
|       if (!eventHandlers.hasOwnProperty(eventType)) {
 | |
|         return;
 | |
|       }
 | |
|       var handlers = eventHandlers[eventType], i;
 | |
|       for (i = 0;i < handlers.length;i += 1) {
 | |
|         handlers[i].apply(null, args);
 | |
|       }
 | |
|     }
 | |
|     function fixContainerSize() {
 | |
|       var minHeight, odfdoc = sizer.firstChild, zoomLevel = zoomHelper.getZoomLevel();
 | |
|       if (!odfdoc) {
 | |
|         return;
 | |
|       }
 | |
|       sizer.style.WebkitTransformOrigin = "0% 0%";
 | |
|       sizer.style.MozTransformOrigin = "0% 0%";
 | |
|       sizer.style.msTransformOrigin = "0% 0%";
 | |
|       sizer.style.OTransformOrigin = "0% 0%";
 | |
|       sizer.style.transformOrigin = "0% 0%";
 | |
|       if (annotationViewManager) {
 | |
|         minHeight = annotationViewManager.getMinimumHeightForAnnotationPane();
 | |
|         if (minHeight) {
 | |
|           sizer.style.minHeight = minHeight;
 | |
|         } else {
 | |
|           sizer.style.removeProperty("min-height");
 | |
|         }
 | |
|       }
 | |
|       element.style.width = Math.round(zoomLevel * sizer.offsetWidth) + "px";
 | |
|       element.style.height = Math.round(zoomLevel * sizer.offsetHeight) + "px";
 | |
|       element.style.display = "inline-block";
 | |
|     }
 | |
|     function redrawContainer() {
 | |
|       if (shouldRefreshCss) {
 | |
|         handleStyles(odfcontainer, formatting, stylesxmlcss);
 | |
|         shouldRefreshCss = false;
 | |
|       }
 | |
|       if (shouldRerenderAnnotations) {
 | |
|         if (annotationViewManager) {
 | |
|           annotationViewManager.rerenderAnnotations();
 | |
|         }
 | |
|         shouldRerenderAnnotations = false;
 | |
|       }
 | |
|       fixContainerSize();
 | |
|     }
 | |
|     function handleContent(container, odfnode) {
 | |
|       var css = (positioncss.sheet);
 | |
|       domUtils.removeAllChildNodes(element);
 | |
|       sizer = (doc.createElementNS(element.namespaceURI, "div"));
 | |
|       sizer.style.display = "inline-block";
 | |
|       sizer.style.background = "white";
 | |
|       sizer.style.setProperty("float", "left", "important");
 | |
|       sizer.appendChild(odfnode);
 | |
|       element.appendChild(sizer);
 | |
|       annotationsPane = (doc.createElementNS(element.namespaceURI, "div"));
 | |
|       annotationsPane.id = "annotationsPane";
 | |
|       shadowContent = doc.createElementNS(element.namespaceURI, "div");
 | |
|       shadowContent.id = "shadowContent";
 | |
|       shadowContent.style.position = "absolute";
 | |
|       shadowContent.style.top = 0;
 | |
|       shadowContent.style.left = 0;
 | |
|       container.getContentElement().appendChild(shadowContent);
 | |
|       modifyDrawElements(odfnode.body, css);
 | |
|       cloneMasterPages(formatting, container, shadowContent, odfnode.body, css);
 | |
|       modifyTables(odfnode.body, element.namespaceURI);
 | |
|       modifyLineBreakElements(odfnode.body);
 | |
|       expandSpaceElements(odfnode.body);
 | |
|       expandTabElements(odfnode.body);
 | |
|       loadImages(container, odfnode.body, css);
 | |
|       loadVideos(container, odfnode.body);
 | |
|       sizer.insertBefore(shadowContent, sizer.firstChild);
 | |
|       zoomHelper.setZoomableElement(sizer);
 | |
|     }
 | |
|     function handleAnnotations(odfnode) {
 | |
|       var annotationNodes;
 | |
|       if (allowAnnotations) {
 | |
|         if (!annotationsPane.parentNode) {
 | |
|           sizer.appendChild(annotationsPane);
 | |
|         }
 | |
|         if (annotationViewManager) {
 | |
|           annotationViewManager.forgetAnnotations();
 | |
|         }
 | |
|         annotationViewManager = new gui.AnnotationViewManager(self, odfnode.body, annotationsPane, showAnnotationRemoveButton);
 | |
|         annotationNodes = (domUtils.getElementsByTagNameNS(odfnode.body, officens, "annotation"));
 | |
|         annotationViewManager.addAnnotations(annotationNodes);
 | |
|         fixContainerSize();
 | |
|       } else {
 | |
|         if (annotationsPane.parentNode) {
 | |
|           sizer.removeChild(annotationsPane);
 | |
|           annotationViewManager.forgetAnnotations();
 | |
|           fixContainerSize();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function refreshOdf(suppressEvent) {
 | |
|       function callback() {
 | |
|         clearCSSStyleSheet(fontcss);
 | |
|         clearCSSStyleSheet(stylesxmlcss);
 | |
|         clearCSSStyleSheet(positioncss);
 | |
|         domUtils.removeAllChildNodes(element);
 | |
|         element.style.display = "inline-block";
 | |
|         var odfnode = odfcontainer.rootElement;
 | |
|         element.ownerDocument.importNode(odfnode, true);
 | |
|         formatting.setOdfContainer(odfcontainer);
 | |
|         handleFonts(odfcontainer, fontcss);
 | |
|         handleStyles(odfcontainer, formatting, stylesxmlcss);
 | |
|         handleContent(odfcontainer, odfnode);
 | |
|         handleAnnotations(odfnode);
 | |
|         if (!suppressEvent) {
 | |
|           loadingQueue.addToQueue(function() {
 | |
|             fireEvent("statereadychange", [odfcontainer]);
 | |
|           });
 | |
|         }
 | |
|       }
 | |
|       if (odfcontainer.state === odf.OdfContainer.DONE) {
 | |
|         callback();
 | |
|       } else {
 | |
|         runtime.log("WARNING: refreshOdf called but ODF was not DONE.");
 | |
|         waitingForDoneTimeoutId = runtime.setTimeout(function later_cb() {
 | |
|           if (odfcontainer.state === odf.OdfContainer.DONE) {
 | |
|             callback();
 | |
|           } else {
 | |
|             runtime.log("will be back later...");
 | |
|             waitingForDoneTimeoutId = runtime.setTimeout(later_cb, 500);
 | |
|           }
 | |
|         }, 100);
 | |
|       }
 | |
|     }
 | |
|     this.refreshCSS = function() {
 | |
|       shouldRefreshCss = true;
 | |
|       redrawContainerTask.trigger();
 | |
|     };
 | |
|     this.refreshSize = function() {
 | |
|       redrawContainerTask.trigger();
 | |
|     };
 | |
|     this.odfContainer = function() {
 | |
|       return odfcontainer;
 | |
|     };
 | |
|     this.setOdfContainer = function(container, suppressEvent) {
 | |
|       odfcontainer = container;
 | |
|       refreshOdf(suppressEvent === true);
 | |
|     };
 | |
|     function load(url) {
 | |
|       loadingQueue.clearQueue();
 | |
|       domUtils.removeAllChildNodes(element);
 | |
|       element.appendChild(element.ownerDocument.createTextNode(runtime.tr("Loading") + url + "..."));
 | |
|       element.removeAttribute("style");
 | |
|       odfcontainer = new odf.OdfContainer(url, function(container) {
 | |
|         odfcontainer = container;
 | |
|         refreshOdf(false);
 | |
|       });
 | |
|     }
 | |
|     this["load"] = load;
 | |
|     this.load = load;
 | |
|     this.save = function(callback) {
 | |
|       odfcontainer.save(callback);
 | |
|     };
 | |
|     this.addListener = function(eventName, handler) {
 | |
|       switch(eventName) {
 | |
|         case "click":
 | |
|           listenEvent(element, eventName, handler);
 | |
|           break;
 | |
|         default:
 | |
|           addEventListener(eventName, handler);
 | |
|           break;
 | |
|       }
 | |
|     };
 | |
|     this.getFormatting = function() {
 | |
|       return formatting;
 | |
|     };
 | |
|     this.getAnnotationViewManager = function() {
 | |
|       return annotationViewManager;
 | |
|     };
 | |
|     this.refreshAnnotations = function() {
 | |
|       handleAnnotations(odfcontainer.rootElement);
 | |
|     };
 | |
|     this.rerenderAnnotations = function() {
 | |
|       if (annotationViewManager) {
 | |
|         shouldRerenderAnnotations = true;
 | |
|         redrawContainerTask.trigger();
 | |
|       }
 | |
|     };
 | |
|     this.getSizer = function() {
 | |
|       return (sizer);
 | |
|     };
 | |
|     this.enableAnnotations = function(allow, showRemoveButton) {
 | |
|       if (allow !== allowAnnotations) {
 | |
|         allowAnnotations = allow;
 | |
|         showAnnotationRemoveButton = showRemoveButton;
 | |
|         if (odfcontainer) {
 | |
|           handleAnnotations(odfcontainer.rootElement);
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     this.addAnnotation = function(annotation) {
 | |
|       if (annotationViewManager) {
 | |
|         annotationViewManager.addAnnotations([annotation]);
 | |
|         fixContainerSize();
 | |
|       }
 | |
|     };
 | |
|     this.forgetAnnotation = function(annotation) {
 | |
|       if (annotationViewManager) {
 | |
|         annotationViewManager.forgetAnnotation(annotation);
 | |
|         fixContainerSize();
 | |
|       }
 | |
|     };
 | |
|     this.getZoomHelper = function() {
 | |
|       return zoomHelper;
 | |
|     };
 | |
|     this.setZoomLevel = function(zoom) {
 | |
|       zoomHelper.setZoomLevel(zoom);
 | |
|     };
 | |
|     this.getZoomLevel = function() {
 | |
|       return zoomHelper.getZoomLevel();
 | |
|     };
 | |
|     this.fitToContainingElement = function(width, height) {
 | |
|       var zoomLevel = zoomHelper.getZoomLevel(), realWidth = element.offsetWidth / zoomLevel, realHeight = element.offsetHeight / zoomLevel, zoom;
 | |
|       zoom = width / realWidth;
 | |
|       if (height / realHeight < zoom) {
 | |
|         zoom = height / realHeight;
 | |
|       }
 | |
|       zoomHelper.setZoomLevel(zoom);
 | |
|     };
 | |
|     this.fitToWidth = function(width) {
 | |
|       var realWidth = element.offsetWidth / zoomHelper.getZoomLevel();
 | |
|       zoomHelper.setZoomLevel(width / realWidth);
 | |
|     };
 | |
|     this.fitSmart = function(width, height) {
 | |
|       var realWidth, realHeight, newScale, zoomLevel = zoomHelper.getZoomLevel();
 | |
|       realWidth = element.offsetWidth / zoomLevel;
 | |
|       realHeight = element.offsetHeight / zoomLevel;
 | |
|       newScale = width / realWidth;
 | |
|       if (height !== undefined) {
 | |
|         if (height / realHeight < newScale) {
 | |
|           newScale = height / realHeight;
 | |
|         }
 | |
|       }
 | |
|       zoomHelper.setZoomLevel(Math.min(1, newScale));
 | |
|     };
 | |
|     this.fitToHeight = function(height) {
 | |
|       var realHeight = element.offsetHeight / zoomHelper.getZoomLevel();
 | |
|       zoomHelper.setZoomLevel(height / realHeight);
 | |
|     };
 | |
|     this.showFirstPage = function() {
 | |
|       pageSwitcher.showFirstPage();
 | |
|     };
 | |
|     this.showNextPage = function() {
 | |
|       pageSwitcher.showNextPage();
 | |
|     };
 | |
|     this.showPreviousPage = function() {
 | |
|       pageSwitcher.showPreviousPage();
 | |
|     };
 | |
|     this.showPage = function(n) {
 | |
|       pageSwitcher.showPage(n);
 | |
|       fixContainerSize();
 | |
|     };
 | |
|     this.getElement = function() {
 | |
|       return element;
 | |
|     };
 | |
|     this.getViewport = function() {
 | |
|       return canvasViewport;
 | |
|     };
 | |
|     this.addCssForFrameWithImage = function(frame) {
 | |
|       var frameName = frame.getAttributeNS(drawns, "name"), fc = frame.firstElementChild;
 | |
|       setDrawElementPosition(frameName, frame, (positioncss.sheet));
 | |
|       if (fc) {
 | |
|         setImage(frameName + "img", odfcontainer, fc, (positioncss.sheet));
 | |
|       }
 | |
|     };
 | |
|     this.destroy = function(callback) {
 | |
|       var head = (doc.getElementsByTagName("head")[0]), cleanup = [pageSwitcher.destroy, redrawContainerTask.destroy];
 | |
|       runtime.clearTimeout(waitingForDoneTimeoutId);
 | |
|       if (annotationsPane && annotationsPane.parentNode) {
 | |
|         annotationsPane.parentNode.removeChild(annotationsPane);
 | |
|       }
 | |
|       zoomHelper.destroy(function() {
 | |
|         if (sizer) {
 | |
|           element.removeChild(sizer);
 | |
|           sizer = null;
 | |
|         }
 | |
|       });
 | |
|       removeWebODFStyleSheet(webodfcss);
 | |
|       head.removeChild(fontcss);
 | |
|       head.removeChild(stylesxmlcss);
 | |
|       head.removeChild(positioncss);
 | |
|       core.Async.destroyAll(cleanup, callback);
 | |
|     };
 | |
|     function init() {
 | |
|       webodfcss = addWebODFStyleSheet(doc);
 | |
|       pageSwitcher = new PageSwitcher(addStyleSheet(doc));
 | |
|       fontcss = addStyleSheet(doc);
 | |
|       stylesxmlcss = addStyleSheet(doc);
 | |
|       positioncss = addStyleSheet(doc);
 | |
|       redrawContainerTask = core.Task.createRedrawTask(redrawContainer);
 | |
|       zoomHelper.subscribe(gui.ZoomHelper.signalZoomChanged, fixContainerSize);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
| })();
 | |
| odf.StepUtils = function StepUtils() {
 | |
|   function getContentBounds(stepIterator) {
 | |
|     var container = stepIterator.container(), offset, contentBounds;
 | |
|     runtime.assert(stepIterator.isStep(), "Step iterator must be on a step");
 | |
|     if (container.nodeType === Node.TEXT_NODE && stepIterator.offset() > 0) {
 | |
|       offset = stepIterator.offset();
 | |
|     } else {
 | |
|       container = stepIterator.leftNode();
 | |
|       if (container && container.nodeType === Node.TEXT_NODE) {
 | |
|         offset = (container).length;
 | |
|       }
 | |
|     }
 | |
|     if (container) {
 | |
|       if (container.nodeType === Node.TEXT_NODE) {
 | |
|         runtime.assert(offset > 0, "Empty text node found");
 | |
|         contentBounds = {container:container, startOffset:(offset) - 1, endOffset:(offset)};
 | |
|       } else {
 | |
|         contentBounds = {container:container, startOffset:0, endOffset:container.childNodes.length};
 | |
|       }
 | |
|     }
 | |
|     return contentBounds;
 | |
|   }
 | |
|   this.getContentBounds = getContentBounds;
 | |
| };
 | |
| ops.MemberProperties = function() {
 | |
|   this.fullName;
 | |
|   this.color;
 | |
|   this.imageUrl;
 | |
| };
 | |
| ops.Member = function Member(memberId, properties) {
 | |
|   var props = new ops.MemberProperties;
 | |
|   function getMemberId() {
 | |
|     return memberId;
 | |
|   }
 | |
|   function getProperties() {
 | |
|     return props;
 | |
|   }
 | |
|   function setProperties(newProperties) {
 | |
|     Object.keys(newProperties).forEach(function(key) {
 | |
|       props[key] = newProperties[key];
 | |
|     });
 | |
|   }
 | |
|   function removeProperties(removedProperties) {
 | |
|     Object.keys(removedProperties).forEach(function(key) {
 | |
|       if (key !== "fullName" && key !== "color" && key !== "imageUrl" && props.hasOwnProperty(key)) {
 | |
|         delete props[key];
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   this.getMemberId = getMemberId;
 | |
|   this.getProperties = getProperties;
 | |
|   this.setProperties = setProperties;
 | |
|   this.removeProperties = removeProperties;
 | |
|   function init() {
 | |
|     runtime.assert(Boolean(memberId), "No memberId was supplied!");
 | |
|     if (!properties.fullName) {
 | |
|       properties.fullName = runtime.tr("Unknown Author");
 | |
|     }
 | |
|     if (!properties.color) {
 | |
|       properties.color = "black";
 | |
|     }
 | |
|     if (!properties.imageUrl) {
 | |
|       properties.imageUrl = "avatar-joe.png";
 | |
|     }
 | |
|     props = properties;
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| ops.Document = function Document() {
 | |
| };
 | |
| ops.Document.prototype.getMemberIds = function() {
 | |
| };
 | |
| ops.Document.prototype.removeCursor = function(memberid) {
 | |
| };
 | |
| ops.Document.prototype.getDocumentElement = function() {
 | |
| };
 | |
| ops.Document.prototype.getRootNode = function() {
 | |
| };
 | |
| ops.Document.prototype.getDOMDocument = function() {
 | |
| };
 | |
| ops.Document.prototype.cloneDocumentElement = function() {
 | |
| };
 | |
| ops.Document.prototype.setDocumentElement = function(element) {
 | |
| };
 | |
| ops.Document.prototype.subscribe = function(eventid, cb) {
 | |
| };
 | |
| ops.Document.prototype.unsubscribe = function(eventid, cb) {
 | |
| };
 | |
| ops.Document.prototype.getCanvas = function() {
 | |
| };
 | |
| ops.Document.prototype.createRootFilter = function(inputMemberId) {
 | |
| };
 | |
| ops.Document.prototype.createPositionIterator = function(rootNode) {
 | |
| };
 | |
| ops.Document.signalCursorAdded = "cursor/added";
 | |
| ops.Document.signalCursorRemoved = "cursor/removed";
 | |
| ops.Document.signalCursorMoved = "cursor/moved";
 | |
| ops.Document.signalMemberAdded = "member/added";
 | |
| ops.Document.signalMemberUpdated = "member/updated";
 | |
| ops.Document.signalMemberRemoved = "member/removed";
 | |
| ops.OdtCursor = function OdtCursor(memberId, document) {
 | |
|   var self = this, validSelectionTypes = {}, selectionType, cursor, events = new core.EventNotifier([ops.OdtCursor.signalCursorUpdated]);
 | |
|   this.removeFromDocument = function() {
 | |
|     cursor.remove();
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     events.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     events.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   this.getMemberId = function() {
 | |
|     return memberId;
 | |
|   };
 | |
|   this.getNode = function() {
 | |
|     return cursor.getNode();
 | |
|   };
 | |
|   this.getAnchorNode = function() {
 | |
|     return cursor.getAnchorNode();
 | |
|   };
 | |
|   this.getSelectedRange = function() {
 | |
|     return cursor.getSelectedRange();
 | |
|   };
 | |
|   this.setSelectedRange = function(range, isForwardSelection) {
 | |
|     cursor.setSelectedRange(range, isForwardSelection);
 | |
|     events.emit(ops.OdtCursor.signalCursorUpdated, self);
 | |
|   };
 | |
|   this.hasForwardSelection = function() {
 | |
|     return cursor.hasForwardSelection();
 | |
|   };
 | |
|   this.getDocument = function() {
 | |
|     return document;
 | |
|   };
 | |
|   this.getSelectionType = function() {
 | |
|     return selectionType;
 | |
|   };
 | |
|   this.setSelectionType = function(value) {
 | |
|     if (validSelectionTypes.hasOwnProperty(value)) {
 | |
|       selectionType = value;
 | |
|     } else {
 | |
|       runtime.log("Invalid selection type: " + value);
 | |
|     }
 | |
|   };
 | |
|   this.resetSelectionType = function() {
 | |
|     self.setSelectionType(ops.OdtCursor.RangeSelection);
 | |
|   };
 | |
|   function init() {
 | |
|     cursor = new core.Cursor(document.getDOMDocument(), memberId);
 | |
|     validSelectionTypes[ops.OdtCursor.RangeSelection] = true;
 | |
|     validSelectionTypes[ops.OdtCursor.RegionSelection] = true;
 | |
|     self.resetSelectionType();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| ops.OdtCursor.RangeSelection = "Range";
 | |
| ops.OdtCursor.RegionSelection = "Region";
 | |
| ops.OdtCursor.signalCursorUpdated = "cursorUpdated";
 | |
| (function() {
 | |
|   var nextNodeId = 0;
 | |
|   ops.StepsCache = function StepsCache(rootElement, bucketSize, restoreBookmarkPosition) {
 | |
|     var coordinatens = "urn:webodf:names:steps", stepToDomPoint = {}, nodeToBookmark = {}, domUtils = core.DomUtils, basePoint, lastUndamagedCacheStep, DOCUMENT_POSITION_FOLLOWING = Node.DOCUMENT_POSITION_FOLLOWING, DOCUMENT_POSITION_PRECEDING = Node.DOCUMENT_POSITION_PRECEDING;
 | |
|     function NodeBookmark(nodeId, bookmarkNode) {
 | |
|       var self = this;
 | |
|       this.nodeId = nodeId;
 | |
|       this.steps = -1;
 | |
|       this.node = bookmarkNode;
 | |
|       this.nextBookmark = null;
 | |
|       this.previousBookmark = null;
 | |
|       this.setIteratorPosition = function(iterator) {
 | |
|         iterator.setPositionBeforeElement(bookmarkNode);
 | |
|         restoreBookmarkPosition(self.steps, iterator);
 | |
|       };
 | |
|     }
 | |
|     function RootBookmark(nodeId, steps, rootNode) {
 | |
|       var self = this;
 | |
|       this.nodeId = nodeId;
 | |
|       this.steps = steps;
 | |
|       this.node = rootNode;
 | |
|       this.nextBookmark = null;
 | |
|       this.previousBookmark = null;
 | |
|       this.setIteratorPosition = function(iterator) {
 | |
|         iterator.setUnfilteredPosition(rootNode, 0);
 | |
|         restoreBookmarkPosition(self.steps, iterator);
 | |
|       };
 | |
|     }
 | |
|     function inspectBookmarks(bookmark1, bookmark2) {
 | |
|       var parts = "[" + bookmark1.nodeId;
 | |
|       if (bookmark2) {
 | |
|         parts += " => " + bookmark2.nodeId;
 | |
|       }
 | |
|       return parts + "]";
 | |
|     }
 | |
|     function isUndamagedBookmark(bookmark) {
 | |
|       return lastUndamagedCacheStep === undefined || bookmark === basePoint || bookmark.steps <= lastUndamagedCacheStep;
 | |
|     }
 | |
|     function verifyCache() {
 | |
|       if (ops.StepsCache.ENABLE_CACHE_VERIFICATION !== true) {
 | |
|         return;
 | |
|       }
 | |
|       var bookmark = basePoint, previousBookmark, nextBookmark, documentPosition, loopCheck = new core.LoopWatchDog(0, 1E5), stepToDomPointNodeIds = {};
 | |
|       while (bookmark) {
 | |
|         loopCheck.check();
 | |
|         previousBookmark = bookmark.previousBookmark;
 | |
|         if (previousBookmark) {
 | |
|           runtime.assert(previousBookmark.nextBookmark === bookmark, "Broken bookmark link to previous @" + inspectBookmarks(previousBookmark, bookmark));
 | |
|         } else {
 | |
|           runtime.assert(bookmark === basePoint, "Broken bookmark link @" + inspectBookmarks(bookmark));
 | |
|           runtime.assert(isUndamagedBookmark(basePoint), "Base point is damaged @" + inspectBookmarks(bookmark));
 | |
|         }
 | |
|         nextBookmark = bookmark.nextBookmark;
 | |
|         if (nextBookmark) {
 | |
|           runtime.assert(nextBookmark.previousBookmark === bookmark, "Broken bookmark link to next @" + inspectBookmarks(bookmark, nextBookmark));
 | |
|         }
 | |
|         if (isUndamagedBookmark(bookmark)) {
 | |
|           runtime.assert(domUtils.containsNode(rootElement, bookmark.node), "Disconnected node is being reported as undamaged @" + inspectBookmarks(bookmark));
 | |
|           if (previousBookmark) {
 | |
|             documentPosition = bookmark.node.compareDocumentPosition(previousBookmark.node);
 | |
|             runtime.assert(documentPosition === 0 || (documentPosition & DOCUMENT_POSITION_PRECEDING) !== 0, "Bookmark order with previous does not reflect DOM order @" + inspectBookmarks(previousBookmark, bookmark));
 | |
|           }
 | |
|           if (nextBookmark) {
 | |
|             if (domUtils.containsNode(rootElement, nextBookmark.node)) {
 | |
|               documentPosition = bookmark.node.compareDocumentPosition(nextBookmark.node);
 | |
|               runtime.assert(documentPosition === 0 || (documentPosition & DOCUMENT_POSITION_FOLLOWING) !== 0, "Bookmark order with next does not reflect DOM order @" + inspectBookmarks(bookmark, nextBookmark));
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         bookmark = bookmark.nextBookmark;
 | |
|       }
 | |
|       Object.keys(stepToDomPoint).forEach(function(step) {
 | |
|         var domPointBookmark = stepToDomPoint[step];
 | |
|         if (lastUndamagedCacheStep === undefined || step <= lastUndamagedCacheStep) {
 | |
|           runtime.assert(domPointBookmark.steps <= step, "Bookmark step of " + domPointBookmark.steps + " exceeds cached step lookup for " + step + " @" + inspectBookmarks(domPointBookmark));
 | |
|         }
 | |
|         runtime.assert(stepToDomPointNodeIds.hasOwnProperty(domPointBookmark.nodeId) === false, "Bookmark " + inspectBookmarks(domPointBookmark) + " appears twice in cached step lookup at steps " + stepToDomPointNodeIds[domPointBookmark.nodeId] + " and " + step);
 | |
|         stepToDomPointNodeIds[domPointBookmark.nodeId] = step;
 | |
|       });
 | |
|     }
 | |
|     function getBucket(steps) {
 | |
|       return Math.floor(steps / bucketSize) * bucketSize;
 | |
|     }
 | |
|     function getDestinationBucket(steps) {
 | |
|       return Math.ceil(steps / bucketSize) * bucketSize;
 | |
|     }
 | |
|     function clearNodeId(node) {
 | |
|       node.removeAttributeNS(coordinatens, "nodeId");
 | |
|     }
 | |
|     function getNodeId(node) {
 | |
|       var id = "";
 | |
|       if (node.nodeType === Node.ELEMENT_NODE) {
 | |
|         id = (node).getAttributeNS(coordinatens, "nodeId") || "";
 | |
|       }
 | |
|       return id;
 | |
|     }
 | |
|     function setNodeId(node) {
 | |
|       var nodeId = nextNodeId.toString();
 | |
|       node.setAttributeNS(coordinatens, "nodeId", nodeId);
 | |
|       nextNodeId += 1;
 | |
|       return nodeId;
 | |
|     }
 | |
|     function isValidBookmarkForNode(node, bookmark) {
 | |
|       return bookmark.node === node;
 | |
|     }
 | |
|     function getNodeBookmark(node) {
 | |
|       var nodeId = getNodeId(node) || setNodeId(node), existingBookmark;
 | |
|       existingBookmark = nodeToBookmark[nodeId];
 | |
|       if (!existingBookmark) {
 | |
|         existingBookmark = nodeToBookmark[nodeId] = new NodeBookmark(nodeId, node);
 | |
|       } else {
 | |
|         if (!isValidBookmarkForNode(node, existingBookmark)) {
 | |
|           runtime.log("Cloned node detected. Creating new bookmark");
 | |
|           nodeId = setNodeId(node);
 | |
|           existingBookmark = nodeToBookmark[nodeId] = new NodeBookmark(nodeId, node);
 | |
|         }
 | |
|       }
 | |
|       return existingBookmark;
 | |
|     }
 | |
|     function getClosestBookmark(steps) {
 | |
|       var cacheBucket, cachePoint, loopGuard = new core.LoopWatchDog(0, 1E4);
 | |
|       if (lastUndamagedCacheStep !== undefined && steps > lastUndamagedCacheStep) {
 | |
|         steps = lastUndamagedCacheStep;
 | |
|       }
 | |
|       cacheBucket = getBucket(steps);
 | |
|       while (!cachePoint && cacheBucket >= 0) {
 | |
|         cachePoint = stepToDomPoint[cacheBucket];
 | |
|         cacheBucket -= bucketSize;
 | |
|       }
 | |
|       cachePoint = cachePoint || basePoint;
 | |
|       while (cachePoint.nextBookmark && cachePoint.nextBookmark.steps <= steps) {
 | |
|         loopGuard.check();
 | |
|         cachePoint = cachePoint.nextBookmark;
 | |
|       }
 | |
|       runtime.assert(steps === -1 || cachePoint.steps <= steps, "Bookmark @" + inspectBookmarks(cachePoint) + " at step " + cachePoint.steps + " exceeds requested step of " + steps);
 | |
|       return cachePoint;
 | |
|     }
 | |
|     function getUndamagedBookmark(bookmark) {
 | |
|       if (lastUndamagedCacheStep !== undefined && bookmark.steps > lastUndamagedCacheStep) {
 | |
|         bookmark = getClosestBookmark(lastUndamagedCacheStep);
 | |
|       }
 | |
|       return bookmark;
 | |
|     }
 | |
|     function removeBookmark(currentBookmark) {
 | |
|       if (currentBookmark.previousBookmark) {
 | |
|         currentBookmark.previousBookmark.nextBookmark = currentBookmark.nextBookmark;
 | |
|       }
 | |
|       if (currentBookmark.nextBookmark) {
 | |
|         currentBookmark.nextBookmark.previousBookmark = currentBookmark.previousBookmark;
 | |
|       }
 | |
|     }
 | |
|     function isAlreadyInOrder(previousBookmark, newBookmark) {
 | |
|       return previousBookmark === newBookmark || previousBookmark.nextBookmark === newBookmark;
 | |
|     }
 | |
|     function insertBookmark(previousBookmark, newBookmark) {
 | |
|       var nextBookmark;
 | |
|       if (!isAlreadyInOrder(previousBookmark, newBookmark)) {
 | |
|         if (previousBookmark.steps === newBookmark.steps) {
 | |
|           while ((newBookmark.node.compareDocumentPosition(previousBookmark.node) & DOCUMENT_POSITION_FOLLOWING) !== 0 && previousBookmark !== basePoint) {
 | |
|             previousBookmark = (previousBookmark.previousBookmark);
 | |
|           }
 | |
|         }
 | |
|         if (!isAlreadyInOrder(previousBookmark, newBookmark)) {
 | |
|           removeBookmark(newBookmark);
 | |
|           nextBookmark = previousBookmark.nextBookmark;
 | |
|           newBookmark.nextBookmark = previousBookmark.nextBookmark;
 | |
|           newBookmark.previousBookmark = previousBookmark;
 | |
|           previousBookmark.nextBookmark = newBookmark;
 | |
|           if (nextBookmark) {
 | |
|             nextBookmark.previousBookmark = newBookmark;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function repairCacheUpToStep(currentIteratorStep) {
 | |
|       var damagedBookmark, undamagedBookmark, nextBookmark, stepsBucket;
 | |
|       if (lastUndamagedCacheStep !== undefined && lastUndamagedCacheStep < currentIteratorStep) {
 | |
|         undamagedBookmark = getClosestBookmark(lastUndamagedCacheStep);
 | |
|         damagedBookmark = undamagedBookmark.nextBookmark;
 | |
|         while (damagedBookmark && damagedBookmark.steps <= currentIteratorStep) {
 | |
|           nextBookmark = damagedBookmark.nextBookmark;
 | |
|           stepsBucket = getDestinationBucket(damagedBookmark.steps);
 | |
|           if (stepToDomPoint[stepsBucket] === damagedBookmark) {
 | |
|             delete stepToDomPoint[stepsBucket];
 | |
|           }
 | |
|           if (!domUtils.containsNode(rootElement, damagedBookmark.node)) {
 | |
|             removeBookmark(damagedBookmark);
 | |
|             delete nodeToBookmark[damagedBookmark.nodeId];
 | |
|           } else {
 | |
|             damagedBookmark.steps = currentIteratorStep + 1;
 | |
|           }
 | |
|           damagedBookmark = nextBookmark;
 | |
|         }
 | |
|         lastUndamagedCacheStep = currentIteratorStep;
 | |
|       } else {
 | |
|         undamagedBookmark = getClosestBookmark(currentIteratorStep);
 | |
|       }
 | |
|       return undamagedBookmark;
 | |
|     }
 | |
|     this.updateBookmark = function(steps, node) {
 | |
|       var previousCacheBucket, newCacheBucket = getDestinationBucket(steps), existingCachePoint, bookmark, closestPriorBookmark;
 | |
|       closestPriorBookmark = repairCacheUpToStep(steps);
 | |
|       bookmark = getNodeBookmark((node));
 | |
|       if (bookmark.steps !== steps) {
 | |
|         previousCacheBucket = getDestinationBucket(bookmark.steps);
 | |
|         if (previousCacheBucket !== newCacheBucket && stepToDomPoint[previousCacheBucket] === bookmark) {
 | |
|           delete stepToDomPoint[previousCacheBucket];
 | |
|         }
 | |
|         bookmark.steps = steps;
 | |
|       }
 | |
|       insertBookmark(closestPriorBookmark, bookmark);
 | |
|       existingCachePoint = stepToDomPoint[newCacheBucket];
 | |
|       if (!existingCachePoint || bookmark.steps > existingCachePoint.steps) {
 | |
|         stepToDomPoint[newCacheBucket] = bookmark;
 | |
|       }
 | |
|       verifyCache();
 | |
|     };
 | |
|     this.setToClosestStep = function(steps, iterator) {
 | |
|       var cachePoint;
 | |
|       verifyCache();
 | |
|       cachePoint = getClosestBookmark(steps);
 | |
|       cachePoint.setIteratorPosition(iterator);
 | |
|       return cachePoint.steps;
 | |
|     };
 | |
|     function findBookmarkedAncestor(node) {
 | |
|       var currentNode = node, nodeId, bookmark = null;
 | |
|       while (!bookmark && currentNode && currentNode !== rootElement) {
 | |
|         nodeId = getNodeId(currentNode);
 | |
|         if (nodeId) {
 | |
|           bookmark = nodeToBookmark[nodeId];
 | |
|           if (bookmark && !isValidBookmarkForNode(currentNode, bookmark)) {
 | |
|             runtime.log("Cloned node detected. Creating new bookmark");
 | |
|             bookmark = null;
 | |
|             clearNodeId((currentNode));
 | |
|           }
 | |
|         }
 | |
|         currentNode = currentNode.parentNode;
 | |
|       }
 | |
|       return bookmark;
 | |
|     }
 | |
|     this.setToClosestDomPoint = function(node, offset, iterator) {
 | |
|       var bookmark, b, key;
 | |
|       verifyCache();
 | |
|       if (node === rootElement && offset === 0) {
 | |
|         bookmark = basePoint;
 | |
|       } else {
 | |
|         if (node === rootElement && offset === rootElement.childNodes.length) {
 | |
|           bookmark = basePoint;
 | |
|           for (key in stepToDomPoint) {
 | |
|             if (stepToDomPoint.hasOwnProperty(key)) {
 | |
|               b = stepToDomPoint[key];
 | |
|               if (b.steps > bookmark.steps) {
 | |
|                 bookmark = b;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         } else {
 | |
|           bookmark = findBookmarkedAncestor(node.childNodes.item(offset) || node);
 | |
|           if (!bookmark) {
 | |
|             iterator.setUnfilteredPosition(node, offset);
 | |
|             while (!bookmark && iterator.previousNode()) {
 | |
|               bookmark = findBookmarkedAncestor(iterator.getCurrentNode());
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       bookmark = getUndamagedBookmark(bookmark || basePoint);
 | |
|       bookmark.setIteratorPosition(iterator);
 | |
|       return bookmark.steps;
 | |
|     };
 | |
|     this.damageCacheAfterStep = function(inflectionStep) {
 | |
|       if (inflectionStep < 0) {
 | |
|         inflectionStep = -1;
 | |
|       }
 | |
|       if (lastUndamagedCacheStep === undefined) {
 | |
|         lastUndamagedCacheStep = inflectionStep;
 | |
|       } else {
 | |
|         if (inflectionStep < lastUndamagedCacheStep) {
 | |
|           lastUndamagedCacheStep = inflectionStep;
 | |
|         }
 | |
|       }
 | |
|       verifyCache();
 | |
|     };
 | |
|     function init() {
 | |
|       var rootElementId = getNodeId(rootElement) || setNodeId(rootElement);
 | |
|       basePoint = new RootBookmark(rootElementId, 0, rootElement);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
|   ops.StepsCache.ENABLE_CACHE_VERIFICATION = false;
 | |
|   ops.StepsCache.Bookmark = function Bookmark() {
 | |
|   };
 | |
|   ops.StepsCache.Bookmark.prototype.nodeId;
 | |
|   ops.StepsCache.Bookmark.prototype.node;
 | |
|   ops.StepsCache.Bookmark.prototype.steps;
 | |
|   ops.StepsCache.Bookmark.prototype.previousBookmark;
 | |
|   ops.StepsCache.Bookmark.prototype.nextBookmark;
 | |
|   ops.StepsCache.Bookmark.prototype.setIteratorPosition = function(iterator) {
 | |
|   };
 | |
| })();
 | |
| (function() {
 | |
|   ops.OdtStepsTranslator = function OdtStepsTranslator(rootNode, iterator, filter, bucketSize) {
 | |
|     var stepsCache, odfUtils = odf.OdfUtils, domUtils = core.DomUtils, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, PREVIOUS = core.StepDirection.PREVIOUS, NEXT = core.StepDirection.NEXT;
 | |
|     function updateCache(steps, iterator, isStep) {
 | |
|       var node = iterator.getCurrentNode();
 | |
|       if (iterator.isBeforeNode() && odfUtils.isParagraph(node)) {
 | |
|         if (!isStep) {
 | |
|           steps += 1;
 | |
|         }
 | |
|         stepsCache.updateBookmark(steps, node);
 | |
|       }
 | |
|     }
 | |
|     function roundUpToStep(steps, iterator) {
 | |
|       do {
 | |
|         if (filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 | |
|           updateCache(steps, iterator, true);
 | |
|           break;
 | |
|         }
 | |
|         updateCache(steps - 1, iterator, false);
 | |
|       } while (iterator.nextPosition());
 | |
|     }
 | |
|     this.convertStepsToDomPoint = function(steps) {
 | |
|       var stepsFromRoot, isStep;
 | |
|       if (isNaN(steps)) {
 | |
|         throw new TypeError("Requested steps is not numeric (" + steps + ")");
 | |
|       }
 | |
|       if (steps < 0) {
 | |
|         throw new RangeError("Requested steps is negative (" + steps + ")");
 | |
|       }
 | |
|       stepsFromRoot = stepsCache.setToClosestStep(steps, iterator);
 | |
|       while (stepsFromRoot < steps && iterator.nextPosition()) {
 | |
|         isStep = filter.acceptPosition(iterator) === FILTER_ACCEPT;
 | |
|         if (isStep) {
 | |
|           stepsFromRoot += 1;
 | |
|         }
 | |
|         updateCache(stepsFromRoot, iterator, isStep);
 | |
|       }
 | |
|       if (stepsFromRoot !== steps) {
 | |
|         throw new RangeError("Requested steps (" + steps + ") exceeds available steps (" + stepsFromRoot + ")");
 | |
|       }
 | |
|       return {node:iterator.container(), offset:iterator.unfilteredDomOffset()};
 | |
|     };
 | |
|     function roundToPreferredStep(iterator, roundDirection) {
 | |
|       if (!roundDirection || filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 | |
|         return true;
 | |
|       }
 | |
|       while (iterator.previousPosition()) {
 | |
|         if (filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 | |
|           if (roundDirection(PREVIOUS, iterator.container(), iterator.unfilteredDomOffset())) {
 | |
|             return true;
 | |
|           }
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       while (iterator.nextPosition()) {
 | |
|         if (filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 | |
|           if (roundDirection(NEXT, iterator.container(), iterator.unfilteredDomOffset())) {
 | |
|             return true;
 | |
|           }
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
|     this.convertDomPointToSteps = function(node, offset, roundDirection) {
 | |
|       var stepsFromRoot, beforeRoot, destinationNode, destinationOffset, rounding = 0, isStep;
 | |
|       if (!domUtils.containsNode(rootNode, node)) {
 | |
|         beforeRoot = domUtils.comparePoints(rootNode, 0, node, offset) < 0;
 | |
|         node = (rootNode);
 | |
|         offset = beforeRoot ? 0 : (rootNode).childNodes.length;
 | |
|       }
 | |
|       iterator.setUnfilteredPosition(node, offset);
 | |
|       if (!roundToPreferredStep(iterator, roundDirection)) {
 | |
|         iterator.setUnfilteredPosition(node, offset);
 | |
|       }
 | |
|       destinationNode = iterator.container();
 | |
|       destinationOffset = iterator.unfilteredDomOffset();
 | |
|       stepsFromRoot = stepsCache.setToClosestDomPoint(destinationNode, destinationOffset, iterator);
 | |
|       if (domUtils.comparePoints(iterator.container(), iterator.unfilteredDomOffset(), destinationNode, destinationOffset) < 0) {
 | |
|         return stepsFromRoot > 0 ? stepsFromRoot - 1 : stepsFromRoot;
 | |
|       }
 | |
|       while (!(iterator.container() === destinationNode && iterator.unfilteredDomOffset() === destinationOffset) && iterator.nextPosition()) {
 | |
|         isStep = filter.acceptPosition(iterator) === FILTER_ACCEPT;
 | |
|         if (isStep) {
 | |
|           stepsFromRoot += 1;
 | |
|         }
 | |
|         updateCache(stepsFromRoot, iterator, isStep);
 | |
|       }
 | |
|       return stepsFromRoot + rounding;
 | |
|     };
 | |
|     this.prime = function() {
 | |
|       var stepsFromRoot, isStep;
 | |
|       stepsFromRoot = stepsCache.setToClosestStep(0, iterator);
 | |
|       while (iterator.nextPosition()) {
 | |
|         isStep = filter.acceptPosition(iterator) === FILTER_ACCEPT;
 | |
|         if (isStep) {
 | |
|           stepsFromRoot += 1;
 | |
|         }
 | |
|         updateCache(stepsFromRoot, iterator, isStep);
 | |
|       }
 | |
|     };
 | |
|     this.handleStepsInserted = function(eventArgs) {
 | |
|       stepsCache.damageCacheAfterStep(eventArgs.position);
 | |
|     };
 | |
|     this.handleStepsRemoved = function(eventArgs) {
 | |
|       stepsCache.damageCacheAfterStep(eventArgs.position - 1);
 | |
|     };
 | |
|     function init() {
 | |
|       stepsCache = new ops.StepsCache(rootNode, bucketSize, roundUpToStep);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
| })();
 | |
| ops.Operation = function Operation() {
 | |
| };
 | |
| ops.Operation.prototype.init = function(data) {
 | |
| };
 | |
| ops.Operation.prototype.isEdit;
 | |
| ops.Operation.prototype.group;
 | |
| ops.Operation.prototype.execute = function(document) {
 | |
| };
 | |
| ops.Operation.prototype.spec = function() {
 | |
| };
 | |
| ops.TextPositionFilter = function TextPositionFilter() {
 | |
|   var odfUtils = odf.OdfUtils, ELEMENT_NODE = Node.ELEMENT_NODE, TEXT_NODE = Node.TEXT_NODE, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
 | |
|   function previousSibling(node, nodeFilter) {
 | |
|     while (node && nodeFilter(node) !== FILTER_ACCEPT) {
 | |
|       node = node.previousSibling;
 | |
|     }
 | |
|     return node;
 | |
|   }
 | |
|   function checkLeftRight(container, leftNode, rightNode, nodeFilter) {
 | |
|     var r, firstPos, rightOfChar;
 | |
|     if (leftNode) {
 | |
|       if (odfUtils.isInlineRoot(leftNode) && odfUtils.isGroupingElement(rightNode)) {
 | |
|         return FILTER_REJECT;
 | |
|       }
 | |
|       r = odfUtils.lookLeftForCharacter(leftNode);
 | |
|       if (r === 1) {
 | |
|         return FILTER_ACCEPT;
 | |
|       }
 | |
|       if (r === 2 && (odfUtils.scanRightForAnyCharacter(rightNode) || odfUtils.scanRightForAnyCharacter(odfUtils.nextNode(container)))) {
 | |
|         return FILTER_ACCEPT;
 | |
|       }
 | |
|     } else {
 | |
|       if (odfUtils.isGroupingElement(container) && odfUtils.isInlineRoot(previousSibling(container.previousSibling, nodeFilter))) {
 | |
|         return FILTER_ACCEPT;
 | |
|       }
 | |
|     }
 | |
|     firstPos = leftNode === null && odfUtils.isParagraph(container);
 | |
|     rightOfChar = odfUtils.lookRightForCharacter(rightNode);
 | |
|     if (firstPos) {
 | |
|       if (rightOfChar) {
 | |
|         return FILTER_ACCEPT;
 | |
|       }
 | |
|       return odfUtils.scanRightForAnyCharacter(rightNode) ? FILTER_REJECT : FILTER_ACCEPT;
 | |
|     }
 | |
|     if (!rightOfChar) {
 | |
|       return FILTER_REJECT;
 | |
|     }
 | |
|     leftNode = leftNode || odfUtils.previousNode(container);
 | |
|     return odfUtils.scanLeftForAnyCharacter(leftNode) ? FILTER_REJECT : FILTER_ACCEPT;
 | |
|   }
 | |
|   this.acceptPosition = function(iterator) {
 | |
|     var container = iterator.container(), nodeType = container.nodeType, offset, text, leftChar, rightChar, leftNode, rightNode, r;
 | |
|     if (nodeType !== ELEMENT_NODE && nodeType !== TEXT_NODE) {
 | |
|       return FILTER_REJECT;
 | |
|     }
 | |
|     if (nodeType === TEXT_NODE) {
 | |
|       offset = iterator.unfilteredDomOffset();
 | |
|       text = container.data;
 | |
|       runtime.assert(offset !== text.length, "Unexpected offset.");
 | |
|       if (offset > 0) {
 | |
|         leftChar = (text[offset - 1]);
 | |
|         if (!odfUtils.isODFWhitespace(leftChar)) {
 | |
|           return FILTER_ACCEPT;
 | |
|         }
 | |
|         if (offset > 1) {
 | |
|           leftChar = (text[offset - 2]);
 | |
|           if (!odfUtils.isODFWhitespace(leftChar)) {
 | |
|             r = FILTER_ACCEPT;
 | |
|           } else {
 | |
|             if (!odfUtils.isODFWhitespace(text.substr(0, offset))) {
 | |
|               return FILTER_REJECT;
 | |
|             }
 | |
|           }
 | |
|         } else {
 | |
|           leftNode = odfUtils.previousNode(container);
 | |
|           if (odfUtils.scanLeftForNonSpace(leftNode)) {
 | |
|             r = FILTER_ACCEPT;
 | |
|           }
 | |
|         }
 | |
|         if (r === FILTER_ACCEPT) {
 | |
|           return odfUtils.isTrailingWhitespace((container), offset) ? FILTER_REJECT : FILTER_ACCEPT;
 | |
|         }
 | |
|         rightChar = (text[offset]);
 | |
|         if (odfUtils.isODFWhitespace(rightChar)) {
 | |
|           return FILTER_REJECT;
 | |
|         }
 | |
|         return odfUtils.scanLeftForAnyCharacter(odfUtils.previousNode(container)) ? FILTER_REJECT : FILTER_ACCEPT;
 | |
|       }
 | |
|       leftNode = iterator.leftNode();
 | |
|       rightNode = container;
 | |
|       container = (container.parentNode);
 | |
|       r = checkLeftRight(container, leftNode, rightNode, iterator.getNodeFilter());
 | |
|     } else {
 | |
|       if (!odfUtils.isGroupingElement(container)) {
 | |
|         r = FILTER_REJECT;
 | |
|       } else {
 | |
|         leftNode = iterator.leftNode();
 | |
|         rightNode = iterator.rightNode();
 | |
|         r = checkLeftRight(container, leftNode, rightNode, iterator.getNodeFilter());
 | |
|       }
 | |
|     }
 | |
|     return r;
 | |
|   };
 | |
| };
 | |
| function RootFilter(anchor, cursors, getRoot) {
 | |
|   var FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
 | |
|   this.acceptPosition = function(iterator) {
 | |
|     var node = iterator.container(), anchorNode;
 | |
|     if (typeof anchor === "string") {
 | |
|       anchorNode = cursors[anchor].getNode();
 | |
|     } else {
 | |
|       anchorNode = anchor;
 | |
|     }
 | |
|     if (getRoot(node) === getRoot(anchorNode)) {
 | |
|       return FILTER_ACCEPT;
 | |
|     }
 | |
|     return FILTER_REJECT;
 | |
|   };
 | |
| }
 | |
| ops.OdtDocument = function OdtDocument(odfCanvas) {
 | |
|   var self = this, stepUtils, odfUtils = odf.OdfUtils, domUtils = core.DomUtils, cursors = {}, members = {}, eventNotifier = new core.EventNotifier([ops.Document.signalMemberAdded, ops.Document.signalMemberUpdated, ops.Document.signalMemberRemoved, ops.Document.signalCursorAdded, ops.Document.signalCursorRemoved, ops.Document.signalCursorMoved, ops.OdtDocument.signalParagraphChanged, ops.OdtDocument.signalParagraphStyleModified, ops.OdtDocument.signalCommonStyleCreated, ops.OdtDocument.signalCommonStyleDeleted, 
 | |
|   ops.OdtDocument.signalTableAdded, ops.OdtDocument.signalOperationStart, ops.OdtDocument.signalOperationEnd, ops.OdtDocument.signalProcessingBatchStart, ops.OdtDocument.signalProcessingBatchEnd, ops.OdtDocument.signalUndoStackChanged, ops.OdtDocument.signalStepsInserted, ops.OdtDocument.signalStepsRemoved, ops.OdtDocument.signalMetadataUpdated, ops.OdtDocument.signalAnnotationAdded]), NEXT = core.StepDirection.NEXT, filter, stepsTranslator, lastEditingOp, unsupportedMetadataRemoved = false, SHOW_ALL = 
 | |
|   NodeFilter.SHOW_ALL, blacklistedNodes = new gui.BlacklistNamespaceNodeFilter(["urn:webodf:names:cursor", "urn:webodf:names:editinfo"]), odfTextBodyFilter = new gui.OdfTextBodyNodeFilter, defaultNodeFilter = new core.NodeFilterChain([blacklistedNodes, odfTextBodyFilter]);
 | |
|   function createPositionIterator(rootNode) {
 | |
|     return new core.PositionIterator(rootNode, SHOW_ALL, defaultNodeFilter, false);
 | |
|   }
 | |
|   this.createPositionIterator = createPositionIterator;
 | |
|   function getRootNode() {
 | |
|     var element = odfCanvas.odfContainer().getContentElement(), localName = element && element.localName;
 | |
|     runtime.assert(localName === "text", "Unsupported content element type '" + localName + "' for OdtDocument");
 | |
|     return element;
 | |
|   }
 | |
|   this.getDocumentElement = function() {
 | |
|     return odfCanvas.odfContainer().rootElement;
 | |
|   };
 | |
|   this.cloneDocumentElement = function() {
 | |
|     var rootElement = self.getDocumentElement(), annotationViewManager = odfCanvas.getAnnotationViewManager(), initialDoc;
 | |
|     if (annotationViewManager) {
 | |
|       annotationViewManager.forgetAnnotations();
 | |
|     }
 | |
|     initialDoc = rootElement.cloneNode(true);
 | |
|     odfCanvas.refreshAnnotations();
 | |
|     self.fixCursorPositions();
 | |
|     return initialDoc;
 | |
|   };
 | |
|   this.setDocumentElement = function(documentElement) {
 | |
|     var odfContainer = odfCanvas.odfContainer(), rootNode;
 | |
|     eventNotifier.unsubscribe(ops.OdtDocument.signalStepsInserted, stepsTranslator.handleStepsInserted);
 | |
|     eventNotifier.unsubscribe(ops.OdtDocument.signalStepsRemoved, stepsTranslator.handleStepsRemoved);
 | |
|     odfContainer.setRootElement(documentElement);
 | |
|     odfCanvas.setOdfContainer(odfContainer, true);
 | |
|     odfCanvas.refreshCSS();
 | |
|     rootNode = getRootNode();
 | |
|     stepsTranslator = new ops.OdtStepsTranslator(rootNode, createPositionIterator(rootNode), filter, 500);
 | |
|     eventNotifier.subscribe(ops.OdtDocument.signalStepsInserted, stepsTranslator.handleStepsInserted);
 | |
|     eventNotifier.subscribe(ops.OdtDocument.signalStepsRemoved, stepsTranslator.handleStepsRemoved);
 | |
|   };
 | |
|   function getDOMDocument() {
 | |
|     return (self.getDocumentElement().ownerDocument);
 | |
|   }
 | |
|   this.getDOMDocument = getDOMDocument;
 | |
|   function isRoot(node) {
 | |
|     if (node.namespaceURI === odf.Namespaces.officens && node.localName === "text" || node.namespaceURI === odf.Namespaces.officens && node.localName === "annotation") {
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function getRoot(node) {
 | |
|     while (node && !isRoot(node)) {
 | |
|       node = (node.parentNode);
 | |
|     }
 | |
|     return node;
 | |
|   }
 | |
|   this.getRootElement = getRoot;
 | |
|   function createStepIterator(container, offset, filters, subTree) {
 | |
|     var positionIterator = createPositionIterator(subTree), filterOrChain, stepIterator;
 | |
|     if (filters.length === 1) {
 | |
|       filterOrChain = filters[0];
 | |
|     } else {
 | |
|       filterOrChain = new core.PositionFilterChain;
 | |
|       filters.forEach(filterOrChain.addFilter);
 | |
|     }
 | |
|     stepIterator = new core.StepIterator(filterOrChain, positionIterator);
 | |
|     stepIterator.setPosition(container, offset);
 | |
|     return stepIterator;
 | |
|   }
 | |
|   this.createStepIterator = createStepIterator;
 | |
|   function getIteratorAtPosition(position) {
 | |
|     var iterator = createPositionIterator(getRootNode()), point = stepsTranslator.convertStepsToDomPoint(position);
 | |
|     iterator.setUnfilteredPosition(point.node, point.offset);
 | |
|     return iterator;
 | |
|   }
 | |
|   this.getIteratorAtPosition = getIteratorAtPosition;
 | |
|   this.convertCursorStepToDomPoint = function(step) {
 | |
|     return stepsTranslator.convertStepsToDomPoint(step);
 | |
|   };
 | |
|   function roundUp(step) {
 | |
|     return step === NEXT;
 | |
|   }
 | |
|   this.convertDomPointToCursorStep = function(node, offset, roundDirection) {
 | |
|     var roundingFunc;
 | |
|     if (roundDirection === NEXT) {
 | |
|       roundingFunc = roundUp;
 | |
|     }
 | |
|     return stepsTranslator.convertDomPointToSteps(node, offset, roundingFunc);
 | |
|   };
 | |
|   this.convertDomToCursorRange = function(selection) {
 | |
|     var point1, point2;
 | |
|     point1 = stepsTranslator.convertDomPointToSteps(selection.anchorNode, selection.anchorOffset);
 | |
|     if (selection.anchorNode === selection.focusNode && selection.anchorOffset === selection.focusOffset) {
 | |
|       point2 = point1;
 | |
|     } else {
 | |
|       point2 = stepsTranslator.convertDomPointToSteps(selection.focusNode, selection.focusOffset);
 | |
|     }
 | |
|     return {position:point1, length:point2 - point1};
 | |
|   };
 | |
|   this.convertCursorToDomRange = function(position, length) {
 | |
|     var range = getDOMDocument().createRange(), point1, point2;
 | |
|     point1 = stepsTranslator.convertStepsToDomPoint(position);
 | |
|     if (length) {
 | |
|       point2 = stepsTranslator.convertStepsToDomPoint(position + length);
 | |
|       if (length > 0) {
 | |
|         range.setStart(point1.node, point1.offset);
 | |
|         range.setEnd(point2.node, point2.offset);
 | |
|       } else {
 | |
|         range.setStart(point2.node, point2.offset);
 | |
|         range.setEnd(point1.node, point1.offset);
 | |
|       }
 | |
|     } else {
 | |
|       range.setStart(point1.node, point1.offset);
 | |
|     }
 | |
|     return range;
 | |
|   };
 | |
|   function getTextNodeAtStep(steps, memberid) {
 | |
|     var iterator = getIteratorAtPosition(steps), node = iterator.container(), lastTextNode, nodeOffset = 0, cursorNode = null, text;
 | |
|     if (node.nodeType === Node.TEXT_NODE) {
 | |
|       lastTextNode = (node);
 | |
|       nodeOffset = (iterator.unfilteredDomOffset());
 | |
|       if (lastTextNode.length > 0) {
 | |
|         if (nodeOffset > 0) {
 | |
|           lastTextNode = lastTextNode.splitText(nodeOffset);
 | |
|         }
 | |
|         lastTextNode.parentNode.insertBefore(getDOMDocument().createTextNode(""), lastTextNode);
 | |
|         lastTextNode = (lastTextNode.previousSibling);
 | |
|         nodeOffset = 0;
 | |
|       }
 | |
|     } else {
 | |
|       lastTextNode = getDOMDocument().createTextNode("");
 | |
|       nodeOffset = 0;
 | |
|       node.insertBefore(lastTextNode, iterator.rightNode());
 | |
|     }
 | |
|     if (memberid) {
 | |
|       if (cursors[memberid] && self.getCursorPosition(memberid) === steps) {
 | |
|         cursorNode = cursors[memberid].getNode();
 | |
|         while (cursorNode.nextSibling && cursorNode.nextSibling.localName === "cursor") {
 | |
|           cursorNode.parentNode.insertBefore(cursorNode.nextSibling, cursorNode);
 | |
|         }
 | |
|         if (lastTextNode.length > 0 && lastTextNode.nextSibling !== cursorNode) {
 | |
|           lastTextNode = getDOMDocument().createTextNode("");
 | |
|           nodeOffset = 0;
 | |
|         }
 | |
|         cursorNode.parentNode.insertBefore(lastTextNode, cursorNode);
 | |
|       }
 | |
|     } else {
 | |
|       while (lastTextNode.nextSibling && lastTextNode.nextSibling.localName === "cursor") {
 | |
|         lastTextNode.parentNode.insertBefore(lastTextNode.nextSibling, lastTextNode);
 | |
|       }
 | |
|     }
 | |
|     while (lastTextNode.previousSibling && lastTextNode.previousSibling.nodeType === Node.TEXT_NODE) {
 | |
|       text = (lastTextNode.previousSibling);
 | |
|       text.appendData(lastTextNode.data);
 | |
|       nodeOffset = text.length;
 | |
|       lastTextNode = text;
 | |
|       lastTextNode.parentNode.removeChild(lastTextNode.nextSibling);
 | |
|     }
 | |
|     while (lastTextNode.nextSibling && lastTextNode.nextSibling.nodeType === Node.TEXT_NODE) {
 | |
|       text = (lastTextNode.nextSibling);
 | |
|       lastTextNode.appendData(text.data);
 | |
|       lastTextNode.parentNode.removeChild(text);
 | |
|     }
 | |
|     return {textNode:lastTextNode, offset:nodeOffset};
 | |
|   }
 | |
|   function handleOperationExecuted(op) {
 | |
|     var opspec = op.spec(), memberId = opspec.memberid, date = (new Date(opspec.timestamp)).toISOString(), odfContainer = odfCanvas.odfContainer(), changedMetadata, fullName;
 | |
|     if (op.isEdit) {
 | |
|       fullName = self.getMember(memberId).getProperties().fullName;
 | |
|       odfContainer.setMetadata({"dc:creator":fullName, "dc:date":date}, null);
 | |
|       changedMetadata = {setProperties:{"dc:creator":fullName, "dc:date":date}, removedProperties:[]};
 | |
|       if (!lastEditingOp) {
 | |
|         changedMetadata.setProperties["meta:editing-cycles"] = odfContainer.incrementEditingCycles();
 | |
|         if (!unsupportedMetadataRemoved) {
 | |
|           odfContainer.setMetadata(null, ["meta:editing-duration", "meta:document-statistic"]);
 | |
|         }
 | |
|       }
 | |
|       lastEditingOp = op;
 | |
|       self.emit(ops.OdtDocument.signalMetadataUpdated, changedMetadata);
 | |
|     }
 | |
|   }
 | |
|   function upgradeWhitespaceToElement(textNode, offset) {
 | |
|     runtime.assert(textNode.data[offset] === " ", "upgradeWhitespaceToElement: textNode.data[offset] should be a literal space");
 | |
|     var space = textNode.ownerDocument.createElementNS(odf.Namespaces.textns, "text:s"), container = textNode.parentNode, adjacentNode = textNode;
 | |
|     space.appendChild(textNode.ownerDocument.createTextNode(" "));
 | |
|     if (textNode.length === 1) {
 | |
|       container.replaceChild(space, textNode);
 | |
|     } else {
 | |
|       textNode.deleteData(offset, 1);
 | |
|       if (offset > 0) {
 | |
|         if (offset < textNode.length) {
 | |
|           textNode.splitText(offset);
 | |
|         }
 | |
|         adjacentNode = textNode.nextSibling;
 | |
|       }
 | |
|       container.insertBefore(space, adjacentNode);
 | |
|     }
 | |
|     return space;
 | |
|   }
 | |
|   function upgradeWhitespacesAtPosition(step) {
 | |
|     var positionIterator = getIteratorAtPosition(step), stepIterator = new core.StepIterator(filter, positionIterator), contentBounds, container, offset, stepsToUpgrade = 2;
 | |
|     runtime.assert(stepIterator.isStep(), "positionIterator is not at a step (requested step: " + step + ")");
 | |
|     do {
 | |
|       contentBounds = stepUtils.getContentBounds(stepIterator);
 | |
|       if (contentBounds) {
 | |
|         container = contentBounds.container;
 | |
|         offset = contentBounds.startOffset;
 | |
|         if (container.nodeType === Node.TEXT_NODE && odfUtils.isSignificantWhitespace((container), offset)) {
 | |
|           container = upgradeWhitespaceToElement((container), offset);
 | |
|           stepIterator.setPosition(container, container.childNodes.length);
 | |
|           stepIterator.roundToPreviousStep();
 | |
|         }
 | |
|       }
 | |
|       stepsToUpgrade -= 1;
 | |
|     } while (stepsToUpgrade > 0 && stepIterator.nextStep());
 | |
|   }
 | |
|   this.upgradeWhitespacesAtPosition = upgradeWhitespacesAtPosition;
 | |
|   function maxOffset(node) {
 | |
|     return node.nodeType === Node.TEXT_NODE ? (node).length : node.childNodes.length;
 | |
|   }
 | |
|   function downgradeWhitespaces(stepIterator) {
 | |
|     var contentBounds, container, modifiedNodes = [], lastChild, stepsToUpgrade = 2;
 | |
|     runtime.assert(stepIterator.isStep(), "positionIterator is not at a step");
 | |
|     do {
 | |
|       contentBounds = stepUtils.getContentBounds(stepIterator);
 | |
|       if (contentBounds) {
 | |
|         container = contentBounds.container;
 | |
|         if (odfUtils.isDowngradableSpaceElement(container)) {
 | |
|           lastChild = (container.lastChild);
 | |
|           while (container.firstChild) {
 | |
|             modifiedNodes.push(container.firstChild);
 | |
|             container.parentNode.insertBefore(container.firstChild, container);
 | |
|           }
 | |
|           container.parentNode.removeChild(container);
 | |
|           stepIterator.setPosition(lastChild, maxOffset(lastChild));
 | |
|           stepIterator.roundToPreviousStep();
 | |
|         }
 | |
|       }
 | |
|       stepsToUpgrade -= 1;
 | |
|     } while (stepsToUpgrade > 0 && stepIterator.nextStep());
 | |
|     modifiedNodes.forEach(domUtils.normalizeTextNodes);
 | |
|   }
 | |
|   this.downgradeWhitespaces = downgradeWhitespaces;
 | |
|   this.downgradeWhitespacesAtPosition = function(step) {
 | |
|     var positionIterator = getIteratorAtPosition(step), stepIterator = new core.StepIterator(filter, positionIterator);
 | |
|     downgradeWhitespaces(stepIterator);
 | |
|   };
 | |
|   this.getTextNodeAtStep = getTextNodeAtStep;
 | |
|   function paragraphOrRoot(container, offset, root) {
 | |
|     var node = container.childNodes.item(offset) || container, paragraph = odfUtils.getParagraphElement(node);
 | |
|     if (paragraph && domUtils.containsNode(root, paragraph)) {
 | |
|       return (paragraph);
 | |
|     }
 | |
|     return root;
 | |
|   }
 | |
|   this.fixCursorPositions = function() {
 | |
|     Object.keys(cursors).forEach(function(memberId) {
 | |
|       var cursor = cursors[memberId], root = getRoot(cursor.getNode()), rootFilter = self.createRootFilter(root), subTree, startPoint, endPoint, selectedRange, cursorMoved = false;
 | |
|       selectedRange = cursor.getSelectedRange();
 | |
|       subTree = paragraphOrRoot((selectedRange.startContainer), selectedRange.startOffset, root);
 | |
|       startPoint = createStepIterator((selectedRange.startContainer), selectedRange.startOffset, [filter, rootFilter], subTree);
 | |
|       if (!selectedRange.collapsed) {
 | |
|         subTree = paragraphOrRoot((selectedRange.endContainer), selectedRange.endOffset, root);
 | |
|         endPoint = createStepIterator((selectedRange.endContainer), selectedRange.endOffset, [filter, rootFilter], subTree);
 | |
|       } else {
 | |
|         endPoint = startPoint;
 | |
|       }
 | |
|       if (!startPoint.isStep() || !endPoint.isStep()) {
 | |
|         cursorMoved = true;
 | |
|         runtime.assert(startPoint.roundToClosestStep(), "No walkable step found for cursor owned by " + memberId);
 | |
|         selectedRange.setStart(startPoint.container(), startPoint.offset());
 | |
|         runtime.assert(endPoint.roundToClosestStep(), "No walkable step found for cursor owned by " + memberId);
 | |
|         selectedRange.setEnd(endPoint.container(), endPoint.offset());
 | |
|       } else {
 | |
|         if (startPoint.container() === endPoint.container() && startPoint.offset() === endPoint.offset()) {
 | |
|           if (!selectedRange.collapsed || cursor.getAnchorNode() !== cursor.getNode()) {
 | |
|             cursorMoved = true;
 | |
|             selectedRange.setStart(startPoint.container(), startPoint.offset());
 | |
|             selectedRange.collapse(true);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (cursorMoved) {
 | |
|         cursor.setSelectedRange(selectedRange, cursor.hasForwardSelection());
 | |
|         self.emit(ops.Document.signalCursorMoved, cursor);
 | |
|       }
 | |
|     });
 | |
|   };
 | |
|   this.getCursorPosition = function(memberid) {
 | |
|     var cursor = cursors[memberid];
 | |
|     return cursor ? stepsTranslator.convertDomPointToSteps(cursor.getNode(), 0) : 0;
 | |
|   };
 | |
|   this.getCursorSelection = function(memberid) {
 | |
|     var cursor = cursors[memberid], focusPosition = 0, anchorPosition = 0;
 | |
|     if (cursor) {
 | |
|       focusPosition = stepsTranslator.convertDomPointToSteps(cursor.getNode(), 0);
 | |
|       anchorPosition = stepsTranslator.convertDomPointToSteps(cursor.getAnchorNode(), 0);
 | |
|     }
 | |
|     return {position:anchorPosition, length:focusPosition - anchorPosition};
 | |
|   };
 | |
|   this.getPositionFilter = function() {
 | |
|     return filter;
 | |
|   };
 | |
|   this.getOdfCanvas = function() {
 | |
|     return odfCanvas;
 | |
|   };
 | |
|   this.getCanvas = function() {
 | |
|     return odfCanvas;
 | |
|   };
 | |
|   this.getRootNode = getRootNode;
 | |
|   this.addMember = function(member) {
 | |
|     runtime.assert(members[member.getMemberId()] === undefined, "This member already exists");
 | |
|     members[member.getMemberId()] = member;
 | |
|   };
 | |
|   this.getMember = function(memberId) {
 | |
|     return members.hasOwnProperty(memberId) ? members[memberId] : null;
 | |
|   };
 | |
|   this.removeMember = function(memberId) {
 | |
|     delete members[memberId];
 | |
|   };
 | |
|   this.getCursor = function(memberid) {
 | |
|     return cursors[memberid];
 | |
|   };
 | |
|   this.getMemberIds = function() {
 | |
|     var list = [], i;
 | |
|     for (i in cursors) {
 | |
|       if (cursors.hasOwnProperty(i)) {
 | |
|         list.push(cursors[i].getMemberId());
 | |
|       }
 | |
|     }
 | |
|     return list;
 | |
|   };
 | |
|   this.addCursor = function(cursor) {
 | |
|     runtime.assert(Boolean(cursor), "OdtDocument::addCursor without cursor");
 | |
|     var memberid = cursor.getMemberId(), initialSelection = self.convertCursorToDomRange(0, 0);
 | |
|     runtime.assert(typeof memberid === "string", "OdtDocument::addCursor has cursor without memberid");
 | |
|     runtime.assert(!cursors[memberid], "OdtDocument::addCursor is adding a duplicate cursor with memberid " + memberid);
 | |
|     cursor.setSelectedRange(initialSelection, true);
 | |
|     cursors[memberid] = cursor;
 | |
|   };
 | |
|   this.removeCursor = function(memberid) {
 | |
|     var cursor = cursors[memberid];
 | |
|     if (cursor) {
 | |
|       cursor.removeFromDocument();
 | |
|       delete cursors[memberid];
 | |
|       self.emit(ops.Document.signalCursorRemoved, memberid);
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
|   this.moveCursor = function(memberid, position, length, selectionType) {
 | |
|     var cursor = cursors[memberid], selectionRange = self.convertCursorToDomRange(position, length);
 | |
|     if (cursor) {
 | |
|       cursor.setSelectedRange(selectionRange, length >= 0);
 | |
|       cursor.setSelectionType(selectionType || ops.OdtCursor.RangeSelection);
 | |
|     }
 | |
|   };
 | |
|   this.getFormatting = function() {
 | |
|     return odfCanvas.getFormatting();
 | |
|   };
 | |
|   this.emit = function(eventid, args) {
 | |
|     eventNotifier.emit(eventid, args);
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     eventNotifier.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     eventNotifier.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   this.createRootFilter = function(inputMemberId) {
 | |
|     return new RootFilter(inputMemberId, cursors, getRoot);
 | |
|   };
 | |
|   this.close = function(callback) {
 | |
|     callback();
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     var rootNode = getRootNode();
 | |
|     filter = new ops.TextPositionFilter;
 | |
|     stepUtils = new odf.StepUtils;
 | |
|     stepsTranslator = new ops.OdtStepsTranslator(rootNode, createPositionIterator(rootNode), filter, 500);
 | |
|     eventNotifier.subscribe(ops.OdtDocument.signalStepsInserted, stepsTranslator.handleStepsInserted);
 | |
|     eventNotifier.subscribe(ops.OdtDocument.signalStepsRemoved, stepsTranslator.handleStepsRemoved);
 | |
|     eventNotifier.subscribe(ops.OdtDocument.signalOperationEnd, handleOperationExecuted);
 | |
|     eventNotifier.subscribe(ops.OdtDocument.signalProcessingBatchEnd, core.Task.processTasks);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| ops.OdtDocument.signalParagraphChanged = "paragraph/changed";
 | |
| ops.OdtDocument.signalTableAdded = "table/added";
 | |
| ops.OdtDocument.signalCommonStyleCreated = "style/created";
 | |
| ops.OdtDocument.signalCommonStyleDeleted = "style/deleted";
 | |
| ops.OdtDocument.signalParagraphStyleModified = "paragraphstyle/modified";
 | |
| ops.OdtDocument.signalOperationStart = "operation/start";
 | |
| ops.OdtDocument.signalOperationEnd = "operation/end";
 | |
| ops.OdtDocument.signalProcessingBatchStart = "router/batchstart";
 | |
| ops.OdtDocument.signalProcessingBatchEnd = "router/batchend";
 | |
| ops.OdtDocument.signalUndoStackChanged = "undo/changed";
 | |
| ops.OdtDocument.signalStepsInserted = "steps/inserted";
 | |
| ops.OdtDocument.signalStepsRemoved = "steps/removed";
 | |
| ops.OdtDocument.signalMetadataUpdated = "metadata/updated";
 | |
| ops.OdtDocument.signalAnnotationAdded = "annotation/added";
 | |
| ops.OpAddAnnotation = function OpAddAnnotation() {
 | |
|   var memberid, timestamp, position, length, name, doc;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = parseInt(data.timestamp, 10);
 | |
|     position = parseInt(data.position, 10);
 | |
|     length = data.length !== undefined ? parseInt(data.length, 10) || 0 : undefined;
 | |
|     name = data.name;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function createAnnotationNode(odtDocument, date) {
 | |
|     var annotationNode, creatorNode, dateNode, listNode, listItemNode, paragraphNode;
 | |
|     annotationNode = (doc.createElementNS(odf.Namespaces.officens, "office:annotation"));
 | |
|     annotationNode.setAttributeNS(odf.Namespaces.officens, "office:name", name);
 | |
|     creatorNode = doc.createElementNS(odf.Namespaces.dcns, "dc:creator");
 | |
|     creatorNode.setAttributeNS("urn:webodf:names:editinfo", "editinfo:memberid", memberid);
 | |
|     creatorNode.textContent = odtDocument.getMember(memberid).getProperties().fullName;
 | |
|     dateNode = doc.createElementNS(odf.Namespaces.dcns, "dc:date");
 | |
|     dateNode.appendChild(doc.createTextNode(date.toISOString()));
 | |
|     listNode = doc.createElementNS(odf.Namespaces.textns, "text:list");
 | |
|     listItemNode = doc.createElementNS(odf.Namespaces.textns, "text:list-item");
 | |
|     paragraphNode = doc.createElementNS(odf.Namespaces.textns, "text:p");
 | |
|     listItemNode.appendChild(paragraphNode);
 | |
|     listNode.appendChild(listItemNode);
 | |
|     annotationNode.appendChild(creatorNode);
 | |
|     annotationNode.appendChild(dateNode);
 | |
|     annotationNode.appendChild(listNode);
 | |
|     return annotationNode;
 | |
|   }
 | |
|   function createAnnotationEnd() {
 | |
|     var annotationEnd;
 | |
|     annotationEnd = doc.createElementNS(odf.Namespaces.officens, "office:annotation-end");
 | |
|     annotationEnd.setAttributeNS(odf.Namespaces.officens, "office:name", name);
 | |
|     return annotationEnd;
 | |
|   }
 | |
|   function insertNodeAtPosition(odtDocument, node, insertPosition) {
 | |
|     var previousNode, parentNode, domPosition = odtDocument.getTextNodeAtStep(insertPosition, memberid);
 | |
|     if (domPosition) {
 | |
|       previousNode = domPosition.textNode;
 | |
|       parentNode = previousNode.parentNode;
 | |
|       if (domPosition.offset !== previousNode.length) {
 | |
|         previousNode.splitText(domPosition.offset);
 | |
|       }
 | |
|       parentNode.insertBefore(node, previousNode.nextSibling);
 | |
|       if (previousNode.length === 0) {
 | |
|         parentNode.removeChild(previousNode);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), annotation, annotationEnd, cursor = odtDocument.getCursor(memberid), selectedRange, paragraphElement;
 | |
|     doc = odtDocument.getDOMDocument();
 | |
|     annotation = createAnnotationNode(odtDocument, new Date(timestamp));
 | |
|     if (length !== undefined) {
 | |
|       annotationEnd = createAnnotationEnd();
 | |
|       annotation.annotationEndElement = annotationEnd;
 | |
|       insertNodeAtPosition(odtDocument, annotationEnd, position + length);
 | |
|     }
 | |
|     insertNodeAtPosition(odtDocument, annotation, position);
 | |
|     odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position});
 | |
|     if (cursor) {
 | |
|       selectedRange = doc.createRange();
 | |
|       paragraphElement = (annotation.getElementsByTagNameNS(odf.Namespaces.textns, "p")[0]);
 | |
|       selectedRange.selectNodeContents(paragraphElement);
 | |
|       cursor.setSelectedRange(selectedRange, false);
 | |
|       cursor.setSelectionType(ops.OdtCursor.RangeSelection);
 | |
|       odtDocument.emit(ops.Document.signalCursorMoved, cursor);
 | |
|     }
 | |
|     odtDocument.getOdfCanvas().addAnnotation(annotation);
 | |
|     odtDocument.fixCursorPositions();
 | |
|     odtDocument.emit(ops.OdtDocument.signalAnnotationAdded, {memberId:memberid, annotation:annotation});
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"AddAnnotation", memberid:memberid, timestamp:timestamp, position:position, length:length, name:name};
 | |
|   };
 | |
| };
 | |
| ops.OpAddAnnotation.Spec;
 | |
| ops.OpAddAnnotation.InitSpec;
 | |
| ops.OpAddCursor = function OpAddCursor() {
 | |
|   var memberid, timestamp;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|   };
 | |
|   this.isEdit = false;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), cursor = odtDocument.getCursor(memberid);
 | |
|     if (cursor) {
 | |
|       return false;
 | |
|     }
 | |
|     cursor = new ops.OdtCursor(memberid, odtDocument);
 | |
|     odtDocument.addCursor(cursor);
 | |
|     odtDocument.emit(ops.Document.signalCursorAdded, cursor);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"AddCursor", memberid:memberid, timestamp:timestamp};
 | |
|   };
 | |
| };
 | |
| ops.OpAddCursor.Spec;
 | |
| ops.OpAddCursor.InitSpec;
 | |
| ops.OpAddMember = function OpAddMember() {
 | |
|   var memberid, timestamp, setProperties;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = parseInt(data.timestamp, 10);
 | |
|     setProperties = data.setProperties;
 | |
|   };
 | |
|   this.isEdit = false;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), member;
 | |
|     if (odtDocument.getMember(memberid)) {
 | |
|       return false;
 | |
|     }
 | |
|     member = new ops.Member(memberid, setProperties);
 | |
|     odtDocument.addMember(member);
 | |
|     odtDocument.emit(ops.Document.signalMemberAdded, member);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"AddMember", memberid:memberid, timestamp:timestamp, setProperties:setProperties};
 | |
|   };
 | |
| };
 | |
| ops.OpAddMember.Spec;
 | |
| ops.OpAddMember.InitSpec;
 | |
| ops.OpAddStyle = function OpAddStyle() {
 | |
|   var memberid, timestamp, styleName, styleFamily, isAutomaticStyle, setProperties, stylens = odf.Namespaces.stylens;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     styleName = data.styleName;
 | |
|     styleFamily = data.styleFamily;
 | |
|     isAutomaticStyle = data.isAutomaticStyle === "true" || data.isAutomaticStyle === true;
 | |
|     setProperties = data.setProperties;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), odfContainer = odtDocument.getOdfCanvas().odfContainer(), formatting = odtDocument.getFormatting(), dom = odtDocument.getDOMDocument(), styleNode = dom.createElementNS(stylens, "style:style");
 | |
|     if (!styleNode) {
 | |
|       return false;
 | |
|     }
 | |
|     if (setProperties) {
 | |
|       formatting.updateStyle(styleNode, setProperties);
 | |
|     }
 | |
|     styleNode.setAttributeNS(stylens, "style:family", styleFamily);
 | |
|     styleNode.setAttributeNS(stylens, "style:name", styleName);
 | |
|     if (isAutomaticStyle) {
 | |
|       odfContainer.rootElement.automaticStyles.appendChild(styleNode);
 | |
|     } else {
 | |
|       odfContainer.rootElement.styles.appendChild(styleNode);
 | |
|     }
 | |
|     odtDocument.getOdfCanvas().refreshCSS();
 | |
|     if (!isAutomaticStyle) {
 | |
|       odtDocument.emit(ops.OdtDocument.signalCommonStyleCreated, {name:styleName, family:styleFamily});
 | |
|     }
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"AddStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, styleFamily:styleFamily, isAutomaticStyle:isAutomaticStyle, setProperties:setProperties};
 | |
|   };
 | |
| };
 | |
| ops.OpAddStyle.Spec;
 | |
| ops.OpAddStyle.InitSpec;
 | |
| odf.ObjectNameGenerator = function ObjectNameGenerator(odfContainer, memberId) {
 | |
|   var stylens = odf.Namespaces.stylens, drawns = odf.Namespaces.drawns, xlinkns = odf.Namespaces.xlinkns, utils = new core.Utils, memberIdHash = utils.hashString(memberId), styleNameGenerator = null, frameNameGenerator = null, imageNameGenerator = null, existingFrameNames = {}, existingImageNames = {};
 | |
|   function NameGenerator(prefix, findExistingNames) {
 | |
|     var reportedNames = {};
 | |
|     this.generateName = function() {
 | |
|       var existingNames = findExistingNames(), startIndex = 0, name;
 | |
|       do {
 | |
|         name = prefix + startIndex;
 | |
|         startIndex += 1;
 | |
|       } while (reportedNames[name] || existingNames[name]);
 | |
|       reportedNames[name] = true;
 | |
|       return name;
 | |
|     };
 | |
|   }
 | |
|   function getAllStyleNames() {
 | |
|     var styleElements = [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles], styleNames = {};
 | |
|     function getStyleNames(styleListElement) {
 | |
|       var e = styleListElement.firstElementChild;
 | |
|       while (e) {
 | |
|         if (e.namespaceURI === stylens && e.localName === "style") {
 | |
|           styleNames[e.getAttributeNS(stylens, "name")] = true;
 | |
|         }
 | |
|         e = e.nextElementSibling;
 | |
|       }
 | |
|     }
 | |
|     styleElements.forEach(getStyleNames);
 | |
|     return styleNames;
 | |
|   }
 | |
|   this.generateStyleName = function() {
 | |
|     if (styleNameGenerator === null) {
 | |
|       styleNameGenerator = new NameGenerator("auto" + memberIdHash + "_", function() {
 | |
|         return getAllStyleNames();
 | |
|       });
 | |
|     }
 | |
|     return styleNameGenerator.generateName();
 | |
|   };
 | |
|   this.generateFrameName = function() {
 | |
|     var i, nodes, node;
 | |
|     if (frameNameGenerator === null) {
 | |
|       nodes = odfContainer.rootElement.body.getElementsByTagNameNS(drawns, "frame");
 | |
|       for (i = 0;i < nodes.length;i += 1) {
 | |
|         node = (nodes.item(i));
 | |
|         existingFrameNames[node.getAttributeNS(drawns, "name")] = true;
 | |
|       }
 | |
|       frameNameGenerator = new NameGenerator("fr" + memberIdHash + "_", function() {
 | |
|         return existingFrameNames;
 | |
|       });
 | |
|     }
 | |
|     return frameNameGenerator.generateName();
 | |
|   };
 | |
|   this.generateImageName = function() {
 | |
|     var i, path, nodes, node;
 | |
|     if (imageNameGenerator === null) {
 | |
|       nodes = odfContainer.rootElement.body.getElementsByTagNameNS(drawns, "image");
 | |
|       for (i = 0;i < nodes.length;i += 1) {
 | |
|         node = (nodes.item(i));
 | |
|         path = node.getAttributeNS(xlinkns, "href");
 | |
|         path = path.substring("Pictures/".length, path.lastIndexOf("."));
 | |
|         existingImageNames[path] = true;
 | |
|       }
 | |
|       imageNameGenerator = new NameGenerator("img" + memberIdHash + "_", function() {
 | |
|         return existingImageNames;
 | |
|       });
 | |
|     }
 | |
|     return imageNameGenerator.generateName();
 | |
|   };
 | |
| };
 | |
| odf.TextStyleApplicator = function TextStyleApplicator(objectNameGenerator, formatting, automaticStyles) {
 | |
|   var domUtils = core.DomUtils, textns = odf.Namespaces.textns, stylens = odf.Namespaces.stylens, textProperties = "style:text-properties", webodfns = "urn:webodf:names:scope";
 | |
|   function StyleLookup(info) {
 | |
|     var cachedAppliedStyles = {};
 | |
|     function compare(expected, actual) {
 | |
|       if (typeof expected === "object" && typeof actual === "object") {
 | |
|         return Object.keys(expected).every(function(key) {
 | |
|           return compare(expected[key], actual[key]);
 | |
|         });
 | |
|       }
 | |
|       return expected === actual;
 | |
|     }
 | |
|     this.isStyleApplied = function(textNode) {
 | |
|       var appliedStyle = formatting.getAppliedStylesForElement(textNode, cachedAppliedStyles).styleProperties;
 | |
|       return compare(info, appliedStyle);
 | |
|     };
 | |
|   }
 | |
|   function StyleManager(info) {
 | |
|     var createdStyles = {};
 | |
|     function createDirectFormat(existingStyleName, document) {
 | |
|       var derivedStyleInfo, derivedStyleNode;
 | |
|       derivedStyleInfo = existingStyleName ? formatting.createDerivedStyleObject(existingStyleName, "text", info) : info;
 | |
|       derivedStyleNode = document.createElementNS(stylens, "style:style");
 | |
|       formatting.updateStyle(derivedStyleNode, derivedStyleInfo);
 | |
|       derivedStyleNode.setAttributeNS(stylens, "style:name", objectNameGenerator.generateStyleName());
 | |
|       derivedStyleNode.setAttributeNS(stylens, "style:family", "text");
 | |
|       derivedStyleNode.setAttributeNS(webodfns, "scope", "document-content");
 | |
|       automaticStyles.appendChild(derivedStyleNode);
 | |
|       return derivedStyleNode;
 | |
|     }
 | |
|     function getDirectStyle(existingStyleName, document) {
 | |
|       existingStyleName = existingStyleName || "";
 | |
|       if (!createdStyles.hasOwnProperty(existingStyleName)) {
 | |
|         createdStyles[existingStyleName] = createDirectFormat(existingStyleName, document);
 | |
|       }
 | |
|       return createdStyles[existingStyleName].getAttributeNS(stylens, "name");
 | |
|     }
 | |
|     this.applyStyleToContainer = function(container) {
 | |
|       var name = getDirectStyle(container.getAttributeNS(textns, "style-name"), container.ownerDocument);
 | |
|       container.setAttributeNS(textns, "text:style-name", name);
 | |
|     };
 | |
|   }
 | |
|   function isTextSpan(node) {
 | |
|     return node.localName === "span" && node.namespaceURI === textns;
 | |
|   }
 | |
|   function moveToNewSpan(startNode, range) {
 | |
|     var document = startNode.ownerDocument, originalContainer = (startNode.parentNode), styledContainer, trailingContainer, moveTrailing, node, nextNode, loopGuard = new core.LoopWatchDog(1E4), styledNodes = [];
 | |
|     styledNodes.push(startNode);
 | |
|     node = startNode.nextSibling;
 | |
|     while (node && domUtils.rangeContainsNode(range, node)) {
 | |
|       loopGuard.check();
 | |
|       styledNodes.push(node);
 | |
|       node = node.nextSibling;
 | |
|     }
 | |
|     if (!isTextSpan(originalContainer)) {
 | |
|       styledContainer = document.createElementNS(textns, "text:span");
 | |
|       originalContainer.insertBefore(styledContainer, startNode);
 | |
|       moveTrailing = false;
 | |
|     } else {
 | |
|       if (startNode.previousSibling && !domUtils.rangeContainsNode(range, (originalContainer.firstChild))) {
 | |
|         styledContainer = originalContainer.cloneNode(false);
 | |
|         originalContainer.parentNode.insertBefore(styledContainer, originalContainer.nextSibling);
 | |
|         moveTrailing = true;
 | |
|       } else {
 | |
|         styledContainer = originalContainer;
 | |
|         moveTrailing = true;
 | |
|       }
 | |
|     }
 | |
|     styledNodes.forEach(function(n) {
 | |
|       if (n.parentNode !== styledContainer) {
 | |
|         styledContainer.appendChild(n);
 | |
|       }
 | |
|     });
 | |
|     if (node && moveTrailing) {
 | |
|       trailingContainer = styledContainer.cloneNode(false);
 | |
|       styledContainer.parentNode.insertBefore(trailingContainer, styledContainer.nextSibling);
 | |
|       while (node) {
 | |
|         loopGuard.check();
 | |
|         nextNode = node.nextSibling;
 | |
|         trailingContainer.appendChild(node);
 | |
|         node = nextNode;
 | |
|       }
 | |
|     }
 | |
|     return (styledContainer);
 | |
|   }
 | |
|   this.applyStyle = function(textNodes, range, info) {
 | |
|     var textPropsOnly = {}, isStyled, container, styleCache, styleLookup;
 | |
|     runtime.assert(info && info.hasOwnProperty(textProperties), "applyStyle without any text properties");
 | |
|     textPropsOnly[textProperties] = info[textProperties];
 | |
|     styleCache = new StyleManager(textPropsOnly);
 | |
|     styleLookup = new StyleLookup(textPropsOnly);
 | |
|     function apply(n) {
 | |
|       isStyled = styleLookup.isStyleApplied(n);
 | |
|       if (isStyled === false) {
 | |
|         container = moveToNewSpan(n, range);
 | |
|         styleCache.applyStyleToContainer(container);
 | |
|       }
 | |
|     }
 | |
|     textNodes.forEach(apply);
 | |
|   };
 | |
| };
 | |
| ops.OpApplyDirectStyling = function OpApplyDirectStyling() {
 | |
|   var memberid, timestamp, position, length, setProperties, odfUtils = odf.OdfUtils, domUtils = core.DomUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = parseInt(data.position, 10);
 | |
|     length = parseInt(data.length, 10);
 | |
|     setProperties = data.setProperties;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function applyStyle(odtDocument, range, info) {
 | |
|     var odfCanvas = odtDocument.getOdfCanvas(), odfContainer = odfCanvas.odfContainer(), nextTextNodes = domUtils.splitBoundaries(range), textNodes = odfUtils.getTextNodes(range, false), textStyles;
 | |
|     textStyles = new odf.TextStyleApplicator(new odf.ObjectNameGenerator((odfContainer), memberid), odtDocument.getFormatting(), odfContainer.rootElement.automaticStyles);
 | |
|     textStyles.applyStyle(textNodes, range, info);
 | |
|     nextTextNodes.forEach(domUtils.normalizeTextNodes);
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), range = odtDocument.convertCursorToDomRange(position, length), impactedParagraphs = odfUtils.getParagraphElements(range);
 | |
|     applyStyle(odtDocument, range, setProperties);
 | |
|     range.detach();
 | |
|     odtDocument.getOdfCanvas().refreshCSS();
 | |
|     odtDocument.fixCursorPositions();
 | |
|     impactedParagraphs.forEach(function(n) {
 | |
|       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:n, memberId:memberid, timeStamp:timestamp});
 | |
|     });
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"ApplyDirectStyling", memberid:memberid, timestamp:timestamp, position:position, length:length, setProperties:setProperties};
 | |
|   };
 | |
| };
 | |
| ops.OpApplyDirectStyling.Spec;
 | |
| ops.OpApplyDirectStyling.InitSpec;
 | |
| ops.OpApplyHyperlink = function OpApplyHyperlink() {
 | |
|   var memberid, timestamp, position, length, hyperlink, domUtils = core.DomUtils, odfUtils = odf.OdfUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     length = data.length;
 | |
|     hyperlink = data.hyperlink;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function createHyperlink(document, hyperlink) {
 | |
|     var node = document.createElementNS(odf.Namespaces.textns, "text:a");
 | |
|     node.setAttributeNS(odf.Namespaces.xlinkns, "xlink:type", "simple");
 | |
|     node.setAttributeNS(odf.Namespaces.xlinkns, "xlink:href", hyperlink);
 | |
|     return node;
 | |
|   }
 | |
|   function isPartOfLink(node) {
 | |
|     while (node) {
 | |
|       if (odfUtils.isHyperlink(node)) {
 | |
|         return true;
 | |
|       }
 | |
|       node = node.parentNode;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), ownerDocument = odtDocument.getDOMDocument(), range = odtDocument.convertCursorToDomRange(position, length), boundaryNodes = domUtils.splitBoundaries(range), modifiedParagraphs = [], textNodes = odfUtils.getTextNodes(range, false);
 | |
|     if (textNodes.length === 0) {
 | |
|       return false;
 | |
|     }
 | |
|     textNodes.forEach(function(node) {
 | |
|       var linkNode, paragraph = odfUtils.getParagraphElement(node);
 | |
|       runtime.assert(isPartOfLink(node) === false, "The given range should not contain any link.");
 | |
|       linkNode = createHyperlink(ownerDocument, hyperlink);
 | |
|       node.parentNode.insertBefore(linkNode, node);
 | |
|       linkNode.appendChild(node);
 | |
|       if (modifiedParagraphs.indexOf(paragraph) === -1) {
 | |
|         modifiedParagraphs.push(paragraph);
 | |
|       }
 | |
|     });
 | |
|     boundaryNodes.forEach(domUtils.normalizeTextNodes);
 | |
|     range.detach();
 | |
|     odtDocument.fixCursorPositions();
 | |
|     odtDocument.getOdfCanvas().refreshSize();
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     modifiedParagraphs.forEach(function(paragraph) {
 | |
|       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraph, memberId:memberid, timeStamp:timestamp});
 | |
|     });
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"ApplyHyperlink", memberid:memberid, timestamp:timestamp, position:position, length:length, hyperlink:hyperlink};
 | |
|   };
 | |
| };
 | |
| ops.OpApplyHyperlink.Spec;
 | |
| ops.OpApplyHyperlink.InitSpec;
 | |
| ops.OpInsertImage = function OpInsertImage() {
 | |
|   var memberid, timestamp, position, filename, frameWidth, frameHeight, frameStyleName, frameName, drawns = odf.Namespaces.drawns, svgns = odf.Namespaces.svgns, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns, odfUtils = odf.OdfUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     filename = data.filename;
 | |
|     frameWidth = data.frameWidth;
 | |
|     frameHeight = data.frameHeight;
 | |
|     frameStyleName = data.frameStyleName;
 | |
|     frameName = data.frameName;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function createFrameElement(document) {
 | |
|     var imageNode = document.createElementNS(drawns, "draw:image"), frameNode = document.createElementNS(drawns, "draw:frame");
 | |
|     imageNode.setAttributeNS(xlinkns, "xlink:href", filename);
 | |
|     imageNode.setAttributeNS(xlinkns, "xlink:type", "simple");
 | |
|     imageNode.setAttributeNS(xlinkns, "xlink:show", "embed");
 | |
|     imageNode.setAttributeNS(xlinkns, "xlink:actuate", "onLoad");
 | |
|     frameNode.setAttributeNS(drawns, "draw:style-name", frameStyleName);
 | |
|     frameNode.setAttributeNS(drawns, "draw:name", frameName);
 | |
|     frameNode.setAttributeNS(textns, "text:anchor-type", "as-char");
 | |
|     frameNode.setAttributeNS(svgns, "svg:width", frameWidth);
 | |
|     frameNode.setAttributeNS(svgns, "svg:height", frameHeight);
 | |
|     frameNode.appendChild(imageNode);
 | |
|     return frameNode;
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), odfCanvas = odtDocument.getOdfCanvas(), domPosition = odtDocument.getTextNodeAtStep(position, memberid), textNode, refNode, paragraphElement, frameElement;
 | |
|     if (!domPosition) {
 | |
|       return false;
 | |
|     }
 | |
|     textNode = domPosition.textNode;
 | |
|     paragraphElement = odfUtils.getParagraphElement(textNode);
 | |
|     refNode = domPosition.offset !== textNode.length ? textNode.splitText(domPosition.offset) : textNode.nextSibling;
 | |
|     frameElement = createFrameElement(odtDocument.getDOMDocument());
 | |
|     textNode.parentNode.insertBefore(frameElement, refNode);
 | |
|     odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position});
 | |
|     if (textNode.length === 0) {
 | |
|       textNode.parentNode.removeChild(textNode);
 | |
|     }
 | |
|     odfCanvas.addCssForFrameWithImage(frameElement);
 | |
|     odfCanvas.refreshCSS();
 | |
|     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphElement, memberId:memberid, timeStamp:timestamp});
 | |
|     odfCanvas.rerenderAnnotations();
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"InsertImage", memberid:memberid, timestamp:timestamp, filename:filename, position:position, frameWidth:frameWidth, frameHeight:frameHeight, frameStyleName:frameStyleName, frameName:frameName};
 | |
|   };
 | |
| };
 | |
| ops.OpInsertImage.Spec;
 | |
| ops.OpInsertImage.InitSpec;
 | |
| ops.OpInsertTable = function OpInsertTable() {
 | |
|   var memberid, timestamp, initialRows, initialColumns, position, tableName, tableStyleName, tableColumnStyleName, tableCellStyleMatrix, tablens = "urn:oasis:names:tc:opendocument:xmlns:table:1.0", textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0", odfUtils = odf.OdfUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     initialRows = data.initialRows;
 | |
|     initialColumns = data.initialColumns;
 | |
|     tableName = data.tableName;
 | |
|     tableStyleName = data.tableStyleName;
 | |
|     tableColumnStyleName = data.tableColumnStyleName;
 | |
|     tableCellStyleMatrix = data.tableCellStyleMatrix;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function getCellStyleName(row, column) {
 | |
|     var rowStyles;
 | |
|     if (tableCellStyleMatrix.length === 1) {
 | |
|       rowStyles = tableCellStyleMatrix[0];
 | |
|     } else {
 | |
|       if (tableCellStyleMatrix.length === 3) {
 | |
|         switch(row) {
 | |
|           case 0:
 | |
|             rowStyles = tableCellStyleMatrix[0];
 | |
|             break;
 | |
|           case initialRows - 1:
 | |
|             rowStyles = tableCellStyleMatrix[2];
 | |
|             break;
 | |
|           default:
 | |
|             rowStyles = tableCellStyleMatrix[1];
 | |
|             break;
 | |
|         }
 | |
|       } else {
 | |
|         rowStyles = tableCellStyleMatrix[row];
 | |
|       }
 | |
|     }
 | |
|     if (rowStyles.length === 1) {
 | |
|       return rowStyles[0];
 | |
|     }
 | |
|     if (rowStyles.length === 3) {
 | |
|       switch(column) {
 | |
|         case 0:
 | |
|           return rowStyles[0];
 | |
|         case initialColumns - 1:
 | |
|           return rowStyles[2];
 | |
|         default:
 | |
|           return rowStyles[1];
 | |
|       }
 | |
|     }
 | |
|     return rowStyles[column];
 | |
|   }
 | |
|   function createTableNode(document) {
 | |
|     var tableNode = document.createElementNS(tablens, "table:table"), columns = document.createElementNS(tablens, "table:table-column"), row, cell, paragraph, rowCounter, columnCounter, cellStyleName;
 | |
|     if (tableStyleName) {
 | |
|       tableNode.setAttributeNS(tablens, "table:style-name", tableStyleName);
 | |
|     }
 | |
|     if (tableName) {
 | |
|       tableNode.setAttributeNS(tablens, "table:name", tableName);
 | |
|     }
 | |
|     columns.setAttributeNS(tablens, "table:number-columns-repeated", initialColumns);
 | |
|     if (tableColumnStyleName) {
 | |
|       columns.setAttributeNS(tablens, "table:style-name", tableColumnStyleName);
 | |
|     }
 | |
|     tableNode.appendChild(columns);
 | |
|     for (rowCounter = 0;rowCounter < initialRows;rowCounter += 1) {
 | |
|       row = document.createElementNS(tablens, "table:table-row");
 | |
|       for (columnCounter = 0;columnCounter < initialColumns;columnCounter += 1) {
 | |
|         cell = document.createElementNS(tablens, "table:table-cell");
 | |
|         cellStyleName = getCellStyleName(rowCounter, columnCounter);
 | |
|         if (cellStyleName) {
 | |
|           cell.setAttributeNS(tablens, "table:style-name", cellStyleName);
 | |
|         }
 | |
|         paragraph = document.createElementNS(textns, "text:p");
 | |
|         cell.appendChild(paragraph);
 | |
|         row.appendChild(cell);
 | |
|       }
 | |
|       tableNode.appendChild(row);
 | |
|     }
 | |
|     return tableNode;
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), domPosition = odtDocument.getTextNodeAtStep(position), rootNode = odtDocument.getRootNode(), previousSibling, tableNode;
 | |
|     if (domPosition) {
 | |
|       tableNode = createTableNode(odtDocument.getDOMDocument());
 | |
|       previousSibling = odfUtils.getParagraphElement(domPosition.textNode);
 | |
|       rootNode.insertBefore(tableNode, previousSibling.nextSibling);
 | |
|       odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position});
 | |
|       odtDocument.getOdfCanvas().refreshSize();
 | |
|       odtDocument.emit(ops.OdtDocument.signalTableAdded, {tableElement:tableNode, memberId:memberid, timeStamp:timestamp});
 | |
|       odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"InsertTable", memberid:memberid, timestamp:timestamp, position:position, initialRows:initialRows, initialColumns:initialColumns, tableName:tableName, tableStyleName:tableStyleName, tableColumnStyleName:tableColumnStyleName, tableCellStyleMatrix:tableCellStyleMatrix};
 | |
|   };
 | |
| };
 | |
| ops.OpInsertTable.Spec;
 | |
| ops.OpInsertTable.InitSpec;
 | |
| ops.OpInsertText = function OpInsertText() {
 | |
|   var tab = "\t", memberid, timestamp, position, moveCursor, text, odfUtils = odf.OdfUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     text = data.text;
 | |
|     moveCursor = data.moveCursor === "true" || data.moveCursor === true;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function triggerLayoutInWebkit(textNode) {
 | |
|     var parent = textNode.parentNode, next = textNode.nextSibling;
 | |
|     parent.removeChild(textNode);
 | |
|     parent.insertBefore(textNode, next);
 | |
|   }
 | |
|   function isNonTabWhiteSpace(character) {
 | |
|     return character !== tab && odfUtils.isODFWhitespace(character);
 | |
|   }
 | |
|   function requiresSpaceElement(text, index) {
 | |
|     return isNonTabWhiteSpace(text[index]) && (index === 0 || index === text.length - 1 || isNonTabWhiteSpace(text[index - 1]));
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), domPosition, previousNode, parentElement, nextNode = null, ownerDocument = odtDocument.getDOMDocument(), paragraphElement, textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0", toInsertIndex = 0, spaceElement, cursor = odtDocument.getCursor(memberid), i;
 | |
|     function insertTextNode(toInsertText) {
 | |
|       parentElement.insertBefore(ownerDocument.createTextNode(toInsertText), nextNode);
 | |
|     }
 | |
|     odtDocument.upgradeWhitespacesAtPosition(position);
 | |
|     domPosition = odtDocument.getTextNodeAtStep(position);
 | |
|     if (domPosition) {
 | |
|       previousNode = domPosition.textNode;
 | |
|       nextNode = previousNode.nextSibling;
 | |
|       parentElement = (previousNode.parentNode);
 | |
|       paragraphElement = odfUtils.getParagraphElement(previousNode);
 | |
|       for (i = 0;i < text.length;i += 1) {
 | |
|         if (text[i] === tab || requiresSpaceElement(text, i)) {
 | |
|           if (toInsertIndex === 0) {
 | |
|             if (domPosition.offset !== previousNode.length) {
 | |
|               nextNode = previousNode.splitText(domPosition.offset);
 | |
|             }
 | |
|             if (0 < i) {
 | |
|               previousNode.appendData(text.substring(0, i));
 | |
|             }
 | |
|           } else {
 | |
|             if (toInsertIndex < i) {
 | |
|               insertTextNode(text.substring(toInsertIndex, i));
 | |
|             }
 | |
|           }
 | |
|           toInsertIndex = i + 1;
 | |
|           if (text[i] === tab) {
 | |
|             spaceElement = ownerDocument.createElementNS(textns, "text:tab");
 | |
|             spaceElement.appendChild(ownerDocument.createTextNode("\t"));
 | |
|           } else {
 | |
|             if (text[i] !== " ") {
 | |
|               runtime.log("WARN: InsertText operation contains non-tab, non-space whitespace character (character code " + text.charCodeAt(i) + ")");
 | |
|             }
 | |
|             spaceElement = ownerDocument.createElementNS(textns, "text:s");
 | |
|             spaceElement.appendChild(ownerDocument.createTextNode(" "));
 | |
|           }
 | |
|           parentElement.insertBefore(spaceElement, nextNode);
 | |
|         }
 | |
|       }
 | |
|       if (toInsertIndex === 0) {
 | |
|         previousNode.insertData(domPosition.offset, text);
 | |
|       } else {
 | |
|         if (toInsertIndex < text.length) {
 | |
|           insertTextNode(text.substring(toInsertIndex));
 | |
|         }
 | |
|       }
 | |
|       triggerLayoutInWebkit(previousNode);
 | |
|       if (previousNode.length === 0) {
 | |
|         previousNode.parentNode.removeChild(previousNode);
 | |
|       }
 | |
|       odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position});
 | |
|       if (cursor && moveCursor) {
 | |
|         odtDocument.moveCursor(memberid, position + text.length, 0);
 | |
|         odtDocument.emit(ops.Document.signalCursorMoved, cursor);
 | |
|       }
 | |
|       odtDocument.downgradeWhitespacesAtPosition(position);
 | |
|       odtDocument.downgradeWhitespacesAtPosition(position + text.length);
 | |
|       odtDocument.getOdfCanvas().refreshSize();
 | |
|       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphElement, memberId:memberid, timeStamp:timestamp});
 | |
|       odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"InsertText", memberid:memberid, timestamp:timestamp, position:position, text:text, moveCursor:moveCursor};
 | |
|   };
 | |
| };
 | |
| ops.OpInsertText.Spec;
 | |
| ops.OpInsertText.InitSpec;
 | |
| odf.CollapsingRules = function CollapsingRules(rootNode) {
 | |
|   var odfUtils = odf.OdfUtils, domUtils = core.DomUtils;
 | |
|   function filterOdfNodesToRemove(node) {
 | |
|     var isToRemove = odfUtils.isODFNode(node) || node.localName === "br" && odfUtils.isLineBreak(node.parentNode) || node.nodeType === Node.TEXT_NODE && odfUtils.isODFNode((node.parentNode));
 | |
|     return isToRemove ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
 | |
|   }
 | |
|   function isCollapsibleContainer(node) {
 | |
|     return !odfUtils.isParagraph(node) && node !== rootNode && odfUtils.hasNoODFContent(node);
 | |
|   }
 | |
|   function mergeChildrenIntoParent(targetNode) {
 | |
|     var parent;
 | |
|     if (targetNode.nodeType === Node.TEXT_NODE) {
 | |
|       parent = targetNode.parentNode;
 | |
|       parent.removeChild(targetNode);
 | |
|     } else {
 | |
|       parent = domUtils.removeUnwantedNodes(targetNode, filterOdfNodesToRemove);
 | |
|     }
 | |
|     if (parent && isCollapsibleContainer(parent)) {
 | |
|       return mergeChildrenIntoParent(parent);
 | |
|     }
 | |
|     return parent;
 | |
|   }
 | |
|   this.mergeChildrenIntoParent = mergeChildrenIntoParent;
 | |
| };
 | |
| ops.OpMergeParagraph = function OpMergeParagraph() {
 | |
|   var memberid, timestamp, moveCursor, paragraphStyleName, sourceStartPosition, destinationStartPosition, odfUtils = odf.OdfUtils, domUtils = core.DomUtils, textns = odf.Namespaces.textns;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     moveCursor = data.moveCursor;
 | |
|     paragraphStyleName = data.paragraphStyleName;
 | |
|     sourceStartPosition = parseInt(data.sourceStartPosition, 10);
 | |
|     destinationStartPosition = parseInt(data.destinationStartPosition, 10);
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function filterEmptyGroupingElementToRemove(element) {
 | |
|     if (odf.OdfUtils.isInlineRoot(element)) {
 | |
|       return NodeFilter.FILTER_SKIP;
 | |
|     }
 | |
|     return odfUtils.isGroupingElement(element) && odfUtils.hasNoODFContent(element) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
 | |
|   }
 | |
|   function mergeParagraphs(destination, source) {
 | |
|     var child;
 | |
|     child = source.firstChild;
 | |
|     while (child) {
 | |
|       if (child.localName === "editinfo") {
 | |
|         source.removeChild(child);
 | |
|       } else {
 | |
|         destination.appendChild(child);
 | |
|         domUtils.removeUnwantedNodes(child, filterEmptyGroupingElementToRemove);
 | |
|       }
 | |
|       child = source.firstChild;
 | |
|     }
 | |
|   }
 | |
|   function isInsignificantWhitespace(node) {
 | |
|     var textNode, badNodeDescription;
 | |
|     if (node.nodeType === Node.TEXT_NODE) {
 | |
|       textNode = (node);
 | |
|       if (textNode.length === 0) {
 | |
|         runtime.log("WARN: Empty text node found during merge operation");
 | |
|         return true;
 | |
|       }
 | |
|       if (odfUtils.isODFWhitespace(textNode.data) && odfUtils.isSignificantWhitespace(textNode, 0) === false) {
 | |
|         return true;
 | |
|       }
 | |
|       badNodeDescription = "#text";
 | |
|     } else {
 | |
|       badNodeDescription = (node.prefix ? node.prefix + ":" : "") + node.localName;
 | |
|     }
 | |
|     runtime.log("WARN: Unexpected text element found near paragraph boundary [" + badNodeDescription + "]");
 | |
|     return false;
 | |
|   }
 | |
|   function removeTextNodes(range) {
 | |
|     var emptyTextNodes;
 | |
|     if (range.collapsed) {
 | |
|       return;
 | |
|     }
 | |
|     domUtils.splitBoundaries(range);
 | |
|     emptyTextNodes = odfUtils.getTextElements(range, false, true).filter(isInsignificantWhitespace);
 | |
|     emptyTextNodes.forEach(function(node) {
 | |
|       node.parentNode.removeChild(node);
 | |
|     });
 | |
|   }
 | |
|   function trimLeadingInsignificantWhitespace(stepIterator, paragraphElement) {
 | |
|     var range = paragraphElement.ownerDocument.createRange();
 | |
|     stepIterator.setPosition(paragraphElement, 0);
 | |
|     stepIterator.roundToNextStep();
 | |
|     range.setStart(paragraphElement, 0);
 | |
|     range.setEnd(stepIterator.container(), stepIterator.offset());
 | |
|     removeTextNodes(range);
 | |
|   }
 | |
|   function trimTrailingInsignificantWhitespace(stepIterator, paragraphElement) {
 | |
|     var range = paragraphElement.ownerDocument.createRange();
 | |
|     stepIterator.setPosition(paragraphElement, paragraphElement.childNodes.length);
 | |
|     stepIterator.roundToPreviousStep();
 | |
|     range.setStart(stepIterator.container(), stepIterator.offset());
 | |
|     range.setEnd(paragraphElement, paragraphElement.childNodes.length);
 | |
|     removeTextNodes(range);
 | |
|   }
 | |
|   function getParagraphAtStep(odtDocument, steps, stepIterator) {
 | |
|     var domPoint = odtDocument.convertCursorStepToDomPoint(steps), paragraph = odfUtils.getParagraphElement(domPoint.node, domPoint.offset);
 | |
|     runtime.assert(Boolean(paragraph), "Paragraph not found at step " + steps);
 | |
|     if (stepIterator) {
 | |
|       stepIterator.setPosition(domPoint.node, domPoint.offset);
 | |
|     }
 | |
|     return (paragraph);
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), sourceParagraph, destinationParagraph, cursor = odtDocument.getCursor(memberid), rootNode = odtDocument.getRootNode(), collapseRules = new odf.CollapsingRules(rootNode), stepIterator = odtDocument.createStepIterator(rootNode, 0, [odtDocument.getPositionFilter()], rootNode), downgradeOffset;
 | |
|     runtime.assert(destinationStartPosition < sourceStartPosition, "Destination paragraph (" + destinationStartPosition + ") must be " + "before source paragraph (" + sourceStartPosition + ")");
 | |
|     destinationParagraph = getParagraphAtStep(odtDocument, destinationStartPosition);
 | |
|     sourceParagraph = getParagraphAtStep(odtDocument, sourceStartPosition, stepIterator);
 | |
|     stepIterator.previousStep();
 | |
|     runtime.assert(domUtils.containsNode(destinationParagraph, stepIterator.container()), "Destination paragraph must be adjacent to the source paragraph");
 | |
|     trimTrailingInsignificantWhitespace(stepIterator, destinationParagraph);
 | |
|     downgradeOffset = destinationParagraph.childNodes.length;
 | |
|     trimLeadingInsignificantWhitespace(stepIterator, sourceParagraph);
 | |
|     mergeParagraphs(destinationParagraph, sourceParagraph);
 | |
|     runtime.assert(sourceParagraph.childNodes.length === 0, "Source paragraph should be empty before it is removed");
 | |
|     collapseRules.mergeChildrenIntoParent(sourceParagraph);
 | |
|     odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:sourceStartPosition - 1});
 | |
|     stepIterator.setPosition(destinationParagraph, downgradeOffset);
 | |
|     stepIterator.roundToClosestStep();
 | |
|     if (!stepIterator.previousStep()) {
 | |
|       stepIterator.roundToNextStep();
 | |
|     }
 | |
|     odtDocument.downgradeWhitespaces(stepIterator);
 | |
|     if (paragraphStyleName) {
 | |
|       destinationParagraph.setAttributeNS(textns, "text:style-name", paragraphStyleName);
 | |
|     } else {
 | |
|       destinationParagraph.removeAttributeNS(textns, "style-name");
 | |
|     }
 | |
|     if (cursor && moveCursor) {
 | |
|       odtDocument.moveCursor(memberid, sourceStartPosition - 1, 0);
 | |
|       odtDocument.emit(ops.Document.signalCursorMoved, cursor);
 | |
|     }
 | |
|     odtDocument.fixCursorPositions();
 | |
|     odtDocument.getOdfCanvas().refreshSize();
 | |
|     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:destinationParagraph, memberId:memberid, timeStamp:timestamp});
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"MergeParagraph", memberid:memberid, timestamp:timestamp, moveCursor:moveCursor, paragraphStyleName:paragraphStyleName, sourceStartPosition:sourceStartPosition, destinationStartPosition:destinationStartPosition};
 | |
|   };
 | |
| };
 | |
| ops.OpMergeParagraph.Spec;
 | |
| ops.OpMergeParagraph.InitSpec;
 | |
| ops.OpMoveCursor = function OpMoveCursor() {
 | |
|   var memberid, timestamp, position, length, selectionType;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     length = data.length || 0;
 | |
|     selectionType = data.selectionType || ops.OdtCursor.RangeSelection;
 | |
|   };
 | |
|   this.isEdit = false;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), cursor = odtDocument.getCursor(memberid), selectedRange;
 | |
|     if (!cursor) {
 | |
|       return false;
 | |
|     }
 | |
|     selectedRange = odtDocument.convertCursorToDomRange(position, length);
 | |
|     cursor.setSelectedRange(selectedRange, length >= 0);
 | |
|     cursor.setSelectionType(selectionType);
 | |
|     odtDocument.emit(ops.Document.signalCursorMoved, cursor);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"MoveCursor", memberid:memberid, timestamp:timestamp, position:position, length:length, selectionType:selectionType};
 | |
|   };
 | |
| };
 | |
| ops.OpMoveCursor.Spec;
 | |
| ops.OpMoveCursor.InitSpec;
 | |
| ops.OpRemoveAnnotation = function OpRemoveAnnotation() {
 | |
|   var memberid, timestamp, position, length, domUtils = core.DomUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = parseInt(data.position, 10);
 | |
|     length = parseInt(data.length, 10);
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), iterator = odtDocument.getIteratorAtPosition(position), container = iterator.container(), annotationNode, annotationEnd;
 | |
|     while (!(container.namespaceURI === odf.Namespaces.officens && container.localName === "annotation")) {
 | |
|       container = container.parentNode;
 | |
|     }
 | |
|     if (container === null) {
 | |
|       return false;
 | |
|     }
 | |
|     annotationNode = (container);
 | |
|     annotationEnd = annotationNode.annotationEndElement;
 | |
|     odtDocument.getOdfCanvas().forgetAnnotation(annotationNode);
 | |
|     function insert(node) {
 | |
|       (annotationNode).parentNode.insertBefore(node, annotationNode);
 | |
|     }
 | |
|     domUtils.getElementsByTagNameNS(annotationNode, "urn:webodf:names:cursor", "cursor").forEach(insert);
 | |
|     domUtils.getElementsByTagNameNS(annotationNode, "urn:webodf:names:cursor", "anchor").forEach(insert);
 | |
|     annotationNode.parentNode.removeChild(annotationNode);
 | |
|     if (annotationEnd) {
 | |
|       annotationEnd.parentNode.removeChild(annotationEnd);
 | |
|     }
 | |
|     odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:position > 0 ? position - 1 : position});
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     odtDocument.fixCursorPositions();
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveAnnotation", memberid:memberid, timestamp:timestamp, position:position, length:length};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveAnnotation.Spec;
 | |
| ops.OpRemoveAnnotation.InitSpec;
 | |
| ops.OpRemoveBlob = function OpRemoveBlob() {
 | |
|   var memberid, timestamp, filename;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     filename = data.filename;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document);
 | |
|     odtDocument.getOdfCanvas().odfContainer().removeBlob(filename);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveBlob", memberid:memberid, timestamp:timestamp, filename:filename};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveBlob.Spec;
 | |
| ops.OpRemoveBlob.InitSpec;
 | |
| ops.OpRemoveCursor = function OpRemoveCursor() {
 | |
|   var memberid, timestamp;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|   };
 | |
|   this.isEdit = false;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document);
 | |
|     if (!odtDocument.removeCursor(memberid)) {
 | |
|       return false;
 | |
|     }
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveCursor", memberid:memberid, timestamp:timestamp};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveCursor.Spec;
 | |
| ops.OpRemoveCursor.InitSpec;
 | |
| ops.OpRemoveHyperlink = function OpRemoveHyperlink() {
 | |
|   var memberid, timestamp, position, length, domUtils = core.DomUtils, odfUtils = odf.OdfUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     length = data.length;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), range = odtDocument.convertCursorToDomRange(position, length), links = odfUtils.getHyperlinkElements(range), node;
 | |
|     runtime.assert(links.length === 1, "The given range should only contain a single link.");
 | |
|     node = domUtils.mergeIntoParent((links[0]));
 | |
|     range.detach();
 | |
|     odtDocument.fixCursorPositions();
 | |
|     odtDocument.getOdfCanvas().refreshSize();
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:odfUtils.getParagraphElement(node), memberId:memberid, timeStamp:timestamp});
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveHyperlink", memberid:memberid, timestamp:timestamp, position:position, length:length};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveHyperlink.Spec;
 | |
| ops.OpRemoveHyperlink.InitSpec;
 | |
| ops.OpRemoveMember = function OpRemoveMember() {
 | |
|   var memberid, timestamp;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = parseInt(data.timestamp, 10);
 | |
|   };
 | |
|   this.isEdit = false;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document);
 | |
|     if (!odtDocument.getMember(memberid)) {
 | |
|       return false;
 | |
|     }
 | |
|     odtDocument.removeMember(memberid);
 | |
|     odtDocument.emit(ops.Document.signalMemberRemoved, memberid);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveMember", memberid:memberid, timestamp:timestamp};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveMember.Spec;
 | |
| ops.OpRemoveMember.InitSpec;
 | |
| ops.OpRemoveStyle = function OpRemoveStyle() {
 | |
|   var memberid, timestamp, styleName, styleFamily;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     styleName = data.styleName;
 | |
|     styleFamily = data.styleFamily;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), styleNode = odtDocument.getFormatting().getStyleElement(styleName, styleFamily);
 | |
|     if (!styleNode) {
 | |
|       return false;
 | |
|     }
 | |
|     styleNode.parentNode.removeChild(styleNode);
 | |
|     odtDocument.getOdfCanvas().refreshCSS();
 | |
|     odtDocument.emit(ops.OdtDocument.signalCommonStyleDeleted, {name:styleName, family:styleFamily});
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, styleFamily:styleFamily};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveStyle.Spec;
 | |
| ops.OpRemoveStyle.InitSpec;
 | |
| ops.OpRemoveText = function OpRemoveText() {
 | |
|   var memberid, timestamp, position, length, odfUtils = odf.OdfUtils, domUtils = core.DomUtils;
 | |
|   this.init = function(data) {
 | |
|     runtime.assert(data.length >= 0, "OpRemoveText only supports positive lengths");
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = parseInt(data.position, 10);
 | |
|     length = parseInt(data.length, 10);
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), range, textNodes, paragraph, cursor = odtDocument.getCursor(memberid), collapseRules = new odf.CollapsingRules(odtDocument.getRootNode());
 | |
|     odtDocument.upgradeWhitespacesAtPosition(position);
 | |
|     odtDocument.upgradeWhitespacesAtPosition(position + length);
 | |
|     range = odtDocument.convertCursorToDomRange(position, length);
 | |
|     domUtils.splitBoundaries(range);
 | |
|     textNodes = odfUtils.getTextElements(range, false, true);
 | |
|     paragraph = (odfUtils.getParagraphElement(range.startContainer, range.startOffset));
 | |
|     runtime.assert(paragraph !== undefined, "Attempting to remove text outside a paragraph element");
 | |
|     range.detach();
 | |
|     textNodes.forEach(function(element) {
 | |
|       if (element.parentNode) {
 | |
|         runtime.assert(domUtils.containsNode(paragraph, element), "RemoveText only supports removing elements within the same paragraph");
 | |
|         collapseRules.mergeChildrenIntoParent(element);
 | |
|       } else {
 | |
|         runtime.log("WARN: text element has already been removed from it's container");
 | |
|       }
 | |
|     });
 | |
|     odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:position});
 | |
|     odtDocument.downgradeWhitespacesAtPosition(position);
 | |
|     odtDocument.fixCursorPositions();
 | |
|     odtDocument.getOdfCanvas().refreshSize();
 | |
|     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraph, memberId:memberid, timeStamp:timestamp});
 | |
|     if (cursor) {
 | |
|       cursor.resetSelectionType();
 | |
|       odtDocument.emit(ops.Document.signalCursorMoved, cursor);
 | |
|     }
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"RemoveText", memberid:memberid, timestamp:timestamp, position:position, length:length};
 | |
|   };
 | |
| };
 | |
| ops.OpRemoveText.Spec;
 | |
| ops.OpRemoveText.InitSpec;
 | |
| ops.OpSetBlob = function OpSetBlob() {
 | |
|   var memberid, timestamp, filename, mimetype, content;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     filename = data.filename;
 | |
|     mimetype = data.mimetype;
 | |
|     content = data.content;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document);
 | |
|     odtDocument.getOdfCanvas().odfContainer().setBlob(filename, mimetype, content);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"SetBlob", memberid:memberid, timestamp:timestamp, filename:filename, mimetype:mimetype, content:content};
 | |
|   };
 | |
| };
 | |
| ops.OpSetBlob.Spec;
 | |
| ops.OpSetBlob.InitSpec;
 | |
| ops.OpSetParagraphStyle = function OpSetParagraphStyle() {
 | |
|   var memberid, timestamp, position, styleName, textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0", odfUtils = odf.OdfUtils;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     styleName = data.styleName;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   function isFirstStep(odtDocument, paragraphNode, iterator) {
 | |
|     var filters = [odtDocument.getPositionFilter()], container = iterator.container(), offset = iterator.unfilteredDomOffset(), stepIterator = odtDocument.createStepIterator(container, offset, filters, paragraphNode);
 | |
|     return stepIterator.previousStep() === false;
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), iterator, paragraphNode;
 | |
|     iterator = odtDocument.getIteratorAtPosition(position);
 | |
|     paragraphNode = odfUtils.getParagraphElement(iterator.container());
 | |
|     if (paragraphNode) {
 | |
|       runtime.assert(isFirstStep(odtDocument, paragraphNode, iterator), "SetParagraphStyle position should be the first position in the paragraph");
 | |
|       if (styleName) {
 | |
|         paragraphNode.setAttributeNS(textns, "text:style-name", styleName);
 | |
|       } else {
 | |
|         paragraphNode.removeAttributeNS(textns, "style-name");
 | |
|       }
 | |
|       odtDocument.getOdfCanvas().refreshSize();
 | |
|       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphNode, timeStamp:timestamp, memberId:memberid});
 | |
|       odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"SetParagraphStyle", memberid:memberid, timestamp:timestamp, position:position, styleName:styleName};
 | |
|   };
 | |
| };
 | |
| ops.OpSetParagraphStyle.Spec;
 | |
| ops.OpSetParagraphStyle.InitSpec;
 | |
| ops.OpSplitParagraph = function OpSplitParagraph() {
 | |
|   var memberid, timestamp, sourceParagraphPosition, position, moveCursor, paragraphStyleName, odfUtils = odf.OdfUtils, textns = odf.Namespaces.textns;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     position = data.position;
 | |
|     sourceParagraphPosition = data.sourceParagraphPosition;
 | |
|     paragraphStyleName = data.paragraphStyleName;
 | |
|     moveCursor = data.moveCursor === "true" || data.moveCursor === true;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), domPosition, paragraphNode, targetNode, node, splitNode, splitChildNode, keptChildNode, cursor = odtDocument.getCursor(memberid);
 | |
|     odtDocument.upgradeWhitespacesAtPosition(position);
 | |
|     domPosition = odtDocument.getTextNodeAtStep(position);
 | |
|     if (!domPosition) {
 | |
|       return false;
 | |
|     }
 | |
|     paragraphNode = odfUtils.getParagraphElement(domPosition.textNode);
 | |
|     if (!paragraphNode) {
 | |
|       return false;
 | |
|     }
 | |
|     if (odfUtils.isListItem(paragraphNode.parentNode)) {
 | |
|       targetNode = paragraphNode.parentNode;
 | |
|     } else {
 | |
|       targetNode = paragraphNode;
 | |
|     }
 | |
|     if (domPosition.offset === 0) {
 | |
|       keptChildNode = domPosition.textNode.previousSibling;
 | |
|       splitChildNode = null;
 | |
|     } else {
 | |
|       keptChildNode = domPosition.textNode;
 | |
|       if (domPosition.offset >= domPosition.textNode.length) {
 | |
|         splitChildNode = null;
 | |
|       } else {
 | |
|         splitChildNode = (domPosition.textNode.splitText(domPosition.offset));
 | |
|       }
 | |
|     }
 | |
|     node = domPosition.textNode;
 | |
|     while (node !== targetNode) {
 | |
|       node = node.parentNode;
 | |
|       splitNode = node.cloneNode(false);
 | |
|       if (splitChildNode) {
 | |
|         splitNode.appendChild(splitChildNode);
 | |
|       }
 | |
|       if (keptChildNode) {
 | |
|         while (keptChildNode && keptChildNode.nextSibling) {
 | |
|           splitNode.appendChild(keptChildNode.nextSibling);
 | |
|         }
 | |
|       } else {
 | |
|         while (node.firstChild) {
 | |
|           splitNode.appendChild(node.firstChild);
 | |
|         }
 | |
|       }
 | |
|       node.parentNode.insertBefore(splitNode, node.nextSibling);
 | |
|       keptChildNode = node;
 | |
|       splitChildNode = splitNode;
 | |
|     }
 | |
|     if (odfUtils.isListItem(splitChildNode)) {
 | |
|       splitChildNode = splitChildNode.childNodes.item(0);
 | |
|     }
 | |
|     if (paragraphStyleName) {
 | |
|       (splitChildNode).setAttributeNS(textns, "text:style-name", paragraphStyleName);
 | |
|     } else {
 | |
|       (splitChildNode).removeAttributeNS(textns, "style-name");
 | |
|     }
 | |
|     if (domPosition.textNode.length === 0) {
 | |
|       domPosition.textNode.parentNode.removeChild(domPosition.textNode);
 | |
|     }
 | |
|     odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position});
 | |
|     if (cursor && moveCursor) {
 | |
|       odtDocument.moveCursor(memberid, position + 1, 0);
 | |
|       odtDocument.emit(ops.Document.signalCursorMoved, cursor);
 | |
|     }
 | |
|     odtDocument.fixCursorPositions();
 | |
|     odtDocument.getOdfCanvas().refreshSize();
 | |
|     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphNode, memberId:memberid, timeStamp:timestamp});
 | |
|     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:splitChildNode, memberId:memberid, timeStamp:timestamp});
 | |
|     odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"SplitParagraph", memberid:memberid, timestamp:timestamp, position:position, sourceParagraphPosition:sourceParagraphPosition, paragraphStyleName:paragraphStyleName, moveCursor:moveCursor};
 | |
|   };
 | |
| };
 | |
| ops.OpSplitParagraph.Spec;
 | |
| ops.OpSplitParagraph.InitSpec;
 | |
| ops.OpUpdateMember = function OpUpdateMember() {
 | |
|   var memberid, timestamp, setProperties, removedProperties;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = parseInt(data.timestamp, 10);
 | |
|     setProperties = data.setProperties;
 | |
|     removedProperties = data.removedProperties;
 | |
|   };
 | |
|   this.isEdit = false;
 | |
|   this.group = undefined;
 | |
|   function updateCreators(doc) {
 | |
|     var xpath = xmldom.XPath, xp = "//dc:creator[@editinfo:memberid='" + memberid + "']", creators = xpath.getODFElementsWithXPath(doc.getRootNode(), xp, function(prefix) {
 | |
|       if (prefix === "editinfo") {
 | |
|         return "urn:webodf:names:editinfo";
 | |
|       }
 | |
|       return odf.Namespaces.lookupNamespaceURI(prefix);
 | |
|     }), i;
 | |
|     for (i = 0;i < creators.length;i += 1) {
 | |
|       creators[i].textContent = setProperties.fullName;
 | |
|     }
 | |
|   }
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), member = odtDocument.getMember(memberid);
 | |
|     if (!member) {
 | |
|       return false;
 | |
|     }
 | |
|     if (removedProperties) {
 | |
|       member.removeProperties(removedProperties);
 | |
|     }
 | |
|     if (setProperties) {
 | |
|       member.setProperties(setProperties);
 | |
|       if (setProperties.fullName) {
 | |
|         updateCreators(odtDocument);
 | |
|       }
 | |
|     }
 | |
|     odtDocument.emit(ops.Document.signalMemberUpdated, member);
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"UpdateMember", memberid:memberid, timestamp:timestamp, setProperties:setProperties, removedProperties:removedProperties};
 | |
|   };
 | |
| };
 | |
| ops.OpUpdateMember.Spec;
 | |
| ops.OpUpdateMember.InitSpec;
 | |
| ops.OpUpdateMetadata = function OpUpdateMetadata() {
 | |
|   var memberid, timestamp, setProperties, removedProperties;
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = parseInt(data.timestamp, 10);
 | |
|     setProperties = data.setProperties;
 | |
|     removedProperties = data.removedProperties;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), odfContainer = odtDocument.getOdfCanvas().odfContainer(), removedPropertiesArray = null;
 | |
|     if (removedProperties) {
 | |
|       removedPropertiesArray = removedProperties.attributes.split(",");
 | |
|     }
 | |
|     odfContainer.setMetadata(setProperties, removedPropertiesArray);
 | |
|     odtDocument.emit(ops.OdtDocument.signalMetadataUpdated, {setProperties:setProperties !== null ? setProperties : {}, removedProperties:removedPropertiesArray !== null ? removedPropertiesArray : []});
 | |
|     return true;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"UpdateMetadata", memberid:memberid, timestamp:timestamp, setProperties:setProperties, removedProperties:removedProperties};
 | |
|   };
 | |
| };
 | |
| ops.OpUpdateMetadata.Spec;
 | |
| ops.OpUpdateMetadata.InitSpec;
 | |
| ops.OpUpdateParagraphStyle = function OpUpdateParagraphStyle() {
 | |
|   var memberid, timestamp, styleName, setProperties, removedProperties, paragraphPropertiesName = "style:paragraph-properties", textPropertiesName = "style:text-properties", stylens = odf.Namespaces.stylens;
 | |
|   function removedAttributesFromStyleNode(node, removedAttributeNames) {
 | |
|     var i, attributeNameParts, attributeNameList = removedAttributeNames ? removedAttributeNames.split(",") : [];
 | |
|     for (i = 0;i < attributeNameList.length;i += 1) {
 | |
|       attributeNameParts = attributeNameList[i].split(":");
 | |
|       node.removeAttributeNS((odf.Namespaces.lookupNamespaceURI(attributeNameParts[0])), attributeNameParts[1]);
 | |
|     }
 | |
|   }
 | |
|   this.init = function(data) {
 | |
|     memberid = data.memberid;
 | |
|     timestamp = data.timestamp;
 | |
|     styleName = data.styleName;
 | |
|     setProperties = data.setProperties;
 | |
|     removedProperties = data.removedProperties;
 | |
|   };
 | |
|   this.isEdit = true;
 | |
|   this.group = undefined;
 | |
|   this.execute = function(document) {
 | |
|     var odtDocument = (document), formatting = odtDocument.getFormatting(), styleNode, object, paragraphPropertiesNode, textPropertiesNode;
 | |
|     if (styleName !== "") {
 | |
|       styleNode = formatting.getStyleElement(styleName, "paragraph");
 | |
|     } else {
 | |
|       styleNode = formatting.getDefaultStyleElement("paragraph");
 | |
|     }
 | |
|     if (styleNode) {
 | |
|       paragraphPropertiesNode = (styleNode.getElementsByTagNameNS(stylens, "paragraph-properties").item(0));
 | |
|       textPropertiesNode = (styleNode.getElementsByTagNameNS(stylens, "text-properties").item(0));
 | |
|       if (setProperties) {
 | |
|         formatting.updateStyle(styleNode, setProperties);
 | |
|       }
 | |
|       if (removedProperties) {
 | |
|         object = (removedProperties[paragraphPropertiesName]);
 | |
|         if (paragraphPropertiesNode && object) {
 | |
|           removedAttributesFromStyleNode(paragraphPropertiesNode, object.attributes);
 | |
|           if (paragraphPropertiesNode.attributes.length === 0) {
 | |
|             styleNode.removeChild(paragraphPropertiesNode);
 | |
|           }
 | |
|         }
 | |
|         object = (removedProperties[textPropertiesName]);
 | |
|         if (textPropertiesNode && object) {
 | |
|           removedAttributesFromStyleNode(textPropertiesNode, object.attributes);
 | |
|           if (textPropertiesNode.attributes.length === 0) {
 | |
|             styleNode.removeChild(textPropertiesNode);
 | |
|           }
 | |
|         }
 | |
|         removedAttributesFromStyleNode(styleNode, removedProperties.attributes);
 | |
|       }
 | |
|       odtDocument.getOdfCanvas().refreshCSS();
 | |
|       odtDocument.emit(ops.OdtDocument.signalParagraphStyleModified, styleName);
 | |
|       odtDocument.getOdfCanvas().rerenderAnnotations();
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
|   this.spec = function() {
 | |
|     return {optype:"UpdateParagraphStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, setProperties:setProperties, removedProperties:removedProperties};
 | |
|   };
 | |
| };
 | |
| ops.OpUpdateParagraphStyle.Spec;
 | |
| ops.OpUpdateParagraphStyle.InitSpec;
 | |
| ops.OperationFactory = function OperationFactory() {
 | |
|   var specs;
 | |
|   function construct(Constructor) {
 | |
|     return function(spec) {
 | |
|       return new Constructor;
 | |
|     };
 | |
|   }
 | |
|   this.register = function(specName, specConstructor) {
 | |
|     specs[specName] = specConstructor;
 | |
|   };
 | |
|   this.create = function(spec) {
 | |
|     var op = null, constructor = specs[spec.optype];
 | |
|     if (constructor) {
 | |
|       op = constructor(spec);
 | |
|       op.init(spec);
 | |
|     }
 | |
|     return op;
 | |
|   };
 | |
|   function init() {
 | |
|     specs = {AddMember:construct(ops.OpAddMember), UpdateMember:construct(ops.OpUpdateMember), RemoveMember:construct(ops.OpRemoveMember), AddCursor:construct(ops.OpAddCursor), ApplyDirectStyling:construct(ops.OpApplyDirectStyling), SetBlob:construct(ops.OpSetBlob), RemoveBlob:construct(ops.OpRemoveBlob), InsertImage:construct(ops.OpInsertImage), InsertTable:construct(ops.OpInsertTable), InsertText:construct(ops.OpInsertText), RemoveText:construct(ops.OpRemoveText), MergeParagraph:construct(ops.OpMergeParagraph), 
 | |
|     SplitParagraph:construct(ops.OpSplitParagraph), SetParagraphStyle:construct(ops.OpSetParagraphStyle), UpdateParagraphStyle:construct(ops.OpUpdateParagraphStyle), AddStyle:construct(ops.OpAddStyle), RemoveStyle:construct(ops.OpRemoveStyle), MoveCursor:construct(ops.OpMoveCursor), RemoveCursor:construct(ops.OpRemoveCursor), AddAnnotation:construct(ops.OpAddAnnotation), RemoveAnnotation:construct(ops.OpRemoveAnnotation), UpdateMetadata:construct(ops.OpUpdateMetadata), ApplyHyperlink:construct(ops.OpApplyHyperlink), 
 | |
|     RemoveHyperlink:construct(ops.OpRemoveHyperlink)};
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| ops.OperationFactory.SpecConstructor;
 | |
| ops.OperationRouter = function OperationRouter() {
 | |
| };
 | |
| ops.OperationRouter.prototype.setOperationFactory = function(f) {
 | |
| };
 | |
| ops.OperationRouter.prototype.setPlaybackFunction = function(playback_func) {
 | |
| };
 | |
| ops.OperationRouter.prototype.push = function(operations) {
 | |
| };
 | |
| ops.OperationRouter.prototype.close = function(callback) {
 | |
| };
 | |
| ops.OperationRouter.prototype.subscribe = function(eventId, cb) {
 | |
| };
 | |
| ops.OperationRouter.prototype.unsubscribe = function(eventId, cb) {
 | |
| };
 | |
| ops.OperationRouter.prototype.hasLocalUnsyncedOps = function() {
 | |
| };
 | |
| ops.OperationRouter.prototype.hasSessionHostConnection = function() {
 | |
| };
 | |
| ops.OperationRouter.signalProcessingBatchStart = "router/batchstart";
 | |
| ops.OperationRouter.signalProcessingBatchEnd = "router/batchend";
 | |
| ops.TrivialOperationRouter = function TrivialOperationRouter() {
 | |
|   var events = new core.EventNotifier([ops.OperationRouter.signalProcessingBatchStart, ops.OperationRouter.signalProcessingBatchEnd]), operationFactory, playbackFunction, groupIdentifier = 0;
 | |
|   this.setOperationFactory = function(f) {
 | |
|     operationFactory = f;
 | |
|   };
 | |
|   this.setPlaybackFunction = function(playback_func) {
 | |
|     playbackFunction = playback_func;
 | |
|   };
 | |
|   this.push = function(operations) {
 | |
|     groupIdentifier += 1;
 | |
|     events.emit(ops.OperationRouter.signalProcessingBatchStart, {});
 | |
|     operations.forEach(function(op) {
 | |
|       var timedOp, opspec = op.spec();
 | |
|       opspec.timestamp = Date.now();
 | |
|       timedOp = operationFactory.create(opspec);
 | |
|       timedOp.group = "g" + groupIdentifier;
 | |
|       playbackFunction(timedOp);
 | |
|     });
 | |
|     events.emit(ops.OperationRouter.signalProcessingBatchEnd, {});
 | |
|   };
 | |
|   this.close = function(cb) {
 | |
|     cb();
 | |
|   };
 | |
|   this.subscribe = function(eventId, cb) {
 | |
|     events.subscribe(eventId, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventId, cb) {
 | |
|     events.unsubscribe(eventId, cb);
 | |
|   };
 | |
|   this.hasLocalUnsyncedOps = function() {
 | |
|     return false;
 | |
|   };
 | |
|   this.hasSessionHostConnection = function() {
 | |
|     return true;
 | |
|   };
 | |
| };
 | |
| ops.Session = function Session(odfCanvas) {
 | |
|   var self = this, operationFactory = new ops.OperationFactory, odtDocument = new ops.OdtDocument(odfCanvas), operationRouter = null;
 | |
|   function forwardBatchStart(args) {
 | |
|     odtDocument.emit(ops.OdtDocument.signalProcessingBatchStart, args);
 | |
|   }
 | |
|   function forwardBatchEnd(args) {
 | |
|     odtDocument.emit(ops.OdtDocument.signalProcessingBatchEnd, args);
 | |
|   }
 | |
|   this.setOperationFactory = function(opFactory) {
 | |
|     operationFactory = opFactory;
 | |
|     if (operationRouter) {
 | |
|       operationRouter.setOperationFactory(operationFactory);
 | |
|     }
 | |
|   };
 | |
|   this.setOperationRouter = function(opRouter) {
 | |
|     if (operationRouter) {
 | |
|       operationRouter.unsubscribe(ops.OperationRouter.signalProcessingBatchStart, forwardBatchStart);
 | |
|       operationRouter.unsubscribe(ops.OperationRouter.signalProcessingBatchEnd, forwardBatchEnd);
 | |
|     }
 | |
|     operationRouter = opRouter;
 | |
|     operationRouter.subscribe(ops.OperationRouter.signalProcessingBatchStart, forwardBatchStart);
 | |
|     operationRouter.subscribe(ops.OperationRouter.signalProcessingBatchEnd, forwardBatchEnd);
 | |
|     opRouter.setPlaybackFunction(function(op) {
 | |
|       odtDocument.emit(ops.OdtDocument.signalOperationStart, op);
 | |
|       if (op.execute(odtDocument)) {
 | |
|         odtDocument.emit(ops.OdtDocument.signalOperationEnd, op);
 | |
|         return true;
 | |
|       }
 | |
|       return false;
 | |
|     });
 | |
|     opRouter.setOperationFactory(operationFactory);
 | |
|   };
 | |
|   this.getOperationFactory = function() {
 | |
|     return operationFactory;
 | |
|   };
 | |
|   this.getOdtDocument = function() {
 | |
|     return odtDocument;
 | |
|   };
 | |
|   this.enqueue = function(ops) {
 | |
|     operationRouter.push(ops);
 | |
|   };
 | |
|   this.close = function(callback) {
 | |
|     operationRouter.close(function(err) {
 | |
|       if (err) {
 | |
|         callback(err);
 | |
|       } else {
 | |
|         odtDocument.close(callback);
 | |
|       }
 | |
|     });
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.destroy(callback);
 | |
|   };
 | |
|   function init() {
 | |
|     self.setOperationRouter(new ops.TrivialOperationRouter);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.AnnotationController = function AnnotationController(session, sessionConstraints, inputMemberId) {
 | |
|   var odtDocument = session.getOdtDocument(), isAnnotatable = false, eventNotifier = new core.EventNotifier([gui.AnnotationController.annotatableChanged]), odfUtils = odf.OdfUtils, NEXT = core.StepDirection.NEXT;
 | |
|   function updatedCachedValues() {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), cursorNode = cursor && cursor.getNode(), newIsAnnotatable = false;
 | |
|     if (cursorNode) {
 | |
|       newIsAnnotatable = !odfUtils.isWithinAnnotation(cursorNode, odtDocument.getRootNode());
 | |
|     }
 | |
|     if (newIsAnnotatable !== isAnnotatable) {
 | |
|       isAnnotatable = newIsAnnotatable;
 | |
|       eventNotifier.emit(gui.AnnotationController.annotatableChanged, isAnnotatable);
 | |
|     }
 | |
|   }
 | |
|   function onCursorAdded(cursor) {
 | |
|     if (cursor.getMemberId() === inputMemberId) {
 | |
|       updatedCachedValues();
 | |
|     }
 | |
|   }
 | |
|   function onCursorRemoved(memberId) {
 | |
|     if (memberId === inputMemberId) {
 | |
|       updatedCachedValues();
 | |
|     }
 | |
|   }
 | |
|   function onCursorMoved(cursor) {
 | |
|     if (cursor.getMemberId() === inputMemberId) {
 | |
|       updatedCachedValues();
 | |
|     }
 | |
|   }
 | |
|   this.isAnnotatable = function() {
 | |
|     return isAnnotatable;
 | |
|   };
 | |
|   this.addAnnotation = function() {
 | |
|     var op = new ops.OpAddAnnotation, selection = odtDocument.getCursorSelection(inputMemberId), length = selection.length, position = selection.position;
 | |
|     if (!isAnnotatable) {
 | |
|       return;
 | |
|     }
 | |
|     if (length === 0) {
 | |
|       length = undefined;
 | |
|     } else {
 | |
|       position = length >= 0 ? position : position + length;
 | |
|       length = Math.abs(length);
 | |
|     }
 | |
|     op.init({memberid:inputMemberId, position:position, length:length, name:inputMemberId + Date.now()});
 | |
|     session.enqueue([op]);
 | |
|   };
 | |
|   this.removeAnnotation = function(annotationNode) {
 | |
|     var startStep, endStep, op, moveCursor, currentUserName = odtDocument.getMember(inputMemberId).getProperties().fullName;
 | |
|     if (sessionConstraints.getState(gui.CommonConstraints.EDIT.ANNOTATIONS.ONLY_DELETE_OWN) === true) {
 | |
|       if (currentUserName !== odfUtils.getAnnotationCreator(annotationNode)) {
 | |
|         return;
 | |
|       }
 | |
|     }
 | |
|     startStep = odtDocument.convertDomPointToCursorStep(annotationNode, 0, NEXT);
 | |
|     endStep = odtDocument.convertDomPointToCursorStep(annotationNode, annotationNode.childNodes.length);
 | |
|     op = new ops.OpRemoveAnnotation;
 | |
|     op.init({memberid:inputMemberId, position:startStep, length:endStep - startStep});
 | |
|     moveCursor = new ops.OpMoveCursor;
 | |
|     moveCursor.init({memberid:inputMemberId, position:startStep > 0 ? startStep - 1 : startStep, length:0});
 | |
|     session.enqueue([op, moveCursor]);
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     eventNotifier.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     eventNotifier.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorAdded);
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorMoved);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     sessionConstraints.registerConstraint(gui.CommonConstraints.EDIT.ANNOTATIONS.ONLY_DELETE_OWN);
 | |
|     odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorAdded);
 | |
|     odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
 | |
|     odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorMoved);
 | |
|     updatedCachedValues();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.AnnotationController.annotatableChanged = "annotatable/changed";
 | |
| gui.Avatar = function Avatar(parentElement, avatarInitiallyVisible) {
 | |
|   var self = this, handle, image, pendingImageUrl, displayShown = "block", displayHidden = "none";
 | |
|   this.setColor = function(color) {
 | |
|     image.style.borderColor = color;
 | |
|   };
 | |
|   this.setImageUrl = function(url) {
 | |
|     if (self.isVisible()) {
 | |
|       image.src = url;
 | |
|     } else {
 | |
|       pendingImageUrl = url;
 | |
|     }
 | |
|   };
 | |
|   this.isVisible = function() {
 | |
|     return handle.style.display === displayShown;
 | |
|   };
 | |
|   this.show = function() {
 | |
|     if (pendingImageUrl) {
 | |
|       image.src = pendingImageUrl;
 | |
|       pendingImageUrl = undefined;
 | |
|     }
 | |
|     handle.style.display = displayShown;
 | |
|   };
 | |
|   this.hide = function() {
 | |
|     handle.style.display = displayHidden;
 | |
|   };
 | |
|   this.markAsFocussed = function(isFocussed) {
 | |
|     if (isFocussed) {
 | |
|       handle.classList.add("active");
 | |
|     } else {
 | |
|       handle.classList.remove("active");
 | |
|     }
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     parentElement.removeChild(handle);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     var document = (parentElement.ownerDocument);
 | |
|     handle = (document.createElement("div"));
 | |
|     image = (document.createElement("img"));
 | |
|     handle.appendChild(image);
 | |
|     handle.style.display = avatarInitiallyVisible ? displayShown : displayHidden;
 | |
|     handle.className = "handle";
 | |
|     parentElement.appendChild(handle);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.StepInfo = function() {
 | |
| };
 | |
| gui.StepInfo.VisualDirection = {LEFT_TO_RIGHT:0, RIGHT_TO_LEFT:1};
 | |
| gui.StepInfo.prototype.token;
 | |
| gui.StepInfo.prototype.container = function() {
 | |
| };
 | |
| gui.StepInfo.prototype.offset = function() {
 | |
| };
 | |
| gui.StepInfo.prototype.direction;
 | |
| gui.StepInfo.prototype.visualDirection;
 | |
| gui.VisualStepScanner = function() {
 | |
| };
 | |
| gui.VisualStepScanner.prototype.token;
 | |
| gui.VisualStepScanner.prototype.process = function(stepInfo, previousRect, nextRect) {
 | |
| };
 | |
| gui.GuiStepUtils = function GuiStepUtils() {
 | |
|   var odfUtils = odf.OdfUtils, stepUtils = new odf.StepUtils, domUtils = core.DomUtils, NEXT = core.StepDirection.NEXT, LEFT_TO_RIGHT = gui.StepInfo.VisualDirection.LEFT_TO_RIGHT, RIGHT_TO_LEFT = gui.StepInfo.VisualDirection.RIGHT_TO_LEFT;
 | |
|   function getContentRect(stepIterator) {
 | |
|     var bounds = stepUtils.getContentBounds(stepIterator), range, rect = null;
 | |
|     if (bounds) {
 | |
|       if (bounds.container.nodeType === Node.TEXT_NODE) {
 | |
|         range = bounds.container.ownerDocument.createRange();
 | |
|         range.setStart(bounds.container, bounds.startOffset);
 | |
|         range.setEnd(bounds.container, bounds.endOffset);
 | |
|         rect = range.getClientRects().length > 0 ? range.getBoundingClientRect() : null;
 | |
|         if (rect && (bounds.container).data.substring(bounds.startOffset, bounds.endOffset) === " " && rect.width <= 1) {
 | |
|           rect = null;
 | |
|         }
 | |
|         range.detach();
 | |
|       } else {
 | |
|         if (odfUtils.isCharacterElement(bounds.container) || odfUtils.isCharacterFrame(bounds.container)) {
 | |
|           rect = domUtils.getBoundingClientRect(bounds.container);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return rect;
 | |
|   }
 | |
|   this.getContentRect = getContentRect;
 | |
|   function moveToFilteredStep(stepIterator, direction, scanners) {
 | |
|     var isForward = direction === NEXT, leftRect, rightRect, previousRect, nextRect, destinationToken, initialToken = stepIterator.snapshot(), wasTerminated = false, stepInfo;
 | |
|     function process(terminated, scanner) {
 | |
|       if (scanner.process(stepInfo, previousRect, nextRect)) {
 | |
|         terminated = true;
 | |
|         if (!destinationToken && scanner.token) {
 | |
|           destinationToken = scanner.token;
 | |
|         }
 | |
|       }
 | |
|       return terminated;
 | |
|     }
 | |
|     do {
 | |
|       leftRect = getContentRect(stepIterator);
 | |
|       stepInfo = ({token:stepIterator.snapshot(), container:stepIterator.container, offset:stepIterator.offset, direction:direction, visualDirection:direction === NEXT ? LEFT_TO_RIGHT : RIGHT_TO_LEFT});
 | |
|       if (stepIterator.nextStep()) {
 | |
|         rightRect = getContentRect(stepIterator);
 | |
|       } else {
 | |
|         rightRect = null;
 | |
|       }
 | |
|       stepIterator.restore(stepInfo.token);
 | |
|       if (isForward) {
 | |
|         previousRect = leftRect;
 | |
|         nextRect = rightRect;
 | |
|       } else {
 | |
|         previousRect = rightRect;
 | |
|         nextRect = leftRect;
 | |
|       }
 | |
|       wasTerminated = scanners.reduce(process, false);
 | |
|     } while (!wasTerminated && stepIterator.advanceStep(direction));
 | |
|     if (!wasTerminated) {
 | |
|       scanners.forEach(function(scanner) {
 | |
|         if (!destinationToken && scanner.token) {
 | |
|           destinationToken = scanner.token;
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     stepIterator.restore(destinationToken || initialToken);
 | |
|     return Boolean(destinationToken);
 | |
|   }
 | |
|   this.moveToFilteredStep = moveToFilteredStep;
 | |
| };
 | |
| gui.Caret = function Caret(cursor, viewport, avatarInitiallyVisible, blinkOnRangeSelect) {
 | |
|   var cursorns = "urn:webodf:names:cursor", MIN_OVERLAY_HEIGHT_PX = 8, BLINK_PERIOD_MS = 500, caretOverlay, caretElement, avatar, overlayElement, caretSizer, caretSizerRange, canvas = cursor.getDocument().getCanvas(), domUtils = core.DomUtils, guiStepUtils = new gui.GuiStepUtils, stepIterator, redrawTask, blinkTask, shouldResetBlink = false, shouldCheckCaretVisibility = false, shouldUpdateCaretSize = false, state = {isFocused:false, isShown:true, visibility:"hidden"}, lastState = {isFocused:!state.isFocused, 
 | |
|   isShown:!state.isShown, visibility:"hidden"};
 | |
|   function blinkCaret() {
 | |
|     caretElement.style.opacity = caretElement.style.opacity === "0" ? "1" : "0";
 | |
|     blinkTask.trigger();
 | |
|   }
 | |
|   function getCaretSizeFromCursor() {
 | |
|     caretSizerRange.selectNodeContents(caretSizer);
 | |
|     return caretSizerRange.getBoundingClientRect();
 | |
|   }
 | |
|   function getSelectionRect() {
 | |
|     var node = cursor.getNode(), caretRectangle, nextRectangle, selectionRectangle, rootRect = (domUtils.getBoundingClientRect(canvas.getSizer())), useLeftEdge = false, width = 0;
 | |
|     node.removeAttributeNS(cursorns, "caret-sizer-active");
 | |
|     if (node.getClientRects().length > 0) {
 | |
|       selectionRectangle = getCaretSizeFromCursor();
 | |
|       width = selectionRectangle.left - domUtils.getBoundingClientRect(node).left;
 | |
|       useLeftEdge = true;
 | |
|     } else {
 | |
|       stepIterator.setPosition(node, 0);
 | |
|       selectionRectangle = guiStepUtils.getContentRect(stepIterator);
 | |
|       if (!selectionRectangle && stepIterator.nextStep()) {
 | |
|         nextRectangle = guiStepUtils.getContentRect(stepIterator);
 | |
|         if (nextRectangle) {
 | |
|           selectionRectangle = nextRectangle;
 | |
|           useLeftEdge = true;
 | |
|         }
 | |
|       }
 | |
|       if (!selectionRectangle) {
 | |
|         node.setAttributeNS(cursorns, "caret-sizer-active", "true");
 | |
|         selectionRectangle = getCaretSizeFromCursor();
 | |
|         useLeftEdge = true;
 | |
|       }
 | |
|       if (!selectionRectangle) {
 | |
|         runtime.log("WARN: No suitable client rectangle found for visual caret for " + cursor.getMemberId());
 | |
|         while (node) {
 | |
|           if ((node).getClientRects().length > 0) {
 | |
|             selectionRectangle = domUtils.getBoundingClientRect(node);
 | |
|             useLeftEdge = true;
 | |
|             break;
 | |
|           }
 | |
|           node = node.parentNode;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     selectionRectangle = domUtils.translateRect((selectionRectangle), rootRect, canvas.getZoomLevel());
 | |
|     caretRectangle = {top:selectionRectangle.top, height:selectionRectangle.height, right:useLeftEdge ? selectionRectangle.left : selectionRectangle.right, width:domUtils.adaptRangeDifferenceToZoomLevel(width, canvas.getZoomLevel())};
 | |
|     return caretRectangle;
 | |
|   }
 | |
|   function updateOverlayHeightAndPosition() {
 | |
|     var selectionRect = getSelectionRect(), cursorStyle;
 | |
|     if (selectionRect.height < MIN_OVERLAY_HEIGHT_PX) {
 | |
|       selectionRect = {top:selectionRect.top - (MIN_OVERLAY_HEIGHT_PX - selectionRect.height) / 2, height:MIN_OVERLAY_HEIGHT_PX, right:selectionRect.right};
 | |
|     }
 | |
|     caretOverlay.style.height = selectionRect.height + "px";
 | |
|     caretOverlay.style.top = selectionRect.top + "px";
 | |
|     caretOverlay.style.left = selectionRect.right - selectionRect.width + "px";
 | |
|     caretOverlay.style.width = selectionRect.width ? selectionRect.width + "px" : "";
 | |
|     if (overlayElement) {
 | |
|       cursorStyle = runtime.getWindow().getComputedStyle(cursor.getNode(), null);
 | |
|       if (cursorStyle.font) {
 | |
|         overlayElement.style.font = cursorStyle.font;
 | |
|       } else {
 | |
|         overlayElement.style.fontStyle = cursorStyle.fontStyle;
 | |
|         overlayElement.style.fontVariant = cursorStyle.fontVariant;
 | |
|         overlayElement.style.fontWeight = cursorStyle.fontWeight;
 | |
|         overlayElement.style.fontSize = cursorStyle.fontSize;
 | |
|         overlayElement.style.lineHeight = cursorStyle.lineHeight;
 | |
|         overlayElement.style.fontFamily = cursorStyle.fontFamily;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function hasStateChanged(property) {
 | |
|     return lastState[property] !== state[property];
 | |
|   }
 | |
|   function saveState() {
 | |
|     Object.keys(state).forEach(function(key) {
 | |
|       lastState[key] = state[key];
 | |
|     });
 | |
|   }
 | |
|   function updateCaret() {
 | |
|     if (state.isShown === false || cursor.getSelectionType() !== ops.OdtCursor.RangeSelection || !blinkOnRangeSelect && !cursor.getSelectedRange().collapsed) {
 | |
|       state.visibility = "hidden";
 | |
|       caretElement.style.visibility = "hidden";
 | |
|       blinkTask.cancel();
 | |
|     } else {
 | |
|       state.visibility = "visible";
 | |
|       caretElement.style.visibility = "visible";
 | |
|       if (state.isFocused === false) {
 | |
|         caretElement.style.opacity = "1";
 | |
|         blinkTask.cancel();
 | |
|       } else {
 | |
|         if (shouldResetBlink || hasStateChanged("visibility")) {
 | |
|           caretElement.style.opacity = "1";
 | |
|           blinkTask.cancel();
 | |
|         }
 | |
|         blinkTask.trigger();
 | |
|       }
 | |
|     }
 | |
|     if (shouldUpdateCaretSize || shouldCheckCaretVisibility) {
 | |
|       updateOverlayHeightAndPosition();
 | |
|     }
 | |
|     if (state.isShown && shouldCheckCaretVisibility) {
 | |
|       viewport.scrollIntoView(caretElement.getBoundingClientRect());
 | |
|     }
 | |
|     if (hasStateChanged("isFocused")) {
 | |
|       avatar.markAsFocussed(state.isFocused);
 | |
|     }
 | |
|     saveState();
 | |
|     shouldResetBlink = false;
 | |
|     shouldCheckCaretVisibility = false;
 | |
|     shouldUpdateCaretSize = false;
 | |
|   }
 | |
|   this.handleUpdate = function() {
 | |
|     shouldUpdateCaretSize = true;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.refreshCursorBlinking = function() {
 | |
|     shouldResetBlink = true;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.setFocus = function() {
 | |
|     state.isFocused = true;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.removeFocus = function() {
 | |
|     state.isFocused = false;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.show = function() {
 | |
|     state.isShown = true;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.hide = function() {
 | |
|     state.isShown = false;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.setAvatarImageUrl = function(url) {
 | |
|     avatar.setImageUrl(url);
 | |
|   };
 | |
|   this.setColor = function(newColor) {
 | |
|     caretElement.style.borderColor = newColor;
 | |
|     avatar.setColor(newColor);
 | |
|   };
 | |
|   this.getCursor = function() {
 | |
|     return cursor;
 | |
|   };
 | |
|   this.getFocusElement = function() {
 | |
|     return caretElement;
 | |
|   };
 | |
|   this.toggleHandleVisibility = function() {
 | |
|     if (avatar.isVisible()) {
 | |
|       avatar.hide();
 | |
|     } else {
 | |
|       avatar.show();
 | |
|     }
 | |
|   };
 | |
|   this.showHandle = function() {
 | |
|     avatar.show();
 | |
|   };
 | |
|   this.hideHandle = function() {
 | |
|     avatar.hide();
 | |
|   };
 | |
|   this.setOverlayElement = function(element) {
 | |
|     overlayElement = element;
 | |
|     caretOverlay.appendChild(element);
 | |
|     shouldUpdateCaretSize = true;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.ensureVisible = function() {
 | |
|     shouldCheckCaretVisibility = true;
 | |
|     redrawTask.trigger();
 | |
|   };
 | |
|   this.getBoundingClientRect = function() {
 | |
|     return domUtils.getBoundingClientRect(caretOverlay);
 | |
|   };
 | |
|   function destroy(callback) {
 | |
|     caretOverlay.parentNode.removeChild(caretOverlay);
 | |
|     caretSizer.parentNode.removeChild(caretSizer);
 | |
|     callback();
 | |
|   }
 | |
|   this.destroy = function(callback) {
 | |
|     var cleanup = [redrawTask.destroy, blinkTask.destroy, avatar.destroy, destroy];
 | |
|     core.Async.destroyAll(cleanup, callback);
 | |
|   };
 | |
|   function init() {
 | |
|     var odtDocument = (cursor.getDocument()), positionFilters = [odtDocument.createRootFilter(cursor.getMemberId()), odtDocument.getPositionFilter()], dom = odtDocument.getDOMDocument(), editinfons = "urn:webodf:names:editinfo";
 | |
|     caretSizerRange = (dom.createRange());
 | |
|     caretSizer = dom.createElement("span");
 | |
|     caretSizer.className = "webodf-caretSizer";
 | |
|     caretSizer.textContent = "|";
 | |
|     cursor.getNode().appendChild(caretSizer);
 | |
|     caretOverlay = (dom.createElement("div"));
 | |
|     caretOverlay.setAttributeNS(editinfons, "editinfo:memberid", cursor.getMemberId());
 | |
|     caretOverlay.className = "webodf-caretOverlay";
 | |
|     caretElement = (dom.createElement("div"));
 | |
|     caretElement.className = "caret";
 | |
|     caretOverlay.appendChild(caretElement);
 | |
|     avatar = new gui.Avatar(caretOverlay, avatarInitiallyVisible);
 | |
|     canvas.getSizer().appendChild(caretOverlay);
 | |
|     stepIterator = odtDocument.createStepIterator(cursor.getNode(), 0, positionFilters, odtDocument.getRootNode());
 | |
|     redrawTask = core.Task.createRedrawTask(updateCaret);
 | |
|     blinkTask = core.Task.createTimeoutTask(blinkCaret, BLINK_PERIOD_MS);
 | |
|     redrawTask.triggerImmediate();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.TextSerializer = function TextSerializer() {
 | |
|   var self = this, odfUtils = odf.OdfUtils;
 | |
|   function serializeNode(node) {
 | |
|     var s = "", accept = self.filter ? self.filter.acceptNode(node) : NodeFilter.FILTER_ACCEPT, nodeType = node.nodeType, child;
 | |
|     if ((accept === NodeFilter.FILTER_ACCEPT || accept === NodeFilter.FILTER_SKIP) && odfUtils.isTextContentContainingNode(node)) {
 | |
|       child = node.firstChild;
 | |
|       while (child) {
 | |
|         s += serializeNode(child);
 | |
|         child = child.nextSibling;
 | |
|       }
 | |
|     }
 | |
|     if (accept === NodeFilter.FILTER_ACCEPT) {
 | |
|       if (nodeType === Node.ELEMENT_NODE && odfUtils.isParagraph(node)) {
 | |
|         s += "\n";
 | |
|       } else {
 | |
|         if (nodeType === Node.TEXT_NODE && node.textContent) {
 | |
|           s += node.textContent;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return s;
 | |
|   }
 | |
|   this.filter = null;
 | |
|   this.writeToString = function(node) {
 | |
|     var plainText;
 | |
|     if (!node) {
 | |
|       return "";
 | |
|     }
 | |
|     plainText = serializeNode(node);
 | |
|     if (plainText[plainText.length - 1] === "\n") {
 | |
|       plainText = plainText.substr(0, plainText.length - 1);
 | |
|     }
 | |
|     return plainText;
 | |
|   };
 | |
| };
 | |
| gui.MimeDataExporter = function MimeDataExporter() {
 | |
|   var textSerializer;
 | |
|   this.exportRangeToDataTransfer = function(dataTransfer, range) {
 | |
|     var document = range.startContainer.ownerDocument, serializedFragment, fragmentContainer;
 | |
|     fragmentContainer = document.createElement("span");
 | |
|     fragmentContainer.appendChild(range.cloneContents());
 | |
|     serializedFragment = textSerializer.writeToString(fragmentContainer);
 | |
|     try {
 | |
|       dataTransfer.setData("text/plain", serializedFragment);
 | |
|     } catch (e) {
 | |
|       dataTransfer.setData("Text", serializedFragment);
 | |
|     }
 | |
|   };
 | |
|   function init() {
 | |
|     textSerializer = new odf.TextSerializer;
 | |
|     textSerializer.filter = new odf.OdfNodeFilter;
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.Clipboard = function Clipboard(mimeDataExporter) {
 | |
|   this.setDataFromRange = function(e, range) {
 | |
|     var result, clipboard = e.clipboardData, window = runtime.getWindow();
 | |
|     if (!clipboard && window) {
 | |
|       clipboard = window.clipboardData;
 | |
|     }
 | |
|     if (clipboard) {
 | |
|       result = true;
 | |
|       mimeDataExporter.exportRangeToDataTransfer((clipboard), range);
 | |
|       e.preventDefault();
 | |
|     } else {
 | |
|       result = false;
 | |
|     }
 | |
|     return result;
 | |
|   };
 | |
| };
 | |
| gui.SessionContext = function(session, inputMemberId) {
 | |
|   var odtDocument = session.getOdtDocument(), odfUtils = odf.OdfUtils;
 | |
|   this.isLocalCursorWithinOwnAnnotation = function() {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), cursorNode, currentUserName, parentAnnotation;
 | |
|     if (!cursor) {
 | |
|       return false;
 | |
|     }
 | |
|     cursorNode = cursor && cursor.getNode();
 | |
|     currentUserName = odtDocument.getMember(inputMemberId).getProperties().fullName;
 | |
|     parentAnnotation = odfUtils.getParentAnnotation(cursorNode, odtDocument.getRootNode());
 | |
|     if (parentAnnotation && odfUtils.getAnnotationCreator(parentAnnotation) === currentUserName) {
 | |
|       return true;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
| };
 | |
| gui.StyleSummary = function StyleSummary(styles) {
 | |
|   var propertyValues = {};
 | |
|   function getPropertyValues(section, propertyName) {
 | |
|     var cacheKey = section + "|" + propertyName, values;
 | |
|     if (!propertyValues.hasOwnProperty(cacheKey)) {
 | |
|       values = [];
 | |
|       styles.forEach(function(style) {
 | |
|         var styleSection = (style.styleProperties[section]), value = styleSection && styleSection[propertyName];
 | |
|         if (values.indexOf(value) === -1) {
 | |
|           values.push(value);
 | |
|         }
 | |
|       });
 | |
|       propertyValues[cacheKey] = values;
 | |
|     }
 | |
|     return propertyValues[cacheKey];
 | |
|   }
 | |
|   this.getPropertyValues = getPropertyValues;
 | |
|   function lazilyLoaded(section, propertyName, acceptedPropertyValues) {
 | |
|     return function() {
 | |
|       var existingPropertyValues = getPropertyValues(section, propertyName);
 | |
|       return acceptedPropertyValues.length >= existingPropertyValues.length && existingPropertyValues.every(function(v) {
 | |
|         return acceptedPropertyValues.indexOf(v) !== -1;
 | |
|       });
 | |
|     };
 | |
|   }
 | |
|   function getCommonValue(section, propertyName) {
 | |
|     var values = getPropertyValues(section, propertyName);
 | |
|     return values.length === 1 ? values[0] : undefined;
 | |
|   }
 | |
|   this.getCommonValue = getCommonValue;
 | |
|   this.isBold = lazilyLoaded("style:text-properties", "fo:font-weight", ["bold"]);
 | |
|   this.isItalic = lazilyLoaded("style:text-properties", "fo:font-style", ["italic"]);
 | |
|   this.hasUnderline = lazilyLoaded("style:text-properties", "style:text-underline-style", ["solid"]);
 | |
|   this.hasStrikeThrough = lazilyLoaded("style:text-properties", "style:text-line-through-style", ["solid"]);
 | |
|   this.fontSize = function() {
 | |
|     var stringFontSize = getCommonValue("style:text-properties", "fo:font-size");
 | |
|     return (stringFontSize && parseFloat(stringFontSize));
 | |
|   };
 | |
|   this.fontName = function() {
 | |
|     return getCommonValue("style:text-properties", "style:font-name");
 | |
|   };
 | |
|   this.isAlignedLeft = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["left", "start"]);
 | |
|   this.isAlignedCenter = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["center"]);
 | |
|   this.isAlignedRight = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["right", "end"]);
 | |
|   this.isAlignedJustified = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["justify"]);
 | |
|   this.text = {isBold:this.isBold, isItalic:this.isItalic, hasUnderline:this.hasUnderline, hasStrikeThrough:this.hasStrikeThrough, fontSize:this.fontSize, fontName:this.fontName};
 | |
|   this.paragraph = {isAlignedLeft:this.isAlignedLeft, isAlignedCenter:this.isAlignedCenter, isAlignedRight:this.isAlignedRight, isAlignedJustified:this.isAlignedJustified};
 | |
| };
 | |
| gui.DirectFormattingController = function DirectFormattingController(session, sessionConstraints, sessionContext, inputMemberId, objectNameGenerator, directTextStylingEnabled, directParagraphStylingEnabled) {
 | |
|   var self = this, odtDocument = session.getOdtDocument(), utils = new core.Utils, odfUtils = odf.OdfUtils, eventNotifier = new core.EventNotifier([gui.DirectFormattingController.enabledChanged, gui.DirectFormattingController.textStylingChanged, gui.DirectFormattingController.paragraphStylingChanged]), textns = odf.Namespaces.textns, NEXT = core.StepDirection.NEXT, directCursorStyleProperties = null, lastSignalledSelectionInfo, selectionInfoCache;
 | |
|   function getCachedStyleSummary() {
 | |
|     return selectionInfoCache.value().styleSummary;
 | |
|   }
 | |
|   function getCachedEnabledFeatures() {
 | |
|     return selectionInfoCache.value().enabledFeatures;
 | |
|   }
 | |
|   this.enabledFeatures = getCachedEnabledFeatures;
 | |
|   function getNodes(range) {
 | |
|     var container, nodes;
 | |
|     if (range.collapsed) {
 | |
|       container = range.startContainer;
 | |
|       if (container.hasChildNodes() && range.startOffset < container.childNodes.length) {
 | |
|         container = container.childNodes.item(range.startOffset);
 | |
|       }
 | |
|       nodes = [container];
 | |
|     } else {
 | |
|       nodes = odfUtils.getTextElements(range, true, false);
 | |
|     }
 | |
|     return nodes;
 | |
|   }
 | |
|   function getSelectionInfo() {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), range = cursor && cursor.getSelectedRange(), nodes = [], selectionStyles = [], selectionContainsText = true, enabledFeatures = {directTextStyling:true, directParagraphStyling:true};
 | |
|     if (range) {
 | |
|       nodes = getNodes(range);
 | |
|       if (nodes.length === 0) {
 | |
|         nodes = [range.startContainer, range.endContainer];
 | |
|         selectionContainsText = false;
 | |
|       }
 | |
|       selectionStyles = odtDocument.getFormatting().getAppliedStyles(nodes);
 | |
|     }
 | |
|     if (selectionStyles[0] !== undefined && directCursorStyleProperties) {
 | |
|       selectionStyles[0].styleProperties = utils.mergeObjects(selectionStyles[0].styleProperties, directCursorStyleProperties);
 | |
|     }
 | |
|     if (sessionConstraints.getState(gui.CommonConstraints.EDIT.REVIEW_MODE) === true) {
 | |
|       enabledFeatures.directTextStyling = enabledFeatures.directParagraphStyling = (sessionContext.isLocalCursorWithinOwnAnnotation());
 | |
|     }
 | |
|     if (enabledFeatures.directTextStyling) {
 | |
|       enabledFeatures.directTextStyling = selectionContainsText && cursor !== undefined && cursor.getSelectionType() === ops.OdtCursor.RangeSelection;
 | |
|     }
 | |
|     return ({enabledFeatures:enabledFeatures, appliedStyles:selectionStyles, styleSummary:new gui.StyleSummary(selectionStyles)});
 | |
|   }
 | |
|   function createDiff(oldSummary, newSummary) {
 | |
|     var diffMap = {};
 | |
|     Object.keys(oldSummary).forEach(function(funcName) {
 | |
|       var oldValue = oldSummary[funcName](), newValue = newSummary[funcName]();
 | |
|       if (oldValue !== newValue) {
 | |
|         diffMap[funcName] = newValue;
 | |
|       }
 | |
|     });
 | |
|     return diffMap;
 | |
|   }
 | |
|   function emitSelectionChanges() {
 | |
|     var textStyleDiff, paragraphStyleDiff, lastStyleSummary = lastSignalledSelectionInfo.styleSummary, newSelectionInfo = selectionInfoCache.value(), newSelectionStylesSummary = newSelectionInfo.styleSummary, lastEnabledFeatures = lastSignalledSelectionInfo.enabledFeatures, newEnabledFeatures = newSelectionInfo.enabledFeatures, enabledFeaturesChanged;
 | |
|     textStyleDiff = createDiff(lastStyleSummary.text, newSelectionStylesSummary.text);
 | |
|     paragraphStyleDiff = createDiff(lastStyleSummary.paragraph, newSelectionStylesSummary.paragraph);
 | |
|     enabledFeaturesChanged = !(newEnabledFeatures.directTextStyling === lastEnabledFeatures.directTextStyling && newEnabledFeatures.directParagraphStyling === lastEnabledFeatures.directParagraphStyling);
 | |
|     lastSignalledSelectionInfo = newSelectionInfo;
 | |
|     if (enabledFeaturesChanged) {
 | |
|       eventNotifier.emit(gui.DirectFormattingController.enabledChanged, newEnabledFeatures);
 | |
|     }
 | |
|     if (Object.keys(textStyleDiff).length > 0) {
 | |
|       eventNotifier.emit(gui.DirectFormattingController.textStylingChanged, textStyleDiff);
 | |
|     }
 | |
|     if (Object.keys(paragraphStyleDiff).length > 0) {
 | |
|       eventNotifier.emit(gui.DirectFormattingController.paragraphStylingChanged, paragraphStyleDiff);
 | |
|     }
 | |
|   }
 | |
|   function forceSelectionInfoRefresh() {
 | |
|     selectionInfoCache.reset();
 | |
|     emitSelectionChanges();
 | |
|   }
 | |
|   function onCursorEvent(cursorOrId) {
 | |
|     var cursorMemberId = typeof cursorOrId === "string" ? cursorOrId : cursorOrId.getMemberId();
 | |
|     if (cursorMemberId === inputMemberId) {
 | |
|       selectionInfoCache.reset();
 | |
|     }
 | |
|   }
 | |
|   function onParagraphStyleModified() {
 | |
|     selectionInfoCache.reset();
 | |
|   }
 | |
|   function onParagraphChanged(args) {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), p = args.paragraphElement;
 | |
|     if (cursor && odfUtils.getParagraphElement(cursor.getNode()) === p) {
 | |
|       selectionInfoCache.reset();
 | |
|     }
 | |
|   }
 | |
|   function toggle(predicate, toggleMethod) {
 | |
|     toggleMethod(!predicate());
 | |
|     return true;
 | |
|   }
 | |
|   function formatTextSelection(textProperties) {
 | |
|     if (!getCachedEnabledFeatures().directTextStyling) {
 | |
|       return;
 | |
|     }
 | |
|     var selection = odtDocument.getCursorSelection(inputMemberId), op, properties = {"style:text-properties":textProperties};
 | |
|     if (selection.length !== 0) {
 | |
|       op = new ops.OpApplyDirectStyling;
 | |
|       op.init({memberid:inputMemberId, position:selection.position, length:selection.length, setProperties:properties});
 | |
|       session.enqueue([op]);
 | |
|     } else {
 | |
|       directCursorStyleProperties = utils.mergeObjects(directCursorStyleProperties || {}, properties);
 | |
|       selectionInfoCache.reset();
 | |
|     }
 | |
|   }
 | |
|   this.formatTextSelection = formatTextSelection;
 | |
|   function applyTextPropertyToSelection(propertyName, propertyValue) {
 | |
|     var textProperties = {};
 | |
|     textProperties[propertyName] = propertyValue;
 | |
|     formatTextSelection(textProperties);
 | |
|   }
 | |
|   this.createCursorStyleOp = function(position, length, useCachedStyle) {
 | |
|     var styleOp = null, appliedStyles, properties = directCursorStyleProperties;
 | |
|     if (useCachedStyle) {
 | |
|       appliedStyles = selectionInfoCache.value().appliedStyles[0];
 | |
|       properties = appliedStyles && appliedStyles.styleProperties;
 | |
|     }
 | |
|     if (properties && properties["style:text-properties"]) {
 | |
|       styleOp = new ops.OpApplyDirectStyling;
 | |
|       styleOp.init({memberid:inputMemberId, position:position, length:length, setProperties:{"style:text-properties":properties["style:text-properties"]}});
 | |
|       directCursorStyleProperties = null;
 | |
|       selectionInfoCache.reset();
 | |
|     }
 | |
|     return styleOp;
 | |
|   };
 | |
|   function clearCursorStyle(op) {
 | |
|     var spec = op.spec();
 | |
|     if (directCursorStyleProperties && spec.memberid === inputMemberId) {
 | |
|       if (spec.optype !== "SplitParagraph") {
 | |
|         directCursorStyleProperties = null;
 | |
|         selectionInfoCache.reset();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function setBold(checked) {
 | |
|     var value = checked ? "bold" : "normal";
 | |
|     applyTextPropertyToSelection("fo:font-weight", value);
 | |
|   }
 | |
|   this.setBold = setBold;
 | |
|   function setItalic(checked) {
 | |
|     var value = checked ? "italic" : "normal";
 | |
|     applyTextPropertyToSelection("fo:font-style", value);
 | |
|   }
 | |
|   this.setItalic = setItalic;
 | |
|   function setHasUnderline(checked) {
 | |
|     var value = checked ? "solid" : "none";
 | |
|     applyTextPropertyToSelection("style:text-underline-style", value);
 | |
|   }
 | |
|   this.setHasUnderline = setHasUnderline;
 | |
|   function setHasStrikethrough(checked) {
 | |
|     var value = checked ? "solid" : "none";
 | |
|     applyTextPropertyToSelection("style:text-line-through-style", value);
 | |
|   }
 | |
|   this.setHasStrikethrough = setHasStrikethrough;
 | |
|   function setFontSize(value) {
 | |
|     applyTextPropertyToSelection("fo:font-size", value + "pt");
 | |
|   }
 | |
|   this.setFontSize = setFontSize;
 | |
|   function setFontName(value) {
 | |
|     applyTextPropertyToSelection("style:font-name", value);
 | |
|   }
 | |
|   this.setFontName = setFontName;
 | |
|   this.getAppliedStyles = function() {
 | |
|     return selectionInfoCache.value().appliedStyles;
 | |
|   };
 | |
|   this.toggleBold = toggle.bind(self, function() {
 | |
|     return getCachedStyleSummary().isBold();
 | |
|   }, setBold);
 | |
|   this.toggleItalic = toggle.bind(self, function() {
 | |
|     return getCachedStyleSummary().isItalic();
 | |
|   }, setItalic);
 | |
|   this.toggleUnderline = toggle.bind(self, function() {
 | |
|     return getCachedStyleSummary().hasUnderline();
 | |
|   }, setHasUnderline);
 | |
|   this.toggleStrikethrough = toggle.bind(self, function() {
 | |
|     return getCachedStyleSummary().hasStrikeThrough();
 | |
|   }, setHasStrikethrough);
 | |
|   this.isBold = function() {
 | |
|     return getCachedStyleSummary().isBold();
 | |
|   };
 | |
|   this.isItalic = function() {
 | |
|     return getCachedStyleSummary().isItalic();
 | |
|   };
 | |
|   this.hasUnderline = function() {
 | |
|     return getCachedStyleSummary().hasUnderline();
 | |
|   };
 | |
|   this.hasStrikeThrough = function() {
 | |
|     return getCachedStyleSummary().hasStrikeThrough();
 | |
|   };
 | |
|   this.fontSize = function() {
 | |
|     return getCachedStyleSummary().fontSize();
 | |
|   };
 | |
|   this.fontName = function() {
 | |
|     return getCachedStyleSummary().fontName();
 | |
|   };
 | |
|   this.isAlignedLeft = function() {
 | |
|     return getCachedStyleSummary().isAlignedLeft();
 | |
|   };
 | |
|   this.isAlignedCenter = function() {
 | |
|     return getCachedStyleSummary().isAlignedCenter();
 | |
|   };
 | |
|   this.isAlignedRight = function() {
 | |
|     return getCachedStyleSummary().isAlignedRight();
 | |
|   };
 | |
|   this.isAlignedJustified = function() {
 | |
|     return getCachedStyleSummary().isAlignedJustified();
 | |
|   };
 | |
|   function getOwnProperty(obj, key) {
 | |
|     return obj.hasOwnProperty(key) ? obj[key] : undefined;
 | |
|   }
 | |
|   function applyParagraphDirectStyling(applyDirectStyling) {
 | |
|     if (!getCachedEnabledFeatures().directParagraphStyling) {
 | |
|       return;
 | |
|     }
 | |
|     var range = odtDocument.getCursor(inputMemberId).getSelectedRange(), paragraphs = odfUtils.getParagraphElements(range), formatting = odtDocument.getFormatting(), operations = [], derivedStyleNames = {}, defaultStyleName;
 | |
|     paragraphs.forEach(function(paragraph) {
 | |
|       var paragraphStartPoint = odtDocument.convertDomPointToCursorStep(paragraph, 0, NEXT), paragraphStyleName = paragraph.getAttributeNS(odf.Namespaces.textns, "style-name"), newParagraphStyleName, opAddStyle, opSetParagraphStyle, paragraphProperties;
 | |
|       if (paragraphStyleName) {
 | |
|         newParagraphStyleName = getOwnProperty(derivedStyleNames, paragraphStyleName);
 | |
|       } else {
 | |
|         newParagraphStyleName = defaultStyleName;
 | |
|       }
 | |
|       if (!newParagraphStyleName) {
 | |
|         newParagraphStyleName = objectNameGenerator.generateStyleName();
 | |
|         if (paragraphStyleName) {
 | |
|           derivedStyleNames[paragraphStyleName] = newParagraphStyleName;
 | |
|           paragraphProperties = formatting.createDerivedStyleObject(paragraphStyleName, "paragraph", {});
 | |
|         } else {
 | |
|           defaultStyleName = newParagraphStyleName;
 | |
|           paragraphProperties = {};
 | |
|         }
 | |
|         paragraphProperties = applyDirectStyling(paragraphProperties);
 | |
|         opAddStyle = new ops.OpAddStyle;
 | |
|         opAddStyle.init({memberid:inputMemberId, styleName:newParagraphStyleName.toString(), styleFamily:"paragraph", isAutomaticStyle:true, setProperties:paragraphProperties});
 | |
|         operations.push(opAddStyle);
 | |
|       }
 | |
|       opSetParagraphStyle = new ops.OpSetParagraphStyle;
 | |
|       opSetParagraphStyle.init({memberid:inputMemberId, styleName:newParagraphStyleName.toString(), position:paragraphStartPoint});
 | |
|       operations.push(opSetParagraphStyle);
 | |
|     });
 | |
|     session.enqueue(operations);
 | |
|   }
 | |
|   function applySimpleParagraphDirectStyling(styleOverrides) {
 | |
|     applyParagraphDirectStyling(function(paragraphStyle) {
 | |
|       return (utils.mergeObjects(paragraphStyle, styleOverrides));
 | |
|     });
 | |
|   }
 | |
|   function alignParagraph(alignment) {
 | |
|     applySimpleParagraphDirectStyling({"style:paragraph-properties":{"fo:text-align":alignment}});
 | |
|   }
 | |
|   this.alignParagraphLeft = function() {
 | |
|     alignParagraph("left");
 | |
|     return true;
 | |
|   };
 | |
|   this.alignParagraphCenter = function() {
 | |
|     alignParagraph("center");
 | |
|     return true;
 | |
|   };
 | |
|   this.alignParagraphRight = function() {
 | |
|     alignParagraph("right");
 | |
|     return true;
 | |
|   };
 | |
|   this.alignParagraphJustified = function() {
 | |
|     alignParagraph("justify");
 | |
|     return true;
 | |
|   };
 | |
|   function modifyParagraphIndent(direction, paragraphStyle) {
 | |
|     var tabStopDistance = odtDocument.getFormatting().getDefaultTabStopDistance(), paragraphProperties = paragraphStyle["style:paragraph-properties"], indentValue, indent, newIndent;
 | |
|     if (paragraphProperties) {
 | |
|       indentValue = (paragraphProperties["fo:margin-left"]);
 | |
|       indent = odfUtils.parseLength(indentValue);
 | |
|     }
 | |
|     if (indent && indent.unit === tabStopDistance.unit) {
 | |
|       newIndent = indent.value + direction * tabStopDistance.value + indent.unit;
 | |
|     } else {
 | |
|       newIndent = direction * tabStopDistance.value + tabStopDistance.unit;
 | |
|     }
 | |
|     return (utils.mergeObjects(paragraphStyle, {"style:paragraph-properties":{"fo:margin-left":newIndent}}));
 | |
|   }
 | |
|   this.indent = function() {
 | |
|     applyParagraphDirectStyling(modifyParagraphIndent.bind(null, 1));
 | |
|     return true;
 | |
|   };
 | |
|   this.outdent = function() {
 | |
|     applyParagraphDirectStyling(modifyParagraphIndent.bind(null, -1));
 | |
|     return true;
 | |
|   };
 | |
|   function isSelectionAtTheEndOfLastParagraph(range, paragraphNode) {
 | |
|     var stepIterator, filters = [odtDocument.getPositionFilter(), odtDocument.createRootFilter(inputMemberId)];
 | |
|     stepIterator = odtDocument.createStepIterator((range.endContainer), range.endOffset, filters, paragraphNode);
 | |
|     return stepIterator.nextStep() === false;
 | |
|   }
 | |
|   function isTextStyleDifferentFromFirstParagraph(range, paragraphNode) {
 | |
|     var textNodes = getNodes(range), selectedNodes = textNodes.length === 0 ? [range.startContainer] : textNodes, appliedTextStyles = odtDocument.getFormatting().getAppliedStyles(selectedNodes), textStyle = appliedTextStyles.length > 0 ? appliedTextStyles[0].styleProperties : undefined, paragraphStyle = odtDocument.getFormatting().getAppliedStylesForElement(paragraphNode).styleProperties;
 | |
|     if (!textStyle || textStyle["style:family"] !== "text" || !textStyle["style:text-properties"]) {
 | |
|       return false;
 | |
|     }
 | |
|     if (!paragraphStyle || !paragraphStyle["style:text-properties"]) {
 | |
|       return true;
 | |
|     }
 | |
|     textStyle = (textStyle["style:text-properties"]);
 | |
|     paragraphStyle = (paragraphStyle["style:text-properties"]);
 | |
|     return !Object.keys(textStyle).every(function(key) {
 | |
|       return textStyle[key] === paragraphStyle[key];
 | |
|     });
 | |
|   }
 | |
|   this.createParagraphStyleOps = function(position) {
 | |
|     if (!getCachedEnabledFeatures().directParagraphStyling) {
 | |
|       return [];
 | |
|     }
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), range = cursor.getSelectedRange(), operations = [], op, startNode, endNode, paragraphNode, appliedStyles, properties, parentStyleName, styleName;
 | |
|     if (cursor.hasForwardSelection()) {
 | |
|       startNode = cursor.getAnchorNode();
 | |
|       endNode = cursor.getNode();
 | |
|     } else {
 | |
|       startNode = cursor.getNode();
 | |
|       endNode = cursor.getAnchorNode();
 | |
|     }
 | |
|     paragraphNode = (odfUtils.getParagraphElement(endNode));
 | |
|     runtime.assert(Boolean(paragraphNode), "DirectFormattingController: Cursor outside paragraph");
 | |
|     if (!isSelectionAtTheEndOfLastParagraph(range, paragraphNode)) {
 | |
|       return operations;
 | |
|     }
 | |
|     if (endNode !== startNode) {
 | |
|       paragraphNode = (odfUtils.getParagraphElement(startNode));
 | |
|     }
 | |
|     if (!directCursorStyleProperties && !isTextStyleDifferentFromFirstParagraph(range, paragraphNode)) {
 | |
|       return operations;
 | |
|     }
 | |
|     appliedStyles = selectionInfoCache.value().appliedStyles[0];
 | |
|     properties = appliedStyles && appliedStyles.styleProperties;
 | |
|     if (!properties) {
 | |
|       return operations;
 | |
|     }
 | |
|     parentStyleName = paragraphNode.getAttributeNS(textns, "style-name");
 | |
|     if (parentStyleName) {
 | |
|       properties = {"style:text-properties":properties["style:text-properties"]};
 | |
|       properties = odtDocument.getFormatting().createDerivedStyleObject(parentStyleName, "paragraph", properties);
 | |
|     }
 | |
|     styleName = objectNameGenerator.generateStyleName();
 | |
|     op = new ops.OpAddStyle;
 | |
|     op.init({memberid:inputMemberId, styleName:styleName, styleFamily:"paragraph", isAutomaticStyle:true, setProperties:properties});
 | |
|     operations.push(op);
 | |
|     op = new ops.OpSetParagraphStyle;
 | |
|     op.init({memberid:inputMemberId, styleName:styleName, position:position});
 | |
|     operations.push(op);
 | |
|     return operations;
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     eventNotifier.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     eventNotifier.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorEvent);
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorEvent);
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
 | |
|     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
 | |
|     odtDocument.unsubscribe(ops.OdtDocument.signalOperationEnd, clearCursorStyle);
 | |
|     odtDocument.unsubscribe(ops.OdtDocument.signalProcessingBatchEnd, emitSelectionChanges);
 | |
|     sessionConstraints.unsubscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, forceSelectionInfoRefresh);
 | |
|     callback();
 | |
|   };
 | |
|   function emptyFunction() {
 | |
|   }
 | |
|   function emptyBoolFunction() {
 | |
|     return false;
 | |
|   }
 | |
|   function emptyFalseReturningFunction() {
 | |
|     return false;
 | |
|   }
 | |
|   function getCachedSelectionInfo() {
 | |
|     return selectionInfoCache.value();
 | |
|   }
 | |
|   function init() {
 | |
|     odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorEvent);
 | |
|     odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorEvent);
 | |
|     odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
 | |
|     odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
 | |
|     odtDocument.subscribe(ops.OdtDocument.signalOperationEnd, clearCursorStyle);
 | |
|     odtDocument.subscribe(ops.OdtDocument.signalProcessingBatchEnd, emitSelectionChanges);
 | |
|     sessionConstraints.subscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, forceSelectionInfoRefresh);
 | |
|     selectionInfoCache = new core.LazyProperty(getSelectionInfo);
 | |
|     lastSignalledSelectionInfo = getCachedSelectionInfo();
 | |
|     if (!directTextStylingEnabled) {
 | |
|       self.formatTextSelection = emptyFunction;
 | |
|       self.setBold = emptyFunction;
 | |
|       self.setItalic = emptyFunction;
 | |
|       self.setHasUnderline = emptyFunction;
 | |
|       self.setHasStrikethrough = emptyFunction;
 | |
|       self.setFontSize = emptyFunction;
 | |
|       self.setFontName = emptyFunction;
 | |
|       self.toggleBold = emptyFalseReturningFunction;
 | |
|       self.toggleItalic = emptyFalseReturningFunction;
 | |
|       self.toggleUnderline = emptyFalseReturningFunction;
 | |
|       self.toggleStrikethrough = emptyFalseReturningFunction;
 | |
|     }
 | |
|     if (!directParagraphStylingEnabled) {
 | |
|       self.alignParagraphCenter = emptyBoolFunction;
 | |
|       self.alignParagraphJustified = emptyBoolFunction;
 | |
|       self.alignParagraphLeft = emptyBoolFunction;
 | |
|       self.alignParagraphRight = emptyBoolFunction;
 | |
|       self.createParagraphStyleOps = function() {
 | |
|         return [];
 | |
|       };
 | |
|       self.indent = emptyBoolFunction;
 | |
|       self.outdent = emptyBoolFunction;
 | |
|     }
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.DirectFormattingController.enabledChanged = "enabled/changed";
 | |
| gui.DirectFormattingController.textStylingChanged = "textStyling/changed";
 | |
| gui.DirectFormattingController.paragraphStylingChanged = "paragraphStyling/changed";
 | |
| gui.DirectFormattingController.SelectionInfo = function() {
 | |
|   this.enabledFeatures;
 | |
|   this.appliedStyles;
 | |
|   this.styleSummary;
 | |
| };
 | |
| gui.KeyboardHandler = function KeyboardHandler() {
 | |
|   var modifier = gui.KeyboardHandler.Modifier, defaultBinding = null, bindings = {};
 | |
|   function getModifiers(e) {
 | |
|     var modifiers = modifier.None;
 | |
|     if (e.metaKey) {
 | |
|       modifiers |= modifier.Meta;
 | |
|     }
 | |
|     if (e.ctrlKey) {
 | |
|       modifiers |= modifier.Ctrl;
 | |
|     }
 | |
|     if (e.altKey) {
 | |
|       modifiers |= modifier.Alt;
 | |
|     }
 | |
|     if (e.shiftKey) {
 | |
|       modifiers |= modifier.Shift;
 | |
|     }
 | |
|     return modifiers;
 | |
|   }
 | |
|   function getKeyCombo(keyCode, modifiers) {
 | |
|     if (!modifiers) {
 | |
|       modifiers = modifier.None;
 | |
|     }
 | |
|     switch(keyCode) {
 | |
|       case gui.KeyboardHandler.KeyCode.LeftMeta:
 | |
|       ;
 | |
|       case gui.KeyboardHandler.KeyCode.RightMeta:
 | |
|       ;
 | |
|       case gui.KeyboardHandler.KeyCode.MetaInMozilla:
 | |
|         modifiers |= modifier.Meta;
 | |
|         break;
 | |
|       case gui.KeyboardHandler.KeyCode.Ctrl:
 | |
|         modifiers |= modifier.Ctrl;
 | |
|         break;
 | |
|       case gui.KeyboardHandler.KeyCode.Alt:
 | |
|         modifiers |= modifier.Alt;
 | |
|         break;
 | |
|       case gui.KeyboardHandler.KeyCode.Shift:
 | |
|         modifiers |= modifier.Shift;
 | |
|         break;
 | |
|     }
 | |
|     return keyCode + ":" + modifiers;
 | |
|   }
 | |
|   this.setDefault = function(callback) {
 | |
|     defaultBinding = callback;
 | |
|   };
 | |
|   this.bind = function(keyCode, modifiers, callback, overwrite) {
 | |
|     var keyCombo = getKeyCombo(keyCode, modifiers);
 | |
|     runtime.assert(overwrite || bindings.hasOwnProperty(keyCombo) === false, "tried to overwrite the callback handler of key combo: " + keyCombo);
 | |
|     bindings[keyCombo] = callback;
 | |
|   };
 | |
|   this.unbind = function(keyCode, modifiers) {
 | |
|     var keyCombo = getKeyCombo(keyCode, modifiers);
 | |
|     delete bindings[keyCombo];
 | |
|   };
 | |
|   this.reset = function() {
 | |
|     defaultBinding = null;
 | |
|     bindings = {};
 | |
|   };
 | |
|   this.handleEvent = function(e) {
 | |
|     var keyCombo = getKeyCombo(e.keyCode, getModifiers(e)), callback = bindings[keyCombo], handled = false;
 | |
|     if (callback) {
 | |
|       handled = callback();
 | |
|     } else {
 | |
|       if (defaultBinding !== null) {
 | |
|         handled = defaultBinding(e);
 | |
|       }
 | |
|     }
 | |
|     if (handled) {
 | |
|       if (e.preventDefault) {
 | |
|         e.preventDefault();
 | |
|       } else {
 | |
|         e.returnValue = false;
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| };
 | |
| gui.KeyboardHandler.Modifier = {None:0, Meta:1, Ctrl:2, Alt:4, CtrlAlt:6, Shift:8, MetaShift:9, CtrlShift:10, AltShift:12};
 | |
| gui.KeyboardHandler.KeyCode = {Backspace:8, Tab:9, Clear:12, Enter:13, Shift:16, Ctrl:17, Alt:18, End:35, Home:36, Left:37, Up:38, Right:39, Down:40, Delete:46, A:65, B:66, C:67, D:68, E:69, F:70, G:71, H:72, I:73, J:74, K:75, L:76, M:77, N:78, O:79, P:80, Q:81, R:82, S:83, T:84, U:85, V:86, W:87, X:88, Y:89, Z:90, LeftMeta:91, RightMeta:93, MetaInMozilla:224};
 | |
| gui.HyperlinkClickHandler = function HyperlinkClickHandler(getContainer, keyDownHandler, keyUpHandler) {
 | |
|   var inactiveLinksCssClass = "webodf-inactiveLinks", modifier = gui.KeyboardHandler.Modifier, keyCode = gui.KeyboardHandler.KeyCode, xpath = xmldom.XPath, odfUtils = odf.OdfUtils, window = (runtime.getWindow()), activeModifier = modifier.None, activeKeyBindings = [];
 | |
|   runtime.assert(window !== null, "Expected to be run in an environment which has a global window, like a browser.");
 | |
|   function getHyperlinkElement(node) {
 | |
|     while (node !== null) {
 | |
|       if (odfUtils.isHyperlink(node)) {
 | |
|         return (node);
 | |
|       }
 | |
|       if (odfUtils.isParagraph(node)) {
 | |
|         break;
 | |
|       }
 | |
|       node = node.parentNode;
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   this.handleClick = function(e) {
 | |
|     var target = e.target || e.srcElement, pressedModifier, linkElement, url, rootNode, bookmarks;
 | |
|     if (e.ctrlKey) {
 | |
|       pressedModifier = modifier.Ctrl;
 | |
|     } else {
 | |
|       if (e.metaKey) {
 | |
|         pressedModifier = modifier.Meta;
 | |
|       }
 | |
|     }
 | |
|     if (activeModifier !== modifier.None && activeModifier !== pressedModifier) {
 | |
|       return;
 | |
|     }
 | |
|     linkElement = getHyperlinkElement((target));
 | |
|     if (!linkElement) {
 | |
|       return;
 | |
|     }
 | |
|     url = odfUtils.getHyperlinkTarget(linkElement);
 | |
|     if (url === "") {
 | |
|       return;
 | |
|     }
 | |
|     if (url[0] === "#") {
 | |
|       url = url.substring(1);
 | |
|       rootNode = getContainer();
 | |
|       bookmarks = xpath.getODFElementsWithXPath(rootNode, "//text:bookmark-start[@text:name='" + url + "']", odf.Namespaces.lookupNamespaceURI);
 | |
|       if (bookmarks.length === 0) {
 | |
|         bookmarks = xpath.getODFElementsWithXPath(rootNode, "//text:bookmark[@text:name='" + url + "']", odf.Namespaces.lookupNamespaceURI);
 | |
|       }
 | |
|       if (bookmarks.length > 0) {
 | |
|         bookmarks[0].scrollIntoView(true);
 | |
|       }
 | |
|     } else {
 | |
|       if (/^\s*(javascript|data):/.test(url)) {
 | |
|         runtime.log("WARN:", "potentially malicious URL ignored");
 | |
|       } else {
 | |
|         window.open(url);
 | |
|       }
 | |
|     }
 | |
|     if (e.preventDefault) {
 | |
|       e.preventDefault();
 | |
|     } else {
 | |
|       e.returnValue = false;
 | |
|     }
 | |
|   };
 | |
|   function showPointerCursor() {
 | |
|     var container = getContainer();
 | |
|     runtime.assert(Boolean(container.classList), "Document container has no classList element");
 | |
|     container.classList.remove(inactiveLinksCssClass);
 | |
|   }
 | |
|   function showTextCursor() {
 | |
|     var container = getContainer();
 | |
|     runtime.assert(Boolean(container.classList), "Document container has no classList element");
 | |
|     container.classList.add(inactiveLinksCssClass);
 | |
|   }
 | |
|   function cleanupEventBindings() {
 | |
|     window.removeEventListener("focus", showTextCursor, false);
 | |
|     activeKeyBindings.forEach(function(boundShortcut) {
 | |
|       keyDownHandler.unbind(boundShortcut.keyCode, boundShortcut.modifier);
 | |
|       keyUpHandler.unbind(boundShortcut.keyCode, boundShortcut.modifier);
 | |
|     });
 | |
|     activeKeyBindings.length = 0;
 | |
|   }
 | |
|   function bindEvents(modifierKey) {
 | |
|     cleanupEventBindings();
 | |
|     if (modifierKey !== modifier.None) {
 | |
|       window.addEventListener("focus", showTextCursor, false);
 | |
|       switch(modifierKey) {
 | |
|         case modifier.Ctrl:
 | |
|           activeKeyBindings.push({keyCode:keyCode.Ctrl, modifier:modifier.None});
 | |
|           break;
 | |
|         case modifier.Meta:
 | |
|           activeKeyBindings.push({keyCode:keyCode.LeftMeta, modifier:modifier.None});
 | |
|           activeKeyBindings.push({keyCode:keyCode.RightMeta, modifier:modifier.None});
 | |
|           activeKeyBindings.push({keyCode:keyCode.MetaInMozilla, modifier:modifier.None});
 | |
|           break;
 | |
|       }
 | |
|       activeKeyBindings.forEach(function(boundShortcut) {
 | |
|         keyDownHandler.bind(boundShortcut.keyCode, boundShortcut.modifier, showPointerCursor);
 | |
|         keyUpHandler.bind(boundShortcut.keyCode, boundShortcut.modifier, showTextCursor);
 | |
|       });
 | |
|     }
 | |
|   }
 | |
|   this.setModifier = function(value) {
 | |
|     if (activeModifier === value) {
 | |
|       return;
 | |
|     }
 | |
|     runtime.assert(value === modifier.None || value === modifier.Ctrl || value === modifier.Meta, "Unsupported KeyboardHandler.Modifier value: " + value);
 | |
|     activeModifier = value;
 | |
|     if (activeModifier !== modifier.None) {
 | |
|       showTextCursor();
 | |
|     } else {
 | |
|       showPointerCursor();
 | |
|     }
 | |
|     bindEvents(activeModifier);
 | |
|   };
 | |
|   this.getModifier = function() {
 | |
|     return activeModifier;
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     showTextCursor();
 | |
|     cleanupEventBindings();
 | |
|     callback();
 | |
|   };
 | |
| };
 | |
| gui.EventManager = function EventManager(odtDocument) {
 | |
|   var window = (runtime.getWindow()), bindToDirectHandler = {"beforecut":true, "beforepaste":true, "longpress":true, "drag":true, "dragstop":true}, bindToWindow = {"mousedown":true, "mouseup":true, "focus":true}, compoundEvents = {}, eventDelegates = {}, eventTrap, canvasElement = (odtDocument.getCanvas().getElement()), eventManager = this, longPressTimers = {}, LONGPRESS_DURATION = 400;
 | |
|   function EventDelegate(eventName) {
 | |
|     var self = this, recentEvents = [], subscribers = new core.EventNotifier([eventName]);
 | |
|     function listenEvent(eventTarget, eventType, eventHandler) {
 | |
|       var onVariant, bound = false;
 | |
|       onVariant = "on" + eventType;
 | |
|       if (eventTarget.attachEvent) {
 | |
|         eventTarget.attachEvent(onVariant, eventHandler);
 | |
|         bound = true;
 | |
|       }
 | |
|       if (!bound && eventTarget.addEventListener) {
 | |
|         eventTarget.addEventListener(eventType, eventHandler, false);
 | |
|         bound = true;
 | |
|       }
 | |
|       if ((!bound || bindToDirectHandler[eventType]) && eventTarget.hasOwnProperty(onVariant)) {
 | |
|         eventTarget[onVariant] = eventHandler;
 | |
|       }
 | |
|     }
 | |
|     function removeEvent(eventTarget, eventType, eventHandler) {
 | |
|       var onVariant = "on" + eventType;
 | |
|       if ((eventTarget).detachEvent) {
 | |
|         (eventTarget).detachEvent(onVariant, eventHandler);
 | |
|       }
 | |
|       if (eventTarget.removeEventListener) {
 | |
|         eventTarget.removeEventListener(eventType, eventHandler, false);
 | |
|       }
 | |
|       if (eventTarget[onVariant] === eventHandler) {
 | |
|         eventTarget[onVariant] = null;
 | |
|       }
 | |
|     }
 | |
|     function handleEvent(e) {
 | |
|       if (recentEvents.indexOf(e) === -1) {
 | |
|         recentEvents.push(e);
 | |
|         if (self.filters.every(function(filter) {
 | |
|           return filter(e);
 | |
|         })) {
 | |
|           try {
 | |
|             subscribers.emit(eventName, e);
 | |
|           } catch (err) {
 | |
|             runtime.log("Error occurred while processing " + eventName + ":\n" + err.message + "\n" + err.stack);
 | |
|           }
 | |
|         }
 | |
|         runtime.setTimeout(function() {
 | |
|           recentEvents.splice(recentEvents.indexOf(e), 1);
 | |
|         }, 0);
 | |
|       }
 | |
|     }
 | |
|     this.filters = [];
 | |
|     this.subscribe = function(cb) {
 | |
|       subscribers.subscribe(eventName, cb);
 | |
|     };
 | |
|     this.unsubscribe = function(cb) {
 | |
|       subscribers.unsubscribe(eventName, cb);
 | |
|     };
 | |
|     this.destroy = function() {
 | |
|       removeEvent(window, eventName, handleEvent);
 | |
|       removeEvent(eventTrap, eventName, handleEvent);
 | |
|       removeEvent(canvasElement, eventName, handleEvent);
 | |
|     };
 | |
|     function init() {
 | |
|       if (bindToWindow[eventName]) {
 | |
|         listenEvent(window, eventName, handleEvent);
 | |
|       }
 | |
|       listenEvent(eventTrap, eventName, handleEvent);
 | |
|       listenEvent(canvasElement, eventName, handleEvent);
 | |
|     }
 | |
|     init();
 | |
|   }
 | |
|   function CompoundEvent(eventName, dependencies, eventProxy) {
 | |
|     var cachedState = {}, subscribers = new core.EventNotifier([eventName]);
 | |
|     function subscribedProxy(event) {
 | |
|       eventProxy(event, cachedState, function(compoundEventInstance) {
 | |
|         compoundEventInstance.type = eventName;
 | |
|         subscribers.emit(eventName, compoundEventInstance);
 | |
|       });
 | |
|     }
 | |
|     this.subscribe = function(cb) {
 | |
|       subscribers.subscribe(eventName, cb);
 | |
|     };
 | |
|     this.unsubscribe = function(cb) {
 | |
|       subscribers.unsubscribe(eventName, cb);
 | |
|     };
 | |
|     this.destroy = function() {
 | |
|       dependencies.forEach(function(eventName) {
 | |
|         eventManager.unsubscribe(eventName, subscribedProxy);
 | |
|       });
 | |
|     };
 | |
|     function init() {
 | |
|       dependencies.forEach(function(eventName) {
 | |
|         eventManager.subscribe(eventName, subscribedProxy);
 | |
|       });
 | |
|     }
 | |
|     init();
 | |
|   }
 | |
|   function clearTimeout(timer) {
 | |
|     runtime.clearTimeout(timer);
 | |
|     delete longPressTimers[timer];
 | |
|   }
 | |
|   function setTimeout(fn, duration) {
 | |
|     var timer = runtime.setTimeout(function() {
 | |
|       fn();
 | |
|       clearTimeout(timer);
 | |
|     }, duration);
 | |
|     longPressTimers[timer] = true;
 | |
|     return timer;
 | |
|   }
 | |
|   function getTarget(e) {
 | |
|     return (e.target) || e.srcElement || null;
 | |
|   }
 | |
|   function emitLongPressEvent(event, cachedState, callback) {
 | |
|     var touchEvent = (event), fingers = (touchEvent.touches.length), touch = (touchEvent.touches[0]), timer = (cachedState).timer;
 | |
|     if (event.type === "touchmove" || event.type === "touchend") {
 | |
|       if (timer) {
 | |
|         clearTimeout(timer);
 | |
|       }
 | |
|     } else {
 | |
|       if (event.type === "touchstart") {
 | |
|         if (fingers !== 1) {
 | |
|           runtime.clearTimeout(timer);
 | |
|         } else {
 | |
|           timer = setTimeout(function() {
 | |
|             callback({clientX:touch.clientX, clientY:touch.clientY, pageX:touch.pageX, pageY:touch.pageY, target:getTarget(event), detail:1});
 | |
|           }, LONGPRESS_DURATION);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     cachedState.timer = timer;
 | |
|   }
 | |
|   function emitDragEvent(event, cachedState, callback) {
 | |
|     var touchEvent = (event), fingers = (touchEvent.touches.length), touch = (touchEvent.touches[0]), target = (getTarget(event)), cachedTarget = (cachedState).target;
 | |
|     if (fingers !== 1 || event.type === "touchend") {
 | |
|       cachedTarget = null;
 | |
|     } else {
 | |
|       if (event.type === "touchstart" && target.getAttribute("class") === "webodf-draggable") {
 | |
|         cachedTarget = target;
 | |
|       } else {
 | |
|         if (event.type === "touchmove" && cachedTarget) {
 | |
|           event.preventDefault();
 | |
|           event.stopPropagation();
 | |
|           callback({clientX:touch.clientX, clientY:touch.clientY, pageX:touch.pageX, pageY:touch.pageY, target:cachedTarget, detail:1});
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     cachedState.target = cachedTarget;
 | |
|   }
 | |
|   function emitDragStopEvent(event, cachedState, callback) {
 | |
|     var touchEvent = (event), target = (getTarget(event)), touch, dragging = (cachedState).dragging;
 | |
|     if (event.type === "drag") {
 | |
|       dragging = true;
 | |
|     } else {
 | |
|       if (event.type === "touchend" && dragging) {
 | |
|         dragging = false;
 | |
|         touch = (touchEvent.changedTouches[0]);
 | |
|         callback({clientX:touch.clientX, clientY:touch.clientY, pageX:touch.pageX, pageY:touch.pageY, target:target, detail:1});
 | |
|       }
 | |
|     }
 | |
|     cachedState.dragging = dragging;
 | |
|   }
 | |
|   function declareTouchEnabled() {
 | |
|     canvasElement.classList.add("webodf-touchEnabled");
 | |
|     eventManager.unsubscribe("touchstart", declareTouchEnabled);
 | |
|   }
 | |
|   function WindowScrollState(window) {
 | |
|     var x = window.scrollX, y = window.scrollY;
 | |
|     this.restore = function() {
 | |
|       if (window.scrollX !== x || window.scrollY !== y) {
 | |
|         window.scrollTo(x, y);
 | |
|       }
 | |
|     };
 | |
|   }
 | |
|   function ElementScrollState(element) {
 | |
|     var top = element.scrollTop, left = element.scrollLeft;
 | |
|     this.restore = function() {
 | |
|       if (element.scrollTop !== top || element.scrollLeft !== left) {
 | |
|         element.scrollTop = top;
 | |
|         element.scrollLeft = left;
 | |
|       }
 | |
|     };
 | |
|   }
 | |
|   function getDelegateForEvent(eventName, shouldCreate) {
 | |
|     var delegate = eventDelegates[eventName] || compoundEvents[eventName] || null;
 | |
|     if (!delegate && shouldCreate) {
 | |
|       delegate = eventDelegates[eventName] = new EventDelegate(eventName);
 | |
|     }
 | |
|     return delegate;
 | |
|   }
 | |
|   this.addFilter = function(eventName, filter) {
 | |
|     var delegate = getDelegateForEvent(eventName, true);
 | |
|     delegate.filters.push(filter);
 | |
|   };
 | |
|   this.removeFilter = function(eventName, filter) {
 | |
|     var delegate = getDelegateForEvent(eventName, true), index = delegate.filters.indexOf(filter);
 | |
|     if (index !== -1) {
 | |
|       delegate.filters.splice(index, 1);
 | |
|     }
 | |
|   };
 | |
|   function subscribe(eventName, handler) {
 | |
|     var delegate = getDelegateForEvent(eventName, true);
 | |
|     delegate.subscribe(handler);
 | |
|   }
 | |
|   this.subscribe = subscribe;
 | |
|   function unsubscribe(eventName, handler) {
 | |
|     var delegate = getDelegateForEvent(eventName, false);
 | |
|     if (delegate) {
 | |
|       delegate.unsubscribe(handler);
 | |
|     }
 | |
|   }
 | |
|   this.unsubscribe = unsubscribe;
 | |
|   function hasFocus() {
 | |
|     return odtDocument.getDOMDocument().activeElement === eventTrap;
 | |
|   }
 | |
|   this.hasFocus = hasFocus;
 | |
|   function disableTrapSelection() {
 | |
|     if (hasFocus()) {
 | |
|       eventTrap.blur();
 | |
|     }
 | |
|     eventTrap.setAttribute("disabled", "true");
 | |
|   }
 | |
|   function enableTrapSelection() {
 | |
|     eventTrap.removeAttribute("disabled");
 | |
|   }
 | |
|   function findScrollableParents(element) {
 | |
|     var scrollParents = [];
 | |
|     while (element) {
 | |
|       if (element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight) {
 | |
|         scrollParents.push(new ElementScrollState(element));
 | |
|       }
 | |
|       element = (element.parentNode);
 | |
|     }
 | |
|     scrollParents.push(new WindowScrollState(window));
 | |
|     return scrollParents;
 | |
|   }
 | |
|   function focus() {
 | |
|     var scrollParents;
 | |
|     if (!hasFocus()) {
 | |
|       scrollParents = findScrollableParents(eventTrap);
 | |
|       enableTrapSelection();
 | |
|       eventTrap.focus();
 | |
|       scrollParents.forEach(function(scrollParent) {
 | |
|         scrollParent.restore();
 | |
|       });
 | |
|     }
 | |
|   }
 | |
|   this.focus = focus;
 | |
|   this.getEventTrap = function() {
 | |
|     return eventTrap;
 | |
|   };
 | |
|   this.setEditing = function(editable) {
 | |
|     var hadFocus = hasFocus();
 | |
|     if (hadFocus) {
 | |
|       eventTrap.blur();
 | |
|     }
 | |
|     if (editable) {
 | |
|       eventTrap.removeAttribute("readOnly");
 | |
|     } else {
 | |
|       eventTrap.setAttribute("readOnly", "true");
 | |
|     }
 | |
|     if (hadFocus) {
 | |
|       focus();
 | |
|     }
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     unsubscribe("touchstart", declareTouchEnabled);
 | |
|     Object.keys(longPressTimers).forEach(function(timer) {
 | |
|       clearTimeout(parseInt(timer, 10));
 | |
|     });
 | |
|     longPressTimers.length = 0;
 | |
|     Object.keys(compoundEvents).forEach(function(compoundEventName) {
 | |
|       compoundEvents[compoundEventName].destroy();
 | |
|     });
 | |
|     compoundEvents = {};
 | |
|     unsubscribe("mousedown", disableTrapSelection);
 | |
|     unsubscribe("mouseup", enableTrapSelection);
 | |
|     unsubscribe("contextmenu", enableTrapSelection);
 | |
|     Object.keys(eventDelegates).forEach(function(eventName) {
 | |
|       eventDelegates[eventName].destroy();
 | |
|     });
 | |
|     eventDelegates = {};
 | |
|     eventTrap.parentNode.removeChild(eventTrap);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     var sizerElement = odtDocument.getOdfCanvas().getSizer(), doc = sizerElement.ownerDocument;
 | |
|     runtime.assert(Boolean(window), "EventManager requires a window object to operate correctly");
 | |
|     eventTrap = (doc.createElement("textarea"));
 | |
|     eventTrap.id = "eventTrap";
 | |
|     eventTrap.setAttribute("tabindex", "-1");
 | |
|     eventTrap.setAttribute("readOnly", "true");
 | |
|     eventTrap.setAttribute("rows", "1");
 | |
|     sizerElement.appendChild(eventTrap);
 | |
|     subscribe("mousedown", disableTrapSelection);
 | |
|     subscribe("mouseup", enableTrapSelection);
 | |
|     subscribe("contextmenu", enableTrapSelection);
 | |
|     compoundEvents.longpress = new CompoundEvent("longpress", ["touchstart", "touchmove", "touchend"], emitLongPressEvent);
 | |
|     compoundEvents.drag = new CompoundEvent("drag", ["touchstart", "touchmove", "touchend"], emitDragEvent);
 | |
|     compoundEvents.dragstop = new CompoundEvent("dragstop", ["drag", "touchend"], emitDragStopEvent);
 | |
|     subscribe("touchstart", declareTouchEnabled);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.IOSSafariSupport = function(eventManager) {
 | |
|   var window = runtime.getWindow(), eventTrap = eventManager.getEventTrap();
 | |
|   function suppressFocusScrollIfKeyboardOpen() {
 | |
|     if (window.innerHeight !== window.outerHeight) {
 | |
|       eventTrap.style.display = "none";
 | |
|       runtime.requestAnimationFrame(function() {
 | |
|         eventTrap.style.display = "block";
 | |
|       });
 | |
|     }
 | |
|   }
 | |
|   this.destroy = function(callback) {
 | |
|     eventManager.unsubscribe("focus", suppressFocusScrollIfKeyboardOpen);
 | |
|     eventTrap.removeAttribute("autocapitalize");
 | |
|     eventTrap.style.WebkitTransform = "";
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     eventManager.subscribe("focus", suppressFocusScrollIfKeyboardOpen);
 | |
|     eventTrap.setAttribute("autocapitalize", "off");
 | |
|     eventTrap.style.WebkitTransform = "translateX(-10000px)";
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.HyperlinkController = function HyperlinkController(session, sessionConstraints, sessionContext, inputMemberId) {
 | |
|   var odfUtils = odf.OdfUtils, odtDocument = session.getOdtDocument(), eventNotifier = new core.EventNotifier([gui.HyperlinkController.enabledChanged]), isEnabled = false;
 | |
|   function updateEnabledState() {
 | |
|     var newIsEnabled = true;
 | |
|     if (sessionConstraints.getState(gui.CommonConstraints.EDIT.REVIEW_MODE) === true) {
 | |
|       newIsEnabled = (sessionContext.isLocalCursorWithinOwnAnnotation());
 | |
|     }
 | |
|     if (newIsEnabled !== isEnabled) {
 | |
|       isEnabled = newIsEnabled;
 | |
|       eventNotifier.emit(gui.HyperlinkController.enabledChanged, isEnabled);
 | |
|     }
 | |
|   }
 | |
|   function onCursorEvent(cursor) {
 | |
|     if (cursor.getMemberId() === inputMemberId) {
 | |
|       updateEnabledState();
 | |
|     }
 | |
|   }
 | |
|   this.isEnabled = function() {
 | |
|     return isEnabled;
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     eventNotifier.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     eventNotifier.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   function addHyperlink(hyperlink, insertionText) {
 | |
|     if (!isEnabled) {
 | |
|       return;
 | |
|     }
 | |
|     var selection = odtDocument.getCursorSelection(inputMemberId), op = new ops.OpApplyHyperlink, operations = [];
 | |
|     if (selection.length === 0 || insertionText) {
 | |
|       insertionText = insertionText || hyperlink;
 | |
|       op = new ops.OpInsertText;
 | |
|       op.init({memberid:inputMemberId, position:selection.position, text:insertionText});
 | |
|       selection.length = insertionText.length;
 | |
|       operations.push(op);
 | |
|     }
 | |
|     op = new ops.OpApplyHyperlink;
 | |
|     op.init({memberid:inputMemberId, position:selection.position, length:selection.length, hyperlink:hyperlink});
 | |
|     operations.push(op);
 | |
|     session.enqueue(operations);
 | |
|   }
 | |
|   this.addHyperlink = addHyperlink;
 | |
|   function removeHyperlinks() {
 | |
|     if (!isEnabled) {
 | |
|       return;
 | |
|     }
 | |
|     var iterator = odtDocument.createPositionIterator(odtDocument.getRootNode()), selectedRange = odtDocument.getCursor(inputMemberId).getSelectedRange(), links = odfUtils.getHyperlinkElements(selectedRange), removeEntireLink = selectedRange.collapsed && links.length === 1, domRange = odtDocument.getDOMDocument().createRange(), operations = [], cursorRange, firstLink, lastLink, offset, op;
 | |
|     if (links.length === 0) {
 | |
|       return;
 | |
|     }
 | |
|     links.forEach(function(link) {
 | |
|       domRange.selectNodeContents(link);
 | |
|       cursorRange = odtDocument.convertDomToCursorRange({anchorNode:(domRange.startContainer), anchorOffset:domRange.startOffset, focusNode:(domRange.endContainer), focusOffset:domRange.endOffset});
 | |
|       op = new ops.OpRemoveHyperlink;
 | |
|       op.init({memberid:inputMemberId, position:cursorRange.position, length:cursorRange.length});
 | |
|       operations.push(op);
 | |
|     });
 | |
|     if (!removeEntireLink) {
 | |
|       firstLink = (links[0]);
 | |
|       if (selectedRange.comparePoint(firstLink, 0) === -1) {
 | |
|         domRange.setStart(firstLink, 0);
 | |
|         domRange.setEnd(selectedRange.startContainer, selectedRange.startOffset);
 | |
|         cursorRange = odtDocument.convertDomToCursorRange({anchorNode:(domRange.startContainer), anchorOffset:domRange.startOffset, focusNode:(domRange.endContainer), focusOffset:domRange.endOffset});
 | |
|         if (cursorRange.length > 0) {
 | |
|           op = new ops.OpApplyHyperlink;
 | |
|           (op).init({memberid:inputMemberId, position:cursorRange.position, length:cursorRange.length, hyperlink:odfUtils.getHyperlinkTarget(firstLink)});
 | |
|           operations.push(op);
 | |
|         }
 | |
|       }
 | |
|       lastLink = (links[links.length - 1]);
 | |
|       iterator.moveToEndOfNode(lastLink);
 | |
|       offset = iterator.unfilteredDomOffset();
 | |
|       if (selectedRange.comparePoint(lastLink, offset) === 1) {
 | |
|         domRange.setStart(selectedRange.endContainer, selectedRange.endOffset);
 | |
|         domRange.setEnd(lastLink, offset);
 | |
|         cursorRange = odtDocument.convertDomToCursorRange({anchorNode:(domRange.startContainer), anchorOffset:domRange.startOffset, focusNode:(domRange.endContainer), focusOffset:domRange.endOffset});
 | |
|         if (cursorRange.length > 0) {
 | |
|           op = new ops.OpApplyHyperlink;
 | |
|           (op).init({memberid:inputMemberId, position:cursorRange.position, length:cursorRange.length, hyperlink:odfUtils.getHyperlinkTarget(lastLink)});
 | |
|           operations.push(op);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     session.enqueue(operations);
 | |
|     domRange.detach();
 | |
|   }
 | |
|   this.removeHyperlinks = removeHyperlinks;
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.unsubscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.subscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     updateEnabledState();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.HyperlinkController.enabledChanged = "enabled/changed";
 | |
| gui.ImageController = function ImageController(session, sessionConstraints, sessionContext, inputMemberId, objectNameGenerator) {
 | |
|   var fileExtensionByMimetype = {"image/gif":".gif", "image/jpeg":".jpg", "image/png":".png"}, textns = odf.Namespaces.textns, odtDocument = session.getOdtDocument(), odfUtils = odf.OdfUtils, formatting = odtDocument.getFormatting(), eventNotifier = new core.EventNotifier([gui.HyperlinkController.enabledChanged]), isEnabled = false;
 | |
|   function updateEnabledState() {
 | |
|     var newIsEnabled = true;
 | |
|     if (sessionConstraints.getState(gui.CommonConstraints.EDIT.REVIEW_MODE) === true) {
 | |
|       newIsEnabled = (sessionContext.isLocalCursorWithinOwnAnnotation());
 | |
|     }
 | |
|     if (newIsEnabled !== isEnabled) {
 | |
|       isEnabled = newIsEnabled;
 | |
|       eventNotifier.emit(gui.ImageController.enabledChanged, isEnabled);
 | |
|     }
 | |
|   }
 | |
|   function onCursorEvent(cursor) {
 | |
|     if (cursor.getMemberId() === inputMemberId) {
 | |
|       updateEnabledState();
 | |
|     }
 | |
|   }
 | |
|   this.isEnabled = function() {
 | |
|     return isEnabled;
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     eventNotifier.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     eventNotifier.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   function createAddGraphicsStyleOp(name) {
 | |
|     var op = new ops.OpAddStyle;
 | |
|     op.init({memberid:inputMemberId, styleName:name, styleFamily:"graphic", isAutomaticStyle:false, setProperties:{"style:graphic-properties":{"text:anchor-type":"paragraph", "svg:x":"0cm", "svg:y":"0cm", "style:wrap":"dynamic", "style:number-wrapped-paragraphs":"no-limit", "style:wrap-contour":"false", "style:vertical-pos":"top", "style:vertical-rel":"paragraph", "style:horizontal-pos":"center", "style:horizontal-rel":"paragraph"}}});
 | |
|     return op;
 | |
|   }
 | |
|   function createAddFrameStyleOp(styleName, parentStyleName) {
 | |
|     var op = new ops.OpAddStyle;
 | |
|     op.init({memberid:inputMemberId, styleName:styleName, styleFamily:"graphic", isAutomaticStyle:true, setProperties:{"style:parent-style-name":parentStyleName, "style:graphic-properties":{"style:vertical-pos":"top", "style:vertical-rel":"baseline", "style:horizontal-pos":"center", "style:horizontal-rel":"paragraph", "fo:background-color":"transparent", "style:background-transparency":"100%", "style:shadow":"none", "style:mirror":"none", "fo:clip":"rect(0cm, 0cm, 0cm, 0cm)", "draw:luminance":"0%", 
 | |
|     "draw:contrast":"0%", "draw:red":"0%", "draw:green":"0%", "draw:blue":"0%", "draw:gamma":"100%", "draw:color-inversion":"false", "draw:image-opacity":"100%", "draw:color-mode":"standard"}}});
 | |
|     return op;
 | |
|   }
 | |
|   function getFileExtension(mimetype) {
 | |
|     mimetype = mimetype.toLowerCase();
 | |
|     return fileExtensionByMimetype.hasOwnProperty(mimetype) ? fileExtensionByMimetype[mimetype] : null;
 | |
|   }
 | |
|   function insertImageInternal(mimetype, content, widthMeasure, heightMeasure) {
 | |
|     var graphicsStyleName = "Graphics", stylesElement = odtDocument.getOdfCanvas().odfContainer().rootElement.styles, fileExtension = getFileExtension(mimetype), fileName, graphicsStyleElement, frameStyleName, op, operations = [];
 | |
|     runtime.assert(fileExtension !== null, "Image type is not supported: " + mimetype);
 | |
|     fileName = "Pictures/" + objectNameGenerator.generateImageName() + fileExtension;
 | |
|     op = new ops.OpSetBlob;
 | |
|     op.init({memberid:inputMemberId, filename:fileName, mimetype:mimetype, content:content});
 | |
|     operations.push(op);
 | |
|     graphicsStyleElement = formatting.getStyleElement(graphicsStyleName, "graphic", [stylesElement]);
 | |
|     if (!graphicsStyleElement) {
 | |
|       op = createAddGraphicsStyleOp(graphicsStyleName);
 | |
|       operations.push(op);
 | |
|     }
 | |
|     frameStyleName = objectNameGenerator.generateStyleName();
 | |
|     op = createAddFrameStyleOp(frameStyleName, graphicsStyleName);
 | |
|     operations.push(op);
 | |
|     op = new ops.OpInsertImage;
 | |
|     op.init({memberid:inputMemberId, position:odtDocument.getCursorPosition(inputMemberId), filename:fileName, frameWidth:widthMeasure, frameHeight:heightMeasure, frameStyleName:frameStyleName, frameName:objectNameGenerator.generateFrameName()});
 | |
|     operations.push(op);
 | |
|     session.enqueue(operations);
 | |
|   }
 | |
|   function scaleToAvailableContentSize(originalSize, pageContentSize) {
 | |
|     var widthRatio = 1, heightRatio = 1, ratio;
 | |
|     if (originalSize.width > pageContentSize.width) {
 | |
|       widthRatio = pageContentSize.width / originalSize.width;
 | |
|     }
 | |
|     if (originalSize.height > pageContentSize.height) {
 | |
|       heightRatio = pageContentSize.height / originalSize.height;
 | |
|     }
 | |
|     ratio = Math.min(widthRatio, heightRatio);
 | |
|     return {width:originalSize.width * ratio, height:originalSize.height * ratio};
 | |
|   }
 | |
|   this.insertImage = function(mimetype, content, widthInPx, heightInPx) {
 | |
|     if (!isEnabled) {
 | |
|       return;
 | |
|     }
 | |
|     var paragraphElement, styleName, pageContentSize, imageSize;
 | |
|     runtime.assert(widthInPx > 0 && heightInPx > 0, "Both width and height of the image should be greater than 0px.");
 | |
|     imageSize = {width:widthInPx, height:heightInPx};
 | |
|     paragraphElement = odfUtils.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode());
 | |
|     styleName = paragraphElement.getAttributeNS(textns, "style-name");
 | |
|     if (styleName) {
 | |
|       pageContentSize = formatting.getContentSize(styleName, "paragraph");
 | |
|       imageSize = scaleToAvailableContentSize(imageSize, pageContentSize);
 | |
|     }
 | |
|     insertImageInternal(mimetype, content, imageSize.width + "px", imageSize.height + "px");
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.unsubscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.subscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     updateEnabledState();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.ImageController.enabledChanged = "enabled/changed";
 | |
| gui.ImageSelector = function ImageSelector(odfCanvas) {
 | |
|   var svgns = odf.Namespaces.svgns, imageSelectorId = "imageSelector", selectorBorderWidth = 1, squareClassNames = ["topLeft", "topRight", "bottomRight", "bottomLeft", "topMiddle", "rightMiddle", "bottomMiddle", "leftMiddle"], document = odfCanvas.getElement().ownerDocument, hasSelection = false;
 | |
|   function createSelectorElement() {
 | |
|     var sizerElement = odfCanvas.getSizer(), selectorElement = (document.createElement("div"));
 | |
|     selectorElement.id = "imageSelector";
 | |
|     selectorElement.style.borderWidth = selectorBorderWidth + "px";
 | |
|     sizerElement.appendChild(selectorElement);
 | |
|     function createDiv(className) {
 | |
|       var squareElement = document.createElement("div");
 | |
|       squareElement.className = className;
 | |
|       selectorElement.appendChild(squareElement);
 | |
|     }
 | |
|     squareClassNames.forEach(createDiv);
 | |
|     return selectorElement;
 | |
|   }
 | |
|   function getPosition(element, referenceElement) {
 | |
|     var rect = element.getBoundingClientRect(), refRect = referenceElement.getBoundingClientRect(), zoomLevel = odfCanvas.getZoomLevel();
 | |
|     return {left:(rect.left - refRect.left) / zoomLevel - selectorBorderWidth, top:(rect.top - refRect.top) / zoomLevel - selectorBorderWidth};
 | |
|   }
 | |
|   this.select = function(frameElement) {
 | |
|     var selectorElement = document.getElementById(imageSelectorId), position;
 | |
|     if (!selectorElement) {
 | |
|       selectorElement = createSelectorElement();
 | |
|     }
 | |
|     hasSelection = true;
 | |
|     position = getPosition(frameElement, (selectorElement.parentNode));
 | |
|     selectorElement.style.display = "block";
 | |
|     selectorElement.style.left = position.left + "px";
 | |
|     selectorElement.style.top = position.top + "px";
 | |
|     selectorElement.style.width = frameElement.getAttributeNS(svgns, "width");
 | |
|     selectorElement.style.height = frameElement.getAttributeNS(svgns, "height");
 | |
|   };
 | |
|   this.clearSelection = function() {
 | |
|     var selectorElement;
 | |
|     if (hasSelection) {
 | |
|       selectorElement = document.getElementById(imageSelectorId);
 | |
|       if (selectorElement) {
 | |
|         selectorElement.style.display = "none";
 | |
|       }
 | |
|     }
 | |
|     hasSelection = false;
 | |
|   };
 | |
|   this.isSelectorElement = function(node) {
 | |
|     var selectorElement = document.getElementById(imageSelectorId);
 | |
|     if (!selectorElement) {
 | |
|       return false;
 | |
|     }
 | |
|     return node === selectorElement || node.parentNode === selectorElement;
 | |
|   };
 | |
| };
 | |
| (function() {
 | |
|   function DetectSafariCompositionError(eventManager) {
 | |
|     var lastCompositionValue, suppressedKeyPress = false;
 | |
|     function suppressIncorrectKeyPress(e) {
 | |
|       suppressedKeyPress = e.which && String.fromCharCode(e.which) === lastCompositionValue;
 | |
|       lastCompositionValue = undefined;
 | |
|       return suppressedKeyPress === false;
 | |
|     }
 | |
|     function clearSuppression() {
 | |
|       suppressedKeyPress = false;
 | |
|     }
 | |
|     function trapComposedValue(e) {
 | |
|       lastCompositionValue = e.data;
 | |
|       suppressedKeyPress = false;
 | |
|     }
 | |
|     function init() {
 | |
|       eventManager.subscribe("textInput", clearSuppression);
 | |
|       eventManager.subscribe("compositionend", trapComposedValue);
 | |
|       eventManager.addFilter("keypress", suppressIncorrectKeyPress);
 | |
|     }
 | |
|     this.destroy = function(callback) {
 | |
|       eventManager.unsubscribe("textInput", clearSuppression);
 | |
|       eventManager.unsubscribe("compositionend", trapComposedValue);
 | |
|       eventManager.removeFilter("keypress", suppressIncorrectKeyPress);
 | |
|       callback();
 | |
|     };
 | |
|     init();
 | |
|   }
 | |
|   gui.InputMethodEditor = function InputMethodEditor(inputMemberId, eventManager) {
 | |
|     var cursorns = "urn:webodf:names:cursor", localCursor = null, eventTrap = eventManager.getEventTrap(), doc = (eventTrap.ownerDocument), compositionElement, processUpdates, pendingEvent = false, pendingData = "", events = new core.EventNotifier([gui.InputMethodEditor.signalCompositionStart, gui.InputMethodEditor.signalCompositionEnd]), lastCompositionData, textSerializer, filters = [], cleanup, processingFocusEvent = false;
 | |
|     this.subscribe = events.subscribe;
 | |
|     this.unsubscribe = events.unsubscribe;
 | |
|     function setCursorComposing(state) {
 | |
|       if (localCursor) {
 | |
|         if (state) {
 | |
|           localCursor.getNode().setAttributeNS(cursorns, "composing", "true");
 | |
|         } else {
 | |
|           localCursor.getNode().removeAttributeNS(cursorns, "composing");
 | |
|           compositionElement.textContent = "";
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function flushEvent() {
 | |
|       if (pendingEvent) {
 | |
|         pendingEvent = false;
 | |
|         setCursorComposing(false);
 | |
|         events.emit(gui.InputMethodEditor.signalCompositionEnd, {data:pendingData});
 | |
|         pendingData = "";
 | |
|       }
 | |
|     }
 | |
|     function addCompositionData(data) {
 | |
|       pendingEvent = true;
 | |
|       pendingData += data;
 | |
|       processUpdates.trigger();
 | |
|     }
 | |
|     function synchronizeWindowSelection() {
 | |
|       if (processingFocusEvent) {
 | |
|         return;
 | |
|       }
 | |
|       processingFocusEvent = true;
 | |
|       flushEvent();
 | |
|       if (localCursor && localCursor.getSelectedRange().collapsed) {
 | |
|         eventTrap.value = "";
 | |
|       } else {
 | |
|         eventTrap.value = textSerializer.writeToString(localCursor.getSelectedRange().cloneContents());
 | |
|       }
 | |
|       eventTrap.setSelectionRange(0, eventTrap.value.length);
 | |
|       processingFocusEvent = false;
 | |
|     }
 | |
|     function handleCursorUpdated() {
 | |
|       if (eventManager.hasFocus()) {
 | |
|         processUpdates.trigger();
 | |
|       }
 | |
|     }
 | |
|     function compositionStart() {
 | |
|       lastCompositionData = undefined;
 | |
|       processUpdates.cancel();
 | |
|       setCursorComposing(true);
 | |
|       if (!pendingEvent) {
 | |
|         events.emit(gui.InputMethodEditor.signalCompositionStart, {data:""});
 | |
|       }
 | |
|     }
 | |
|     function compositionEnd(e) {
 | |
|       lastCompositionData = e.data;
 | |
|       addCompositionData(e.data);
 | |
|     }
 | |
|     function textInput(e) {
 | |
|       if (e.data !== lastCompositionData) {
 | |
|         addCompositionData(e.data);
 | |
|       }
 | |
|       lastCompositionData = undefined;
 | |
|     }
 | |
|     function synchronizeCompositionText() {
 | |
|       compositionElement.textContent = eventTrap.value;
 | |
|     }
 | |
|     this.registerCursor = function(cursor) {
 | |
|       if (cursor.getMemberId() === inputMemberId) {
 | |
|         localCursor = cursor;
 | |
|         localCursor.getNode().appendChild(compositionElement);
 | |
|         cursor.subscribe(ops.OdtCursor.signalCursorUpdated, handleCursorUpdated);
 | |
|         eventManager.subscribe("input", synchronizeCompositionText);
 | |
|         eventManager.subscribe("compositionupdate", synchronizeCompositionText);
 | |
|       }
 | |
|     };
 | |
|     this.removeCursor = function(memberid) {
 | |
|       if (localCursor && memberid === inputMemberId) {
 | |
|         localCursor.getNode().removeChild(compositionElement);
 | |
|         localCursor.unsubscribe(ops.OdtCursor.signalCursorUpdated, handleCursorUpdated);
 | |
|         eventManager.unsubscribe("input", synchronizeCompositionText);
 | |
|         eventManager.unsubscribe("compositionupdate", synchronizeCompositionText);
 | |
|         localCursor = null;
 | |
|       }
 | |
|     };
 | |
|     this.destroy = function(callback) {
 | |
|       eventManager.unsubscribe("compositionstart", compositionStart);
 | |
|       eventManager.unsubscribe("compositionend", compositionEnd);
 | |
|       eventManager.unsubscribe("textInput", textInput);
 | |
|       eventManager.unsubscribe("keypress", flushEvent);
 | |
|       eventManager.unsubscribe("focus", synchronizeWindowSelection);
 | |
|       core.Async.destroyAll(cleanup, callback);
 | |
|     };
 | |
|     function init() {
 | |
|       textSerializer = new odf.TextSerializer;
 | |
|       textSerializer.filter = new odf.OdfNodeFilter;
 | |
|       eventManager.subscribe("compositionstart", compositionStart);
 | |
|       eventManager.subscribe("compositionend", compositionEnd);
 | |
|       eventManager.subscribe("textInput", textInput);
 | |
|       eventManager.subscribe("keypress", flushEvent);
 | |
|       eventManager.subscribe("focus", synchronizeWindowSelection);
 | |
|       filters.push(new DetectSafariCompositionError(eventManager));
 | |
|       function getDestroy(filter) {
 | |
|         return filter.destroy;
 | |
|       }
 | |
|       cleanup = filters.map(getDestroy);
 | |
|       compositionElement = doc.createElement("span");
 | |
|       compositionElement.setAttribute("id", "composer");
 | |
|       processUpdates = core.Task.createTimeoutTask(synchronizeWindowSelection, 1);
 | |
|       cleanup.push(processUpdates.destroy);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
|   gui.InputMethodEditor.signalCompositionStart = "input/compositionstart";
 | |
|   gui.InputMethodEditor.signalCompositionEnd = "input/compositionend";
 | |
| })();
 | |
| gui.MetadataController = function MetadataController(session, inputMemberId) {
 | |
|   var odtDocument = session.getOdtDocument(), eventNotifier = new core.EventNotifier([gui.MetadataController.signalMetadataChanged]), readonlyProperties = ["dc:creator", "dc:date", "meta:editing-cycles", "meta:editing-duration", "meta:document-statistic"];
 | |
|   function onMetadataUpdated(changes) {
 | |
|     eventNotifier.emit(gui.MetadataController.signalMetadataChanged, changes);
 | |
|   }
 | |
|   function isWriteableMetadata(property) {
 | |
|     var isWriteable = readonlyProperties.indexOf(property) === -1;
 | |
|     if (!isWriteable) {
 | |
|       runtime.log("Setting " + property + " is restricted.");
 | |
|     }
 | |
|     return isWriteable;
 | |
|   }
 | |
|   this.setMetadata = function(setProperties, removedProperties) {
 | |
|     var filteredSetProperties = {}, filteredRemovedProperties = "", op;
 | |
|     if (setProperties) {
 | |
|       Object.keys(setProperties).filter(isWriteableMetadata).forEach(function(property) {
 | |
|         filteredSetProperties[property] = setProperties[property];
 | |
|       });
 | |
|     }
 | |
|     if (removedProperties) {
 | |
|       filteredRemovedProperties = removedProperties.filter(isWriteableMetadata).join(",");
 | |
|     }
 | |
|     if (filteredRemovedProperties.length > 0 || Object.keys(filteredSetProperties).length > 0) {
 | |
|       op = new ops.OpUpdateMetadata;
 | |
|       op.init({memberid:inputMemberId, setProperties:filteredSetProperties, removedProperties:filteredRemovedProperties.length > 0 ? {attributes:filteredRemovedProperties} : null});
 | |
|       session.enqueue([op]);
 | |
|     }
 | |
|   };
 | |
|   this.getMetadata = function(property) {
 | |
|     var namespaceUri, parts;
 | |
|     runtime.assert(typeof property === "string", "Property must be a string");
 | |
|     parts = property.split(":");
 | |
|     runtime.assert(parts.length === 2, "Property must be a namespace-prefixed string");
 | |
|     namespaceUri = odf.Namespaces.lookupNamespaceURI(parts[0]);
 | |
|     runtime.assert(Boolean(namespaceUri), "Prefix must be for an ODF namespace.");
 | |
|     return odtDocument.getOdfCanvas().odfContainer().getMetadata((namespaceUri), parts[1]);
 | |
|   };
 | |
|   this.subscribe = function(eventid, cb) {
 | |
|     eventNotifier.subscribe(eventid, cb);
 | |
|   };
 | |
|   this.unsubscribe = function(eventid, cb) {
 | |
|     eventNotifier.unsubscribe(eventid, cb);
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.OdtDocument.signalMetadataUpdated, onMetadataUpdated);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     odtDocument.subscribe(ops.OdtDocument.signalMetadataUpdated, onMetadataUpdated);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.MetadataController.signalMetadataChanged = "metadata/changed";
 | |
| gui.PasteController = function PasteController(session, sessionConstraints, sessionContext, inputMemberId) {
 | |
|   var odtDocument = session.getOdtDocument(), isEnabled = false, textns = odf.Namespaces.textns, NEXT = core.StepDirection.NEXT, odfUtils = odf.OdfUtils;
 | |
|   function updateEnabledState() {
 | |
|     if (sessionConstraints.getState(gui.CommonConstraints.EDIT.REVIEW_MODE) === true) {
 | |
|       isEnabled = (sessionContext.isLocalCursorWithinOwnAnnotation());
 | |
|     } else {
 | |
|       isEnabled = true;
 | |
|     }
 | |
|   }
 | |
|   function onCursorEvent(cursor) {
 | |
|     if (cursor.getMemberId() === inputMemberId) {
 | |
|       updateEnabledState();
 | |
|     }
 | |
|   }
 | |
|   this.isEnabled = function() {
 | |
|     return isEnabled;
 | |
|   };
 | |
|   this.paste = function(data) {
 | |
|     if (!isEnabled) {
 | |
|       return;
 | |
|     }
 | |
|     var originalCursorPosition = odtDocument.getCursorPosition(inputMemberId), cursorNode = odtDocument.getCursor(inputMemberId).getNode(), originalParagraph = (odfUtils.getParagraphElement(cursorNode)), paragraphStyle = originalParagraph.getAttributeNS(textns, "style-name") || "", cursorPosition = originalCursorPosition, operations = [], currentParagraphStartPosition = odtDocument.convertDomPointToCursorStep(originalParagraph, 0, NEXT), paragraphs;
 | |
|     paragraphs = data.replace(/\r/g, "").split("\n");
 | |
|     paragraphs.forEach(function(text) {
 | |
|       var insertTextOp = new ops.OpInsertText, splitParagraphOp = new ops.OpSplitParagraph;
 | |
|       insertTextOp.init({memberid:inputMemberId, position:cursorPosition, text:text, moveCursor:true});
 | |
|       operations.push(insertTextOp);
 | |
|       cursorPosition += text.length;
 | |
|       splitParagraphOp.init({memberid:inputMemberId, position:cursorPosition, paragraphStyleName:paragraphStyle, sourceParagraphPosition:currentParagraphStartPosition, moveCursor:true});
 | |
|       operations.push(splitParagraphOp);
 | |
|       cursorPosition += 1;
 | |
|       currentParagraphStartPosition = cursorPosition;
 | |
|     });
 | |
|     operations.pop();
 | |
|     session.enqueue(operations);
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.unsubscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.subscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     updateEnabledState();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.ClosestXOffsetScanner = function(offset) {
 | |
|   var self = this, closestDiff, LEFT_TO_RIGHT = gui.StepInfo.VisualDirection.LEFT_TO_RIGHT;
 | |
|   this.token = undefined;
 | |
|   function isFurtherFromOffset(edgeOffset) {
 | |
|     if (edgeOffset !== null && closestDiff !== undefined) {
 | |
|       return Math.abs(edgeOffset - offset) > closestDiff;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function updateDiffIfSmaller(edge) {
 | |
|     if (edge !== null && isFurtherFromOffset(edge) === false) {
 | |
|       closestDiff = Math.abs(edge - offset);
 | |
|     }
 | |
|   }
 | |
|   this.process = function(stepInfo, previousRect, nextRect) {
 | |
|     var edge1, edge2;
 | |
|     if (stepInfo.visualDirection === LEFT_TO_RIGHT) {
 | |
|       edge1 = previousRect && previousRect.right;
 | |
|       edge2 = nextRect && nextRect.left;
 | |
|     } else {
 | |
|       edge1 = previousRect && previousRect.left;
 | |
|       edge2 = nextRect && nextRect.right;
 | |
|     }
 | |
|     if (isFurtherFromOffset(edge1) || isFurtherFromOffset(edge2)) {
 | |
|       return true;
 | |
|     }
 | |
|     if (previousRect || nextRect) {
 | |
|       updateDiffIfSmaller(edge1);
 | |
|       updateDiffIfSmaller(edge2);
 | |
|       self.token = stepInfo.token;
 | |
|     }
 | |
|     return false;
 | |
|   };
 | |
| };
 | |
| gui.LineBoundaryScanner = function() {
 | |
|   var self = this, lineRect = null, MIN_OVERLAP_THRESHOLD = .4;
 | |
|   function verticalOverlapPercent(rect1, rect2) {
 | |
|     var rect1Height = rect1.bottom - rect1.top, rect2Height = rect2.bottom - rect2.top, minRectHeight = Math.min(rect1Height, rect2Height), intersectTop = Math.max(rect1.top, rect2.top), intersectBottom = Math.min(rect1.bottom, rect2.bottom), overlapHeight = intersectBottom - intersectTop;
 | |
|     return minRectHeight > 0 ? overlapHeight / minRectHeight : 0;
 | |
|   }
 | |
|   function isLineBoundary(nextRect) {
 | |
|     if (lineRect) {
 | |
|       return verticalOverlapPercent((lineRect), nextRect) <= MIN_OVERLAP_THRESHOLD;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function combineRects(rect1, rect2) {
 | |
|     return {left:Math.min(rect1.left, rect2.left), right:Math.max(rect1.right, rect2.right), top:Math.min(rect1.top, rect2.top), bottom:Math.min(rect1.bottom, rect2.bottom)};
 | |
|   }
 | |
|   function growRect(originalRect, newRect) {
 | |
|     if (originalRect && newRect) {
 | |
|       return combineRects((originalRect), (newRect));
 | |
|     }
 | |
|     return originalRect || newRect;
 | |
|   }
 | |
|   this.token = undefined;
 | |
|   this.process = function(stepInfo, previousRect, nextRect) {
 | |
|     var isOverLineBoundary = nextRect && isLineBoundary((nextRect));
 | |
|     if (previousRect && (!nextRect || isOverLineBoundary)) {
 | |
|       self.token = stepInfo.token;
 | |
|     }
 | |
|     if (isOverLineBoundary) {
 | |
|       return true;
 | |
|     }
 | |
|     lineRect = growRect(lineRect, previousRect);
 | |
|     return false;
 | |
|   };
 | |
| };
 | |
| gui.ParagraphBoundaryScanner = function() {
 | |
|   var self = this, isInitialised = false, lastParagraph, odfUtils = odf.OdfUtils;
 | |
|   this.token = undefined;
 | |
|   this.process = function(stepInfo) {
 | |
|     var currentParagraph = odfUtils.getParagraphElement(stepInfo.container());
 | |
|     if (!isInitialised) {
 | |
|       lastParagraph = currentParagraph;
 | |
|       isInitialised = true;
 | |
|     }
 | |
|     if (lastParagraph !== currentParagraph) {
 | |
|       return true;
 | |
|     }
 | |
|     self.token = stepInfo.token;
 | |
|     return false;
 | |
|   };
 | |
| };
 | |
| odf.WordBoundaryFilter = function WordBoundaryFilter(odtDocument, includeWhitespace) {
 | |
|   var TEXT_NODE = Node.TEXT_NODE, ELEMENT_NODE = Node.ELEMENT_NODE, odfUtils = odf.OdfUtils, punctuation = /[!-#%-*,-\/:-;?-@\[-\]_{}\u00a1\u00ab\u00b7\u00bb\u00bf;\u00b7\u055a-\u055f\u0589-\u058a\u05be\u05c0\u05c3\u05c6\u05f3-\u05f4\u0609-\u060a\u060c-\u060d\u061b\u061e-\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0964-\u0965\u0970\u0df4\u0e4f\u0e5a-\u0e5b\u0f04-\u0f12\u0f3a-\u0f3d\u0f85\u0fd0-\u0fd4\u104a-\u104f\u10fb\u1361-\u1368\u166d-\u166e\u169b-\u169c\u16eb-\u16ed\u1735-\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u180a\u1944-\u1945\u19de-\u19df\u1a1e-\u1a1f\u1b5a-\u1b60\u1c3b-\u1c3f\u1c7e-\u1c7f\u2000-\u206e\u207d-\u207e\u208d-\u208e\u3008-\u3009\u2768-\u2775\u27c5-\u27c6\u27e6-\u27ef\u2983-\u2998\u29d8-\u29db\u29fc-\u29fd\u2cf9-\u2cfc\u2cfe-\u2cff\u2e00-\u2e7e\u3000-\u303f\u30a0\u30fb\ua60d-\ua60f\ua673\ua67e\ua874-\ua877\ua8ce-\ua8cf\ua92e-\ua92f\ua95f\uaa5c-\uaa5f\ufd3e-\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe61\ufe63\ufe68\ufe6a-\ufe6b\uff01-\uff03\uff05-\uff0a\uff0c-\uff0f\uff1a-\uff1b\uff1f-\uff20\uff3b-\uff3d\uff3f\uff5b\uff5d\uff5f-\uff65]|\ud800[\udd00-\udd01\udf9f\udfd0]|\ud802[\udd1f\udd3f\ude50-\ude58]|\ud809[\udc00-\udc7e]/, 
 | |
|   spacing = /\s/, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT, TRAILING = odf.WordBoundaryFilter.IncludeWhitespace.TRAILING, LEADING = odf.WordBoundaryFilter.IncludeWhitespace.LEADING, NeighborType = {NO_NEIGHBOUR:0, SPACE_CHAR:1, PUNCTUATION_CHAR:2, WORD_CHAR:3, OTHER:4};
 | |
|   function findHigherNeighborNode(node, direction, nodeFilter) {
 | |
|     var neighboringNode = null, rootNode = odtDocument.getRootNode(), unfilteredCandidate;
 | |
|     while (node !== rootNode && node !== null && neighboringNode === null) {
 | |
|       unfilteredCandidate = direction < 0 ? node.previousSibling : node.nextSibling;
 | |
|       if (nodeFilter(unfilteredCandidate) === NodeFilter.FILTER_ACCEPT) {
 | |
|         neighboringNode = unfilteredCandidate;
 | |
|       }
 | |
|       node = node.parentNode;
 | |
|     }
 | |
|     return neighboringNode;
 | |
|   }
 | |
|   function typeOfNeighbor(node, getOffset) {
 | |
|     var neighboringChar;
 | |
|     if (node === null) {
 | |
|       return NeighborType.NO_NEIGHBOUR;
 | |
|     }
 | |
|     if (odfUtils.isCharacterElement(node)) {
 | |
|       return NeighborType.SPACE_CHAR;
 | |
|     }
 | |
|     if (node.nodeType === TEXT_NODE || odfUtils.isTextSpan(node) || odfUtils.isHyperlink(node)) {
 | |
|       neighboringChar = node.textContent.charAt(getOffset());
 | |
|       if (spacing.test(neighboringChar)) {
 | |
|         return NeighborType.SPACE_CHAR;
 | |
|       }
 | |
|       if (punctuation.test(neighboringChar)) {
 | |
|         return NeighborType.PUNCTUATION_CHAR;
 | |
|       }
 | |
|       return NeighborType.WORD_CHAR;
 | |
|     }
 | |
|     return NeighborType.OTHER;
 | |
|   }
 | |
|   this.acceptPosition = function(iterator) {
 | |
|     var container = iterator.container(), leftNode = iterator.leftNode(), rightNode = iterator.rightNode(), getRightCharOffset = iterator.unfilteredDomOffset, getLeftCharOffset = function() {
 | |
|       return iterator.unfilteredDomOffset() - 1;
 | |
|     }, leftNeighborType, rightNeighborType;
 | |
|     if (container.nodeType === ELEMENT_NODE) {
 | |
|       if (rightNode === null) {
 | |
|         rightNode = findHigherNeighborNode(container, 1, iterator.getNodeFilter());
 | |
|       }
 | |
|       if (leftNode === null) {
 | |
|         leftNode = findHigherNeighborNode(container, -1, iterator.getNodeFilter());
 | |
|       }
 | |
|     }
 | |
|     if (container !== rightNode) {
 | |
|       getRightCharOffset = function() {
 | |
|         return 0;
 | |
|       };
 | |
|     }
 | |
|     if (container !== leftNode && leftNode !== null) {
 | |
|       getLeftCharOffset = function() {
 | |
|         return leftNode.textContent.length - 1;
 | |
|       };
 | |
|     }
 | |
|     leftNeighborType = typeOfNeighbor(leftNode, getLeftCharOffset);
 | |
|     rightNeighborType = typeOfNeighbor(rightNode, getRightCharOffset);
 | |
|     if (leftNeighborType === NeighborType.WORD_CHAR && rightNeighborType === NeighborType.WORD_CHAR || leftNeighborType === NeighborType.PUNCTUATION_CHAR && rightNeighborType === NeighborType.PUNCTUATION_CHAR || includeWhitespace === TRAILING && leftNeighborType !== NeighborType.NO_NEIGHBOUR && rightNeighborType === NeighborType.SPACE_CHAR || includeWhitespace === LEADING && leftNeighborType === NeighborType.SPACE_CHAR && rightNeighborType !== NeighborType.NO_NEIGHBOUR) {
 | |
|       return FILTER_REJECT;
 | |
|     }
 | |
|     return FILTER_ACCEPT;
 | |
|   };
 | |
| };
 | |
| odf.WordBoundaryFilter.IncludeWhitespace = {None:0, TRAILING:1, LEADING:2};
 | |
| gui.SelectionController = function SelectionController(session, inputMemberId) {
 | |
|   var odtDocument = session.getOdtDocument(), domUtils = core.DomUtils, odfUtils = odf.OdfUtils, baseFilter = odtDocument.getPositionFilter(), guiStepUtils = new gui.GuiStepUtils, rootFilter = odtDocument.createRootFilter(inputMemberId), caretXPositionLocator = null, lastXPosition, resetLastXPositionTask, TRAILING_SPACE = odf.WordBoundaryFilter.IncludeWhitespace.TRAILING, LEADING_SPACE = odf.WordBoundaryFilter.IncludeWhitespace.LEADING, PREVIOUS = core.StepDirection.PREVIOUS, NEXT = core.StepDirection.NEXT, 
 | |
|   UPDOWN_NAVIGATION_RESET_DELAY_MS = 2E3;
 | |
|   function resetLastXPosition(op) {
 | |
|     var opspec = op.spec();
 | |
|     if (op.isEdit || opspec.memberid === inputMemberId) {
 | |
|       lastXPosition = undefined;
 | |
|       resetLastXPositionTask.cancel();
 | |
|     }
 | |
|   }
 | |
|   function createKeyboardStepIterator() {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), node = cursor.getNode();
 | |
|     return odtDocument.createStepIterator(node, 0, [baseFilter, rootFilter], odtDocument.getRootElement(node));
 | |
|   }
 | |
|   function createWordBoundaryStepIterator(node, offset, includeWhitespace) {
 | |
|     var wordBoundaryFilter = new odf.WordBoundaryFilter(odtDocument, includeWhitespace), nodeRoot = odtDocument.getRootElement(node) || odtDocument.getRootNode(), nodeRootFilter = odtDocument.createRootFilter(nodeRoot);
 | |
|     return odtDocument.createStepIterator(node, offset, [baseFilter, nodeRootFilter, wordBoundaryFilter], nodeRoot);
 | |
|   }
 | |
|   function selectionToRange(selection) {
 | |
|     var hasForwardSelection = domUtils.comparePoints((selection.anchorNode), selection.anchorOffset, (selection.focusNode), selection.focusOffset) >= 0, range = selection.focusNode.ownerDocument.createRange();
 | |
|     if (hasForwardSelection) {
 | |
|       range.setStart(selection.anchorNode, selection.anchorOffset);
 | |
|       range.setEnd(selection.focusNode, selection.focusOffset);
 | |
|     } else {
 | |
|       range.setStart(selection.focusNode, selection.focusOffset);
 | |
|       range.setEnd(selection.anchorNode, selection.anchorOffset);
 | |
|     }
 | |
|     return {range:range, hasForwardSelection:hasForwardSelection};
 | |
|   }
 | |
|   this.selectionToRange = selectionToRange;
 | |
|   function rangeToSelection(range, hasForwardSelection) {
 | |
|     if (hasForwardSelection) {
 | |
|       return {anchorNode:(range.startContainer), anchorOffset:range.startOffset, focusNode:(range.endContainer), focusOffset:range.endOffset};
 | |
|     }
 | |
|     return {anchorNode:(range.endContainer), anchorOffset:range.endOffset, focusNode:(range.startContainer), focusOffset:range.startOffset};
 | |
|   }
 | |
|   this.rangeToSelection = rangeToSelection;
 | |
|   function createOpMoveCursor(position, length, selectionType) {
 | |
|     var op = new ops.OpMoveCursor;
 | |
|     op.init({memberid:inputMemberId, position:position, length:length || 0, selectionType:selectionType});
 | |
|     return op;
 | |
|   }
 | |
|   function moveCursorFocusPoint(focusNode, focusOffset, extend) {
 | |
|     var cursor, newSelection, newCursorSelection;
 | |
|     cursor = odtDocument.getCursor(inputMemberId);
 | |
|     newSelection = rangeToSelection(cursor.getSelectedRange(), cursor.hasForwardSelection());
 | |
|     newSelection.focusNode = focusNode;
 | |
|     newSelection.focusOffset = focusOffset;
 | |
|     if (!extend) {
 | |
|       newSelection.anchorNode = newSelection.focusNode;
 | |
|       newSelection.anchorOffset = newSelection.focusOffset;
 | |
|     }
 | |
|     newCursorSelection = odtDocument.convertDomToCursorRange(newSelection);
 | |
|     session.enqueue([createOpMoveCursor(newCursorSelection.position, newCursorSelection.length)]);
 | |
|   }
 | |
|   function selectImage(frameNode) {
 | |
|     var frameRoot = odtDocument.getRootElement(frameNode), frameRootFilter = odtDocument.createRootFilter(frameRoot), stepIterator = odtDocument.createStepIterator(frameNode, 0, [frameRootFilter, odtDocument.getPositionFilter()], frameRoot), anchorNode, anchorOffset, newSelection, op;
 | |
|     if (!stepIterator.roundToPreviousStep()) {
 | |
|       runtime.assert(false, "No walkable position before frame");
 | |
|     }
 | |
|     anchorNode = stepIterator.container();
 | |
|     anchorOffset = stepIterator.offset();
 | |
|     stepIterator.setPosition(frameNode, frameNode.childNodes.length);
 | |
|     if (!stepIterator.roundToNextStep()) {
 | |
|       runtime.assert(false, "No walkable position after frame");
 | |
|     }
 | |
|     newSelection = odtDocument.convertDomToCursorRange({anchorNode:anchorNode, anchorOffset:anchorOffset, focusNode:stepIterator.container(), focusOffset:stepIterator.offset()});
 | |
|     op = createOpMoveCursor(newSelection.position, newSelection.length, ops.OdtCursor.RegionSelection);
 | |
|     session.enqueue([op]);
 | |
|   }
 | |
|   this.selectImage = selectImage;
 | |
|   function expandToWordBoundaries(range) {
 | |
|     var stepIterator;
 | |
|     stepIterator = createWordBoundaryStepIterator((range.startContainer), range.startOffset, TRAILING_SPACE);
 | |
|     if (stepIterator.roundToPreviousStep()) {
 | |
|       range.setStart(stepIterator.container(), stepIterator.offset());
 | |
|     }
 | |
|     stepIterator = createWordBoundaryStepIterator((range.endContainer), range.endOffset, LEADING_SPACE);
 | |
|     if (stepIterator.roundToNextStep()) {
 | |
|       range.setEnd(stepIterator.container(), stepIterator.offset());
 | |
|     }
 | |
|   }
 | |
|   this.expandToWordBoundaries = expandToWordBoundaries;
 | |
|   function expandToParagraphBoundaries(range) {
 | |
|     var paragraphs = odfUtils.getParagraphElements(range), startParagraph = paragraphs[0], endParagraph = paragraphs[paragraphs.length - 1];
 | |
|     if (startParagraph) {
 | |
|       range.setStart(startParagraph, 0);
 | |
|     }
 | |
|     if (endParagraph) {
 | |
|       if (odfUtils.isParagraph(range.endContainer) && range.endOffset === 0) {
 | |
|         range.setEndBefore(endParagraph);
 | |
|       } else {
 | |
|         range.setEnd(endParagraph, endParagraph.childNodes.length);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   this.expandToParagraphBoundaries = expandToParagraphBoundaries;
 | |
|   function roundToClosestStep(root, filters, range, modifyStart) {
 | |
|     var stepIterator, node, offset;
 | |
|     if (modifyStart) {
 | |
|       node = (range.startContainer);
 | |
|       offset = range.startOffset;
 | |
|     } else {
 | |
|       node = (range.endContainer);
 | |
|       offset = range.endOffset;
 | |
|     }
 | |
|     if (!domUtils.containsNode(root, node)) {
 | |
|       if (domUtils.comparePoints(root, 0, node, offset) < 0) {
 | |
|         offset = 0;
 | |
|       } else {
 | |
|         offset = root.childNodes.length;
 | |
|       }
 | |
|       node = root;
 | |
|     }
 | |
|     stepIterator = odtDocument.createStepIterator(node, offset, filters, odfUtils.getParagraphElement(node) || root);
 | |
|     if (!stepIterator.roundToClosestStep()) {
 | |
|       runtime.assert(false, "No step found in requested range");
 | |
|     }
 | |
|     if (modifyStart) {
 | |
|       range.setStart(stepIterator.container(), stepIterator.offset());
 | |
|     } else {
 | |
|       range.setEnd(stepIterator.container(), stepIterator.offset());
 | |
|     }
 | |
|   }
 | |
|   function selectRange(range, hasForwardSelection, clickCount) {
 | |
|     var canvasElement = odtDocument.getOdfCanvas().getElement(), validSelection, startInsideCanvas, endInsideCanvas, existingSelection, newSelection, anchorRoot, filters = [baseFilter], op;
 | |
|     startInsideCanvas = domUtils.containsNode(canvasElement, range.startContainer);
 | |
|     endInsideCanvas = domUtils.containsNode(canvasElement, range.endContainer);
 | |
|     if (!startInsideCanvas && !endInsideCanvas) {
 | |
|       return;
 | |
|     }
 | |
|     if (startInsideCanvas && endInsideCanvas) {
 | |
|       if (clickCount === 2) {
 | |
|         expandToWordBoundaries(range);
 | |
|       } else {
 | |
|         if (clickCount >= 3) {
 | |
|           expandToParagraphBoundaries(range);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (hasForwardSelection) {
 | |
|       anchorRoot = odtDocument.getRootElement((range.startContainer));
 | |
|     } else {
 | |
|       anchorRoot = odtDocument.getRootElement((range.endContainer));
 | |
|     }
 | |
|     if (!anchorRoot) {
 | |
|       anchorRoot = odtDocument.getRootNode();
 | |
|     }
 | |
|     filters.push(odtDocument.createRootFilter(anchorRoot));
 | |
|     roundToClosestStep(anchorRoot, filters, range, true);
 | |
|     roundToClosestStep(anchorRoot, filters, range, false);
 | |
|     validSelection = rangeToSelection(range, hasForwardSelection);
 | |
|     newSelection = odtDocument.convertDomToCursorRange(validSelection);
 | |
|     existingSelection = odtDocument.getCursorSelection(inputMemberId);
 | |
|     if (newSelection.position !== existingSelection.position || newSelection.length !== existingSelection.length) {
 | |
|       op = createOpMoveCursor(newSelection.position, newSelection.length, ops.OdtCursor.RangeSelection);
 | |
|       session.enqueue([op]);
 | |
|     }
 | |
|   }
 | |
|   this.selectRange = selectRange;
 | |
|   function moveCursor(direction, extend) {
 | |
|     var stepIterator = createKeyboardStepIterator();
 | |
|     if (stepIterator.advanceStep(direction)) {
 | |
|       moveCursorFocusPoint(stepIterator.container(), stepIterator.offset(), extend);
 | |
|     }
 | |
|   }
 | |
|   function moveCursorToLeft() {
 | |
|     moveCursor(PREVIOUS, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorToLeft = moveCursorToLeft;
 | |
|   function moveCursorToRight() {
 | |
|     moveCursor(NEXT, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorToRight = moveCursorToRight;
 | |
|   function extendSelectionToLeft() {
 | |
|     moveCursor(PREVIOUS, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionToLeft = extendSelectionToLeft;
 | |
|   function extendSelectionToRight() {
 | |
|     moveCursor(NEXT, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionToRight = extendSelectionToRight;
 | |
|   this.setCaretXPositionLocator = function(locator) {
 | |
|     caretXPositionLocator = locator;
 | |
|   };
 | |
|   function moveCursorByLine(direction, extend) {
 | |
|     var stepIterator, currentX = lastXPosition, stepScanners = [new gui.LineBoundaryScanner, new gui.ParagraphBoundaryScanner];
 | |
|     if (currentX === undefined && caretXPositionLocator) {
 | |
|       currentX = caretXPositionLocator();
 | |
|     }
 | |
|     if (isNaN(currentX)) {
 | |
|       return;
 | |
|     }
 | |
|     stepIterator = createKeyboardStepIterator();
 | |
|     if (!guiStepUtils.moveToFilteredStep(stepIterator, direction, stepScanners)) {
 | |
|       return;
 | |
|     }
 | |
|     if (!stepIterator.advanceStep(direction)) {
 | |
|       return;
 | |
|     }
 | |
|     stepScanners = [new gui.ClosestXOffsetScanner((currentX)), new gui.LineBoundaryScanner, new gui.ParagraphBoundaryScanner];
 | |
|     if (guiStepUtils.moveToFilteredStep(stepIterator, direction, stepScanners)) {
 | |
|       moveCursorFocusPoint(stepIterator.container(), stepIterator.offset(), extend);
 | |
|       lastXPosition = currentX;
 | |
|       resetLastXPositionTask.restart();
 | |
|     }
 | |
|   }
 | |
|   function moveCursorUp() {
 | |
|     moveCursorByLine(PREVIOUS, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorUp = moveCursorUp;
 | |
|   function moveCursorDown() {
 | |
|     moveCursorByLine(NEXT, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorDown = moveCursorDown;
 | |
|   function extendSelectionUp() {
 | |
|     moveCursorByLine(PREVIOUS, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionUp = extendSelectionUp;
 | |
|   function extendSelectionDown() {
 | |
|     moveCursorByLine(NEXT, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionDown = extendSelectionDown;
 | |
|   function moveCursorToLineBoundary(direction, extend) {
 | |
|     var stepIterator = createKeyboardStepIterator(), stepScanners = [new gui.LineBoundaryScanner, new gui.ParagraphBoundaryScanner];
 | |
|     if (guiStepUtils.moveToFilteredStep(stepIterator, direction, stepScanners)) {
 | |
|       moveCursorFocusPoint(stepIterator.container(), stepIterator.offset(), extend);
 | |
|     }
 | |
|   }
 | |
|   function moveCursorByWord(direction, extend) {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), newSelection = rangeToSelection(cursor.getSelectedRange(), cursor.hasForwardSelection()), stepIterator = createWordBoundaryStepIterator(newSelection.focusNode, newSelection.focusOffset, TRAILING_SPACE);
 | |
|     if (stepIterator.advanceStep(direction)) {
 | |
|       moveCursorFocusPoint(stepIterator.container(), stepIterator.offset(), extend);
 | |
|     }
 | |
|   }
 | |
|   function moveCursorBeforeWord() {
 | |
|     moveCursorByWord(PREVIOUS, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorBeforeWord = moveCursorBeforeWord;
 | |
|   function moveCursorPastWord() {
 | |
|     moveCursorByWord(NEXT, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorPastWord = moveCursorPastWord;
 | |
|   function extendSelectionBeforeWord() {
 | |
|     moveCursorByWord(PREVIOUS, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionBeforeWord = extendSelectionBeforeWord;
 | |
|   function extendSelectionPastWord() {
 | |
|     moveCursorByWord(NEXT, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionPastWord = extendSelectionPastWord;
 | |
|   function moveCursorToLineStart() {
 | |
|     moveCursorToLineBoundary(PREVIOUS, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorToLineStart = moveCursorToLineStart;
 | |
|   function moveCursorToLineEnd() {
 | |
|     moveCursorToLineBoundary(NEXT, false);
 | |
|     return true;
 | |
|   }
 | |
|   this.moveCursorToLineEnd = moveCursorToLineEnd;
 | |
|   function extendSelectionToLineStart() {
 | |
|     moveCursorToLineBoundary(PREVIOUS, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionToLineStart = extendSelectionToLineStart;
 | |
|   function extendSelectionToLineEnd() {
 | |
|     moveCursorToLineBoundary(NEXT, true);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionToLineEnd = extendSelectionToLineEnd;
 | |
|   function adjustSelectionByNode(direction, extend, getContainmentNode) {
 | |
|     var validStepFound = false, cursor = odtDocument.getCursor(inputMemberId), containmentNode, selection = rangeToSelection(cursor.getSelectedRange(), cursor.hasForwardSelection()), rootElement = odtDocument.getRootElement(selection.focusNode), stepIterator;
 | |
|     runtime.assert(Boolean(rootElement), "SelectionController: Cursor outside root");
 | |
|     stepIterator = odtDocument.createStepIterator(selection.focusNode, selection.focusOffset, [baseFilter, rootFilter], rootElement);
 | |
|     stepIterator.roundToClosestStep();
 | |
|     if (!stepIterator.advanceStep(direction)) {
 | |
|       return;
 | |
|     }
 | |
|     containmentNode = getContainmentNode(stepIterator.container());
 | |
|     if (!containmentNode) {
 | |
|       return;
 | |
|     }
 | |
|     if (direction === PREVIOUS) {
 | |
|       stepIterator.setPosition((containmentNode), 0);
 | |
|       validStepFound = stepIterator.roundToNextStep();
 | |
|     } else {
 | |
|       stepIterator.setPosition((containmentNode), containmentNode.childNodes.length);
 | |
|       validStepFound = stepIterator.roundToPreviousStep();
 | |
|     }
 | |
|     if (validStepFound) {
 | |
|       moveCursorFocusPoint(stepIterator.container(), stepIterator.offset(), extend);
 | |
|     }
 | |
|   }
 | |
|   this.extendSelectionToParagraphStart = function() {
 | |
|     adjustSelectionByNode(PREVIOUS, true, odfUtils.getParagraphElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.extendSelectionToParagraphEnd = function() {
 | |
|     adjustSelectionByNode(NEXT, true, odfUtils.getParagraphElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.moveCursorToParagraphStart = function() {
 | |
|     adjustSelectionByNode(PREVIOUS, false, odfUtils.getParagraphElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.moveCursorToParagraphEnd = function() {
 | |
|     adjustSelectionByNode(NEXT, false, odfUtils.getParagraphElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.moveCursorToDocumentStart = function() {
 | |
|     adjustSelectionByNode(PREVIOUS, false, odtDocument.getRootElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.moveCursorToDocumentEnd = function() {
 | |
|     adjustSelectionByNode(NEXT, false, odtDocument.getRootElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.extendSelectionToDocumentStart = function() {
 | |
|     adjustSelectionByNode(PREVIOUS, true, odtDocument.getRootElement);
 | |
|     return true;
 | |
|   };
 | |
|   this.extendSelectionToDocumentEnd = function() {
 | |
|     adjustSelectionByNode(NEXT, true, odtDocument.getRootElement);
 | |
|     return true;
 | |
|   };
 | |
|   function extendSelectionToEntireDocument() {
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), rootElement = odtDocument.getRootElement(cursor.getNode()), anchorNode, anchorOffset, stepIterator, newCursorSelection;
 | |
|     runtime.assert(Boolean(rootElement), "SelectionController: Cursor outside root");
 | |
|     stepIterator = odtDocument.createStepIterator(rootElement, 0, [baseFilter, rootFilter], rootElement);
 | |
|     stepIterator.roundToClosestStep();
 | |
|     anchorNode = stepIterator.container();
 | |
|     anchorOffset = stepIterator.offset();
 | |
|     stepIterator.setPosition(rootElement, rootElement.childNodes.length);
 | |
|     stepIterator.roundToClosestStep();
 | |
|     newCursorSelection = odtDocument.convertDomToCursorRange({anchorNode:anchorNode, anchorOffset:anchorOffset, focusNode:stepIterator.container(), focusOffset:stepIterator.offset()});
 | |
|     session.enqueue([createOpMoveCursor(newCursorSelection.position, newCursorSelection.length)]);
 | |
|     return true;
 | |
|   }
 | |
|   this.extendSelectionToEntireDocument = extendSelectionToEntireDocument;
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.OdtDocument.signalOperationStart, resetLastXPosition);
 | |
|     core.Async.destroyAll([resetLastXPositionTask.destroy], callback);
 | |
|   };
 | |
|   function init() {
 | |
|     resetLastXPositionTask = core.Task.createTimeoutTask(function() {
 | |
|       lastXPosition = undefined;
 | |
|     }, UPDOWN_NAVIGATION_RESET_DELAY_MS);
 | |
|     odtDocument.subscribe(ops.OdtDocument.signalOperationStart, resetLastXPosition);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.TextController = function TextController(session, sessionConstraints, sessionContext, inputMemberId, directStyleOp, paragraphStyleOps) {
 | |
|   var odtDocument = session.getOdtDocument(), odfUtils = odf.OdfUtils, domUtils = core.DomUtils, BACKWARD = false, FORWARD = true, isEnabled = false, textns = odf.Namespaces.textns, NEXT = core.StepDirection.NEXT;
 | |
|   function updateEnabledState() {
 | |
|     if (sessionConstraints.getState(gui.CommonConstraints.EDIT.REVIEW_MODE) === true) {
 | |
|       isEnabled = (sessionContext.isLocalCursorWithinOwnAnnotation());
 | |
|     } else {
 | |
|       isEnabled = true;
 | |
|     }
 | |
|   }
 | |
|   function onCursorEvent(cursor) {
 | |
|     if (cursor.getMemberId() === inputMemberId) {
 | |
|       updateEnabledState();
 | |
|     }
 | |
|   }
 | |
|   this.isEnabled = function() {
 | |
|     return isEnabled;
 | |
|   };
 | |
|   function domToCursorRange(range, subTree, withRootFilter) {
 | |
|     var filters = [odtDocument.getPositionFilter()], startStep, endStep, stepIterator;
 | |
|     if (withRootFilter) {
 | |
|       filters.push(odtDocument.createRootFilter((range.startContainer)));
 | |
|     }
 | |
|     stepIterator = odtDocument.createStepIterator((range.startContainer), range.startOffset, filters, subTree);
 | |
|     if (!stepIterator.roundToClosestStep()) {
 | |
|       runtime.assert(false, "No walkable step found in paragraph element at range start");
 | |
|     }
 | |
|     startStep = odtDocument.convertDomPointToCursorStep(stepIterator.container(), stepIterator.offset());
 | |
|     if (range.collapsed) {
 | |
|       endStep = startStep;
 | |
|     } else {
 | |
|       stepIterator.setPosition((range.endContainer), range.endOffset);
 | |
|       if (!stepIterator.roundToClosestStep()) {
 | |
|         runtime.assert(false, "No walkable step found in paragraph element at range end");
 | |
|       }
 | |
|       endStep = odtDocument.convertDomPointToCursorStep(stepIterator.container(), stepIterator.offset());
 | |
|     }
 | |
|     return {position:(startStep), length:(endStep - startStep)};
 | |
|   }
 | |
|   function createRemoveSelectionOps(range) {
 | |
|     var firstParagraph, lastParagraph, mergedParagraphStyleName, previousParagraphStart, paragraphs = odfUtils.getParagraphElements(range), paragraphRange = (range.cloneRange()), operations = [];
 | |
|     firstParagraph = paragraphs[0];
 | |
|     if (paragraphs.length > 1) {
 | |
|       if (odfUtils.hasNoODFContent(firstParagraph)) {
 | |
|         lastParagraph = paragraphs[paragraphs.length - 1];
 | |
|         mergedParagraphStyleName = lastParagraph.getAttributeNS(odf.Namespaces.textns, "style-name") || "";
 | |
|       } else {
 | |
|         mergedParagraphStyleName = firstParagraph.getAttributeNS(odf.Namespaces.textns, "style-name") || "";
 | |
|       }
 | |
|     }
 | |
|     paragraphs.forEach(function(paragraph, index) {
 | |
|       var paragraphStart, removeLimits, intersectionRange, removeOp, mergeOp;
 | |
|       paragraphRange.setStart(paragraph, 0);
 | |
|       paragraphRange.collapse(true);
 | |
|       paragraphStart = domToCursorRange(paragraphRange, paragraph, false).position;
 | |
|       if (index > 0) {
 | |
|         mergeOp = new ops.OpMergeParagraph;
 | |
|         mergeOp.init({memberid:inputMemberId, paragraphStyleName:mergedParagraphStyleName, destinationStartPosition:previousParagraphStart, sourceStartPosition:paragraphStart, moveCursor:index === 1});
 | |
|         operations.unshift(mergeOp);
 | |
|       }
 | |
|       previousParagraphStart = paragraphStart;
 | |
|       paragraphRange.selectNodeContents(paragraph);
 | |
|       intersectionRange = domUtils.rangeIntersection(paragraphRange, range);
 | |
|       if (intersectionRange) {
 | |
|         removeLimits = domToCursorRange(intersectionRange, paragraph, true);
 | |
|         if (removeLimits.length > 0) {
 | |
|           removeOp = new ops.OpRemoveText;
 | |
|           removeOp.init({memberid:inputMemberId, position:removeLimits.position, length:removeLimits.length});
 | |
|           operations.unshift(removeOp);
 | |
|         }
 | |
|       }
 | |
|     });
 | |
|     return operations;
 | |
|   }
 | |
|   function toForwardSelection(selection) {
 | |
|     if (selection.length < 0) {
 | |
|       selection.position += selection.length;
 | |
|       selection.length = -selection.length;
 | |
|     }
 | |
|     return selection;
 | |
|   }
 | |
|   this.enqueueParagraphSplittingOps = function() {
 | |
|     if (!isEnabled) {
 | |
|       return false;
 | |
|     }
 | |
|     var cursor = odtDocument.getCursor(inputMemberId), range = cursor.getSelectedRange(), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op, operations = [], styleOps, originalParagraph = (odfUtils.getParagraphElement(cursor.getNode())), paragraphStyle = originalParagraph.getAttributeNS(textns, "style-name") || "";
 | |
|     if (selection.length > 0) {
 | |
|       operations = operations.concat(createRemoveSelectionOps(range));
 | |
|     }
 | |
|     op = new ops.OpSplitParagraph;
 | |
|     op.init({memberid:inputMemberId, position:selection.position, paragraphStyleName:paragraphStyle, sourceParagraphPosition:odtDocument.convertDomPointToCursorStep(originalParagraph, 0, NEXT), moveCursor:true});
 | |
|     operations.push(op);
 | |
|     if (paragraphStyleOps) {
 | |
|       styleOps = paragraphStyleOps(selection.position + 1);
 | |
|       operations = operations.concat(styleOps);
 | |
|     }
 | |
|     session.enqueue(operations);
 | |
|     return true;
 | |
|   };
 | |
|   function createStepIterator(cursorNode) {
 | |
|     var cursorRoot = odtDocument.getRootElement(cursorNode), filters = [odtDocument.getPositionFilter(), odtDocument.createRootFilter(cursorRoot)];
 | |
|     return odtDocument.createStepIterator(cursorNode, 0, filters, cursorRoot);
 | |
|   }
 | |
|   function removeTextInDirection(isForward) {
 | |
|     if (!isEnabled) {
 | |
|       return false;
 | |
|     }
 | |
|     var cursorNode, range = (odtDocument.getCursor(inputMemberId).getSelectedRange().cloneRange()), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), stepIterator;
 | |
|     if (selection.length === 0) {
 | |
|       selection = undefined;
 | |
|       cursorNode = odtDocument.getCursor(inputMemberId).getNode();
 | |
|       stepIterator = createStepIterator(cursorNode);
 | |
|       if (stepIterator.roundToClosestStep() && (isForward ? stepIterator.nextStep() : stepIterator.previousStep())) {
 | |
|         selection = toForwardSelection(odtDocument.convertDomToCursorRange({anchorNode:cursorNode, anchorOffset:0, focusNode:stepIterator.container(), focusOffset:stepIterator.offset()}));
 | |
|         if (isForward) {
 | |
|           range.setStart(cursorNode, 0);
 | |
|           range.setEnd(stepIterator.container(), stepIterator.offset());
 | |
|         } else {
 | |
|           range.setStart(stepIterator.container(), stepIterator.offset());
 | |
|           range.setEnd(cursorNode, 0);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (selection) {
 | |
|       session.enqueue(createRemoveSelectionOps(range));
 | |
|     }
 | |
|     return selection !== undefined;
 | |
|   }
 | |
|   this.removeTextByBackspaceKey = function() {
 | |
|     return removeTextInDirection(BACKWARD);
 | |
|   };
 | |
|   this.removeTextByDeleteKey = function() {
 | |
|     return removeTextInDirection(FORWARD);
 | |
|   };
 | |
|   this.removeCurrentSelection = function() {
 | |
|     if (!isEnabled) {
 | |
|       return false;
 | |
|     }
 | |
|     var range = odtDocument.getCursor(inputMemberId).getSelectedRange();
 | |
|     session.enqueue(createRemoveSelectionOps(range));
 | |
|     return true;
 | |
|   };
 | |
|   function insertText(text) {
 | |
|     if (!isEnabled) {
 | |
|       return;
 | |
|     }
 | |
|     var range = odtDocument.getCursor(inputMemberId).getSelectedRange(), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op, stylingOp, operations = [], useCachedStyle = false;
 | |
|     if (selection.length > 0) {
 | |
|       operations = operations.concat(createRemoveSelectionOps(range));
 | |
|       useCachedStyle = true;
 | |
|     }
 | |
|     op = new ops.OpInsertText;
 | |
|     op.init({memberid:inputMemberId, position:selection.position, text:text, moveCursor:true});
 | |
|     operations.push(op);
 | |
|     if (directStyleOp) {
 | |
|       stylingOp = directStyleOp(selection.position, text.length, useCachedStyle);
 | |
|       if (stylingOp) {
 | |
|         operations.push(stylingOp);
 | |
|       }
 | |
|     }
 | |
|     session.enqueue(operations);
 | |
|   }
 | |
|   this.insertText = insertText;
 | |
|   this.destroy = function(callback) {
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.unsubscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorEvent);
 | |
|     sessionConstraints.subscribe(gui.CommonConstraints.EDIT.REVIEW_MODE, updateEnabledState);
 | |
|     updateEnabledState();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.UndoManager = function UndoManager() {
 | |
| };
 | |
| gui.UndoManager.prototype.subscribe = function(signal, callback) {
 | |
| };
 | |
| gui.UndoManager.prototype.unsubscribe = function(signal, callback) {
 | |
| };
 | |
| gui.UndoManager.prototype.setDocument = function(newDocument) {
 | |
| };
 | |
| gui.UndoManager.prototype.setInitialState = function() {
 | |
| };
 | |
| gui.UndoManager.prototype.initialize = function() {
 | |
| };
 | |
| gui.UndoManager.prototype.purgeInitialState = function() {
 | |
| };
 | |
| gui.UndoManager.prototype.setPlaybackFunction = function(playback_func) {
 | |
| };
 | |
| gui.UndoManager.prototype.hasUndoStates = function() {
 | |
| };
 | |
| gui.UndoManager.prototype.hasRedoStates = function() {
 | |
| };
 | |
| gui.UndoManager.prototype.moveForward = function(states) {
 | |
| };
 | |
| gui.UndoManager.prototype.moveBackward = function(states) {
 | |
| };
 | |
| gui.UndoManager.prototype.onOperationExecuted = function(op) {
 | |
| };
 | |
| gui.UndoManager.prototype.isDocumentModified = function() {
 | |
| };
 | |
| gui.UndoManager.prototype.setDocumentModified = function(modified) {
 | |
| };
 | |
| gui.UndoManager.signalUndoStackChanged = "undoStackChanged";
 | |
| gui.UndoManager.signalUndoStateCreated = "undoStateCreated";
 | |
| gui.UndoManager.signalUndoStateModified = "undoStateModified";
 | |
| gui.UndoManager.signalDocumentModifiedChanged = "documentModifiedChanged";
 | |
| gui.SessionControllerOptions = function() {
 | |
|   this.directTextStylingEnabled = false;
 | |
|   this.directParagraphStylingEnabled = false;
 | |
|   this.annotationsEnabled = false;
 | |
| };
 | |
| (function() {
 | |
|   var FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
 | |
|   gui.SessionController = function SessionController(session, inputMemberId, shadowCursor, args) {
 | |
|     var window = (runtime.getWindow()), odtDocument = session.getOdtDocument(), sessionConstraints = new gui.SessionConstraints, sessionContext = new gui.SessionContext(session, inputMemberId), domUtils = core.DomUtils, odfUtils = odf.OdfUtils, mimeDataExporter = new gui.MimeDataExporter, clipboard = new gui.Clipboard(mimeDataExporter), keyDownHandler = new gui.KeyboardHandler, keyPressHandler = new gui.KeyboardHandler, keyUpHandler = new gui.KeyboardHandler, clickStartedWithinCanvas = false, objectNameGenerator = 
 | |
|     new odf.ObjectNameGenerator(odtDocument.getOdfCanvas().odfContainer(), inputMemberId), isMouseMoved = false, mouseDownRootFilter = null, handleMouseClickTimeoutId, undoManager = null, eventManager = new gui.EventManager(odtDocument), annotationsEnabled = args.annotationsEnabled, annotationController = new gui.AnnotationController(session, sessionConstraints, inputMemberId), directFormattingController = new gui.DirectFormattingController(session, sessionConstraints, sessionContext, inputMemberId, 
 | |
|     objectNameGenerator, args.directTextStylingEnabled, args.directParagraphStylingEnabled), createCursorStyleOp = (directFormattingController.createCursorStyleOp), createParagraphStyleOps = (directFormattingController.createParagraphStyleOps), textController = new gui.TextController(session, sessionConstraints, sessionContext, inputMemberId, createCursorStyleOp, createParagraphStyleOps), imageController = new gui.ImageController(session, sessionConstraints, sessionContext, inputMemberId, objectNameGenerator), 
 | |
|     imageSelector = new gui.ImageSelector(odtDocument.getOdfCanvas()), shadowCursorIterator = odtDocument.createPositionIterator(odtDocument.getRootNode()), drawShadowCursorTask, redrawRegionSelectionTask, pasteController = new gui.PasteController(session, sessionConstraints, sessionContext, inputMemberId), inputMethodEditor = new gui.InputMethodEditor(inputMemberId, eventManager), clickCount = 0, hyperlinkClickHandler = new gui.HyperlinkClickHandler(odtDocument.getOdfCanvas().getElement, keyDownHandler, 
 | |
|     keyUpHandler), hyperlinkController = new gui.HyperlinkController(session, sessionConstraints, sessionContext, inputMemberId), selectionController = new gui.SelectionController(session, inputMemberId), metadataController = new gui.MetadataController(session, inputMemberId), modifier = gui.KeyboardHandler.Modifier, keyCode = gui.KeyboardHandler.KeyCode, isMacOS = window.navigator.appVersion.toLowerCase().indexOf("mac") !== -1, isIOS = ["iPad", "iPod", "iPhone"].indexOf(window.navigator.platform) !== 
 | |
|     -1, iOSSafariSupport;
 | |
|     runtime.assert(window !== null, "Expected to be run in an environment which has a global window, like a browser.");
 | |
|     function getTarget(e) {
 | |
|       return (e.target) || e.srcElement || null;
 | |
|     }
 | |
|     function cancelEvent(event) {
 | |
|       if (event.preventDefault) {
 | |
|         event.preventDefault();
 | |
|       } else {
 | |
|         event.returnValue = false;
 | |
|       }
 | |
|     }
 | |
|     function caretPositionFromPoint(x, y) {
 | |
|       var doc = odtDocument.getDOMDocument(), c, result = null;
 | |
|       if (doc.caretRangeFromPoint) {
 | |
|         c = doc.caretRangeFromPoint(x, y);
 | |
|         result = {container:(c.startContainer), offset:c.startOffset};
 | |
|       } else {
 | |
|         if (doc.caretPositionFromPoint) {
 | |
|           c = doc.caretPositionFromPoint(x, y);
 | |
|           if (c && c.offsetNode) {
 | |
|             result = {container:c.offsetNode, offset:c.offset};
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       return result;
 | |
|     }
 | |
|     function redrawRegionSelection() {
 | |
|       var cursor = odtDocument.getCursor(inputMemberId), imageElement;
 | |
|       if (cursor && cursor.getSelectionType() === ops.OdtCursor.RegionSelection) {
 | |
|         imageElement = odfUtils.getImageElements(cursor.getSelectedRange())[0];
 | |
|         if (imageElement) {
 | |
|           imageSelector.select((imageElement.parentNode));
 | |
|           return;
 | |
|         }
 | |
|       }
 | |
|       imageSelector.clearSelection();
 | |
|     }
 | |
|     function stringFromKeyPress(event) {
 | |
|       if (event.which === null || event.which === undefined) {
 | |
|         return String.fromCharCode(event.keyCode);
 | |
|       }
 | |
|       if (event.which !== 0 && event.charCode !== 0) {
 | |
|         return String.fromCharCode(event.which);
 | |
|       }
 | |
|       return null;
 | |
|     }
 | |
|     function handleCut(e) {
 | |
|       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
 | |
|       if (selectedRange.collapsed) {
 | |
|         e.preventDefault();
 | |
|         return;
 | |
|       }
 | |
|       if (clipboard.setDataFromRange(e, selectedRange)) {
 | |
|         textController.removeCurrentSelection();
 | |
|       } else {
 | |
|         runtime.log("Cut operation failed");
 | |
|       }
 | |
|     }
 | |
|     function handleBeforeCut() {
 | |
|       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
 | |
|       return selectedRange.collapsed !== false;
 | |
|     }
 | |
|     function handleCopy(e) {
 | |
|       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
 | |
|       if (selectedRange.collapsed) {
 | |
|         e.preventDefault();
 | |
|         return;
 | |
|       }
 | |
|       if (!clipboard.setDataFromRange(e, selectedRange)) {
 | |
|         runtime.log("Copy operation failed");
 | |
|       }
 | |
|     }
 | |
|     function handlePaste(e) {
 | |
|       var plainText;
 | |
|       if (window.clipboardData && window.clipboardData.getData) {
 | |
|         plainText = window.clipboardData.getData("Text");
 | |
|       } else {
 | |
|         if (e.clipboardData && e.clipboardData.getData) {
 | |
|           plainText = e.clipboardData.getData("text/plain");
 | |
|         }
 | |
|       }
 | |
|       if (plainText) {
 | |
|         textController.removeCurrentSelection();
 | |
|         pasteController.paste(plainText);
 | |
|       }
 | |
|       cancelEvent(e);
 | |
|     }
 | |
|     function handleBeforePaste() {
 | |
|       return false;
 | |
|     }
 | |
|     function updateUndoStack(op) {
 | |
|       if (undoManager) {
 | |
|         undoManager.onOperationExecuted(op);
 | |
|       }
 | |
|     }
 | |
|     function forwardUndoStackChange(e) {
 | |
|       odtDocument.emit(ops.OdtDocument.signalUndoStackChanged, e);
 | |
|     }
 | |
|     function undo() {
 | |
|       var hadFocusBefore;
 | |
|       if (undoManager) {
 | |
|         hadFocusBefore = eventManager.hasFocus();
 | |
|         undoManager.moveBackward(1);
 | |
|         if (hadFocusBefore) {
 | |
|           eventManager.focus();
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
|     this.undo = undo;
 | |
|     function redo() {
 | |
|       var hadFocusBefore;
 | |
|       if (undoManager) {
 | |
|         hadFocusBefore = eventManager.hasFocus();
 | |
|         undoManager.moveForward(1);
 | |
|         if (hadFocusBefore) {
 | |
|           eventManager.focus();
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
|     this.redo = redo;
 | |
|     function extendSelectionByDrag(event) {
 | |
|       var position, cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange(), newSelectionRange, handleEnd = (getTarget(event)).getAttribute("end");
 | |
|       if (selectedRange && handleEnd) {
 | |
|         position = caretPositionFromPoint(event.clientX, event.clientY);
 | |
|         if (position) {
 | |
|           shadowCursorIterator.setUnfilteredPosition(position.container, position.offset);
 | |
|           if (mouseDownRootFilter.acceptPosition(shadowCursorIterator) === FILTER_ACCEPT) {
 | |
|             newSelectionRange = (selectedRange.cloneRange());
 | |
|             if (handleEnd === "left") {
 | |
|               newSelectionRange.setStart(shadowCursorIterator.container(), shadowCursorIterator.unfilteredDomOffset());
 | |
|             } else {
 | |
|               newSelectionRange.setEnd(shadowCursorIterator.container(), shadowCursorIterator.unfilteredDomOffset());
 | |
|             }
 | |
|             shadowCursor.setSelectedRange(newSelectionRange, handleEnd === "right");
 | |
|             odtDocument.emit(ops.Document.signalCursorMoved, shadowCursor);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function updateCursorSelection() {
 | |
|       selectionController.selectRange(shadowCursor.getSelectedRange(), shadowCursor.hasForwardSelection(), 1);
 | |
|     }
 | |
|     function updateShadowCursor() {
 | |
|       var selection = window.getSelection(), selectionRange = selection.rangeCount > 0 && selectionController.selectionToRange(selection);
 | |
|       if (clickStartedWithinCanvas && selectionRange) {
 | |
|         isMouseMoved = true;
 | |
|         imageSelector.clearSelection();
 | |
|         shadowCursorIterator.setUnfilteredPosition((selection.focusNode), selection.focusOffset);
 | |
|         if (mouseDownRootFilter.acceptPosition(shadowCursorIterator) === FILTER_ACCEPT) {
 | |
|           if (clickCount === 2) {
 | |
|             selectionController.expandToWordBoundaries(selectionRange.range);
 | |
|           } else {
 | |
|             if (clickCount >= 3) {
 | |
|               selectionController.expandToParagraphBoundaries(selectionRange.range);
 | |
|             }
 | |
|           }
 | |
|           shadowCursor.setSelectedRange(selectionRange.range, selectionRange.hasForwardSelection);
 | |
|           odtDocument.emit(ops.Document.signalCursorMoved, shadowCursor);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function synchronizeWindowSelection(cursor) {
 | |
|       var selection = window.getSelection(), range = cursor.getSelectedRange();
 | |
|       if (selection.extend) {
 | |
|         if (cursor.hasForwardSelection()) {
 | |
|           selection.collapse(range.startContainer, range.startOffset);
 | |
|           selection.extend(range.endContainer, range.endOffset);
 | |
|         } else {
 | |
|           selection.collapse(range.endContainer, range.endOffset);
 | |
|           selection.extend(range.startContainer, range.startOffset);
 | |
|         }
 | |
|       } else {
 | |
|         selection.removeAllRanges();
 | |
|         selection.addRange(range.cloneRange());
 | |
|       }
 | |
|     }
 | |
|     function computeClickCount(event) {
 | |
|       return event.button === 0 ? event.detail : 0;
 | |
|     }
 | |
|     function handleMouseDown(e) {
 | |
|       var target = getTarget(e), cursor = odtDocument.getCursor(inputMemberId), rootNode;
 | |
|       clickStartedWithinCanvas = target !== null && domUtils.containsNode(odtDocument.getOdfCanvas().getElement(), target);
 | |
|       if (clickStartedWithinCanvas) {
 | |
|         isMouseMoved = false;
 | |
|         rootNode = odtDocument.getRootElement((target)) || odtDocument.getRootNode();
 | |
|         mouseDownRootFilter = odtDocument.createRootFilter(rootNode);
 | |
|         clickCount = computeClickCount(e);
 | |
|         if (cursor && e.shiftKey) {
 | |
|           window.getSelection().collapse(cursor.getAnchorNode(), 0);
 | |
|         } else {
 | |
|           synchronizeWindowSelection(cursor);
 | |
|         }
 | |
|         if (clickCount > 1) {
 | |
|           updateShadowCursor();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function mutableSelection(selection) {
 | |
|       if (selection) {
 | |
|         return {anchorNode:selection.anchorNode, anchorOffset:selection.anchorOffset, focusNode:selection.focusNode, focusOffset:selection.focusOffset};
 | |
|       }
 | |
|       return null;
 | |
|     }
 | |
|     function getNextWalkablePosition(node) {
 | |
|       var root = odtDocument.getRootElement(node), rootFilter = odtDocument.createRootFilter(root), stepIterator = odtDocument.createStepIterator(node, 0, [rootFilter, odtDocument.getPositionFilter()], root);
 | |
|       stepIterator.setPosition(node, node.childNodes.length);
 | |
|       if (!stepIterator.roundToNextStep()) {
 | |
|         return null;
 | |
|       }
 | |
|       return {container:stepIterator.container(), offset:stepIterator.offset()};
 | |
|     }
 | |
|     function moveByMouseClickEvent(event) {
 | |
|       var selection = mutableSelection(window.getSelection()), isCollapsed = window.getSelection().isCollapsed, position, selectionRange, rect, frameNode;
 | |
|       if (!selection.anchorNode && !selection.focusNode) {
 | |
|         position = caretPositionFromPoint(event.clientX, event.clientY);
 | |
|         if (position) {
 | |
|           selection.anchorNode = (position.container);
 | |
|           selection.anchorOffset = position.offset;
 | |
|           selection.focusNode = selection.anchorNode;
 | |
|           selection.focusOffset = selection.anchorOffset;
 | |
|         }
 | |
|       }
 | |
|       if (odfUtils.isImage(selection.focusNode) && selection.focusOffset === 0 && odfUtils.isCharacterFrame(selection.focusNode.parentNode)) {
 | |
|         frameNode = (selection.focusNode.parentNode);
 | |
|         rect = frameNode.getBoundingClientRect();
 | |
|         if (event.clientX > rect.left) {
 | |
|           position = getNextWalkablePosition(frameNode);
 | |
|           if (position) {
 | |
|             selection.focusNode = position.container;
 | |
|             selection.focusOffset = position.offset;
 | |
|             if (isCollapsed) {
 | |
|               selection.anchorNode = selection.focusNode;
 | |
|               selection.anchorOffset = selection.focusOffset;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         if (odfUtils.isImage(selection.focusNode.firstChild) && selection.focusOffset === 1 && odfUtils.isCharacterFrame(selection.focusNode)) {
 | |
|           position = getNextWalkablePosition(selection.focusNode);
 | |
|           if (position) {
 | |
|             selection.anchorNode = selection.focusNode = position.container;
 | |
|             selection.anchorOffset = selection.focusOffset = position.offset;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (selection.anchorNode && selection.focusNode) {
 | |
|         selectionRange = selectionController.selectionToRange(selection);
 | |
|         selectionController.selectRange(selectionRange.range, selectionRange.hasForwardSelection, computeClickCount(event));
 | |
|       }
 | |
|       eventManager.focus();
 | |
|     }
 | |
|     function selectWordByLongPress(event) {
 | |
|       var selection, position, selectionRange, container, offset;
 | |
|       position = caretPositionFromPoint(event.clientX, event.clientY);
 | |
|       if (position) {
 | |
|         container = (position.container);
 | |
|         offset = position.offset;
 | |
|         selection = {anchorNode:container, anchorOffset:offset, focusNode:container, focusOffset:offset};
 | |
|         selectionRange = selectionController.selectionToRange(selection);
 | |
|         selectionController.selectRange(selectionRange.range, selectionRange.hasForwardSelection, 2);
 | |
|         eventManager.focus();
 | |
|       }
 | |
|     }
 | |
|     function handleMouseClickEvent(event) {
 | |
|       var target = getTarget(event), clickEvent, range, wasCollapsed, frameNode, pos;
 | |
|       drawShadowCursorTask.processRequests();
 | |
|       if (clickStartedWithinCanvas) {
 | |
|         if (odfUtils.isImage(target) && odfUtils.isCharacterFrame(target.parentNode) && window.getSelection().isCollapsed) {
 | |
|           selectionController.selectImage((target.parentNode));
 | |
|           eventManager.focus();
 | |
|         } else {
 | |
|           if (imageSelector.isSelectorElement(target)) {
 | |
|             eventManager.focus();
 | |
|           } else {
 | |
|             if (isMouseMoved) {
 | |
|               range = shadowCursor.getSelectedRange();
 | |
|               wasCollapsed = range.collapsed;
 | |
|               if (odfUtils.isImage(range.endContainer) && range.endOffset === 0 && odfUtils.isCharacterFrame(range.endContainer.parentNode)) {
 | |
|                 frameNode = (range.endContainer.parentNode);
 | |
|                 pos = getNextWalkablePosition(frameNode);
 | |
|                 if (pos) {
 | |
|                   range.setEnd(pos.container, pos.offset);
 | |
|                   if (wasCollapsed) {
 | |
|                     range.collapse(false);
 | |
|                   }
 | |
|                 }
 | |
|               }
 | |
|               selectionController.selectRange(range, shadowCursor.hasForwardSelection(), computeClickCount(event));
 | |
|               eventManager.focus();
 | |
|             } else {
 | |
|               if (isIOS) {
 | |
|                 moveByMouseClickEvent(event);
 | |
|               } else {
 | |
|                 clickEvent = (domUtils.cloneEvent(event));
 | |
|                 handleMouseClickTimeoutId = runtime.setTimeout(function() {
 | |
|                   moveByMouseClickEvent(clickEvent);
 | |
|                 }, 0);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         clickCount = 0;
 | |
|         clickStartedWithinCanvas = false;
 | |
|         isMouseMoved = false;
 | |
|       }
 | |
|     }
 | |
|     function handleDragStart(e) {
 | |
|       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
 | |
|       if (selectedRange.collapsed) {
 | |
|         return;
 | |
|       }
 | |
|       mimeDataExporter.exportRangeToDataTransfer((e.dataTransfer), selectedRange);
 | |
|     }
 | |
|     function handleDragEnd() {
 | |
|       if (clickStartedWithinCanvas) {
 | |
|         eventManager.focus();
 | |
|       }
 | |
|       clickCount = 0;
 | |
|       clickStartedWithinCanvas = false;
 | |
|       isMouseMoved = false;
 | |
|     }
 | |
|     function handleContextMenu(e) {
 | |
|       handleMouseClickEvent(e);
 | |
|     }
 | |
|     function handleMouseUp(event) {
 | |
|       var target = (getTarget(event)), annotationNode = null;
 | |
|       if (target.className === "annotationRemoveButton") {
 | |
|         runtime.assert(annotationsEnabled, "Remove buttons are displayed on annotations while annotation editing is disabled in the controller.");
 | |
|         annotationNode = (target.parentNode).getElementsByTagNameNS(odf.Namespaces.officens, "annotation").item(0);
 | |
|         annotationController.removeAnnotation((annotationNode));
 | |
|         eventManager.focus();
 | |
|       } else {
 | |
|         if (target.getAttribute("class") !== "webodf-draggable") {
 | |
|           handleMouseClickEvent(event);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function insertNonEmptyData(e) {
 | |
|       var input = e.data;
 | |
|       if (input) {
 | |
|         if (input.indexOf("\n") === -1) {
 | |
|           textController.insertText(input);
 | |
|         } else {
 | |
|           pasteController.paste(input);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function returnTrue(fn) {
 | |
|       return function() {
 | |
|         fn();
 | |
|         return true;
 | |
|       };
 | |
|     }
 | |
|     function rangeSelectionOnly(fn) {
 | |
|       function f(e) {
 | |
|         var selectionType = odtDocument.getCursor(inputMemberId).getSelectionType();
 | |
|         if (selectionType === ops.OdtCursor.RangeSelection) {
 | |
|           return fn(e);
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
|       return f;
 | |
|     }
 | |
|     function insertLocalCursor() {
 | |
|       runtime.assert(session.getOdtDocument().getCursor(inputMemberId) === undefined, "Inserting local cursor a second time.");
 | |
|       var op = new ops.OpAddCursor;
 | |
|       op.init({memberid:inputMemberId});
 | |
|       session.enqueue([op]);
 | |
|       eventManager.focus();
 | |
|     }
 | |
|     this.insertLocalCursor = insertLocalCursor;
 | |
|     function removeLocalCursor() {
 | |
|       runtime.assert(session.getOdtDocument().getCursor(inputMemberId) !== undefined, "Removing local cursor without inserting before.");
 | |
|       var op = new ops.OpRemoveCursor;
 | |
|       op.init({memberid:inputMemberId});
 | |
|       session.enqueue([op]);
 | |
|     }
 | |
|     this.removeLocalCursor = removeLocalCursor;
 | |
|     this.startEditing = function() {
 | |
|       inputMethodEditor.subscribe(gui.InputMethodEditor.signalCompositionStart, textController.removeCurrentSelection);
 | |
|       inputMethodEditor.subscribe(gui.InputMethodEditor.signalCompositionEnd, insertNonEmptyData);
 | |
|       eventManager.subscribe("beforecut", handleBeforeCut);
 | |
|       eventManager.subscribe("cut", handleCut);
 | |
|       eventManager.subscribe("beforepaste", handleBeforePaste);
 | |
|       eventManager.subscribe("paste", handlePaste);
 | |
|       if (undoManager) {
 | |
|         undoManager.initialize();
 | |
|       }
 | |
|       eventManager.setEditing(true);
 | |
|       hyperlinkClickHandler.setModifier(isMacOS ? modifier.Meta : modifier.Ctrl);
 | |
|       keyDownHandler.bind(keyCode.Backspace, modifier.None, returnTrue(textController.removeTextByBackspaceKey), true);
 | |
|       keyDownHandler.bind(keyCode.Delete, modifier.None, textController.removeTextByDeleteKey);
 | |
|       keyDownHandler.bind(keyCode.Tab, modifier.None, rangeSelectionOnly(function() {
 | |
|         textController.insertText("\t");
 | |
|         return true;
 | |
|       }));
 | |
|       if (isMacOS) {
 | |
|         keyDownHandler.bind(keyCode.Clear, modifier.None, textController.removeCurrentSelection);
 | |
|         keyDownHandler.bind(keyCode.B, modifier.Meta, rangeSelectionOnly(directFormattingController.toggleBold));
 | |
|         keyDownHandler.bind(keyCode.I, modifier.Meta, rangeSelectionOnly(directFormattingController.toggleItalic));
 | |
|         keyDownHandler.bind(keyCode.U, modifier.Meta, rangeSelectionOnly(directFormattingController.toggleUnderline));
 | |
|         keyDownHandler.bind(keyCode.L, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphLeft));
 | |
|         keyDownHandler.bind(keyCode.E, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphCenter));
 | |
|         keyDownHandler.bind(keyCode.R, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphRight));
 | |
|         keyDownHandler.bind(keyCode.J, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphJustified));
 | |
|         if (annotationsEnabled) {
 | |
|           keyDownHandler.bind(keyCode.C, modifier.MetaShift, annotationController.addAnnotation);
 | |
|         }
 | |
|         keyDownHandler.bind(keyCode.Z, modifier.Meta, undo);
 | |
|         keyDownHandler.bind(keyCode.Z, modifier.MetaShift, redo);
 | |
|       } else {
 | |
|         keyDownHandler.bind(keyCode.B, modifier.Ctrl, rangeSelectionOnly(directFormattingController.toggleBold));
 | |
|         keyDownHandler.bind(keyCode.I, modifier.Ctrl, rangeSelectionOnly(directFormattingController.toggleItalic));
 | |
|         keyDownHandler.bind(keyCode.U, modifier.Ctrl, rangeSelectionOnly(directFormattingController.toggleUnderline));
 | |
|         keyDownHandler.bind(keyCode.L, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphLeft));
 | |
|         keyDownHandler.bind(keyCode.E, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphCenter));
 | |
|         keyDownHandler.bind(keyCode.R, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphRight));
 | |
|         keyDownHandler.bind(keyCode.J, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphJustified));
 | |
|         if (annotationsEnabled) {
 | |
|           keyDownHandler.bind(keyCode.C, modifier.CtrlAlt, annotationController.addAnnotation);
 | |
|         }
 | |
|         keyDownHandler.bind(keyCode.Z, modifier.Ctrl, undo);
 | |
|         keyDownHandler.bind(keyCode.Z, modifier.CtrlShift, redo);
 | |
|       }
 | |
|       function handler(e) {
 | |
|         var text = stringFromKeyPress(e);
 | |
|         if (text && !(e.altKey || e.ctrlKey || e.metaKey)) {
 | |
|           textController.insertText(text);
 | |
|           return true;
 | |
|         }
 | |
|         return false;
 | |
|       }
 | |
|       keyPressHandler.setDefault(rangeSelectionOnly(handler));
 | |
|       keyPressHandler.bind(keyCode.Enter, modifier.None, rangeSelectionOnly(textController.enqueueParagraphSplittingOps));
 | |
|     };
 | |
|     this.endEditing = function() {
 | |
|       inputMethodEditor.unsubscribe(gui.InputMethodEditor.signalCompositionStart, textController.removeCurrentSelection);
 | |
|       inputMethodEditor.unsubscribe(gui.InputMethodEditor.signalCompositionEnd, insertNonEmptyData);
 | |
|       eventManager.unsubscribe("cut", handleCut);
 | |
|       eventManager.unsubscribe("beforecut", handleBeforeCut);
 | |
|       eventManager.unsubscribe("paste", handlePaste);
 | |
|       eventManager.unsubscribe("beforepaste", handleBeforePaste);
 | |
|       eventManager.setEditing(false);
 | |
|       hyperlinkClickHandler.setModifier(modifier.None);
 | |
|       keyDownHandler.bind(keyCode.Backspace, modifier.None, function() {
 | |
|         return true;
 | |
|       }, true);
 | |
|       keyDownHandler.unbind(keyCode.Delete, modifier.None);
 | |
|       keyDownHandler.unbind(keyCode.Tab, modifier.None);
 | |
|       if (isMacOS) {
 | |
|         keyDownHandler.unbind(keyCode.Clear, modifier.None);
 | |
|         keyDownHandler.unbind(keyCode.B, modifier.Meta);
 | |
|         keyDownHandler.unbind(keyCode.I, modifier.Meta);
 | |
|         keyDownHandler.unbind(keyCode.U, modifier.Meta);
 | |
|         keyDownHandler.unbind(keyCode.L, modifier.MetaShift);
 | |
|         keyDownHandler.unbind(keyCode.E, modifier.MetaShift);
 | |
|         keyDownHandler.unbind(keyCode.R, modifier.MetaShift);
 | |
|         keyDownHandler.unbind(keyCode.J, modifier.MetaShift);
 | |
|         if (annotationsEnabled) {
 | |
|           keyDownHandler.unbind(keyCode.C, modifier.MetaShift);
 | |
|         }
 | |
|         keyDownHandler.unbind(keyCode.Z, modifier.Meta);
 | |
|         keyDownHandler.unbind(keyCode.Z, modifier.MetaShift);
 | |
|       } else {
 | |
|         keyDownHandler.unbind(keyCode.B, modifier.Ctrl);
 | |
|         keyDownHandler.unbind(keyCode.I, modifier.Ctrl);
 | |
|         keyDownHandler.unbind(keyCode.U, modifier.Ctrl);
 | |
|         keyDownHandler.unbind(keyCode.L, modifier.CtrlShift);
 | |
|         keyDownHandler.unbind(keyCode.E, modifier.CtrlShift);
 | |
|         keyDownHandler.unbind(keyCode.R, modifier.CtrlShift);
 | |
|         keyDownHandler.unbind(keyCode.J, modifier.CtrlShift);
 | |
|         if (annotationsEnabled) {
 | |
|           keyDownHandler.unbind(keyCode.C, modifier.CtrlAlt);
 | |
|         }
 | |
|         keyDownHandler.unbind(keyCode.Z, modifier.Ctrl);
 | |
|         keyDownHandler.unbind(keyCode.Z, modifier.CtrlShift);
 | |
|       }
 | |
|       keyPressHandler.setDefault(null);
 | |
|       keyPressHandler.unbind(keyCode.Enter, modifier.None);
 | |
|     };
 | |
|     this.getInputMemberId = function() {
 | |
|       return inputMemberId;
 | |
|     };
 | |
|     this.getSession = function() {
 | |
|       return session;
 | |
|     };
 | |
|     this.getSessionConstraints = function() {
 | |
|       return sessionConstraints;
 | |
|     };
 | |
|     this.setUndoManager = function(manager) {
 | |
|       if (undoManager) {
 | |
|         undoManager.unsubscribe(gui.UndoManager.signalUndoStackChanged, forwardUndoStackChange);
 | |
|       }
 | |
|       undoManager = manager;
 | |
|       if (undoManager) {
 | |
|         undoManager.setDocument(odtDocument);
 | |
|         undoManager.setPlaybackFunction(session.enqueue);
 | |
|         undoManager.subscribe(gui.UndoManager.signalUndoStackChanged, forwardUndoStackChange);
 | |
|       }
 | |
|     };
 | |
|     this.getUndoManager = function() {
 | |
|       return undoManager;
 | |
|     };
 | |
|     this.getMetadataController = function() {
 | |
|       return metadataController;
 | |
|     };
 | |
|     this.getAnnotationController = function() {
 | |
|       return annotationController;
 | |
|     };
 | |
|     this.getDirectFormattingController = function() {
 | |
|       return directFormattingController;
 | |
|     };
 | |
|     this.getHyperlinkClickHandler = function() {
 | |
|       return hyperlinkClickHandler;
 | |
|     };
 | |
|     this.getHyperlinkController = function() {
 | |
|       return hyperlinkController;
 | |
|     };
 | |
|     this.getImageController = function() {
 | |
|       return imageController;
 | |
|     };
 | |
|     this.getSelectionController = function() {
 | |
|       return selectionController;
 | |
|     };
 | |
|     this.getTextController = function() {
 | |
|       return textController;
 | |
|     };
 | |
|     this.getEventManager = function() {
 | |
|       return eventManager;
 | |
|     };
 | |
|     this.getKeyboardHandlers = function() {
 | |
|       return {keydown:keyDownHandler, keypress:keyPressHandler};
 | |
|     };
 | |
|     function destroy(callback) {
 | |
|       eventManager.unsubscribe("keydown", keyDownHandler.handleEvent);
 | |
|       eventManager.unsubscribe("keypress", keyPressHandler.handleEvent);
 | |
|       eventManager.unsubscribe("keyup", keyUpHandler.handleEvent);
 | |
|       eventManager.unsubscribe("copy", handleCopy);
 | |
|       eventManager.unsubscribe("mousedown", handleMouseDown);
 | |
|       eventManager.unsubscribe("mousemove", drawShadowCursorTask.trigger);
 | |
|       eventManager.unsubscribe("mouseup", handleMouseUp);
 | |
|       eventManager.unsubscribe("contextmenu", handleContextMenu);
 | |
|       eventManager.unsubscribe("dragstart", handleDragStart);
 | |
|       eventManager.unsubscribe("dragend", handleDragEnd);
 | |
|       eventManager.unsubscribe("click", hyperlinkClickHandler.handleClick);
 | |
|       eventManager.unsubscribe("longpress", selectWordByLongPress);
 | |
|       eventManager.unsubscribe("drag", extendSelectionByDrag);
 | |
|       eventManager.unsubscribe("dragstop", updateCursorSelection);
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalOperationEnd, redrawRegionSelectionTask.trigger);
 | |
|       odtDocument.unsubscribe(ops.Document.signalCursorAdded, inputMethodEditor.registerCursor);
 | |
|       odtDocument.unsubscribe(ops.Document.signalCursorRemoved, inputMethodEditor.removeCursor);
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalOperationEnd, updateUndoStack);
 | |
|       callback();
 | |
|     }
 | |
|     this.destroy = function(callback) {
 | |
|       var destroyCallbacks = [drawShadowCursorTask.destroy, redrawRegionSelectionTask.destroy, directFormattingController.destroy, inputMethodEditor.destroy, eventManager.destroy, hyperlinkClickHandler.destroy, hyperlinkController.destroy, metadataController.destroy, selectionController.destroy, textController.destroy, destroy];
 | |
|       if (iOSSafariSupport) {
 | |
|         destroyCallbacks.unshift(iOSSafariSupport.destroy);
 | |
|       }
 | |
|       runtime.clearTimeout(handleMouseClickTimeoutId);
 | |
|       core.Async.destroyAll(destroyCallbacks, callback);
 | |
|     };
 | |
|     function init() {
 | |
|       drawShadowCursorTask = core.Task.createRedrawTask(updateShadowCursor);
 | |
|       redrawRegionSelectionTask = core.Task.createRedrawTask(redrawRegionSelection);
 | |
|       keyDownHandler.bind(keyCode.Left, modifier.None, rangeSelectionOnly(selectionController.moveCursorToLeft));
 | |
|       keyDownHandler.bind(keyCode.Right, modifier.None, rangeSelectionOnly(selectionController.moveCursorToRight));
 | |
|       keyDownHandler.bind(keyCode.Up, modifier.None, rangeSelectionOnly(selectionController.moveCursorUp));
 | |
|       keyDownHandler.bind(keyCode.Down, modifier.None, rangeSelectionOnly(selectionController.moveCursorDown));
 | |
|       keyDownHandler.bind(keyCode.Left, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToLeft));
 | |
|       keyDownHandler.bind(keyCode.Right, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToRight));
 | |
|       keyDownHandler.bind(keyCode.Up, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionUp));
 | |
|       keyDownHandler.bind(keyCode.Down, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionDown));
 | |
|       keyDownHandler.bind(keyCode.Home, modifier.None, rangeSelectionOnly(selectionController.moveCursorToLineStart));
 | |
|       keyDownHandler.bind(keyCode.End, modifier.None, rangeSelectionOnly(selectionController.moveCursorToLineEnd));
 | |
|       keyDownHandler.bind(keyCode.Home, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorToDocumentStart));
 | |
|       keyDownHandler.bind(keyCode.End, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorToDocumentEnd));
 | |
|       keyDownHandler.bind(keyCode.Home, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToLineStart));
 | |
|       keyDownHandler.bind(keyCode.End, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToLineEnd));
 | |
|       keyDownHandler.bind(keyCode.Up, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphStart));
 | |
|       keyDownHandler.bind(keyCode.Down, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphEnd));
 | |
|       keyDownHandler.bind(keyCode.Home, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentStart));
 | |
|       keyDownHandler.bind(keyCode.End, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentEnd));
 | |
|       if (isMacOS) {
 | |
|         keyDownHandler.bind(keyCode.Left, modifier.Alt, rangeSelectionOnly(selectionController.moveCursorBeforeWord));
 | |
|         keyDownHandler.bind(keyCode.Right, modifier.Alt, rangeSelectionOnly(selectionController.moveCursorPastWord));
 | |
|         keyDownHandler.bind(keyCode.Left, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToLineStart));
 | |
|         keyDownHandler.bind(keyCode.Right, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToLineEnd));
 | |
|         keyDownHandler.bind(keyCode.Home, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToDocumentStart));
 | |
|         keyDownHandler.bind(keyCode.End, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToDocumentEnd));
 | |
|         keyDownHandler.bind(keyCode.Left, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionBeforeWord));
 | |
|         keyDownHandler.bind(keyCode.Right, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionPastWord));
 | |
|         keyDownHandler.bind(keyCode.Left, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToLineStart));
 | |
|         keyDownHandler.bind(keyCode.Right, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToLineEnd));
 | |
|         keyDownHandler.bind(keyCode.Up, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphStart));
 | |
|         keyDownHandler.bind(keyCode.Down, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphEnd));
 | |
|         keyDownHandler.bind(keyCode.Up, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentStart));
 | |
|         keyDownHandler.bind(keyCode.Down, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentEnd));
 | |
|         keyDownHandler.bind(keyCode.A, modifier.Meta, rangeSelectionOnly(selectionController.extendSelectionToEntireDocument));
 | |
|       } else {
 | |
|         keyDownHandler.bind(keyCode.Left, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorBeforeWord));
 | |
|         keyDownHandler.bind(keyCode.Right, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorPastWord));
 | |
|         keyDownHandler.bind(keyCode.Left, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionBeforeWord));
 | |
|         keyDownHandler.bind(keyCode.Right, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionPastWord));
 | |
|         keyDownHandler.bind(keyCode.A, modifier.Ctrl, rangeSelectionOnly(selectionController.extendSelectionToEntireDocument));
 | |
|       }
 | |
|       if (isIOS) {
 | |
|         iOSSafariSupport = new gui.IOSSafariSupport(eventManager);
 | |
|       }
 | |
|       eventManager.subscribe("keydown", keyDownHandler.handleEvent);
 | |
|       eventManager.subscribe("keypress", keyPressHandler.handleEvent);
 | |
|       eventManager.subscribe("keyup", keyUpHandler.handleEvent);
 | |
|       eventManager.subscribe("copy", handleCopy);
 | |
|       eventManager.subscribe("mousedown", handleMouseDown);
 | |
|       eventManager.subscribe("mousemove", drawShadowCursorTask.trigger);
 | |
|       eventManager.subscribe("mouseup", handleMouseUp);
 | |
|       eventManager.subscribe("contextmenu", handleContextMenu);
 | |
|       eventManager.subscribe("dragstart", handleDragStart);
 | |
|       eventManager.subscribe("dragend", handleDragEnd);
 | |
|       eventManager.subscribe("click", hyperlinkClickHandler.handleClick);
 | |
|       eventManager.subscribe("longpress", selectWordByLongPress);
 | |
|       eventManager.subscribe("drag", extendSelectionByDrag);
 | |
|       eventManager.subscribe("dragstop", updateCursorSelection);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalOperationEnd, redrawRegionSelectionTask.trigger);
 | |
|       odtDocument.subscribe(ops.Document.signalCursorAdded, inputMethodEditor.registerCursor);
 | |
|       odtDocument.subscribe(ops.Document.signalCursorRemoved, inputMethodEditor.removeCursor);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalOperationEnd, updateUndoStack);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
| })();
 | |
| gui.CaretManager = function CaretManager(sessionController, viewport) {
 | |
|   var carets = {}, window = runtime.getWindow(), odtDocument = sessionController.getSession().getOdtDocument(), eventManager = sessionController.getEventManager();
 | |
|   function getCaret(memberId) {
 | |
|     return carets.hasOwnProperty(memberId) ? carets[memberId] : null;
 | |
|   }
 | |
|   function getLocalCaretXOffsetPx() {
 | |
|     var localCaret = getCaret(sessionController.getInputMemberId()), lastRect;
 | |
|     if (localCaret) {
 | |
|       lastRect = localCaret.getBoundingClientRect();
 | |
|     }
 | |
|     return lastRect ? lastRect.right : undefined;
 | |
|   }
 | |
|   function getCarets() {
 | |
|     return Object.keys(carets).map(function(memberid) {
 | |
|       return carets[memberid];
 | |
|     });
 | |
|   }
 | |
|   function removeCaret(memberId) {
 | |
|     var caret = carets[memberId];
 | |
|     if (caret) {
 | |
|       delete carets[memberId];
 | |
|       if (memberId === sessionController.getInputMemberId()) {
 | |
|         odtDocument.unsubscribe(ops.OdtDocument.signalProcessingBatchEnd, caret.ensureVisible);
 | |
|         odtDocument.unsubscribe(ops.Document.signalCursorMoved, caret.refreshCursorBlinking);
 | |
|         eventManager.unsubscribe("compositionupdate", caret.handleUpdate);
 | |
|         eventManager.unsubscribe("compositionend", caret.handleUpdate);
 | |
|         eventManager.unsubscribe("focus", caret.setFocus);
 | |
|         eventManager.unsubscribe("blur", caret.removeFocus);
 | |
|         window.removeEventListener("focus", caret.show, false);
 | |
|         window.removeEventListener("blur", caret.hide, false);
 | |
|       } else {
 | |
|         odtDocument.unsubscribe(ops.OdtDocument.signalProcessingBatchEnd, caret.handleUpdate);
 | |
|       }
 | |
|       caret.destroy(function() {
 | |
|       });
 | |
|     }
 | |
|   }
 | |
|   this.registerCursor = function(cursor, caretAvatarInitiallyVisible, blinkOnRangeSelect) {
 | |
|     var memberid = cursor.getMemberId(), caret = new gui.Caret(cursor, viewport, caretAvatarInitiallyVisible, blinkOnRangeSelect);
 | |
|     carets[memberid] = caret;
 | |
|     if (memberid === sessionController.getInputMemberId()) {
 | |
|       runtime.log("Starting to track input on new cursor of " + memberid);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalProcessingBatchEnd, caret.ensureVisible);
 | |
|       odtDocument.subscribe(ops.Document.signalCursorMoved, caret.refreshCursorBlinking);
 | |
|       eventManager.subscribe("compositionupdate", caret.handleUpdate);
 | |
|       eventManager.subscribe("compositionend", caret.handleUpdate);
 | |
|       eventManager.subscribe("focus", caret.setFocus);
 | |
|       eventManager.subscribe("blur", caret.removeFocus);
 | |
|       window.addEventListener("focus", caret.show, false);
 | |
|       window.addEventListener("blur", caret.hide, false);
 | |
|       caret.setOverlayElement(eventManager.getEventTrap());
 | |
|     } else {
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalProcessingBatchEnd, caret.handleUpdate);
 | |
|     }
 | |
|     return caret;
 | |
|   };
 | |
|   this.getCaret = getCaret;
 | |
|   this.getCarets = getCarets;
 | |
|   this.destroy = function(callback) {
 | |
|     var caretCleanup = getCarets().map(function(caret) {
 | |
|       return caret.destroy;
 | |
|     });
 | |
|     sessionController.getSelectionController().setCaretXPositionLocator(null);
 | |
|     odtDocument.unsubscribe(ops.Document.signalCursorRemoved, removeCaret);
 | |
|     carets = {};
 | |
|     core.Async.destroyAll(caretCleanup, callback);
 | |
|   };
 | |
|   function init() {
 | |
|     sessionController.getSelectionController().setCaretXPositionLocator(getLocalCaretXOffsetPx);
 | |
|     odtDocument.subscribe(ops.Document.signalCursorRemoved, removeCaret);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.EditInfoHandle = function EditInfoHandle(parentElement) {
 | |
|   var edits = [], handle, document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI, editinfons = "urn:webodf:names:editinfo";
 | |
|   function renderEdits() {
 | |
|     var i, infoDiv, colorSpan, authorSpan, timeSpan;
 | |
|     core.DomUtils.removeAllChildNodes(handle);
 | |
|     for (i = 0;i < edits.length;i += 1) {
 | |
|       infoDiv = document.createElementNS(htmlns, "div");
 | |
|       infoDiv.className = "editInfo";
 | |
|       colorSpan = document.createElementNS(htmlns, "span");
 | |
|       colorSpan.className = "editInfoColor";
 | |
|       colorSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
 | |
|       authorSpan = document.createElementNS(htmlns, "span");
 | |
|       authorSpan.className = "editInfoAuthor";
 | |
|       authorSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
 | |
|       timeSpan = document.createElementNS(htmlns, "span");
 | |
|       timeSpan.className = "editInfoTime";
 | |
|       timeSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
 | |
|       timeSpan.appendChild(document.createTextNode(edits[i].time.toString()));
 | |
|       infoDiv.appendChild(colorSpan);
 | |
|       infoDiv.appendChild(authorSpan);
 | |
|       infoDiv.appendChild(timeSpan);
 | |
|       handle.appendChild(infoDiv);
 | |
|     }
 | |
|   }
 | |
|   this.setEdits = function(editArray) {
 | |
|     edits = editArray;
 | |
|     renderEdits();
 | |
|   };
 | |
|   this.show = function() {
 | |
|     handle.style.display = "block";
 | |
|   };
 | |
|   this.hide = function() {
 | |
|     handle.style.display = "none";
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     parentElement.removeChild(handle);
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     handle = (document.createElementNS(htmlns, "div"));
 | |
|     handle.setAttribute("class", "editInfoHandle");
 | |
|     handle.style.display = "none";
 | |
|     parentElement.appendChild(handle);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| ops.EditInfo = function EditInfo(container, odtDocument) {
 | |
|   var editInfoNode, editHistory = {};
 | |
|   function sortEdits() {
 | |
|     var arr = [], memberid;
 | |
|     for (memberid in editHistory) {
 | |
|       if (editHistory.hasOwnProperty(memberid)) {
 | |
|         arr.push({"memberid":memberid, "time":editHistory[memberid].time});
 | |
|       }
 | |
|     }
 | |
|     arr.sort(function(a, b) {
 | |
|       return a.time - b.time;
 | |
|     });
 | |
|     return arr;
 | |
|   }
 | |
|   this.getNode = function() {
 | |
|     return editInfoNode;
 | |
|   };
 | |
|   this.getOdtDocument = function() {
 | |
|     return odtDocument;
 | |
|   };
 | |
|   this.getEdits = function() {
 | |
|     return editHistory;
 | |
|   };
 | |
|   this.getSortedEdits = function() {
 | |
|     return sortEdits();
 | |
|   };
 | |
|   this.addEdit = function(memberid, timestamp) {
 | |
|     editHistory[memberid] = {time:timestamp};
 | |
|   };
 | |
|   this.clearEdits = function() {
 | |
|     editHistory = {};
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     if (container.parentNode) {
 | |
|       container.removeChild(editInfoNode);
 | |
|     }
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     var editInfons = "urn:webodf:names:editinfo", dom = odtDocument.getDOMDocument();
 | |
|     editInfoNode = dom.createElementNS(editInfons, "editinfo");
 | |
|     container.insertBefore(editInfoNode, container.firstChild);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.EditInfoMarker = function EditInfoMarker(editInfo, initialVisibility) {
 | |
|   var self = this, editInfoNode, handle, marker, editinfons = "urn:webodf:names:editinfo", decayTimer0, decayTimer1, decayTimer2, decayTimeStep = 1E4;
 | |
|   function applyDecay(opacity, delay) {
 | |
|     return runtime.setTimeout(function() {
 | |
|       marker.style.opacity = opacity;
 | |
|     }, delay);
 | |
|   }
 | |
|   function deleteDecay(timerId) {
 | |
|     runtime.clearTimeout(timerId);
 | |
|   }
 | |
|   function setLastAuthor(memberid) {
 | |
|     marker.setAttributeNS(editinfons, "editinfo:memberid", memberid);
 | |
|   }
 | |
|   this.addEdit = function(memberid, timestamp) {
 | |
|     var age = Date.now() - timestamp;
 | |
|     editInfo.addEdit(memberid, timestamp);
 | |
|     handle.setEdits(editInfo.getSortedEdits());
 | |
|     setLastAuthor(memberid);
 | |
|     deleteDecay(decayTimer1);
 | |
|     deleteDecay(decayTimer2);
 | |
|     if (age < decayTimeStep) {
 | |
|       decayTimer0 = applyDecay(1, 0);
 | |
|       decayTimer1 = applyDecay(.5, decayTimeStep - age);
 | |
|       decayTimer2 = applyDecay(.2, decayTimeStep * 2 - age);
 | |
|     } else {
 | |
|       if (age >= decayTimeStep && age < decayTimeStep * 2) {
 | |
|         decayTimer0 = applyDecay(.5, 0);
 | |
|         decayTimer2 = applyDecay(.2, decayTimeStep * 2 - age);
 | |
|       } else {
 | |
|         decayTimer0 = applyDecay(.2, 0);
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   this.getEdits = function() {
 | |
|     return editInfo.getEdits();
 | |
|   };
 | |
|   this.clearEdits = function() {
 | |
|     editInfo.clearEdits();
 | |
|     handle.setEdits([]);
 | |
|     if (marker.hasAttributeNS(editinfons, "editinfo:memberid")) {
 | |
|       marker.removeAttributeNS(editinfons, "editinfo:memberid");
 | |
|     }
 | |
|   };
 | |
|   this.getEditInfo = function() {
 | |
|     return editInfo;
 | |
|   };
 | |
|   this.show = function() {
 | |
|     marker.style.display = "block";
 | |
|   };
 | |
|   this.hide = function() {
 | |
|     self.hideHandle();
 | |
|     marker.style.display = "none";
 | |
|   };
 | |
|   this.showHandle = function() {
 | |
|     handle.show();
 | |
|   };
 | |
|   this.hideHandle = function() {
 | |
|     handle.hide();
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     deleteDecay(decayTimer0);
 | |
|     deleteDecay(decayTimer1);
 | |
|     deleteDecay(decayTimer2);
 | |
|     editInfoNode.removeChild(marker);
 | |
|     handle.destroy(function(err) {
 | |
|       if (err) {
 | |
|         callback(err);
 | |
|       } else {
 | |
|         editInfo.destroy(callback);
 | |
|       }
 | |
|     });
 | |
|   };
 | |
|   function init() {
 | |
|     var dom = editInfo.getOdtDocument().getDOMDocument(), htmlns = dom.documentElement.namespaceURI;
 | |
|     marker = (dom.createElementNS(htmlns, "div"));
 | |
|     marker.setAttribute("class", "editInfoMarker");
 | |
|     marker.onmouseover = function() {
 | |
|       self.showHandle();
 | |
|     };
 | |
|     marker.onmouseout = function() {
 | |
|       self.hideHandle();
 | |
|     };
 | |
|     editInfoNode = editInfo.getNode();
 | |
|     editInfoNode.appendChild(marker);
 | |
|     handle = new gui.EditInfoHandle(editInfoNode);
 | |
|     if (!initialVisibility) {
 | |
|       self.hide();
 | |
|     }
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.HyperlinkTooltipView = function HyperlinkTooltipView(odfCanvas, getActiveModifier) {
 | |
|   var domUtils = core.DomUtils, odfUtils = odf.OdfUtils, window = (runtime.getWindow()), linkSpan, textSpan, tooltipElement, offsetXPx = 15, offsetYPx = 10;
 | |
|   runtime.assert(window !== null, "Expected to be run in an environment which has a global window, like a browser.");
 | |
|   function getHyperlinkElement(node) {
 | |
|     while (node) {
 | |
|       if (odfUtils.isHyperlink(node)) {
 | |
|         return (node);
 | |
|       }
 | |
|       if (odfUtils.isParagraph(node) || odfUtils.isInlineRoot(node)) {
 | |
|         break;
 | |
|       }
 | |
|       node = node.parentNode;
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
|   function getHint() {
 | |
|     var modifierKey = getActiveModifier(), hint;
 | |
|     switch(modifierKey) {
 | |
|       case gui.KeyboardHandler.Modifier.Ctrl:
 | |
|         hint = runtime.tr("Ctrl-click to follow link");
 | |
|         break;
 | |
|       case gui.KeyboardHandler.Modifier.Meta:
 | |
|         hint = runtime.tr("\u2318-click to follow link");
 | |
|         break;
 | |
|       default:
 | |
|         hint = "";
 | |
|         break;
 | |
|     }
 | |
|     return hint;
 | |
|   }
 | |
|   this.showTooltip = function(e) {
 | |
|     var target = e.target || e.srcElement, sizerElement = (odfCanvas.getSizer()), zoomLevel = odfCanvas.getZoomLevel(), referenceRect, linkElement, left, top, max;
 | |
|     linkElement = getHyperlinkElement((target));
 | |
|     if (!linkElement) {
 | |
|       return;
 | |
|     }
 | |
|     if (!domUtils.containsNode(sizerElement, tooltipElement)) {
 | |
|       sizerElement.appendChild(tooltipElement);
 | |
|     }
 | |
|     textSpan.textContent = getHint();
 | |
|     linkSpan.textContent = odfUtils.getHyperlinkTarget(linkElement);
 | |
|     tooltipElement.style.display = "block";
 | |
|     max = window.innerWidth - tooltipElement.offsetWidth - offsetXPx;
 | |
|     left = e.clientX > max ? max : e.clientX + offsetXPx;
 | |
|     max = window.innerHeight - tooltipElement.offsetHeight - offsetYPx;
 | |
|     top = e.clientY > max ? max : e.clientY + offsetYPx;
 | |
|     referenceRect = sizerElement.getBoundingClientRect();
 | |
|     left = (left - referenceRect.left) / zoomLevel;
 | |
|     top = (top - referenceRect.top) / zoomLevel;
 | |
|     tooltipElement.style.left = left + "px";
 | |
|     tooltipElement.style.top = top + "px";
 | |
|   };
 | |
|   this.hideTooltip = function() {
 | |
|     tooltipElement.style.display = "none";
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     if (tooltipElement.parentNode) {
 | |
|       tooltipElement.parentNode.removeChild(tooltipElement);
 | |
|     }
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     var document = odfCanvas.getElement().ownerDocument;
 | |
|     linkSpan = document.createElement("span");
 | |
|     textSpan = document.createElement("span");
 | |
|     linkSpan.className = "webodf-hyperlinkTooltipLink";
 | |
|     textSpan.className = "webodf-hyperlinkTooltipText";
 | |
|     tooltipElement = (document.createElement("div"));
 | |
|     tooltipElement.className = "webodf-hyperlinkTooltip";
 | |
|     tooltipElement.appendChild(linkSpan);
 | |
|     tooltipElement.appendChild(textSpan);
 | |
|     odfCanvas.getElement().appendChild(tooltipElement);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.OdfFieldView = function(odfCanvas) {
 | |
|   var style, document = odfCanvas.getElement().ownerDocument;
 | |
|   function newStyleSheet() {
 | |
|     var head = document.getElementsByTagName("head").item(0), sheet = (document.createElement("style")), text = "";
 | |
|     sheet.type = "text/css";
 | |
|     sheet.media = "screen, print, handheld, projection";
 | |
|     odf.Namespaces.forEachPrefix(function(prefix, ns) {
 | |
|       text += "@namespace " + prefix + " url(" + ns + ");\n";
 | |
|     });
 | |
|     sheet.appendChild(document.createTextNode(text));
 | |
|     head.appendChild(sheet);
 | |
|     return sheet;
 | |
|   }
 | |
|   function clearCSSStyleSheet(style) {
 | |
|     var stylesheet = (style.sheet), cssRules = stylesheet.cssRules;
 | |
|     while (cssRules.length) {
 | |
|       stylesheet.deleteRule(cssRules.length - 1);
 | |
|     }
 | |
|   }
 | |
|   function createRule(selectors, css) {
 | |
|     return selectors.join(",\n") + "\n" + css + "\n";
 | |
|   }
 | |
|   function generateFieldCSS() {
 | |
|     var cssSelectors = odf.OdfSchema.getFields().map(function(prefixedName) {
 | |
|       return prefixedName.replace(":", "|");
 | |
|     }), highlightFields = createRule(cssSelectors, "{ background-color: #D0D0D0; }"), emptyCssSelectors = cssSelectors.map(function(selector) {
 | |
|       return selector + ":empty::after";
 | |
|     }), highlightEmptyFields = createRule(emptyCssSelectors, "{ content:' '; white-space: pre; }");
 | |
|     return highlightFields + "\n" + highlightEmptyFields;
 | |
|   }
 | |
|   this.showFieldHighlight = function() {
 | |
|     style.appendChild(document.createTextNode(generateFieldCSS()));
 | |
|   };
 | |
|   this.hideFieldHighlight = function() {
 | |
|     clearCSSStyleSheet(style);
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     if (style.parentNode) {
 | |
|       style.parentNode.removeChild(style);
 | |
|     }
 | |
|     callback();
 | |
|   };
 | |
|   function init() {
 | |
|     style = newStyleSheet();
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.ShadowCursor = function ShadowCursor(document) {
 | |
|   var selectedRange = (document.getDOMDocument().createRange()), forwardSelection = true;
 | |
|   this.removeFromDocument = function() {
 | |
|   };
 | |
|   this.getMemberId = function() {
 | |
|     return gui.ShadowCursor.ShadowCursorMemberId;
 | |
|   };
 | |
|   this.getSelectedRange = function() {
 | |
|     return selectedRange;
 | |
|   };
 | |
|   this.setSelectedRange = function(range, isForwardSelection) {
 | |
|     selectedRange = range;
 | |
|     forwardSelection = isForwardSelection !== false;
 | |
|   };
 | |
|   this.hasForwardSelection = function() {
 | |
|     return forwardSelection;
 | |
|   };
 | |
|   this.getDocument = function() {
 | |
|     return document;
 | |
|   };
 | |
|   this.getSelectionType = function() {
 | |
|     return ops.OdtCursor.RangeSelection;
 | |
|   };
 | |
|   function init() {
 | |
|     selectedRange.setStart(document.getRootNode(), 0);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.ShadowCursor.ShadowCursorMemberId = "";
 | |
| gui.SelectionView = function SelectionView(cursor) {
 | |
| };
 | |
| gui.SelectionView.prototype.rerender = function() {
 | |
| };
 | |
| gui.SelectionView.prototype.show = function() {
 | |
| };
 | |
| gui.SelectionView.prototype.hide = function() {
 | |
| };
 | |
| gui.SelectionView.prototype.destroy = function(callback) {
 | |
| };
 | |
| gui.SelectionViewManager = function SelectionViewManager(SelectionView) {
 | |
|   var selectionViews = {};
 | |
|   function getSelectionView(memberId) {
 | |
|     return selectionViews.hasOwnProperty(memberId) ? selectionViews[memberId] : null;
 | |
|   }
 | |
|   this.getSelectionView = getSelectionView;
 | |
|   function getSelectionViews() {
 | |
|     return Object.keys(selectionViews).map(function(memberid) {
 | |
|       return selectionViews[memberid];
 | |
|     });
 | |
|   }
 | |
|   this.getSelectionViews = getSelectionViews;
 | |
|   function removeSelectionView(memberId) {
 | |
|     if (selectionViews.hasOwnProperty(memberId)) {
 | |
|       selectionViews[memberId].destroy(function() {
 | |
|       });
 | |
|       delete selectionViews[memberId];
 | |
|     }
 | |
|   }
 | |
|   this.removeSelectionView = removeSelectionView;
 | |
|   function hideSelectionView(memberId) {
 | |
|     if (selectionViews.hasOwnProperty(memberId)) {
 | |
|       selectionViews[memberId].hide();
 | |
|     }
 | |
|   }
 | |
|   this.hideSelectionView = hideSelectionView;
 | |
|   function showSelectionView(memberId) {
 | |
|     if (selectionViews.hasOwnProperty(memberId)) {
 | |
|       selectionViews[memberId].show();
 | |
|     }
 | |
|   }
 | |
|   this.showSelectionView = showSelectionView;
 | |
|   this.rerenderSelectionViews = function() {
 | |
|     Object.keys(selectionViews).forEach(function(memberId) {
 | |
|       selectionViews[memberId].rerender();
 | |
|     });
 | |
|   };
 | |
|   this.registerCursor = function(cursor, virtualSelectionsInitiallyVisible) {
 | |
|     var memberId = cursor.getMemberId(), selectionView = new SelectionView(cursor);
 | |
|     if (virtualSelectionsInitiallyVisible) {
 | |
|       selectionView.show();
 | |
|     } else {
 | |
|       selectionView.hide();
 | |
|     }
 | |
|     selectionViews[memberId] = selectionView;
 | |
|     return selectionView;
 | |
|   };
 | |
|   this.destroy = function(callback) {
 | |
|     var selectionViewArray = getSelectionViews();
 | |
|     function destroySelectionView(i, err) {
 | |
|       if (err) {
 | |
|         callback(err);
 | |
|       } else {
 | |
|         if (i < selectionViewArray.length) {
 | |
|           selectionViewArray[i].destroy(function(err) {
 | |
|             destroySelectionView(i + 1, err);
 | |
|           });
 | |
|         } else {
 | |
|           callback();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     destroySelectionView(0, undefined);
 | |
|   };
 | |
| };
 | |
| gui.SessionViewOptions = function() {
 | |
|   this.editInfoMarkersInitiallyVisible = true;
 | |
|   this.caretAvatarsInitiallyVisible = true;
 | |
|   this.caretBlinksOnRangeSelect = true;
 | |
| };
 | |
| (function() {
 | |
|   function configOption(userValue, defaultValue) {
 | |
|     return userValue !== undefined ? Boolean(userValue) : defaultValue;
 | |
|   }
 | |
|   gui.SessionView = function SessionView(viewOptions, localMemberId, session, sessionConstraints, caretManager, selectionViewManager) {
 | |
|     var avatarInfoStyles, annotationConstraintStyles, editInfons = "urn:webodf:names:editinfo", editInfoMap = {}, odtDocument, odfCanvas, highlightRefreshTask, showEditInfoMarkers = configOption(viewOptions.editInfoMarkersInitiallyVisible, true), showCaretAvatars = configOption(viewOptions.caretAvatarsInitiallyVisible, true), blinkOnRangeSelect = configOption(viewOptions.caretBlinksOnRangeSelect, true);
 | |
|     function onAnnotationAdded(info) {
 | |
|       if (info.memberId === localMemberId) {
 | |
|         odfCanvas.getViewport().scrollIntoView(info.annotation.getBoundingClientRect());
 | |
|       }
 | |
|     }
 | |
|     function newStyleSheet() {
 | |
|       var head = document.getElementsByTagName("head").item(0), sheet = (document.createElement("style"));
 | |
|       sheet.type = "text/css";
 | |
|       sheet.media = "screen, print, handheld, projection";
 | |
|       head.appendChild(sheet);
 | |
|       return sheet;
 | |
|     }
 | |
|     function createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) {
 | |
|       return nodeName + '[editinfo|memberid="' + memberId + '"]' + pseudoClass;
 | |
|     }
 | |
|     function getAvatarInfoStyle(nodeName, memberId, pseudoClass) {
 | |
|       var node = avatarInfoStyles.firstChild, nodeMatch = createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) + "{";
 | |
|       while (node) {
 | |
|         if (node.nodeType === Node.TEXT_NODE && (node).data.indexOf(nodeMatch) === 0) {
 | |
|           return node;
 | |
|         }
 | |
|         node = node.nextSibling;
 | |
|       }
 | |
|       return null;
 | |
|     }
 | |
|     function setAvatarInfoStyle(memberId, name, color) {
 | |
|       function setStyle(nodeName, rule, pseudoClass) {
 | |
|         var styleRule = createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) + rule, styleNode = getAvatarInfoStyle(nodeName, memberId, pseudoClass);
 | |
|         if (styleNode) {
 | |
|           styleNode.data = styleRule;
 | |
|         } else {
 | |
|           avatarInfoStyles.appendChild(document.createTextNode(styleRule));
 | |
|         }
 | |
|       }
 | |
|       setStyle("div.editInfoMarker", "{ background-color: " + color + "; }", "");
 | |
|       setStyle("span.editInfoColor", "{ background-color: " + color + "; }", "");
 | |
|       setStyle("span.editInfoAuthor", '{ content: "' + name + '"; }', ":before");
 | |
|       setStyle("dc|creator", "{ background-color: " + color + "; }", "");
 | |
|       setStyle(".webodf-selectionOverlay", "{ fill: " + color + "; stroke: " + color + ";}", "");
 | |
|       if (memberId === localMemberId) {
 | |
|         setStyle(".webodf-touchEnabled .webodf-selectionOverlay", "{ display: block; }", " > .webodf-draggable");
 | |
|         memberId = gui.ShadowCursor.ShadowCursorMemberId;
 | |
|         setStyle(".webodf-selectionOverlay", "{ fill: " + color + "; stroke: " + color + ";}", "");
 | |
|         setStyle(".webodf-touchEnabled .webodf-selectionOverlay", "{ display: block; }", " > .webodf-draggable");
 | |
|       }
 | |
|     }
 | |
|     function highlightEdit(element, memberId, timestamp) {
 | |
|       var editInfo, editInfoMarker, id = "", editInfoNode = element.getElementsByTagNameNS(editInfons, "editinfo").item(0);
 | |
|       if (editInfoNode) {
 | |
|         id = (editInfoNode).getAttributeNS(editInfons, "id");
 | |
|         editInfoMarker = editInfoMap[id];
 | |
|       } else {
 | |
|         id = Math.random().toString();
 | |
|         editInfo = new ops.EditInfo(element, session.getOdtDocument());
 | |
|         editInfoMarker = new gui.EditInfoMarker(editInfo, showEditInfoMarkers);
 | |
|         editInfoNode = (element.getElementsByTagNameNS(editInfons, "editinfo").item(0));
 | |
|         editInfoNode.setAttributeNS(editInfons, "id", id);
 | |
|         editInfoMap[id] = editInfoMarker;
 | |
|       }
 | |
|       editInfoMarker.addEdit(memberId, new Date(timestamp));
 | |
|     }
 | |
|     function setEditInfoMarkerVisibility(visible) {
 | |
|       var editInfoMarker, keyname;
 | |
|       for (keyname in editInfoMap) {
 | |
|         if (editInfoMap.hasOwnProperty(keyname)) {
 | |
|           editInfoMarker = editInfoMap[keyname];
 | |
|           if (visible) {
 | |
|             editInfoMarker.show();
 | |
|           } else {
 | |
|             editInfoMarker.hide();
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function setCaretAvatarVisibility(visible) {
 | |
|       caretManager.getCarets().forEach(function(caret) {
 | |
|         if (visible) {
 | |
|           caret.showHandle();
 | |
|         } else {
 | |
|           caret.hideHandle();
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     this.showEditInfoMarkers = function() {
 | |
|       if (showEditInfoMarkers) {
 | |
|         return;
 | |
|       }
 | |
|       showEditInfoMarkers = true;
 | |
|       setEditInfoMarkerVisibility(showEditInfoMarkers);
 | |
|     };
 | |
|     this.hideEditInfoMarkers = function() {
 | |
|       if (!showEditInfoMarkers) {
 | |
|         return;
 | |
|       }
 | |
|       showEditInfoMarkers = false;
 | |
|       setEditInfoMarkerVisibility(showEditInfoMarkers);
 | |
|     };
 | |
|     this.showCaretAvatars = function() {
 | |
|       if (showCaretAvatars) {
 | |
|         return;
 | |
|       }
 | |
|       showCaretAvatars = true;
 | |
|       setCaretAvatarVisibility(showCaretAvatars);
 | |
|     };
 | |
|     this.hideCaretAvatars = function() {
 | |
|       if (!showCaretAvatars) {
 | |
|         return;
 | |
|       }
 | |
|       showCaretAvatars = false;
 | |
|       setCaretAvatarVisibility(showCaretAvatars);
 | |
|     };
 | |
|     this.getSession = function() {
 | |
|       return session;
 | |
|     };
 | |
|     this.getCaret = function(memberid) {
 | |
|       return caretManager.getCaret(memberid);
 | |
|     };
 | |
|     function renderMemberData(member) {
 | |
|       var memberId = member.getMemberId(), properties = member.getProperties();
 | |
|       setAvatarInfoStyle(memberId, properties.fullName, properties.color);
 | |
|     }
 | |
|     function onCursorAdded(cursor) {
 | |
|       var memberId = cursor.getMemberId(), properties = session.getOdtDocument().getMember(memberId).getProperties(), caret;
 | |
|       caretManager.registerCursor(cursor, showCaretAvatars, blinkOnRangeSelect);
 | |
|       selectionViewManager.registerCursor(cursor, true);
 | |
|       caret = caretManager.getCaret(memberId);
 | |
|       if (caret) {
 | |
|         caret.setAvatarImageUrl(properties.imageUrl);
 | |
|         caret.setColor(properties.color);
 | |
|       }
 | |
|       runtime.log("+++ View here +++ eagerly created an Caret for '" + memberId + "'! +++");
 | |
|     }
 | |
|     function onCursorMoved(cursor) {
 | |
|       var memberId = cursor.getMemberId(), localSelectionView = selectionViewManager.getSelectionView(localMemberId), shadowSelectionView = selectionViewManager.getSelectionView(gui.ShadowCursor.ShadowCursorMemberId), localCaret = caretManager.getCaret(localMemberId);
 | |
|       if (memberId === localMemberId) {
 | |
|         shadowSelectionView.hide();
 | |
|         if (localSelectionView) {
 | |
|           localSelectionView.show();
 | |
|         }
 | |
|         if (localCaret) {
 | |
|           localCaret.show();
 | |
|         }
 | |
|       } else {
 | |
|         if (memberId === gui.ShadowCursor.ShadowCursorMemberId) {
 | |
|           shadowSelectionView.show();
 | |
|           if (localSelectionView) {
 | |
|             localSelectionView.hide();
 | |
|           }
 | |
|           if (localCaret) {
 | |
|             localCaret.hide();
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function onCursorRemoved(memberid) {
 | |
|       selectionViewManager.removeSelectionView(memberid);
 | |
|     }
 | |
|     function onParagraphChanged(info) {
 | |
|       highlightEdit(info.paragraphElement, info.memberId, info.timeStamp);
 | |
|       highlightRefreshTask.trigger();
 | |
|     }
 | |
|     function refreshHighlights() {
 | |
|       var annotationViewManager = odfCanvas.getAnnotationViewManager();
 | |
|       if (annotationViewManager) {
 | |
|         annotationViewManager.rehighlightAnnotations();
 | |
|         odtDocument.fixCursorPositions();
 | |
|       }
 | |
|     }
 | |
|     function processConstraints() {
 | |
|       var localMemberName, cssString, localMember;
 | |
|       if (annotationConstraintStyles.hasChildNodes()) {
 | |
|         core.DomUtils.removeAllChildNodes(annotationConstraintStyles);
 | |
|       }
 | |
|       if (sessionConstraints.getState(gui.CommonConstraints.EDIT.ANNOTATIONS.ONLY_DELETE_OWN) === true) {
 | |
|         localMember = session.getOdtDocument().getMember(localMemberId);
 | |
|         if (localMember) {
 | |
|           localMemberName = localMember.getProperties().fullName;
 | |
|           cssString = ".annotationWrapper:not([creator = '" + localMemberName + "']) .annotationRemoveButton { display: none; }";
 | |
|           annotationConstraintStyles.appendChild(document.createTextNode(cssString));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     function destroy(callback) {
 | |
|       var editInfoArray = Object.keys(editInfoMap).map(function(keyname) {
 | |
|         return editInfoMap[keyname];
 | |
|       });
 | |
|       odtDocument.unsubscribe(ops.Document.signalMemberAdded, renderMemberData);
 | |
|       odtDocument.unsubscribe(ops.Document.signalMemberUpdated, renderMemberData);
 | |
|       odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorAdded);
 | |
|       odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
 | |
|       odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorMoved);
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, selectionViewManager.rerenderSelectionViews);
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalTableAdded, selectionViewManager.rerenderSelectionViews);
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, selectionViewManager.rerenderSelectionViews);
 | |
|       sessionConstraints.unsubscribe(gui.CommonConstraints.EDIT.ANNOTATIONS.ONLY_DELETE_OWN, processConstraints);
 | |
|       odtDocument.unsubscribe(ops.Document.signalMemberAdded, processConstraints);
 | |
|       odtDocument.unsubscribe(ops.Document.signalMemberUpdated, processConstraints);
 | |
|       avatarInfoStyles.parentNode.removeChild(avatarInfoStyles);
 | |
|       annotationConstraintStyles.parentNode.removeChild(annotationConstraintStyles);
 | |
|       (function destroyEditInfo(i, err) {
 | |
|         if (err) {
 | |
|           callback(err);
 | |
|         } else {
 | |
|           if (i < editInfoArray.length) {
 | |
|             editInfoArray[i].destroy(function(err) {
 | |
|               destroyEditInfo(i + 1, err);
 | |
|             });
 | |
|           } else {
 | |
|             callback();
 | |
|           }
 | |
|         }
 | |
|       })(0, undefined);
 | |
|     }
 | |
|     this.destroy = function(callback) {
 | |
|       var cleanup = [highlightRefreshTask.destroy, destroy];
 | |
|       odtDocument.unsubscribe(ops.OdtDocument.signalAnnotationAdded, onAnnotationAdded);
 | |
|       core.Async.destroyAll(cleanup, callback);
 | |
|     };
 | |
|     function init() {
 | |
|       odtDocument = session.getOdtDocument();
 | |
|       odfCanvas = odtDocument.getOdfCanvas();
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalAnnotationAdded, onAnnotationAdded);
 | |
|       odtDocument.subscribe(ops.Document.signalMemberAdded, renderMemberData);
 | |
|       odtDocument.subscribe(ops.Document.signalMemberUpdated, renderMemberData);
 | |
|       odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorAdded);
 | |
|       odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
 | |
|       odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorMoved);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, selectionViewManager.rerenderSelectionViews);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalTableAdded, selectionViewManager.rerenderSelectionViews);
 | |
|       odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, selectionViewManager.rerenderSelectionViews);
 | |
|       sessionConstraints.subscribe(gui.CommonConstraints.EDIT.ANNOTATIONS.ONLY_DELETE_OWN, processConstraints);
 | |
|       odtDocument.subscribe(ops.Document.signalMemberAdded, processConstraints);
 | |
|       odtDocument.subscribe(ops.Document.signalMemberUpdated, processConstraints);
 | |
|       avatarInfoStyles = newStyleSheet();
 | |
|       avatarInfoStyles.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));
 | |
|       avatarInfoStyles.appendChild(document.createTextNode("@namespace dc url(http://purl.org/dc/elements/1.1/);"));
 | |
|       annotationConstraintStyles = newStyleSheet();
 | |
|       processConstraints();
 | |
|       highlightRefreshTask = core.Task.createRedrawTask(refreshHighlights);
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
| })();
 | |
| gui.SvgSelectionView = function SvgSelectionView(cursor) {
 | |
|   var document = cursor.getDocument(), documentRoot, sizer, doc = document.getDOMDocument(), svgns = "http://www.w3.org/2000/svg", overlay = doc.createElementNS(svgns, "svg"), polygon = doc.createElementNS(svgns, "polygon"), handle1 = doc.createElementNS(svgns, "circle"), handle2 = doc.createElementNS(svgns, "circle"), odfUtils = odf.OdfUtils, domUtils = core.DomUtils, zoomHelper = document.getCanvas().getZoomHelper(), isVisible = true, positionIterator = cursor.getDocument().createPositionIterator(document.getRootNode()), 
 | |
|   FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT, FILTER_REJECT = NodeFilter.FILTER_REJECT, HANDLE_RADIUS = 8, renderTask;
 | |
|   function addOverlay() {
 | |
|     var newDocumentRoot = document.getRootNode();
 | |
|     if (documentRoot !== newDocumentRoot) {
 | |
|       documentRoot = newDocumentRoot;
 | |
|       sizer = document.getCanvas().getSizer();
 | |
|       sizer.appendChild(overlay);
 | |
|       overlay.setAttribute("class", "webodf-selectionOverlay");
 | |
|       handle1.setAttribute("class", "webodf-draggable");
 | |
|       handle2.setAttribute("class", "webodf-draggable");
 | |
|       handle1.setAttribute("end", "left");
 | |
|       handle2.setAttribute("end", "right");
 | |
|       handle1.setAttribute("r", HANDLE_RADIUS);
 | |
|       handle2.setAttribute("r", HANDLE_RADIUS);
 | |
|       overlay.appendChild(polygon);
 | |
|       overlay.appendChild(handle1);
 | |
|       overlay.appendChild(handle2);
 | |
|     }
 | |
|   }
 | |
|   function isRangeVisible(range) {
 | |
|     var bcr = range.getBoundingClientRect();
 | |
|     return Boolean(bcr && bcr.height !== 0);
 | |
|   }
 | |
|   function lastVisibleRect(range, nodes) {
 | |
|     var nextNodeIndex = nodes.length - 1, node = nodes[nextNodeIndex], startOffset, endOffset;
 | |
|     if (range.endContainer === node) {
 | |
|       startOffset = range.endOffset;
 | |
|     } else {
 | |
|       if (node.nodeType === Node.TEXT_NODE) {
 | |
|         startOffset = node.length;
 | |
|       } else {
 | |
|         startOffset = node.childNodes.length;
 | |
|       }
 | |
|     }
 | |
|     endOffset = startOffset;
 | |
|     range.setStart(node, startOffset);
 | |
|     range.setEnd(node, endOffset);
 | |
|     while (!isRangeVisible(range)) {
 | |
|       if (node.nodeType === Node.ELEMENT_NODE && startOffset > 0) {
 | |
|         startOffset = 0;
 | |
|       } else {
 | |
|         if (node.nodeType === Node.TEXT_NODE && startOffset > 0) {
 | |
|           startOffset -= 1;
 | |
|         } else {
 | |
|           if (nodes[nextNodeIndex]) {
 | |
|             node = nodes[nextNodeIndex];
 | |
|             nextNodeIndex -= 1;
 | |
|             startOffset = endOffset = node.length || node.childNodes.length;
 | |
|           } else {
 | |
|             return false;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       range.setStart(node, startOffset);
 | |
|       range.setEnd(node, endOffset);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   function firstVisibleRect(range, nodes) {
 | |
|     var nextNodeIndex = 0, node = nodes[nextNodeIndex], startOffset = range.startContainer === node ? range.startOffset : 0, endOffset = startOffset;
 | |
|     range.setStart(node, startOffset);
 | |
|     range.setEnd(node, endOffset);
 | |
|     while (!isRangeVisible(range)) {
 | |
|       if (node.nodeType === Node.ELEMENT_NODE && endOffset < node.childNodes.length) {
 | |
|         endOffset = node.childNodes.length;
 | |
|       } else {
 | |
|         if (node.nodeType === Node.TEXT_NODE && endOffset < node.length) {
 | |
|           endOffset += 1;
 | |
|         } else {
 | |
|           if (nodes[nextNodeIndex]) {
 | |
|             node = nodes[nextNodeIndex];
 | |
|             nextNodeIndex += 1;
 | |
|             startOffset = endOffset = 0;
 | |
|           } else {
 | |
|             return false;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       range.setStart(node, startOffset);
 | |
|       range.setEnd(node, endOffset);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   function getExtremeRanges(range) {
 | |
|     var nodes = odfUtils.getTextElements(range, true, false), firstRange = (range.cloneRange()), lastRange = (range.cloneRange()), fillerRange = range.cloneRange();
 | |
|     if (!nodes.length) {
 | |
|       return null;
 | |
|     }
 | |
|     if (!firstVisibleRect(firstRange, nodes)) {
 | |
|       return null;
 | |
|     }
 | |
|     if (!lastVisibleRect(lastRange, nodes)) {
 | |
|       return null;
 | |
|     }
 | |
|     fillerRange.setStart(firstRange.startContainer, firstRange.startOffset);
 | |
|     fillerRange.setEnd(lastRange.endContainer, lastRange.endOffset);
 | |
|     return {firstRange:firstRange, lastRange:lastRange, fillerRange:fillerRange};
 | |
|   }
 | |
|   function getBoundingRect(rect1, rect2) {
 | |
|     var resultRect = {};
 | |
|     resultRect.top = Math.min(rect1.top, rect2.top);
 | |
|     resultRect.left = Math.min(rect1.left, rect2.left);
 | |
|     resultRect.right = Math.max(rect1.right, rect2.right);
 | |
|     resultRect.bottom = Math.max(rect1.bottom, rect2.bottom);
 | |
|     resultRect.width = resultRect.right - resultRect.left;
 | |
|     resultRect.height = resultRect.bottom - resultRect.top;
 | |
|     return resultRect;
 | |
|   }
 | |
|   function checkAndGrowOrCreateRect(originalRect, newRect) {
 | |
|     if (newRect && newRect.width > 0 && newRect.height > 0) {
 | |
|       if (!originalRect) {
 | |
|         originalRect = newRect;
 | |
|       } else {
 | |
|         originalRect = getBoundingRect(originalRect, newRect);
 | |
|       }
 | |
|     }
 | |
|     return originalRect;
 | |
|   }
 | |
|   function getFillerRect(fillerRange) {
 | |
|     var containerNode = fillerRange.commonAncestorContainer, firstNode = (fillerRange.startContainer), lastNode = (fillerRange.endContainer), firstOffset = fillerRange.startOffset, lastOffset = fillerRange.endOffset, currentNode, lastMeasuredNode, firstSibling, lastSibling, grownRect = null, currentRect, range = doc.createRange(), rootFilter, odfNodeFilter = new odf.OdfNodeFilter, treeWalker;
 | |
|     function acceptNode(node) {
 | |
|       positionIterator.setUnfilteredPosition(node, 0);
 | |
|       if (odfNodeFilter.acceptNode(node) === FILTER_ACCEPT && rootFilter.acceptPosition(positionIterator) === FILTER_ACCEPT) {
 | |
|         return FILTER_ACCEPT;
 | |
|       }
 | |
|       return FILTER_REJECT;
 | |
|     }
 | |
|     function getRectFromNodeAfterFiltering(node) {
 | |
|       var rect = null;
 | |
|       if (acceptNode(node) === FILTER_ACCEPT) {
 | |
|         rect = domUtils.getBoundingClientRect(node);
 | |
|       }
 | |
|       return rect;
 | |
|     }
 | |
|     if (firstNode === containerNode || lastNode === containerNode) {
 | |
|       range = fillerRange.cloneRange();
 | |
|       grownRect = range.getBoundingClientRect();
 | |
|       range.detach();
 | |
|       return grownRect;
 | |
|     }
 | |
|     firstSibling = firstNode;
 | |
|     while (firstSibling.parentNode !== containerNode) {
 | |
|       firstSibling = firstSibling.parentNode;
 | |
|     }
 | |
|     lastSibling = lastNode;
 | |
|     while (lastSibling.parentNode !== containerNode) {
 | |
|       lastSibling = lastSibling.parentNode;
 | |
|     }
 | |
|     rootFilter = document.createRootFilter(firstNode);
 | |
|     currentNode = firstSibling.nextSibling;
 | |
|     while (currentNode && currentNode !== lastSibling) {
 | |
|       currentRect = getRectFromNodeAfterFiltering(currentNode);
 | |
|       grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
 | |
|       currentNode = currentNode.nextSibling;
 | |
|     }
 | |
|     if (odfUtils.isParagraph(firstSibling)) {
 | |
|       grownRect = checkAndGrowOrCreateRect(grownRect, domUtils.getBoundingClientRect(firstSibling));
 | |
|     } else {
 | |
|       if (firstSibling.nodeType === Node.TEXT_NODE) {
 | |
|         currentNode = firstSibling;
 | |
|         range.setStart(currentNode, firstOffset);
 | |
|         range.setEnd(currentNode, currentNode === lastSibling ? lastOffset : (currentNode).length);
 | |
|         currentRect = range.getBoundingClientRect();
 | |
|         grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
 | |
|       } else {
 | |
|         treeWalker = doc.createTreeWalker(firstSibling, NodeFilter.SHOW_TEXT, acceptNode, false);
 | |
|         currentNode = treeWalker.currentNode = firstNode;
 | |
|         while (currentNode && currentNode !== lastNode) {
 | |
|           range.setStart(currentNode, firstOffset);
 | |
|           range.setEnd(currentNode, (currentNode).length);
 | |
|           currentRect = range.getBoundingClientRect();
 | |
|           grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
 | |
|           lastMeasuredNode = currentNode;
 | |
|           firstOffset = 0;
 | |
|           currentNode = treeWalker.nextNode();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (!lastMeasuredNode) {
 | |
|       lastMeasuredNode = firstNode;
 | |
|     }
 | |
|     if (odfUtils.isParagraph(lastSibling)) {
 | |
|       grownRect = checkAndGrowOrCreateRect(grownRect, domUtils.getBoundingClientRect(lastSibling));
 | |
|     } else {
 | |
|       if (lastSibling.nodeType === Node.TEXT_NODE) {
 | |
|         currentNode = lastSibling;
 | |
|         range.setStart(currentNode, currentNode === firstSibling ? firstOffset : 0);
 | |
|         range.setEnd(currentNode, lastOffset);
 | |
|         currentRect = range.getBoundingClientRect();
 | |
|         grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
 | |
|       } else {
 | |
|         treeWalker = doc.createTreeWalker(lastSibling, NodeFilter.SHOW_TEXT, acceptNode, false);
 | |
|         currentNode = treeWalker.currentNode = lastNode;
 | |
|         while (currentNode && currentNode !== lastMeasuredNode) {
 | |
|           range.setStart(currentNode, 0);
 | |
|           range.setEnd(currentNode, lastOffset);
 | |
|           currentRect = range.getBoundingClientRect();
 | |
|           grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
 | |
|           currentNode = treeWalker.previousNode();
 | |
|           if (currentNode) {
 | |
|             lastOffset = (currentNode).length;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return grownRect;
 | |
|   }
 | |
|   function getCollapsedRectOfTextRange(range, useRightEdge) {
 | |
|     var clientRect = range.getBoundingClientRect(), collapsedRect = {};
 | |
|     collapsedRect.width = 0;
 | |
|     collapsedRect.top = clientRect.top;
 | |
|     collapsedRect.bottom = clientRect.bottom;
 | |
|     collapsedRect.height = clientRect.height;
 | |
|     collapsedRect.left = collapsedRect.right = useRightEdge ? clientRect.right : clientRect.left;
 | |
|     return collapsedRect;
 | |
|   }
 | |
|   function setPoints(points) {
 | |
|     var pointsString = "", i;
 | |
|     for (i = 0;i < points.length;i += 1) {
 | |
|       pointsString += points[i].x + "," + points[i].y + " ";
 | |
|     }
 | |
|     polygon.setAttribute("points", pointsString);
 | |
|   }
 | |
|   function repositionOverlays(selectedRange) {
 | |
|     var rootRect = (domUtils.getBoundingClientRect(sizer)), zoomLevel = zoomHelper.getZoomLevel(), extremes = getExtremeRanges(selectedRange), firstRange, lastRange, fillerRange, firstRect, fillerRect, lastRect, left, right, top, bottom;
 | |
|     if (extremes) {
 | |
|       firstRange = extremes.firstRange;
 | |
|       lastRange = extremes.lastRange;
 | |
|       fillerRange = extremes.fillerRange;
 | |
|       firstRect = domUtils.translateRect(getCollapsedRectOfTextRange(firstRange, false), rootRect, zoomLevel);
 | |
|       lastRect = domUtils.translateRect(getCollapsedRectOfTextRange(lastRange, true), rootRect, zoomLevel);
 | |
|       fillerRect = getFillerRect(fillerRange);
 | |
|       if (!fillerRect) {
 | |
|         fillerRect = getBoundingRect(firstRect, lastRect);
 | |
|       } else {
 | |
|         fillerRect = domUtils.translateRect(fillerRect, rootRect, zoomLevel);
 | |
|       }
 | |
|       left = fillerRect.left;
 | |
|       right = firstRect.left + Math.max(0, fillerRect.width - (firstRect.left - fillerRect.left));
 | |
|       top = Math.min(firstRect.top, lastRect.top);
 | |
|       bottom = lastRect.top + lastRect.height;
 | |
|       setPoints([{x:firstRect.left, y:top + firstRect.height}, {x:firstRect.left, y:top}, {x:right, y:top}, {x:right, y:bottom - lastRect.height}, {x:lastRect.right, y:bottom - lastRect.height}, {x:lastRect.right, y:bottom}, {x:left, y:bottom}, {x:left, y:top + firstRect.height}, {x:firstRect.left, y:top + firstRect.height}]);
 | |
|       handle1.setAttribute("cx", firstRect.left);
 | |
|       handle1.setAttribute("cy", top + firstRect.height / 2);
 | |
|       handle2.setAttribute("cx", lastRect.right);
 | |
|       handle2.setAttribute("cy", bottom - lastRect.height / 2);
 | |
|       firstRange.detach();
 | |
|       lastRange.detach();
 | |
|       fillerRange.detach();
 | |
|     }
 | |
|     return Boolean(extremes);
 | |
|   }
 | |
|   function rerender() {
 | |
|     var range = cursor.getSelectedRange(), shouldShow;
 | |
|     shouldShow = isVisible && cursor.getSelectionType() === ops.OdtCursor.RangeSelection && !range.collapsed;
 | |
|     if (shouldShow) {
 | |
|       addOverlay();
 | |
|       shouldShow = repositionOverlays(range);
 | |
|     }
 | |
|     if (shouldShow) {
 | |
|       overlay.style.display = "block";
 | |
|     } else {
 | |
|       overlay.style.display = "none";
 | |
|     }
 | |
|   }
 | |
|   this.rerender = function() {
 | |
|     if (isVisible) {
 | |
|       renderTask.trigger();
 | |
|     }
 | |
|   };
 | |
|   this.show = function() {
 | |
|     isVisible = true;
 | |
|     renderTask.trigger();
 | |
|   };
 | |
|   this.hide = function() {
 | |
|     isVisible = false;
 | |
|     renderTask.trigger();
 | |
|   };
 | |
|   function handleCursorMove(movedCursor) {
 | |
|     if (isVisible && movedCursor === cursor) {
 | |
|       renderTask.trigger();
 | |
|     }
 | |
|   }
 | |
|   function scaleHandles(zoomLevel) {
 | |
|     var radius = HANDLE_RADIUS / zoomLevel;
 | |
|     handle1.setAttribute("r", radius);
 | |
|     handle2.setAttribute("r", radius);
 | |
|   }
 | |
|   function destroy(callback) {
 | |
|     sizer.removeChild(overlay);
 | |
|     sizer.classList.remove("webodf-virtualSelections");
 | |
|     cursor.getDocument().unsubscribe(ops.Document.signalCursorMoved, handleCursorMove);
 | |
|     zoomHelper.unsubscribe(gui.ZoomHelper.signalZoomChanged, scaleHandles);
 | |
|     callback();
 | |
|   }
 | |
|   this.destroy = function(callback) {
 | |
|     core.Async.destroyAll([renderTask.destroy, destroy], callback);
 | |
|   };
 | |
|   function init() {
 | |
|     var editinfons = "urn:webodf:names:editinfo", memberid = cursor.getMemberId();
 | |
|     renderTask = core.Task.createRedrawTask(rerender);
 | |
|     addOverlay();
 | |
|     overlay.setAttributeNS(editinfons, "editinfo:memberid", memberid);
 | |
|     sizer.classList.add("webodf-virtualSelections");
 | |
|     cursor.getDocument().subscribe(ops.Document.signalCursorMoved, handleCursorMove);
 | |
|     zoomHelper.subscribe(gui.ZoomHelper.signalZoomChanged, scaleHandles);
 | |
|     scaleHandles(zoomHelper.getZoomLevel());
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| gui.UndoStateRules = function UndoStateRules() {
 | |
|   function ReverseIterator(array, predicate) {
 | |
|     var index = array.length;
 | |
|     this.previous = function() {
 | |
|       for (index = index - 1;index >= 0;index -= 1) {
 | |
|         if (predicate(array[index])) {
 | |
|           return array[index];
 | |
|         }
 | |
|       }
 | |
|       return null;
 | |
|     };
 | |
|   }
 | |
|   function getOpType(op) {
 | |
|     return op.spec().optype;
 | |
|   }
 | |
|   function getOpPosition(op) {
 | |
|     var key = "position", spec = op.spec(), value;
 | |
|     if (spec.hasOwnProperty(key)) {
 | |
|       value = (spec[key]);
 | |
|     }
 | |
|     return value;
 | |
|   }
 | |
|   function isEditOperation(op) {
 | |
|     return op.isEdit;
 | |
|   }
 | |
|   this.isEditOperation = isEditOperation;
 | |
|   function canAggregateOperation(op) {
 | |
|     switch(getOpType(op)) {
 | |
|       case "RemoveText":
 | |
|       ;
 | |
|       case "InsertText":
 | |
|         return true;
 | |
|       default:
 | |
|         return false;
 | |
|     }
 | |
|   }
 | |
|   function isSameDirectionOfTravel(thisOp, lastEditOp, secondLastEditOp) {
 | |
|     var thisPosition = getOpPosition(thisOp), lastPosition = getOpPosition(lastEditOp), secondLastPosition = getOpPosition(secondLastEditOp), diffLastToSecondLast = lastPosition - secondLastPosition, diffThisToLast = thisPosition - lastPosition;
 | |
|     return diffThisToLast === diffLastToSecondLast;
 | |
|   }
 | |
|   function isAdjacentOperation(thisOp, lastEditOp) {
 | |
|     var positionDifference = getOpPosition(thisOp) - getOpPosition(lastEditOp);
 | |
|     return positionDifference === 0 || Math.abs(positionDifference) === 1;
 | |
|   }
 | |
|   function continuesOperations(thisOp, lastEditOp, secondLastEditOp) {
 | |
|     if (!secondLastEditOp) {
 | |
|       return isAdjacentOperation(thisOp, lastEditOp);
 | |
|     }
 | |
|     return isSameDirectionOfTravel(thisOp, lastEditOp, secondLastEditOp);
 | |
|   }
 | |
|   function continuesMostRecentEditOperation(thisOp, recentOperations) {
 | |
|     var thisOpType = getOpType(thisOp), editOpsFinder = new ReverseIterator(recentOperations, isEditOperation), lastEditOp = editOpsFinder.previous();
 | |
|     runtime.assert(Boolean(lastEditOp), "No edit operations found in state");
 | |
|     if (thisOpType === getOpType((lastEditOp))) {
 | |
|       return continuesOperations(thisOp, (lastEditOp), editOpsFinder.previous());
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function continuesMostRecentEditGroup(thisOp, recentOperations) {
 | |
|     var thisOpType = getOpType(thisOp), editOpsFinder = new ReverseIterator(recentOperations, isEditOperation), candidateOp = editOpsFinder.previous(), lastEditOp, secondLastEditOp = null, inspectedGroupsCount, groupId;
 | |
|     runtime.assert(Boolean(candidateOp), "No edit operations found in state");
 | |
|     groupId = candidateOp.group;
 | |
|     runtime.assert(groupId !== undefined, "Operation has no group");
 | |
|     inspectedGroupsCount = 1;
 | |
|     while (candidateOp && candidateOp.group === groupId) {
 | |
|       if (thisOpType === getOpType(candidateOp)) {
 | |
|         lastEditOp = candidateOp;
 | |
|         break;
 | |
|       }
 | |
|       candidateOp = editOpsFinder.previous();
 | |
|     }
 | |
|     if (lastEditOp) {
 | |
|       candidateOp = editOpsFinder.previous();
 | |
|       while (candidateOp) {
 | |
|         if (candidateOp.group !== groupId) {
 | |
|           if (inspectedGroupsCount === 2) {
 | |
|             break;
 | |
|           }
 | |
|           groupId = candidateOp.group;
 | |
|           inspectedGroupsCount += 1;
 | |
|         }
 | |
|         if (thisOpType === getOpType(candidateOp)) {
 | |
|           secondLastEditOp = candidateOp;
 | |
|           break;
 | |
|         }
 | |
|         candidateOp = editOpsFinder.previous();
 | |
|       }
 | |
|       return continuesOperations(thisOp, (lastEditOp), secondLastEditOp);
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function isPartOfOperationSet(operation, recentOperations) {
 | |
|     var areOperationsGrouped = operation.group !== undefined, lastOperation;
 | |
|     if (!isEditOperation(operation)) {
 | |
|       return true;
 | |
|     }
 | |
|     if (recentOperations.length === 0) {
 | |
|       return true;
 | |
|     }
 | |
|     lastOperation = recentOperations[recentOperations.length - 1];
 | |
|     if (areOperationsGrouped && operation.group === lastOperation.group) {
 | |
|       return true;
 | |
|     }
 | |
|     if (canAggregateOperation(operation) && recentOperations.some(isEditOperation)) {
 | |
|       if (areOperationsGrouped) {
 | |
|         return continuesMostRecentEditGroup(operation, recentOperations);
 | |
|       }
 | |
|       return continuesMostRecentEditOperation(operation, recentOperations);
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   this.isPartOfOperationSet = isPartOfOperationSet;
 | |
| };
 | |
| (function() {
 | |
|   var stateIdBase = 0;
 | |
|   function StateId(mainId, subId) {
 | |
|     this.mainId = mainId !== undefined ? mainId : -1;
 | |
|     this.subId = subId !== undefined ? subId : -1;
 | |
|   }
 | |
|   function StateTransition(undoRules, initialOps, editOpsPossible) {
 | |
|     var nextStateId, operations, editOpsCount;
 | |
|     this.addOperation = function(op) {
 | |
|       if (undoRules.isEditOperation(op)) {
 | |
|         editOpsCount += 1;
 | |
|       }
 | |
|       operations.push(op);
 | |
|     };
 | |
|     this.isNextStateId = function(stateId) {
 | |
|       return stateId.mainId === nextStateId && stateId.subId === editOpsCount;
 | |
|     };
 | |
|     this.getNextStateId = function() {
 | |
|       return new StateId(nextStateId, editOpsCount);
 | |
|     };
 | |
|     this.getOperations = function() {
 | |
|       return operations;
 | |
|     };
 | |
|     function addEditOpsCount(count, op) {
 | |
|       return count + (undoRules.isEditOperation(op) ? 1 : 0);
 | |
|     }
 | |
|     function init() {
 | |
|       stateIdBase += 1;
 | |
|       nextStateId = stateIdBase;
 | |
|       operations = initialOps || [];
 | |
|       editOpsCount = initialOps && editOpsPossible ? initialOps.reduce(addEditOpsCount, 0) : 0;
 | |
|     }
 | |
|     init();
 | |
|   }
 | |
|   gui.TrivialUndoManager = function TrivialUndoManager(defaultRules) {
 | |
|     var self = this, cursorns = "urn:webodf:names:cursor", domUtils = core.DomUtils, initialDoc, initialStateTransition, playFunc, document, unmodifiedStateId, currentUndoStateTransition, undoStateTransitions = [], redoStateTransitions = [], eventNotifier = new core.EventNotifier([gui.UndoManager.signalUndoStackChanged, gui.UndoManager.signalUndoStateCreated, gui.UndoManager.signalUndoStateModified, gui.UndoManager.signalDocumentModifiedChanged, gui.TrivialUndoManager.signalDocumentRootReplaced]), 
 | |
|     undoRules = defaultRules || new gui.UndoStateRules, isExecutingOps = false;
 | |
|     function isModified() {
 | |
|       return currentUndoStateTransition.isNextStateId(unmodifiedStateId) !== true;
 | |
|     }
 | |
|     function executeOperations(stateTransition) {
 | |
|       var operations = stateTransition.getOperations();
 | |
|       if (operations.length > 0) {
 | |
|         isExecutingOps = true;
 | |
|         playFunc(operations);
 | |
|         isExecutingOps = false;
 | |
|       }
 | |
|     }
 | |
|     function emitStackChange() {
 | |
|       eventNotifier.emit(gui.UndoManager.signalUndoStackChanged, {undoAvailable:self.hasUndoStates(), redoAvailable:self.hasRedoStates()});
 | |
|     }
 | |
|     function emitDocumentModifiedChange(oldModified) {
 | |
|       var newModified = isModified();
 | |
|       if (oldModified !== newModified) {
 | |
|         eventNotifier.emit(gui.UndoManager.signalDocumentModifiedChanged, newModified);
 | |
|       }
 | |
|     }
 | |
|     function mostRecentUndoStateTransition() {
 | |
|       return undoStateTransitions[undoStateTransitions.length - 1];
 | |
|     }
 | |
|     function completeCurrentUndoState() {
 | |
|       if (currentUndoStateTransition !== initialStateTransition && currentUndoStateTransition !== mostRecentUndoStateTransition()) {
 | |
|         undoStateTransitions.push(currentUndoStateTransition);
 | |
|       }
 | |
|     }
 | |
|     function removeNode(node) {
 | |
|       var sibling = node.previousSibling || node.nextSibling;
 | |
|       node.parentNode.removeChild(node);
 | |
|       domUtils.normalizeTextNodes(sibling);
 | |
|     }
 | |
|     function removeCursors(root) {
 | |
|       domUtils.getElementsByTagNameNS(root, cursorns, "cursor").forEach(removeNode);
 | |
|       domUtils.getElementsByTagNameNS(root, cursorns, "anchor").forEach(removeNode);
 | |
|     }
 | |
|     function values(obj) {
 | |
|       return Object.keys(obj).map(function(key) {
 | |
|         return obj[key];
 | |
|       });
 | |
|     }
 | |
|     function extractCursorStates(undoStateTransitions) {
 | |
|       var addCursor = {}, moveCursor = {}, requiredAddOps = {}, remainingAddOps, ops, stateTransition = undoStateTransitions.pop();
 | |
|       document.getMemberIds().forEach(function(memberid) {
 | |
|         requiredAddOps[memberid] = true;
 | |
|       });
 | |
|       remainingAddOps = Object.keys(requiredAddOps).length;
 | |
|       function processOp(op) {
 | |
|         var spec = op.spec();
 | |
|         if (!requiredAddOps[spec.memberid]) {
 | |
|           return;
 | |
|         }
 | |
|         switch(spec.optype) {
 | |
|           case "AddCursor":
 | |
|             if (!addCursor[spec.memberid]) {
 | |
|               addCursor[spec.memberid] = op;
 | |
|               delete requiredAddOps[spec.memberid];
 | |
|               remainingAddOps -= 1;
 | |
|             }
 | |
|             break;
 | |
|           case "MoveCursor":
 | |
|             if (!moveCursor[spec.memberid]) {
 | |
|               moveCursor[spec.memberid] = op;
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
|       }
 | |
|       while (stateTransition && remainingAddOps > 0) {
 | |
|         ops = stateTransition.getOperations();
 | |
|         ops.reverse();
 | |
|         ops.forEach(processOp);
 | |
|         stateTransition = undoStateTransitions.pop();
 | |
|       }
 | |
|       return new StateTransition(undoRules, values(addCursor).concat(values(moveCursor)));
 | |
|     }
 | |
|     this.subscribe = function(signal, callback) {
 | |
|       eventNotifier.subscribe(signal, callback);
 | |
|     };
 | |
|     this.unsubscribe = function(signal, callback) {
 | |
|       eventNotifier.unsubscribe(signal, callback);
 | |
|     };
 | |
|     this.isDocumentModified = isModified;
 | |
|     this.setDocumentModified = function(modified) {
 | |
|       if (isModified() === modified) {
 | |
|         return;
 | |
|       }
 | |
|       if (modified) {
 | |
|         unmodifiedStateId = new StateId;
 | |
|       } else {
 | |
|         unmodifiedStateId = currentUndoStateTransition.getNextStateId();
 | |
|       }
 | |
|       eventNotifier.emit(gui.UndoManager.signalDocumentModifiedChanged, modified);
 | |
|     };
 | |
|     this.hasUndoStates = function() {
 | |
|       return undoStateTransitions.length > 0;
 | |
|     };
 | |
|     this.hasRedoStates = function() {
 | |
|       return redoStateTransitions.length > 0;
 | |
|     };
 | |
|     this.setDocument = function(newDocument) {
 | |
|       document = newDocument;
 | |
|     };
 | |
|     this.purgeInitialState = function() {
 | |
|       var oldModified = isModified();
 | |
|       undoStateTransitions.length = 0;
 | |
|       redoStateTransitions.length = 0;
 | |
|       currentUndoStateTransition = initialStateTransition = new StateTransition(undoRules);
 | |
|       unmodifiedStateId = currentUndoStateTransition.getNextStateId();
 | |
|       initialDoc = null;
 | |
|       emitStackChange();
 | |
|       emitDocumentModifiedChange(oldModified);
 | |
|     };
 | |
|     function setInitialState() {
 | |
|       var oldModified = isModified();
 | |
|       initialDoc = document.cloneDocumentElement();
 | |
|       removeCursors(initialDoc);
 | |
|       completeCurrentUndoState();
 | |
|       currentUndoStateTransition = initialStateTransition = extractCursorStates([initialStateTransition].concat(undoStateTransitions));
 | |
|       undoStateTransitions.length = 0;
 | |
|       redoStateTransitions.length = 0;
 | |
|       if (!oldModified) {
 | |
|         unmodifiedStateId = currentUndoStateTransition.getNextStateId();
 | |
|       }
 | |
|       emitStackChange();
 | |
|       emitDocumentModifiedChange(oldModified);
 | |
|     }
 | |
|     this.setInitialState = setInitialState;
 | |
|     this.initialize = function() {
 | |
|       if (!initialDoc) {
 | |
|         setInitialState();
 | |
|       }
 | |
|     };
 | |
|     this.setPlaybackFunction = function(playback_func) {
 | |
|       playFunc = playback_func;
 | |
|     };
 | |
|     this.onOperationExecuted = function(op) {
 | |
|       if (isExecutingOps) {
 | |
|         return;
 | |
|       }
 | |
|       var oldModified = isModified();
 | |
|       if (undoRules.isEditOperation(op) && (currentUndoStateTransition === initialStateTransition || redoStateTransitions.length > 0) || !undoRules.isPartOfOperationSet(op, currentUndoStateTransition.getOperations())) {
 | |
|         redoStateTransitions.length = 0;
 | |
|         completeCurrentUndoState();
 | |
|         currentUndoStateTransition = new StateTransition(undoRules, [op], true);
 | |
|         undoStateTransitions.push(currentUndoStateTransition);
 | |
|         eventNotifier.emit(gui.UndoManager.signalUndoStateCreated, {operations:currentUndoStateTransition.getOperations()});
 | |
|         emitStackChange();
 | |
|       } else {
 | |
|         currentUndoStateTransition.addOperation(op);
 | |
|         eventNotifier.emit(gui.UndoManager.signalUndoStateModified, {operations:currentUndoStateTransition.getOperations()});
 | |
|       }
 | |
|       emitDocumentModifiedChange(oldModified);
 | |
|     };
 | |
|     this.moveForward = function(states) {
 | |
|       var moved = 0, oldModified = isModified(), redoOperations;
 | |
|       while (states && redoStateTransitions.length) {
 | |
|         redoOperations = redoStateTransitions.pop();
 | |
|         undoStateTransitions.push(redoOperations);
 | |
|         executeOperations(redoOperations);
 | |
|         states -= 1;
 | |
|         moved += 1;
 | |
|       }
 | |
|       if (moved) {
 | |
|         currentUndoStateTransition = mostRecentUndoStateTransition();
 | |
|         emitStackChange();
 | |
|         emitDocumentModifiedChange(oldModified);
 | |
|       }
 | |
|       return moved;
 | |
|     };
 | |
|     this.moveBackward = function(states) {
 | |
|       var moved = 0, oldModified = isModified();
 | |
|       while (states && undoStateTransitions.length) {
 | |
|         redoStateTransitions.push(undoStateTransitions.pop());
 | |
|         states -= 1;
 | |
|         moved += 1;
 | |
|       }
 | |
|       if (moved) {
 | |
|         document.getMemberIds().forEach(function(memberid) {
 | |
|           document.removeCursor(memberid);
 | |
|         });
 | |
|         document.setDocumentElement((initialDoc.cloneNode(true)));
 | |
|         eventNotifier.emit(gui.TrivialUndoManager.signalDocumentRootReplaced, {});
 | |
|         executeOperations(initialStateTransition);
 | |
|         undoStateTransitions.forEach(executeOperations);
 | |
|         currentUndoStateTransition = mostRecentUndoStateTransition() || initialStateTransition;
 | |
|         emitStackChange();
 | |
|         emitDocumentModifiedChange(oldModified);
 | |
|       }
 | |
|       return moved;
 | |
|     };
 | |
|     function init() {
 | |
|       currentUndoStateTransition = initialStateTransition = new StateTransition(undoRules);
 | |
|       unmodifiedStateId = currentUndoStateTransition.getNextStateId();
 | |
|     }
 | |
|     init();
 | |
|   };
 | |
|   gui.TrivialUndoManager.signalDocumentRootReplaced = "documentRootReplaced";
 | |
| })();
 | |
| odf.GraphicProperties = function(element, styleParseUtils, parent) {
 | |
|   var self = this, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, getter;
 | |
|   getter = {verticalPos:function() {
 | |
|     var v = element.getAttributeNS(stylens, "vertical-pos");
 | |
|     return v === "" ? undefined : v;
 | |
|   }, verticalRel:function() {
 | |
|     var v = element.getAttributeNS(stylens, "vertical-rel");
 | |
|     return v === "" ? undefined : v;
 | |
|   }, horizontalPos:function() {
 | |
|     var v = element.getAttributeNS(stylens, "horizontal-pos");
 | |
|     return v === "" ? undefined : v;
 | |
|   }, horizontalRel:function() {
 | |
|     var v = element.getAttributeNS(stylens, "horizontal-rel");
 | |
|     return v === "" ? undefined : v;
 | |
|   }, strokeWidth:function() {
 | |
|     var a = element.getAttributeNS(svgns, "stroke-width");
 | |
|     return styleParseUtils.parseLength(a);
 | |
|   }};
 | |
|   this.verticalPos = function() {
 | |
|     return (self.data.value("verticalPos"));
 | |
|   };
 | |
|   this.verticalRel = function() {
 | |
|     return (self.data.value("verticalRel"));
 | |
|   };
 | |
|   this.horizontalPos = function() {
 | |
|     return (self.data.value("horizontalPos"));
 | |
|   };
 | |
|   this.horizontalRel = function() {
 | |
|     return (self.data.value("horizontalRel"));
 | |
|   };
 | |
|   this.strokeWidth = function() {
 | |
|     return (self.data.value("strokeWidth"));
 | |
|   };
 | |
|   this.data;
 | |
|   function init() {
 | |
|     var p = parent === undefined ? undefined : parent.data;
 | |
|     self.data = new odf.LazyStyleProperties(p, getter);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.ComputedGraphicProperties = function() {
 | |
|   var g;
 | |
|   this.setGraphicProperties = function(graphicProperties) {
 | |
|     g = graphicProperties;
 | |
|   };
 | |
|   this.verticalPos = function() {
 | |
|     return g && g.verticalPos() || "from-top";
 | |
|   };
 | |
|   this.verticalRel = function() {
 | |
|     return g && g.verticalRel() || "page";
 | |
|   };
 | |
|   this.horizontalPos = function() {
 | |
|     return g && g.horizontalPos() || "from-left";
 | |
|   };
 | |
|   this.horizontalRel = function() {
 | |
|     return g && g.horizontalRel() || "page";
 | |
|   };
 | |
| };
 | |
| odf.PageLayoutProperties = function(element, styleParseUtils, parent) {
 | |
|   var self = this, fons = odf.Namespaces.fons, getter;
 | |
|   getter = {pageHeight:function() {
 | |
|     var a, value;
 | |
|     if (element) {
 | |
|       a = element.getAttributeNS(fons, "page-height");
 | |
|       value = styleParseUtils.parseLength(a);
 | |
|     }
 | |
|     return value;
 | |
|   }, pageWidth:function() {
 | |
|     var a, value;
 | |
|     if (element) {
 | |
|       a = element.getAttributeNS(fons, "page-width");
 | |
|       value = styleParseUtils.parseLength(a);
 | |
|     }
 | |
|     return value;
 | |
|   }};
 | |
|   this.pageHeight = function() {
 | |
|     return (self.data.value("pageHeight")) || 1123;
 | |
|   };
 | |
|   this.pageWidth = function() {
 | |
|     return (self.data.value("pageWidth")) || 794;
 | |
|   };
 | |
|   this.data;
 | |
|   function init() {
 | |
|     var p = parent === undefined ? undefined : parent.data;
 | |
|     self.data = new odf.LazyStyleProperties(p, getter);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.PageLayout = function(element, styleParseUtils, parent) {
 | |
|   var self = this;
 | |
|   this.pageLayout;
 | |
|   function init() {
 | |
|     var e = null;
 | |
|     if (element) {
 | |
|       e = styleParseUtils.getPropertiesElement("page-layout-properties", element);
 | |
|     }
 | |
|     self.pageLayout = new odf.PageLayoutProperties(e, styleParseUtils, parent && parent.pageLayout);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.PageLayoutCache = function() {
 | |
| };
 | |
| odf.PageLayoutCache.prototype.getPageLayout = function(name) {
 | |
| };
 | |
| odf.PageLayoutCache.prototype.getDefaultPageLayout = function() {
 | |
| };
 | |
| odf.ParagraphProperties = function(element, styleParseUtils, parent) {
 | |
|   var self = this, fons = odf.Namespaces.fons, getter;
 | |
|   getter = {marginTop:function() {
 | |
|     var a = element.getAttributeNS(fons, "margin-top"), value = styleParseUtils.parsePositiveLengthOrPercent(a, "marginTop", parent && parent.data);
 | |
|     return value;
 | |
|   }};
 | |
|   this.marginTop = function() {
 | |
|     return (self.data.value("marginTop"));
 | |
|   };
 | |
|   this.data;
 | |
|   function init() {
 | |
|     var p = parent === undefined ? undefined : parent.data;
 | |
|     self.data = new odf.LazyStyleProperties(p, getter);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.ComputedParagraphProperties = function() {
 | |
|   var data = {}, styleChain = [];
 | |
|   function value(name) {
 | |
|     var v, i;
 | |
|     if (data.hasOwnProperty(name)) {
 | |
|       v = data[name];
 | |
|     } else {
 | |
|       for (i = 0;v === undefined && i < styleChain.length;i += 1) {
 | |
|         v = (styleChain[i][name])();
 | |
|       }
 | |
|       data[name] = v;
 | |
|     }
 | |
|     return v;
 | |
|   }
 | |
|   this.setStyleChain = function setStyleChain(newStyleChain) {
 | |
|     styleChain = newStyleChain;
 | |
|     data = {};
 | |
|   };
 | |
|   this.marginTop = function() {
 | |
|     return (value("marginTop")) || 0;
 | |
|   };
 | |
| };
 | |
| odf.TextProperties = function(element, styleParseUtils, parent) {
 | |
|   var self = this, fons = odf.Namespaces.fons, getter;
 | |
|   getter = {fontSize:function() {
 | |
|     var a = element.getAttributeNS(fons, "font-size"), value = styleParseUtils.parsePositiveLengthOrPercent(a, "fontSize", parent && parent.data);
 | |
|     return value;
 | |
|   }};
 | |
|   this.fontSize = function() {
 | |
|     return (self.data.value("fontSize"));
 | |
|   };
 | |
|   this.data;
 | |
|   function init() {
 | |
|     var p = parent === undefined ? undefined : parent.data;
 | |
|     self.data = new odf.LazyStyleProperties(p, getter);
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.ComputedTextProperties = function() {
 | |
|   var data = {}, styleChain = [];
 | |
|   function value(name) {
 | |
|     var v, i;
 | |
|     if (data.hasOwnProperty(name)) {
 | |
|       v = data[name];
 | |
|     } else {
 | |
|       for (i = 0;v === undefined && i < styleChain.length;i += 1) {
 | |
|         v = (styleChain[i][name])();
 | |
|       }
 | |
|       data[name] = v;
 | |
|     }
 | |
|     return v;
 | |
|   }
 | |
|   this.setStyleChain = function setStyleChain(newStyleChain) {
 | |
|     styleChain = newStyleChain;
 | |
|     data = {};
 | |
|   };
 | |
|   this.fontSize = function() {
 | |
|     return (value("fontSize")) || 12;
 | |
|   };
 | |
| };
 | |
| odf.MasterPage = function(element, pageLayoutCache) {
 | |
|   var self = this;
 | |
|   this.pageLayout;
 | |
|   function init() {
 | |
|     var pageLayoutName;
 | |
|     if (element) {
 | |
|       pageLayoutName = element.getAttributeNS(odf.Namespaces.stylens, "page-layout-name");
 | |
|       self.pageLayout = pageLayoutCache.getPageLayout(pageLayoutName);
 | |
|     } else {
 | |
|       self.pageLayout = pageLayoutCache.getDefaultPageLayout();
 | |
|     }
 | |
|   }
 | |
|   init();
 | |
| };
 | |
| odf.MasterPageCache = function() {
 | |
| };
 | |
| odf.MasterPageCache.prototype.getMasterPage = function(name) {
 | |
| };
 | |
| odf.StylePileEntry = function(element, styleParseUtils, masterPageCache, parent) {
 | |
|   this.text;
 | |
|   this.paragraph;
 | |
|   this.graphic;
 | |
|   this.masterPage = function() {
 | |
|     var masterPageName = element.getAttributeNS(odf.Namespaces.stylens, "master-page-name"), masterPage = null;
 | |
|     if (masterPageName) {
 | |
|       masterPage = masterPageCache.getMasterPage(masterPageName);
 | |
|     }
 | |
|     return masterPage;
 | |
|   };
 | |
|   function init(self) {
 | |
|     var stylens = odf.Namespaces.stylens, family = element.getAttributeNS(stylens, "family"), e = null;
 | |
|     if (family === "graphic" || family === "chart") {
 | |
|       self.graphic = parent === undefined ? undefined : parent.graphic;
 | |
|       e = styleParseUtils.getPropertiesElement("graphic-properties", element, e);
 | |
|       if (e !== null) {
 | |
|         self.graphic = new odf.GraphicProperties(e, styleParseUtils, self.graphic);
 | |
|       }
 | |
|     }
 | |
|     if (family === "paragraph" || family === "table-cell" || family === "graphic" || family === "presentation" || family === "chart") {
 | |
|       self.paragraph = parent === undefined ? undefined : parent.paragraph;
 | |
|       e = styleParseUtils.getPropertiesElement("paragraph-properties", element, e);
 | |
|       if (e !== null) {
 | |
|         self.paragraph = new odf.ParagraphProperties(e, styleParseUtils, self.paragraph);
 | |
|       }
 | |
|     }
 | |
|     if (family === "text" || family === "paragraph" || family === "table-cell" || family === "graphic" || family === "presentation" || family === "chart") {
 | |
|       self.text = parent === undefined ? undefined : parent.text;
 | |
|       e = styleParseUtils.getPropertiesElement("text-properties", element, e);
 | |
|       if (e !== null) {
 | |
|         self.text = new odf.TextProperties(e, styleParseUtils, self.text);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   init(this);
 | |
| };
 | |
| odf.StylePile = function(styleParseUtils, masterPageCache) {
 | |
|   var stylens = odf.Namespaces.stylens, commonStyles = {}, automaticStyles = {}, defaultStyle, parsedCommonStyles = {}, parsedAutomaticStyles = {}, getCommonStyle;
 | |
|   function parseStyle(element, visitedStyles) {
 | |
|     var parent, parentName, style;
 | |
|     if (element.hasAttributeNS(stylens, "parent-style-name")) {
 | |
|       parentName = element.getAttributeNS(stylens, "parent-style-name");
 | |
|       if (visitedStyles.indexOf(parentName) === -1) {
 | |
|         parent = getCommonStyle(parentName, visitedStyles);
 | |
|       }
 | |
|     }
 | |
|     style = new odf.StylePileEntry(element, styleParseUtils, masterPageCache, parent);
 | |
|     return style;
 | |
|   }
 | |
|   getCommonStyle = function(styleName, visitedStyles) {
 | |
|     var style = parsedCommonStyles[styleName], element;
 | |
|     if (!style) {
 | |
|       element = commonStyles[styleName];
 | |
|       if (element) {
 | |
|         visitedStyles.push(styleName);
 | |
|         style = parseStyle(element, visitedStyles);
 | |
|         parsedCommonStyles[styleName] = style;
 | |
|       }
 | |
|     }
 | |
|     return style;
 | |
|   };
 | |
|   function getStyle(styleName) {
 | |
|     var style = parsedAutomaticStyles[styleName] || parsedCommonStyles[styleName], element, visitedStyles = [];
 | |
|     if (!style) {
 | |
|       element = automaticStyles[styleName];
 | |
|       if (!element) {
 | |
|         element = commonStyles[styleName];
 | |
|         if (element) {
 | |
|           visitedStyles.push(styleName);
 | |
|         }
 | |
|       }
 | |
|       if (element) {
 | |
|         style = parseStyle(element, visitedStyles);
 | |
|       }
 | |
|     }
 | |
|     return style;
 | |
|   }
 | |
|   this.getStyle = getStyle;
 | |
|   this.addCommonStyle = function(style) {
 | |
|     var name;
 | |
|     if (style.hasAttributeNS(stylens, "name")) {
 | |
|       name = style.getAttributeNS(stylens, "name");
 | |
|       if (!commonStyles.hasOwnProperty(name)) {
 | |
|         commonStyles[name] = style;
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   this.addAutomaticStyle = function(style) {
 | |
|     var name;
 | |
|     if (style.hasAttributeNS(stylens, "name")) {
 | |
|       name = style.getAttributeNS(stylens, "name");
 | |
|       if (!automaticStyles.hasOwnProperty(name)) {
 | |
|         automaticStyles[name] = style;
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   this.setDefaultStyle = function(style) {
 | |
|     if (defaultStyle === undefined) {
 | |
|       defaultStyle = parseStyle(style, []);
 | |
|     }
 | |
|   };
 | |
|   this.getDefaultStyle = function() {
 | |
|     return defaultStyle;
 | |
|   };
 | |
| };
 | |
| odf.ComputedGraphicStyle = function() {
 | |
|   this.text = new odf.ComputedTextProperties;
 | |
|   this.paragraph = new odf.ComputedParagraphProperties;
 | |
|   this.graphic = new odf.ComputedGraphicProperties;
 | |
| };
 | |
| odf.ComputedParagraphStyle = function() {
 | |
|   this.text = new odf.ComputedTextProperties;
 | |
|   this.paragraph = new odf.ComputedParagraphProperties;
 | |
| };
 | |
| odf.ComputedTextStyle = function() {
 | |
|   this.text = new odf.ComputedTextProperties;
 | |
| };
 | |
| odf.StyleCache = function(odfroot) {
 | |
|   var self = this, stylePiles, textStyleCache, paragraphStyleCache, graphicStyleCache, textStylePile, paragraphStylePile, graphicStylePile, textns = odf.Namespaces.textns, stylens = odf.Namespaces.stylens, styleInfo = new odf.StyleInfo, styleParseUtils = new odf.StyleParseUtils, masterPages, parsedMasterPages, defaultMasterPage, defaultPageLayout, pageLayouts, parsedPageLayouts;
 | |
|   function appendClassNames(family, ns, element, chain) {
 | |
|     var names = element.getAttributeNS(ns, "class-names"), stylename, i;
 | |
|     if (names) {
 | |
|       names = names.split(" ");
 | |
|       for (i = 0;i < names.length;i += 1) {
 | |
|         stylename = names[i];
 | |
|         if (stylename) {
 | |
|           chain.push(family);
 | |
|           chain.push(stylename);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function getGraphicStyleChain(element, chain) {
 | |
|     var stylename = styleInfo.getStyleName("graphic", element);
 | |
|     if (stylename !== undefined) {
 | |
|       chain.push("graphic");
 | |
|       chain.push(stylename);
 | |
|     }
 | |
|     return chain;
 | |
|   }
 | |
|   function getParagraphStyleChain(element, chain) {
 | |
|     var stylename = styleInfo.getStyleName("paragraph", element);
 | |
|     if (stylename !== undefined) {
 | |
|       chain.push("paragraph");
 | |
|       chain.push(stylename);
 | |
|     }
 | |
|     if (element.namespaceURI === textns && (element.localName === "h" || element.localName === "p")) {
 | |
|       appendClassNames("paragraph", textns, element, chain);
 | |
|     }
 | |
|     return chain;
 | |
|   }
 | |
|   function createPropertiesChain(styleChain, propertiesName, defaultFamily) {
 | |
|     var chain = [], i, lastProperties, family, styleName, pile, style, properties;
 | |
|     for (i = 0;i < styleChain.length;i += 2) {
 | |
|       family = styleChain[i];
 | |
|       styleName = styleChain[i + 1];
 | |
|       pile = (stylePiles[family]);
 | |
|       style = pile.getStyle(styleName);
 | |
|       if (style !== undefined) {
 | |
|         properties = (style[propertiesName]);
 | |
|         if (properties !== undefined && properties !== lastProperties) {
 | |
|           chain.push(properties);
 | |
|           lastProperties = properties;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     pile = (stylePiles[defaultFamily]);
 | |
|     style = pile.getDefaultStyle();
 | |
|     if (style) {
 | |
|       properties = (style[propertiesName]);
 | |
|       if (properties !== undefined && properties !== lastProperties) {
 | |
|         chain.push(properties);
 | |
|       }
 | |
|     }
 | |
|     return chain;
 | |
|   }
 | |
|   this.getComputedGraphicStyle = function(element) {
 | |
|     var styleChain = getGraphicStyleChain(element, []), key = styleChain.join("/"), computedStyle = graphicStyleCache[key];
 | |
|     runtime.assert(styleChain.length % 2 === 0, "Invalid style chain.");
 | |
|     if (computedStyle === undefined) {
 | |
|       computedStyle = new odf.ComputedGraphicStyle;
 | |
|       computedStyle.graphic.setGraphicProperties((createPropertiesChain(styleChain, "graphic", "graphic")[0]));
 | |
|       computedStyle.text.setStyleChain((createPropertiesChain(styleChain, "text", "graphic")));
 | |
|       computedStyle.paragraph.setStyleChain((createPropertiesChain(styleChain, "paragraph", "graphic")));
 | |
|       graphicStyleCache[key] = computedStyle;
 | |
|     }
 | |
|     return computedStyle;
 | |
|   };
 | |
|   this.getComputedParagraphStyle = function(element) {
 | |
|     var styleChain = getParagraphStyleChain(element, []), key = styleChain.join("/"), computedStyle = paragraphStyleCache[key];
 | |
|     runtime.assert(styleChain.length % 2 === 0, "Invalid style chain.");
 | |
|     if (computedStyle === undefined) {
 | |
|       computedStyle = new odf.ComputedParagraphStyle;
 | |
|       computedStyle.text.setStyleChain((createPropertiesChain(styleChain, "text", "paragraph")));
 | |
|       computedStyle.paragraph.setStyleChain((createPropertiesChain(styleChain, "paragraph", "paragraph")));
 | |
|       paragraphStyleCache[key] = computedStyle;
 | |
|     }
 | |
|     return computedStyle;
 | |
|   };
 | |
|   function getTextStyleChain(element, chain) {
 | |
|     var stylename = styleInfo.getStyleName("text", element), parent = (element.parentNode);
 | |
|     if (stylename !== undefined) {
 | |
|       chain.push("text");
 | |
|       chain.push(stylename);
 | |
|     }
 | |
|     if (element.localName === "span" && element.namespaceURI === textns) {
 | |
|       appendClassNames("text", textns, element, chain);
 | |
|     }
 | |
|     if (!parent || parent === odfroot) {
 | |
|       return chain;
 | |
|     }
 | |
|     if (parent.namespaceURI === textns && (parent.localName === "p" || parent.localName === "h")) {
 | |
|       getParagraphStyleChain(parent, chain);
 | |
|     } else {
 | |
|       getTextStyleChain(parent, chain);
 | |
|     }
 | |
|     return chain;
 | |
|   }
 | |
|   this.getComputedTextStyle = function(element) {
 | |
|     var styleChain = getTextStyleChain(element, []), key = styleChain.join("/"), computedStyle = textStyleCache[key];
 | |
|     runtime.assert(styleChain.length % 2 === 0, "Invalid style chain.");
 | |
|     if (computedStyle === undefined) {
 | |
|       computedStyle = new odf.ComputedTextStyle;
 | |
|       computedStyle.text.setStyleChain((createPropertiesChain(styleChain, "text", "text")));
 | |
|       textStyleCache[key] = computedStyle;
 | |
|     }
 | |
|     return computedStyle;
 | |
|   };
 | |
|   function getPileFromElement(element) {
 | |
|     var family = element.getAttributeNS(stylens, "family");
 | |
|     return stylePiles[family];
 | |
|   }
 | |
|   function addMasterPage(element) {
 | |
|     var name = element.getAttributeNS(stylens, "name");
 | |
|     if (name.length > 0 && !masterPages.hasOwnProperty(name)) {
 | |
|       masterPages[name] = element;
 | |
|     }
 | |
|   }
 | |
|   function getPageLayout(name) {
 | |
|     var pageLayout = parsedPageLayouts[name], e;
 | |
|     if (!pageLayout) {
 | |
|       e = pageLayouts[name];
 | |
|       if (e) {
 | |
|         pageLayout = new odf.PageLayout(e, styleParseUtils, defaultPageLayout);
 | |
|         parsedPageLayouts[name] = pageLayout;
 | |
|       } else {
 | |
|         pageLayout = defaultPageLayout;
 | |
|       }
 | |
|     }
 | |
|     return pageLayout;
 | |
|   }
 | |
|   this.getPageLayout = getPageLayout;
 | |
|   this.getDefaultPageLayout = function() {
 | |
|     return defaultPageLayout;
 | |
|   };
 | |
|   function getMasterPage(name) {
 | |
|     var masterPage = parsedMasterPages[name], element;
 | |
|     if (masterPage === undefined) {
 | |
|       element = masterPages[name];
 | |
|       if (element) {
 | |
|         masterPage = new odf.MasterPage(element, self);
 | |
|         parsedMasterPages[name] = masterPage;
 | |
|       } else {
 | |
|         masterPage = null;
 | |
|       }
 | |
|     }
 | |
|     return masterPage;
 | |
|   }
 | |
|   this.getMasterPage = getMasterPage;
 | |
|   this.getDefaultMasterPage = function() {
 | |
|     return defaultMasterPage;
 | |
|   };
 | |
|   function update() {
 | |
|     var e, pile, defaultPageLayoutElement = null, defaultMasterPageElement = null;
 | |
|     textStyleCache = {};
 | |
|     paragraphStyleCache = {};
 | |
|     graphicStyleCache = {};
 | |
|     masterPages = {};
 | |
|     parsedMasterPages = {};
 | |
|     parsedPageLayouts = {};
 | |
|     pageLayouts = {};
 | |
|     textStylePile = new odf.StylePile(styleParseUtils, self);
 | |
|     paragraphStylePile = new odf.StylePile(styleParseUtils, self);
 | |
|     graphicStylePile = new odf.StylePile(styleParseUtils, self);
 | |
|     stylePiles = {text:textStylePile, paragraph:paragraphStylePile, graphic:graphicStylePile};
 | |
|     e = odfroot.styles.firstElementChild;
 | |
|     while (e) {
 | |
|       if (e.namespaceURI === stylens) {
 | |
|         pile = getPileFromElement(e);
 | |
|         if (pile) {
 | |
|           if (e.localName === "style") {
 | |
|             pile.addCommonStyle(e);
 | |
|           } else {
 | |
|             if (e.localName === "default-style") {
 | |
|               pile.setDefaultStyle(e);
 | |
|             }
 | |
|           }
 | |
|         } else {
 | |
|           if (e.localName === "default-page-layout") {
 | |
|             defaultPageLayoutElement = e;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|     defaultPageLayout = new odf.PageLayout(defaultPageLayoutElement, styleParseUtils);
 | |
|     e = odfroot.automaticStyles.firstElementChild;
 | |
|     while (e) {
 | |
|       if (e.namespaceURI === stylens) {
 | |
|         pile = getPileFromElement(e);
 | |
|         if (pile && e.localName === "style") {
 | |
|           pile.addAutomaticStyle(e);
 | |
|         } else {
 | |
|           if (e.localName === "page-layout") {
 | |
|             pageLayouts[e.getAttributeNS(stylens, "name")] = e;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|     e = odfroot.masterStyles.firstElementChild;
 | |
|     while (e) {
 | |
|       if (e.namespaceURI === stylens && e.localName === "master-page") {
 | |
|         defaultMasterPageElement = defaultMasterPageElement || e;
 | |
|         addMasterPage(e);
 | |
|       }
 | |
|       e = e.nextElementSibling;
 | |
|     }
 | |
|     defaultMasterPage = new odf.MasterPage(defaultMasterPageElement, self);
 | |
|   }
 | |
|   this.update = update;
 | |
| };
 | |
| ops.OperationTransformMatrix = function OperationTransformMatrix() {
 | |
|   function invertMoveCursorSpecRange(moveCursorSpec) {
 | |
|     moveCursorSpec.position = moveCursorSpec.position + moveCursorSpec.length;
 | |
|     moveCursorSpec.length *= -1;
 | |
|   }
 | |
|   function invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec) {
 | |
|     var isBackwards = moveCursorSpec.length < 0;
 | |
|     if (isBackwards) {
 | |
|       invertMoveCursorSpecRange(moveCursorSpec);
 | |
|     }
 | |
|     return isBackwards;
 | |
|   }
 | |
|   function getStyleReferencingAttributes(setProperties, styleName) {
 | |
|     var attributes = [];
 | |
|     function check(attributeName) {
 | |
|       if (setProperties[attributeName] === styleName) {
 | |
|         attributes.push(attributeName);
 | |
|       }
 | |
|     }
 | |
|     if (setProperties) {
 | |
|       ["style:parent-style-name", "style:next-style-name"].forEach(check);
 | |
|     }
 | |
|     return attributes;
 | |
|   }
 | |
|   function dropStyleReferencingAttributes(setProperties, deletedStyleName) {
 | |
|     function del(attributeName) {
 | |
|       if (setProperties[attributeName] === deletedStyleName) {
 | |
|         delete setProperties[attributeName];
 | |
|       }
 | |
|     }
 | |
|     if (setProperties) {
 | |
|       ["style:parent-style-name", "style:next-style-name"].forEach(del);
 | |
|     }
 | |
|   }
 | |
|   function cloneOpspec(opspec) {
 | |
|     var result = {};
 | |
|     Object.keys(opspec).forEach(function(key) {
 | |
|       if (typeof opspec[key] === "object") {
 | |
|         result[key] = cloneOpspec(opspec[key]);
 | |
|       } else {
 | |
|         result[key] = opspec[key];
 | |
|       }
 | |
|     });
 | |
|     return result;
 | |
|   }
 | |
|   function dropOverruledAndUnneededAttributes(minorSetProperties, minorRemovedProperties, majorSetProperties, majorRemovedProperties) {
 | |
|     var i, name, majorChanged = false, minorChanged = false, removedPropertyNames, majorRemovedPropertyNames = [];
 | |
|     if (majorRemovedProperties && majorRemovedProperties.attributes) {
 | |
|       majorRemovedPropertyNames = majorRemovedProperties.attributes.split(",");
 | |
|     }
 | |
|     if (minorSetProperties && (majorSetProperties || majorRemovedPropertyNames.length > 0)) {
 | |
|       Object.keys(minorSetProperties).forEach(function(key) {
 | |
|         var value = minorSetProperties[key], overrulingPropertyValue;
 | |
|         if (typeof value !== "object") {
 | |
|           if (majorSetProperties) {
 | |
|             overrulingPropertyValue = majorSetProperties[key];
 | |
|           }
 | |
|           if (overrulingPropertyValue !== undefined) {
 | |
|             delete minorSetProperties[key];
 | |
|             minorChanged = true;
 | |
|             if (overrulingPropertyValue === value) {
 | |
|               delete majorSetProperties[key];
 | |
|               majorChanged = true;
 | |
|             }
 | |
|           } else {
 | |
|             if (majorRemovedPropertyNames.indexOf(key) !== -1) {
 | |
|               delete minorSetProperties[key];
 | |
|               minorChanged = true;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     if (minorRemovedProperties && minorRemovedProperties.attributes && (majorSetProperties || majorRemovedPropertyNames.length > 0)) {
 | |
|       removedPropertyNames = minorRemovedProperties.attributes.split(",");
 | |
|       for (i = 0;i < removedPropertyNames.length;i += 1) {
 | |
|         name = removedPropertyNames[i];
 | |
|         if (majorSetProperties && majorSetProperties[name] !== undefined || majorRemovedPropertyNames && majorRemovedPropertyNames.indexOf(name) !== -1) {
 | |
|           removedPropertyNames.splice(i, 1);
 | |
|           i -= 1;
 | |
|           minorChanged = true;
 | |
|         }
 | |
|       }
 | |
|       if (removedPropertyNames.length > 0) {
 | |
|         minorRemovedProperties.attributes = removedPropertyNames.join(",");
 | |
|       } else {
 | |
|         delete minorRemovedProperties.attributes;
 | |
|       }
 | |
|     }
 | |
|     return {majorChanged:majorChanged, minorChanged:minorChanged};
 | |
|   }
 | |
|   function hasProperties(properties) {
 | |
|     var key;
 | |
|     for (key in properties) {
 | |
|       if (properties.hasOwnProperty(key)) {
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function hasRemovedProperties(properties) {
 | |
|     var key;
 | |
|     for (key in properties) {
 | |
|       if (properties.hasOwnProperty(key)) {
 | |
|         if (key !== "attributes" || properties.attributes.length > 0) {
 | |
|           return true;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   function dropOverruledAndUnneededProperties(minorSet, minorRem, majorSet, majorRem, propertiesName) {
 | |
|     var minorSP = (minorSet ? minorSet[propertiesName] : null), minorRP = minorRem ? minorRem[propertiesName] : null, majorSP = (majorSet ? majorSet[propertiesName] : null), majorRP = majorRem ? majorRem[propertiesName] : null, result;
 | |
|     result = dropOverruledAndUnneededAttributes(minorSP, minorRP, majorSP, majorRP);
 | |
|     if (minorSP && !hasProperties(minorSP)) {
 | |
|       delete minorSet[propertiesName];
 | |
|     }
 | |
|     if (minorRP && !hasRemovedProperties(minorRP)) {
 | |
|       delete minorRem[propertiesName];
 | |
|     }
 | |
|     if (majorSP && !hasProperties(majorSP)) {
 | |
|       delete majorSet[propertiesName];
 | |
|     }
 | |
|     if (majorRP && !hasRemovedProperties(majorRP)) {
 | |
|       delete majorRem[propertiesName];
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
|   function transformAddAnnotationAddAnnotation(addAnnotationSpecA, addAnnotationSpecB, hasAPriority) {
 | |
|     var firstAnnotationSpec, secondAnnotationSpec;
 | |
|     if (addAnnotationSpecA.position < addAnnotationSpecB.position) {
 | |
|       firstAnnotationSpec = addAnnotationSpecA;
 | |
|       secondAnnotationSpec = addAnnotationSpecB;
 | |
|     } else {
 | |
|       if (addAnnotationSpecB.position < addAnnotationSpecA.position) {
 | |
|         firstAnnotationSpec = addAnnotationSpecB;
 | |
|         secondAnnotationSpec = addAnnotationSpecA;
 | |
|       } else {
 | |
|         firstAnnotationSpec = hasAPriority ? addAnnotationSpecA : addAnnotationSpecB;
 | |
|         secondAnnotationSpec = hasAPriority ? addAnnotationSpecB : addAnnotationSpecA;
 | |
|       }
 | |
|     }
 | |
|     if (secondAnnotationSpec.position < firstAnnotationSpec.position + firstAnnotationSpec.length) {
 | |
|       firstAnnotationSpec.length += 2;
 | |
|     }
 | |
|     secondAnnotationSpec.position += 2;
 | |
|     return {opSpecsA:[addAnnotationSpecA], opSpecsB:[addAnnotationSpecB]};
 | |
|   }
 | |
|   function transformAddAnnotationApplyDirectStyling(addAnnotationSpec, applyDirectStylingSpec) {
 | |
|     if (addAnnotationSpec.position <= applyDirectStylingSpec.position) {
 | |
|       applyDirectStylingSpec.position += 2;
 | |
|     } else {
 | |
|       if (addAnnotationSpec.position <= applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
 | |
|         applyDirectStylingSpec.length += 2;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[applyDirectStylingSpec]};
 | |
|   }
 | |
|   function transformAddAnnotationInsertText(addAnnotationSpec, insertTextSpec) {
 | |
|     if (insertTextSpec.position <= addAnnotationSpec.position) {
 | |
|       addAnnotationSpec.position += insertTextSpec.text.length;
 | |
|     } else {
 | |
|       if (addAnnotationSpec.length !== undefined) {
 | |
|         if (insertTextSpec.position <= addAnnotationSpec.position + addAnnotationSpec.length) {
 | |
|           addAnnotationSpec.length += insertTextSpec.text.length;
 | |
|         }
 | |
|       }
 | |
|       insertTextSpec.position += 2;
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[insertTextSpec]};
 | |
|   }
 | |
|   function transformAddAnnotationMergeParagraph(addAnnotationSpec, mergeParagraphSpec) {
 | |
|     if (mergeParagraphSpec.sourceStartPosition <= addAnnotationSpec.position) {
 | |
|       addAnnotationSpec.position -= 1;
 | |
|     } else {
 | |
|       if (addAnnotationSpec.length !== undefined) {
 | |
|         if (mergeParagraphSpec.sourceStartPosition <= addAnnotationSpec.position + addAnnotationSpec.length) {
 | |
|           addAnnotationSpec.length -= 1;
 | |
|         }
 | |
|       }
 | |
|       mergeParagraphSpec.sourceStartPosition += 2;
 | |
|       if (addAnnotationSpec.position < mergeParagraphSpec.destinationStartPosition) {
 | |
|         mergeParagraphSpec.destinationStartPosition += 2;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[mergeParagraphSpec]};
 | |
|   }
 | |
|   function transformAddAnnotationMoveCursor(addAnnotationSpec, moveCursorSpec) {
 | |
|     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
 | |
|     if (addAnnotationSpec.position < moveCursorSpec.position) {
 | |
|       moveCursorSpec.position += 2;
 | |
|     } else {
 | |
|       if (addAnnotationSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
 | |
|         moveCursorSpec.length += 2;
 | |
|       }
 | |
|     }
 | |
|     if (isMoveCursorSpecRangeInverted) {
 | |
|       invertMoveCursorSpecRange(moveCursorSpec);
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[moveCursorSpec]};
 | |
|   }
 | |
|   function transformAddAnnotationRemoveAnnotation(addAnnotationSpec, removeAnnotationSpec) {
 | |
|     if (addAnnotationSpec.position < removeAnnotationSpec.position) {
 | |
|       if (removeAnnotationSpec.position < addAnnotationSpec.position + addAnnotationSpec.length) {
 | |
|         addAnnotationSpec.length -= removeAnnotationSpec.length + 2;
 | |
|       }
 | |
|       removeAnnotationSpec.position += 2;
 | |
|     } else {
 | |
|       addAnnotationSpec.position -= removeAnnotationSpec.length + 2;
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[removeAnnotationSpec]};
 | |
|   }
 | |
|   function transformAddAnnotationRemoveText(addAnnotationSpec, removeTextSpec) {
 | |
|     var removeTextSpecPosition = removeTextSpec.position, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, annotationSpecEnd, helperOpspec, addAnnotationSpecResult = [addAnnotationSpec], removeTextSpecResult = [removeTextSpec];
 | |
|     if (addAnnotationSpec.position <= removeTextSpec.position) {
 | |
|       removeTextSpec.position += 2;
 | |
|     } else {
 | |
|       if (addAnnotationSpec.position < removeTextSpecEnd) {
 | |
|         removeTextSpec.length = addAnnotationSpec.position - removeTextSpec.position;
 | |
|         helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:addAnnotationSpec.position + 2, length:removeTextSpecEnd - addAnnotationSpec.position};
 | |
|         removeTextSpecResult.unshift(helperOpspec);
 | |
|       }
 | |
|     }
 | |
|     if (removeTextSpec.position + removeTextSpec.length <= addAnnotationSpec.position) {
 | |
|       addAnnotationSpec.position -= removeTextSpec.length;
 | |
|       if (addAnnotationSpec.length !== undefined && helperOpspec) {
 | |
|         if (helperOpspec.length >= addAnnotationSpec.length) {
 | |
|           addAnnotationSpec.length = 0;
 | |
|         } else {
 | |
|           addAnnotationSpec.length -= helperOpspec.length;
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       if (addAnnotationSpec.length !== undefined) {
 | |
|         annotationSpecEnd = addAnnotationSpec.position + addAnnotationSpec.length;
 | |
|         if (removeTextSpecEnd <= annotationSpecEnd) {
 | |
|           addAnnotationSpec.length -= removeTextSpec.length;
 | |
|         } else {
 | |
|           if (removeTextSpecPosition < annotationSpecEnd) {
 | |
|             addAnnotationSpec.length = removeTextSpecPosition - addAnnotationSpec.position;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:addAnnotationSpecResult, opSpecsB:removeTextSpecResult};
 | |
|   }
 | |
|   function transformAddAnnotationSetParagraphStyle(addAnnotationSpec, setParagraphStyleSpec) {
 | |
|     if (addAnnotationSpec.position < setParagraphStyleSpec.position) {
 | |
|       setParagraphStyleSpec.position += 2;
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[setParagraphStyleSpec]};
 | |
|   }
 | |
|   function transformAddAnnotationSplitParagraph(addAnnotationSpec, splitParagraphSpec) {
 | |
|     if (addAnnotationSpec.position < splitParagraphSpec.sourceParagraphPosition) {
 | |
|       splitParagraphSpec.sourceParagraphPosition += 2;
 | |
|     }
 | |
|     if (splitParagraphSpec.position <= addAnnotationSpec.position) {
 | |
|       addAnnotationSpec.position += 1;
 | |
|     } else {
 | |
|       if (addAnnotationSpec.length !== undefined) {
 | |
|         if (splitParagraphSpec.position <= addAnnotationSpec.position + addAnnotationSpec.length) {
 | |
|           addAnnotationSpec.length += 1;
 | |
|         }
 | |
|       }
 | |
|       splitParagraphSpec.position += 2;
 | |
|     }
 | |
|     return {opSpecsA:[addAnnotationSpec], opSpecsB:[splitParagraphSpec]};
 | |
|   }
 | |
|   function transformAddStyleRemoveStyle(addStyleSpec, removeStyleSpec) {
 | |
|     var setAttributes, helperOpspec, addStyleSpecResult = [addStyleSpec], removeStyleSpecResult = [removeStyleSpec];
 | |
|     if (addStyleSpec.styleFamily === removeStyleSpec.styleFamily) {
 | |
|       setAttributes = getStyleReferencingAttributes(addStyleSpec.setProperties, removeStyleSpec.styleName);
 | |
|       if (setAttributes.length > 0) {
 | |
|         helperOpspec = {optype:"UpdateParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, styleName:addStyleSpec.styleName, removedProperties:{attributes:setAttributes.join(",")}};
 | |
|         removeStyleSpecResult.unshift(helperOpspec);
 | |
|       }
 | |
|       dropStyleReferencingAttributes(addStyleSpec.setProperties, removeStyleSpec.styleName);
 | |
|     }
 | |
|     return {opSpecsA:addStyleSpecResult, opSpecsB:removeStyleSpecResult};
 | |
|   }
 | |
|   function transformApplyDirectStylingApplyDirectStyling(applyDirectStylingSpecA, applyDirectStylingSpecB, hasAPriority) {
 | |
|     var majorSpec, minorSpec, majorSpecResult, minorSpecResult, majorSpecEnd, minorSpecEnd, dropResult, originalMajorSpec, originalMinorSpec, helperOpspecBefore, helperOpspecAfter, applyDirectStylingSpecAResult = [applyDirectStylingSpecA], applyDirectStylingSpecBResult = [applyDirectStylingSpecB];
 | |
|     if (!(applyDirectStylingSpecA.position + applyDirectStylingSpecA.length <= applyDirectStylingSpecB.position || applyDirectStylingSpecA.position >= applyDirectStylingSpecB.position + applyDirectStylingSpecB.length)) {
 | |
|       majorSpec = hasAPriority ? applyDirectStylingSpecA : applyDirectStylingSpecB;
 | |
|       minorSpec = hasAPriority ? applyDirectStylingSpecB : applyDirectStylingSpecA;
 | |
|       if (applyDirectStylingSpecA.position !== applyDirectStylingSpecB.position || applyDirectStylingSpecA.length !== applyDirectStylingSpecB.length) {
 | |
|         originalMajorSpec = cloneOpspec(majorSpec);
 | |
|         originalMinorSpec = cloneOpspec(minorSpec);
 | |
|       }
 | |
|       dropResult = dropOverruledAndUnneededProperties(minorSpec.setProperties, null, majorSpec.setProperties, null, "style:text-properties");
 | |
|       if (dropResult.majorChanged || dropResult.minorChanged) {
 | |
|         majorSpecResult = [];
 | |
|         minorSpecResult = [];
 | |
|         majorSpecEnd = majorSpec.position + majorSpec.length;
 | |
|         minorSpecEnd = minorSpec.position + minorSpec.length;
 | |
|         if (minorSpec.position < majorSpec.position) {
 | |
|           if (dropResult.minorChanged) {
 | |
|             helperOpspecBefore = cloneOpspec((originalMinorSpec));
 | |
|             helperOpspecBefore.length = majorSpec.position - minorSpec.position;
 | |
|             minorSpecResult.push(helperOpspecBefore);
 | |
|             minorSpec.position = majorSpec.position;
 | |
|             minorSpec.length = minorSpecEnd - minorSpec.position;
 | |
|           }
 | |
|         } else {
 | |
|           if (majorSpec.position < minorSpec.position) {
 | |
|             if (dropResult.majorChanged) {
 | |
|               helperOpspecBefore = cloneOpspec((originalMajorSpec));
 | |
|               helperOpspecBefore.length = minorSpec.position - majorSpec.position;
 | |
|               majorSpecResult.push(helperOpspecBefore);
 | |
|               majorSpec.position = minorSpec.position;
 | |
|               majorSpec.length = majorSpecEnd - majorSpec.position;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         if (minorSpecEnd > majorSpecEnd) {
 | |
|           if (dropResult.minorChanged) {
 | |
|             helperOpspecAfter = originalMinorSpec;
 | |
|             helperOpspecAfter.position = majorSpecEnd;
 | |
|             helperOpspecAfter.length = minorSpecEnd - majorSpecEnd;
 | |
|             minorSpecResult.push(helperOpspecAfter);
 | |
|             minorSpec.length = majorSpecEnd - minorSpec.position;
 | |
|           }
 | |
|         } else {
 | |
|           if (majorSpecEnd > minorSpecEnd) {
 | |
|             if (dropResult.majorChanged) {
 | |
|               helperOpspecAfter = originalMajorSpec;
 | |
|               helperOpspecAfter.position = minorSpecEnd;
 | |
|               helperOpspecAfter.length = majorSpecEnd - minorSpecEnd;
 | |
|               majorSpecResult.push(helperOpspecAfter);
 | |
|               majorSpec.length = minorSpecEnd - majorSpec.position;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         if (majorSpec.setProperties && hasProperties(majorSpec.setProperties)) {
 | |
|           majorSpecResult.push(majorSpec);
 | |
|         }
 | |
|         if (minorSpec.setProperties && hasProperties(minorSpec.setProperties)) {
 | |
|           minorSpecResult.push(minorSpec);
 | |
|         }
 | |
|         if (hasAPriority) {
 | |
|           applyDirectStylingSpecAResult = majorSpecResult;
 | |
|           applyDirectStylingSpecBResult = minorSpecResult;
 | |
|         } else {
 | |
|           applyDirectStylingSpecAResult = minorSpecResult;
 | |
|           applyDirectStylingSpecBResult = majorSpecResult;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:applyDirectStylingSpecAResult, opSpecsB:applyDirectStylingSpecBResult};
 | |
|   }
 | |
|   function transformApplyDirectStylingInsertText(applyDirectStylingSpec, insertTextSpec) {
 | |
|     if (insertTextSpec.position <= applyDirectStylingSpec.position) {
 | |
|       applyDirectStylingSpec.position += insertTextSpec.text.length;
 | |
|     } else {
 | |
|       if (insertTextSpec.position <= applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
 | |
|         applyDirectStylingSpec.length += insertTextSpec.text.length;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[applyDirectStylingSpec], opSpecsB:[insertTextSpec]};
 | |
|   }
 | |
|   function transformApplyDirectStylingMergeParagraph(applyDirectStylingSpec, mergeParagraphSpec) {
 | |
|     var pointA = applyDirectStylingSpec.position, pointB = applyDirectStylingSpec.position + applyDirectStylingSpec.length;
 | |
|     if (pointA >= mergeParagraphSpec.sourceStartPosition) {
 | |
|       pointA -= 1;
 | |
|     }
 | |
|     if (pointB >= mergeParagraphSpec.sourceStartPosition) {
 | |
|       pointB -= 1;
 | |
|     }
 | |
|     applyDirectStylingSpec.position = pointA;
 | |
|     applyDirectStylingSpec.length = pointB - pointA;
 | |
|     return {opSpecsA:[applyDirectStylingSpec], opSpecsB:[mergeParagraphSpec]};
 | |
|   }
 | |
|   function transformApplyDirectStylingRemoveAnnotation(applyDirectStylingSpec, removeAnnotationSpec) {
 | |
|     var pointA = applyDirectStylingSpec.position, pointB = applyDirectStylingSpec.position + applyDirectStylingSpec.length, removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length, applyDirectStylingSpecResult = [applyDirectStylingSpec], removeAnnotationSpecResult = [removeAnnotationSpec];
 | |
|     if (removeAnnotationSpec.position <= pointA && pointB <= removeAnnotationEnd) {
 | |
|       applyDirectStylingSpecResult = [];
 | |
|     } else {
 | |
|       if (removeAnnotationEnd < pointA) {
 | |
|         pointA -= removeAnnotationSpec.length + 2;
 | |
|       }
 | |
|       if (removeAnnotationEnd < pointB) {
 | |
|         pointB -= removeAnnotationSpec.length + 2;
 | |
|       }
 | |
|       applyDirectStylingSpec.position = pointA;
 | |
|       applyDirectStylingSpec.length = pointB - pointA;
 | |
|     }
 | |
|     return {opSpecsA:applyDirectStylingSpecResult, opSpecsB:removeAnnotationSpecResult};
 | |
|   }
 | |
|   function transformApplyDirectStylingRemoveText(applyDirectStylingSpec, removeTextSpec) {
 | |
|     var applyDirectStylingSpecEnd = applyDirectStylingSpec.position + applyDirectStylingSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, applyDirectStylingSpecResult = [applyDirectStylingSpec], removeTextSpecResult = [removeTextSpec];
 | |
|     if (removeTextSpecEnd <= applyDirectStylingSpec.position) {
 | |
|       applyDirectStylingSpec.position -= removeTextSpec.length;
 | |
|     } else {
 | |
|       if (removeTextSpec.position < applyDirectStylingSpecEnd) {
 | |
|         if (applyDirectStylingSpec.position < removeTextSpec.position) {
 | |
|           if (removeTextSpecEnd < applyDirectStylingSpecEnd) {
 | |
|             applyDirectStylingSpec.length -= removeTextSpec.length;
 | |
|           } else {
 | |
|             applyDirectStylingSpec.length = removeTextSpec.position - applyDirectStylingSpec.position;
 | |
|           }
 | |
|         } else {
 | |
|           applyDirectStylingSpec.position = removeTextSpec.position;
 | |
|           if (removeTextSpecEnd < applyDirectStylingSpecEnd) {
 | |
|             applyDirectStylingSpec.length = applyDirectStylingSpecEnd - removeTextSpecEnd;
 | |
|           } else {
 | |
|             applyDirectStylingSpecResult = [];
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:applyDirectStylingSpecResult, opSpecsB:removeTextSpecResult};
 | |
|   }
 | |
|   function transformApplyDirectStylingSplitParagraph(applyDirectStylingSpec, splitParagraphSpec) {
 | |
|     if (splitParagraphSpec.position < applyDirectStylingSpec.position) {
 | |
|       applyDirectStylingSpec.position += 1;
 | |
|     } else {
 | |
|       if (splitParagraphSpec.position < applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
 | |
|         applyDirectStylingSpec.length += 1;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[applyDirectStylingSpec], opSpecsB:[splitParagraphSpec]};
 | |
|   }
 | |
|   function transformInsertTextInsertText(insertTextSpecA, insertTextSpecB, hasAPriority) {
 | |
|     if (insertTextSpecA.position < insertTextSpecB.position) {
 | |
|       insertTextSpecB.position += insertTextSpecA.text.length;
 | |
|     } else {
 | |
|       if (insertTextSpecA.position > insertTextSpecB.position) {
 | |
|         insertTextSpecA.position += insertTextSpecB.text.length;
 | |
|       } else {
 | |
|         if (hasAPriority) {
 | |
|           insertTextSpecB.position += insertTextSpecA.text.length;
 | |
|         } else {
 | |
|           insertTextSpecA.position += insertTextSpecB.text.length;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[insertTextSpecA], opSpecsB:[insertTextSpecB]};
 | |
|   }
 | |
|   function transformInsertTextMergeParagraph(insertTextSpec, mergeParagraphSpec) {
 | |
|     if (insertTextSpec.position >= mergeParagraphSpec.sourceStartPosition) {
 | |
|       insertTextSpec.position -= 1;
 | |
|     } else {
 | |
|       if (insertTextSpec.position < mergeParagraphSpec.sourceStartPosition) {
 | |
|         mergeParagraphSpec.sourceStartPosition += insertTextSpec.text.length;
 | |
|       }
 | |
|       if (insertTextSpec.position < mergeParagraphSpec.destinationStartPosition) {
 | |
|         mergeParagraphSpec.destinationStartPosition += insertTextSpec.text.length;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[insertTextSpec], opSpecsB:[mergeParagraphSpec]};
 | |
|   }
 | |
|   function transformInsertTextMoveCursor(insertTextSpec, moveCursorSpec) {
 | |
|     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
 | |
|     if (insertTextSpec.position < moveCursorSpec.position) {
 | |
|       moveCursorSpec.position += insertTextSpec.text.length;
 | |
|     } else {
 | |
|       if (insertTextSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
 | |
|         moveCursorSpec.length += insertTextSpec.text.length;
 | |
|       }
 | |
|     }
 | |
|     if (isMoveCursorSpecRangeInverted) {
 | |
|       invertMoveCursorSpecRange(moveCursorSpec);
 | |
|     }
 | |
|     return {opSpecsA:[insertTextSpec], opSpecsB:[moveCursorSpec]};
 | |
|   }
 | |
|   function transformInsertTextRemoveAnnotation(insertTextSpec, removeAnnotationSpec) {
 | |
|     var insertTextSpecPosition = insertTextSpec.position, removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length, insertTextSpecResult = [insertTextSpec], removeAnnotationSpecResult = [removeAnnotationSpec];
 | |
|     if (removeAnnotationSpec.position <= insertTextSpecPosition && insertTextSpecPosition <= removeAnnotationEnd) {
 | |
|       insertTextSpecResult = [];
 | |
|       removeAnnotationSpec.length += insertTextSpec.text.length;
 | |
|     } else {
 | |
|       if (removeAnnotationEnd < insertTextSpec.position) {
 | |
|         insertTextSpec.position -= removeAnnotationSpec.length + 2;
 | |
|       } else {
 | |
|         removeAnnotationSpec.position += insertTextSpec.text.length;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:insertTextSpecResult, opSpecsB:removeAnnotationSpecResult};
 | |
|   }
 | |
|   function transformInsertTextRemoveText(insertTextSpec, removeTextSpec) {
 | |
|     var helperOpspec, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, insertTextSpecResult = [insertTextSpec], removeTextSpecResult = [removeTextSpec];
 | |
|     if (removeTextSpecEnd <= insertTextSpec.position) {
 | |
|       insertTextSpec.position -= removeTextSpec.length;
 | |
|     } else {
 | |
|       if (insertTextSpec.position <= removeTextSpec.position) {
 | |
|         removeTextSpec.position += insertTextSpec.text.length;
 | |
|       } else {
 | |
|         removeTextSpec.length = insertTextSpec.position - removeTextSpec.position;
 | |
|         helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:insertTextSpec.position + insertTextSpec.text.length, length:removeTextSpecEnd - insertTextSpec.position};
 | |
|         removeTextSpecResult.unshift(helperOpspec);
 | |
|         insertTextSpec.position = removeTextSpec.position;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:insertTextSpecResult, opSpecsB:removeTextSpecResult};
 | |
|   }
 | |
|   function transformInsertTextSetParagraphStyle(insertTextSpec, setParagraphStyleSpec) {
 | |
|     if (setParagraphStyleSpec.position > insertTextSpec.position) {
 | |
|       setParagraphStyleSpec.position += insertTextSpec.text.length;
 | |
|     }
 | |
|     return {opSpecsA:[insertTextSpec], opSpecsB:[setParagraphStyleSpec]};
 | |
|   }
 | |
|   function transformInsertTextSplitParagraph(insertTextSpec, splitParagraphSpec) {
 | |
|     if (insertTextSpec.position < splitParagraphSpec.sourceParagraphPosition) {
 | |
|       splitParagraphSpec.sourceParagraphPosition += insertTextSpec.text.length;
 | |
|     }
 | |
|     if (insertTextSpec.position <= splitParagraphSpec.position) {
 | |
|       splitParagraphSpec.position += insertTextSpec.text.length;
 | |
|     } else {
 | |
|       insertTextSpec.position += 1;
 | |
|     }
 | |
|     return {opSpecsA:[insertTextSpec], opSpecsB:[splitParagraphSpec]};
 | |
|   }
 | |
|   function transformMergeParagraphMergeParagraph(mergeParagraphSpecA, mergeParagraphSpecB, hasAPriority) {
 | |
|     var specsForB = [mergeParagraphSpecA], specsForA = [mergeParagraphSpecB], priorityOp, styleParagraphFixup, moveCursorA, moveCursorB;
 | |
|     if (mergeParagraphSpecA.destinationStartPosition === mergeParagraphSpecB.destinationStartPosition) {
 | |
|       specsForB = [];
 | |
|       specsForA = [];
 | |
|       if (mergeParagraphSpecA.moveCursor) {
 | |
|         moveCursorA = ({optype:"MoveCursor", memberid:mergeParagraphSpecA.memberid, timestamp:mergeParagraphSpecA.timestamp, position:mergeParagraphSpecA.sourceStartPosition - 1});
 | |
|         specsForB.push(moveCursorA);
 | |
|       }
 | |
|       if (mergeParagraphSpecB.moveCursor) {
 | |
|         moveCursorB = ({optype:"MoveCursor", memberid:mergeParagraphSpecB.memberid, timestamp:mergeParagraphSpecB.timestamp, position:mergeParagraphSpecB.sourceStartPosition - 1});
 | |
|         specsForA.push(moveCursorB);
 | |
|       }
 | |
|       priorityOp = hasAPriority ? mergeParagraphSpecA : mergeParagraphSpecB;
 | |
|       styleParagraphFixup = ({optype:"SetParagraphStyle", memberid:priorityOp.memberid, timestamp:priorityOp.timestamp, position:priorityOp.destinationStartPosition, styleName:priorityOp.paragraphStyleName});
 | |
|       if (hasAPriority) {
 | |
|         specsForB.push(styleParagraphFixup);
 | |
|       } else {
 | |
|         specsForA.push(styleParagraphFixup);
 | |
|       }
 | |
|     } else {
 | |
|       if (mergeParagraphSpecB.sourceStartPosition === mergeParagraphSpecA.destinationStartPosition) {
 | |
|         mergeParagraphSpecA.destinationStartPosition = mergeParagraphSpecB.destinationStartPosition;
 | |
|         mergeParagraphSpecA.sourceStartPosition -= 1;
 | |
|         mergeParagraphSpecA.paragraphStyleName = mergeParagraphSpecB.paragraphStyleName;
 | |
|       } else {
 | |
|         if (mergeParagraphSpecA.sourceStartPosition === mergeParagraphSpecB.destinationStartPosition) {
 | |
|           mergeParagraphSpecB.destinationStartPosition = mergeParagraphSpecA.destinationStartPosition;
 | |
|           mergeParagraphSpecB.sourceStartPosition -= 1;
 | |
|           mergeParagraphSpecB.paragraphStyleName = mergeParagraphSpecA.paragraphStyleName;
 | |
|         } else {
 | |
|           if (mergeParagraphSpecA.destinationStartPosition < mergeParagraphSpecB.destinationStartPosition) {
 | |
|             mergeParagraphSpecB.destinationStartPosition -= 1;
 | |
|             mergeParagraphSpecB.sourceStartPosition -= 1;
 | |
|           } else {
 | |
|             mergeParagraphSpecA.destinationStartPosition -= 1;
 | |
|             mergeParagraphSpecA.sourceStartPosition -= 1;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:specsForB, opSpecsB:specsForA};
 | |
|   }
 | |
|   function transformMergeParagraphMoveCursor(mergeParagraphSpec, moveCursorSpec) {
 | |
|     var pointA = moveCursorSpec.position, pointB = moveCursorSpec.position + moveCursorSpec.length, start = Math.min(pointA, pointB), end = Math.max(pointA, pointB);
 | |
|     if (start >= mergeParagraphSpec.sourceStartPosition) {
 | |
|       start -= 1;
 | |
|     }
 | |
|     if (end >= mergeParagraphSpec.sourceStartPosition) {
 | |
|       end -= 1;
 | |
|     }
 | |
|     if (moveCursorSpec.length >= 0) {
 | |
|       moveCursorSpec.position = start;
 | |
|       moveCursorSpec.length = end - start;
 | |
|     } else {
 | |
|       moveCursorSpec.position = end;
 | |
|       moveCursorSpec.length = start - end;
 | |
|     }
 | |
|     return {opSpecsA:[mergeParagraphSpec], opSpecsB:[moveCursorSpec]};
 | |
|   }
 | |
|   function transformMergeParagraphRemoveAnnotation(mergeParagraphSpec, removeAnnotationSpec) {
 | |
|     var removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length, mergeParagraphSpecResult = [mergeParagraphSpec], removeAnnotationSpecResult = [removeAnnotationSpec];
 | |
|     if (removeAnnotationSpec.position <= mergeParagraphSpec.destinationStartPosition && mergeParagraphSpec.sourceStartPosition <= removeAnnotationEnd) {
 | |
|       mergeParagraphSpecResult = [];
 | |
|       removeAnnotationSpec.length -= 1;
 | |
|     } else {
 | |
|       if (mergeParagraphSpec.sourceStartPosition < removeAnnotationSpec.position) {
 | |
|         removeAnnotationSpec.position -= 1;
 | |
|       } else {
 | |
|         if (removeAnnotationEnd < mergeParagraphSpec.destinationStartPosition) {
 | |
|           mergeParagraphSpec.destinationStartPosition -= removeAnnotationSpec.length + 2;
 | |
|         }
 | |
|         if (removeAnnotationEnd < mergeParagraphSpec.sourceStartPosition) {
 | |
|           mergeParagraphSpec.sourceStartPosition -= removeAnnotationSpec.length + 2;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:mergeParagraphSpecResult, opSpecsB:removeAnnotationSpecResult};
 | |
|   }
 | |
|   function transformMergeParagraphRemoveText(mergeParagraphSpec, removeTextSpec) {
 | |
|     if (removeTextSpec.position >= mergeParagraphSpec.sourceStartPosition) {
 | |
|       removeTextSpec.position -= 1;
 | |
|     } else {
 | |
|       if (removeTextSpec.position < mergeParagraphSpec.destinationStartPosition) {
 | |
|         mergeParagraphSpec.destinationStartPosition -= removeTextSpec.length;
 | |
|       }
 | |
|       if (removeTextSpec.position < mergeParagraphSpec.sourceStartPosition) {
 | |
|         mergeParagraphSpec.sourceStartPosition -= removeTextSpec.length;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[mergeParagraphSpec], opSpecsB:[removeTextSpec]};
 | |
|   }
 | |
|   function transformMergeParagraphSetParagraphStyle(mergeParagraphSpec, setParagraphStyleSpec) {
 | |
|     var opSpecsA = [mergeParagraphSpec], opSpecsB = [setParagraphStyleSpec];
 | |
|     if (setParagraphStyleSpec.position > mergeParagraphSpec.sourceStartPosition) {
 | |
|       setParagraphStyleSpec.position -= 1;
 | |
|     } else {
 | |
|       if (setParagraphStyleSpec.position === mergeParagraphSpec.destinationStartPosition || setParagraphStyleSpec.position === mergeParagraphSpec.sourceStartPosition) {
 | |
|         setParagraphStyleSpec.position = mergeParagraphSpec.destinationStartPosition;
 | |
|         mergeParagraphSpec.paragraphStyleName = setParagraphStyleSpec.styleName;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:opSpecsA, opSpecsB:opSpecsB};
 | |
|   }
 | |
|   function transformMergeParagraphSplitParagraph(mergeParagraphSpec, splitParagraphSpec) {
 | |
|     var styleSplitParagraph, moveCursorOp, opSpecsA = [mergeParagraphSpec], opSpecsB = [splitParagraphSpec];
 | |
|     if (splitParagraphSpec.position < mergeParagraphSpec.destinationStartPosition) {
 | |
|       mergeParagraphSpec.destinationStartPosition += 1;
 | |
|       mergeParagraphSpec.sourceStartPosition += 1;
 | |
|     } else {
 | |
|       if (splitParagraphSpec.position >= mergeParagraphSpec.destinationStartPosition && splitParagraphSpec.position < mergeParagraphSpec.sourceStartPosition) {
 | |
|         splitParagraphSpec.paragraphStyleName = mergeParagraphSpec.paragraphStyleName;
 | |
|         styleSplitParagraph = ({optype:"SetParagraphStyle", memberid:mergeParagraphSpec.memberid, timestamp:mergeParagraphSpec.timestamp, position:mergeParagraphSpec.destinationStartPosition, styleName:mergeParagraphSpec.paragraphStyleName});
 | |
|         opSpecsA.push(styleSplitParagraph);
 | |
|         if (splitParagraphSpec.position === mergeParagraphSpec.sourceStartPosition - 1 && mergeParagraphSpec.moveCursor) {
 | |
|           moveCursorOp = ({optype:"MoveCursor", memberid:mergeParagraphSpec.memberid, timestamp:mergeParagraphSpec.timestamp, position:splitParagraphSpec.position, length:0});
 | |
|           opSpecsA.push(moveCursorOp);
 | |
|         }
 | |
|         mergeParagraphSpec.destinationStartPosition = splitParagraphSpec.position + 1;
 | |
|         mergeParagraphSpec.sourceStartPosition += 1;
 | |
|       } else {
 | |
|         if (splitParagraphSpec.position >= mergeParagraphSpec.sourceStartPosition) {
 | |
|           splitParagraphSpec.position -= 1;
 | |
|           splitParagraphSpec.sourceParagraphPosition -= 1;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:opSpecsA, opSpecsB:opSpecsB};
 | |
|   }
 | |
|   function transformUpdateParagraphStyleUpdateParagraphStyle(updateParagraphStyleSpecA, updateParagraphStyleSpecB, hasAPriority) {
 | |
|     var majorSpec, minorSpec, updateParagraphStyleSpecAResult = [updateParagraphStyleSpecA], updateParagraphStyleSpecBResult = [updateParagraphStyleSpecB];
 | |
|     if (updateParagraphStyleSpecA.styleName === updateParagraphStyleSpecB.styleName) {
 | |
|       majorSpec = hasAPriority ? updateParagraphStyleSpecA : updateParagraphStyleSpecB;
 | |
|       minorSpec = hasAPriority ? updateParagraphStyleSpecB : updateParagraphStyleSpecA;
 | |
|       dropOverruledAndUnneededProperties(minorSpec.setProperties, minorSpec.removedProperties, majorSpec.setProperties, majorSpec.removedProperties, "style:paragraph-properties");
 | |
|       dropOverruledAndUnneededProperties(minorSpec.setProperties, minorSpec.removedProperties, majorSpec.setProperties, majorSpec.removedProperties, "style:text-properties");
 | |
|       dropOverruledAndUnneededAttributes(minorSpec.setProperties || null, (minorSpec.removedProperties) || null, majorSpec.setProperties || null, (majorSpec.removedProperties) || null);
 | |
|       if (!(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) && !(majorSpec.removedProperties && hasRemovedProperties(majorSpec.removedProperties))) {
 | |
|         if (hasAPriority) {
 | |
|           updateParagraphStyleSpecAResult = [];
 | |
|         } else {
 | |
|           updateParagraphStyleSpecBResult = [];
 | |
|         }
 | |
|       }
 | |
|       if (!(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) && !(minorSpec.removedProperties && hasRemovedProperties(minorSpec.removedProperties))) {
 | |
|         if (hasAPriority) {
 | |
|           updateParagraphStyleSpecBResult = [];
 | |
|         } else {
 | |
|           updateParagraphStyleSpecAResult = [];
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:updateParagraphStyleSpecAResult, opSpecsB:updateParagraphStyleSpecBResult};
 | |
|   }
 | |
|   function transformUpdateMetadataUpdateMetadata(updateMetadataSpecA, updateMetadataSpecB, hasAPriority) {
 | |
|     var majorSpec, minorSpec, updateMetadataSpecAResult = [updateMetadataSpecA], updateMetadataSpecBResult = [updateMetadataSpecB];
 | |
|     majorSpec = hasAPriority ? updateMetadataSpecA : updateMetadataSpecB;
 | |
|     minorSpec = hasAPriority ? updateMetadataSpecB : updateMetadataSpecA;
 | |
|     dropOverruledAndUnneededAttributes(minorSpec.setProperties || null, minorSpec.removedProperties || null, majorSpec.setProperties || null, majorSpec.removedProperties || null);
 | |
|     if (!(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) && !(majorSpec.removedProperties && hasRemovedProperties(majorSpec.removedProperties))) {
 | |
|       if (hasAPriority) {
 | |
|         updateMetadataSpecAResult = [];
 | |
|       } else {
 | |
|         updateMetadataSpecBResult = [];
 | |
|       }
 | |
|     }
 | |
|     if (!(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) && !(minorSpec.removedProperties && hasRemovedProperties(minorSpec.removedProperties))) {
 | |
|       if (hasAPriority) {
 | |
|         updateMetadataSpecBResult = [];
 | |
|       } else {
 | |
|         updateMetadataSpecAResult = [];
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:updateMetadataSpecAResult, opSpecsB:updateMetadataSpecBResult};
 | |
|   }
 | |
|   function transformSetParagraphStyleSetParagraphStyle(setParagraphStyleSpecA, setParagraphStyleSpecB, hasAPriority) {
 | |
|     if (setParagraphStyleSpecA.position === setParagraphStyleSpecB.position) {
 | |
|       if (hasAPriority) {
 | |
|         setParagraphStyleSpecB.styleName = setParagraphStyleSpecA.styleName;
 | |
|       } else {
 | |
|         setParagraphStyleSpecA.styleName = setParagraphStyleSpecB.styleName;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[setParagraphStyleSpecA], opSpecsB:[setParagraphStyleSpecB]};
 | |
|   }
 | |
|   function transformSetParagraphStyleSplitParagraph(setParagraphStyleSpec, splitParagraphSpec) {
 | |
|     var opSpecsA = [setParagraphStyleSpec], opSpecsB = [splitParagraphSpec], setParagraphClone;
 | |
|     if (setParagraphStyleSpec.position > splitParagraphSpec.position) {
 | |
|       setParagraphStyleSpec.position += 1;
 | |
|     } else {
 | |
|       if (setParagraphStyleSpec.position === splitParagraphSpec.sourceParagraphPosition) {
 | |
|         splitParagraphSpec.paragraphStyleName = setParagraphStyleSpec.styleName;
 | |
|         setParagraphClone = cloneOpspec(setParagraphStyleSpec);
 | |
|         setParagraphClone.position = splitParagraphSpec.position + 1;
 | |
|         opSpecsA.push(setParagraphClone);
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:opSpecsA, opSpecsB:opSpecsB};
 | |
|   }
 | |
|   function transformSplitParagraphSplitParagraph(splitParagraphSpecA, splitParagraphSpecB, hasAPriority) {
 | |
|     var specABeforeB, specBBeforeA;
 | |
|     if (splitParagraphSpecA.position < splitParagraphSpecB.position) {
 | |
|       specABeforeB = true;
 | |
|     } else {
 | |
|       if (splitParagraphSpecB.position < splitParagraphSpecA.position) {
 | |
|         specBBeforeA = true;
 | |
|       } else {
 | |
|         if (splitParagraphSpecA.position === splitParagraphSpecB.position) {
 | |
|           if (hasAPriority) {
 | |
|             specABeforeB = true;
 | |
|           } else {
 | |
|             specBBeforeA = true;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (specABeforeB) {
 | |
|       splitParagraphSpecB.position += 1;
 | |
|       if (splitParagraphSpecA.position < splitParagraphSpecB.sourceParagraphPosition) {
 | |
|         splitParagraphSpecB.sourceParagraphPosition += 1;
 | |
|       } else {
 | |
|         splitParagraphSpecB.sourceParagraphPosition = splitParagraphSpecA.position + 1;
 | |
|       }
 | |
|     } else {
 | |
|       if (specBBeforeA) {
 | |
|         splitParagraphSpecA.position += 1;
 | |
|         if (splitParagraphSpecB.position < splitParagraphSpecB.sourceParagraphPosition) {
 | |
|           splitParagraphSpecA.sourceParagraphPosition += 1;
 | |
|         } else {
 | |
|           splitParagraphSpecA.sourceParagraphPosition = splitParagraphSpecB.position + 1;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[splitParagraphSpecA], opSpecsB:[splitParagraphSpecB]};
 | |
|   }
 | |
|   function transformMoveCursorRemoveAnnotation(moveCursorSpec, removeAnnotationSpec) {
 | |
|     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec), moveCursorSpecEnd = moveCursorSpec.position + moveCursorSpec.length, removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length;
 | |
|     if (removeAnnotationSpec.position <= moveCursorSpec.position && moveCursorSpecEnd <= removeAnnotationEnd) {
 | |
|       moveCursorSpec.position = removeAnnotationSpec.position - 1;
 | |
|       moveCursorSpec.length = 0;
 | |
|     } else {
 | |
|       if (removeAnnotationEnd < moveCursorSpec.position) {
 | |
|         moveCursorSpec.position -= removeAnnotationSpec.length + 2;
 | |
|       } else {
 | |
|         if (removeAnnotationEnd < moveCursorSpecEnd) {
 | |
|           moveCursorSpec.length -= removeAnnotationSpec.length + 2;
 | |
|         }
 | |
|       }
 | |
|       if (isMoveCursorSpecRangeInverted) {
 | |
|         invertMoveCursorSpecRange(moveCursorSpec);
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:[moveCursorSpec], opSpecsB:[removeAnnotationSpec]};
 | |
|   }
 | |
|   function transformMoveCursorRemoveCursor(moveCursorSpec, removeCursorSpec) {
 | |
|     var isSameCursorRemoved = moveCursorSpec.memberid === removeCursorSpec.memberid;
 | |
|     return {opSpecsA:isSameCursorRemoved ? [] : [moveCursorSpec], opSpecsB:[removeCursorSpec]};
 | |
|   }
 | |
|   function transformMoveCursorRemoveText(moveCursorSpec, removeTextSpec) {
 | |
|     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec), moveCursorSpecEnd = moveCursorSpec.position + moveCursorSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length;
 | |
|     if (removeTextSpecEnd <= moveCursorSpec.position) {
 | |
|       moveCursorSpec.position -= removeTextSpec.length;
 | |
|     } else {
 | |
|       if (removeTextSpec.position < moveCursorSpecEnd) {
 | |
|         if (moveCursorSpec.position < removeTextSpec.position) {
 | |
|           if (removeTextSpecEnd < moveCursorSpecEnd) {
 | |
|             moveCursorSpec.length -= removeTextSpec.length;
 | |
|           } else {
 | |
|             moveCursorSpec.length = removeTextSpec.position - moveCursorSpec.position;
 | |
|           }
 | |
|         } else {
 | |
|           moveCursorSpec.position = removeTextSpec.position;
 | |
|           if (removeTextSpecEnd < moveCursorSpecEnd) {
 | |
|             moveCursorSpec.length = moveCursorSpecEnd - removeTextSpecEnd;
 | |
|           } else {
 | |
|             moveCursorSpec.length = 0;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (isMoveCursorSpecRangeInverted) {
 | |
|       invertMoveCursorSpecRange(moveCursorSpec);
 | |
|     }
 | |
|     return {opSpecsA:[moveCursorSpec], opSpecsB:[removeTextSpec]};
 | |
|   }
 | |
|   function transformMoveCursorSplitParagraph(moveCursorSpec, splitParagraphSpec) {
 | |
|     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
 | |
|     if (splitParagraphSpec.position < moveCursorSpec.position) {
 | |
|       moveCursorSpec.position += 1;
 | |
|     } else {
 | |
|       if (splitParagraphSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
 | |
|         moveCursorSpec.length += 1;
 | |
|       }
 | |
|     }
 | |
|     if (isMoveCursorSpecRangeInverted) {
 | |
|       invertMoveCursorSpecRange(moveCursorSpec);
 | |
|     }
 | |
|     return {opSpecsA:[moveCursorSpec], opSpecsB:[splitParagraphSpec]};
 | |
|   }
 | |
|   function transformRemoveAnnotationRemoveAnnotation(removeAnnotationSpecA, removeAnnotationSpecB) {
 | |
|     var removeAnnotationSpecAResult = [removeAnnotationSpecA], removeAnnotationSpecBResult = [removeAnnotationSpecB];
 | |
|     if (removeAnnotationSpecA.position === removeAnnotationSpecB.position && removeAnnotationSpecA.length === removeAnnotationSpecB.length) {
 | |
|       removeAnnotationSpecAResult = [];
 | |
|       removeAnnotationSpecBResult = [];
 | |
|     } else {
 | |
|       if (removeAnnotationSpecA.position < removeAnnotationSpecB.position) {
 | |
|         removeAnnotationSpecB.position -= removeAnnotationSpecA.length + 2;
 | |
|       } else {
 | |
|         removeAnnotationSpecA.position -= removeAnnotationSpecB.length + 2;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:removeAnnotationSpecAResult, opSpecsB:removeAnnotationSpecBResult};
 | |
|   }
 | |
|   function transformRemoveAnnotationRemoveText(removeAnnotationSpec, removeTextSpec) {
 | |
|     var removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, removeAnnotationSpecResult = [removeAnnotationSpec], removeTextSpecResult = [removeTextSpec];
 | |
|     if (removeAnnotationSpec.position <= removeTextSpec.position && removeTextSpecEnd <= removeAnnotationEnd) {
 | |
|       removeTextSpecResult = [];
 | |
|       removeAnnotationSpec.length -= removeTextSpec.length;
 | |
|     } else {
 | |
|       if (removeTextSpecEnd < removeAnnotationSpec.position) {
 | |
|         removeAnnotationSpec.position -= removeTextSpec.length;
 | |
|       } else {
 | |
|         if (removeTextSpec.position < removeAnnotationSpec.position) {
 | |
|           removeAnnotationSpec.position = removeTextSpec.position + 1;
 | |
|           removeTextSpec.length -= removeAnnotationSpec.length + 2;
 | |
|         } else {
 | |
|           removeTextSpec.position -= removeAnnotationSpec.length + 2;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:removeAnnotationSpecResult, opSpecsB:removeTextSpecResult};
 | |
|   }
 | |
|   function transformRemoveAnnotationSetParagraphStyle(removeAnnotationSpec, setParagraphStyleSpec) {
 | |
|     var setParagraphStyleSpecPosition = setParagraphStyleSpec.position, removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length, removeAnnotationSpecResult = [removeAnnotationSpec], setParagraphStyleSpecResult = [setParagraphStyleSpec];
 | |
|     if (removeAnnotationSpec.position <= setParagraphStyleSpecPosition && setParagraphStyleSpecPosition <= removeAnnotationEnd) {
 | |
|       setParagraphStyleSpecResult = [];
 | |
|     } else {
 | |
|       if (removeAnnotationEnd < setParagraphStyleSpecPosition) {
 | |
|         setParagraphStyleSpec.position -= removeAnnotationSpec.length + 2;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:removeAnnotationSpecResult, opSpecsB:setParagraphStyleSpecResult};
 | |
|   }
 | |
|   function transformRemoveAnnotationSplitParagraph(removeAnnotationSpec, splitParagraphSpec) {
 | |
|     var splitParagraphSpecPosition = splitParagraphSpec.position, removeAnnotationEnd = removeAnnotationSpec.position + removeAnnotationSpec.length, removeAnnotationSpecResult = [removeAnnotationSpec], splitParagraphSpecResult = [splitParagraphSpec];
 | |
|     if (removeAnnotationSpec.position <= splitParagraphSpecPosition && splitParagraphSpecPosition <= removeAnnotationEnd) {
 | |
|       splitParagraphSpecResult = [];
 | |
|       removeAnnotationSpec.length += 1;
 | |
|     } else {
 | |
|       if (removeAnnotationEnd < splitParagraphSpec.sourceParagraphPosition) {
 | |
|         splitParagraphSpec.sourceParagraphPosition -= removeAnnotationSpec.length + 2;
 | |
|       }
 | |
|       if (removeAnnotationEnd < splitParagraphSpecPosition) {
 | |
|         splitParagraphSpec.position -= removeAnnotationSpec.length + 2;
 | |
|       } else {
 | |
|         removeAnnotationSpec.position += 1;
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:removeAnnotationSpecResult, opSpecsB:splitParagraphSpecResult};
 | |
|   }
 | |
|   function transformRemoveCursorRemoveCursor(removeCursorSpecA, removeCursorSpecB) {
 | |
|     var isSameMemberid = removeCursorSpecA.memberid === removeCursorSpecB.memberid;
 | |
|     return {opSpecsA:isSameMemberid ? [] : [removeCursorSpecA], opSpecsB:isSameMemberid ? [] : [removeCursorSpecB]};
 | |
|   }
 | |
|   function transformRemoveStyleRemoveStyle(removeStyleSpecA, removeStyleSpecB) {
 | |
|     var isSameStyle = removeStyleSpecA.styleName === removeStyleSpecB.styleName && removeStyleSpecA.styleFamily === removeStyleSpecB.styleFamily;
 | |
|     return {opSpecsA:isSameStyle ? [] : [removeStyleSpecA], opSpecsB:isSameStyle ? [] : [removeStyleSpecB]};
 | |
|   }
 | |
|   function transformRemoveStyleSetParagraphStyle(removeStyleSpec, setParagraphStyleSpec) {
 | |
|     var helperOpspec, removeStyleSpecResult = [removeStyleSpec], setParagraphStyleSpecResult = [setParagraphStyleSpec];
 | |
|     if (removeStyleSpec.styleFamily === "paragraph" && removeStyleSpec.styleName === setParagraphStyleSpec.styleName) {
 | |
|       helperOpspec = {optype:"SetParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, position:setParagraphStyleSpec.position, styleName:""};
 | |
|       removeStyleSpecResult.unshift(helperOpspec);
 | |
|       setParagraphStyleSpec.styleName = "";
 | |
|     }
 | |
|     return {opSpecsA:removeStyleSpecResult, opSpecsB:setParagraphStyleSpecResult};
 | |
|   }
 | |
|   function transformRemoveStyleUpdateParagraphStyle(removeStyleSpec, updateParagraphStyleSpec) {
 | |
|     var setAttributes, helperOpspec, removeStyleSpecResult = [removeStyleSpec], updateParagraphStyleSpecResult = [updateParagraphStyleSpec];
 | |
|     if (removeStyleSpec.styleFamily === "paragraph") {
 | |
|       setAttributes = getStyleReferencingAttributes(updateParagraphStyleSpec.setProperties, removeStyleSpec.styleName);
 | |
|       if (setAttributes.length > 0) {
 | |
|         helperOpspec = {optype:"UpdateParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, styleName:updateParagraphStyleSpec.styleName, removedProperties:{attributes:setAttributes.join(",")}};
 | |
|         removeStyleSpecResult.unshift(helperOpspec);
 | |
|       }
 | |
|       if (removeStyleSpec.styleName === updateParagraphStyleSpec.styleName) {
 | |
|         updateParagraphStyleSpecResult = [];
 | |
|       } else {
 | |
|         dropStyleReferencingAttributes(updateParagraphStyleSpec.setProperties, removeStyleSpec.styleName);
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:removeStyleSpecResult, opSpecsB:updateParagraphStyleSpecResult};
 | |
|   }
 | |
|   function transformRemoveTextRemoveText(removeTextSpecA, removeTextSpecB) {
 | |
|     var removeTextSpecAEnd = removeTextSpecA.position + removeTextSpecA.length, removeTextSpecBEnd = removeTextSpecB.position + removeTextSpecB.length, removeTextSpecAResult = [removeTextSpecA], removeTextSpecBResult = [removeTextSpecB];
 | |
|     if (removeTextSpecBEnd <= removeTextSpecA.position) {
 | |
|       removeTextSpecA.position -= removeTextSpecB.length;
 | |
|     } else {
 | |
|       if (removeTextSpecAEnd <= removeTextSpecB.position) {
 | |
|         removeTextSpecB.position -= removeTextSpecA.length;
 | |
|       } else {
 | |
|         if (removeTextSpecB.position < removeTextSpecAEnd) {
 | |
|           if (removeTextSpecA.position < removeTextSpecB.position) {
 | |
|             if (removeTextSpecBEnd < removeTextSpecAEnd) {
 | |
|               removeTextSpecA.length = removeTextSpecA.length - removeTextSpecB.length;
 | |
|             } else {
 | |
|               removeTextSpecA.length = removeTextSpecB.position - removeTextSpecA.position;
 | |
|             }
 | |
|             if (removeTextSpecAEnd < removeTextSpecBEnd) {
 | |
|               removeTextSpecB.position = removeTextSpecA.position;
 | |
|               removeTextSpecB.length = removeTextSpecBEnd - removeTextSpecAEnd;
 | |
|             } else {
 | |
|               removeTextSpecBResult = [];
 | |
|             }
 | |
|           } else {
 | |
|             if (removeTextSpecAEnd < removeTextSpecBEnd) {
 | |
|               removeTextSpecB.length = removeTextSpecB.length - removeTextSpecA.length;
 | |
|             } else {
 | |
|               if (removeTextSpecB.position < removeTextSpecA.position) {
 | |
|                 removeTextSpecB.length = removeTextSpecA.position - removeTextSpecB.position;
 | |
|               } else {
 | |
|                 removeTextSpecBResult = [];
 | |
|               }
 | |
|             }
 | |
|             if (removeTextSpecBEnd < removeTextSpecAEnd) {
 | |
|               removeTextSpecA.position = removeTextSpecB.position;
 | |
|               removeTextSpecA.length = removeTextSpecAEnd - removeTextSpecBEnd;
 | |
|             } else {
 | |
|               removeTextSpecAResult = [];
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return {opSpecsA:removeTextSpecAResult, opSpecsB:removeTextSpecBResult};
 | |
|   }
 | |
|   function transformRemoveTextSetParagraphStyle(removeTextSpec, setParagraphStyleSpec) {
 | |
|     if (removeTextSpec.position < setParagraphStyleSpec.position) {
 | |
|       setParagraphStyleSpec.position -= removeTextSpec.length;
 | |
|     }
 | |
|     return {opSpecsA:[removeTextSpec], opSpecsB:[setParagraphStyleSpec]};
 | |
|   }
 | |
|   function transformRemoveTextSplitParagraph(removeTextSpec, splitParagraphSpec) {
 | |
|     var removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, helperOpspec, removeTextSpecResult = [removeTextSpec], splitParagraphSpecResult = [splitParagraphSpec];
 | |
|     if (splitParagraphSpec.position <= removeTextSpec.position) {
 | |
|       removeTextSpec.position += 1;
 | |
|     } else {
 | |
|       if (splitParagraphSpec.position < removeTextSpecEnd) {
 | |
|         removeTextSpec.length = splitParagraphSpec.position - removeTextSpec.position;
 | |
|         helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:splitParagraphSpec.position + 1, length:removeTextSpecEnd - splitParagraphSpec.position};
 | |
|         removeTextSpecResult.unshift(helperOpspec);
 | |
|       }
 | |
|     }
 | |
|     if (removeTextSpec.position + removeTextSpec.length <= splitParagraphSpec.position) {
 | |
|       splitParagraphSpec.position -= removeTextSpec.length;
 | |
|     } else {
 | |
|       if (removeTextSpec.position < splitParagraphSpec.position) {
 | |
|         splitParagraphSpec.position = removeTextSpec.position;
 | |
|       }
 | |
|     }
 | |
|     if (removeTextSpec.position + removeTextSpec.length < splitParagraphSpec.sourceParagraphPosition) {
 | |
|       splitParagraphSpec.sourceParagraphPosition -= removeTextSpec.length;
 | |
|     }
 | |
|     return {opSpecsA:removeTextSpecResult, opSpecsB:splitParagraphSpecResult};
 | |
|   }
 | |
|   function passUnchanged(opSpecA, opSpecB) {
 | |
|     return {opSpecsA:[opSpecA], opSpecsB:[opSpecB]};
 | |
|   }
 | |
|   var transformations;
 | |
|   transformations = {"AddAnnotation":{"AddAnnotation":transformAddAnnotationAddAnnotation, "AddCursor":passUnchanged, "AddMember":passUnchanged, "AddStyle":passUnchanged, "ApplyDirectStyling":transformAddAnnotationApplyDirectStyling, "InsertText":transformAddAnnotationInsertText, "MergeParagraph":transformAddAnnotationMergeParagraph, "MoveCursor":transformAddAnnotationMoveCursor, "RemoveAnnotation":transformAddAnnotationRemoveAnnotation, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, 
 | |
|   "RemoveStyle":passUnchanged, "RemoveText":transformAddAnnotationRemoveText, "SetParagraphStyle":transformAddAnnotationSetParagraphStyle, "SplitParagraph":transformAddAnnotationSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "AddCursor":{"AddCursor":passUnchanged, "AddMember":passUnchanged, "AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MergeParagraph":passUnchanged, "MoveCursor":passUnchanged, 
 | |
|   "RemoveAnnotation":passUnchanged, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "AddMember":{"AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MergeParagraph":passUnchanged, "MoveCursor":passUnchanged, "RemoveAnnotation":passUnchanged, 
 | |
|   "RemoveCursor":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "AddStyle":{"AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MergeParagraph":passUnchanged, "MoveCursor":passUnchanged, "RemoveAnnotation":passUnchanged, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":transformAddStyleRemoveStyle, 
 | |
|   "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "ApplyDirectStyling":{"ApplyDirectStyling":transformApplyDirectStylingApplyDirectStyling, "InsertText":transformApplyDirectStylingInsertText, "MergeParagraph":transformApplyDirectStylingMergeParagraph, "MoveCursor":passUnchanged, "RemoveAnnotation":transformApplyDirectStylingRemoveAnnotation, "RemoveCursor":passUnchanged, 
 | |
|   "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformApplyDirectStylingRemoveText, "SetParagraphStyle":passUnchanged, "SplitParagraph":transformApplyDirectStylingSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "InsertText":{"InsertText":transformInsertTextInsertText, "MergeParagraph":transformInsertTextMergeParagraph, "MoveCursor":transformInsertTextMoveCursor, "RemoveAnnotation":transformInsertTextRemoveAnnotation, 
 | |
|   "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformInsertTextRemoveText, "SetParagraphStyle":transformInsertTextSetParagraphStyle, "SplitParagraph":transformInsertTextSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "MergeParagraph":{"MergeParagraph":transformMergeParagraphMergeParagraph, "MoveCursor":transformMergeParagraphMoveCursor, "RemoveAnnotation":transformMergeParagraphRemoveAnnotation, 
 | |
|   "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformMergeParagraphRemoveText, "SetParagraphStyle":transformMergeParagraphSetParagraphStyle, "SplitParagraph":transformMergeParagraphSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "MoveCursor":{"MoveCursor":passUnchanged, "RemoveAnnotation":transformMoveCursorRemoveAnnotation, "RemoveCursor":transformMoveCursorRemoveCursor, 
 | |
|   "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformMoveCursorRemoveText, "SetParagraphStyle":passUnchanged, "SplitParagraph":transformMoveCursorSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveAnnotation":{"RemoveAnnotation":transformRemoveAnnotationRemoveAnnotation, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformRemoveAnnotationRemoveText, 
 | |
|   "SetParagraphStyle":transformRemoveAnnotationSetParagraphStyle, "SplitParagraph":transformRemoveAnnotationSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveCursor":{"RemoveCursor":transformRemoveCursorRemoveCursor, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, 
 | |
|   "UpdateParagraphStyle":passUnchanged}, "RemoveMember":{"RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveStyle":{"RemoveStyle":transformRemoveStyleRemoveStyle, "RemoveText":passUnchanged, "SetParagraphStyle":transformRemoveStyleSetParagraphStyle, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":transformRemoveStyleUpdateParagraphStyle}, 
 | |
|   "RemoveText":{"RemoveText":transformRemoveTextRemoveText, "SetParagraphStyle":transformRemoveTextSetParagraphStyle, "SplitParagraph":transformRemoveTextSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "SetParagraphStyle":{"SetParagraphStyle":transformSetParagraphStyleSetParagraphStyle, "SplitParagraph":transformSetParagraphStyleSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, 
 | |
|   "SplitParagraph":{"SplitParagraph":transformSplitParagraphSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "UpdateMember":{"UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "UpdateMetadata":{"UpdateMetadata":transformUpdateMetadataUpdateMetadata, "UpdateParagraphStyle":passUnchanged}, "UpdateParagraphStyle":{"UpdateParagraphStyle":transformUpdateParagraphStyleUpdateParagraphStyle}};
 | |
|   this.passUnchanged = passUnchanged;
 | |
|   this.extendTransformations = function(moreTransformations) {
 | |
|     Object.keys(moreTransformations).forEach(function(optypeA) {
 | |
|       var moreTransformationsOptypeAMap = moreTransformations[optypeA], optypeAMap, isExtendingOptypeAMap = transformations.hasOwnProperty(optypeA);
 | |
|       runtime.log((isExtendingOptypeAMap ? "Extending" : "Adding") + " map for optypeA: " + optypeA);
 | |
|       if (!isExtendingOptypeAMap) {
 | |
|         transformations[optypeA] = {};
 | |
|       }
 | |
|       optypeAMap = transformations[optypeA];
 | |
|       Object.keys(moreTransformationsOptypeAMap).forEach(function(optypeB) {
 | |
|         var isOverwritingOptypeBEntry = optypeAMap.hasOwnProperty(optypeB);
 | |
|         runtime.assert(optypeA <= optypeB, "Wrong order:" + optypeA + ", " + optypeB);
 | |
|         runtime.log("  " + (isOverwritingOptypeBEntry ? "Overwriting" : "Adding") + " entry for optypeB: " + optypeB);
 | |
|         optypeAMap[optypeB] = moreTransformationsOptypeAMap[optypeB];
 | |
|       });
 | |
|     });
 | |
|   };
 | |
|   this.transformOpspecVsOpspec = function(opSpecA, opSpecB) {
 | |
|     var isOptypeAAlphaNumericSmaller = opSpecA.optype <= opSpecB.optype, helper, transformationFunctionMap, transformationFunction, result;
 | |
|     runtime.log("Crosstransforming:");
 | |
|     runtime.log(runtime.toJson(opSpecA));
 | |
|     runtime.log(runtime.toJson(opSpecB));
 | |
|     if (!isOptypeAAlphaNumericSmaller) {
 | |
|       helper = opSpecA;
 | |
|       opSpecA = opSpecB;
 | |
|       opSpecB = helper;
 | |
|     }
 | |
|     transformationFunctionMap = transformations[opSpecA.optype];
 | |
|     transformationFunction = transformationFunctionMap && transformationFunctionMap[opSpecB.optype];
 | |
|     if (transformationFunction) {
 | |
|       result = transformationFunction(opSpecA, opSpecB, !isOptypeAAlphaNumericSmaller);
 | |
|       if (!isOptypeAAlphaNumericSmaller && result !== null) {
 | |
|         result = {opSpecsA:result.opSpecsB, opSpecsB:result.opSpecsA};
 | |
|       }
 | |
|     } else {
 | |
|       result = null;
 | |
|     }
 | |
|     runtime.log("result:");
 | |
|     if (result) {
 | |
|       runtime.log(runtime.toJson(result.opSpecsA));
 | |
|       runtime.log(runtime.toJson(result.opSpecsB));
 | |
|     } else {
 | |
|       runtime.log("null");
 | |
|     }
 | |
|     return result;
 | |
|   };
 | |
| };
 | |
| ops.OperationTransformer = function OperationTransformer() {
 | |
|   var operationTransformMatrix = new ops.OperationTransformMatrix;
 | |
|   function transformOpVsOp(opSpecA, opSpecB) {
 | |
|     return operationTransformMatrix.transformOpspecVsOpspec(opSpecA, opSpecB);
 | |
|   }
 | |
|   function transformOpListVsOp(opSpecsA, opSpecB) {
 | |
|     var transformResult, transformListResult, transformedOpspecsA = [], transformedOpspecsB = [];
 | |
|     while (opSpecsA.length > 0 && opSpecB) {
 | |
|       transformResult = transformOpVsOp(opSpecsA.shift(), opSpecB);
 | |
|       if (!transformResult) {
 | |
|         return null;
 | |
|       }
 | |
|       transformedOpspecsA = transformedOpspecsA.concat(transformResult.opSpecsA);
 | |
|       if (transformResult.opSpecsB.length === 0) {
 | |
|         transformedOpspecsA = transformedOpspecsA.concat(opSpecsA);
 | |
|         opSpecB = null;
 | |
|         break;
 | |
|       }
 | |
|       while (transformResult.opSpecsB.length > 1) {
 | |
|         transformListResult = transformOpListVsOp(opSpecsA, transformResult.opSpecsB.shift());
 | |
|         if (!transformListResult) {
 | |
|           return null;
 | |
|         }
 | |
|         transformedOpspecsB = transformedOpspecsB.concat(transformListResult.opSpecsB);
 | |
|         opSpecsA = transformListResult.opSpecsA;
 | |
|       }
 | |
|       opSpecB = transformResult.opSpecsB.pop();
 | |
|     }
 | |
|     if (opSpecB) {
 | |
|       transformedOpspecsB.push(opSpecB);
 | |
|     }
 | |
|     return {opSpecsA:transformedOpspecsA, opSpecsB:transformedOpspecsB};
 | |
|   }
 | |
|   this.getOperationTransformMatrix = function() {
 | |
|     return operationTransformMatrix;
 | |
|   };
 | |
|   this.transform = function(opSpecsA, opSpecsB) {
 | |
|     var transformResult, transformedOpspecsB = [];
 | |
|     while (opSpecsB.length > 0) {
 | |
|       transformResult = transformOpListVsOp(opSpecsA, opSpecsB.shift());
 | |
|       if (!transformResult) {
 | |
|         return null;
 | |
|       }
 | |
|       opSpecsA = transformResult.opSpecsA;
 | |
|       transformedOpspecsB = transformedOpspecsB.concat(transformResult.opSpecsB);
 | |
|     }
 | |
|     return {opSpecsA:(opSpecsA), opSpecsB:(transformedOpspecsB)};
 | |
|   };
 | |
| };
 | |
| var webodf_css = '@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);@namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);@namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);@namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);@namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);@namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);@namespace table url(urn:oasis:names:tc:opendocument:xmlns:table:1.0);@namespace text url(urn:oasis:names:tc:opendocument:xmlns:text:1.0);@namespace webodfhelper url(urn:webodf:names:helper);@namespace cursor url(urn:webodf:names:cursor);@namespace editinfo url(urn:webodf:names:editinfo);@namespace annotation url(urn:webodf:names:annotation);@namespace dc url(http://purl.org/dc/elements/1.1/);@namespace svgns url(http://www.w3.org/2000/svg);office|document > *, office|document-content > * {display: none;}office|body, office|document {display: inline-block;position: relative;}text|p, text|h {display: block;padding: 0;margin: 0;line-height: normal;position: relative;}text|p::after, text|h::after {content: "\\200B";white-space: pre;}*[webodfhelper|containsparagraphanchor] {position: relative;}text|s {white-space: pre;}text|tab {display: inline;white-space: pre;}text|tracked-changes {display: none;}office|binary-data {display: none;}office|text {display: block;text-align: left;overflow: visible;word-wrap: break-word;}office|text::selection {background: transparent;}.webodf-virtualSelections *::selection {background: transparent;}.webodf-virtualSelections *::-moz-selection {background: transparent;}office|text * draw|text-box {display: block;border: 1px solid #d3d3d3;}office|text draw|frame {z-index: 1;}office|spreadsheet {display: block;border-collapse: collapse;empty-cells: show;font-family: sans-serif;font-size: 10pt;text-align: left;page-break-inside: avoid;overflow: hidden;}office|presentation {display: inline-block;text-align: left;}#shadowContent {display: inline-block;text-align: left;}draw|page {display: block;position: relative;overflow: hidden;}presentation|notes, presentation|footer-decl, presentation|date-time-decl {display: none;}@media print {draw|page {border: 1pt solid black;page-break-inside: avoid;}presentation|notes {}}office|spreadsheet text|p {border: 0px;padding: 1px;margin: 0px;}office|spreadsheet table|table {margin: 3px;}office|spreadsheet table|table:after {}office|spreadsheet table|table-row {counter-increment: row;}office|spreadsheet table|table-row:before {width: 3em;background: #cccccc;border: 1px solid black;text-align: center;content: counter(row);display: table-cell;}office|spreadsheet table|table-cell {border: 1px solid #cccccc;}table|table {display: table;}draw|frame table|table {width: 100%;height: 100%;background: white;}table|table-header-rows {display: table-header-group;}table|table-row {display: table-row;}table|table-column {display: table-column;}table|table-cell {width: 0.889in;display: table-cell;word-break: break-all;}draw|frame {display: block;}draw|image {display: block;width: 100%;height: 100%;top: 0px;left: 0px;background-repeat: no-repeat;background-size: 100% 100%;-moz-background-size: 100% 100%;}draw|frame > draw|image:nth-of-type(n+2) {display: none;}text|list:before {display: none;content:"";}text|list {display: block;}text|list-item {display: block;}text|number {display:none;}text|a {color: blue;text-decoration: underline;cursor: pointer;}.webodf-inactiveLinks text|a {cursor: text;}text|note-citation {vertical-align: super;font-size: smaller;}text|note-body {display: none;}text|note:hover text|note-citation {background: #dddddd;}text|note:hover text|note-body {display: block;left:1em;max-width: 80%;position: absolute;background: #ffffaa;}text|bibliography-source {display: none;}svg|title, svg|desc {display: none;}video {width: 100%;height: 100%}cursor|anchor {display: none;}cursor|cursor {display: none;}.webodf-caretOverlay {position: absolute;top: 5%;height: 1em;z-index: 10;padding-left: 1px;pointer-events: none;}.webodf-caretOverlay .caret {position: absolute;border-left: 2px solid black;top: 0;bottom: 0;right: 0;}.webodf-caretOverlay .handle {position: absolute;margin-top: 5px;padding-top: 3px;margin-left: auto;margin-right: auto;width: 64px;height: 68px;border-radius: 5px;opacity: 0.3;text-align: center;background-color: black;box-shadow: 0px 0px 5px rgb(90, 90, 90);border: 1px solid black;top: -85px;right: -32px;}.webodf-caretOverlay .handle > img {box-shadow: 0px 0px 5px rgb(90, 90, 90) inset;background-color: rgb(200, 200, 200);border-radius: 5px;border: 2px solid;height: 60px;width: 60px;display: block;margin: auto;}.webodf-caretOverlay .handle.active {opacity: 0.8;}.webodf-caretOverlay .handle:after {content: " ";position: absolute;width: 0px;height: 0px;border-style: solid;border-width: 8.7px 5px 0 5px;border-color: black transparent transparent transparent;top: 100%;left: 43%;}.webodf-caretSizer {display: inline-block;width: 0;visibility: hidden;}#eventTrap {display: block;position: absolute;bottom: 0;left: 0;outline: none;opacity: 0;color: rgba(255, 255, 255, 0);pointer-events: none;white-space: pre;overflow: hidden;}cursor|cursor > #composer {text-decoration: underline;}cursor|cursor[cursor|caret-sizer-active="true"],cursor|cursor[cursor|composing="true"] {display: inline;}editinfo|editinfo {display: inline-block;}.editInfoMarker {position: absolute;width: 10px;height: 100%;left: -20px;opacity: 0.8;top: 0;border-radius: 5px;background-color: transparent;box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);}.editInfoMarker:hover {box-shadow: 0px 0px 8px rgba(0, 0, 0, 1);}.editInfoHandle {position: absolute;background-color: black;padding: 5px;border-radius: 5px;opacity: 0.8;box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);bottom: 100%;margin-bottom: 10px;z-index: 3;left: -25px;}.editInfoHandle:after {content: " ";position: absolute;width: 0px;height: 0px;border-style: solid;border-width: 8.7px 5px 0 5px;border-color: black transparent transparent transparent;top: 100%;left: 5px;}.editInfo {font-family: sans-serif;font-weight: normal;font-style: normal;text-decoration: none;color: white;width: 100%;height: 12pt;}.editInfoColor {float: left;width: 10pt;height: 10pt;border: 1px solid white;}.editInfoAuthor {float: left;margin-left: 5pt;font-size: 10pt;text-align: left;height: 12pt;line-height: 12pt;}.editInfoTime {float: right;margin-left: 30pt;font-size: 8pt;font-style: italic;color: yellow;height: 12pt;line-height: 12pt;}.annotationWrapper {display: inline;position: relative;}.annotationRemoveButton:before {content: "\u00d7";color: white;padding: 5px;line-height: 1em;}.annotationRemoveButton {width: 20px;height: 20px;border-radius: 10px;background-color: black;box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);position: absolute;top: -10px;left: -10px;z-index: 3;text-align: center;font-family: sans-serif;font-style: normal;font-weight: normal;text-decoration: none;font-size: 15px;}.annotationRemoveButton:hover {cursor: pointer;box-shadow: 0px 0px 5px rgba(0, 0, 0, 1);}.annotationNote {width: 4cm;position: absolute;display: inline;z-index: 10;top: 0;}.annotationNote > office|annotation {display: block;text-align: left;}.annotationConnector {position: absolute;display: inline;top: 0;z-index: 2;border-top: 1px dashed brown;}.annotationConnector.angular {-moz-transform-origin: left top;-webkit-transform-origin: left top;-ms-transform-origin: left top;transform-origin: left top;}.annotationConnector.horizontal {left: 0;}.annotationConnector.horizontal:before {content: "";display: inline;position: absolute;width: 0px;height: 0px;border-style: solid;border-width: 8.7px 5px 0 5px;border-color: brown transparent transparent transparent;top: -1px;left: -5px;}office|annotation {width: 100%;height: 100%;display: none;background: rgb(198, 238, 184);background: -moz-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);background: -webkit-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);background: -o-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);background: -ms-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);background: linear-gradient(180deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);box-shadow: 0 3px 4px -3px #ccc;}office|annotation > dc|creator {display: block;font-size: 10pt;font-weight: normal;font-style: normal;font-family: sans-serif;color: white;background-color: brown;padding: 4px;}office|annotation > dc|date {display: block;font-size: 10pt;font-weight: normal;font-style: normal;font-family: sans-serif;border: 4px solid transparent;color: black;}office|annotation > text|list {display: block;padding: 5px;}office|annotation text|p {font-size: 10pt;color: black;font-weight: normal;font-style: normal;text-decoration: none;font-family: sans-serif;}#annotationsPane {background-color: #EAEAEA;width: 4cm;height: 100%;display: none;position: absolute;outline: 1px solid #ccc;}.webodf-annotationHighlight {background-color: yellow;position: relative;}.webodf-selectionOverlay {position: absolute;pointer-events: none;top: 0;left: 0;top: 0;left: 0;width: 100%;height: 100%;z-index: 15;}.webodf-selectionOverlay > polygon {fill-opacity: 0.3;stroke-opacity: 0.8;stroke-width: 1;fill-rule: evenodd;}.webodf-selectionOverlay > .webodf-draggable {fill-opacity: 0.8;stroke-opacity: 0;stroke-width: 8;pointer-events: all;display: none;-moz-transform-origin: center center;-webkit-transform-origin: center center;-ms-transform-origin: center center;transform-origin: center center;}#imageSelector {display: none;position: absolute;border-style: solid;border-color: black;}#imageSelector > div {width: 5px;height: 5px;display: block;position: absolute;border: 1px solid black;background-color: #ffffff;}#imageSelector > .topLeft {top: -4px;left: -4px;}#imageSelector > .topRight {top: -4px;right: -4px;}#imageSelector > .bottomRight {right: -4px;bottom: -4px;}#imageSelector > .bottomLeft {bottom: -4px;left: -4px;}#imageSelector > .topMiddle {top: -4px;left: 50%;margin-left: -2.5px;}#imageSelector > .rightMiddle {top: 50%;right: -4px;margin-top: -2.5px;}#imageSelector > .bottomMiddle {bottom: -4px;left: 50%;margin-left: -2.5px;}#imageSelector > .leftMiddle {top: 50%;left: -4px;margin-top: -2.5px;}div.webodf-customScrollbars::-webkit-scrollbar{width: 8px;height: 8px;background-color: transparent;}div.webodf-customScrollbars::-webkit-scrollbar-track{background-color: transparent;}div.webodf-customScrollbars::-webkit-scrollbar-thumb{background-color: #444;border-radius: 4px;}.webodf-hyperlinkTooltip {display: none;color: white;background-color: black;border-radius: 5px;box-shadow: 2px 2px 5px gray;padding: 3px;position: absolute;max-width: 210px;text-align: left;word-break: break-all;z-index: 16;}.webodf-hyperlinkTooltipText {display: block;font-weight: bold;}';
 | |
| 
 |