From e74535bdf64554194291aaaf18b9dd48f82baf5a Mon Sep 17 00:00:00 2001 From: "Friedrich W. H. Kossebau" Date: Fri, 30 Aug 2013 17:35:35 +0200 Subject: [PATCH] Update to current webodf: saves on closing the session/document (needs server support still) saves only is the user has edited something --- js/documents.js | 59 +- js/editor/Editor.js | 406 +++--- js/editor/EditorSession.js | 81 +- .../{MemberList.js => MemberListView.js} | 59 +- js/editor/SessionList.js | 65 + js/editor/SessionListView.js | 3 - js/editor/boot_editor.js | 462 ------- js/editor/nls/de/myResources.js | 21 +- js/editor/nls/myResources.js | 17 +- js/editor/server/nowjs/sessionList.js | 124 -- .../ServerFactory.js} | 37 +- js/editor/server/pullbox/MemberModel.js | 281 ++++ js/editor/server/pullbox/OperationRouter.js | 508 ++++++++ js/editor/server/pullbox/Server.js | 293 +++++ .../{serverFactory.js => ServerFactory.js} | 23 +- .../{sessionList.js => SessionList.js} | 31 +- js/editor/widgets.js | 220 ++-- .../widgets/dialogWidgets/alignmentPane.js | 10 +- .../widgets/dialogWidgets/fontEffectsPane.js | 17 +- js/editor/widgets/paragraphStyles.js | 78 +- js/editor/widgets/paragraphStylesDialog.js | 511 ++++---- js/editor/widgets/simpleStyles.js | 205 +-- .../widgets/toolbarWidgets/currentStyle.js | 67 +- js/editor/widgets/undoRedoMenu.js | 113 +- js/editor/widgets/zoomSlider.js | 69 +- js/webodf-debug.js | 886 ++----------- js/webodf.js | 1150 +++++++---------- 27 files changed, 2926 insertions(+), 2870 deletions(-) rename js/editor/{MemberList.js => MemberListView.js} (76%) create mode 100644 js/editor/SessionList.js delete mode 100644 js/editor/boot_editor.js delete mode 100644 js/editor/server/nowjs/sessionList.js rename js/editor/server/{nowjs/serverFactory.js => owncloud/ServerFactory.js} (65%) create mode 100644 js/editor/server/pullbox/MemberModel.js create mode 100644 js/editor/server/pullbox/OperationRouter.js create mode 100644 js/editor/server/pullbox/Server.js rename js/editor/server/pullbox/{serverFactory.js => ServerFactory.js} (78%) rename js/editor/server/pullbox/{sessionList.js => SessionList.js} (85%) diff --git a/js/documents.js b/js/documents.js index 378ec86e..351ef962 100644 --- a/js/documents.js +++ b/js/documents.js @@ -33,9 +33,7 @@ var documentsMain = { return; } - OC.addScript('documents', 'editor/boot_editor').done(function() { - var doclocation = response.es_id; - + require({ }, ["webodf/editor/server/owncloud/ServerFactory", "webodf/editor/Editor"], function (ServerFactory, Editor) { // fade out file list and show WebODF canvas $('.documentslist, #emptyfolder').fadeOut('slow').promise().done(function() { // odf action toolbar @@ -67,6 +65,9 @@ var documentsMain = { ' ' + ' ' + ''; + + var serverFactory = new ServerFactory(); + $(document.body).addClass("claro"); $('.documentslist, #emptyfolder').after(canvashtml); // in case we are on the public sharing page we shall display the odf into the preview tag @@ -74,21 +75,13 @@ var documentsMain = { runtime.assert(response.es_id, "invalid session id."); memberId = response.member_id; - webodfEditor.boot( - { - collaborative: "owncloud", - docUrl: doclocation, - loginProcedure: function(cb) { - cb(response.es_id, OC.currentUser, "token"); - }, - joinSession: function(userId, sessionId, cb) { - cb(memberId); - }, - callback: function(webodfEditorInstance) { - documentsMain.webodfEditorInstance = webodfEditorInstance; - } - } - ); + documentsMain.webodfServerInstance = serverFactory.createServer(); + documentsMain.webodfEditorInstance = new Editor({}, documentsMain.webodfServerInstance, serverFactory); + + // load the document and get called back when it's live + documentsMain.webodfEditorInstance.loadSession(response.es_id, memberId, function() { + documentsMain.webodfEditorInstance.startEditing(); + }); }); }); }, @@ -155,24 +148,24 @@ var documentsMain = { onClose: function() { "use strict"; - var saveSessionRoute = OC.Router.generate('documents_session_save'); - //auto save document - documentsMain.webodfEditorInstance.saveDocument(saveSessionRoute, function(){}); - //close editor - documentsMain.webodfEditorInstance.shutdown(function() { + documentsMain.webodfEditorInstance.endEditing(); + documentsMain.webodfEditorInstance.closeDocument(function() { // successfull shutdown - all is good. + // TODO: proper session leaving call to server, either by webodfServerInstance or custom +// documentsMain.webodfServerInstance.leaveSession(sessionId, memberId, function() { - // Fade out odf-toolbar - $('#odf-toolbar').fadeOut('slow'); - // Fade out editor - $('#mainContainer').fadeOut('slow', function() { - $('#mainContainer').remove(); - $('#odf-canvas').remove(); - $('.actions,#file_access_panel').fadeIn('slow'); - $('.documentslist, #emptyfolder').fadeIn('slow'); - $(document.body).removeClass('claro'); - }); + // Fade out odf-toolbar + $('#odf-toolbar').fadeOut('slow'); + // Fade out editor + $('#mainContainer').fadeOut('slow', function() { + $('#mainContainer').remove(); + $('#odf-canvas').remove(); + $('.actions,#file_access_panel').fadeIn('slow'); + $('.documentslist, #emptyfolder').fadeIn('slow'); + $(document.body).removeClass('claro'); + }); +// }); }); }, loadDocuments: function () { diff --git a/js/editor/Editor.js b/js/editor/Editor.js index d6439a0b..22f2c637 100644 --- a/js/editor/Editor.js +++ b/js/editor/Editor.js @@ -36,28 +36,27 @@ define("webodf/editor/Editor", [ "dojo/i18n!webodf/editor/nls/myResources", "webodf/editor/EditorSession", - "webodf/editor/MemberList", + "webodf/editor/MemberListView", "dijit/layout/BorderContainer", "dijit/layout/ContentPane", "webodf/editor/widgets"], function (myResources, EditorSession, - MemberList, + MemberListView, BorderContainer, ContentPane, - loadWidgets) { + ToolBarTools) { "use strict"; + runtime.loadClass('odf.OdfCanvas'); + /** * @constructor - * @param {{networked:boolean=, - * memberid:!string, + * @param {{unstableFeaturesEnabled:boolean=, * loadCallback:function()=, * saveCallback:function()=, - * cursorAddedCallback:function(!string)=, - * cursorRemovedCallback:function(!string)=, - * registerCallbackForShutdown:function(!function())= }} args + * closeCallback:function()=, * @param {!ops.Server=} server * @param {!ServerFactory=} serverFactory */ @@ -65,26 +64,25 @@ define("webodf/editor/Editor", [ var self = this, // Private - memberid = args.memberid, session, editorSession, - memberList, - networked = args.networked === true, - opRouter, - memberModel, + memberListView, + toolbarTools, loadOdtFile = args.loadCallback, saveOdtFile = args.saveCallback, - cursorAddedHandler = args.cursorAddedCallback, - cursorRemovedHandler = args.cursorRemovedCallback, - registerCallbackForShutdown = args.registerCallbackForShutdown, - documentUrl, - odfCanvas; - - function translator(key, context) { - if (undefined === myResources[key]) { - return "translation missing: " + key; + close = args.closeCallback, + odfCanvas, + pendingMemberId, + pendingEditorReadyCallback; + + function getFileBlob(cbSuccess, cbError) { + var odfContainer = odfCanvas.odfContainer(); + + if (odfContainer) { + odfContainer.createByteArray(cbSuccess, cbError); + } else { + cbError("No odfContainer!"); } - return myResources[key]; } /** @@ -94,37 +92,188 @@ define("webodf/editor/Editor", [ * which will insert the the cursor. * * @param {!string} initialDocumentUrl + * @param {!string} memberId * @param {!function()} editorReadyCallback + * @return {undefined} */ - function initGuiAndDoc(initialDocumentUrl, editorReadyCallback) { - var odfElement, mainContainer, - editorPane, memberListPane, - inviteButton, - viewOptions = { - editInfoMarkersInitiallyVisible: networked, - caretAvatarsInitiallyVisible: networked, - caretBlinksOnRangeSelect: true - }, - memberListDiv = document.getElementById('memberList'); - - if (networked) { - runtime.assert(memberListDiv, "missing memberList div in HTML"); + function initDocLoading(initialDocumentUrl, memberId, editorReadyCallback) { + runtime.assert(initialDocumentUrl, "document should be defined here."); + runtime.assert(memberId !== undefined, "memberId should be defined here."); + runtime.assert(!pendingEditorReadyCallback, "pendingEditorReadyCallback should not exist here."); + runtime.assert(!editorSession, "editorSession should not exist here."); + runtime.assert(!session, "session should not exist here."); + + pendingMemberId = memberId; + pendingEditorReadyCallback = editorReadyCallback; + + odfCanvas.load(initialDocumentUrl); + odfCanvas.setEditable(false); + } + + + /** + * create the editor, load the starting document, + * call editorReadyCallback once everything is done. + * + * @param {!string} docUrl + * @param {!string} memberId + * @param {!function()} editorReadyCallback + * @return {undefined} + */ + this.loadDocument = function (docUrl, memberId, editorReadyCallback) { + initDocLoading(docUrl, memberId, editorReadyCallback); + }; + + /** + * @param {!string} filename + * @param {?function()} callback + * @return {undefined} + */ + this.saveDocument = function (filename, callback) { + function onsuccess(data) { + var mimebase = "application/vnd.oasis.opendocument.", + mimetype = mimebase + "text", + blob; + filename = filename || "doc.odt"; + if (filename.substr(-4) === ".odp") { + mimetype = mimebase + "presentation"; + } else if (filename.substr(-4) === ".ods") { + mimetype = mimebase + "spreadsheet"; + } + blob = new Blob([data.buffer], {type: mimetype}); + saveAs(blob, filename); + } + function onerror(error) { + alert(error); + } + + getFileBlob(onsuccess, onerror); + }; + + /** + * create the editor, load the starting document of an + * editing-session, request a replay of previous operations, call + * editorReadyCallback once everything is done. + * + * @param {!string} sessionId + * @param {!string} memberId + * @param {!function()} editorReadyCallback + * @return {undefined} + */ + this.loadSession = function (sessionId, memberId, editorReadyCallback) { + initDocLoading(server.getGenesisUrl(sessionId), memberId, function () { + var opRouter, memberModel; + // overwrite router and member model + // TODO: serverFactory should be a backendFactory, + // and there should be a backendFactory for local editing + opRouter = serverFactory.createOperationRouter(sessionId, memberId, server, odfCanvas.odfContainer()); + session.setOperationRouter(opRouter); + + memberModel = serverFactory.createMemberModel(sessionId, server); + session.setMemberModel(memberModel); + + opRouter.requestReplay(function done() { + editorReadyCallback(); + }); + + }); + }; + + /** + * Closes the current editing running editing (polling-timer), + * cleanup. + * @param {!function(!Object=)} callback, passing an error object in case of error + * @return {undefined} + */ + this.closeDocument = function (callback) { + runtime.assert(session, "session should exist here."); + if (memberListView) { + memberListView.setEditorSession(undefined); } + // TODO: there is a better pattern for this instead of unrolling + session.getOperationRouter().close(function(err) { + if (err) { + callback(err); + } else { + session.getMemberModel().close(function(err) { + if (err) { + callback(err); + } else { + editorSession.close(function(err) { + if (err) { + callback(err); + } else { + editorSession = undefined; + session.close(function(err) { + if (err) { + callback(err); + } else { + session = undefined; + callback(); + } + }); + } + }); + } + }); + } + }); + }; - runtime.loadClass('odf.OdfCanvas'); + /** + * Adds a cursor and enables the tools and allows modifications. + * Should be called inside/after editorReadyCallback. + * TODO: turn this and endEditing() into readonly switch + * @return {undefined} + */ + this.startEditing = function () { + runtime.assert(editorSession, "editorSession should exist here."); - // we might need it later - documentUrl = initialDocumentUrl; - runtime.assert(documentUrl, "document should be defined here."); + toolbarTools.setEditorSession(editorSession); + editorSession.sessionController.startEditing(); + }; - runtime.assert(memberid !== undefined, "memberid should be defined here."); + /** + * Removes the cursor and disables the tools and allows modifications. + * Should be called before closeDocument, if startEditing was called before + * @return {undefined} + */ + this.endEditing = function () { + runtime.assert(editorSession, "editorSession should exist here."); + + toolbarTools.setEditorSession(undefined); + editorSession.sessionController.endEditing(); + }; - odfElement = document.getElementById("canvas"); - runtime.assert(odfElement, "initGuiAndDoc failed to get odf canvas from html"); - odfCanvas = new odf.OdfCanvas(odfElement); - // make the canvas accessible to users of editor.js - self.odfCanvas = odfCanvas; + // init + function init() { + var mainContainer, + editorPane, memberListPane, + inviteButton, + canvasElement = document.getElementById("canvas"), + memberListElement = document.getElementById('memberList'), + collabEditing = Boolean(server), + directStylingEnabled = (! collabEditing) || args.unstableFeaturesEnabled, + // annotations not yet properly supported for OT + annotationsEnabled = (! collabEditing) || args.unstableFeaturesEnabled, + // undo manager is not yet integrated with collaboration + undoRedoEnabled = (! collabEditing), + closeCallback; + + if (collabEditing) { + runtime.assert(memberListElement, 'missing "memberList" div in HTML'); + } + runtime.assert(canvasElement, 'missing "canvas" div in HTML'); + + // setup translations + // TODO: move from document instance into webodf namespace + function translator(key, context) { + if (undefined === myResources[key]) { + return "translation missing: " + key; + } + return myResources[key]; + } document.translator = translator; function translateContent(node) { @@ -147,43 +296,6 @@ define("webodf/editor/Editor", [ } document.translateContent = translateContent; - odfCanvas.addListener("statereadychange", function () { - if (!editorReadyCallback) { - // already called once, restart session and return - // undo manager is not yet integrated with collaboration - if (! server) { - editorSession.sessionController.setUndoManager(new gui.TrivialUndoManager()); - } - editorSession.startEditing(); - return; - } - // Allow annotations - odfCanvas.enableAnnotations(true); - - session = new ops.Session(odfCanvas); - editorSession = new EditorSession(session, memberid, { - viewOptions: viewOptions - }); - // undo manager is not yet integrated with collaboration - if (! server) { - editorSession.sessionController.setUndoManager(new gui.TrivialUndoManager()); - } - - if (memberListDiv) { - memberList = new MemberList(editorSession, memberListDiv); - } - - if (registerCallbackForShutdown) { - registerCallbackForShutdown(editorSession.endEditing); - } - - loadWidgets(editorSession, loadOdtFile, saveOdtFile); - editorReadyCallback(); - editorReadyCallback = null; - }); - odfCanvas.load(initialDocumentUrl); - odfCanvas.setEditable(false); - // App Widgets mainContainer = new BorderContainer({}, 'mainContainer'); @@ -192,12 +304,13 @@ define("webodf/editor/Editor", [ }, 'editor'); mainContainer.addChild(editorPane); - if (networked && memberListDiv) { + if (collabEditing) { memberListPane = new ContentPane({ region: 'right', title: translator("members") }, 'members'); mainContainer.addChild(memberListPane); + memberListView = new MemberListView(memberListElement); } mainContainer.startup(); @@ -210,107 +323,48 @@ define("webodf/editor/Editor", [ inviteButton.onclick = window.inviteButtonProxy.clicked; } } - } - /** - * create the editor, load the starting document, - * call editorReadyCallback once everything is done. - * - * @param {!string} docUrl - * @param {!function()} editorReadyCallback - * @return {undefined} - */ - self.initAndLoadDocument = function (docUrl, editorReadyCallback) { - initGuiAndDoc(docUrl, function () { - editorReadyCallback(editorSession); - }); - }; + toolbarTools = new ToolBarTools({ + loadOdtFile: loadOdtFile, + saveOdtFile: saveOdtFile, + close: close, + directStylingEnabled: directStylingEnabled, + annotationsEnabled: annotationsEnabled, + undoRedoEnabled: undoRedoEnabled + }); - /** - * Shutdown running editing (polling-timer), - * cleanup. - */ - self.shutdown = function (successfullShutdownCallback) { - editorSession.endEditing(); - opRouter.shutdown(function() { - memberModel.shutdown(); - successfullShutdownCallback(); - }); - }; + odfCanvas = new odf.OdfCanvas(canvasElement); + odfCanvas.enableAnnotations(annotationsEnabled); - /** - * Load a document in an editor that has already been initialized. - */ - self.loadDocument = function (docUrl) { - self.shutdown(); - odfCanvas.load(docUrl); - }; + odfCanvas.addListener("statereadychange", function () { + var viewOptions = { + editInfoMarkersInitiallyVisible: collabEditing, + caretAvatarsInitiallyVisible: collabEditing, + caretBlinksOnRangeSelect: true + }; - /** - * @param {?function()} callback - * @return {undefined} - */ - self.saveDocument = function (filename, callback) { - function onsuccess(data) { - var mimebase = "application/vnd.oasis.opendocument.", - mimetype = mimebase + "text", - blob; - filename = filename || "doc.odt"; - if (filename.substr(-4) === ".odp") { - mimetype = mimebase + "presentation"; - } else if (filename.substr(-4) === ".ods") { - mimetype = mimebase + "spreadsheet"; + // create session around loaded document + session = new ops.Session(odfCanvas); + editorSession = new EditorSession(session, pendingMemberId, { + viewOptions: viewOptions + }); + if (undoRedoEnabled) { + editorSession.sessionController.setUndoManager(new gui.TrivialUndoManager()); } - blob = new Blob([data.buffer], {type: mimetype}); - saveAs(blob, filename); - } - function onerror(error) { - alert(error); - } - var doc = odfCanvas.odfContainer(); - doc.createByteArray(onsuccess, onerror); - }; - /** - * create the editor, load the starting document of an - * editing-session, request a replay of previous operations, call - * editorReadyCallback once everything is done. - * - * @param {!string} sessionId - * @param {?function()} editorReadyCallback - */ - self.loadSession = function (sessionId, editorReadyCallback) { - initGuiAndDoc(server.getGenesisUrl(sessionId), function () { - // get router and member model - opRouter = opRouter || serverFactory.createOperationRouter(sessionId, memberid, server); - session.setOperationRouter(opRouter); - - memberModel = memberModel || serverFactory.createMemberModel(sessionId, server); - session.setMemberModel(memberModel); - - opRouter.requestReplay(function done() { - var odtDocument = session.getOdtDocument(); - if (cursorAddedHandler) { - odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, function (cursor) { - cursorAddedHandler(cursor.getMemberId()); - }); - } - if (cursorRemovedHandler) { - odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, function (memberId) { - cursorRemovedHandler(memberId); - }); - } - - editorReadyCallback(editorSession); - }); + if (memberListView) { + memberListView.setEditorSession(editorSession); + } + // and report back to caller + pendingEditorReadyCallback(); + // reset + pendingEditorReadyCallback = null; + pendingMemberId = null; }); - }; + } - // access to member model - self.getMemberModel = function () { - return memberModel; - }; + init(); } return Editor; }); diff --git a/js/editor/EditorSession.js b/js/editor/EditorSession.js index 3da4bb27..0f2e1526 100644 --- a/js/editor/EditorSession.js +++ b/js/editor/EditorSession.js @@ -56,11 +56,11 @@ define("webodf/editor/EditorSession", [ /** * Instantiate a new editor session attached to an existing operation session * @param {!ops.Session} session - * @param {!string} memberid + * @param {!string} localMemberId * @param {{viewOptions:gui.SessionViewOptions}} config * @constructor */ - var EditorSession = function EditorSession(session, memberid, config) { + var EditorSession = function EditorSession(session, localMemberId, config) { var self = this, currentParagraphNode = null, currentNamedStyleName = null, @@ -80,7 +80,7 @@ define("webodf/editor/EditorSession", [ EditorSession.signalUndoStackChanged]); - this.sessionController = new gui.SessionController(session, memberid); + this.sessionController = new gui.SessionController(session, localMemberId); this.sessionView = new gui.SessionView(config.viewOptions, session, new gui.CaretManager(self.sessionController)); this.availableFonts = []; @@ -160,11 +160,11 @@ define("webodf/editor/EditorSession", [ function uniqueParagraphStyleNCName(name) { var result, i = 0, - ncMemberId = createNCName(memberid), + ncMemberId = createNCName(localMemberId), ncName = createNCName(name); // create default paragraph style - // memberid is used to avoid id conflicts with ids created by other members + // localMemberId is used to avoid id conflicts with ids created by other members result = ncName + "_" + ncMemberId; // then loop until result is really unique while (formatting.hasParagraphStyle(result)) { @@ -206,7 +206,7 @@ define("webodf/editor/EditorSession", [ odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, function (cursor) { // Emit 'cursorMoved' only when *I* am moving the cursor, not the other users - if (cursor.getMemberId() === memberid) { + if (cursor.getMemberId() === localMemberId) { self.emit(EditorSession.signalCursorMoved, cursor); } }); @@ -225,14 +225,6 @@ define("webodf/editor/EditorSession", [ odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, trackCurrentParagraph); - this.startEditing = function () { - self.sessionController.startEditing(); - }; - - this.endEditing = function () { - self.sessionController.endEditing(); - }; - /** * Call all subscribers for the given event with the specified argument * @param {!string} eventid @@ -251,6 +243,15 @@ define("webodf/editor/EditorSession", [ eventNotifier.subscribe(eventid, cb); }; + /** + * @param {!string} eventid + * @param {!Function} cb + * @return {undefined} + */ + this.unsubscribe = function (eventid, cb) { + eventNotifier.unsubscribe(eventid, cb); + }; + this.getMemberDetailsAndUpdates = function (memberId, subscriber) { return session.getMemberModel().getMemberDetailsAndUpdates(memberId, subscriber); }; @@ -260,11 +261,11 @@ define("webodf/editor/EditorSession", [ }; this.getCursorPosition = function () { - return odtDocument.getCursorPosition(memberid); + return odtDocument.getCursorPosition(localMemberId); }; this.getCursorSelection = function () { - return odtDocument.getCursorSelection(memberid); + return odtDocument.getCursorSelection(localMemberId); }; this.getOdfCanvas = function () { @@ -280,7 +281,7 @@ define("webodf/editor/EditorSession", [ }; this.isBold = function () { - var cursor = odtDocument.getCursor(memberid); + var cursor = odtDocument.getCursor(localMemberId); // no own cursor yet/currently added? if (!cursor) { return false; @@ -289,7 +290,7 @@ define("webodf/editor/EditorSession", [ }; this.isItalic = function () { - var cursor = odtDocument.getCursor(memberid); + var cursor = odtDocument.getCursor(localMemberId); // no own cursor yet/currently added? if (!cursor) { return false; @@ -298,7 +299,7 @@ define("webodf/editor/EditorSession", [ }; this.hasUnderline = function () { - var cursor = odtDocument.getCursor(memberid); + var cursor = odtDocument.getCursor(localMemberId); // no own cursor yet/currently added? if (!cursor) { return false; @@ -307,7 +308,7 @@ define("webodf/editor/EditorSession", [ }; this.hasStrikeThrough = function () { - var cursor = odtDocument.getCursor(memberid); + var cursor = odtDocument.getCursor(localMemberId); // no own cursor yet/currently added? if (!cursor) { return false; @@ -323,7 +324,7 @@ define("webodf/editor/EditorSession", [ var op = new ops.OpApplyDirectStyling(), selection = self.getCursorSelection(); op.init({ - memberid: memberid, + memberId: localMemberId, position: selection.position, length: selection.length, setProperties: value @@ -345,10 +346,10 @@ define("webodf/editor/EditorSession", [ length = Math.abs(length); op.init({ - memberid: memberid, + memberId: localMemberId, position: position, length: length, - name: memberid + Date.now() + name: localMemberId + Date.now() }); session.enqueue(op); }; @@ -358,7 +359,7 @@ define("webodf/editor/EditorSession", [ if (currentNamedStyleName !== value) { op = new ops.OpSetParagraphStyle(); op.init({ - memberid: memberid, + memberId: localMemberId, position: self.getCursorPosition(), styleName: value }); @@ -369,7 +370,7 @@ define("webodf/editor/EditorSession", [ this.insertTable = function (initialRows, initialColumns, tableStyleName, tableColumnStyleName, tableCellStyleMatrix) { var op = new ops.OpInsertTable(); op.init({ - memberid: memberid, + memberId: localMemberId, position: self.getCursorPosition(), initialRows: initialRows, initialColumns: initialColumns, @@ -409,7 +410,7 @@ define("webodf/editor/EditorSession", [ var op; op = new ops.OpUpdateParagraphStyle(); op.init({ - memberid: memberid, + memberId: localMemberId, styleName: styleName, setProperties: setProperties, removedProperties: (!removedProperties) ? {} : removedProperties @@ -447,7 +448,7 @@ define("webodf/editor/EditorSession", [ op = new ops.OpAddParagraphStyle(); op.init({ - memberid: memberid, + memberId: localMemberId, styleName: newStyleName, setProperties: setProperties }); @@ -460,7 +461,7 @@ define("webodf/editor/EditorSession", [ var op; op = new ops.OpRemoveParagraphStyle(); op.init({ - memberid: memberid, + memberId: localMemberId, styleName: styleName }); session.enqueue(op); @@ -528,6 +529,28 @@ define("webodf/editor/EditorSession", [ this.subscribe(EditorSession.signalCursorMoved, trackCursor); + /** + * @param {!function(!Object=)} callback, passing an error object in case of error + * @return {undefined} + */ + this.close = function(callback) { + self.sessionController.close(function(err) { + if (err) { + callback(err); + } else { + delete self.sessionController; + self.sessionView.close(function(err) { + if (err) { + callback(err); + } else { + delete self.sessionView; + callback(); + } + }); + } + }); + }; + function init() { var head = document.getElementsByTagName('head')[0], fontStyles = document.createElement('style'); @@ -548,7 +571,7 @@ define("webodf/editor/EditorSession", [ /**@const*/EditorSession.signalStyleCreated = "styleCreated"; /**@const*/EditorSession.signalStyleDeleted = "styleDeleted"; /**@const*/EditorSession.signalParagraphStyleModified = "paragraphStyleModified"; - /**@const*/EditorSession.signalUndoStackChanged = "signalUndoStackChanged"; + /**@const*/EditorSession.signalUndoStackChanged = "signalUndoStackChanged"; return EditorSession; }); diff --git a/js/editor/MemberList.js b/js/editor/MemberListView.js similarity index 76% rename from js/editor/MemberList.js rename to js/editor/MemberListView.js index cc18a5ad..fb0d84bf 100644 --- a/js/editor/MemberList.js +++ b/js/editor/MemberListView.js @@ -32,27 +32,27 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,runtime */ -define("webodf/editor/MemberList", +define("webodf/editor/MemberListView", ["webodf/editor/EditorSession"], function (EditorSession) { "use strict"; - return function MemberList(editorSession, memberListDiv) { - var self = this; - - editorSession.subscribe(EditorSession.signalMemberAdded, function (memberId) { - self.addMember(memberId); - }); + /** + * @param {!Element} memberListDiv + * @constructor + */ + return function MemberListView(memberListDiv) { + var editorSession = null; - editorSession.subscribe(EditorSession.signalMemberRemoved, function (memberId) { - self.removeMember(memberId); - }); + runtime.assert(memberListDiv, "memberListDiv unavailable"); /** * @param {!string} memberId + * @return {undefined} */ function updateAvatarButton(memberId, memberDetails) { var node = memberListDiv.firstChild; @@ -86,9 +86,9 @@ define("webodf/editor/MemberList", /** * @param {!string} memberId + * @return {undefined} */ function createAvatarButton(memberId) { - runtime.assert(memberListDiv, "memberListDiv unavailable"); var doc = memberListDiv.ownerDocument, htmlns = doc.documentElement.namespaceURI, avatarDiv = doc.createElementNS(htmlns, "div"), @@ -123,6 +123,7 @@ define("webodf/editor/MemberList", /** * @param {!string} memberId + * @return {undefined} */ function removeAvatarButton(memberId) { var node = memberListDiv.firstChild; @@ -137,18 +138,48 @@ define("webodf/editor/MemberList", /** * @param {!string} memberId + * @return {undefined} */ - this.addMember = function (memberId) { + function addMember(memberId) { createAvatarButton(memberId); editorSession.getMemberDetailsAndUpdates(memberId, updateAvatarButton); - }; + } /** * @param {!string} memberId + * @return {undefined} */ - this.removeMember = function (memberId) { + function removeMember(memberId) { editorSession.unsubscribeMemberDetailsUpdates(memberId, updateAvatarButton); removeAvatarButton(memberId); }; + + /** + * @param {!EditorSession} session + * @return {undefined} + */ + this.setEditorSession = function(session) { + var node = memberListDiv.firstChild, nextNode; + + if (editorSession) { + // remove all current avatars + while (node) { + nextNode = node.nextSibling; + if (node.memberId) { + editorSession.unsubscribeMemberDetailsUpdates(node.memberId, updateAvatarButton); + } + memberListDiv.removeChild(node); + node = nextNode; + } + // unsubscribe from old editorSession + editorSession.unsubscribe(EditorSession.signalMemberAdded, addMember); + editorSession.unsubscribe(EditorSession.signalMemberRemoved, removeMember); + } + editorSession = session; + if (editorSession) { + editorSession.subscribe(EditorSession.signalMemberAdded, addMember); + editorSession.subscribe(EditorSession.signalMemberRemoved, removeMember); + } + }; }; }); diff --git a/js/editor/SessionList.js b/js/editor/SessionList.js new file mode 100644 index 00000000..8000f648 --- /dev/null +++ b/js/editor/SessionList.js @@ -0,0 +1,65 @@ +/** + * @license + * Copyright (C) 2012-2013 KO GmbH + * + * @licstart + * The JavaScript code in this page 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. The code is distributed + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. + * + * As additional permission under GNU AGPL version 3 section 7, you + * may distribute non-source (e.g., minimized or compacted) forms of + * that code without the copy of the GNU GPL normally required by + * section 4, provided you include this license notice and a URL + * through which recipients can access the Corresponding Source. + * + * As a special exception to the AGPL, any HTML file which merely makes function + * calls to this code, and for that purpose includes it by reference shall be + * deemed a separate work for copyright law purposes. In addition, the copyright + * holders of this code give you permission to combine this code with free + * software libraries that are released under the GNU LGPL. You may copy and + * distribute such a system following the terms of the GNU AGPL for this code + * and the LGPL for the libraries. If you modify this code, you may extend this + * exception to your version of the code, but you are not obligated to do so. + * If you do not wish to do so, delete this exception statement from your + * version. + * + * This license applies to this entire compilation. + * @licend + * @source: http://www.webodf.org/ + * @source: http://gitorious.org/webodf/webodf/ + */ + +/*global ops, runtime */ + +/** + * A model which provides information about sessions. + * @interface + */ +SessionList = function SessionList() {"use strict"; }; + +/** + * @param {{onCreated:function(!Object), + * onUpdated:function(!Object), + * onRemoved:function(!string) }} subscriber + * @return {undefined} + */ +SessionList.prototype.getSessions = function (subscriber) {"use strict"; }; + +/** + * @param {{onCreated:function(!Object), + * onUpdated:function(!Object), + * onRemoved:function(!string) }} subscriber + * @return {undefined} + */ +SessionList.prototype.unsubscribe = function (subscriber) {"use strict"; }; + +/** + * Per default updates are enabled. + * @param {!boolean} enabled + * @return {undefined} + */ +SessionList.prototype.setUpdatesEnabled = function (enabled) {"use strict"; }; diff --git a/js/editor/SessionListView.js b/js/editor/SessionListView.js index d539ec49..961e9186 100644 --- a/js/editor/SessionListView.js +++ b/js/editor/SessionListView.js @@ -59,9 +59,6 @@ define("webodf/editor/SessionListView", [], function () { sessionDiv.sessionId = sessionDetails.id; // TODO: namespace? sessionDiv.style.cursor = "pointer"; // TODO: do not set on each element, use CSS sessionDiv.onclick = function () { - // HACK: stop pulling, so that does not mess up the logs - // Remove before merging to master - if (sessionList.stopPulling) { sessionList.stopPulling(); } cb(sessionDetails.id); }; diff --git a/js/editor/boot_editor.js b/js/editor/boot_editor.js deleted file mode 100644 index 9246e0bb..00000000 --- a/js/editor/boot_editor.js +++ /dev/null @@ -1,462 +0,0 @@ -/** - * Copyright (C) 2013 KO GmbH - * - * @licstart - * The JavaScript code in this page 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. The code is distributed - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - * - * As additional permission under GNU AGPL version 3 section 7, you - * may distribute non-source (e.g., minimized or compacted) forms of - * that code without the copy of the GNU GPL normally required by - * section 4, provided you include this license notice and a URL - * through which recipients can access the Corresponding Source. - * - * As a special exception to the AGPL, any HTML file which merely makes function - * calls to this code, and for that purpose includes it by reference shall be - * deemed a separate work for copyright law purposes. In addition, the copyright - * holders of this code give you permission to combine this code with free - * software libraries that are released under the GNU LGPL. You may copy and - * distribute such a system following the terms of the GNU AGPL for this code - * and the LGPL for the libraries. If you modify this code, you may extend this - * exception to your version of the code, but you are not obligated to do so. - * If you do not wish to do so, delete this exception statement from your - * version. - * - * This license applies to this entire compilation. - * @licend - * @source: http://www.webodf.org/ - * @source: http://gitorious.org/webodf/webodf/ - */ - -/* - * bootstrap the editor in different ways. - * this file is meant to be included from HTML and used - * by users who do not want to know much about the inner - * complexity. - * so we need to make it really easy. - * - * including this file will result in the namespace/object - * "webodfEditor" to be available from the HTML side. - * calling webodfEditor.boot() will start the editor. - * the method can also take some parameters to specify - * behaviour. see documentation of that method. - * - */ - -/*global runtime, require, document, alert, net, window, SessionListView, ops */ - -// define the namespace/object we want to provide -// this is the first line of API, the user gets. -var webodfEditor = (function () { - "use strict"; - - runtime.currentDirectory = function () { - return "../../webodf/lib"; - }; - runtime.libraryPaths = function () { - return [ runtime.currentDirectory() ]; - }; - - var editorInstance = null, - serverFactory = null, - server = null, - booting = false, - loadedFilename; - - /** - * wait for a network connection through nowjs to establish. - * call the callback when done, when finally failed, or - * when a timeout reached. - * the parameter to the callback is a string with the possible - * values: - * "unavailable", "timeout", "ready" - * - * @param {!function(!string)} callback - * @return {undefined} - */ - function connectNetwork(backend, callback) { - function createServer(ServerFactory) { - serverFactory = new ServerFactory(); - server = serverFactory.createServer(); - server.connect(8000, callback); - } - - switch (backend) { - case "pullbox": - require({ }, ["webodf/editor/server/pullbox/serverFactory"], createServer); - break; - case "nowjs": - require({ }, ["webodf/editor/server/nowjs/serverFactory"], createServer); - break; - case "owncloud": - require({ }, ["webodf/editor/server/pullbox/serverFactory"], function (ServerFactory) { - serverFactory = new ServerFactory(); - server = serverFactory.createServer({url: "./documents/ajax/otpoll.php"}); - server.getGenesisUrl = function(sid) { - // what a dirty hack :) - return OC.Router.generate('documents_genesis')+'/' +sid; - }; - server.connect(8000, callback); - }); - default: - callback("unavailable"); - } - } - - /** - * try to auto-sense the server-backend. - * - * NOT IMPLEMENTED / MIGHT BE NICE TO HAVE... - * for now: try to connect to pullbox backend - * - * @param {!function(!string)} callback - * @return {undefined} - */ - function detectNetwork(callback) { - connectNetwork("pullbox", callback); - } - - /** - * extract document url from the url-fragment - * - * @return {?string} - */ - function guessDocUrl() { - var pos, docUrl = String(document.location); - // If the URL has a fragment (#...), try to load the file it represents - pos = docUrl.indexOf('#'); - if (pos !== -1) { - docUrl = docUrl.substr(pos + 1); - } else { - docUrl = "welcome.odt"; - } - return docUrl || null; - } - - function fileSelectHandler(evt) { - var file, files, reader; - files = (evt.target && evt.target.files) || - (evt.dataTransfer && evt.dataTransfer.files); - function onloadend() { - if (reader.readyState === 2) { - runtime.registerFile(file.name, reader.result); - loadedFilename = file.name; - editorInstance.loadDocument(file.name); - } - } - if (files && files.length === 1) { - file = files[0]; - reader = new FileReader(); - reader.onloadend = onloadend; - reader.readAsArrayBuffer(file); - } else { - alert("File could not be opened in this browser."); - } - } - - function enhanceRuntime() { - var openedFiles = {}, - read = runtime.read, - getFileSize = runtime.getFileSize; - runtime.read = function (path, offset, length, callback) { - var array; - if (openedFiles.hasOwnProperty(path)) { - array = new Uint8Array(openedFiles[path], offset, length); - callback(undefined, array); - } else { - return read(path, offset, length, callback); - } - }; - runtime.getFileSize = function (path, callback) { - if (openedFiles.hasOwnProperty(path)) { - return callback(openedFiles[path].byteLength); - } else { - return getFileSize(path, callback); - } - }; - runtime.registerFile = function (path, data) { - openedFiles[path] = data; - }; - } - - function createFileLoadForm() { - var form = document.createElement("form"), - input = document.createElement("input"); - form.appendChild(input); - form.style.display = "none"; - input.id = "fileloader"; - input.setAttribute("type", "file"); - input.addEventListener("change", fileSelectHandler, false); - document.body.appendChild(form); - } - - function load() { - var form = document.getElementById("fileloader"); - if (!form) { - enhanceRuntime(); - createFileLoadForm(); - form = document.getElementById("fileloader"); - } - form.click(); - } - - function save() { - editorInstance.saveDocument(loadedFilename); - } - - /** - * create a new editor instance, and start the editor with - * the given document. - * - * @param {!string} docUrl - * @param {?Object} editorOptions - * @param {?function(!Object)} editorReadyCallback - */ - function createLocalEditor(docUrl, editorOptions, editorReadyCallback) { - var pos; - booting = true; - editorOptions = editorOptions || {}; - editorOptions.memberid = "localuser"; - editorOptions.loadCallback = load; - editorOptions.saveCallback = save; - - if (docUrl === undefined) { - docUrl = guessDocUrl(); - } - runtime.assert(docUrl, "docUrl needs to be specified"); - runtime.assert(editorInstance === null, "cannot boot with instanciated editor"); - - document.getElementById("mainContainer").style.display = ""; - - require({ }, ["webodf/editor/Editor"], - function (Editor) { - editorInstance = new Editor(editorOptions); - editorInstance.initAndLoadDocument(docUrl, function (editorSession) { - editorSession.startEditing(); - editorReadyCallback(editorInstance); - }); - } - ); - } - - /** - * assume the network connection is established, create a new editor instance, - * and start the editor on the network. - * - * @param {!string} sessionId - * @param {!string} memberId - * @param {?string} token - * @param {?Object} editorOptions - * @param {?function(!Object)} editorReadyCallback - */ - function createNetworkedEditor(sessionId, memberId, token, editorOptions, editorReadyCallback) { - - runtime.assert(sessionId, "sessionId needs to be specified"); - runtime.assert(memberId, "memberId needs to be specified"); - runtime.assert(editorInstance === null, "cannot boot with instanciated editor"); - - editorOptions = editorOptions || {}; - editorOptions.memberid = memberId; - editorOptions.networked = true; - editorOptions.networkSecurityToken = token; - - require({ }, ["webodf/editor/Editor"], - function (Editor) { - // TODO: the networkSecurityToken needs to be retrieved via now.login - // (but this is to be implemented later) - editorInstance = new Editor(editorOptions, server, serverFactory); - - // load the document and get called back when it's live - editorInstance.loadSession(sessionId, function (editorSession) { - editorSession.startEditing(); - editorReadyCallback(editorInstance); - }); - } - ); - } - - - /** - * start the login process by offering a login/password prompt. - * the login is validated via nowjs namespace. - * on success a list of sessions is offered. - * when the user selects a session the callback is called - * with the sessionId as parameter - * - * @param {!function(!string, !string, ?string)} callback - * @returns {undefined} - */ - function startLoginProcess(callback) { - var userid, token; - - booting = true; - - runtime.assert(editorInstance === null, "cannot boot with instanciated editor"); - - function enterSession(selectedSessionId) { - document.getElementById("sessionListContainer").style.display = "none"; - document.getElementById("mainContainer").style.display = ""; - - callback(selectedSessionId, userid, token); - } - - function showSessions() { - require({ }, ["webodf/editor/SessionListView"], - function (SessionListView) { - var sessionListDiv = document.getElementById("sessionList"), - sessionList = new serverFactory.createSessionList(server), - sessionListView = new SessionListView(sessionList, sessionListDiv, enterSession); - - // hide login view - document.getElementById("loginContainer").style.display = "none"; - - // show session list - document.getElementById("sessionListContainer").style.display = ""; - } - ); - } - - function loginSuccess(userData) { - runtime.log("connected:" + userData.full_name); - userid = userData.uid; - token = userData.securityToken || null; - - showSessions(); - } - - function loginFail(result) { - alert("Login failed: " + result); - } - - function onLoginSubmit() { - server.login(document.loginForm.login.value, document.loginForm.password.value, loginSuccess, loginFail); - - // block the submit button, we already dealt with the input - return false; - } - - // bring up the login form - document.loginForm.Submit.onclick = onLoginSubmit; - document.getElementById("loginContainer").style.display = ""; - } - - /** - * make a guess about the document (# in URL) - * also guess about local/collaborative (depending on nowjs) - * - * @param {?Object} args - * - * args: - * - * collaborative: if set to true: connect to the network and start a - * collaborative editor. in that case the document url - * is ignored. and user needs to select a session. - * - * if set to the string "auto": it will try the above - * but fall back to non-collaborative mode [default] - * - * docUrl: if given it is used as the url to the document to load - * - * callback: callback to be called as soon as the document is loaded - * - */ - function boot(args) { - var editorOptions = {}, - loginProcedure = startLoginProcess; - runtime.assert(!booting, "editor creation already in progress"); - - args = args || {}; - - if (args.collaborative === undefined) { - args.collaborative = "standalone"; - } else { - args.collaborative = String(args.collaborative).toLowerCase(); - } - - if (args.saveCallback) { - editorOptions.saveCallback = args.saveCallback; - } - if (args.cursorAddedCallback) { - editorOptions.cursorAddedCallback = args.cursorAddedCallback; - } - if (args.cursorRemovedCallback) { - editorOptions.cursorRemovedCallback = args.cursorRemovedCallback; - } - if (args.registerCallbackForShutdown) { - editorOptions.registerCallbackForShutdown = args.registerCallbackForShutdown; - } else { - editorOptions.registerCallbackForShutdown = function (callback) { - window.onunload = callback; - }; - } - - if (args.loginProcedure) { - loginProcedure = args.loginProcedure; - } - - // start the editor with network - function handleNetworkedSituation() { - var joinSession = server.joinSession; - - if (args.joinSession) { - joinSession = args.joinSession; - } - - loginProcedure(function (sessionId, userId, token) { - // if pre-authentication has happened: - if (token) { - server.setToken(token); - } - - joinSession(userId, sessionId, function(memberId) { - createNetworkedEditor(sessionId, memberId, token, editorOptions, function (ed) { - if (args.callback) { - args.callback(ed); - } - }); - }); - }); - } - - // start the editor without network - function handleNonNetworkedSituation() { - createLocalEditor(args.docUrl, editorOptions, function (editor) { - if (args.callback) { - args.callback(editor); - } - }); - } - - if (args.collaborative === "auto") { - runtime.log("detecting network..."); - detectNetwork(function (state) { - if (state === "ready") { - runtime.log("... network available."); - handleNetworkedSituation(); - } else { - runtime.log("... no network available (" + state + ")."); - handleNonNetworkedSituation(); - } - }); - } else if ((args.collaborative === "pullbox") || - (args.collaborative === "owncloud")) { - runtime.log("starting collaborative editor for ["+args.collaborative+"]."); - connectNetwork(args.collaborative, function (state) { - if (state === "ready") { - handleNetworkedSituation(); - } - }); - } else { - runtime.log("starting local editor."); - handleNonNetworkedSituation(); - } - } - - // exposed API - return { boot: boot }; -}()); - diff --git a/js/editor/nls/de/myResources.js b/js/editor/nls/de/myResources.js index 89faf0e4..1dd1c290 100644 --- a/js/editor/nls/de/myResources.js +++ b/js/editor/nls/de/myResources.js @@ -1,5 +1,6 @@ /** - * Copyright (C) 2012 KO GmbH + * @license + * Copyright (C) 2012-2013 KO GmbH * * @licstart * The JavaScript code in this page is free software: you can redistribute it @@ -31,14 +32,21 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + define({ // menus file: "Datei", + open: "Öffnen", save: "Speichern", edit: "Bearbeiten", view: "Ansicht", + annotate: "Kommentieren", + clone: "Kopiere", + create: "Erzeuge", + delete: "Entferne", insert: "Einfügen", format: "Formatieren", + close: "Schließe", character_DDD: "Zeichen...", paragraph_DDD: "Absatz...", // dialogs @@ -50,13 +58,12 @@ define({ textFlow: "Textfluß", character: "Zeichen", paragraphStyles: "Absatzstile", + cloneThisStyle: "Kopiere diesen Stil", + newName_C: "Neuer Name:", // Collaboration pane collaborationPane: "Zusammenarbeitsfeld", - people: "Leute", - chat: "Chat", - typeYourName_DDD: "Geben Sie Ihren Namen ein...", - invitePeople: "Leute einladen", - startTypingToChat_DDD: "Eingabe beginnen für Chat...", + members: "Teilnehmer", + inviteMembers: "Teilnehmer einladen", // Various left: "Links", right: "Rechts", @@ -67,6 +74,8 @@ define({ spacing: "Abstand", options: "Optionen", style: "Stil", + undo: "Rückgängig", + redo: "Wiederherstellen", bold: "Fett", italic: "Kursiv", underline: "Unterstrichen", diff --git a/js/editor/nls/myResources.js b/js/editor/nls/myResources.js index 64aef05d..6946907b 100644 --- a/js/editor/nls/myResources.js +++ b/js/editor/nls/myResources.js @@ -35,11 +35,17 @@ define({ root: { // menus file: "File", + open: "Open", save: "Save", edit: "Edit", view: "View", + annotate: "Annotate", + clone: "Clone", + create: "Create", + delete: "Delete", insert: "Insert", format: "Format", + close: "Close", character_DDD: "Character...", paragraph_DDD: "Paragraph...", // dialogs @@ -51,13 +57,12 @@ define({ textFlow: "Text Flow", character: "Character", paragraphStyles: "Paragraph Styles", + cloneThisStyle: "Clone this style", + newName_C: "New name:", // Collaboration pane collaborationPane: "Collaboration Pane", - people: "People", - chat: "Chat", - typeYourName_DDD: "Type your name...", - invitePeople: "Invite People", - startTypingToChat_DDD: "Start typing to chat...", + members: "Members", + inviteMembers: "Invite members", // Various left: "Left", right: "Right", @@ -68,6 +73,8 @@ define({ spacing: "Spacing", options: "Options", style: "Style", + undo: "Undo", + redo: "Redo", bold: "Bold", italic: "Italic", underline: "Underline", diff --git a/js/editor/server/nowjs/sessionList.js b/js/editor/server/nowjs/sessionList.js deleted file mode 100644 index 4b04d563..00000000 --- a/js/editor/server/nowjs/sessionList.js +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @license - * Copyright (C) 2012-2013 KO GmbH - * - * @licstart - * The JavaScript code in this page 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. The code is distributed - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - * - * As additional permission under GNU AGPL version 3 section 7, you - * may distribute non-source (e.g., minimized or compacted) forms of - * that code without the copy of the GNU GPL normally required by - * section 4, provided you include this license notice and a URL - * through which recipients can access the Corresponding Source. - * - * As a special exception to the AGPL, any HTML file which merely makes function - * calls to this code, and for that purpose includes it by reference shall be - * deemed a separate work for copyright law purposes. In addition, the copyright - * holders of this code give you permission to combine this code with free - * software libraries that are released under the GNU LGPL. You may copy and - * distribute such a system following the terms of the GNU AGPL for this code - * and the LGPL for the libraries. If you modify this code, you may extend this - * exception to your version of the code, but you are not obligated to do so. - * If you do not wish to do so, delete this exception statement from your - * version. - * - * This license applies to this entire compilation. - * @licend - * @source: http://www.webodf.org/ - * @source: http://gitorious.org/webodf/webodf/ - */ - -/*global define, ops, runtime */ - -define("webodf/editor/server/nowjs/sessionList", [], function () { - "use strict"; - - return function NowjsSessionList(nowjsServer) { - - var cachedSessionData = {}, - subscribers = []; - - function onSessionData(sessionData) { - var i, - isNew = ! cachedSessionData.hasOwnProperty(sessionData.id); - - // cache - cachedSessionData[sessionData.id] = sessionData; - runtime.log("get session data for:"+sessionData.title+", is new:"+isNew); - - for (i = 0; i < subscribers.length; i += 1) { - if (isNew) { - subscribers[i].onCreated(sessionData); - } else { - subscribers[i].onUpdated(sessionData); - } - } - } - - function onSessionRemoved(sessionId) { - var i; - - if (cachedSessionData.hasOwnProperty(sessionId)) { - delete cachedSessionData[sessionId]; - - for (i = 0; i < subscribers.length; i += 1) { - subscribers[i].onRemoved(sessionId); - } - } - } - - this.getSessions = function (subscriber) { - var i, - sessionList = []; - - if (subscriber) { - subscribers.push(subscriber); - } - - for (i in cachedSessionData) { - if (cachedSessionData.hasOwnProperty(i)) { - sessionList.push(cachedSessionData[i]); - } - } - - return sessionList; - }; - - this.unsubscribe = function (subscriber) { - var i; - - for (i=0; i + * + * @licstart + * The JavaScript code in this page 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. The code is distributed + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. + * + * As additional permission under GNU AGPL version 3 section 7, you + * may distribute non-source (e.g., minimized or compacted) forms of + * that code without the copy of the GNU GPL normally required by + * section 4, provided you include this license notice and a URL + * through which recipients can access the Corresponding Source. + * + * As a special exception to the AGPL, any HTML file which merely makes function + * calls to this code, and for that purpose includes it by reference shall be + * deemed a separate work for copyright law purposes. In addition, the copyright + * holders of this code give you permission to combine this code with free + * software libraries that are released under the GNU LGPL. You may copy and + * distribute such a system following the terms of the GNU AGPL for this code + * and the LGPL for the libraries. If you modify this code, you may extend this + * exception to your version of the code, but you are not obligated to do so. + * If you do not wish to do so, delete this exception statement from your + * version. + * + * This license applies to this entire compilation. + * @licend + * @source: http://www.webodf.org/ + * @source: http://gitorious.org/webodf/webodf/ + */ + +/*global runtime, ops*/ + +define("webodf/editor/server/pullbox/MemberModel", [], function () { + "use strict"; + + /** + * @constructor + * @implements ops.MemberModel + */ + return function PullBoxMemberModel(sessionId, server) { + + var cachedMemberData = {}, + memberDataSubscribers = {}, + isServerPullingActivated = false, + isServerPullingOpen = true, + serverPullingTimeoutId = null, + isInstantPullingRequested = false, + isPulling = false, + /**@const*/pullingIntervall = 20000; + + + /** + * @param {!Object} memberData + */ + function cacheMemberDatum(memberData) { + var subscribers, + i; + + // notify all subscribers who are interested in this data + subscribers = memberDataSubscribers[memberData.memberid]; + if (subscribers) { + // cache + cachedMemberData[memberData.memberid] = memberData; + + for (i = 0; i < subscribers.length; i += 1) { + subscribers[i](memberData.memberid, memberData); + } + } + } + + function pullMemberData() { + var i, + memberIds = Object.keys(memberDataSubscribers); + + if (!isServerPullingOpen || isPulling) { + return; + } + + // no more timeout or instant pull request in any case + serverPullingTimeoutId = null; + isInstantPullingRequested = false; + // set lock + isPulling = true; + + runtime.log("member-list request for : " + memberIds.join(",")); + + server.call({ + command: 'query_memberdata_list', + args: { + es_id: sessionId, + member_ids: memberIds + } + }, function(responseData) { + var response = /**@type {{memberdata_list:Array.<{uid,member_id,display_name,avatar_url,color}>}}*/(runtime.fromJson(responseData)), + memberDataList, + newMemberData, oldMemberData; + + // unlock + isPulling = false; + + // meanwhile closed/disactivated? + if (!isServerPullingOpen || !isServerPullingActivated) { + return; + } + + runtime.log("member-list reply: " + responseData); + + if (response.hasOwnProperty("memberdata_list")) { + + // add/update with all delivered memberdata + memberDataList = response.memberdata_list; + for (i = 0; i < memberDataList.length; i+=1) { + newMemberData = { + memberid: memberDataList[i].member_id, + fullname: memberDataList[i].display_name, + imageurl: memberDataList[i].avatar_url, + color: memberDataList[i].color + }; + + oldMemberData = cachedMemberData.hasOwnProperty(newMemberData.memberid) ? cachedMemberData[newMemberData.memberid] : null; + if (!oldMemberData || + oldMemberData.fullname !== newMemberData.fullname || + oldMemberData.imageurl !== newMemberData.imageurl || + oldMemberData.color !== newMemberData.color) { + cacheMemberDatum(newMemberData); + } + } + } else { + runtime.log("Meh, memberdata list broken: " + responseData); + } + + // trigger the next pulling + if (isInstantPullingRequested) { + pullMemberData(); + } else { + serverPullingTimeoutId = runtime.setTimeout(pullMemberData, pullingIntervall); + } + }); + } + + /** + * Activates the pulling + * @return {undefined} + */ + function pullNewMemberData() { + // cancel any running pulling timeout + if (serverPullingTimeoutId !== null) { + runtime.clearTimeout(serverPullingTimeoutId); + } + + isInstantPullingRequested = true; + isServerPullingActivated = true; + + pullMemberData(); + } + + /** + * Deactivates the pulling if there are no more subscribers + * @return {undefined} + */ + function deactivatePeriodicMemberDataPulling() { + var key; + + if (!isServerPullingActivated) { + return; + } + + // check if there is no more subscription + for(key in memberDataSubscribers) { + if (memberDataSubscribers.hasOwnProperty(key)) { + // still subscribers, cannot deactivate yet + return; + } + } + + isServerPullingActivated = false; + // cancel any running pulling timeout + if (serverPullingTimeoutId !== null) { + runtime.clearTimeout(serverPullingTimeoutId); + } + } + + /** + * callback is called as soon as the memberdata is available and after that + * on every memberdata update. + * a parameter `null` passed to the callback means that the member is finally + * not known. + * + * @param {!string} memberId + * @param {!function(!string, ?Object)} subscriber + * @return {undefined} + */ + this.getMemberDetailsAndUpdates = function (memberId, subscriber) { + var /**@type{Object}*/ + memberData = cachedMemberData[memberId], + subscribers = memberDataSubscribers[memberId] || [], + i; + memberDataSubscribers[memberId] = subscribers; + + runtime.assert(subscriber !== undefined, "missing callback"); + + // detect double subscription + for (i=0; i + * + * @licstart + * The JavaScript code in this page 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. The code is distributed + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. + * + * As additional permission under GNU AGPL version 3 section 7, you + * may distribute non-source (e.g., minimized or compacted) forms of + * that code without the copy of the GNU GPL normally required by + * section 4, provided you include this license notice and a URL + * through which recipients can access the Corresponding Source. + * + * As a special exception to the AGPL, any HTML file which merely makes function + * calls to this code, and for that purpose includes it by reference shall be + * deemed a separate work for copyright law purposes. In addition, the copyright + * holders of this code give you permission to combine this code with free + * software libraries that are released under the GNU LGPL. You may copy and + * distribute such a system following the terms of the GNU AGPL for this code + * and the LGPL for the libraries. If you modify this code, you may extend this + * exception to your version of the code, but you are not obligated to do so. + * If you do not wish to do so, delete this exception statement from your + * version. + * + * This license applies to this entire compilation. + * @licend + * @source: http://www.webodf.org/ + * @source: http://gitorious.org/webodf/webodf/ + */ + +/*global runtime, ops*/ + +define("webodf/editor/server/pullbox/OperationRouter", [], function () { + "use strict"; + + runtime.loadClass("ops.OperationTransformer"); + + /** + * route operations in a networked collaborative manner. + * + * incoming operations (from controller) are sent to a server, + * who will distribute them. + * + * incoming operations (from the server are played on the DOM. + */ + + /** + * @constructor + * @implements ops.OperationRouter + */ + return function PullBoxOperationRouter(sessionId, memberId, server, odfContainer) { + "use strict"; + + var operationFactory, + singleTimeCallbackOnCompleteServerOpSpecsPlay, + /**@type{function(!ops.Operation)}*/ + playbackFunction, + /**@type{?{active:!boolean}}*/ + pullingTimeOutFlag = null, + /**@type{!boolean}*/ + triggerPushingOpsActivated = false, + /**@type{!boolean}*/ + playUnplayedServerOpSpecsTriggered = false, + /**@type{!boolean}*/ + syncLock = false, + /**@type{!boolean}*/ + hasUnresolvableConflict = false, + /**@type{!boolean}*/ + syncingBlocked = false, + /** @type {!string} id of latest op stack state known on the server */ + lastServerSeq = "", + /** @type {!Array.} ops created since the last sync call to the server */ + unsyncedClientOpspecQueue = [], + /** @type {!Array.} ops created since the last sync call to the server */ + unplayedServerOpspecQueue = [], + /** @type {!Array.} ops created since the last sync call to the server */ + hasLocalUnsyncedOpsStateSubscribers = [], + /**@type{!boolean}*/ + hasLocalUnsyncedOps = false, + /**@type{!boolean} tells if any local ops have been modifying ops */ + hasPushedModificationOps = false, + operationTransformer = new ops.OperationTransformer(), + /**@const*/replayTime = 500, + /**@const*/pushingIntervall = 3000, + /**@const*/pullingIntervall = 8000; + + + function updateHasLocalUnsyncedOpsState() { + var i, + hasLocalUnsyncedOpsNow = (unsyncedClientOpspecQueue.length > 0); + + // no change? + if (hasLocalUnsyncedOps === hasLocalUnsyncedOpsNow) { + return; + } + + hasLocalUnsyncedOps = hasLocalUnsyncedOpsNow; + for (i=0; i} opspecs + * @return {!Array.} + */ + function compressOpSpecs(opspecs) { + var i, j, op, + result = []; + + i = 0; + while (i < opspecs.length) { + // use factory to create an instance, and playback! + op = operationFactory.create(opspecs[i]); + // is known op and can do merge? + if (op !== null && op.merge) { + // go over the following and try to merge them + for (j = i+1; j < opspecs.length; j += 1) { + if (!op.merge(opspecs[j])) { + break; + } +runtime.log("Merged: "+opspecs[i].optype+" with "+opspecs[j].optype); + } + // add the resulting op to the results + result.push(op.spec()); + // and continue with the one which could not be merged, or behind end + i = j; + } else { + // just pass on + result.push(opspecs[i]); + i += 1; + } + } +runtime.log("Merged: from "+opspecs.length+" to "+result.length+" specs"); + + return result; + } + + /** + * @return {undefined} + */ + function playUnplayedServerOpSpecs() { + /** + * @return {undefined} + */ + function doPlayUnplayedServerOpSpecs() { + var opspec, op, startTime; + + playUnplayedServerOpSpecsTriggered = false; + + // take start time + startTime = (new Date()).getTime(); + + // apply as much as possible in the given time + while (unplayedServerOpspecQueue.length > 0) { + // time over? + if ((new Date().getTime()) - startTime > replayTime) { + break; + } + + opspec = unplayedServerOpspecQueue.shift(); + + // use factory to create an instance, and playback! + op = operationFactory.create(opspec); + runtime.log(" op in: "+runtime.toJson(opspec)); + if (op !== null) { + playbackFunction(op); + } else { + runtime.log("ignoring invalid incoming opspec: " + opspec); + } + } + + // still unplayed opspecs? + if (unplayedServerOpspecQueue.length > 0) { + // let other events be handled. then continue + playUnplayedServerOpSpecsTriggered = true; + runtime.getWindow().setTimeout(doPlayUnplayedServerOpSpecs, 1); + } else { + // This is such a sad hack. But there is no other way for now to inject + // the callback after the initial replay. + if (singleTimeCallbackOnCompleteServerOpSpecsPlay) { + singleTimeCallbackOnCompleteServerOpSpecsPlay(); + singleTimeCallbackOnCompleteServerOpSpecsPlay = null; + } + } + } + + if (playUnplayedServerOpSpecsTriggered) { + return; + } + doPlayUnplayedServerOpSpecs(); + } + + /** + * @param {Array.} opspecs + * @return {undefined} + */ + function receiveOpSpecsFromNetwork(opspecs) { + // append to existing unplayed + unplayedServerOpspecQueue = unplayedServerOpspecQueue.concat(opspecs); + } + + /** + * Transforms the unsynced client ops and the server ops, + * applies the server ops after transformation + * @param {Array.} serverOpspecs + * @return {!boolean} + */ + function handleOpsSyncConflict(serverOpspecs) { + var i, + transformResult; + + if (! serverOpspecs) { + // TODO: proper error message, stop working + runtime.assert(false, "no opspecs received!"); + return false; + } // TODO: more checking of proper content in serverOpspecs + + transformResult = operationTransformer.transform(unsyncedClientOpspecQueue, /**@type{!Array.}*/(serverOpspecs)); + + if (!transformResult) { + return false; + } + + // store transformed server ops + for (i = 0; i < transformResult.opsB.length; i += 1) { + unplayedServerOpspecQueue.push(transformResult.opsB[i].spec()); + } + + // store opspecs of all transformed client opspecs + unsyncedClientOpspecQueue = []; + for (i = 0; i < transformResult.opsA.length; i += 1) { + unsyncedClientOpspecQueue.push(transformResult.opsA[i].spec()); + } + + return true; + } + + /** + * @return {undefined} + */ + function syncOps() { + function triggerPullingOps() { + var flag = {active: true}; + // provide flag globally + pullingTimeOutFlag = flag; + runtime.getWindow().setTimeout(function() { +runtime.log("Pulling activated:" + flag.active); + // remove our flag + pullingTimeOutFlag = null; + if (flag.active) { + syncOps(); + } + }, pullingIntervall); + } + + /** + * @return {undefined} + */ + function doSyncOps() { + var syncedClientOpspecs; + + if (syncLock || hasUnresolvableConflict) { + return; + } + // TODO: hack, remove + if (syncingBlocked) { + return; + } + + syncLock = true; + + // take specs from queue, if any + syncedClientOpspecs = unsyncedClientOpspecQueue; + unsyncedClientOpspecQueue = []; + + server.call({ + command: 'sync_ops', + args: { + es_id: sessionId, + member_id: memberId, + seq_head: String(lastServerSeq), + client_ops: syncedClientOpspecs + } + }, function(responseData) { + var shouldRetryInstantly = false, + response = /** @type{{result:string, head_seq:string, ops:Array.}} */(runtime.fromJson(responseData)); + + // TODO: hack, remove + if (syncingBlocked) { + return; + } + + runtime.log("sync-ops reply: " + responseData); + + // just new ops? + if (response.result === "new_ops") { + if (response.ops.length > 0) { + // no new locally in the meantime? + if (unsyncedClientOpspecQueue.length === 0) { + receiveOpSpecsFromNetwork(compressOpSpecs(response.ops)); + } else { + // transform server ops against new local ones and apply, + // transform and send new local ops to server + runtime.log("meh, have new ops locally meanwhile, have to do transformations."); + hasUnresolvableConflict = !handleOpsSyncConflict(compressOpSpecs(response.ops)); + } + // and note server state + lastServerSeq = response.head_seq; + } + } else if (response.result === "added") { + runtime.log("All added to server"); + // note server state + lastServerSeq = response.head_seq; + updateHasLocalUnsyncedOpsState(); + } else if (response.result === "conflict") { + // put the send ops back into the outgoing queue + unsyncedClientOpspecQueue = syncedClientOpspecs.concat(unsyncedClientOpspecQueue); + // transform server ops against new local ones and apply, + // transform and request new send new local ops to server + runtime.log("meh, server has new ops meanwhile, have to do transformations."); + hasUnresolvableConflict = !handleOpsSyncConflict(compressOpSpecs(response.ops)); + // and note server state + lastServerSeq = response.head_seq; + // try again instantly + if (!hasUnresolvableConflict) { + shouldRetryInstantly = true; + } + } else { + runtime.assert(false, "Unexpected result on sync-ops call: "+response.result); + } + + syncLock = false; + + if (hasUnresolvableConflict) { + // TODO: offer option to reload session automatically? + runtime.assert(false, + "Sorry to tell:\n" + + "we hit a pair of operations in a state which yet need to be supported for transformation against each other.\n" + + "Client disconnected from session, no further editing accepted.\n\n" + + "Please reconnect manually for now."); + } else { + if (shouldRetryInstantly) { + doSyncOps(); + } else { +runtime.log("Preparing next: " + (unsyncedClientOpspecQueue.length === 0)); + // prepare next sync + // nothing to push right now? + if (unsyncedClientOpspecQueue.length === 0) { + triggerPullingOps(); + } + } + playUnplayedServerOpSpecs(); + } + }); + } + doSyncOps(); + } + + function triggerPushingOps() { + if (syncLock || triggerPushingOpsActivated) { + return; + } + + triggerPushingOpsActivated = true; + // disable current pulling timeout + if (pullingTimeOutFlag) { + pullingTimeOutFlag.active = false; + } + + runtime.getWindow().setTimeout(function() { +runtime.log("Pushing activated"); + triggerPushingOpsActivated = false; + syncOps(); + }, pushingIntervall); + } + + this.requestReplay = function (done_cb) { + singleTimeCallbackOnCompleteServerOpSpecsPlay = done_cb; + syncOps(); + }; + + /** + * Sets the factory to use to create operation instances from operation specs. + * + * @param {!ops.OperationFactory} f + * @return {undefined} + */ + this.setOperationFactory = function (f) { + operationFactory = f; + operationTransformer.setOperationFactory(f); + }; + + /** + * Sets the method which should be called to apply operations. + * + * @param {!function(!ops.Operation)} playback_func + * @return {undefined} + */ + this.setPlaybackFunction = function (playback_func) { + playbackFunction = playback_func; + }; + + /** + * Brings the locally created operations into the game. + * + * @param {!ops.Operation} op + * @return {undefined} + */ + this.push = function (op) { + var timedOp, + opspec = op.spec(); + + if (hasUnresolvableConflict) { + return; + } + // TODO: should be an assert in the future + // there needs to be a flag telling that processing is happening, + // and thus any input should be dropped in the sessioncontroller + // ideally also have some UI element showing the processing state + if (unplayedServerOpspecQueue.length > 0) { + return; + } + + // note if any local ops modified TODO: find less fragile way, perhaps have the operationFactory check it? + hasPushedModificationOps = hasPushedModificationOps || !/^(AddCursor|RemoveCursor)$/.test(opspec.optype); + + // apply locally + opspec.timestamp = (new Date()).getTime(); + timedOp = operationFactory.create(opspec); + + playbackFunction(timedOp); + + // send to server + unsyncedClientOpspecQueue.push(opspec); + + triggerPushingOps(); + + updateHasLocalUnsyncedOpsState(); + }; + + /** + * Requests a gracefull shutdown of the Operation Router. + * Buffered operations shall be sent to the server. + * A callback is called on success. + */ + this.close = function (cb) { + function writeSessionStateToFile() { + function cbSuccess(fileData) { + server.writeSessionStateToFile(sessionId, memberId, lastServerSeq, fileData, cb); + }; + odfContainer.createByteArray(cbSuccess, cb); + } + + // TODO: hack, rather add callback to syncOps for success and properly close things + syncOps(); + runtime.getWindow().setTimeout(function() { + syncingBlocked = true; + if (hasPushedModificationOps) { + writeSessionStateToFile(); + } else { + cb(); + } + }, 2000); + }; + + this.getHasLocalUnsyncedOpsAndUpdates = function (subscriber) { + var i; + + // detect double subscription + for (i=0; i + * + * @licstart + * The JavaScript code in this page 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. The code is distributed + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. + * + * As additional permission under GNU AGPL version 3 section 7, you + * may distribute non-source (e.g., minimized or compacted) forms of + * that code without the copy of the GNU GPL normally required by + * section 4, provided you include this license notice and a URL + * through which recipients can access the Corresponding Source. + * + * As a special exception to the AGPL, any HTML file which merely makes function + * calls to this code, and for that purpose includes it by reference shall be + * deemed a separate work for copyright law purposes. In addition, the copyright + * holders of this code give you permission to combine this code with free + * software libraries that are released under the GNU LGPL. You may copy and + * distribute such a system following the terms of the GNU AGPL for this code + * and the LGPL for the libraries. If you modify this code, you may extend this + * exception to your version of the code, but you are not obligated to do so. + * If you do not wish to do so, delete this exception statement from your + * version. + * + * This license applies to this entire compilation. + * @licend + * @source: http://www.webodf.org/ + * @source: http://gitorious.org/webodf/webodf/ + */ + +/*global XMLHttpRequest, runtime, core, ops*/ + +define("webodf/editor/server/pullbox/Server", [], function () { + "use strict"; + + runtime.loadClass("core.Base64"); + runtime.loadClass("core.ByteArrayWriter"); + + /** + * @constructor + * @implements ops.Server + * @param {{url:string}} args + */ + return function PullBoxServer(args) { + + var self = this, + token, + base64 = new core.Base64(); + + args = args || {}; + args.url = args.url || "/WSER"; + args.sessionStateToFileUrl = args.sessionStateToFileUrl || "/SS2F" + + this.getGenesisUrl = function (sessionId) { + return "/session/" + sessionId + "/genesis"; + }; + + /** + * @param {!Object} message + * @param {!function(!string)} cb + * @return {undefined} + */ + function call(message, cb) { + var xhr = new XMLHttpRequest(), + byteArrayWriter = new core.ByteArrayWriter("utf8"), + messageString = JSON.stringify(message), + data; + + function handleResult() { + if (xhr.readyState === 4) { + if ((xhr.status < 200 || xhr.status >= 300) && xhr.status === 0) { + // report error + runtime.log("Status " + String(xhr.status) + ": " + + xhr.responseText || xhr.statusText); + } + cb(xhr.responseText); + } + } +runtime.log("Sending message to server: "+messageString); + // create body data for request from metadata and payload + byteArrayWriter.appendString(messageString); + // byteArrayWriter.appendByteArray(zipData); + data = byteArrayWriter.getByteArray(); + + // do the request + xhr.open('POST', args.url, true); + xhr.onreadystatechange = handleResult; + // ArrayBufferView will have an ArrayBuffer property, in WebKit, XHR can send() + // an ArrayBuffer, In Firefox, one must use sendAsBinary with a string + if (data.buffer && !xhr.sendAsBinary) { + data = data.buffer; // webkit supports sending an ArrayBuffer + } else { + // encode into a string, this works in FireFox >= 3 + data = runtime.byteArrayToString(data, "binary"); + } + try { + if (xhr.sendAsBinary) { + xhr.sendAsBinary(data); + } else { + xhr.send(data); + } + } catch (e) { + runtime.log("Problem with calling server: " + e + " " + data); + cb(e.message); + } + } + + this.call = call; + + this.getToken = function () { + return token; + }; + + /** + * for pre-authenticated use + */ + this.setToken = function (a_token) { + token = a_token; + }; + + + /*jslint unparam: true*/ + /** + * @param {!number} timeout in milliseconds + * @param {!function(!string)} callback + * @return {undefined} + */ + this.connect = function (timeout, callback) { + /* + var accumulatedWaitingTime = 0; + + // already tried connecting? + if (self.networkStatus() === "ready") { + return; + } + */ + callback("ready"); + }; + /*jslint unparam: false*/ + + /** + * @return {!string} + */ + this.networkStatus = function () { + return "ready"; + }; + + /** + * @param {!string} login + * @param {!string} password + * @param {function(!Object)} successCb + * @param {function(!string)} failCb + * @return {undefined} + */ + this.login = function (login, password, successCb, failCb) { + call({ + command: "login", + args: { + login: base64.toBase64(login), + password: base64.toBase64(password) + } + }, function(responseData) { + var response = /**@type {{token:string}}*/(runtime.fromJson(responseData)); + runtime.log("Login reply: " + responseData); + + if (response.hasOwnProperty("token")) { + token = response.token; + runtime.log("Caching token: " + self.getToken()); + successCb(response); + } else { + failCb(responseData); + } + }); + }; + + /** + * @param {!string} userId + * @param {!string} sessionId + * @param {!function(!string)} successCb + * @param {function()=} failCb + * @return {undefined} + */ + this.joinSession = function (userId, sessionId, successCb, failCb) { + call({ + command: "join_session", + args: { + user_id: userId, + es_id: sessionId + } + }, function(responseData) { + var response = /**@type {{success:string, member_id:string}}*/(runtime.fromJson(responseData)); + runtime.log("join_session reply: " + responseData); + + if (response.hasOwnProperty("success") && response.success) { + successCb(response.member_id); + } else { + if (failCb) { + failCb(); + } + } + }); + }; + + /** + * @param {!string} sessionId + * @param {!string} memberId + * @param {!function()} successCb + * @param {function()=} failCb + * @return {undefined} + */ + this.leaveSession = function (sessionId, memberId, successCb, failCb) { + call({ + command: "leave_session", + args: { + es_id: sessionId, + member_id: memberId + } + }, function(responseData) { + var response = /**@type {{success:string, member_id:string}}*/(runtime.fromJson(responseData)); + runtime.log("leave_session reply: " + responseData); + + if (response.hasOwnProperty("success") && response.success) { + successCb(); + } else { + if (failCb) { + failCb(); + } + } + }); + }; + + /** + * @param {!string} sessionId + * @param {!string} memberId + * @param {!string} seqHead + * @param {function()=} callback + * @return {undefined} + */ + this.writeSessionStateToFile = function(sessionId, memberId, seqHead, fileData, callback) { + // code copied from BrowserRuntime.writeFile and adapted + var xhr = new XMLHttpRequest(); + + function handleResult() { + if (xhr.readyState === 4) { + if (xhr.status === 0 && !xhr.responseText) {// TODO: check makes sense here as well? + // for local files there is no difference between missing + // and empty files, so empty files are considered as errors + runtime.log("File " + args.sessionStateToFileUrl + " is empty."); + } else if ((xhr.status >= 200 && xhr.status < 300) || + xhr.status === 0) { + // report success + runtime.log(null); + } else { + // report error + runtime.log("Status " + String(xhr.status) + ": " + + xhr.responseText || xhr.statusText); + } + callback(); + } + } + + // do the request + xhr.open('POST', args.sessionStateToFileUrl, true); + xhr.setRequestHeader("x-webodf-es_id", sessionId); + xhr.setRequestHeader("x-webodf-member_id", memberId); + xhr.setRequestHeader("x-webodf-seq_head", seqHead); + xhr.onreadystatechange = handleResult; + // ArrayBufferView will have an ArrayBuffer property, in WebKit, XHR can send() + // an ArrayBuffer, In Firefox, one must use sendAsBinary with a string + if (fileData.buffer && !xhr.sendAsBinary) { + fileData = fileData.buffer; // webkit supports sending an ArrayBuffer + } else { + // encode into a string, this works in FireFox >= 3 + fileData = runtime.byteArrayToString(fileData, "binary"); + } + try { + if (xhr.sendAsBinary) { + xhr.sendAsBinary(fileData); + } else { + xhr.send(fileData); + } + } catch (e) { + runtime.log("Problem with calling \"writeSessionStateToFile\" on server"); + callback(e.message); + } + }; + }; +}); diff --git a/js/editor/server/pullbox/serverFactory.js b/js/editor/server/pullbox/ServerFactory.js similarity index 78% rename from js/editor/server/pullbox/serverFactory.js rename to js/editor/server/pullbox/ServerFactory.js index fbac3f7b..5a67425a 100644 --- a/js/editor/server/pullbox/serverFactory.js +++ b/js/editor/server/pullbox/ServerFactory.js @@ -33,30 +33,29 @@ * @source: http://gitorious.org/webodf/webodf/ */ -/*global define, document, require, runtime, core, ops */ +/*global define, document, require, runtime, ops */ -define("webodf/editor/server/pullbox/serverFactory", [ - "webodf/editor/server/pullbox/sessionList"], - function (PullBoxSessionList) { +define("webodf/editor/server/pullbox/ServerFactory", [ + "webodf/editor/server/pullbox/Server", + "webodf/editor/server/pullbox/MemberModel", + "webodf/editor/server/pullbox/OperationRouter", + "webodf/editor/server/pullbox/SessionList"], + function (PullBoxServer, PullBoxMemberModel, PullBoxOperationRouter, PullBoxSessionList) { "use strict"; - runtime.loadClass("ops.PullBoxServer"); - runtime.loadClass("ops.PullBoxMemberModel"); - runtime.loadClass("ops.PullBoxOperationRouter"); - /** * @constructor * @implements ServerFactory */ return function PullBoxServerFactory() { this.createServer = function (args) { - return new ops.PullBoxServer(args); + return new PullBoxServer(args); }; - this.createOperationRouter = function (sid, mid, server) { - return new ops.PullBoxOperationRouter(sid, mid, server); + this.createOperationRouter = function (sid, mid, server, odfContainer) { + return new PullBoxOperationRouter(sid, mid, server, odfContainer); }; this.createMemberModel = function (sid, server) { - return new ops.PullBoxMemberModel(sid, server); + return new PullBoxMemberModel(sid, server); }; this.createSessionList = function (server) { return new PullBoxSessionList(server); diff --git a/js/editor/server/pullbox/sessionList.js b/js/editor/server/pullbox/SessionList.js similarity index 85% rename from js/editor/server/pullbox/sessionList.js rename to js/editor/server/pullbox/SessionList.js index db521758..c0b6b349 100644 --- a/js/editor/server/pullbox/sessionList.js +++ b/js/editor/server/pullbox/SessionList.js @@ -35,14 +35,13 @@ /*global define, ops, runtime */ -define("webodf/editor/server/pullbox/sessionList", [], function () { +define("webodf/editor/server/pullbox/SessionList", [], function () { "use strict"; return function PullBoxSessionList(server) { var cachedSessionData = {}, subscribers = [], - /** HACK: allow to stop pulling, so that does not mess up the logs - * Remove before merging to master */ + serverPullingTimeoutId = null, pullingActive = true; function onSessionData(sessionData) { @@ -75,7 +74,7 @@ define("webodf/editor/server/pullbox/sessionList", [], function () { } function pullSessionList() { - if (!pullingActive) { return; } + serverPullingTimeoutId = null; server.call({ command: "query_sessiondata_list" @@ -84,6 +83,11 @@ define("webodf/editor/server/pullbox/sessionList", [], function () { sessionList, i, unupdatedSessions = {}; + // stopped meanwhile? TODO: support for cancelling calls + if (!pullingActive) { + return; + } + runtime.log("query_sessiondata_list reply: " + responseData); if (response.hasOwnProperty("sessiondata_list")) { @@ -111,7 +115,7 @@ define("webodf/editor/server/pullbox/sessionList", [], function () { } // next update in 5 secs - runtime.getWindow().setTimeout(pullSessionList, 5000); + serverPullingTimeoutId = runtime.getWindow().setTimeout(pullSessionList, 5000); } else { runtime.log("Meh, sessionlist data broken: " + responseData); } @@ -150,8 +154,21 @@ define("webodf/editor/server/pullbox/sessionList", [], function () { subscribers.splice(i,1); }; - this.stopPulling = function () { - pullingActive = false; + this.setUpdatesEnabled = function (enabled) { + if (pullingActive === enabled) { + return; + } + + pullingActive = enabled; + if (pullingActive) { + pullSessionList(); + } else { + // cancel any running pulling timeout + if (serverPullingTimeoutId !== null) { + runtime.clearTimeout(serverPullingTimeoutId); + serverPullingTimeoutId = null; + } + } }; function init() { diff --git a/js/editor/widgets.js b/js/editor/widgets.js index f039431c..1dd95da6 100644 --- a/js/editor/widgets.js +++ b/js/editor/widgets.js @@ -31,122 +31,180 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,document,require */ + define("webodf/editor/widgets", [ + "dojo/ready", + "dijit/MenuItem", + "dijit/DropDownMenu", + "dijit/form/Button", + "dijit/form/DropDownButton", + "dijit/Toolbar", "webodf/editor/widgets/simpleStyles", "webodf/editor/widgets/undoRedoMenu", "webodf/editor/widgets/toolbarWidgets/currentStyle", "webodf/editor/widgets/paragraphStylesDialog", "webodf/editor/widgets/zoomSlider"], - function (SimpleStyles, UndoRedoMenu, CurrentStyle, ParagraphStylesDialog, ZoomSlider) { + function (ready, MenuItem, DropDownMenu, Button, DropDownButton, Toolbar, SimpleStyles, UndoRedoMenu, CurrentStyle, ParagraphStylesDialog, ZoomSlider) { "use strict"; - return function loadWidgets(editorSession, loadOdtFile, saveOdtFile) { - var translator = document.translator; - - // Menubar - require([ - "dojo/ready", - "dijit/MenuItem", - "dijit/DropDownMenu", - "dijit/form/Button", - "dijit/form/DropDownButton", - "dijit/Toolbar" - ], function (ready, MenuItem, DropDownMenu, Button, DropDownButton, Toolbar) { - ready(function () { - var loadButton, saveButton, dropDownMenu, menuButton, paragraphStylesMenuItem, dialog, toolbar, simpleStyles, currentStyle, zoomSlider, - undoRedoMenu, annotateButton; - - dropDownMenu = new DropDownMenu({}); - paragraphStylesMenuItem = new MenuItem({ - label: translator("paragraph_DDD") - }); - dropDownMenu.addChild(paragraphStylesMenuItem); - - dialog = new ParagraphStylesDialog(editorSession, function (dialog) { - paragraphStylesMenuItem.onClick = function () { - dialog.startup(); - dialog.show(); - }; - }); + return function ToolBarTools(args) { + var translator = document.translator, + loadOdtFile = args.loadOdtFile, + saveOdtFile = args.saveOdtFile, + close = args.close, + toolbar, + loadButton, saveButton, annotateButton, closeButton, + formatDropDownMenu, formatMenuButton, + paragraphStylesMenuItem, paragraphStylesDialog, simpleStyles, currentStyle, + zoomSlider, + undoRedoMenu, + editorSession; - // Toolbar - toolbar = new Toolbar({}, "toolbar"); + this.setEditorSession = function(session) { + editorSession = session; + if (undoRedoMenu) { + undoRedoMenu.setEditorSession(session); + } + if (simpleStyles) { + simpleStyles.setEditorSession(session); + } + if (currentStyle) { + currentStyle.setEditorSession(session); + } + if (zoomSlider) { + zoomSlider.setEditorSession(session); + } + if (paragraphStylesDialog) { + paragraphStylesDialog.setEditorSession(session); + } + }; - if (editorSession.hasUndoManager()) { - undoRedoMenu = new UndoRedoMenu(editorSession, function (widget) { - widget.placeAt(toolbar); - widget.startup(); - }); - } + // init + ready(function () { + toolbar = new Toolbar({}, "toolbar"); - // Simple Style Selector [B, I, U, S] - simpleStyles = new SimpleStyles(editorSession, function (widget) { + // Undo/Redo + if (args.undoRedoEnabled) { + undoRedoMenu = new UndoRedoMenu(function (widget) { widget.placeAt(toolbar); widget.startup(); }); + undoRedoMenu.setEditorSession(editorSession); + } - // Paragraph Style Selector - currentStyle = new CurrentStyle(editorSession, function (widget) { + if (args.directStylingEnabled) { + // Simple Style Selector [B, I, U, S] + simpleStyles = new SimpleStyles(function (widget) { widget.placeAt(toolbar); widget.startup(); }); + simpleStyles.setEditorSession(editorSession); + } - // Zoom Level Selector - zoomSlider = new ZoomSlider(editorSession, function (widget) { - widget.placeAt(toolbar); - widget.startup(); - }); + // Paragraph Style Selector + currentStyle = new CurrentStyle(function (widget) { + widget.placeAt(toolbar); + widget.startup(); + }); + currentStyle.setEditorSession(editorSession); - if (loadOdtFile) { - loadButton = new Button({ - label: translator('open'), - showLabel: false, - iconClass: 'dijitIcon dijitIconFolderOpen', - style: { - float: 'left' - }, - onClick: function () { - loadOdtFile(); - } - }); - loadButton.placeAt(toolbar); - } - if (saveOdtFile) { - saveButton = new Button({ - label: translator('save'), - showLabel: false, - iconClass: 'dijitEditorIcon dijitEditorIconSave', - style: { - float: 'left' - }, - onClick: function () { - saveOdtFile(); - } - }); - saveButton.placeAt(toolbar); - } + // Zoom Level Selector + zoomSlider = new ZoomSlider(function (widget) { + widget.placeAt(toolbar); + widget.startup(); + }); + zoomSlider.setEditorSession(editorSession); + + // Load + if (loadOdtFile) { + loadButton = new Button({ + label: translator('open'), + showLabel: false, + iconClass: 'dijitIcon dijitIconFolderOpen', + style: { + float: 'left' + }, + onClick: function () { + loadOdtFile(); + } + }); + loadButton.placeAt(toolbar); + } - menuButton = new DropDownButton({ - dropDown: dropDownMenu, - label: translator('format'), - iconClass: "dijitIconEditTask", + // Save + if (saveOdtFile) { + saveButton = new Button({ + label: translator('save'), + showLabel: false, + iconClass: 'dijitEditorIcon dijitEditorIconSave', style: { float: 'left' + }, + onClick: function () { + saveOdtFile(); } }); - menuButton.placeAt(toolbar); + saveButton.placeAt(toolbar); + } + + // Format menu + formatDropDownMenu = new DropDownMenu({}); + paragraphStylesMenuItem = new MenuItem({ + label: translator("paragraph_DDD") + }); + formatDropDownMenu.addChild(paragraphStylesMenuItem); + + paragraphStylesDialog = new ParagraphStylesDialog(function (dialog) { + paragraphStylesMenuItem.onClick = function () { + if (editorSession) { + dialog.startup(); + dialog.show(); + } + }; + }); + paragraphStylesDialog.setEditorSession(editorSession); + formatMenuButton = new DropDownButton({ + dropDown: formatDropDownMenu, + label: translator('format'), + iconClass: "dijitIconEditTask", + style: { + float: 'left' + } + }); + formatMenuButton.placeAt(toolbar); + + // Add annotation + if (args.annotationsEnabled) { annotateButton = new Button({ label: translator('annotate'), showLabel: false, iconClass: 'dijitIconBookmark', onClick: function () { - editorSession.addAnnotation(); + if (editorSession) { + editorSession.addAnnotation(); + } } }); annotateButton.placeAt(toolbar); - }); + } + + if (close) { + closeButton = new Button({ + label: translator('close'), + showLabel: false, + iconClass: 'dijitEditorIcon dijitEditorIconCancel', + style: { + float: 'right' + }, + onClick: function () { + close(); + } + }); + closeButton.placeAt(toolbar); + } }); }; diff --git a/js/editor/widgets/dialogWidgets/alignmentPane.js b/js/editor/widgets/dialogWidgets/alignmentPane.js index 798b698a..d0356588 100644 --- a/js/editor/widgets/dialogWidgets/alignmentPane.js +++ b/js/editor/widgets/dialogWidgets/alignmentPane.js @@ -1,5 +1,7 @@ /** + * @license * Copyright (C) 2013 KO GmbH + * * @licstart * The JavaScript code in this page is free software: you can redistribute it * and/or modify it under the terms of the GNU Affero General Public License @@ -30,14 +32,16 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global runtime,core,define,require,document,dijit */ runtime.loadClass("core.CSSUnits"); define("webodf/editor/widgets/dialogWidgets/alignmentPane", [], function () { "use strict"; - var AlignmentPane = function (editorSession, callback) { + var AlignmentPane = function (callback) { var self = this, + editorSession, contentPane, form; @@ -83,6 +87,10 @@ define("webodf/editor/widgets/dialogWidgets/alignmentPane", [], function () { } }; + this.setEditorSession = function(session) { + editorSession = session; + }; + function init(cb) { require([ "dojo", diff --git a/js/editor/widgets/dialogWidgets/fontEffectsPane.js b/js/editor/widgets/dialogWidgets/fontEffectsPane.js index 84cb330e..9394f032 100644 --- a/js/editor/widgets/dialogWidgets/fontEffectsPane.js +++ b/js/editor/widgets/dialogWidgets/fontEffectsPane.js @@ -1,5 +1,7 @@ /** + * @license * Copyright (C) 2013 KO GmbH + * * @licstart * The JavaScript code in this page is free software: you can redistribute it * and/or modify it under the terms of the GNU Affero General Public License @@ -30,12 +32,15 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global runtime,define,require,document,dijit */ + define("webodf/editor/widgets/dialogWidgets/fontEffectsPane", [], function () { "use strict"; - var FontEffectsPane = function (editorSession, callback) { + var FontEffectsPane = function (callback) { var self = this, + editorSession, contentPane, form, preview, @@ -148,10 +153,11 @@ define("webodf/editor/widgets/dialogWidgets/fontEffectsPane", [], function () { backgroundColorTB.set('value', value); }; - fontPicker = new FontPicker(editorSession, function (picker) { + fontPicker = new FontPicker(function (picker) { picker.widget().startup(); document.getElementById('fontPicker').appendChild(picker.widget().domNode); picker.widget().name = 'fontName'; + picker.setEditorSession(editorSession); }); // Automatically update preview when selections change @@ -184,6 +190,13 @@ define("webodf/editor/widgets/dialogWidgets/fontEffectsPane", [], function () { }); } + this.setEditorSession = function(session) { + editorSession = session; + if (fontPicker) { + fontPicker.setEditorSession(editorSession); + } + }; + init(function () { return callback(self); }); diff --git a/js/editor/widgets/paragraphStyles.js b/js/editor/widgets/paragraphStyles.js index cd9c6c7a..6d8bf205 100644 --- a/js/editor/widgets/paragraphStyles.js +++ b/js/editor/widgets/paragraphStyles.js @@ -1,5 +1,6 @@ /** - * Copyright (C) 2012 KO GmbH + * @license + * Copyright (C) 2012-2013 KO GmbH * * @licstart * The JavaScript code in this page is free software: you can redistribute it @@ -31,7 +32,9 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,require */ + define("webodf/editor/widgets/paragraphStyles", ["webodf/editor/EditorSession"], @@ -40,8 +43,9 @@ define("webodf/editor/widgets/paragraphStyles", /** * @constructor */ - var ParagraphStyles = function (editorSession, callback) { + var ParagraphStyles = function (callback) { var self = this, + editorSession, select; this.widget = function () { @@ -61,9 +65,14 @@ define("webodf/editor/widgets/paragraphStyles", this.onRemove = null; function populateStyles() { - var i, availableStyles, selectionList; + var i, selectionList, availableStyles; + + if (! select) { + return; + } + selectionList = []; - availableStyles = editorSession.getAvailableParagraphStyles(); + availableStyles = editorSession ? editorSession.getAvailableParagraphStyles() : []; for (i = 0; i < availableStyles.length; i += 1) { selectionList.push({ @@ -76,10 +85,34 @@ define("webodf/editor/widgets/paragraphStyles", select.addOption(selectionList); } + function addStyle(newStyleName) { + var stylens = "urn:oasis:names:tc:opendocument:xmlns:style:1.0", + newStyleElement = editorSession.getParagraphStyleElement(newStyleName); + + if (select) { + select.addOption({ + value: newStyleName, + label: newStyleElement.getAttributeNS(stylens, 'display-name') + }); + } + + if (self.onAdd) { + self.onAdd(newStyleName); + } + } + + function removeStyle(styleName) { + if (select) { + select.removeOption(styleName); + } + + if (self.onRemove) { + self.onRemove(styleName); + } + } + function init(cb) { require(["dijit/form/Select"], function (Select) { - var stylens = "urn:oasis:names:tc:opendocument:xmlns:style:1.0"; - select = new Select({ name: 'ParagraphStyles', maxHeight: 200, @@ -90,29 +123,24 @@ define("webodf/editor/widgets/paragraphStyles", populateStyles(); - editorSession.subscribe(EditorSession.signalStyleCreated, function (newStyleName) { - var newStyleElement = editorSession.getParagraphStyleElement(newStyleName); - select.addOption({ - value: newStyleName, - label: newStyleElement.getAttributeNS(stylens, 'display-name') - }); - - if (self.onAdd) { - self.onAdd(newStyleName); - } - }); - - editorSession.subscribe(EditorSession.signalStyleDeleted, function (styleName) { - select.removeOption(styleName); - - if (self.onRemove) { - self.onRemove(styleName); - } - }); return cb(); }); } + this.setEditorSession = function(session) { + if (editorSession) { + editorSession.unsubscribe(EditorSession.signalStyleCreated, addStyle); + editorSession.unsubscribe(EditorSession.signalStyleDeleted, removeStyle); + } + editorSession = session; + if (editorSession) { + editorSession.subscribe(EditorSession.signalStyleCreated, addStyle); + editorSession.subscribe(EditorSession.signalStyleDeleted, removeStyle); + populateStyles(); + } + }; + + // init init(function () { return callback(self); }); diff --git a/js/editor/widgets/paragraphStylesDialog.js b/js/editor/widgets/paragraphStylesDialog.js index 9e19552f..a7513d3f 100644 --- a/js/editor/widgets/paragraphStylesDialog.js +++ b/js/editor/widgets/paragraphStylesDialog.js @@ -1,5 +1,6 @@ /** - * Copyright (C) 2012 KO GmbH + * @license + * Copyright (C) 2012-2013 KO GmbH * * @licstart * The JavaScript code in this page is free software: you can redistribute it @@ -31,278 +32,300 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,require,document,dojo,dijit */ + define("webodf/editor/widgets/paragraphStylesDialog", [], function () { "use strict"; - function makeWidget(editorSession, callback) { - require([ - "dijit/Dialog", - "dijit/TooltipDialog", - "dijit/popup", - "dijit/layout/TabContainer", - "dijit/layout/ContentPane", - "dijit/form/Button", - "dijit/form/DropDownButton", - "dijit/form/RadioButton"], function (Dialog, TooltipDialog, popup, TabContainer, ContentPane, Button, DropDownButton, RadioButton) { - var i, - dialog, - translator = document.translator, - tabContainer, - alignmentPane, - fontEffectsPane, - stylePicker, - flowPane, - numberingPane, - tabsPane, - capsPane, - bordersPane, - backgroundPane, - indentsPane, - actionBar, - okButton, - cancelButton, - cloneButton, - deleteButton, - cloneTooltip, - cloneDropDown, - newStyleName = null, - /** - * Mapping of the properties from edit pane properties to the attributes of style:text-properties - * @const@type{Array.} - */ - textPropertyMapping = [ - { - propertyName: 'fontSize', - attributeName: 'fo:font-size', - unit: 'pt' - }, { - propertyName: 'fontName', - attributeName: 'style:font-name' - }, { - propertyName: 'color', - attributeName: 'fo:color' - }, { - propertyName: 'backgroundColor', - attributeName: 'fo:background-color' - }, { - propertyName: 'fontWeight', - attributeName: 'fo:font-weight' - }, { - propertyName: 'fontStyle', - attributeName: 'fo:font-style' - }, { - propertyName: 'underline', - attributeName: 'style:text-underline-style' - }, { - propertyName: 'strikethrough', - attributeName: 'style:text-line-through-style' - }], + return function ParagraphStylesDialog(callback) { + var editorSession, + dialog, + stylePicker, alignmentPane, fontEffectsPane; + + function makeWidget(callback) { + require([ + "dijit/Dialog", + "dijit/TooltipDialog", + "dijit/popup", + "dijit/layout/TabContainer", + "dijit/layout/ContentPane", + "dijit/form/Button", + "dijit/form/DropDownButton", + "dijit/form/RadioButton"], function (Dialog, TooltipDialog, popup, TabContainer, ContentPane, Button, DropDownButton, RadioButton) { + var i, + translator = document.translator, + tabContainer, + flowPane, + numberingPane, + tabsPane, + capsPane, + bordersPane, + backgroundPane, + indentsPane, + actionBar, + okButton, + cancelButton, + cloneButton, + deleteButton, + cloneTooltip, + cloneDropDown, + newStyleName = null, + /** + * Mapping of the properties from edit pane properties to the attributes of style:text-properties + * @const@type{Array.} + */ + textPropertyMapping = [ + { + propertyName: 'fontSize', + attributeName: 'fo:font-size', + unit: 'pt' + }, { + propertyName: 'fontName', + attributeName: 'style:font-name' + }, { + propertyName: 'color', + attributeName: 'fo:color' + }, { + propertyName: 'backgroundColor', + attributeName: 'fo:background-color' + }, { + propertyName: 'fontWeight', + attributeName: 'fo:font-weight' + }, { + propertyName: 'fontStyle', + attributeName: 'fo:font-style' + }, { + propertyName: 'underline', + attributeName: 'style:text-underline-style' + }, { + propertyName: 'strikethrough', + attributeName: 'style:text-line-through-style' + }], + /** + * Mapping of the properties from edit pane properties to the attributes of style:paragraph-properties + * @const@type{Array.} + */ + paragraphPropertyMapping = [ + { + propertyName: 'topMargin', + attributeName: 'fo:margin-top', + unit: 'mm' + }, { + propertyName: 'bottomMargin', + attributeName: 'fo:margin-bottom', + unit: 'mm' + }, { + propertyName: 'leftMargin', + attributeName: 'fo:margin-left', + unit: 'mm' + }, { + propertyName: 'rightMargin', + attributeName: 'fo:margin-right', + unit: 'mm' + }, { + propertyName: 'textAlign', + attributeName: 'fo:text-align' + }]; + /** - * Mapping of the properties from edit pane properties to the attributes of style:paragraph-properties - * @const@type{Array.} + * Sets attributes of a node by the properties of the object properties, + * based on the mapping defined in propertyMapping. + * @param {!Object} properties + * @param {!Array.} propertyMapping + * @return {undefined} */ - paragraphPropertyMapping = [ - { - propertyName: 'topMargin', - attributeName: 'fo:margin-top', - unit: 'mm' - }, { - propertyName: 'bottomMargin', - attributeName: 'fo:margin-bottom', - unit: 'mm' - }, { - propertyName: 'leftMargin', - attributeName: 'fo:margin-left', - unit: 'mm' - }, { - propertyName: 'rightMargin', - attributeName: 'fo:margin-right', - unit: 'mm' - }, { - propertyName: 'textAlign', - attributeName: 'fo:text-align' - }]; - - /** - * Sets attributes of a node by the properties of the object properties, - * based on the mapping defined in propertyMapping. - * @param {!Object} properties - * @param {!Array.} propertyMapping - * @return {undefined} - */ - function mappedProperties(properties, propertyMapping) { - var i, m, value, - result = {}; - for (i = 0; i < propertyMapping.length; i += 1) { - m = propertyMapping[i]; - value = properties[m.propertyName]; - // Set a value as the attribute of a node, if that value is defined. - // If there is a unit specified, it is suffixed to the value. - if (value !== undefined) { - result[m.attributeName] = (m.unit !== undefined) ? value + m.unit : value; + function mappedProperties(properties, propertyMapping) { + var i, m, value, + result = {}; + for (i = 0; i < propertyMapping.length; i += 1) { + m = propertyMapping[i]; + value = properties[m.propertyName]; + // Set a value as the attribute of a node, if that value is defined. + // If there is a unit specified, it is suffixed to the value. + if (value !== undefined) { + result[m.attributeName] = (m.unit !== undefined) ? value + m.unit : value; + } } + return result; } - return result; - } - - function accept() { - editorSession.updateParagraphStyle(stylePicker.value(), { - "style:paragraph-properties": mappedProperties(alignmentPane.value(), paragraphPropertyMapping), - "style:text-properties": mappedProperties(fontEffectsPane.value(), textPropertyMapping) - }); - dialog.hide(); - } + function accept() { + editorSession.updateParagraphStyle(stylePicker.value(), { + "style:paragraph-properties": mappedProperties(alignmentPane.value(), paragraphPropertyMapping), + "style:text-properties": mappedProperties(fontEffectsPane.value(), textPropertyMapping) + }); - function cancel() { - dialog.hide(); - } - - /** - * Creates and enqueues a paragraph-style cloning operation. - * Remembers the id of the created style in newStyleName, so the - * style picker can be set to it, once the operation has been applied. - * @param {!string} styleName id of the style to clone - * @param {!string} newStyleDisplayName display name of the new style - */ - function cloneStyle(styleName, newStyleDisplayName) { - newStyleName = editorSession.cloneParagraphStyle(styleName, newStyleDisplayName); - } + dialog.hide(); + } - function deleteStyle(styleName) { - editorSession.deleteStyle(styleName); - } - // Dialog - dialog = new Dialog({ - title: translator("paragraphStyles") - }); + function cancel() { + dialog.hide(); + } - cloneTooltip = new TooltipDialog({ - content: - '

Clone this style


' + - '

', - style: "width: 300px;" - }); - cloneButton = new Button({ - label: 'Create', - onClick: function () { - cloneStyle(stylePicker.value(), cloneTooltip.get('value').name); - cloneTooltip.reset(); - popup.close(cloneTooltip); + /** + * Creates and enqueues a paragraph-style cloning operation. + * Remembers the id of the created style in newStyleName, so the + * style picker can be set to it, once the operation has been applied. + * @param {!string} styleName id of the style to clone + * @param {!string} newStyleDisplayName display name of the new style + */ + function cloneStyle(styleName, newStyleDisplayName) { + newStyleName = editorSession.cloneParagraphStyle(styleName, newStyleDisplayName); } - }); - cloneTooltip.addChild(cloneButton); - cloneDropDown = new DropDownButton({ - label: 'Clone', - showLabel: false, - iconClass: 'dijitEditorIcon dijitEditorIconCopy', - dropDown: cloneTooltip, - style: "float: right; margin-bottom: 5px;" - }); - dialog.addChild(cloneDropDown, 1); - deleteButton = new Button({ - label: 'Delete', - showLabel: false, - iconClass: 'dijitEditorIcon dijitEditorIconDelete', - style: "float: right; margin-bottom: 5px;", - onClick: function () { - deleteStyle(stylePicker.value()); + function deleteStyle(styleName) { + editorSession.deleteStyle(styleName); } - }); - dialog.addChild(deleteButton, 2); + // Dialog + dialog = new Dialog({ + title: translator("paragraphStyles") + }); - // Tab Container - tabContainer = new TabContainer({ - style: "height: 100%; width: 100%;" - }); - dialog.addChild(tabContainer, 3); + cloneTooltip = new TooltipDialog({ + content: + '

'+translator("cloneThisStyle")+'


' + + '

', + style: "width: 300px;" + }); + cloneButton = new Button({ + label: translator("create"), + onClick: function () { + cloneStyle(stylePicker.value(), cloneTooltip.get('value').name); + cloneTooltip.reset(); + popup.close(cloneTooltip); + } + }); + cloneTooltip.addChild(cloneButton); + cloneDropDown = new DropDownButton({ + label: translator("clone"), + showLabel: false, + iconClass: 'dijitEditorIcon dijitEditorIconCopy', + dropDown: cloneTooltip, + style: "float: right; margin-bottom: 5px;" + }); + dialog.addChild(cloneDropDown, 1); - actionBar = dojo.create("div", { - "class": "dijitDialogPaneActionBar" - }); - okButton = new dijit.form.Button({ - label: translator("ok"), - onClick: accept - }).placeAt(actionBar); - cancelButton = new dijit.form.Button({ - label: translator("cancel"), - onClick: cancel - }).placeAt(actionBar); - dialog.domNode.appendChild(actionBar); + deleteButton = new Button({ + label: translator("delete"), + showLabel: false, + iconClass: 'dijitEditorIcon dijitEditorIconDelete', + style: "float: right; margin-bottom: 5px;", + onClick: function () { + deleteStyle(stylePicker.value()); + } + }); + dialog.addChild(deleteButton, 2); + // Tab Container + tabContainer = new TabContainer({ + style: "height: 100%; width: 100%;" + }); + dialog.addChild(tabContainer, 3); - require([ - "webodf/editor/widgets/paragraphStyles", - "webodf/editor/widgets/dialogWidgets/alignmentPane", - "webodf/editor/widgets/dialogWidgets/fontEffectsPane" - ], function (ParagraphStyles, AlignmentPane, FontEffectsPane) { - var p, a, f; + actionBar = dojo.create("div", { + "class": "dijitDialogPaneActionBar" + }); + okButton = new dijit.form.Button({ + label: translator("ok"), + onClick: accept + }).placeAt(actionBar); + cancelButton = new dijit.form.Button({ + label: translator("cancel"), + onClick: cancel + }).placeAt(actionBar); + dialog.domNode.appendChild(actionBar); - function openStyle(value) { - alignmentPane.setStyle(value); - fontEffectsPane.setStyle(value); - if (editorSession.isStyleUsed(editorSession.getParagraphStyleElement(value))) { - deleteButton.domNode.style.display = 'none'; - } else { - deleteButton.domNode.style.display = 'block'; - } - } - p = new ParagraphStyles(editorSession, function (paragraphStyles) { - stylePicker = paragraphStyles; - stylePicker.widget().startup(); - stylePicker.widget().domNode.style.float = "left"; - stylePicker.widget().domNode.style.width = "350px"; - stylePicker.widget().domNode.style.marginTop = "5px"; - dialog.addChild(stylePicker.widget(), 0); + require([ + "webodf/editor/widgets/paragraphStyles", + "webodf/editor/widgets/dialogWidgets/alignmentPane", + "webodf/editor/widgets/dialogWidgets/fontEffectsPane" + ], function (ParagraphStyles, AlignmentPane, FontEffectsPane) { + var p, a, f; - stylePicker.onAdd = function (name) { - if (newStyleName === name) { - stylePicker.setValue(name); - newStyleName = null; // reset 'flag' name + function openStyle(value) { + alignmentPane.setStyle(value); + fontEffectsPane.setStyle(value); + if (editorSession.isStyleUsed(editorSession.getParagraphStyleElement(value))) { + deleteButton.domNode.style.display = 'none'; + } else { + deleteButton.domNode.style.display = 'block'; } - }; + } - stylePicker.onRemove = function (name) { - // Set the first style name as current - stylePicker.setValue(stylePicker.widget().getOptions(0)); - }; + p = new ParagraphStyles(function (paragraphStyles) { + stylePicker = paragraphStyles; + stylePicker.widget().startup(); + stylePicker.widget().domNode.style.float = "left"; + stylePicker.widget().domNode.style.width = "350px"; + stylePicker.widget().domNode.style.marginTop = "5px"; + dialog.addChild(stylePicker.widget(), 0); - stylePicker.widget().onChange = openStyle; - }); - a = new AlignmentPane(editorSession, function (pane) { - alignmentPane = pane; - alignmentPane.widget().startup(); - tabContainer.addChild(alignmentPane.widget()); - }); - f = new FontEffectsPane(editorSession, function (pane) { - fontEffectsPane = pane; - fontEffectsPane.widget().startup(); - tabContainer.addChild(fontEffectsPane.widget()); + stylePicker.onAdd = function (name) { + if (newStyleName === name) { + stylePicker.setValue(name); + newStyleName = null; // reset 'flag' name + } + }; + + stylePicker.onRemove = function (name) { + // Set the first style name as current + stylePicker.setValue(stylePicker.widget().getOptions(0)); + }; + + stylePicker.widget().onChange = openStyle; + stylePicker.setEditorSession(editorSession); + }); + a = new AlignmentPane(function (pane) { + alignmentPane = pane; + alignmentPane.widget().startup(); + tabContainer.addChild(alignmentPane.widget()); + alignmentPane.setEditorSession(editorSession); + }); + f = new FontEffectsPane(function (pane) { + fontEffectsPane = pane; + fontEffectsPane.widget().startup(); + tabContainer.addChild(fontEffectsPane.widget()); + fontEffectsPane.setEditorSession(editorSession); + }); + + dialog.onShow = function () { + var currentStyle = editorSession.getCurrentParagraphStyle(); + // setting the stylepicker value if the style name is the same + // will not trigger onChange, so specifically open the style in + // the panes. + if (stylePicker.value() === currentStyle) { + openStyle(currentStyle); + } else { + stylePicker.setValue(currentStyle); + } + }; }); - dialog.onShow = function () { - var currentStyle = editorSession.getCurrentParagraphStyle(); - // setting the stylepicker value if the style name is the same - // will not trigger onChange, so specifically open the style in - // the panes. - if (stylePicker.value() === currentStyle) { - openStyle(currentStyle); - } else { - stylePicker.setValue(currentStyle); - } - }; - }); + tabContainer.startup(); - tabContainer.startup(); + return callback(dialog); + }); + } - return callback(dialog); - }); - } + this.setEditorSession = function(session) { + editorSession = session; + if (stylePicker) { + stylePicker.setEditorSession(session); + } + if (alignmentPane) { + alignmentPane.setEditorSession(session); + } + if (fontEffectsPane) { + fontEffectsPane.setEditorSession(session); + } + if (!editorSession && dialog) { // TODO: check show state + dialog.hide(); + } + }; - return function ParagraphStylesDialog(editorSession, callback) { - makeWidget(editorSession, function (dialog) { + // init + makeWidget(function (dialog) { return callback(dialog); }); }; diff --git a/js/editor/widgets/simpleStyles.js b/js/editor/widgets/simpleStyles.js index da8bfedf..6524bc7d 100644 --- a/js/editor/widgets/simpleStyles.js +++ b/js/editor/widgets/simpleStyles.js @@ -1,5 +1,6 @@ /** - * Copyright (C) 2012 KO GmbH + * @license + * Copyright (C) 2012-2013 KO GmbH * * @licstart * The JavaScript code in this page is free software: you can redistribute it @@ -31,113 +32,145 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,require,document */ + define("webodf/editor/widgets/simpleStyles", ["webodf/editor/EditorSession"], function (EditorSession) { "use strict"; - function makeWidget(editorSession, callback) { - require(["dijit/form/ToggleButton"], function (ToggleButton) { - var i, - widget = {}, - boldButton, - italicButton, - underlineButton, - strikethroughButton; + return function SimpleStyles(callback) { + var editorSession, + boldButton, + italicButton, + underlineButton, + strikethroughButton; - boldButton = new ToggleButton({ - label: document.translator('bold'), - showLabel: false, - checked: false, - iconClass: "dijitEditorIcon dijitEditorIconBold", - onChange: function (checked) { - var value = checked ? 'bold' : 'normal'; - editorSession.formatSelection({ - 'style:text-properties': { - 'fo:font-weight' : value + function makeWidget(callback) { + require(["dijit/form/ToggleButton"], function (ToggleButton) { + var i, + widget = {}; + + boldButton = new ToggleButton({ + label: document.translator('bold'), + showLabel: false, + checked: editorSession ? editorSession.isBold(): false, + iconClass: "dijitEditorIcon dijitEditorIconBold", + onChange: function (checked) { + var value = checked ? 'bold' : 'normal'; + if (editorSession) { + editorSession.formatSelection({ + 'style:text-properties': { + 'fo:font-weight' : value + } + }); } - }); - } - }); + } + }); - italicButton = new ToggleButton({ - label: document.translator('italic'), - showLabel: false, - checked: false, - iconClass: "dijitEditorIcon dijitEditorIconItalic", - onChange: function (checked) { - var value = checked ? 'italic' : 'normal'; - editorSession.formatSelection({ - 'style:text-properties': { - 'fo:font-style' : value + italicButton = new ToggleButton({ + label: document.translator('italic'), + showLabel: false, + checked: editorSession ? editorSession.isItalic(): false, + iconClass: "dijitEditorIcon dijitEditorIconItalic", + onChange: function (checked) { + var value = checked ? 'italic' : 'normal'; + if (editorSession) { + editorSession.formatSelection({ + 'style:text-properties': { + 'fo:font-style' : value + } + }); } - }); - } - }); - underlineButton = new ToggleButton({ - label: document.translator('underline'), - showLabel: false, - checked: false, - iconClass: "dijitEditorIcon dijitEditorIconUnderline", - onChange: function (checked) { - var value = checked ? 'solid' : 'none'; - editorSession.formatSelection({ - 'style:text-properties': { - 'style:text-underline-style' : value + } + }); + underlineButton = new ToggleButton({ + label: document.translator('underline'), + showLabel: false, + checked: editorSession ? editorSession.hasUnderline(): false, + iconClass: "dijitEditorIcon dijitEditorIconUnderline", + onChange: function (checked) { + var value = checked ? 'solid' : 'none'; + if (editorSession) { + editorSession.formatSelection({ + 'style:text-properties': { + 'style:text-underline-style' : value + } + }); } - }); - } - }); - strikethroughButton = new ToggleButton({ - label: document.translator('strikethrough'), - showLabel: false, - checked: false, - iconClass: "dijitEditorIcon dijitEditorIconStrikethrough", - onChange: function (checked) { - var value = checked ? 'solid' : 'none'; - editorSession.formatSelection({ - 'style:text-properties': { - 'style:text-line-through-style' : value + } + }); + strikethroughButton = new ToggleButton({ + label: document.translator('strikethrough'), + showLabel: false, + checked: editorSession ? editorSession.hasStrikeThrough(): false, + iconClass: "dijitEditorIcon dijitEditorIconStrikethrough", + onChange: function (checked) { + var value = checked ? 'solid' : 'none'; + if (editorSession) { + editorSession.formatSelection({ + 'style:text-properties': { + 'style:text-line-through-style' : value + } + }); } + } + }); + + widget.children = [boldButton, italicButton, underlineButton, strikethroughButton]; + widget.startup = function () { + widget.children.forEach(function (element) { + element.startup(); + }); + }; + + widget.placeAt = function (container) { + widget.children.forEach(function (element) { + element.placeAt(container); }); - } + return widget; + }; + + return callback(widget); }); - - function checkStyleButtons() { - // The 3rd parameter is false to avoid firing onChange when setting the value - // programmatically. + } + + function checkStyleButtons() { + // The 3rd parameter is false to avoid firing onChange when setting the value + // programmatically. + if (boldButton) { boldButton.set('checked', editorSession.isBold(), false); + } + if (italicButton) { italicButton.set('checked', editorSession.isItalic(), false); + } + if (underlineButton) { underlineButton.set('checked', editorSession.hasUnderline(), false); + } + if (strikethroughButton) { strikethroughButton.set('checked', editorSession.hasStrikeThrough(), false); } + } - editorSession.subscribe(EditorSession.signalCursorMoved, checkStyleButtons); - editorSession.subscribe(EditorSession.signalParagraphChanged, checkStyleButtons); - editorSession.subscribe(EditorSession.signalParagraphStyleModified, checkStyleButtons); - - widget.children = [boldButton, italicButton, underlineButton, strikethroughButton]; - widget.startup = function () { - widget.children.forEach(function (element) { - element.startup(); - }); - }; - - widget.placeAt = function (container) { - widget.children.forEach(function (element) { - element.placeAt(container); - }); - return widget; - }; - - return callback(widget); - }); - } + this.setEditorSession = function(session) { + if (editorSession) { + editorSession.unsubscribe(EditorSession.signalCursorMoved, checkStyleButtons); + editorSession.unsubscribe(EditorSession.signalParagraphChanged, checkStyleButtons); + editorSession.unsubscribe(EditorSession.signalParagraphStyleModified, checkStyleButtons); + } + editorSession = session; + if (editorSession) { + editorSession.subscribe(EditorSession.signalCursorMoved, checkStyleButtons); + editorSession.subscribe(EditorSession.signalParagraphChanged, checkStyleButtons); + editorSession.subscribe(EditorSession.signalParagraphStyleModified, checkStyleButtons); + checkStyleButtons(); + } + }; - return function SimpleStyles(editorSession, callback) { - makeWidget(editorSession, function (widget) { + // init + makeWidget(function (widget) { return callback(widget); }); }; diff --git a/js/editor/widgets/toolbarWidgets/currentStyle.js b/js/editor/widgets/toolbarWidgets/currentStyle.js index c3976d8b..328b159c 100644 --- a/js/editor/widgets/toolbarWidgets/currentStyle.js +++ b/js/editor/widgets/toolbarWidgets/currentStyle.js @@ -1,5 +1,6 @@ /** - * Copyright (C) 2012 KO GmbH + * @license + * Copyright (C) 2012-2013 KO GmbH * * @licstart * The JavaScript code in this page is free software: you can redistribute it @@ -31,35 +32,63 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define, require */ + define("webodf/editor/widgets/toolbarWidgets/currentStyle", ["webodf/editor/EditorSession"], function (EditorSession) { "use strict"; - function makeWidget(editorSession, callback) { - require(["webodf/editor/widgets/paragraphStyles"], function (ParagraphStyles) { - var paragraphStyles, widget; - paragraphStyles = new ParagraphStyles(editorSession, function (pStyles) { - // if the current paragraph style changes, update the widget - editorSession.subscribe(EditorSession.signalParagraphChanged, function (info) { - if (info.type === 'style') { - pStyles.widget().set("value", info.styleName); - } - }); + return function CurrentStyle(callback) { + var editorSession, + paragraphStyles; + + function selectParagraphStyle(info) { + if (paragraphStyles) { + if (info.type === 'style') { + paragraphStyles.widget().set("value", info.styleName); + } + } + } + + function setParagraphStyle(value) { + if (editorSession) { + editorSession.setCurrentParagraphStyle(value); + } + } - pStyles.widget().onChange = function (value) { - editorSession.setCurrentParagraphStyle(value); - }; + function makeWidget(callback) { + require(["webodf/editor/widgets/paragraphStyles"], function (ParagraphStyles) { + var p; - return callback(pStyles.widget()); + p = new ParagraphStyles(function (pStyles) { + paragraphStyles = pStyles; + + paragraphStyles.widget().onChange = setParagraphStyle; + + paragraphStyles.setEditorSession(editorSession); + return callback(paragraphStyles.widget()); + }); }); - }); - } + } + + this.setEditorSession = function(session) { + if (editorSession) { + editorSession.unsubscribe(EditorSession.signalParagraphChanged, selectParagraphStyle); + } + editorSession = session; + if (paragraphStyles) { + paragraphStyles.setEditorSession(editorSession); + } + if (editorSession) { + editorSession.subscribe(EditorSession.signalParagraphChanged, selectParagraphStyle); + // TODO: selectParagraphStyle(editorSession.getCurrentParagraphStyle()); + } + }; - return function CurrentStyle(editorSession, callback) { - makeWidget(editorSession, function (widget) { + makeWidget(function (widget) { return callback(widget); }); }; diff --git a/js/editor/widgets/undoRedoMenu.js b/js/editor/widgets/undoRedoMenu.js index 280b1284..7014074b 100644 --- a/js/editor/widgets/undoRedoMenu.js +++ b/js/editor/widgets/undoRedoMenu.js @@ -1,5 +1,6 @@ /** - * Copyright (C) 2012 KO GmbH + * @license + * Copyright (C) 2012-2013 KO GmbH * * @licstart * The JavaScript code in this page is free software: you can redistribute it @@ -31,66 +32,88 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,require,document */ + define("webodf/editor/widgets/undoRedoMenu", ["webodf/editor/EditorSession"], function (EditorSession) { "use strict"; - function makeWidget(editorSession, callback) { - require(["dijit/form/Button"], function (Button) { - var widget = {}, - undoButton, - redoButton; + return function UndoRedoMenu(callback) { + var editorSession, + undoButton, + redoButton; - undoButton = new Button({ - label: document.translator('undo'), - showLabel: false, - disabled: true, - iconClass: "dijitEditorIcon dijitEditorIconUndo", - onClick: function () { - editorSession.undo(); - } - }); + function makeWidget(callback) { + require(["dijit/form/Button"], function (Button) { + var widget = {}; + + undoButton = new Button({ + label: document.translator('undo'), + showLabel: false, + disabled: true, // TODO: get current session state + iconClass: "dijitEditorIcon dijitEditorIconUndo", + onClick: function () { + if (editorSession) { + editorSession.undo(); + } + } + }); - redoButton = new Button({ - label: document.translator('redo'), - showLabel: false, - disabled: true, - iconClass: "dijitEditorIcon dijitEditorIconRedo", - onClick: function () { - editorSession.redo(); - } + redoButton = new Button({ + label: document.translator('redo'), + showLabel: false, + disabled: true, // TODO: get current session state + iconClass: "dijitEditorIcon dijitEditorIconRedo", + onClick: function () { + if (editorSession) { + editorSession.redo(); + } + } + }); + + widget.children = [undoButton, redoButton]; + widget.startup = function () { + widget.children.forEach(function (element) { + element.startup(); + }); + }; + + widget.placeAt = function (container) { + widget.children.forEach(function (element) { + element.placeAt(container); + }); + return widget; + }; + + return callback(widget); }); + } - function checkUndoButtons(e) { + function checkUndoButtons(e) { + if (undoButton) { undoButton.set('disabled', e.undoAvailable === false); + } + if (redoButton) { redoButton.set('disabled', e.redoAvailable === false); } + } - editorSession.subscribe(EditorSession.signalUndoStackChanged, checkUndoButtons); - - widget.children = [undoButton, redoButton]; - widget.startup = function () { - widget.children.forEach(function (element) { - element.startup(); - }); - }; - - widget.placeAt = function (container) { - widget.children.forEach(function (element) { - element.placeAt(container); - }); - return widget; - }; - - return callback(widget); - }); - } + this.setEditorSession = function(session) { + if (editorSession) { + editorSession.unsubscribe(EditorSession.signalUndoStackChanged, checkUndoButtons); + } + editorSession = session; + if (editorSession) { + editorSession.subscribe(EditorSession.signalUndoStackChanged, checkUndoButtons); + // TODO: checkUndoButtons(editorSession.getundoredoavailablalalo()); + } + }; - return function UndoRedoMenu(editorSession, callback) { - makeWidget(editorSession, function (widget) { + // init + makeWidget(function (widget) { return callback(widget); }); }; diff --git a/js/editor/widgets/zoomSlider.js b/js/editor/widgets/zoomSlider.js index 15024f55..09d8b383 100644 --- a/js/editor/widgets/zoomSlider.js +++ b/js/editor/widgets/zoomSlider.js @@ -1,6 +1,7 @@ /** - * Copyright (C) 2012 KO GmbH - + * @license + * Copyright (C) 2012-2013 KO GmbH + * * @licstart * The JavaScript code in this page is free software: you can redistribute it * and/or modify it under the terms of the GNU Affero General Public License @@ -31,39 +32,51 @@ * @source: http://www.webodf.org/ * @source: http://gitorious.org/webodf/webodf/ */ + /*global define,require,document */ + define("webodf/editor/widgets/zoomSlider", [], function () { "use strict"; - function makeWidget(editorSession, callback) { - require(["dijit/form/HorizontalSlider", "dijit/form/NumberTextBox", "dojo"], function (HorizontalSlider, NumberTextBox, dojo) { - var widget = {}, - canvas; - widget = new HorizontalSlider({ - name: 'zoomSlider', - value: 100, - minimum: 30, - maximum: 150, - discreteValues: 100, - intermediateChanges: true, - style: { - width: '150px', - height: '25px', - float: 'right' - } - }); + return function ZoomSlider(callback) { + var editorSession, + slider; - canvas = dojo.byId('canvas'); - widget.onChange = function (value) { - editorSession.getOdfCanvas().setZoomLevel(value / 100.0); - }; + function makeWidget(callback) { + require(["dijit/form/HorizontalSlider", "dijit/form/NumberTextBox", "dojo"], function (HorizontalSlider, NumberTextBox, dojo) { + var widget = {}; - return callback(widget); - }); - } + slider = new HorizontalSlider({ + name: 'zoomSlider', + value: 100, + minimum: 30, + maximum: 150, + discreteValues: 100, + intermediateChanges: true, + style: { + width: '150px', + height: '25px', + float: 'right' + } + }); + + slider.onChange = function (value) { + if (editorSession) { + editorSession.getOdfCanvas().setZoomLevel(value / 100.0); + } + }; + + return callback(slider); + }); + } + + this.setEditorSession = function(session) { + editorSession = session; +// if (slider) { slider.setValue(editorSession.getOdfCanvas().getZoomLevel() ); TODO! + }; - return function ZoomSlider(editorSession, callback) { - makeWidget(editorSession, function (widget) { + // init + makeWidget(function (widget) { return callback(widget); }); }; diff --git a/js/webodf-debug.js b/js/webodf-debug.js index c8fb1edd..48d46837 100644 --- a/js/webodf-debug.js +++ b/js/webodf-debug.js @@ -3037,7 +3037,6 @@ core.DomUtils = function DomUtils() { } this.rangesIntersect = rangesIntersect; function getNodesInRange(range, nodeFilter) { - runtime.assert(Boolean(range.startContainer), "Expected to get a range with a startContainer in getNodesInRange()."); var document = range.startContainer.ownerDocument, elements = [], root = (range.commonAncestorContainer), n, treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ALL, nodeFilter, false); treeWalker.currentNode = range.startContainer; n = range.startContainer; @@ -3084,7 +3083,6 @@ core.DomUtils = function DomUtils() { } this.normalizeTextNodes = normalizeTextNodes; function rangeContainsNode(limits, node) { - runtime.assert(Boolean(node), "Expected to get a node in rangeContainsNode()"); var range = node.ownerDocument.createRange(), nodeLength = node.nodeType === Node.TEXT_NODE ? node.length : node.childNodes.length, result; range.setStart(limits.startContainer, limits.startOffset); range.setEnd(limits.endContainer, limits.endOffset); @@ -5691,7 +5689,6 @@ xmldom.XPath = function() { return nodelist } function getODFElementsWithXPath(node, xpath, namespaceResolver) { - runtime.assert(Boolean(node), "Expected to get a node in getODFElementsWithXPath()"); var doc = node.ownerDocument, nodes, elements = [], n = null; if(!doc || !doc.evaluate) { elements = fallback(node, xpath, namespaceResolver) @@ -5747,7 +5744,6 @@ xmldom.XPath = function() { @source: http://gitorious.org/webodf/webodf/ */ gui.AnnotationViewManager = function AnnotationViewManager(odfCanvas, odfFragment, annotationsPane) { - runtime.assert(Boolean(odfFragment), "Expected to get an odfFragment"); var annotations = [], doc = odfFragment.ownerDocument, odfUtils = new odf.OdfUtils, CONNECTOR_MARGIN = 30, NOTE_MARGIN = 20, window = runtime.getWindow(); runtime.assert(Boolean(window), "Expected to be run in an environment which has a global window, like a browser."); function wrapAnnotation(annotation) { @@ -5837,6 +5833,17 @@ gui.AnnotationViewManager = function AnnotationViewManager(odfCanvas, odfFragmen } } } + function showAnnotationsPane(show) { + var sizer = odfCanvas.getSizer(); + if(show) { + annotationsPane.style.display = "inline-block"; + sizer.style.paddingRight = window.getComputedStyle(annotationsPane).width + }else { + annotationsPane.style.display = "none"; + sizer.style.paddingRight = 0 + } + odfCanvas.refreshSize() + } function sortAnnotations() { annotations.sort(function(a, b) { if(a.node.compareDocumentPosition(b.node) === Node.DOCUMENT_POSITION_FOLLOWING) { @@ -5853,6 +5860,7 @@ gui.AnnotationViewManager = function AnnotationViewManager(odfCanvas, odfFragmen } this.rerenderAnnotations = rerenderAnnotations; function addAnnotation(annotation) { + showAnnotationsPane(true); annotations.push({node:annotation.node, end:annotation.end}); sortAnnotations(); wrapAnnotation(annotation); @@ -5869,6 +5877,9 @@ gui.AnnotationViewManager = function AnnotationViewManager(odfCanvas, odfFragmen if(index !== -1) { annotations.splice(index, 1) } + if(annotations.length === 0) { + showAnnotationsPane(false) + } } function forgetAnnotations() { while(annotations.length) { @@ -6593,7 +6604,6 @@ odf.OdfUtils = function OdfUtils() { return Boolean(getParagraphElement(textNode) && (!isODFWhitespace(textNode.textContent) || isSignificantWhitespace(textNode, 0))) } function getTextNodes(range, includePartial) { - runtime.assert(Boolean(range.startContainer), "Expected to get a range with a startContainer in getTextNodes()."); var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), textNodes; function nodeFilter(node) { nodeRange.selectNodeContents(node); @@ -6616,7 +6626,6 @@ odf.OdfUtils = function OdfUtils() { } this.getTextNodes = getTextNodes; this.getTextElements = function(range, includeInsignificantWhitespace) { - runtime.assert(Boolean(range.startContainer), "Expected to get a range with a startContainer in getTextElements()."); var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), elements; function nodeFilter(node) { var nodeType = node.nodeType; @@ -6643,7 +6652,6 @@ odf.OdfUtils = function OdfUtils() { return elements }; this.getParagraphElements = function(range) { - runtime.assert(Boolean(range.startContainer), "Expected to get a range with a startContainer in getParagraphElements()."); var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), elements; function nodeFilter(node) { nodeRange.selectNodeContents(node); @@ -6915,10 +6923,11 @@ odf.Style2CSS = function Style2CSS() { "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"]], 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}, fontFaceDeclsMap = {}, utils = new odf.OdfUtils, documentType, odfRoot, defaultFontSize, xpath = new xmldom.XPath, cssUnits = new core.CSSUnits; + "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}, fontFaceDeclsMap = {}, utils = new odf.OdfUtils, documentType, odfRoot, defaultFontSize, xpath = new xmldom.XPath, cssUnits = new core.CSSUnits; function getStyleMap(stylesnode) { var stylemap = {}, node, name, family, style; if(!stylesnode) { @@ -8563,7 +8572,7 @@ odf.OdfCanvas = function() { listenEvent(element, "keyup", checkSelection); listenEvent(element, "keydown", checkSelection) } - 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, xmlns = odf.Namespaces.xmlns, presentationns = odf.Namespaces.presentationns, window = runtime.getWindow(), xpath = new xmldom.XPath, utils = new odf.OdfUtils, domUtils = new core.DomUtils, shadowContent, annotationsPane, allowAnnotations = + 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, xmlns = odf.Namespaces.xmlns, presentationns = odf.Namespaces.presentationns, window = runtime.getWindow(), xpath = new xmldom.XPath, utils = new odf.OdfUtils, domUtils = new core.DomUtils, shadowContent, sizer, annotationsPane, allowAnnotations = false, annotationManager; function clear(element) { while(element.firstChild) { @@ -9026,7 +9035,7 @@ odf.OdfCanvas = function() { } } function fixContainerSize() { - var sizer = element.firstChild, odfdoc = sizer.firstChild; + var odfdoc = sizer.firstChild; if(!odfdoc) { return } @@ -9049,12 +9058,11 @@ odf.OdfCanvas = function() { element.style.height = Math.round(zoomLevel * sizer.offsetHeight) + "px" } function handleContent(container, odfnode) { - var css = positioncss.sheet, sizer; + var css = positioncss.sheet; clear(element); sizer = doc.createElementNS(element.namespaceURI, "div"); sizer.style.display = "inline-block"; sizer.style.background = "white"; - sizer.id = "sizer"; sizer.appendChild(odfnode); element.appendChild(sizer); annotationsPane = doc.createElementNS(element.namespaceURI, "div"); @@ -9077,11 +9085,9 @@ odf.OdfCanvas = function() { fixContainerSize() } function handleAnnotations(odfnode) { - var sizer = doc.getElementById("sizer"); if(allowAnnotations) { if(!annotationsPane.parentNode) { sizer.appendChild(annotationsPane); - sizer.style.paddingRight = window.getComputedStyle(annotationsPane).width; fixContainerSize() } if(annotationManager) { @@ -9092,7 +9098,6 @@ odf.OdfCanvas = function() { }else { if(annotationsPane.parentNode) { sizer.removeChild(annotationsPane); - sizer.style.paddingRight = 0; annotationManager.forgetAnnotations(); fixContainerSize() } @@ -9249,10 +9254,15 @@ odf.OdfCanvas = function() { annotationManager.rerenderAnnotations() } }; + this.getSizer = function() { + return sizer + }; this.enableAnnotations = function(allow) { if(allow !== allowAnnotations) { allowAnnotations = allow; - handleAnnotations(odfcontainer.rootElement) + if(odfcontainer) { + handleAnnotations(odfcontainer.rootElement) + } } }; this.addAnnotation = function(annotation) { @@ -9396,210 +9406,9 @@ ops.Server.prototype.login = function(login, password, successCb, failCb) { }; ops.Server.prototype.joinSession = function(userId, sessionId, successCb, failCb) { }; -ops.Server.prototype.getGenesisUrl = function(sessionId) { +ops.Server.prototype.leaveSession = function(sessionId, memberId, successCb, failCb) { }; -/* - - Copyright (C) 2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -ops.NowjsServer = function NowjsServer() { - var nowObject; - this.getNowObject = function() { - return nowObject - }; - this.getGenesisUrl = function(sessionId) { - return"/session/" + sessionId + "/genesis" - }; - this.connect = function(timeout, callback) { - var accumulatedWaitingTime = 0; - if(nowObject) { - return - } - nowObject = runtime.getVariable("now"); - if(nowObject === undefined) { - nowObject = {networkStatus:"unavailable"} - } - function laterCb() { - if(nowObject.networkStatus === "unavailable") { - runtime.log("connection to server unavailable."); - callback("unavailable"); - return - } - if(nowObject.networkStatus !== "ready") { - if(accumulatedWaitingTime > timeout) { - runtime.log("connection to server timed out."); - callback("timeout"); - return - } - accumulatedWaitingTime += 100; - runtime.getWindow().setTimeout(laterCb, 100) - }else { - runtime.log("connection to collaboration server established."); - callback("ready") - } - } - laterCb() - }; - this.networkStatus = function() { - return nowObject ? nowObject.networkStatus : "unavailable" - }; - this.login = function(login, password, successCb, failCb) { - if(!nowObject) { - failCb("Not connected to server") - }else { - nowObject.login(login, password, successCb, failCb) - } - }; - this.joinSession = function(userId, sessionId, successCb, failCb) { - nowObject.joinSession(userId, sessionId, function(memberId) { - nowObject.memberid = memberId; - successCb(memberId) - }, failCb) - } -}; -/* - - Copyright (C) 2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -runtime.loadClass("core.Base64"); -runtime.loadClass("core.ByteArrayWriter"); -ops.PullBoxServer = function PullBoxServer(args) { - var self = this, token, base64 = new core.Base64; - args = args || {}; - args.url = args.url || "/WSER"; - this.getGenesisUrl = function(sessionId) { - return"/session/" + sessionId + "/genesis" - }; - function call(message, cb) { - var xhr = new XMLHttpRequest, byteArrayWriter = new core.ByteArrayWriter("utf8"), messageString = JSON.stringify(message), data; - function handleResult() { - if(xhr.readyState === 4) { - if((xhr.status < 200 || xhr.status >= 300) && xhr.status === 0) { - runtime.log("Status " + String(xhr.status) + ": " + xhr.responseText || xhr.statusText) - } - cb(xhr.responseText) - } - } - runtime.log("Sending message to server: " + messageString); - byteArrayWriter.appendString(messageString); - data = byteArrayWriter.getByteArray(); - xhr.open("POST", args.url, true); - xhr.onreadystatechange = handleResult; - if(data.buffer && !xhr.sendAsBinary) { - data = data.buffer - }else { - data = runtime.byteArrayToString(data, "binary") - } - try { - if(xhr.sendAsBinary) { - xhr.sendAsBinary(data) - }else { - xhr.send(data) - } - }catch(e) { - runtime.log("Problem with calling server: " + e + " " + data); - cb(e.message) - } - } - this.call = call; - this.getToken = function() { - return token - }; - this.setToken = function(a_token) { - token = a_token - }; - this.connect = function(timeout, callback) { - callback("ready") - }; - this.networkStatus = function() { - return"ready" - }; - this.login = function(login, password, successCb, failCb) { - call({command:"login", args:{login:base64.toBase64(login), password:base64.toBase64(password)}}, function(responseData) { - var response = (runtime.fromJson(responseData)); - runtime.log("Login reply: " + responseData); - if(response.hasOwnProperty("token")) { - token = response.token; - runtime.log("Caching token: " + self.getToken()); - successCb(response) - }else { - failCb(responseData) - } - }) - }; - this.joinSession = function(userId, sessionId, successCb, failCb) { - call({command:"join_session", args:{user_id:userId, es_id:sessionId}}, function(responseData) { - var response = (runtime.fromJson(responseData)); - runtime.log("join_session reply: " + responseData); - if(response.hasOwnProperty("success") && response.success) { - successCb(response.member_id) - }else { - if(failCb) { - failCb() - } - } - }) - } +ops.Server.prototype.getGenesisUrl = function(sessionId) { }; /* @@ -11538,7 +11347,6 @@ runtime.loadClass("core.PositionFilter"); runtime.loadClass("core.LoopWatchDog"); runtime.loadClass("odf.OdfUtils"); gui.SelectionMover = function SelectionMover(cursor, rootNode) { - runtime.assert(Boolean(rootNode), "Expected to get a rootNode for gui.SelectionMover."); var odfUtils, positionIterator, cachedXOffset, timeoutHandle, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT; function getIteratorAtCursor() { positionIterator.setUnfilteredPosition(cursor.getNode(), 0); @@ -12479,7 +12287,8 @@ runtime.loadClass("gui.KeyboardHandler"); runtime.loadClass("gui.StyleHelper"); gui.SessionController = function() { gui.SessionController = function SessionController(session, inputMemberId) { - var window = (runtime.getWindow()), odtDocument = session.getOdtDocument(), domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils, clipboard = new gui.Clipboard, clickHandler = new gui.ClickHandler, keyDownHandler = new gui.KeyboardHandler, keyPressHandler = new gui.KeyboardHandler, styleHelper = new gui.StyleHelper(odtDocument.getFormatting()), keyboardMovementsFilter = new core.PositionFilterChain, baseFilter = odtDocument.getPositionFilter(), undoManager = null; + var window = (runtime.getWindow()), odtDocument = session.getOdtDocument(), domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils, clipboard = new gui.Clipboard, clickHandler = new gui.ClickHandler, keyDownHandler = new gui.KeyboardHandler, keyPressHandler = new gui.KeyboardHandler, styleHelper = new gui.StyleHelper(odtDocument.getFormatting()), keyboardMovementsFilter = new core.PositionFilterChain, baseFilter = odtDocument.getPositionFilter(), clickStartedWithinContainer = false, undoManager = + null; runtime.assert(window !== null, "Expected to be run in an environment which has a global window, like a browser."); keyboardMovementsFilter.addFilter("BaseFilter", baseFilter); keyboardMovementsFilter.addFilter("RootFilter", odtDocument.createRootFilter(inputMemberId)); @@ -12641,6 +12450,9 @@ gui.SessionController = function() { session.enqueue(op) } function selectRange(e) { + if(!clickStartedWithinContainer) { + return + } runtime.setTimeout(function() { var selection = getSelection(e), oldPosition, stepsToAnchor, stepsToFocus, op; if(selection === null) { @@ -12662,39 +12474,46 @@ gui.SessionController = function() { function handleContextMenu(e) { selectRange(e) } + function isTextSpan(node) { + return node.namespaceURI === odf.Namespaces.textns && node.localName === "span" + } function selectWord() { - var canvasElement = odtDocument.getOdfCanvas().getElement(), alphaNumeric = /[A-Za-z0-9]/, stepsToStart = 0, stepsToEnd = 0, iterator, cursorNode, oldPosition, currentNode, i, c, op; + var canvasElement = odtDocument.getOdfCanvas().getElement(), alphaNumeric = /[A-Za-z0-9]/, stepsToStart = 0, stepsToEnd = 0, iterator, cursorNode, oldPosition, currentNode, c, op; if(!domUtils.containsNode(canvasElement, window.getSelection().focusNode)) { return } iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()); cursorNode = odtDocument.getCursor(inputMemberId).getNode(); iterator.setUnfilteredPosition(cursorNode, 0); - if(iterator.previousPosition()) { + while(iterator.previousPosition()) { currentNode = iterator.getCurrentNode(); if(currentNode.nodeType === Node.TEXT_NODE) { - for(i = currentNode.data.length - 1;i >= 0;i -= 1) { - c = currentNode.data[i]; - if(!alphaNumeric.test(c)) { - break - } - stepsToStart -= 1 + c = currentNode.data[iterator.unfilteredDomOffset()]; + if(!alphaNumeric.test(c)) { + break + } + stepsToStart -= 1 + }else { + if(!isTextSpan(currentNode)) { + break } } } iterator.setUnfilteredPosition(cursorNode, 0); - if(iterator.nextPosition()) { + do { currentNode = iterator.getCurrentNode(); if(currentNode.nodeType === Node.TEXT_NODE) { - for(i = 0;i < currentNode.data.length;i += 1) { - c = currentNode.data[i]; - if(!alphaNumeric.test(c)) { - break - } - stepsToEnd += 1 + c = currentNode.data[iterator.unfilteredDomOffset()]; + if(!alphaNumeric.test(c)) { + break + } + stepsToEnd += 1 + }else { + if(!isTextSpan(currentNode)) { + break } } - } + }while(iterator.nextPosition()); if(stepsToStart !== 0 || stepsToEnd !== 0) { oldPosition = odtDocument.getCursorPosition(inputMemberId); op = createOpMoveCursor(oldPosition + stepsToStart, Math.abs(stepsToStart) + Math.abs(stepsToEnd)); @@ -13035,6 +12854,9 @@ gui.SessionController = function() { formatTextSelection("style:text-underline-style", value); return true } + function filterMouseClicks(e) { + clickStartedWithinContainer = e.target && domUtils.containsNode(odtDocument.getOdfCanvas().getElement(), e.target) + } this.startEditing = function() { var canvasElement, op; canvasElement = odtDocument.getOdfCanvas().getElement(); @@ -13046,6 +12868,7 @@ gui.SessionController = function() { listenEvent(canvasElement, "copy", handleCopy); listenEvent(canvasElement, "beforepaste", handleBeforePaste, true); listenEvent(canvasElement, "paste", handlePaste); + listenEvent(window, "mousedown", filterMouseClicks); listenEvent(window, "mouseup", clickHandler.handleMouseUp); listenEvent(canvasElement, "contextmenu", handleContextMenu); odtDocument.subscribe(ops.OdtDocument.signalOperationExecuted, maintainCursorSelection); @@ -13070,6 +12893,7 @@ gui.SessionController = function() { removeEvent(canvasElement, "copy", handleCopy); removeEvent(canvasElement, "paste", handlePaste); removeEvent(canvasElement, "beforepaste", handleBeforePaste); + removeEvent(window, "mousedown", filterMouseClicks); removeEvent(window, "mouseup", clickHandler.handleMouseUp); removeEvent(canvasElement, "contextmenu", handleContextMenu); op = new ops.OpRemoveCursor; @@ -13101,6 +12925,9 @@ gui.SessionController = function() { this.getUndoManager = function() { return undoManager }; + this.close = function(callback) { + callback() + }; function init() { var isMacOS = window.navigator.appVersion.toLowerCase().indexOf("mac") !== -1, modifier = gui.KeyboardHandler.Modifier, keyCode = gui.KeyboardHandler.KeyCode; keyDownHandler.bind(keyCode.Tab, modifier.None, function() { @@ -13218,7 +13045,7 @@ ops.MemberModel.prototype.getMemberDetailsAndUpdates = function(memberId, subscr }; ops.MemberModel.prototype.unsubscribeMemberDetailsUpdates = function(memberId, subscriber) { }; -ops.MemberModel.prototype.shutdown = function() { +ops.MemberModel.prototype.close = function(callback) { }; /* @@ -13260,243 +13087,9 @@ ops.TrivialMemberModel = function TrivialMemberModel() { }; this.unsubscribeMemberDetailsUpdates = function(memberId, subscriber) { }; - this.shutdown = function() { - } -}; -/* - - Copyright (C) 2012-2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -ops.NowjsMemberModel = function NowjsMemberModel(server) { - var cachedUserData = {}, memberDataSubscribers = {}, nowObject = server.getNowObject(); - function userIdFromMemberId(memberId) { - return memberId.split("___")[0] - } - function cacheUserDatum(userId, userData) { - var subscribers, i; - subscribers = memberDataSubscribers[userId]; - if(subscribers) { - cachedUserData[userId] = userData; - for(i = 0;i < subscribers.length;i += 1) { - subscribers[i].subscriber(subscribers[i].memberId, userData) - } - } - } - this.getMemberDetailsAndUpdates = function(memberId, subscriber) { - var userId = userIdFromMemberId(memberId), userData = cachedUserData[userId], subscribers = memberDataSubscribers[userId] || [], i; - memberDataSubscribers[userId] = subscribers; - runtime.assert(subscriber !== undefined, "missing callback"); - for(i = 0;i < subscribers.length;i += 1) { - if(subscribers[i].subscriber === subscriber && subscribers[i].memberId === memberId) { - break - } - } - if(i < subscribers.length) { - runtime.log("double subscription request for " + memberId + " in NowjsMemberModel::getMemberDetailsAndUpdates") - }else { - subscribers.push({memberId:memberId, subscriber:subscriber}); - if(subscribers.length === 1) { - nowObject.subscribeUserDetailsUpdates(userId) - } - } - if(userData) { - subscriber(memberId, userData) - } - }; - this.unsubscribeMemberDetailsUpdates = function(memberId, subscriber) { - var i, userId = userIdFromMemberId(memberId), subscribers = memberDataSubscribers[userId]; - runtime.assert(subscriber !== undefined, "missing subscriber parameter or null"); - runtime.assert(subscribers, "tried to unsubscribe when no one is subscribed ('" + memberId + "')"); - if(subscribers) { - for(i = 0;i < subscribers.length;i += 1) { - if(subscribers[i].subscriber === subscriber && subscribers[i].memberId === memberId) { - break - } - } - runtime.assert(i < subscribers.length, "tried to unsubscribe when not subscribed for memberId '" + memberId + "'"); - subscribers.splice(i, 1); - if(subscribers.length === 0) { - runtime.log("no more subscribers for: " + memberId); - delete memberDataSubscribers[userId]; - delete cachedUserData[userId]; - nowObject.unsubscribeUserDetailsUpdates(userId) - } - } - }; - this.shutdown = function() { - }; - nowObject.updateUserDetails = function(userId, udata) { - cacheUserDatum(userId, udata ? {userid:udata.uid, fullname:udata.fullname, imageurl:"/user/" + udata.avatarId + "/avatar.png", color:udata.color} : null) - }; - runtime.assert(nowObject.networkStatus === "ready", "network not ready") -}; -/* - - Copyright (C) 2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -ops.PullBoxMemberModel = function PullBoxMemberModel(sessionId, server) { - var cachedMemberData = {}, memberDataSubscribers = {}, serverPullingActivated = false, pullingIntervall = 2E4; - function cacheMemberDatum(memberData) { - var subscribers, i; - subscribers = memberDataSubscribers[memberData.memberid]; - if(subscribers) { - cachedMemberData[memberData.memberid] = memberData; - for(i = 0;i < subscribers.length;i += 1) { - subscribers[i](memberData.memberid, memberData) - } - } - } - function pullMemberData() { - var i, memberIds = Object.keys(memberDataSubscribers); - runtime.log("member-list request for : " + memberIds.join(",")); - server.call({command:"query_memberdata_list", args:{es_id:sessionId, member_ids:memberIds}}, function(responseData) { - var response = (runtime.fromJson(responseData)), memberDataList, newMemberData, oldMemberData; - runtime.log("member-list reply: " + responseData); - if(response.hasOwnProperty("memberdata_list")) { - memberDataList = response.memberdata_list; - for(i = 0;i < memberDataList.length;i += 1) { - newMemberData = {memberid:memberDataList[i].member_id, fullname:memberDataList[i].display_name, imageurl:memberDataList[i].avatar_url, color:memberDataList[i].color}; - oldMemberData = cachedMemberData.hasOwnProperty(newMemberData.memberid) ? cachedMemberData[newMemberData.memberid] : null; - if(!oldMemberData || oldMemberData.fullname !== newMemberData.fullname || oldMemberData.imageurl !== newMemberData.imageurl || oldMemberData.color !== newMemberData.color) { - cacheMemberDatum(newMemberData) - } - } - }else { - runtime.log("Meh, memberdata list broken: " + responseData) - } - }) - } - function periodicPullMemberData() { - if(!serverPullingActivated) { - return - } - pullMemberData(); - runtime.setTimeout(periodicPullMemberData, pullingIntervall) - } - function activatePeriodicMemberDataPulling() { - if(serverPullingActivated) { - return - } - serverPullingActivated = true; - runtime.setTimeout(periodicPullMemberData, pullingIntervall) - } - function deactivatePeriodicMemberDataPulling() { - var key; - if(!serverPullingActivated) { - return - } - for(key in memberDataSubscribers) { - if(memberDataSubscribers.hasOwnProperty(key)) { - return - } - } - serverPullingActivated = false + this.close = function(cb) { + cb() } - this.getMemberDetailsAndUpdates = function(memberId, subscriber) { - var memberData = cachedMemberData[memberId], subscribers = memberDataSubscribers[memberId] || [], i; - memberDataSubscribers[memberId] = subscribers; - runtime.assert(subscriber !== undefined, "missing callback"); - for(i = 0;i < subscribers.length;i += 1) { - if(subscribers[i] === subscriber) { - break - } - } - if(i < subscribers.length) { - runtime.log("double subscription request for " + memberId + " in PullBoxMemberModel::getMemberDetailsAndUpdates") - }else { - subscribers.push(subscriber); - if(subscribers.length === 1) { - pullMemberData() - } - } - if(memberData) { - subscriber(memberId, memberData) - } - activatePeriodicMemberDataPulling() - }; - this.unsubscribeMemberDetailsUpdates = function(memberId, subscriber) { - var i, subscribers = memberDataSubscribers[memberId]; - runtime.assert(subscriber !== undefined, "missing subscriber parameter or null"); - runtime.assert(subscribers, "tried to unsubscribe when no one is subscribed ('" + memberId + "')"); - if(subscribers) { - for(i = 0;i < subscribers.length;i += 1) { - if(subscribers[i] === subscriber) { - break - } - } - runtime.assert(i < subscribers.length, "tried to unsubscribe when not subscribed for memberId '" + memberId + "'"); - subscribers.splice(i, 1); - if(subscribers.length === 0) { - runtime.log("no more subscribers for: " + memberId); - delete memberDataSubscribers[memberId]; - delete cachedMemberData[memberId]; - deactivatePeriodicMemberDataPulling() - } - } - }; - this.shutdown = function() { - }; - runtime.assert(server.networkStatus() === "ready", "network not ready") }; /* @@ -13540,7 +13133,11 @@ ops.OperationRouter.prototype.setPlaybackFunction = function(playback_func) { }; ops.OperationRouter.prototype.push = function(op) { }; -ops.OperationRouter.prototype.shutdown = function(success_callback) { +ops.OperationRouter.prototype.close = function(callback) { +}; +ops.OperationRouter.prototype.getHasLocalUnsyncedOpsAndUpdates = function(subscriber) { +}; +ops.OperationRouter.prototype.unsubscribeHasLocalUnsyncedOpsUpdates = function(subscriber) { }; /* @@ -13590,305 +13187,13 @@ ops.TrivialOperationRouter = function TrivialOperationRouter() { timedOp = operationFactory.create(opspec); playbackFunction(timedOp) }; - this.shutdown = function(cb) { + this.close = function(cb) { cb() - } -}; -ops.NowjsOperationRouter = function NowjsOperationRouter(sessionId, memberid, server) { - var operationFactory, playbackFunction, nowObject = server.getNowObject(), last_server_seq = -1, reorder_queue = {}, sends_since_server_op = 0, router_sequence = 1E3; - function nextNonce() { - runtime.assert(memberid !== null, "Router sequence N/A without memberid"); - router_sequence += 1; - return"C:" + memberid + ":" + router_sequence - } - this.setOperationFactory = function(f) { - operationFactory = f - }; - this.setPlaybackFunction = function(playback_func) { - playbackFunction = playback_func }; - function receiveOpFromNetwork(opspec) { - var idx, seq, op = operationFactory.create(opspec); - runtime.log(" op in: " + runtime.toJson(opspec)); - if(op !== null) { - seq = Number(opspec.server_seq); - runtime.assert(!isNaN(seq), "server seq is not a number"); - if(seq === last_server_seq + 1) { - playbackFunction(op); - last_server_seq = seq; - sends_since_server_op = 0; - for(idx = last_server_seq + 1;reorder_queue.hasOwnProperty(idx);idx += 1) { - playbackFunction(reorder_queue[idx]); - delete reorder_queue[idx]; - runtime.log("op with server seq " + seq + " taken from hold (reordered)") - } - }else { - runtime.assert(seq !== last_server_seq + 1, "received incorrect order from server"); - runtime.assert(!reorder_queue.hasOwnProperty(seq), "reorder_queue has incoming op"); - runtime.log("op with server seq " + seq + " put on hold"); - reorder_queue[seq] = op - } - }else { - runtime.log("ignoring invalid incoming opspec: " + opspec) - } - } - nowObject.ping = function(pong) { - if(memberid !== null) { - pong(memberid) - } - }; - nowObject.receiveOp = function(op_session_id, opspec) { - if(op_session_id === sessionId) { - receiveOpFromNetwork(opspec) - } - }; - this.push = function(op) { - var opspec = op.spec(); - opspec.client_nonce = nextNonce(); - opspec.parent_op = last_server_seq + "+" + sends_since_server_op; - sends_since_server_op += 1; - runtime.log("op out: " + runtime.toJson(opspec)); - nowObject.deliverOp(sessionId, opspec) - }; - this.requestReplay = function(done_cb) { - nowObject.requestReplay(sessionId, function(opspec) { - runtime.log("replaying: " + runtime.toJson(opspec)); - receiveOpFromNetwork(opspec) - }, function(count) { - runtime.log("replay done (" + count + " ops)."); - if(done_cb) { - done_cb() - } - }) + this.getHasLocalUnsyncedOpsAndUpdates = function(subscriber) { + subscriber(true) }; - this.shutdown = function(cb) { - } -}; -/* - - Copyright (C) 2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -runtime.loadClass("ops.OperationTransformer"); -ops.PullBoxOperationRouter = function PullBoxOperationRouter(sessionId, memberId, server) { - var operationFactory, singleTimeCallbackOnCompleteServerOpSpecsPlay, playbackFunction, pullingTimeOutFlag = null, triggerPushingOpsActivated = false, playUnplayedServerOpSpecsTriggered = false, syncLock = false, hasUnresolvableConflict = false, lastServerSeq = "", unsyncedClientOpspecQueue = [], unplayedServerOpspecQueue = [], operationTransformer = new ops.OperationTransformer, replayTime = 500, pushingIntervall = 3E3, pullingIntervall = 8E3; - function compressOpSpecs(opspecs) { - var i, j, op, result = []; - i = 0; - while(i < opspecs.length) { - op = operationFactory.create(opspecs[i]); - if(op !== null && op.merge) { - for(j = i + 1;j < opspecs.length;j += 1) { - if(!op.merge(opspecs[j])) { - break - } - runtime.log("Merged: " + opspecs[i].optype + " with " + opspecs[j].optype) - } - result.push(op.spec()); - i = j - }else { - result.push(opspecs[i]); - i += 1 - } - } - runtime.log("Merged: from " + opspecs.length + " to " + result.length + " specs"); - return result - } - function playUnplayedServerOpSpecs() { - function doPlayUnplayedServerOpSpecs() { - var opspec, op, startTime; - playUnplayedServerOpSpecsTriggered = false; - startTime = (new Date).getTime(); - while(unplayedServerOpspecQueue.length > 0) { - if((new Date).getTime() - startTime > replayTime) { - break - } - opspec = unplayedServerOpspecQueue.shift(); - op = operationFactory.create(opspec); - runtime.log(" op in: " + runtime.toJson(opspec)); - if(op !== null) { - playbackFunction(op) - }else { - runtime.log("ignoring invalid incoming opspec: " + opspec) - } - } - if(unplayedServerOpspecQueue.length > 0) { - playUnplayedServerOpSpecsTriggered = true; - runtime.getWindow().setTimeout(doPlayUnplayedServerOpSpecs, 1) - }else { - if(singleTimeCallbackOnCompleteServerOpSpecsPlay) { - singleTimeCallbackOnCompleteServerOpSpecsPlay(); - singleTimeCallbackOnCompleteServerOpSpecsPlay = null - } - } - } - if(playUnplayedServerOpSpecsTriggered) { - return - } - doPlayUnplayedServerOpSpecs() - } - function receiveOpSpecsFromNetwork(opspecs) { - unplayedServerOpspecQueue = unplayedServerOpspecQueue.concat(opspecs) - } - function handleOpsSyncConflict(serverOpspecs) { - var i, transformResult; - if(!serverOpspecs) { - runtime.assert(false, "no opspecs received!"); - return false - } - transformResult = operationTransformer.transform(unsyncedClientOpspecQueue, (serverOpspecs)); - if(!transformResult) { - return false - } - for(i = 0;i < transformResult.opsB.length;i += 1) { - unplayedServerOpspecQueue.push(transformResult.opsB[i].spec()) - } - unsyncedClientOpspecQueue = []; - for(i = 0;i < transformResult.opsA.length;i += 1) { - unsyncedClientOpspecQueue.push(transformResult.opsA[i].spec()) - } - return true - } - function syncOps() { - function triggerPullingOps() { - var flag = {active:true}; - pullingTimeOutFlag = flag; - runtime.getWindow().setTimeout(function() { - runtime.log("Pulling activated:" + flag.active); - pullingTimeOutFlag = null; - if(flag.active) { - syncOps() - } - }, pullingIntervall) - } - function doSyncOps() { - var syncedClientOpspecs; - if(syncLock || hasUnresolvableConflict) { - return - } - syncLock = true; - syncedClientOpspecs = unsyncedClientOpspecQueue; - unsyncedClientOpspecQueue = []; - server.call({command:"sync_ops", args:{es_id:sessionId, member_id:memberId, seq_head:String(lastServerSeq), client_ops:syncedClientOpspecs}}, function(responseData) { - var shouldRetryInstantly = false, response = (runtime.fromJson(responseData)); - runtime.log("sync-ops reply: " + responseData); - if(response.result === "new_ops") { - if(response.ops.length > 0) { - if(unsyncedClientOpspecQueue.length === 0) { - receiveOpSpecsFromNetwork(compressOpSpecs(response.ops)) - }else { - runtime.log("meh, have new ops locally meanwhile, have to do transformations."); - hasUnresolvableConflict = !handleOpsSyncConflict(compressOpSpecs(response.ops)) - } - lastServerSeq = response.head_seq - } - }else { - if(response.result === "added") { - runtime.log("All added to server"); - lastServerSeq = response.head_seq - }else { - if(response.result === "conflict") { - unsyncedClientOpspecQueue = syncedClientOpspecs.concat(unsyncedClientOpspecQueue); - runtime.log("meh, server has new ops meanwhile, have to do transformations."); - hasUnresolvableConflict = !handleOpsSyncConflict(compressOpSpecs(response.ops)); - lastServerSeq = response.head_seq; - if(!hasUnresolvableConflict) { - shouldRetryInstantly = true - } - }else { - runtime.assert(false, "Unexpected result on sync-ops call: " + response.result) - } - } - } - syncLock = false; - if(hasUnresolvableConflict) { - runtime.assert(false, "Sorry to tell:\n" + "we hit a pair of operations in a state which yet need to be supported for transformation against each other.\n" + "Client disconnected from session, no further editing accepted.\n\n" + "Please reconnect manually for now.") - }else { - if(shouldRetryInstantly) { - doSyncOps() - }else { - runtime.log("Preparing next: " + (unsyncedClientOpspecQueue.length === 0)); - if(unsyncedClientOpspecQueue.length === 0) { - triggerPullingOps() - } - } - playUnplayedServerOpSpecs() - } - }) - } - doSyncOps() - } - function triggerPushingOps() { - if(syncLock || triggerPushingOpsActivated) { - return - } - triggerPushingOpsActivated = true; - if(pullingTimeOutFlag) { - pullingTimeOutFlag.active = false - } - runtime.getWindow().setTimeout(function() { - runtime.log("Pushing activated"); - triggerPushingOpsActivated = false; - syncOps() - }, pushingIntervall) - } - this.requestReplay = function(done_cb) { - singleTimeCallbackOnCompleteServerOpSpecsPlay = done_cb; - syncOps() - }; - this.setOperationFactory = function(f) { - operationFactory = f; - operationTransformer.setOperationFactory(f) - }; - this.setPlaybackFunction = function(playback_func) { - playbackFunction = playback_func - }; - this.push = function(op) { - var timedOp, opspec = op.spec(); - if(hasUnresolvableConflict) { - return - } - if(unplayedServerOpspecQueue.length > 0) { - return - } - opspec.timestamp = (new Date).getTime(); - timedOp = operationFactory.create(opspec); - playbackFunction(timedOp); - unsyncedClientOpspecQueue.push(opspec); - triggerPushingOps() - }; - this.shutdown = function(cb) { - syncOps(); - runtime.getWindow().setTimeout(cb, 2E3) + this.unsubscribeHasLocalUnsyncedOpsUpdates = function(subscriber) { } }; gui.EditInfoHandle = function EditInfoHandle(parentElement) { @@ -14199,6 +13504,9 @@ gui.SessionView = function() { session.getMemberModel().unsubscribeMemberDetailsUpdates(memberid, renderMemberData) } } + this.close = function(callback) { + callback() + }; function init() { var odtDocument = session.getOdtDocument(), head = document.getElementsByTagName("head")[0]; odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded); @@ -15199,7 +14507,7 @@ ops.OdtDocument = function OdtDocument(odfCanvas) { } this.getIteratorAtPosition = getIteratorAtPosition; function getPositionInTextNode(position, memberid) { - var iterator = gui.SelectionMover.createPositionIterator(getRootNode()), lastTextNode = null, node, nodeOffset = 0, cursorNode = null; + var iterator = gui.SelectionMover.createPositionIterator(getRootNode()), lastTextNode = null, node, nodeOffset = 0, cursorNode = null, originalPosition = position; runtime.assert(position >= 0, "position must be >= 0"); if(filter.acceptPosition(iterator) === 1) { node = iterator.container(); @@ -15245,7 +14553,7 @@ ops.OdtDocument = function OdtDocument(odfCanvas) { if(lastTextNode === null) { return null } - if(memberid && cursors[memberid]) { + if(memberid && cursors[memberid] && self.getCursorPosition(memberid) === originalPosition) { cursorNode = cursors[memberid].getNode(); while(nodeOffset === 0 && cursorNode.nextSibling && cursorNode.nextSibling.localName === "cursor") { cursorNode.parentNode.insertBefore(cursorNode, cursorNode.nextSibling.nextSibling) @@ -15320,13 +14628,15 @@ ops.OdtDocument = function OdtDocument(odfCanvas) { this.getParagraphStyleAttributes = getParagraphStyleAttributes; this.getPositionInTextNode = getPositionInTextNode; this.fixCursorPositions = function(localMemberId) { - var posfilter = self.getPositionFilter(), memberId, cursor, stepCounter, steps; + var memberId, cursor, stepCounter, steps, rootConstrainedFilter = new core.PositionFilterChain; + rootConstrainedFilter.addFilter("BaseFilter", self.getPositionFilter()); for(memberId in cursors) { if(cursors.hasOwnProperty(memberId)) { + rootConstrainedFilter.addFilter("RootFilter", self.createRootFilter(memberId)); cursor = cursors[memberId]; stepCounter = cursor.getStepCounter(); - if(!stepCounter.isPositionWalkable(posfilter)) { - steps = stepCounter.countStepsToValidPosition(posfilter); + if(!stepCounter.isPositionWalkable(rootConstrainedFilter)) { + steps = stepCounter.countStepsToValidPosition(rootConstrainedFilter); cursor.move(steps); if(memberId === localMemberId) { self.emit(ops.OdtDocument.signalCursorMoved, cursor) @@ -15336,6 +14646,7 @@ ops.OdtDocument = function OdtDocument(odfCanvas) { cursor.move(0) } } + rootConstrainedFilter.removeFilter("RootFilter") } } }; @@ -15449,6 +14760,9 @@ ops.OdtDocument = function OdtDocument(odfCanvas) { this.createRootFilter = function(inputMemberId) { return new RootFilter(inputMemberId) }; + this.close = function(callback) { + callback() + }; function init() { filter = new TextPositionFilter; odfUtils = new odf.OdfUtils @@ -15525,6 +14839,9 @@ ops.Session = function Session(odfCanvas) { }); opRouter.setOperationFactory(operationFactory) }; + this.getOperationRouter = function() { + return operationRouter + }; this.getMemberModel = function() { return memberModel }; @@ -15537,10 +14854,19 @@ ops.Session = function Session(odfCanvas) { this.enqueue = function(operation) { operationRouter.push(operation) }; + this.close = function(callback) { + odtDocument.close(function(err) { + if(err) { + callback(err) + }else { + callback() + } + }) + }; function init() { self.setOperationRouter(new ops.TrivialOperationRouter) } init() }; -var webodf_css = "@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n@namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n@namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n@namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n@namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n@namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n@namespace table url(urn:oasis:names:tc:opendocument:xmlns:table:1.0);\n@namespace text url(urn:oasis:names:tc:opendocument:xmlns:text:1.0);\n@namespace runtimens url(urn:webodf); /* namespace for runtime only */\n@namespace cursor url(urn:webodf:names:cursor);\n@namespace editinfo url(urn:webodf:names:editinfo);\n@namespace annotation url(urn:webodf:names:annotation);\n@namespace dc url(http://purl.org/dc/elements/1.1/);\n\noffice|document > *, office|document-content > * {\n display: none;\n}\noffice|body, office|document {\n display: inline-block;\n position: relative;\n}\n\ntext|p, text|h {\n display: block;\n padding: 0;\n margin: 0;\n line-height: normal;\n position: relative;\n min-height: 1.3em; /* prevent empty paragraphs and headings from collapsing if they are empty */\n}\n*[runtimens|containsparagraphanchor] {\n position: relative;\n}\ntext|s {\n white-space: pre;\n}\ntext|tab {\n display: inline;\n white-space: pre;\n}\ntext|line-break {\n content: \" \";\n display: block;\n}\ntext|tracked-changes {\n /*Consumers that do not support change tracking, should ignore changes.*/\n display: none;\n}\noffice|binary-data {\n display: none;\n}\noffice|text {\n display: block;\n text-align: left;\n overflow: visible;\n word-wrap: break-word;\n}\n\noffice|text::selection {\n /** Let's not draw selection highlight that overflows into the office|text\n * node when selecting content across several paragraphs\n */\n background: transparent;\n}\n\noffice|spreadsheet {\n display: block;\n border-collapse: collapse;\n empty-cells: show;\n font-family: sans-serif;\n font-size: 10pt;\n text-align: left;\n page-break-inside: avoid;\n overflow: hidden;\n}\noffice|presentation {\n display: inline-block;\n text-align: left;\n}\n#shadowContent {\n display: inline-block;\n text-align: left;\n}\ndraw|page {\n display: block;\n position: relative;\n overflow: hidden;\n}\npresentation|notes, presentation|footer-decl, presentation|date-time-decl {\n display: none;\n}\n@media print {\n draw|page {\n border: 1pt solid black;\n page-break-inside: avoid;\n }\n presentation|notes {\n /*TODO*/\n }\n}\noffice|spreadsheet text|p {\n border: 0px;\n padding: 1px;\n margin: 0px;\n}\noffice|spreadsheet table|table {\n margin: 3px;\n}\noffice|spreadsheet table|table:after {\n /* show sheet name the end of the sheet */\n /*content: attr(table|name);*/ /* gives parsing error in opera */\n}\noffice|spreadsheet table|table-row {\n counter-increment: row;\n}\noffice|spreadsheet table|table-row:before {\n width: 3em;\n background: #cccccc;\n border: 1px solid black;\n text-align: center;\n content: counter(row);\n display: table-cell;\n}\noffice|spreadsheet table|table-cell {\n border: 1px solid #cccccc;\n}\ntable|table {\n display: table;\n}\ndraw|frame table|table {\n width: 100%;\n height: 100%;\n background: white;\n}\ntable|table-header-rows {\n display: table-header-group;\n}\ntable|table-row {\n display: table-row;\n}\ntable|table-column {\n display: table-column;\n}\ntable|table-cell {\n width: 0.889in;\n display: table-cell;\n word-break: break-all; /* prevent long words from extending out the table cell */\n}\ndraw|frame {\n display: block;\n}\ndraw|image {\n display: block;\n width: 100%;\n height: 100%;\n top: 0px;\n left: 0px;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n -moz-background-size: 100% 100%;\n}\n/* only show the first image in frame */\ndraw|frame > draw|image:nth-of-type(n+2) {\n display: none;\n}\ntext|list:before {\n display: none;\n content:\"\";\n}\ntext|list {\n counter-reset: list;\n}\ntext|list-item {\n display: block;\n}\ntext|number {\n display:none;\n}\n\ntext|a {\n color: blue;\n text-decoration: underline;\n cursor: pointer;\n}\ntext|note-citation {\n vertical-align: super;\n font-size: smaller;\n}\ntext|note-body {\n display: none;\n}\ntext|note:hover text|note-citation {\n background: #dddddd;\n}\ntext|note:hover text|note-body {\n display: block;\n left:1em;\n max-width: 80%;\n position: absolute;\n background: #ffffaa;\n}\nsvg|title, svg|desc {\n display: none;\n}\nvideo {\n width: 100%;\n height: 100%\n}\n\n/* below set up the cursor */\ncursor|cursor {\n display: inline;\n width: 0px;\n height: 1em;\n /* making the position relative enables the avatar to use\n the cursor as reference for its absolute position */\n position: relative;\n z-index: 1;\n}\ncursor|cursor > span {\n display: inline;\n position: absolute;\n top: 5%; /* push down the caret; 0px can do the job, 5% looks better, 10% is a bit over */\n height: 1em;\n border-left: 2px solid black;\n outline: none;\n}\n\ncursor|cursor > div {\n padding: 3px;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n border: none !important;\n border-radius: 5px;\n opacity: 0.3;\n}\n\ncursor|cursor > div > img {\n border-radius: 5px;\n}\n\ncursor|cursor > div.active {\n opacity: 0.8;\n}\n\ncursor|cursor > div:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 43%;\n}\n\n\n.editInfoMarker {\n position: absolute;\n width: 10px;\n height: 100%;\n left: -20px;\n opacity: 0.8;\n top: 0;\n border-radius: 5px;\n background-color: transparent;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n}\n.editInfoMarker:hover {\n box-shadow: 0px 0px 8px rgba(0, 0, 0, 1);\n}\n\n.editInfoHandle {\n position: absolute;\n background-color: black;\n padding: 5px;\n border-radius: 5px;\n opacity: 0.8;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n bottom: 100%;\n margin-bottom: 10px;\n z-index: 3;\n left: -25px;\n}\n.editInfoHandle:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 5px;\n}\n.editInfo {\n font-family: sans-serif;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n color: white;\n width: 100%;\n height: 12pt;\n}\n.editInfoColor {\n float: left;\n width: 10pt;\n height: 10pt;\n border: 1px solid white;\n}\n.editInfoAuthor {\n float: left;\n margin-left: 5pt;\n font-size: 10pt;\n text-align: left;\n height: 12pt;\n line-height: 12pt;\n}\n.editInfoTime {\n float: right;\n margin-left: 30pt;\n font-size: 8pt;\n font-style: italic;\n color: yellow;\n height: 12pt;\n line-height: 12pt;\n}\n\n.annotationWrapper {\n display: inline;\n position: relative;\n}\n\n.annotationRemoveButton:before {\n content: '\u00d7';\n color: white;\n padding: 5px;\n line-height: 1em;\n}\n\n.annotationRemoveButton {\n width: 20px;\n height: 20px;\n border-radius: 10px;\n background-color: black;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n position: absolute;\n top: -10px;\n left: -10px;\n z-index: 3;\n text-align: center;\n font-family: sans-serif;\n font-style: normal;\n font-weight: normal;\n text-decoration: none;\n font-size: 15px;\n}\n.annotationRemoveButton:hover {\n cursor: pointer;\n box-shadow: 0px 0px 5px rgba(0, 0, 0, 1);\n}\n\n.annotationNote {\n width: 4cm;\n position: absolute;\n display: inline;\n z-index: 10;\n}\n.annotationNote > office|annotation {\n display: block;\n}\n\n.annotationConnector {\n position: absolute;\n display: inline;\n z-index: 2;\n border-top: 1px dashed brown;\n}\n.annotationConnector.angular {\n -moz-transform-origin: left top;\n -webkit-transform-origin: left top;\n -ms-transform-origin: left top;\n transform-origin: left top;\n}\n.annotationConnector.horizontal {\n left: 0;\n}\n.annotationConnector.horizontal:before {\n content: '';\n display: inline;\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: brown transparent transparent transparent;\n top: -1px;\n left: -5px;\n}\n\noffice|annotation {\n width: 100%;\n height: 100%;\n display: none;\n background: rgb(198, 238, 184);\n background: -moz-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -webkit-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -o-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -ms-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: linear-gradient(180deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n box-shadow: 0 3px 4px -3px #ccc;\n}\n\noffice|annotation > dc|creator {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n color: white;\n background-color: brown;\n padding: 4px;\n}\noffice|annotation > dc|date {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n border: 4px solid transparent;\n}\noffice|annotation > text|list {\n display: block;\n padding: 5px;\n}\n\n/* This is very temporary CSS. This must go once\n * we start bundling webodf-default ODF styles for annotations.\n */\noffice|annotation text|p {\n font-size: 10pt;\n color: black;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n font-family: sans-serif;\n}\n\ndc|*::selection {\n background: transparent;\n}\ndc|*::-moz-selection {\n background: transparent;\n}\n\n#annotationsPane {\n background-color: #EAEAEA;\n width: 4cm;\n height: 100%;\n display: inline-block;\n position: absolute;\n outline: 1px solid #ccc;\n}\n\n.annotationHighlight {\n background-color: yellow;\n position: relative;\n}\n"; +var webodf_css = "@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n@namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n@namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n@namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n@namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n@namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n@namespace table url(urn:oasis:names:tc:opendocument:xmlns:table:1.0);\n@namespace text url(urn:oasis:names:tc:opendocument:xmlns:text:1.0);\n@namespace runtimens url(urn:webodf); /* namespace for runtime only */\n@namespace cursor url(urn:webodf:names:cursor);\n@namespace editinfo url(urn:webodf:names:editinfo);\n@namespace annotation url(urn:webodf:names:annotation);\n@namespace dc url(http://purl.org/dc/elements/1.1/);\n\noffice|document > *, office|document-content > * {\n display: none;\n}\noffice|body, office|document {\n display: inline-block;\n position: relative;\n}\n\ntext|p, text|h {\n display: block;\n padding: 0;\n margin: 0;\n line-height: normal;\n position: relative;\n min-height: 1.3em; /* prevent empty paragraphs and headings from collapsing if they are empty */\n}\n*[runtimens|containsparagraphanchor] {\n position: relative;\n}\ntext|s {\n white-space: pre;\n}\ntext|tab {\n display: inline;\n white-space: pre;\n}\ntext|line-break {\n content: \" \";\n display: block;\n}\ntext|tracked-changes {\n /*Consumers that do not support change tracking, should ignore changes.*/\n display: none;\n}\noffice|binary-data {\n display: none;\n}\noffice|text {\n display: block;\n text-align: left;\n overflow: visible;\n word-wrap: break-word;\n}\n\noffice|text::selection {\n /** Let's not draw selection highlight that overflows into the office|text\n * node when selecting content across several paragraphs\n */\n background: transparent;\n}\noffice|text * draw|text-box {\n /** only for text documents */\n display: block;\n border: 1px solid #d3d3d3;\n}\noffice|spreadsheet {\n display: block;\n border-collapse: collapse;\n empty-cells: show;\n font-family: sans-serif;\n font-size: 10pt;\n text-align: left;\n page-break-inside: avoid;\n overflow: hidden;\n}\noffice|presentation {\n display: inline-block;\n text-align: left;\n}\n#shadowContent {\n display: inline-block;\n text-align: left;\n}\ndraw|page {\n display: block;\n position: relative;\n overflow: hidden;\n}\npresentation|notes, presentation|footer-decl, presentation|date-time-decl {\n display: none;\n}\n@media print {\n draw|page {\n border: 1pt solid black;\n page-break-inside: avoid;\n }\n presentation|notes {\n /*TODO*/\n }\n}\noffice|spreadsheet text|p {\n border: 0px;\n padding: 1px;\n margin: 0px;\n}\noffice|spreadsheet table|table {\n margin: 3px;\n}\noffice|spreadsheet table|table:after {\n /* show sheet name the end of the sheet */\n /*content: attr(table|name);*/ /* gives parsing error in opera */\n}\noffice|spreadsheet table|table-row {\n counter-increment: row;\n}\noffice|spreadsheet table|table-row:before {\n width: 3em;\n background: #cccccc;\n border: 1px solid black;\n text-align: center;\n content: counter(row);\n display: table-cell;\n}\noffice|spreadsheet table|table-cell {\n border: 1px solid #cccccc;\n}\ntable|table {\n display: table;\n}\ndraw|frame table|table {\n width: 100%;\n height: 100%;\n background: white;\n}\ntable|table-header-rows {\n display: table-header-group;\n}\ntable|table-row {\n display: table-row;\n}\ntable|table-column {\n display: table-column;\n}\ntable|table-cell {\n width: 0.889in;\n display: table-cell;\n word-break: break-all; /* prevent long words from extending out the table cell */\n}\ndraw|frame {\n display: block;\n}\ndraw|image {\n display: block;\n width: 100%;\n height: 100%;\n top: 0px;\n left: 0px;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n -moz-background-size: 100% 100%;\n}\n/* only show the first image in frame */\ndraw|frame > draw|image:nth-of-type(n+2) {\n display: none;\n}\ntext|list:before {\n display: none;\n content:\"\";\n}\ntext|list {\n counter-reset: list;\n}\ntext|list-item {\n display: block;\n}\ntext|number {\n display:none;\n}\n\ntext|a {\n color: blue;\n text-decoration: underline;\n cursor: pointer;\n}\ntext|note-citation {\n vertical-align: super;\n font-size: smaller;\n}\ntext|note-body {\n display: none;\n}\ntext|note:hover text|note-citation {\n background: #dddddd;\n}\ntext|note:hover text|note-body {\n display: block;\n left:1em;\n max-width: 80%;\n position: absolute;\n background: #ffffaa;\n}\nsvg|title, svg|desc {\n display: none;\n}\nvideo {\n width: 100%;\n height: 100%\n}\n\n/* below set up the cursor */\ncursor|cursor {\n display: inline;\n width: 0px;\n height: 1em;\n /* making the position relative enables the avatar to use\n the cursor as reference for its absolute position */\n position: relative;\n z-index: 1;\n}\ncursor|cursor > span {\n display: inline;\n position: absolute;\n top: 5%; /* push down the caret; 0px can do the job, 5% looks better, 10% is a bit over */\n height: 1em;\n border-left: 2px solid black;\n outline: none;\n}\n\ncursor|cursor > div {\n padding: 3px;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n border: none !important;\n border-radius: 5px;\n opacity: 0.3;\n}\n\ncursor|cursor > div > img {\n border-radius: 5px;\n}\n\ncursor|cursor > div.active {\n opacity: 0.8;\n}\n\ncursor|cursor > div:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 43%;\n}\n\n\n.editInfoMarker {\n position: absolute;\n width: 10px;\n height: 100%;\n left: -20px;\n opacity: 0.8;\n top: 0;\n border-radius: 5px;\n background-color: transparent;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n}\n.editInfoMarker:hover {\n box-shadow: 0px 0px 8px rgba(0, 0, 0, 1);\n}\n\n.editInfoHandle {\n position: absolute;\n background-color: black;\n padding: 5px;\n border-radius: 5px;\n opacity: 0.8;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n bottom: 100%;\n margin-bottom: 10px;\n z-index: 3;\n left: -25px;\n}\n.editInfoHandle:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 5px;\n}\n.editInfo {\n font-family: sans-serif;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n color: white;\n width: 100%;\n height: 12pt;\n}\n.editInfoColor {\n float: left;\n width: 10pt;\n height: 10pt;\n border: 1px solid white;\n}\n.editInfoAuthor {\n float: left;\n margin-left: 5pt;\n font-size: 10pt;\n text-align: left;\n height: 12pt;\n line-height: 12pt;\n}\n.editInfoTime {\n float: right;\n margin-left: 30pt;\n font-size: 8pt;\n font-style: italic;\n color: yellow;\n height: 12pt;\n line-height: 12pt;\n}\n\n.annotationWrapper {\n display: inline;\n position: relative;\n}\n\n.annotationRemoveButton:before {\n content: '\u00d7';\n color: white;\n padding: 5px;\n line-height: 1em;\n}\n\n.annotationRemoveButton {\n width: 20px;\n height: 20px;\n border-radius: 10px;\n background-color: black;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n position: absolute;\n top: -10px;\n left: -10px;\n z-index: 3;\n text-align: center;\n font-family: sans-serif;\n font-style: normal;\n font-weight: normal;\n text-decoration: none;\n font-size: 15px;\n}\n.annotationRemoveButton:hover {\n cursor: pointer;\n box-shadow: 0px 0px 5px rgba(0, 0, 0, 1);\n}\n\n.annotationNote {\n width: 4cm;\n position: absolute;\n display: inline;\n z-index: 10;\n}\n.annotationNote > office|annotation {\n display: block;\n}\n\n.annotationConnector {\n position: absolute;\n display: inline;\n z-index: 2;\n border-top: 1px dashed brown;\n}\n.annotationConnector.angular {\n -moz-transform-origin: left top;\n -webkit-transform-origin: left top;\n -ms-transform-origin: left top;\n transform-origin: left top;\n}\n.annotationConnector.horizontal {\n left: 0;\n}\n.annotationConnector.horizontal:before {\n content: '';\n display: inline;\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: brown transparent transparent transparent;\n top: -1px;\n left: -5px;\n}\n\noffice|annotation {\n width: 100%;\n height: 100%;\n display: none;\n background: rgb(198, 238, 184);\n background: -moz-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -webkit-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -o-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -ms-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: linear-gradient(180deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n box-shadow: 0 3px 4px -3px #ccc;\n}\n\noffice|annotation > dc|creator {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n color: white;\n background-color: brown;\n padding: 4px;\n}\noffice|annotation > dc|date {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n border: 4px solid transparent;\n}\noffice|annotation > text|list {\n display: block;\n padding: 5px;\n}\n\n/* This is very temporary CSS. This must go once\n * we start bundling webodf-default ODF styles for annotations.\n */\noffice|annotation text|p {\n font-size: 10pt;\n color: black;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n font-family: sans-serif;\n}\n\ndc|*::selection {\n background: transparent;\n}\ndc|*::-moz-selection {\n background: transparent;\n}\n\n#annotationsPane {\n background-color: #EAEAEA;\n width: 4cm;\n height: 100%;\n display: none;\n position: absolute;\n outline: 1px solid #ccc;\n}\n\n.annotationHighlight {\n background-color: yellow;\n position: relative;\n}\n"; diff --git a/js/webodf.js b/js/webodf.js index ad7b6e73..8ad6c571 100644 --- a/js/webodf.js +++ b/js/webodf.js @@ -36,79 +36,79 @@ */ var core={},gui={},xmldom={},odf={},ops={}; // Input 1 -function Runtime(){}Runtime.ByteArray=function(k){};Runtime.prototype.getVariable=function(k){};Runtime.prototype.toJson=function(k){};Runtime.prototype.fromJson=function(k){};Runtime.ByteArray.prototype.slice=function(k,l){};Runtime.ByteArray.prototype.length=0;Runtime.prototype.byteArrayFromArray=function(k){};Runtime.prototype.byteArrayFromString=function(k,l){};Runtime.prototype.byteArrayToString=function(k,l){};Runtime.prototype.concatByteArrays=function(k,l){}; -Runtime.prototype.read=function(k,l,h,e){};Runtime.prototype.readFile=function(k,l,h){};Runtime.prototype.readFileSync=function(k,l){};Runtime.prototype.loadXML=function(k,l){};Runtime.prototype.writeFile=function(k,l,h){};Runtime.prototype.isFile=function(k,l){};Runtime.prototype.getFileSize=function(k,l){};Runtime.prototype.deleteFile=function(k,l){};Runtime.prototype.log=function(k,l){};Runtime.prototype.setTimeout=function(k,l){};Runtime.prototype.clearTimeout=function(k){}; -Runtime.prototype.libraryPaths=function(){};Runtime.prototype.type=function(){};Runtime.prototype.getDOMImplementation=function(){};Runtime.prototype.parseXML=function(k){};Runtime.prototype.getWindow=function(){};Runtime.prototype.assert=function(k,l,h){};var IS_COMPILED_CODE=!0; -Runtime.byteArrayToString=function(k,l){function h(b){var a="",f,d=b.length;for(f=0;fc?a+=String.fromCharCode(c):(f+=1,e=b[f],194<=c&&224>c?a+=String.fromCharCode((c&31)<<6|e&63):(f+=1,m=b[f],224<=c&&240>c?a+=String.fromCharCode((c&15)<<12|(e&63)<<6|m&63):(f+=1,q=b[f],240<=c&&245>c&&(c=(c&7)<<18|(e&63)<<12|(m&63)<<6|q&63,c-=65536,a+=String.fromCharCode((c>>10)+55296,(c&1023)+56320))))); -return a}var b;"utf8"===l?b=e(k):("binary"!==l&&this.log("Unsupported encoding: "+l),b=h(k));return b};Runtime.getVariable=function(k){try{return eval(k)}catch(l){}};Runtime.toJson=function(k){return JSON.stringify(k)};Runtime.fromJson=function(k){return JSON.parse(k)};Runtime.getFunctionName=function(k){return void 0===k.name?(k=/function\s+(\w+)/.exec(k))&&k[1]:k.name}; -function BrowserRuntime(k){function l(a,f){var d,c,b;void 0!==f?b=a:f=a;k?(c=k.ownerDocument,b&&(d=c.createElement("span"),d.className=b,d.appendChild(c.createTextNode(b)),k.appendChild(d),k.appendChild(c.createTextNode(" "))),d=c.createElement("span"),0m?(c[q]=m,q+=1):2048>m?(c[q]=192|m>>>6,c[q+1]=128|m&63,q+=2):(c[q]=224|m>>>12&15,c[q+1]=128|m>>>6&63,c[q+2]=128|m&63,q+=3)}else for("binary"!== -f&&e.log("unknown encoding: "+f),d=a.length,c=new e.ByteArray(d),b=0;bc.status||0===c.status?d(null):d("Status "+String(c.status)+": "+c.responseText|| -c.statusText):d("File "+a+" is empty."))};f=f.buffer&&!c.sendAsBinary?f.buffer:e.byteArrayToString(f,"binary");try{c.sendAsBinary?c.sendAsBinary(f):c.send(f)}catch(g){e.log("HUH? "+g+" "+f),d(g.message)}};this.deleteFile=function(a,f){delete b[a];var d=new XMLHttpRequest;d.open("DELETE",a,!0);d.onreadystatechange=function(){4===d.readyState&&(200>d.status&&300<=d.status?f(d.responseText):f(null))};d.send(null)};this.loadXML=function(a,f){var d=new XMLHttpRequest;d.open("GET",a,!0);d.overrideMimeType&& -d.overrideMimeType("text/xml");d.onreadystatechange=function(){4===d.readyState&&(0!==d.status||d.responseText?200===d.status||0===d.status?f(null,d.responseXML):f(d.responseText):f("File "+a+" is empty."))};try{d.send(null)}catch(c){f(c.message)}};this.isFile=function(a,f){e.getFileSize(a,function(a){f(-1!==a)})};this.getFileSize=function(a,f){var d=new XMLHttpRequest;d.open("HEAD",a,!0);d.onreadystatechange=function(){if(4===d.readyState){var c=d.getResponseHeader("Content-Length");c?f(parseInt(c, -10)):h(a,"binary",function(c,a){c?f(-1):f(a.length)})}};d.send(null)};this.log=l;this.assert=function(a,f,d){if(!a)throw l("alert","ASSERTION FAILED:\n"+f),d&&d(),f;};this.setTimeout=function(a,f){return setTimeout(function(){a()},f)};this.clearTimeout=function(a){clearTimeout(a)};this.libraryPaths=function(){return["lib"]};this.setCurrentDirectory=function(){};this.type=function(){return"BrowserRuntime"};this.getDOMImplementation=function(){return window.document.implementation};this.parseXML=function(a){return(new DOMParser).parseFromString(a, -"text/xml")};this.exit=function(a){l("Calling exit with code "+String(a)+", but exit() is not implemented.")};this.getWindow=function(){return window}} -function NodeJSRuntime(){function k(f,a,c){f=e.resolve(b,f);"binary"!==a?h.readFile(f,a,c):h.readFile(f,null,c)}var l=this,h=require("fs"),e=require("path"),b="",g,a;this.ByteArray=function(a){return new Buffer(a)};this.byteArrayFromArray=function(a){var d=new Buffer(a.length),c,b=a.length;for(c=0;c").implementation} -function RhinoRuntime(){function k(a,b){var d;void 0!==b?d=a:b=a;"alert"===d&&print("\n!!!!! ALERT !!!!!");print(b);"alert"===d&&print("!!!!! ALERT !!!!!")}var l=this,h=Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance(),e,b,g="";h.setValidating(!1);h.setNamespaceAware(!0);h.setExpandEntityReferences(!1);h.setSchema(null);b=Packages.org.xml.sax.EntityResolver({resolveEntity:function(a,b){var d=new Packages.java.io.FileReader(b);return new Packages.org.xml.sax.InputSource(d)}});e=h.newDocumentBuilder(); -e.setEntityResolver(b);this.ByteArray=function(a){return[a]};this.byteArrayFromArray=function(a){return a};this.byteArrayFromString=function(a,b){var d=[],c,g=a.length;for(c=0;cc?a+=String.fromCharCode(c):(h+=1,d=b[h],194<=c&&224>c?a+=String.fromCharCode((c&31)<<6|d&63):(h+=1,k=b[h],224<=c&&240>c?a+=String.fromCharCode((c&15)<<12|(d&63)<<6|k&63):(h+=1,q=b[h],240<=c&&245>c&&(c=(c&7)<<18|(d&63)<<12|(k&63)<<6|q&63,c-=65536,a+=String.fromCharCode((c>>10)+55296,(c&1023)+56320))))); +return a}var b;"utf8"===m?b=d(n):("binary"!==m&&this.log("Unsupported encoding: "+m),b=l(n));return b};Runtime.getVariable=function(n){try{return eval(n)}catch(m){}};Runtime.toJson=function(n){return JSON.stringify(n)};Runtime.fromJson=function(n){return JSON.parse(n)};Runtime.getFunctionName=function(n){return void 0===n.name?(n=/function\s+(\w+)/.exec(n))&&n[1]:n.name}; +function BrowserRuntime(n){function m(a,h){var f,c,b;void 0!==h?b=a:h=a;n?(c=n.ownerDocument,b&&(f=c.createElement("span"),f.className=b,f.appendChild(c.createTextNode(b)),n.appendChild(f),n.appendChild(c.createTextNode(" "))),f=c.createElement("span"),0k?(c[q]=k,q+=1):2048>k?(c[q]=192|k>>>6,c[q+1]=128|k&63,q+=2):(c[q]=224|k>>>12&15,c[q+1]=128|k>>>6&63,c[q+2]=128|k&63,q+=3)}else for("binary"!== +h&&d.log("unknown encoding: "+h),f=a.length,c=new d.ByteArray(f),b=0;bc.status||0===c.status?f(null):f("Status "+String(c.status)+": "+c.responseText|| +c.statusText):f("File "+a+" is empty."))};h=h.buffer&&!c.sendAsBinary?h.buffer:d.byteArrayToString(h,"binary");try{c.sendAsBinary?c.sendAsBinary(h):c.send(h)}catch(e){d.log("HUH? "+e+" "+h),f(e.message)}};this.deleteFile=function(a,h){delete b[a];var f=new XMLHttpRequest;f.open("DELETE",a,!0);f.onreadystatechange=function(){4===f.readyState&&(200>f.status&&300<=f.status?h(f.responseText):h(null))};f.send(null)};this.loadXML=function(a,h){var f=new XMLHttpRequest;f.open("GET",a,!0);f.overrideMimeType&& +f.overrideMimeType("text/xml");f.onreadystatechange=function(){4===f.readyState&&(0!==f.status||f.responseText?200===f.status||0===f.status?h(null,f.responseXML):h(f.responseText):h("File "+a+" is empty."))};try{f.send(null)}catch(c){h(c.message)}};this.isFile=function(a,h){d.getFileSize(a,function(a){h(-1!==a)})};this.getFileSize=function(a,h){var f=new XMLHttpRequest;f.open("HEAD",a,!0);f.onreadystatechange=function(){if(4===f.readyState){var c=f.getResponseHeader("Content-Length");c?h(parseInt(c, +10)):l(a,"binary",function(c,a){c?h(-1):h(a.length)})}};f.send(null)};this.log=m;this.assert=function(a,h,f){if(!a)throw m("alert","ASSERTION FAILED:\n"+h),f&&f(),h;};this.setTimeout=function(a,h){return setTimeout(function(){a()},h)};this.clearTimeout=function(a){clearTimeout(a)};this.libraryPaths=function(){return["lib"]};this.setCurrentDirectory=function(){};this.type=function(){return"BrowserRuntime"};this.getDOMImplementation=function(){return window.document.implementation};this.parseXML=function(a){return(new DOMParser).parseFromString(a, +"text/xml")};this.exit=function(a){m("Calling exit with code "+String(a)+", but exit() is not implemented.")};this.getWindow=function(){return window}} +function NodeJSRuntime(){function n(a,f,c){a=d.resolve(b,a);"binary"!==f?l.readFile(a,f,c):l.readFile(a,null,c)}var m=this,l=require("fs"),d=require("path"),b="",e,a;this.ByteArray=function(a){return new Buffer(a)};this.byteArrayFromArray=function(a){var f=new Buffer(a.length),c,b=a.length;for(c=0;c").implementation} +function RhinoRuntime(){function n(a,b){var f;void 0!==b?f=a:b=a;"alert"===f&&print("\n!!!!! ALERT !!!!!");print(b);"alert"===f&&print("!!!!! ALERT !!!!!")}var m=this,l=Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance(),d,b,e="";l.setValidating(!1);l.setNamespaceAware(!0);l.setExpandEntityReferences(!1);l.setSchema(null);b=Packages.org.xml.sax.EntityResolver({resolveEntity:function(a,b){var f=new Packages.java.io.FileReader(b);return new Packages.org.xml.sax.InputSource(f)}});d=l.newDocumentBuilder(); +d.setEntityResolver(b);this.ByteArray=function(a){return[a]};this.byteArrayFromArray=function(a){return a};this.byteArrayFromString=function(a,b){var f=[],c,d=a.length;for(c=0;c>>18],b+=p[a>>>12&63],b+=p[a>>>6&63],b+=p[a&63];m===d+1?(a=c[m]<<4,b+=p[a>>>6],b+=p[a&63],b+="=="):m===d&&(a=c[m]<<10|c[m+1]<<2,b+=p[a>>>12],b+=p[a>>>6&63],b+=p[a&63],b+="=");return b}function h(c){c=c.replace(/[^A-Za-z0-9+\/]+/g,"");var a=[],b=c.length%4,m,d=c.length,f;for(m=0;m>16,f>>8&255,f&255);a.length-=[0,0,2,1][b];return a}function e(c){var a=[],b,m=c.length,d;for(b=0;bd?a.push(d):2048>d?a.push(192|d>>>6,128|d&63):a.push(224|d>>>12&15,128|d>>>6&63,128|d&63);return a}function b(c){var a=[],b,m=c.length,d,f,n;for(b=0;bd?a.push(d):(b+=1,f=c[b],224>d?a.push((d&31)<<6|f&63):(b+=1,n=c[b],a.push((d&15)<<12|(f&63)<<6|n&63)));return a}function g(c){return l(k(c))} -function a(c){return String.fromCharCode.apply(String,h(c))}function f(c){return b(k(c))}function d(c){c=b(c);for(var a="",m=0;ma?m+=String.fromCharCode(a):(n+=1,d=c.charCodeAt(n)&255,224>a?m+=String.fromCharCode((a&31)<<6|d&63):(n+=1,f=c.charCodeAt(n)&255,m+=String.fromCharCode((a&15)<<12|(d&63)<<6|f&63)));return m}function t(a,b){function m(){var g= -n+d;g>a.length&&(g=a.length);f+=c(a,n,g);n=g;g=n===a.length;b(f,g)&&!g&&runtime.setTimeout(m,0)}var d=1E5,f="",n=0;a.length>>18],b+=p[a>>>12&63],b+=p[a>>>6&63],b+=p[a&63];g===k+1?(a=c[g]<<4,b+=p[a>>>6],b+=p[a&63],b+="=="):g===k&&(a=c[g]<<10|c[g+1]<<2,b+=p[a>>>12],b+=p[a>>>6&63],b+=p[a&63],b+="=");return b}function l(c){c=c.replace(/[^A-Za-z0-9+\/]+/g,"");var a=[],b=c.length%4,g,k=c.length,f;for(g=0;g>16,f>>8&255,f&255);a.length-=[0,0,2,1][b];return a}function d(c){var a=[],b,g=c.length,k;for(b=0;bk?a.push(k):2048>k?a.push(192|k>>>6,128|k&63):a.push(224|k>>>12&15,128|k>>>6&63,128|k&63);return a}function b(c){var a=[],b,g=c.length,k,f,p;for(b=0;bk?a.push(k):(b+=1,f=c[b],224>k?a.push((k&31)<<6|f&63):(b+=1,p=c[b],a.push((k&15)<<12|(f&63)<<6|p&63)));return a}function e(c){return m(n(c))} +function a(c){return String.fromCharCode.apply(String,l(c))}function h(c){return b(n(c))}function f(c){c=b(c);for(var a="",g=0;ga?g+=String.fromCharCode(a):(p+=1,k=c.charCodeAt(p)&255,224>a?g+=String.fromCharCode((a&31)<<6|k&63):(p+=1,f=c.charCodeAt(p)&255,g+=String.fromCharCode((a&15)<<12|(k&63)<<6|f&63)));return g}function t(a,b){function g(){var d= +p+k;d>a.length&&(d=a.length);f+=c(a,p,d);p=d;d=p===a.length;b(f,d)&&!d&&runtime.setTimeout(g,0)}var k=1E5,f="",p=0;a.length>>8):(ka(a&255),ka(a>>>8))},ba=function(){s=(s<<5^n[B+3-1]&255)&8191;v=w[32768+s];w[B&32767]=v;w[32768+s]=B},U=function(c,a){y>16-a?(u|=c<>16-y,y+=a-16):(u|=c<c;c++)n[c]=n[c+32768];P-=32768;B-=32768;x-=32768;for(c=0;8192>c;c++)a=w[32768+c],w[32768+c]=32768<=a?a-32768:0;for(c=0;32768>c;c++)a=w[c],w[c]=32768<=a?a-32768:0;b+=32768}z||(c=pa(n,B+J,b),0>=c?z=!0:J+=c)},Ca=function(c){var a=X,b=B,m,d=O,f=32506=qa&&(a>>=2);do if(m=c,n[m+d]===e&&n[m+d-1]===q&&n[m]===n[b]&&n[++m]===n[b+1]){b+= -2;m++;do++b;while(n[b]===n[++m]&&n[++b]===n[++m]&&n[++b]===n[++m]&&n[++b]===n[++m]&&n[++b]===n[++m]&&n[++b]===n[++m]&&n[++b]===n[++m]&&n[++b]===n[++m]&&bd){P=c;d=m;if(258<=m)break;q=n[b+d-1];e=n[b+d]}c=w[c&32767]}while(c>f&&0!==--a);return d},xa=function(c,a){r[H++]=a;0===c?aa[a].fc++:(c--,aa[fa[a]+256+1].fc++,ca[(256>c?M[c]:M[256+(c>>7)])&255].fc++,p[ga++]=c,ja|=ra);ra<<=1;0===(H&7)&&(ia[Z++]=ja,ja=0,ra=1);if(2d;d++)b+=ca[d].fc* -(5+oa[d]);b>>=3;if(ga>=1,b<<=1;while(0<--a);return b>>1},Ea=function(c,a){var b=[];b.length=16;var m=0,d;for(d=1;15>=d;d++)m=m+R[d-1]<<1,b[d]=m;for(m=0;m<=a;m++)d=c[m].dl,0!==d&&(c[m].fc=Da(b[d]++,d))},Ba=function(c){var a=c.dyn_tree,b=c.static_tree,m=c.elems,d,n=-1, -f=m;S=0;ha=573;for(d=0;dS;)d=L[++S]=2>n?++n:0,a[d].fc=1,ea[d]=0,W--,null!==b&&(C-=b[d].dl);c.max_code=n;for(d=S>>1;1<=d;d--)Aa(a,d);do d=L[1],L[1]=L[S--],Aa(a,1),b=L[1],L[--ha]=d,L[--ha]=b,a[f].fc=a[d].fc+a[b].fc,ea[f]=ea[d]>ea[b]+1?ea[d]:ea[b]+1,a[d].dl=a[b].dl=f,L[1]=f++,Aa(a,1);while(2<=S);L[--ha]=L[1];f=c.dyn_tree;d=c.extra_bits;var m=c.extra_base,b=c.max_code,g=c.max_length,q=c.static_tree,e,p,s,h,r=0;for(p=0;15>=p;p++)R[p]=0;f[L[ha]].dl= -0;for(c=ha+1;573>c;c++)e=L[c],p=f[f[e].dl].dl+1,p>g&&(p=g,r++),f[e].dl=p,e>b||(R[p]++,s=0,e>=m&&(s=d[e-m]),h=f[e].fc,W+=h*(p+s),null!==q&&(C+=h*(q[e].dl+s)));if(0!==r){do{for(p=g-1;0===R[p];)p--;R[p]--;R[p+1]+=2;R[g]--;r-=2}while(0b||(f[d].dl!==p&&(W+=(p-f[d].dl)*f[d].fc,f[d].fc=p),e--)}Ea(a,n)},Fa=function(c,a){var b,m=-1,d,f=c[0].dl,n=0,g=7,e=4;0===f&&(g=138,e=3);c[a+1].dl=65535;for(b=0;b<=a;b++)d=f,f=c[b+1].dl,++n=n?T[17].fc++:T[18].fc++,n=0,m=d,0===f?(g=138,e=3):d===f?(g=6,e=3):(g=7,e=4))},Ga=function(){8b?M[b]:M[256+(b>>7)])&255,$(g,a),e=oa[g],0!==e&&(b-=na[g],U(b,e))),n>>=1;while(m=n?($(17,T),U(n-3,3)):($(18,T),U(n-11,7));n=0;m=d;0===f?(g=138,e=3):d===f?(g=6,e=3):(g=7,e=4)}},Ja=function(){var c;for(c=0;286>c;c++)aa[c].fc=0;for(c=0;30>c;c++)ca[c].fc=0;for(c=0;19>c;c++)T[c].fc=0;aa[256].fc=1;ja=H=ga=Z=W=C=0;ra=1},ya=function(c){var a,b,m,d;d=B-x;ia[Z]=ja;Ba(N);Ba(E);Fa(aa,N.max_code);Fa(ca,E.max_code);Ba(K);for(m=18;3<=m&&0===T[ta[m]].dl;m--);W+= -3*(m+1)+14;a=W+3+7>>3;b=C+3+7>>3;b<=a&&(a=b);if(d+4<=a&&0<=x)for(U(0+c,3),Ga(),ma(d),ma(~d),m=0;ma.len&&(e=a.len);for(p=0;pt-m&&(e=t-m);for(p=0;pp;p++)for(G[p]=g,e= -0;e<1<p;p++)for(na[p]=g,e=0;e<1<>=7;30>p;p++)for(na[p]=g<<7,e=0;e<1<=e;e++)R[e]=0;for(e=0;143>=e;)Q[e++].dl=8,R[8]++;for(;255>=e;)Q[e++].dl=9,R[9]++;for(;279>=e;)Q[e++].dl=7,R[7]++;for(;287>=e;)Q[e++].dl=8,R[8]++;Ea(Q,287);for(e=0;30>e;e++)Y[e].dl=5,Y[e].fc=Da(e,5);Ja()}for(e=0;8192>e;e++)w[32768+e]=0;da=sa[V].max_lazy;qa=sa[V].good_length;X=sa[V].max_chain;x=B=0;J=pa(n,0,65536);if(0>=J)z=!0, -J=0;else{for(z=!1;262>J&&!z;)za();for(e=s=0;2>e;e++)s=(s<<5^n[e]&255)&8191}a=null;m=t=0;3>=V?(O=2,D=0):(D=2,F=0);q=!1}d=!0;if(0===J)return q=!0,0}e=Ka(c,b,f);if(e===f)return f;if(q)return e;if(3>=V)for(;0!==J&&null===a;){ba();0!==v&&32506>=B-v&&(D=Ca(v),D>J&&(D=J));if(3<=D)if(p=xa(B-P,D-3),J-=D,D<=da){D--;do B++,ba();while(0!==--D);B++}else B+=D,D=0,s=n[B]&255,s=(s<<5^n[B+1]&255)&8191;else p=xa(0,n[B]&255),J--,B++;p&&(ya(0),x=B);for(;262>J&&!z;)za()}else for(;0!==J&&null===a;){ba();O=D;A=P;D=2;0!== -v&&(O=B-v)&&(D=Ca(v),D>J&&(D=J),3===D&&4096J&&!z;)za()}0===J&&(0!==F&&xa(0,n[B-1]&255),ya(1),q=!0);return e+Ka(c,e+b,f-e)};this.deflate=function(m,e){var q,s;la=m;va=0;"undefined"===String(typeof e)&&(e=6);(q=e)?1>q?q=1:9q;q++)aa[q]=new k;ca=[];ca.length=61;for(q=0;61>q;q++)ca[q]=new k;Q=[];Q.length=288;for(q=0;288>q;q++)Q[q]=new k;Y=[];Y.length=30;for(q=0;30>q;q++)Y[q]=new k;T=[];T.length=39;for(q=0;39>q;q++)T[q]=new k;N=new l;E=new l;K=new l;R=[];R.length=16;L=[];L.length=573;ea=[];ea.length=573;fa=[];fa.length=256;M=[];M.length=512;G=[];G.length=29;na=[];na.length=30;ia=[];ia.length=1024}var h=Array(1024),u=[],v=[];for(q=La(h,0,h.length);0< -q;){v.length=q;for(s=0;s>>8):(ta(a&255),ta(a>>>8))},na=function(){s=(s<<5^g[z+3-1]&255)&8191;v=w[32768+s];w[z&32767]=v;w[32768+s]=z},ga=function(c,a){A>16-a?(u|=c<>16-A,A+=a-16):(u|=c<c;c++)g[c]=g[c+32768];P-=32768;z-=32768;y-=32768;for(c=0;8192>c;c++)a=w[32768+c],w[32768+c]=32768<=a?a-32768:0;for(c=0;32768>c;c++)a=w[c],w[c]=32768<=a?a-32768:0;b+=32768}C||(c=qa(g,z+K,b),0>=c?C=!0:K+=c)},Ca=function(c){var a=M,b=z,k,f=O,p=32506=aa&&(a>>=2);do if(k=c,g[k+f]===h&&g[k+f-1]===q&&g[k]===g[b]&&g[++k]===g[b+1]){b+= +2;k++;do++b;while(g[b]===g[++k]&&g[++b]===g[++k]&&g[++b]===g[++k]&&g[++b]===g[++k]&&g[++b]===g[++k]&&g[++b]===g[++k]&&g[++b]===g[++k]&&g[++b]===g[++k]&&bf){P=c;f=k;if(258<=k)break;q=g[b+f-1];h=g[b+f]}c=w[c&32767]}while(c>p&&0!==--a);return f},xa=function(c,a){r[V++]=a;0===c?ba[a].fc++:(c--,ba[oa[a]+256+1].fc++,ea[(256>c?L[c]:L[256+(c>>7)])&255].fc++,p[T++]=c,Z|=ka);ka<<=1;0===(V&7)&&(pa[ha++]=Z,Z=0,ka=1);if(2k;k++)b+=ea[k].fc* +(5+sa[k]);b>>=3;if(T>=1,b<<=1;while(0<--a);return b>>1},Ea=function(c,a){var b=[];b.length=16;var g=0,k;for(k=1;15>=k;k++)g=g+S[k-1]<<1,b[k]=g;for(g=0;g<=a;g++)k=c[g].dl,0!==k&&(c[g].fc=Da(b[k]++,k))},Ba=function(c){var a=c.dyn_tree,b=c.static_tree,g=c.elems,k,f=-1, +p=g;$=0;Y=573;for(k=0;k$;)k=R[++$]=2>f?++f:0,a[k].fc=1,fa[k]=0,la--,null!==b&&(X-=b[k].dl);c.max_code=f;for(k=$>>1;1<=k;k--)Aa(a,k);do k=R[1],R[1]=R[$--],Aa(a,1),b=R[1],R[--Y]=k,R[--Y]=b,a[p].fc=a[k].fc+a[b].fc,fa[p]=fa[k]>fa[b]+1?fa[k]:fa[b]+1,a[k].dl=a[b].dl=p,R[1]=p++,Aa(a,1);while(2<=$);R[--Y]=R[1];p=c.dyn_tree;k=c.extra_bits;var g=c.extra_base,b=c.max_code,d=c.max_length,q=c.static_tree,h,e,r,s,l=0;for(e=0;15>=e;e++)S[e]=0;p[R[Y]].dl=0; +for(c=Y+1;573>c;c++)h=R[c],e=p[p[h].dl].dl+1,e>d&&(e=d,l++),p[h].dl=e,h>b||(S[e]++,r=0,h>=g&&(r=k[h-g]),s=p[h].fc,la+=s*(e+r),null!==q&&(X+=s*(q[h].dl+r)));if(0!==l){do{for(e=d-1;0===S[e];)e--;S[e]--;S[e+1]+=2;S[d]--;l-=2}while(0b||(p[k].dl!==e&&(la+=(e-p[k].dl)*p[k].fc,p[k].fc=e),h--)}Ea(a,f)},Fa=function(c,a){var b,g=-1,k,f=c[0].dl,p=0,d=7,h=4;0===f&&(d=138,h=3);c[a+1].dl=65535;for(b=0;b<=a;b++)k=f,f=c[b+1].dl,++p=p?U[17].fc++:U[18].fc++,p=0,g=k,0===f?(d=138,h=3):k===f?(d=6,h=3):(d=7,h=4))},Ga=function(){8b?L[b]:L[256+(b>>7)])&255,H(h,a),e=sa[h],0!==e&&(b-=ia[h],ga(b,e))),d>>=1;while(k=p?(H(17,U),ga(p-3,3)):(H(18,U),ga(p-11,7));p=0;k=g;0===f?(d=138,h=3):g===f?(d=6,h=3):(d=7,h=4)}},Ja=function(){var c;for(c=0;286>c;c++)ba[c].fc=0;for(c=0;30>c;c++)ea[c].fc=0;for(c=0;19>c;c++)U[c].fc=0;ba[256].fc=1;Z=V=T=ha=la=X=0;ka=1},ya=function(c){var a,b,k,f;f=z-y;pa[ha]=Z;Ba(N);Ba(D);Fa(ba,N.max_code);Fa(ea,D.max_code);Ba(I);for(k=18;3<=k&&0===U[J[k]].dl;k--); +la+=3*(k+1)+14;a=la+3+7>>3;b=X+3+7>>3;b<=a&&(a=b);if(f+4<=a&&0<=y)for(ga(0+c,3),Ga(),ja(f),ja(~f),k=0;ka.len&&(d=a.len);for(h=0;ht-k&&(d=t-k);for(h=0;he;e++)for(G[e]= +h,d=0;d<1<e;e++)for(ia[e]=h,d=0;d<1<>=7;30>e;e++)for(ia[e]=h<<7,d=0;d<1<=d;d++)S[d]=0;for(d=0;143>=d;)Q[d++].dl=8,S[8]++;for(;255>=d;)Q[d++].dl=9,S[9]++;for(;279>=d;)Q[d++].dl=7,S[7]++;for(;287>=d;)Q[d++].dl=8,S[8]++;Ea(Q,287);for(d=0;30>d;d++)W[d].dl=5,W[d].fc=Da(d,5);Ja()}for(d=0;8192>d;d++)w[32768+d]=0;ca=ra[da].max_lazy;aa=ra[da].good_length;M=ra[da].max_chain;y=z=0;K=qa(g,0,65536);if(0>= +K)C=!0,K=0;else{for(C=!1;262>K&&!C;)za();for(d=s=0;2>d;d++)s=(s<<5^g[d]&255)&8191}a=null;k=t=0;3>=da?(O=2,E=0):(E=2,F=0);q=!1}f=!0;if(0===K)return q=!0,0}d=Ka(c,b,p);if(d===p)return p;if(q)return d;if(3>=da)for(;0!==K&&null===a;){na();0!==v&&32506>=z-v&&(E=Ca(v),E>K&&(E=K));if(3<=E)if(e=xa(z-P,E-3),K-=E,E<=ca){E--;do z++,na();while(0!==--E);z++}else z+=E,E=0,s=g[z]&255,s=(s<<5^g[z+1]&255)&8191;else e=xa(0,g[z]&255),K--,z++;e&&(ya(0),y=z);for(;262>K&&!C;)za()}else for(;0!==K&&null===a;){na();O=E;x= +P;E=2;0!==v&&(O=z-v)&&(E=Ca(v),E>K&&(E=K),3===E&&4096K&&!C;)za()}0===K&&(0!==F&&xa(0,g[z-1]&255),ya(1),q=!0);return d+Ka(c,d+b,p-d)};this.deflate=function(k,d){var q,s;B=k;ma=0;"undefined"===String(typeof d)&&(d=6);(q=d)?1>q?q=1:9q;q++)ba[q]=new n;ea=[];ea.length=61;for(q=0;61>q;q++)ea[q]=new n;Q=[];Q.length=288;for(q=0;288>q;q++)Q[q]=new n;W=[];W.length=30;for(q=0;30>q;q++)W[q]=new n;U=[];U.length=39;for(q=0;39>q;q++)U[q]=new n;N=new m;D=new m;I=new m;S=[];S.length=16;R=[];R.length=573;fa=[];fa.length=573;oa=[];oa.length=256;L=[];L.length=512;G=[];G.length=29;ia=[];ia.length=30;pa=[];pa.length=1024}var l=Array(1024),u=[],v=[];for(q=La(l, +0,l.length);0>8&255])};this.appendUInt32LE=function(e){l.appendArray([e&255,e>>8&255,e>>16&255,e>>24&255])};this.appendString=function(e){h=runtime.concatByteArrays(h, -runtime.byteArrayFromString(e,k))};this.getLength=function(){return h.length};this.getByteArray=function(){return h}}; +core.ByteArrayWriter=function(n){var m=this,l=new runtime.ByteArray(0);this.appendByteArrayWriter=function(d){l=runtime.concatByteArrays(l,d.getByteArray())};this.appendByteArray=function(d){l=runtime.concatByteArrays(l,d)};this.appendArray=function(d){l=runtime.concatByteArrays(l,runtime.byteArrayFromArray(d))};this.appendUInt16LE=function(d){m.appendArray([d&255,d>>8&255])};this.appendUInt32LE=function(d){m.appendArray([d&255,d>>8&255,d>>16&255,d>>24&255])};this.appendString=function(d){l=runtime.concatByteArrays(l, +runtime.byteArrayFromString(d,n))};this.getLength=function(){return l.length};this.getByteArray=function(){return l}}; // Input 6 -core.RawInflate=function(){var k,l,h=null,e,b,g,a,f,d,c,t,m,q,n,p,r,w,u=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],y=[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],x=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99],s=[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],v=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],A=[16,17,18, -0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],F=function(){this.list=this.next=null},D=function(){this.n=this.b=this.e=0;this.t=null},O=function(c,a,b,m,d,n){this.BMAX=16;this.N_MAX=288;this.status=0;this.root=null;this.m=0;var f=Array(this.BMAX+1),e,g,p,q,s,h,r,l=Array(this.BMAX+1),k,u,v,t=new D,w=Array(this.BMAX);q=Array(this.N_MAX);var x,y=Array(this.BMAX+1),A,B,z;z=this.root=null;for(s=0;ss&&(n=s);for(A=1<(A-=f[h])){this.status=2;this.m=n;return}if(0>(A-=f[s]))this.status=2,this.m=n;else{f[s]+=A;y[1]=h=0;k=f;u=1;for(v=2;0<--s;)y[v++]=h+=k[u++];k=c;s=u=0;do 0!=(h=k[u++])&&(q[y[h]++]=s);while(++sx+l[1+q];){x+=l[1+q];q++;B=(B=p-x)>n?n:B;if((g=1<<(h=r-x))>c+1)for(g-=c+1,v=r;++he&&x>x-l[q],w[q-1][h].e=t.e,w[q-1][h].b=t.b,w[q-1][h].n=t.n,w[q-1][h].t=t.t)}t.b=r-x;u>=a?t.e=99:k[u]k[u]?16:15,t.n=k[u++]): -(t.e=d[k[u]-b],t.n=m[k[u++]-b]);g=1<>x;h>=1)s^=h;for(s^=h;(s&(1<>=c;a-=c},J=function(a,b,d){var e,g,s;if(0==d)return 0;for(s=0;;){B(n);g=m.list[P(n)];for(e=g.e;16 -f;f++)k[A[f]]=0;n=7;f=new O(k,19,19,null,null,n);if(0!=f.status)return-1;m=f.root;n=f.m;g=r+l;for(d=e=0;df)k[d++]=e=f;else if(16==f){B(2);f=3+P(2);z(2);if(d+f>g)return-1;for(;0g)return-1;for(;0E;E++)N[E]=8;for(;256>E;E++)N[E]=9;for(;280>E;E++)N[E]=7;for(;288>E;E++)N[E]=8;b=7;E=new O(N,288,257,y,x,b);if(0!=E.status){alert("HufBuild error: "+E.status);Q=-1;break b}h=E.root;b=E.m;for(E=0;30>E;E++)N[E]=5;X=5;E=new O(N,30,0,s,v,X);if(1r&&(f=r);for(z=1<(z-=d[s])){this.status=2;this.m=f;return}if(0>(z-=d[r]))this.status=2,this.m=f;else{d[r]+=z;A[1]=s=0;n=d;m=1;for(v=2;0<--r;)A[v++]=s+=n[m++];n=c;r=m=0;do 0!=(s=n[m++])&&(e[A[s]++]=r);while(++rt+u[1+e];){t+=u[1+e];e++;x=(x=q-t)>f?f:x;if((h=1<<(s=l-t))>c+1)for(h-=c+1,v=l;++sp&&t>t-u[e],y[e-1][s].e=w.e,y[e-1][s].b=w.b,y[e-1][s].n=w.n,y[e-1][s].t=w.t)}w.b=l-t;m>=a?w.e=99:n[m]n[m]?16:15,w.n=n[m++]): +(w.e=g[n[m]-b],w.n=k[n[m++]-b]);h=1<>t;s>=1)r^=s;for(r^=s;(r&(1<>=c;a-=c},K=function(a,b,f){var d,e,r;if(0==f)return 0;for(r=0;;){z(g);e=k.list[P(g)];for(d=e.e;16 +f;f++)n[x[f]]=0;g=7;f=new O(n,19,19,null,null,g);if(0!=f.status)return-1;k=f.root;g=f.m;h=l+u;for(d=e=0;df)n[d++]=e=f;else if(16==f){z(2);f=3+P(2);C(2);if(d+f>h)return-1;for(;0h)return-1;for(;0D;D++)N[D]=8;for(;256>D;D++)N[D]=9;for(;280>D;D++)N[D]=7;for(;288>D;D++)N[D]=8;b=7;D=new O(N,288,257,A,y,b);if(0!=D.status){alert("HufBuild error: "+D.status);Q=-1;break b}l=D.root;b=D.m;for(D=0;30>D;D++)N[D]=5;M=5;D=new O(N,30,0,s,v,M);if(1k))throw runtime.log("alert","watchdog timeout"),"timeout!";if(0l))throw runtime.log("alert","watchdog loop overflow"),"loop overflow";}}; +core.LoopWatchDog=function(n,m){var l=Date.now(),d=0;this.check=function(){var b;if(n&&(b=Date.now(),b-l>n))throw runtime.log("alert","watchdog timeout"),"timeout!";if(0m))throw runtime.log("alert","watchdog loop overflow"),"loop overflow";}}; // Input 8 -core.Utils=function(){this.hashString=function(k){var l=0,h,e;h=0;for(e=k.length;h=h.compareBoundaryPoints(h.START_TO_START,e)&&0<=h.compareBoundaryPoints(h.END_TO_END,e)};this.rangesIntersect=function(h,e){return 0>=h.compareBoundaryPoints(h.END_TO_START,e)&&0<=h.compareBoundaryPoints(h.START_TO_END,e)};this.getNodesInRange=function(h,e){runtime.assert(Boolean(h.startContainer),"Expected to get a range with a startContainer in getNodesInRange().");var b=[],g,a=h.startContainer.ownerDocument.createTreeWalker(h.commonAncestorContainer, -NodeFilter.SHOW_ALL,e,!1);for(g=a.currentNode=h.startContainer;g;){if(e(g)===NodeFilter.FILTER_ACCEPT)b.push(g);else if(e(g)===NodeFilter.FILTER_REJECT)break;g=g.parentNode}b.reverse();for(g=a.nextNode();g;)b.push(g),g=a.nextNode();return b};this.normalizeTextNodes=function(h){h&&h.nextSibling&&(h=k(h,h.nextSibling));h&&h.previousSibling&&k(h.previousSibling,h)};this.rangeContainsNode=function(h,e){runtime.assert(Boolean(e),"Expected to get a node in rangeContainsNode()");var b=e.ownerDocument.createRange(), -g=e.nodeType===Node.TEXT_NODE?e.length:e.childNodes.length;b.setStart(h.startContainer,h.startOffset);b.setEnd(h.endContainer,h.endOffset);g=0===b.comparePoint(e,0)&&0===b.comparePoint(e,g);b.detach();return g};this.mergeIntoParent=function(h){for(var e=h.parentNode;h.firstChild;)e.insertBefore(h.firstChild,h);e.removeChild(h);return e};this.getElementsByTagNameNS=function(h,e,b){return Array.prototype.slice.call(h.getElementsByTagNameNS(e,b))};this.rangeIntersectsNode=function(h,e){var b=e.nodeType=== -Node.TEXT_NODE?e.length:e.childNodes.length;return 0>=h.comparePoint(e,0)&&0<=h.comparePoint(e,b)};this.containsNode=function(h,e){return h===e||h.contains(e)};(function(h){var e=runtime.getWindow();null!==e&&(e=e.navigator.appVersion.toLowerCase(),e=-1===e.indexOf("chrome")&&(-1!==e.indexOf("applewebkit")||-1!==e.indexOf("safari")))&&(h.containsNode=l)})(this)}; +core.DomUtils=function(){function n(l,d){if(l.nodeType===Node.TEXT_NODE)if(0===l.length)l.parentNode.removeChild(l);else if(d.nodeType===Node.TEXT_NODE)return d.insertData(0,l.data),l.parentNode.removeChild(l),d;return l}function m(l,d){return l===d||Boolean(l.compareDocumentPosition(d)&Node.DOCUMENT_POSITION_CONTAINED_BY)}this.splitBoundaries=function(l){var d=[],b;if(l.startContainer.nodeType===Node.TEXT_NODE||l.endContainer.nodeType===Node.TEXT_NODE){b=l.endContainer;var e=l.endOffset;if(e=l.compareBoundaryPoints(l.START_TO_START,d)&&0<=l.compareBoundaryPoints(l.END_TO_END,d)};this.rangesIntersect=function(l,d){return 0>=l.compareBoundaryPoints(l.END_TO_START,d)&&0<=l.compareBoundaryPoints(l.START_TO_END,d)};this.getNodesInRange=function(l,d){var b=[],e,a=l.startContainer.ownerDocument.createTreeWalker(l.commonAncestorContainer,NodeFilter.SHOW_ALL,d,!1);for(e=a.currentNode=l.startContainer;e;){if(d(e)=== +NodeFilter.FILTER_ACCEPT)b.push(e);else if(d(e)===NodeFilter.FILTER_REJECT)break;e=e.parentNode}b.reverse();for(e=a.nextNode();e;)b.push(e),e=a.nextNode();return b};this.normalizeTextNodes=function(l){l&&l.nextSibling&&(l=n(l,l.nextSibling));l&&l.previousSibling&&n(l.previousSibling,l)};this.rangeContainsNode=function(l,d){var b=d.ownerDocument.createRange(),e=d.nodeType===Node.TEXT_NODE?d.length:d.childNodes.length;b.setStart(l.startContainer,l.startOffset);b.setEnd(l.endContainer,l.endOffset);e= +0===b.comparePoint(d,0)&&0===b.comparePoint(d,e);b.detach();return e};this.mergeIntoParent=function(l){for(var d=l.parentNode;l.firstChild;)d.insertBefore(l.firstChild,l);d.removeChild(l);return d};this.getElementsByTagNameNS=function(l,d,b){return Array.prototype.slice.call(l.getElementsByTagNameNS(d,b))};this.rangeIntersectsNode=function(l,d){var b=d.nodeType===Node.TEXT_NODE?d.length:d.childNodes.length;return 0>=l.comparePoint(d,0)&&0<=l.comparePoint(d,b)};this.containsNode=function(l,d){return l=== +d||l.contains(d)};(function(l){var d=runtime.getWindow();null!==d&&(d=d.navigator.appVersion.toLowerCase(),d=-1===d.indexOf("chrome")&&(-1!==d.indexOf("applewebkit")||-1!==d.indexOf("safari")))&&(l.containsNode=m)})(this)}; // Input 10 runtime.loadClass("core.DomUtils"); -core.Cursor=function(k,l){function h(c){c.parentNode&&(f.push(c.previousSibling),f.push(c.nextSibling),c.parentNode.removeChild(c))}function e(c,a,b){if(a.nodeType===Node.TEXT_NODE){runtime.assert(Boolean(a),"putCursorIntoTextNode: invalid container");var d=a.parentNode;runtime.assert(Boolean(d),"putCursorIntoTextNode: container without parent");runtime.assert(0<=b&&b<=a.length,"putCursorIntoTextNode: offset is out of bounds");0===b?d.insertBefore(c,a):(b!==a.length&&a.splitText(b),d.insertBefore(c, -a.nextSibling))}else if(a.nodeType===Node.ELEMENT_NODE){runtime.assert(Boolean(a),"putCursorIntoContainer: invalid container");for(d=a.firstChild;null!==d&&01/e?"-0":String(e),k(c+" should be "+a+". Was "+f+".")):k(c+" should be "+a+" (of type "+typeof a+"). Was "+e+" (of type "+typeof e+").")}var a=0,f;f=function(a,c){var f=Object.keys(a),m=Object.keys(c);f.sort();m.sort();return l(f,m)&&Object.keys(a).every(function(m){var f= -a[m],e=c[m];return b(f,e)?!0:(k(f+" should be "+e+" for key "+m),!1)})};this.areNodesEqual=e;this.shouldBeNull=function(a,c){g(a,c,"null")};this.shouldBeNonNull=function(a,c){var b,m;try{m=eval(c)}catch(f){b=f}b?k(c+" should be non-null. Threw exception "+b):null!==m?runtime.log("pass",c+" is non-null."):k(c+" should be non-null. Was "+m)};this.shouldBe=g;this.countFailedTests=function(){return a}}; -core.UnitTester=function(){function k(e,b){return""+e+""}var l=0,h={};this.runTests=function(e,b,g){function a(m){if(0===m.length)h[f]=t,l+=d.countFailedTests(),b();else{q=m[0];var e=Runtime.getFunctionName(q);runtime.log("Running "+e);p=d.countFailedTests();c.setUp();q(function(){c.tearDown();t[e]=p===d.countFailedTests();a(m.slice(1))})}}var f=Runtime.getFunctionName(e),d=new core.UnitTestRunner,c=new e(d),t={},m,q,n,p,r="BrowserRuntime"=== -runtime.type();if(h.hasOwnProperty(f))runtime.log("Test "+f+" has already run.");else{r?runtime.log("Running "+k(f,'runSuite("'+f+'");')+": "+c.description()+""):runtime.log("Running "+f+": "+c.description);n=c.tests();for(m=0;mRunning "+k(e,'runTest("'+f+'","'+e+'")')+""):runtime.log("Running "+e),p=d.countFailedTests(),c.setUp(),q(),c.tearDown(),t[e]=p===d.countFailedTests()); -a(c.asyncTests())}};this.countFailedTests=function(){return l};this.results=function(){return h}}; +core.UnitTest.provideTestAreaDiv=function(){var n=runtime.getWindow().document,m=n.getElementById("testarea");runtime.assert(!m,'Unclean test environment, found a div with id "testarea".');m=n.createElement("div");m.setAttribute("id","testarea");n.body.appendChild(m);return m}; +core.UnitTest.cleanupTestAreaDiv=function(){var n=runtime.getWindow().document,m=n.getElementById("testarea");runtime.assert(!!m&&m.parentNode===n.body,'Test environment broken, found no div with id "testarea" below body.');n.body.removeChild(m)}; +core.UnitTestRunner=function(){function n(b){a+=1;runtime.log("fail",b)}function m(a,c){var b;try{if(a.length!==c.length)return n("array of length "+a.length+" should be "+c.length+" long"),!1;for(b=0;b1/e?"-0":String(e),n(c+" should be "+a+". Was "+d+".")):n(c+" should be "+a+" (of type "+typeof a+"). Was "+e+" (of type "+typeof e+").")}var a=0,h;h=function(a,c){var d=Object.keys(a),k=Object.keys(c);d.sort();k.sort();return m(d,k)&&Object.keys(a).every(function(k){var g= +a[k],d=c[k];return b(g,d)?!0:(n(g+" should be "+d+" for key "+k),!1)})};this.areNodesEqual=d;this.shouldBeNull=function(a,c){e(a,c,"null")};this.shouldBeNonNull=function(a,c){var b,k;try{k=eval(c)}catch(d){b=d}b?n(c+" should be non-null. Threw exception "+b):null!==k?runtime.log("pass",c+" is non-null."):n(c+" should be non-null. Was "+k)};this.shouldBe=e;this.countFailedTests=function(){return a}}; +core.UnitTester=function(){function n(d,b){return""+d+""}var m=0,l={};this.runTests=function(d,b,e){function a(k){if(0===k.length)l[h]=t,m+=f.countFailedTests(),b();else{q=k[0];var d=Runtime.getFunctionName(q);runtime.log("Running "+d);p=f.countFailedTests();c.setUp();q(function(){c.tearDown();t[d]=p===f.countFailedTests();a(k.slice(1))})}}var h=Runtime.getFunctionName(d),f=new core.UnitTestRunner,c=new d(f),t={},k,q,g,p,r="BrowserRuntime"=== +runtime.type();if(l.hasOwnProperty(h))runtime.log("Test "+h+" has already run.");else{r?runtime.log("Running "+n(h,'runSuite("'+h+'");')+": "+c.description()+""):runtime.log("Running "+h+": "+c.description);g=c.tests();for(k=0;kRunning "+n(d,'runTest("'+h+'","'+d+'")')+""):runtime.log("Running "+d),p=f.countFailedTests(),c.setUp(),q(),c.tearDown(),t[d]=p===f.countFailedTests()); +a(c.asyncTests())}};this.countFailedTests=function(){return m};this.results=function(){return l}}; // Input 13 -core.PositionIterator=function(k,l,h,e){function b(){this.acceptNode=function(c){return c.nodeType===Node.TEXT_NODE&&0===c.length?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}}function g(c){this.acceptNode=function(a){return a.nodeType===Node.TEXT_NODE&&0===a.length?NodeFilter.FILTER_REJECT:c.acceptNode(a)}}function a(){var a=d.currentNode.nodeType;c=a===Node.TEXT_NODE?d.currentNode.length-1:a===Node.ELEMENT_NODE?1:0}var f=this,d,c,t;this.nextPosition=function(){if(d.currentNode===k)return!1; -if(0===c&&d.currentNode.nodeType===Node.ELEMENT_NODE)null===d.firstChild()&&(c=1);else if(d.currentNode.nodeType===Node.TEXT_NODE&&c+1 "+a.length),runtime.assert(0<=b,"Error in setPosition: "+b+" < 0"), -b===a.length&&(c=void 0,d.nextSibling()?c=0:d.parentNode()&&(c=1),runtime.assert(void 0!==c,"Error in setPosition: position not valid.")),!0;e=t(a);b "+a.length),runtime.assert(0<=b,"Error in setPosition: "+b+" < 0"), +b===a.length&&(c=void 0,f.nextSibling()?c=0:f.parentNode()&&(c=1),runtime.assert(void 0!==c,"Error in setPosition: position not valid.")),!0;d=t(a);b>>8^m;return b^-1}function e(a){return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&15,a>>5&63,(a&31)<<1)}function b(a){var c=a.getFullYear();return 1980>c?0:c-1980<< -25|a.getMonth()+1<<21|a.getDate()<<16|a.getHours()<<11|a.getMinutes()<<5|a.getSeconds()>>1}function g(a,c){var b,d,f,m,g,n,h,q=this;this.load=function(c){if(void 0!==q.data)c(null,q.data);else{var b=g+34+d+f+256;b+h>p&&(b=p-h);runtime.read(a,h,b,function(b,d){if(b||null===d)c(b,d);else a:{var f=d,e=new core.ByteArray(f),p=e.readUInt32LE(),s;if(67324752!==p)c("File entry signature is wrong."+p.toString()+" "+f.length.toString(),null);else{e.pos+=22;p=e.readUInt16LE();s=e.readUInt16LE();e.pos+=p+s; -if(m){f=f.slice(e.pos,e.pos+g);if(g!==f.length){c("The amount of compressed bytes read was "+f.length.toString()+" instead of "+g.toString()+" for "+q.filename+" in "+a+".",null);break a}f=w(f,n)}else f=f.slice(e.pos,e.pos+n);n!==f.length?c("The amount of bytes read was "+f.length.toString()+" instead of "+n.toString()+" for "+q.filename+" in "+a+".",null):(q.data=f,c(null,f))}}})}};this.set=function(a,c,b,d){q.filename=a;q.data=c;q.compressed=b;q.date=d};this.error=null;c&&(b=c.readUInt32LE(),33639248!== -b?this.error="Central directory entry has wrong signature at position "+(c.pos-4).toString()+' for file "'+a+'": '+c.data.length.toString():(c.pos+=6,m=c.readUInt16LE(),this.date=e(c.readUInt32LE()),c.readUInt32LE(),g=c.readUInt32LE(),n=c.readUInt32LE(),d=c.readUInt16LE(),f=c.readUInt16LE(),b=c.readUInt16LE(),c.pos+=8,h=c.readUInt32LE(),this.filename=runtime.byteArrayToString(c.data.slice(c.pos,c.pos+d),"utf8"),c.pos+=d+f+b))}function a(a,c){if(22!==a.length)c("Central directory length should be 22.", -u);else{var b=new core.ByteArray(a),d;d=b.readUInt32LE();101010256!==d?c("Central directory signature is wrong: "+d.toString(),u):(d=b.readUInt16LE(),0!==d?c("Zip files with non-zero disk numbers are not supported.",u):(d=b.readUInt16LE(),0!==d?c("Zip files with non-zero disk numbers are not supported.",u):(d=b.readUInt16LE(),r=b.readUInt16LE(),d!==r?c("Number of entries is inconsistent.",u):(d=b.readUInt32LE(),b=b.readUInt16LE(),b=p-22-d,runtime.read(k,b,p-b,function(a,b){if(a||null===b)c(a,u);else a:{var d= -new core.ByteArray(b),f,m;n=[];for(f=0;fp?l("File '"+k+"' cannot be read.",u):runtime.read(k,p-22,22,function(c,b){c||null===l||null===b?l(c,u):a(b,l)})})}; +2932959818,3654703836,1088359270,936918E3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117],b,d,g=a.length,k=0,k=0;b=-1;for(d=0;d>>8^k;return b^-1}function d(a){return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&15,a>>5&63,(a&31)<<1)}function b(a){var c=a.getFullYear();return 1980>c?0:c-1980<< +25|a.getMonth()+1<<21|a.getDate()<<16|a.getHours()<<11|a.getMinutes()<<5|a.getSeconds()>>1}function e(a,c){var b,g,k,f,e,h,r,q=this;this.load=function(c){if(void 0!==q.data)c(null,q.data);else{var b=e+34+g+k+256;b+r>p&&(b=p-r);runtime.read(a,r,b,function(b,d){if(b||null===d)c(b,d);else a:{var g=d,k=new core.ByteArray(g),p=k.readUInt32LE(),r;if(67324752!==p)c("File entry signature is wrong."+p.toString()+" "+g.length.toString(),null);else{k.pos+=22;p=k.readUInt16LE();r=k.readUInt16LE();k.pos+=p+r; +if(f){g=g.slice(k.pos,k.pos+e);if(e!==g.length){c("The amount of compressed bytes read was "+g.length.toString()+" instead of "+e.toString()+" for "+q.filename+" in "+a+".",null);break a}g=w(g,h)}else g=g.slice(k.pos,k.pos+h);h!==g.length?c("The amount of bytes read was "+g.length.toString()+" instead of "+h.toString()+" for "+q.filename+" in "+a+".",null):(q.data=g,c(null,g))}}})}};this.set=function(a,c,b,d){q.filename=a;q.data=c;q.compressed=b;q.date=d};this.error=null;c&&(b=c.readUInt32LE(),33639248!== +b?this.error="Central directory entry has wrong signature at position "+(c.pos-4).toString()+' for file "'+a+'": '+c.data.length.toString():(c.pos+=6,f=c.readUInt16LE(),this.date=d(c.readUInt32LE()),c.readUInt32LE(),e=c.readUInt32LE(),h=c.readUInt32LE(),g=c.readUInt16LE(),k=c.readUInt16LE(),b=c.readUInt16LE(),c.pos+=8,r=c.readUInt32LE(),this.filename=runtime.byteArrayToString(c.data.slice(c.pos,c.pos+g),"utf8"),c.pos+=g+k+b))}function a(a,c){if(22!==a.length)c("Central directory length should be 22.", +u);else{var b=new core.ByteArray(a),d;d=b.readUInt32LE();101010256!==d?c("Central directory signature is wrong: "+d.toString(),u):(d=b.readUInt16LE(),0!==d?c("Zip files with non-zero disk numbers are not supported.",u):(d=b.readUInt16LE(),0!==d?c("Zip files with non-zero disk numbers are not supported.",u):(d=b.readUInt16LE(),r=b.readUInt16LE(),d!==r?c("Number of entries is inconsistent.",u):(d=b.readUInt32LE(),b=b.readUInt16LE(),b=p-22-d,runtime.read(n,b,p-b,function(a,b){if(a||null===b)c(a,u);else a:{var d= +new core.ByteArray(b),k,f;g=[];for(k=0;kp?m("File '"+n+"' cannot be read.",u):runtime.read(n,p-22,22,function(c,b){c||null===m||null===b?m(c,u):a(b,m)})})}; // Input 18 -core.CSSUnits=function(){var k={"in":1,cm:2.54,mm:25.4,pt:72,pc:12};this.convert=function(l,h,e){return l*k[e]/k[h]};this.convertMeasure=function(k,h){var e,b;k&&h?(e=parseFloat(k),b=k.replace(e.toString(),""),e=this.convert(e,b,h)):e="";return e.toString()};this.getUnits=function(k){return k.substr(k.length-2,k.length)}}; +core.CSSUnits=function(){var n={"in":1,cm:2.54,mm:25.4,pt:72,pc:12};this.convert=function(m,l,d){return m*n[d]/n[l]};this.convertMeasure=function(n,l){var d,b;n&&l?(d=parseFloat(n),b=n.replace(d.toString(),""),d=this.convert(d,b,l)):d="";return d.toString()};this.getUnits=function(n){return n.substr(n.length-2,n.length)}}; // Input 19 xmldom.LSSerializerFilter=function(){}; // Input 20 -"function"!==typeof Object.create&&(Object.create=function(k){var l=function(){};l.prototype=k;return new l}); -xmldom.LSSerializer=function(){function k(b){var e=b||{},a=function(a){var c={},b;for(b in a)a.hasOwnProperty(b)&&(c[a[b]]=b);return c}(b),f=[e],d=[a],c=0;this.push=function(){c+=1;e=f[c]=Object.create(e);a=d[c]=Object.create(a)};this.pop=function(){f[c]=void 0;d[c]=void 0;c-=1;e=f[c];a=d[c]};this.getLocalNamespaceDefinitions=function(){return a};this.getQName=function(c){var b=c.namespaceURI,d=0,f;if(!b)return c.localName;if(f=a[b])return f+":"+c.localName;do{f||!c.prefix?(f="ns"+d,d+=1):f=c.prefix; -if(e[f]===b)break;if(!e[f]){e[f]=b;a[b]=f;break}f=null}while(null===f);return f+":"+c.localName}}function l(b){return b.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")}function h(b,g){var a="",f=e.filter?e.filter.acceptNode(g):NodeFilter.FILTER_ACCEPT,d;if(f===NodeFilter.FILTER_ACCEPT&&g.nodeType===Node.ELEMENT_NODE){b.push();d=b.getQName(g);var c,k=g.attributes,m,q,n,p="",r;c="<"+d;m=k.length;for(q=0;q")}if(f===NodeFilter.FILTER_ACCEPT||f===NodeFilter.FILTER_SKIP){for(f=g.firstChild;f;)a+=h(b,f),f=f.nextSibling;g.nodeValue&&(a+=l(g.nodeValue))}d&&(a+="",b.pop());return a}var e=this;this.filter=null;this.writeToString=function(b,e){if(!b)return"";var a=new k(e);return h(a,b)}}; +"function"!==typeof Object.create&&(Object.create=function(n){var m=function(){};m.prototype=n;return new m}); +xmldom.LSSerializer=function(){function n(b){var d=b||{},a=function(a){var c={},b;for(b in a)a.hasOwnProperty(b)&&(c[a[b]]=b);return c}(b),h=[d],f=[a],c=0;this.push=function(){c+=1;d=h[c]=Object.create(d);a=f[c]=Object.create(a)};this.pop=function(){h[c]=void 0;f[c]=void 0;c-=1;d=h[c];a=f[c]};this.getLocalNamespaceDefinitions=function(){return a};this.getQName=function(c){var b=c.namespaceURI,f=0,g;if(!b)return c.localName;if(g=a[b])return g+":"+c.localName;do{g||!c.prefix?(g="ns"+f,f+=1):g=c.prefix; +if(d[g]===b)break;if(!d[g]){d[g]=b;a[b]=g;break}g=null}while(null===g);return g+":"+c.localName}}function m(b){return b.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")}function l(b,e){var a="",h=d.filter?d.filter.acceptNode(e):NodeFilter.FILTER_ACCEPT,f;if(h===NodeFilter.FILTER_ACCEPT&&e.nodeType===Node.ELEMENT_NODE){b.push();f=b.getQName(e);var c,n=e.attributes,k,q,g,p="",r;c="<"+f;k=n.length;for(q=0;q")}if(h===NodeFilter.FILTER_ACCEPT||h===NodeFilter.FILTER_SKIP){for(h=e.firstChild;h;)a+=l(b,h),h=h.nextSibling;e.nodeValue&&(a+=m(e.nodeValue))}f&&(a+="",b.pop());return a}var d=this;this.filter=null;this.writeToString=function(b,d){if(!b)return"";var a=new n(d);return l(a,b)}}; // Input 21 -xmldom.RelaxNGParser=function(){function k(a,b){this.message=function(){b&&(a+=1===b.nodeType?" Element ":" Node ",a+=b.nodeName,b.nodeValue&&(a+=" with value '"+b.nodeValue+"'"),a+=".");return a}}function l(a){if(2>=a.e.length)return a;var b={name:a.name,e:a.e.slice(0,2)};return l({name:a.name,e:[b].concat(a.e.slice(2))})}function h(a){a=a.split(":",2);var b="",d;1===a.length?a=["",a[0]]:b=a[0];for(d in f)f[d]===b&&(a[0]=d);return a}function e(a,b){for(var d=0,f,g,p=a.name;a.e&&d=a.e.length)return a;var b={name:a.name,e:a.e.slice(0,2)};return m({name:a.name,e:[b].concat(a.e.slice(2))})}function l(a){a=a.split(":",2);var b="",d;1===a.length?a=["",a[0]]:b=a[0];for(d in h)h[d]===b&&(a[0]=d);return a}function d(a,b){for(var k=0,f,g,e=a.name;a.e&&k=d.length)return b;0===e&&(e=0);for(var m=d.item(e);m.namespaceURI===c;){e+=1;if(e>=d.length)return b;m=d.item(e)}return m=f(a,b.attDeriv(a,d.item(e)),d,e+1)}function d(a,b,c){c.e[0].a?(a.push(c.e[0].text),b.push(c.e[0].a.ns)):d(a,b,c.e[0]);c.e[1].a?(a.push(c.e[1].text),b.push(c.e[1].a.ns)): -d(a,b,c.e[1])}var c="http://www.w3.org/2000/xmlns/",t,m,q,n,p,r,w,u,y,x,s={type:"notAllowed",nullable:!1,hash:"notAllowed",textDeriv:function(){return s},startTagOpenDeriv:function(){return s},attDeriv:function(){return s},startTagCloseDeriv:function(){return s},endTagDeriv:function(){return s}},v={type:"empty",nullable:!0,hash:"empty",textDeriv:function(){return s},startTagOpenDeriv:function(){return s},attDeriv:function(){return s},startTagCloseDeriv:function(){return v},endTagDeriv:function(){return s}}, -A={type:"text",nullable:!0,hash:"text",textDeriv:function(){return A},startTagOpenDeriv:function(){return s},attDeriv:function(){return s},startTagCloseDeriv:function(){return A},endTagDeriv:function(){return s}},F,D,O;t=e("choice",function(a,b){if(a===s)return b;if(b===s||a===b)return a},function(a,c){var d={},f;b(d,{p1:a,p2:c});c=a=void 0;for(f in d)d.hasOwnProperty(f)&&(void 0===a?a=d[f]:c=void 0===c?d[f]:t(c,d[f]));return function(a,b){return{type:"choice",p1:a,p2:b,nullable:a.nullable||b.nullable, -textDeriv:function(c,d){return t(a.textDeriv(c,d),b.textDeriv(c,d))},startTagOpenDeriv:h(function(c){return t(a.startTagOpenDeriv(c),b.startTagOpenDeriv(c))}),attDeriv:function(c,d){return t(a.attDeriv(c,d),b.attDeriv(c,d))},startTagCloseDeriv:k(function(){return t(a.startTagCloseDeriv(),b.startTagCloseDeriv())}),endTagDeriv:k(function(){return t(a.endTagDeriv(),b.endTagDeriv())})}}(a,c)});m=function(a,b,c){return function(){var d={},f=0;return function(e,m){var g=b&&b(e,m),n,p;if(void 0!==g)return g; -g=e.hash||e.toString();n=m.hash||m.toString();g=d.length)return b;0===g&&(g=0);for(var f=d.item(g);f.namespaceURI===c;){g+=1;if(g>=d.length)return b;f=d.item(g)}return f=h(a,b.attDeriv(a,d.item(g)),d,g+1)}function f(a,b,c){c.e[0].a?(a.push(c.e[0].text),b.push(c.e[0].a.ns)):f(a,b,c.e[0]);c.e[1].a?(a.push(c.e[1].text),b.push(c.e[1].a.ns)): +f(a,b,c.e[1])}var c="http://www.w3.org/2000/xmlns/",t,k,q,g,p,r,w,u,A,y,s={type:"notAllowed",nullable:!1,hash:"notAllowed",textDeriv:function(){return s},startTagOpenDeriv:function(){return s},attDeriv:function(){return s},startTagCloseDeriv:function(){return s},endTagDeriv:function(){return s}},v={type:"empty",nullable:!0,hash:"empty",textDeriv:function(){return s},startTagOpenDeriv:function(){return s},attDeriv:function(){return s},startTagCloseDeriv:function(){return v},endTagDeriv:function(){return s}}, +x={type:"text",nullable:!0,hash:"text",textDeriv:function(){return x},startTagOpenDeriv:function(){return s},attDeriv:function(){return s},startTagCloseDeriv:function(){return x},endTagDeriv:function(){return s}},F,E,O;t=d("choice",function(a,b){if(a===s)return b;if(b===s||a===b)return a},function(a,c){var d={},g;b(d,{p1:a,p2:c});c=a=void 0;for(g in d)d.hasOwnProperty(g)&&(void 0===a?a=d[g]:c=void 0===c?d[g]:t(c,d[g]));return function(a,b){return{type:"choice",p1:a,p2:b,nullable:a.nullable||b.nullable, +textDeriv:function(c,d){return t(a.textDeriv(c,d),b.textDeriv(c,d))},startTagOpenDeriv:l(function(c){return t(a.startTagOpenDeriv(c),b.startTagOpenDeriv(c))}),attDeriv:function(c,d){return t(a.attDeriv(c,d),b.attDeriv(c,d))},startTagCloseDeriv:n(function(){return t(a.startTagCloseDeriv(),b.startTagCloseDeriv())}),endTagDeriv:n(function(){return t(a.endTagDeriv(),b.endTagDeriv())})}}(a,c)});k=function(a,b,c){return function(){var d={},g=0;return function(f,k){var e=b&&b(f,k),h,p;if(void 0!==e)return e; +e=f.hash||f.toString();h=k.hash||k.toString();eNode.ELEMENT_NODE;){if(c!==Node.COMMENT_NODE&&(c!==Node.TEXT_NODE||!/^\s+$/.test(b.currentNode.nodeValue)))return[new k("Not allowed node of type "+ -c+".")];c=(d=b.nextSibling())?d.nodeType:0}if(!d)return[new k("Missing element "+a.names)];if(a.names&&-1===a.names.indexOf(g[d.namespaceURI]+":"+d.localName))return[new k("Found "+d.nodeName+" instead of "+a.names+".",d)];if(b.firstChild()){for(e=l(a.e[1],b,d);b.nextSibling();)if(c=b.currentNode.nodeType,!(b.currentNode&&b.currentNode.nodeType===Node.TEXT_NODE&&/^\s+$/.test(b.currentNode.nodeValue)||c===Node.COMMENT_NODE))return[new k("Spurious content.",b.currentNode)];if(b.parentNode()!==d)return[new k("Implementation error.")]}else e= -l(a.e[1],b,d);b.nextSibling();return e}var e,b,g;b=function(a,f,d,c){var e=a.name,g=null;if("text"===e)a:{for(var q=(a=f.currentNode)?a.nodeType:0;a!==d&&3!==q;){if(1===q){g=[new k("Element not allowed here.",a)];break a}q=(a=f.nextSibling())?a.nodeType:0}f.nextSibling();g=null}else if("data"===e)g=null;else if("value"===e)c!==a.text&&(g=[new k("Wrong value, should be '"+a.text+"', not '"+c+"'",d)]);else if("list"===e)g=null;else if("attribute"===e)a:{if(2!==a.e.length)throw"Attribute with wrong # of elements: "+ -a.e.length;e=a.localnames.length;for(g=0;gNode.ELEMENT_NODE;){if(c!==Node.COMMENT_NODE&&(c!==Node.TEXT_NODE||!/^\s+$/.test(b.currentNode.nodeValue)))return[new n("Not allowed node of type "+ +c+".")];c=(d=b.nextSibling())?d.nodeType:0}if(!d)return[new n("Missing element "+a.names)];if(a.names&&-1===a.names.indexOf(e[d.namespaceURI]+":"+d.localName))return[new n("Found "+d.nodeName+" instead of "+a.names+".",d)];if(b.firstChild()){for(l=m(a.e[1],b,d);b.nextSibling();)if(c=b.currentNode.nodeType,!(b.currentNode&&b.currentNode.nodeType===Node.TEXT_NODE&&/^\s+$/.test(b.currentNode.nodeValue)||c===Node.COMMENT_NODE))return[new n("Spurious content.",b.currentNode)];if(b.parentNode()!==d)return[new n("Implementation error.")]}else l= +m(a.e[1],b,d);b.nextSibling();return l}var d,b,e;b=function(a,d,f,c){var e=a.name,k=null;if("text"===e)a:{for(var q=(a=d.currentNode)?a.nodeType:0;a!==f&&3!==q;){if(1===q){k=[new n("Element not allowed here.",a)];break a}q=(a=d.nextSibling())?a.nodeType:0}d.nextSibling();k=null}else if("data"===e)k=null;else if("value"===e)c!==a.text&&(k=[new n("Wrong value, should be '"+a.text+"', not '"+c+"'",f)]);else if("list"===e)k=null;else if("attribute"===e)a:{if(2!==a.e.length)throw"Attribute with wrong # of elements: "+ +a.e.length;e=a.localnames.length;for(k=0;k=e&&c.push(l(a.substring(b,d)))):"["===a[d]&&(0>=e&&(b=d+1),e+=1),d+=1;return d};xmldom.XPathIterator.prototype.next=function(){};xmldom.XPathIterator.prototype.reset=function(){};c=function(c,d,g){var h,k,l,u;for(h=0;h=e&&c.push(m(a.substring(b,d)))):"["===a[d]&&(0>=e&&(b=d+1),e+=1),d+=1;return d};xmldom.XPathIterator.prototype.next=function(){};xmldom.XPathIterator.prototype.reset=function(){};c=function(c,f,e){var p,r,l,n;for(p=0;p=(l.getBoundingClientRect().top- -y.bottom)/w?e.style.top=Math.abs(l.getBoundingClientRect().top-y.bottom)/w+20+"px":e.style.top="0px");p.style.left=g.getBoundingClientRect().width/w+"px";var g=p.style,l=p.getBoundingClientRect().left/w,u=p.getBoundingClientRect().top/w,y=e.getBoundingClientRect().left/w,x=e.getBoundingClientRect().top/w,s=0,v=0,s=y-l,s=s*s,v=x-u,v=v*v,l=Math.sqrt(s+v);g.width=l+"px";w=Math.asin((e.getBoundingClientRect().top-p.getBoundingClientRect().top)/(w*parseFloat(p.style.width)));p.style.transform="rotate("+ -w+"rad)";p.style.MozTransform="rotate("+w+"rad)";p.style.WebkitTransform="rotate("+w+"rad)";p.style.msTransform="rotate("+w+"rad)";d&&(w=c.getComputedStyle(d,":before").content)&&"none"!==w&&(w=w.substring(1,w.length-1),d.firstChild?d.firstChild.nodeValue=w:d.appendChild(f.createTextNode(w)))}}runtime.assert(Boolean(l),"Expected to get an odfFragment");var a=[],f=l.ownerDocument,d=new odf.OdfUtils,c=runtime.getWindow();runtime.assert(Boolean(c),"Expected to be run in an environment which has a global window, like a browser."); -this.rerenderAnnotations=g;this.addAnnotation=function(c){a.push({node:c.node,end:c.end});b();var d=f.createElement("div"),h=f.createElement("div"),n=f.createElement("div"),p=f.createElement("div"),k=f.createElement("div"),l=c.node;d.className="annotationWrapper";l.parentNode.insertBefore(d,l);h.className="annotationNote";h.appendChild(l);k.className="annotationRemoveButton";h.appendChild(k);n.className="annotationConnector horizontal";p.className="annotationConnector angular";d.appendChild(h);d.appendChild(n); -d.appendChild(p);c.end&&e(c);g()};this.forgetAnnotations=function(){for(;a.length;){var b=a[0],c=a.indexOf(b),d=b.node,e=d.parentNode.parentNode;"div"===e.localName&&(e.parentNode.insertBefore(d,e),e.parentNode.removeChild(e));b=b.node.getAttributeNS(odf.Namespaces.officens,"name");b=f.querySelectorAll('span.annotationHighlight[annotation="'+b+'"]');e=d=void 0;for(d=0;d=(m.getBoundingClientRect().top-y.bottom)/u?c.style.top=Math.abs(m.getBoundingClientRect().top-y.bottom)/u+20+"px":c.style.top="0px");e.style.left=d.getBoundingClientRect().width/u+"px";var d=e.style,m=e.getBoundingClientRect().left/u,A=e.getBoundingClientRect().top/u,y=c.getBoundingClientRect().left/u,s=c.getBoundingClientRect().top/u,v=0,x= +0,v=y-m,v=v*v,x=s-A,x=x*x,m=Math.sqrt(v+x);d.width=m+"px";u=Math.asin((c.getBoundingClientRect().top-e.getBoundingClientRect().top)/(u*parseFloat(e.style.width)));e.style.transform="rotate("+u+"rad)";e.style.MozTransform="rotate("+u+"rad)";e.style.WebkitTransform="rotate("+u+"rad)";e.style.msTransform="rotate("+u+"rad)";b&&(u=t.getComputedStyle(b,":before").content)&&"none"!==u&&(u=u.substring(1,u.length-1),b.firstChild?b.firstChild.nodeValue=u:b.appendChild(f.createTextNode(u)))}}var h=[],f=m.ownerDocument, +c=new odf.OdfUtils,t=runtime.getWindow();runtime.assert(Boolean(t),"Expected to be run in an environment which has a global window, like a browser.");this.rerenderAnnotations=a;this.addAnnotation=function(c){b(!0);h.push({node:c.node,end:c.end});e();var l=f.createElement("div"),g=f.createElement("div"),p=f.createElement("div"),r=f.createElement("div"),n=f.createElement("div"),u=c.node;l.className="annotationWrapper";u.parentNode.insertBefore(l,u);g.className="annotationNote";g.appendChild(u);n.className= +"annotationRemoveButton";g.appendChild(n);p.className="annotationConnector horizontal";r.className="annotationConnector angular";l.appendChild(g);l.appendChild(p);l.appendChild(r);c.end&&d(c);a()};this.forgetAnnotations=function(){for(;h.length;){var a=h[0],c=h.indexOf(a),d=a.node,e=d.parentNode.parentNode;"div"===e.localName&&(e.parentNode.insertBefore(d,e),e.parentNode.removeChild(e));a=a.node.getAttributeNS(odf.Namespaces.officens,"name");a=f.querySelectorAll('span.annotationHighlight[annotation="'+ +a+'"]');e=d=void 0;for(d=0;d=b.value||"%"===b.unit)?null:b;return b||p(a)};this.parseFoLineHeight=function(a){var b;b=(b=n(a))&&(0>b.value|| -"%"===b.unit)?null:b;return b||p(a)};this.getImpactedParagraphs=function(a){var b=a.commonAncestorContainer,c=[];for(b.nodeType===Node.ELEMENT_NODE&&(c=x.getElementsByTagNameNS(b,w,"p").concat(x.getElementsByTagNameNS(b,w,"h")));b&&!k(b);)b=b.parentNode;b&&c.push(b);return c.filter(function(b){return x.rangeIntersectsNode(a,b)})};this.getTextNodes=function(a,b){runtime.assert(Boolean(a.startContainer),"Expected to get a range with a startContainer in getTextNodes().");var c=a.startContainer.ownerDocument.createRange(), -d;d=x.getNodesInRange(a,function(d){c.selectNodeContents(d);if(d.nodeType===Node.TEXT_NODE){if(b&&x.rangesIntersect(a,c)||x.containsRange(a,c))return Boolean(l(d)&&(!h(d.textContent)||q(d,0)))?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}else if(x.rangesIntersect(a,c)&&r(d))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});c.detach();return d};this.getTextElements=function(a,c){runtime.assert(Boolean(a.startContainer),"Expected to get a range with a startContainer in getTextElements()."); -var d=a.startContainer.ownerDocument.createRange(),f;f=x.getNodesInRange(a,function(f){var g=f.nodeType;d.selectNodeContents(f);if(g===Node.TEXT_NODE){if(x.containsRange(a,d)&&(c||Boolean(l(f)&&(!h(f.textContent)||q(f,0)))))return NodeFilter.FILTER_ACCEPT}else if(b(f)){if(x.containsRange(a,d))return NodeFilter.FILTER_ACCEPT}else if(r(f)||e(f))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});d.detach();return f};this.getParagraphElements=function(a){runtime.assert(Boolean(a.startContainer), -"Expected to get a range with a startContainer in getParagraphElements().");var b=a.startContainer.ownerDocument.createRange(),c;c=x.getNodesInRange(a,function(c){b.selectNodeContents(c);if(k(c)){if(x.rangesIntersect(a,b))return NodeFilter.FILTER_ACCEPT}else if(r(c)||e(c))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});b.detach();return c}}; +odf.OdfUtils=function(){function n(a){var b=a&&a.localName;return("p"===b||"h"===b)&&a.namespaceURI===w}function m(a){for(;a&&!n(a);)a=a.parentNode;return a}function l(a){return/^[ \t\r\n]+$/.test(a)}function d(a){var b=a&&a.localName;return/^(span|p|h|a|meta)$/.test(b)&&a.namespaceURI===w||"span"===b&&"annotationHighlight"===a.className?!0:!1}function b(a){var b=a&&a.localName,c,d=!1;b&&(c=a.namespaceURI,c===w?d="s"===b||"tab"===b||"line-break"===b:c===u&&(d="frame"===b&&"as-char"===a.getAttributeNS(w, +"anchor-type")));return d}function e(a){for(;null!==a.firstChild&&d(a);)a=a.firstChild;return a}function a(a){for(;null!==a.lastChild&&d(a);)a=a.lastChild;return a}function h(b){for(;!n(b)&&null===b.previousSibling;)b=b.parentNode;return n(b)?null:a(b.previousSibling)}function f(a){for(;!n(a)&&null===a.nextSibling;)a=a.parentNode;return n(a)?null:e(a.nextSibling)}function c(a){for(var c=!1;a;)if(a.nodeType===Node.TEXT_NODE)if(0===a.length)a=h(a);else return!l(a.data.substr(a.length-1,1));else b(a)? +(c=!0,a=null):a=h(a);return c}function t(a){var c=!1;for(a=a&&e(a);a;){if(a.nodeType===Node.TEXT_NODE&&0=b.value||"%"===b.unit)?null:b;return b||p(a)};this.parseFoLineHeight=function(a){var b;b=(b=g(a))&&(0>b.value|| +"%"===b.unit)?null:b;return b||p(a)};this.getImpactedParagraphs=function(a){var b=a.commonAncestorContainer,c=[];for(b.nodeType===Node.ELEMENT_NODE&&(c=y.getElementsByTagNameNS(b,w,"p").concat(y.getElementsByTagNameNS(b,w,"h")));b&&!n(b);)b=b.parentNode;b&&c.push(b);return c.filter(function(b){return y.rangeIntersectsNode(a,b)})};this.getTextNodes=function(a,b){var c=a.startContainer.ownerDocument.createRange(),d;d=y.getNodesInRange(a,function(d){c.selectNodeContents(d);if(d.nodeType===Node.TEXT_NODE){if(b&& +y.rangesIntersect(a,c)||y.containsRange(a,c))return Boolean(m(d)&&(!l(d.textContent)||q(d,0)))?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}else if(y.rangesIntersect(a,c)&&r(d))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});c.detach();return d};this.getTextElements=function(a,c){var e=a.startContainer.ownerDocument.createRange(),f;f=y.getNodesInRange(a,function(f){var g=f.nodeType;e.selectNodeContents(f);if(g===Node.TEXT_NODE){if(y.containsRange(a,e)&&(c||Boolean(m(f)&&(!l(f.textContent)|| +q(f,0)))))return NodeFilter.FILTER_ACCEPT}else if(b(f)){if(y.containsRange(a,e))return NodeFilter.FILTER_ACCEPT}else if(r(f)||d(f))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});e.detach();return f};this.getParagraphElements=function(a){var b=a.startContainer.ownerDocument.createRange(),c;c=y.getNodesInRange(a,function(c){b.selectNodeContents(c);if(n(c)){if(y.rangesIntersect(a,b))return NodeFilter.FILTER_ACCEPT}else if(r(c)||d(c))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT}); +b.detach();return c}}; // Input 30 /* @@ -566,7 +566,7 @@ var d=a.startContainer.ownerDocument.createRange(),f;f=x.getNodesInRange(a,funct @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("odf.OdfUtils"); -odf.TextSerializer=function(){function k(e){var b="",g=l.filter?l.filter.acceptNode(e):NodeFilter.FILTER_ACCEPT,a=e.nodeType,f;if(g===NodeFilter.FILTER_ACCEPT||g===NodeFilter.FILTER_SKIP)for(f=e.firstChild;f;)b+=k(f),f=f.nextSibling;g===NodeFilter.FILTER_ACCEPT&&(a===Node.ELEMENT_NODE&&h.isParagraph(e)?b+="\n":a===Node.TEXT_NODE&&e.textContent&&(b+=e.textContent));return b}var l=this,h=new odf.OdfUtils;this.filter=null;this.writeToString=function(e){return e?k(e):""}}; +odf.TextSerializer=function(){function n(d){var b="",e=m.filter?m.filter.acceptNode(d):NodeFilter.FILTER_ACCEPT,a=d.nodeType,h;if(e===NodeFilter.FILTER_ACCEPT||e===NodeFilter.FILTER_SKIP)for(h=d.firstChild;h;)b+=n(h),h=h.nextSibling;e===NodeFilter.FILTER_ACCEPT&&(a===Node.ELEMENT_NODE&&l.isParagraph(d)?b+="\n":a===Node.TEXT_NODE&&d.textContent&&(b+=d.textContent));return b}var m=this,l=new odf.OdfUtils;this.filter=null;this.writeToString=function(d){return d?n(d):""}}; // Input 31 /* @@ -603,10 +603,10 @@ odf.TextSerializer=function(){function k(e){var b="",g=l.filter?l.filter.acceptN @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("core.DomUtils");runtime.loadClass("core.LoopWatchDog");runtime.loadClass("odf.Namespaces"); -odf.TextStyleApplicator=function(k,l,h){function e(a){function b(a,c){return"object"===typeof a&&"object"===typeof c?Object.keys(a).every(function(d){return b(a[d],c[d])}):a===c}this.isStyleApplied=function(d){d=l.getAppliedStylesForElement(d);return b(a,d)}}function b(b){var e={};this.applyStyleToContainer=function(g){var q;q=g.getAttributeNS(a,"style-name");var n=g.ownerDocument;q=q||"";if(!e.hasOwnProperty(q)){var p=q,r=q,w;r?(w=l.getStyleElement(r,"text"),w.parentNode===h?n=w.cloneNode(!0):(n= -n.createElementNS(f,"style:style"),n.setAttributeNS(f,"style:parent-style-name",r),n.setAttributeNS(f,"style:family","text"),n.setAttributeNS(d,"scope","document-content"))):(n=n.createElementNS(f,"style:style"),n.setAttributeNS(f,"style:family","text"),n.setAttributeNS(d,"scope","document-content"));l.updateStyle(n,b,k);h.appendChild(n);e[p]=n}q=e[q].getAttributeNS(f,"name");g.setAttributeNS(a,"text:style-name",q)}}var g=new core.DomUtils,a=odf.Namespaces.textns,f=odf.Namespaces.stylens,d="urn:webodf:names:scope"; -this.applyStyle=function(c,d,f){var h={},n,k,l,w;runtime.assert(f&&f["style:text-properties"],"applyStyle without any text properties");h["style:text-properties"]=f["style:text-properties"];l=new b(h);w=new e(h);c.forEach(function(b){n=w.isStyleApplied(b);if(!1===n){var c=b.ownerDocument,f=b.parentNode,e,h=b,m=new core.LoopWatchDog(1E3);"span"===f.localName&&f.namespaceURI===a?(b.previousSibling&&!g.rangeContainsNode(d,b.previousSibling)?(c=f.cloneNode(!1),f.parentNode.insertBefore(c,f.nextSibling)): -c=f,e=!0):(c=c.createElementNS(a,"text:span"),f.insertBefore(c,b),e=!1);for(;h&&(h===b||g.rangeContainsNode(d,h));)m.check(),f=h.nextSibling,h.parentNode!==c&&c.appendChild(h),h=f;if(h&&e)for(b=c.cloneNode(!1),c.parentNode.insertBefore(b,c.nextSibling);h;)m.check(),f=h.nextSibling,b.appendChild(h),h=f;k=c;l.applyStyleToContainer(k)}})}}; +odf.TextStyleApplicator=function(n,m,l){function d(a){function b(a,c){return"object"===typeof a&&"object"===typeof c?Object.keys(a).every(function(d){return b(a[d],c[d])}):a===c}this.isStyleApplied=function(d){d=m.getAppliedStylesForElement(d);return b(a,d)}}function b(b){var d={};this.applyStyleToContainer=function(e){var q;q=e.getAttributeNS(a,"style-name");var g=e.ownerDocument;q=q||"";if(!d.hasOwnProperty(q)){var p=q,r=q,w;r?(w=m.getStyleElement(r,"text"),w.parentNode===l?g=w.cloneNode(!0):(g= +g.createElementNS(h,"style:style"),g.setAttributeNS(h,"style:parent-style-name",r),g.setAttributeNS(h,"style:family","text"),g.setAttributeNS(f,"scope","document-content"))):(g=g.createElementNS(h,"style:style"),g.setAttributeNS(h,"style:family","text"),g.setAttributeNS(f,"scope","document-content"));m.updateStyle(g,b,n);l.appendChild(g);d[p]=g}q=d[q].getAttributeNS(h,"name");e.setAttributeNS(a,"text:style-name",q)}}var e=new core.DomUtils,a=odf.Namespaces.textns,h=odf.Namespaces.stylens,f="urn:webodf:names:scope"; +this.applyStyle=function(c,f,k){var h={},g,l,n,m;runtime.assert(k&&k["style:text-properties"],"applyStyle without any text properties");h["style:text-properties"]=k["style:text-properties"];n=new b(h);m=new d(h);c.forEach(function(b){g=m.isStyleApplied(b);if(!1===g){var c=b.ownerDocument,d=b.parentNode,k,h=b,q=new core.LoopWatchDog(1E3);"span"===d.localName&&d.namespaceURI===a?(b.previousSibling&&!e.rangeContainsNode(f,b.previousSibling)?(c=d.cloneNode(!1),d.parentNode.insertBefore(c,d.nextSibling)): +c=d,k=!0):(c=c.createElementNS(a,"text:span"),d.insertBefore(c,b),k=!1);for(;h&&(h===b||e.rangeContainsNode(f,h));)q.check(),d=h.nextSibling,h.parentNode!==c&&c.appendChild(h),h=d;if(h&&k)for(b=c.cloneNode(!1),c.parentNode.insertBefore(b,c.nextSibling);h;)q.check(),d=h.nextSibling,b.appendChild(h),h=d;l=c;n.applyStyleToContainer(l)}})}}; // Input 32 /* @@ -643,47 +643,48 @@ c=f,e=!0):(c=c.createElementNS(a,"text:span"),f.insertBefore(c,b),e=!1);for(;h&& @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfUtils");runtime.loadClass("xmldom.XPath");runtime.loadClass("core.CSSUnits"); -odf.Style2CSS=function(){function k(a){var b={},c,d;if(!a)return b;for(a=a.firstChild;a;){if(d=a.namespaceURI!==p||"style"!==a.localName&&"default-style"!==a.localName?a.namespaceURI===u&&"list-style"===a.localName?"list":a.namespaceURI!==p||"page-layout"!==a.localName&&"default-page-layout"!==a.localName?void 0:"page":a.getAttributeNS(p,"family"))(c=a.getAttributeNS&&a.getAttributeNS(p,"name"))||(c=""),d=b[d]=b[d]||{},d[c]=a;a=a.nextSibling}return b}function l(a,b){if(!b||!a)return null;if(a[b])return a[b]; -var c,d;for(c in a)if(a.hasOwnProperty(c)&&(d=l(a[c].derivedStyles,b)))return d;return null}function h(a,b,c){var d=b[a],f,e;d&&(f=d.getAttributeNS(p,"parent-style-name"),e=null,f&&(e=l(c,f),!e&&b[f]&&(h(f,b,c),e=b[f],b[f]=null)),e?(e.derivedStyles||(e.derivedStyles={}),e.derivedStyles[a]=d):c[a]=d)}function e(a,b){for(var c in a)a.hasOwnProperty(c)&&(h(c,a,b),a[c]=null)}function b(a,b){var c=s[a],d;if(null===c)return null;d=b?"["+c+'|style-name="'+b+'"]':"["+c+"|style-name]";"presentation"===c&& -(c="draw",d=b?'[presentation|style-name="'+b+'"]':"[presentation|style-name]");return c+"|"+v[a].join(d+","+c+"|")+d}function g(a,c,d){var f=[],e,h;f.push(b(a,c));for(e in d.derivedStyles)if(d.derivedStyles.hasOwnProperty(e))for(h in c=g(a,e,d.derivedStyles[e]),c)c.hasOwnProperty(h)&&f.push(c[h]);return f}function a(a,b,c){if(!a)return null;for(a=a.firstChild;a;){if(a.namespaceURI===b&&a.localName===c)return b=a;a=a.nextSibling}return null}function f(a,b){var c="",d,f;for(d in b)if(b.hasOwnProperty(d)&& -(d=b[d],f=a.getAttributeNS(d[0],d[1]))){f=f.trim();if(V.hasOwnProperty(d[1])){var e=f.indexOf(" "),g=void 0,h=void 0;-1!==e?(g=f.substring(0,e),h=f.substring(e)):(g=f,h="");(g=aa.parseLength(g))&&("pt"===g.unit&&0.75>g.value)&&(f="0.75pt"+h)}d[2]&&(c+=d[2]+":"+f+";")}return c}function d(b){return(b=a(b,p,"text-properties"))?aa.parseFoFontSize(b.getAttributeNS(n,"font-size")):null}function c(a){a=a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,function(a,b,c,d){return b+b+c+c+d+d});return(a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a))? -{r:parseInt(a[1],16),g:parseInt(a[2],16),b:parseInt(a[3],16)}:null}function t(a,b,c,d){b='text|list[text|style-name="'+b+'"]';var f=c.getAttributeNS(u,"level"),e;c=aa.getFirstNonWhitespaceChild(c);c=aa.getFirstNonWhitespaceChild(c);var g;c&&(e=c.attributes,g=e["fo:text-indent"]?e["fo:text-indent"].value:void 0,e=e["fo:margin-left"]?e["fo:margin-left"].value:void 0);g||(g="-0.6cm");c="-"===g.charAt(0)?g.substring(1):"-"+g;for(f=f&&parseInt(f,10);1 text|list-item > text|list",f-=1;f=b+" > text|list-item > *:not(text|list):first-child"; -void 0!==e&&(e=f+"{margin-left:"+e+";}",a.insertRule(e,a.cssRules.length));d=b+" > text|list-item > *:not(text|list):first-child:before{"+d+";";d+="counter-increment:list;";d+="margin-left:"+g+";";d+="width:"+c+";";d+="display:inline-block}";try{a.insertRule(d,a.cssRules.length)}catch(h){throw h;}}function m(b,e,h,k){if("list"===e)for(var l=k.firstChild,r,s;l;){if(l.namespaceURI===u)if(r=l,"list-level-style-number"===l.localName){var v=r;s=v.getAttributeNS(p,"num-format");var M=v.getAttributeNS(p, -"num-suffix"),G={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},v=v.getAttributeNS(p,"num-prefix")||"",v=G.hasOwnProperty(s)?v+(" counter(list, "+G[s]+")"):s?v+("'"+s+"';"):v+" ''";M&&(v+=" '"+M+"'");s="content: "+v+";";t(b,h,r,s)}else"list-level-style-image"===l.localName?(s="content: none;",t(b,h,r,s)):"list-level-style-bullet"===l.localName&&(s="content: '"+r.getAttributeNS(u,"bullet-char")+"';",t(b,h,r,s));l=l.nextSibling}else if("page"===e)if(M=r=h="",l=k.getElementsByTagNameNS(p, -"page-layout-properties")[0],r=l.parentNode.parentNode.parentNode.masterStyles,M="",h+=f(l,X),s=l.getElementsByTagNameNS(p,"background-image"),0g.value)&&(e="0.75pt"+k)}d[2]&&(c+=d[2]+":"+e+";")}return c}function f(b){return(b=a(b,p,"text-properties"))?ba.parseFoFontSize(b.getAttributeNS(g,"font-size")):null}function c(a){a=a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,function(a,b,c,d){return b+b+c+c+d+d});return(a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a))? +{r:parseInt(a[1],16),g:parseInt(a[2],16),b:parseInt(a[3],16)}:null}function t(a,b,c,d){b='text|list[text|style-name="'+b+'"]';var e=c.getAttributeNS(u,"level"),f;c=ba.getFirstNonWhitespaceChild(c);c=ba.getFirstNonWhitespaceChild(c);var g;c&&(f=c.attributes,g=f["fo:text-indent"]?f["fo:text-indent"].value:void 0,f=f["fo:margin-left"]?f["fo:margin-left"].value:void 0);g||(g="-0.6cm");c="-"===g.charAt(0)?g.substring(1):"-"+g;for(e=e&&parseInt(e,10);1 text|list-item > text|list",e-=1;e=b+" > text|list-item > *:not(text|list):first-child"; +void 0!==f&&(f=e+"{margin-left:"+f+";}",a.insertRule(f,a.cssRules.length));d=b+" > text|list-item > *:not(text|list):first-child:before{"+d+";";d+="counter-increment:list;";d+="margin-left:"+g+";";d+="width:"+c+";";d+="display:inline-block}";try{a.insertRule(d,a.cssRules.length)}catch(k){throw k;}}function k(b,d,l,n){if("list"===d)for(var r=n.firstChild,m,s;r;){if(r.namespaceURI===u)if(m=r,"list-level-style-number"===r.localName){var v=m;s=v.getAttributeNS(p,"num-format");var L=v.getAttributeNS(p, +"num-suffix"),G={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},v=v.getAttributeNS(p,"num-prefix")||"",v=G.hasOwnProperty(s)?v+(" counter(list, "+G[s]+")"):s?v+("'"+s+"';"):v+" ''";L&&(v+=" '"+L+"'");s="content: "+v+";";t(b,l,m,s)}else"list-level-style-image"===r.localName?(s="content: none;",t(b,l,m,s)):"list-level-style-bullet"===r.localName&&(s="content: '"+m.getAttributeNS(u,"bullet-char")+"';",t(b,l,m,s));r=r.nextSibling}else if("page"===d)if(L=m=l="",r=n.getElementsByTagNameNS(p, +"page-layout-properties")[0],m=r.parentNode.parentNode.parentNode.masterStyles,L="",l+=h(r,M),s=r.getElementsByTagNameNS(p,"background-image"),0c)break;f=f.nextSibling}a.insertBefore(b,f)}}}function g(a){this.OdfContainer=a}function a(a, -b,c,d){var f=this;this.size=0;this.type=null;this.name=a;this.container=c;this.onchange=this.onreadystatechange=this.document=this.mimetype=this.url=null;this.EMPTY=0;this.LOADING=1;this.DONE=2;this.state=this.EMPTY;this.load=function(){null!==d&&(this.mimetype=b,d.loadAsDataURL(a,b,function(a,b){a&&runtime.log(a);f.url=b;if(f.onchange)f.onchange(f);if(f.onstatereadychange)f.onstatereadychange(f)}))}}var f=new odf.StyleInfo,d="urn:oasis:names:tc:opendocument:xmlns:office:1.0",c="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", -t="urn:webodf:names:scope",m="meta settings scripts font-face-decls styles automatic-styles master-styles body".split(" "),q=(new Date).getTime()+"_webodf_",n=new core.Base64;g.prototype=new function(){};g.prototype.constructor=g;g.namespaceURI=d;g.localName="document";a.prototype.load=function(){};a.prototype.getUrl=function(){return this.data?"data:;base64,"+n.toBase64(this.data):null};odf.OdfContainer=function r(m,n){function l(a){for(var b=a.firstChild,c;b;)c=b.nextSibling,b.nodeType===Node.ELEMENT_NODE? -l(b):b.nodeType===Node.PROCESSING_INSTRUCTION_NODE&&a.removeChild(b),b=c}function x(a,b){for(var c=a&&a.firstChild;c;)c.nodeType===Node.ELEMENT_NODE&&c.setAttributeNS(t,"scope",b),c=c.nextSibling}function s(a,b){var c=null,d,f,e;if(a)for(c=a.cloneNode(!0),d=c.firstChild;d;)f=d.nextSibling,d.nodeType===Node.ELEMENT_NODE&&(e=d.getAttributeNS(t,"scope"))&&e!==b&&c.removeChild(d),d=f;return c}function v(a){var b=K.rootElement.ownerDocument,c;if(a){l(a.documentElement);try{c=b.importNode(a.documentElement, -!0)}catch(d){}}return c}function A(a){K.state=a;if(K.onchange)K.onchange(K);if(K.onstatereadychange)K.onstatereadychange(K)}function F(a){S=null;K.rootElement=a;a.fontFaceDecls=k(a,d,"font-face-decls");a.styles=k(a,d,"styles");a.automaticStyles=k(a,d,"automatic-styles");a.masterStyles=k(a,d,"master-styles");a.body=k(a,d,"body");a.meta=k(a,d,"meta")}function D(a){a=v(a);var c=K.rootElement;a&&"document-styles"===a.localName&&a.namespaceURI===d?(c.fontFaceDecls=k(a,d,"font-face-decls"),b(c,c.fontFaceDecls), -c.styles=k(a,d,"styles"),b(c,c.styles),c.automaticStyles=k(a,d,"automatic-styles"),x(c.automaticStyles,"document-styles"),b(c,c.automaticStyles),c.masterStyles=k(a,d,"master-styles"),b(c,c.masterStyles),f.prefixStyleNames(c.automaticStyles,q,c.masterStyles)):A(r.INVALID)}function O(a){a=v(a);var c,f,e;if(a&&"document-content"===a.localName&&a.namespaceURI===d){c=K.rootElement;f=k(a,d,"font-face-decls");if(c.fontFaceDecls&&f)for(e=f.firstChild;e;)c.fontFaceDecls.appendChild(e),e=f.firstChild;else f&& -(c.fontFaceDecls=f,b(c,f));f=k(a,d,"automatic-styles");x(f,"document-content");if(c.automaticStyles&&f)for(e=f.firstChild;e;)c.automaticStyles.appendChild(e),e=f.firstChild;else f&&(c.automaticStyles=f,b(c,f));c.body=k(a,d,"body");b(c,c.body)}else A(r.INVALID)}function B(a){a=v(a);var c;a&&("document-meta"===a.localName&&a.namespaceURI===d)&&(c=K.rootElement,c.meta=k(a,d,"meta"),b(c,c.meta))}function P(a){a=v(a);var c;a&&("document-settings"===a.localName&&a.namespaceURI===d)&&(c=K.rootElement,c.settings= -k(a,d,"settings"),b(c,c.settings))}function z(a){a=v(a);var b;if(a&&"manifest"===a.localName&&a.namespaceURI===c)for(b=K.rootElement,b.manifest=a,a=b.manifest.firstChild;a;)a.nodeType===Node.ELEMENT_NODE&&("file-entry"===a.localName&&a.namespaceURI===c)&&(L[a.getAttributeNS(c,"full-path")]=a.getAttributeNS(c,"media-type")),a=a.nextSibling}function J(a){var b=a.shift(),c,d;b?(c=b[0],d=b[1],R.loadAsDOM(c,function(b,c){d(c);b||K.state===r.INVALID||J(a)})):A(r.DONE)}function X(a){var b="";odf.Namespaces.forEachPrefix(function(a, -c){b+=" xmlns:"+a+'="'+c+'"'});return''}function da(){var a=new xmldom.LSSerializer,b=X("document-meta");a.filter=new odf.OdfNodeFilter;b+=a.writeToString(K.rootElement.meta,odf.Namespaces.namespaceMap);return b+""}function V(a,b){var d=document.createElementNS(c,"manifest:file-entry");d.setAttributeNS(c,"manifest:full-path",a);d.setAttributeNS(c,"manifest:media-type",b);return d}function qa(){var a= -runtime.parseXML(''),b=k(a,c,"manifest"),d=new xmldom.LSSerializer,f;for(f in L)L.hasOwnProperty(f)&&b.appendChild(V(f,L[f]));d.filter=new odf.OdfNodeFilter;return'\n'+d.writeToString(a,odf.Namespaces.namespaceMap)}function aa(){var a=new xmldom.LSSerializer,b=X("document-settings");a.filter=new odf.OdfNodeFilter;b+=a.writeToString(K.rootElement.settings,odf.Namespaces.namespaceMap); -return b+""}function ca(){var a=odf.Namespaces.namespaceMap,b=new xmldom.LSSerializer,c=s(K.rootElement.automaticStyles,"document-styles"),d=K.rootElement.masterStyles&&K.rootElement.masterStyles.cloneNode(!0),e=X("document-styles");f.removePrefixFromStyleNames(c,q,d);b.filter=new h(d,c);e+=b.writeToString(K.rootElement.fontFaceDecls,a);e+=b.writeToString(K.rootElement.styles,a);e+=b.writeToString(c,a);e+=b.writeToString(d,a);return e+""}function Q(){var a= -odf.Namespaces.namespaceMap,b=new xmldom.LSSerializer,c=s(K.rootElement.automaticStyles,"document-content"),d=X("document-content");b.filter=new e(K.rootElement.body,c);d+=b.writeToString(c,a);d+=b.writeToString(K.rootElement.body,a);return d+""}function Y(a,b){runtime.loadXML(a,function(a,c){if(a)b(a);else{var f=v(c);f&&"document"===f.localName&&f.namespaceURI===d?(F(f),A(r.DONE)):A(r.INVALID)}})}function T(){function a(b,c){var e;c||(c=b);e=document.createElementNS(d,c); -f[b]=e;f.appendChild(e)}var b=new core.Zip("",null),c=runtime.byteArrayFromString("application/vnd.oasis.opendocument.text","utf8"),f=K.rootElement,e=document.createElementNS(d,"text");b.save("mimetype",c,!1,new Date);a("meta");a("settings");a("scripts");a("fontFaceDecls","font-face-decls");a("styles");a("automaticStyles","automatic-styles");a("masterStyles","master-styles");a("body");f.body.appendChild(e);A(r.DONE);return b}function N(){var a,b=new Date;a=runtime.byteArrayFromString(aa(),"utf8"); -R.save("settings.xml",a,!0,b);a=runtime.byteArrayFromString(da(),"utf8");R.save("meta.xml",a,!0,b);a=runtime.byteArrayFromString(ca(),"utf8");R.save("styles.xml",a,!0,b);a=runtime.byteArrayFromString(Q(),"utf8");R.save("content.xml",a,!0,b);a=runtime.byteArrayFromString(qa(),"utf8");R.save("META-INF/manifest.xml",a,!0,b)}function E(a,b){N();R.writeAs(a,function(a){b(a)})}var K=this,R,L={},S;this.onstatereadychange=n;this.rootElement=this.state=this.onchange=null;this.setRootElement=F;this.getContentElement= -function(){var a;S||(a=K.rootElement.body,S=a.getElementsByTagNameNS(d,"text")[0]||a.getElementsByTagNameNS(d,"presentation")[0]||a.getElementsByTagNameNS(d,"spreadsheet")[0]);return S};this.getDocumentType=function(){var a=K.getContentElement();return a&&a.localName};this.getPart=function(b){return new a(b,L[b],K,R)};this.getPartData=function(a,b){R.load(a,b)};this.createByteArray=function(a,b){N();R.createByteArray(a,b)};this.saveAs=E;this.save=function(a){E(m,a)};this.getUrl=function(){return m}; -this.state=r.LOADING;this.rootElement=function(a){var b=document.createElementNS(a.namespaceURI,a.localName),c;a=new a;for(c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}(g);R=m?new core.Zip(m,function(a,b){R=b;a?Y(m,function(b){a&&(R.error=a+"\n"+b,A(r.INVALID))}):J([["styles.xml",D],["content.xml",O],["meta.xml",B],["settings.xml",P],["META-INF/manifest.xml",z]])}):T()};odf.OdfContainer.EMPTY=0;odf.OdfContainer.LOADING=1;odf.OdfContainer.DONE=2;odf.OdfContainer.INVALID=3;odf.OdfContainer.SAVING= +odf.OdfContainer=function(){function n(a,b,c){for(a=a?a.firstChild:null;a;){if(a.localName===c&&a.namespaceURI===b)return a;a=a.nextSibling}return null}function m(a){var b,c=k.length;for(b=0;bc)break;e=e.nextSibling}a.insertBefore(b,e)}}}function e(a){this.OdfContainer=a}function a(a, +b,c,d){var e=this;this.size=0;this.type=null;this.name=a;this.container=c;this.onchange=this.onreadystatechange=this.document=this.mimetype=this.url=null;this.EMPTY=0;this.LOADING=1;this.DONE=2;this.state=this.EMPTY;this.load=function(){null!==d&&(this.mimetype=b,d.loadAsDataURL(a,b,function(a,b){a&&runtime.log(a);e.url=b;if(e.onchange)e.onchange(e);if(e.onstatereadychange)e.onstatereadychange(e)}))}}var h=new odf.StyleInfo,f="urn:oasis:names:tc:opendocument:xmlns:office:1.0",c="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", +t="urn:webodf:names:scope",k="meta settings scripts font-face-decls styles automatic-styles master-styles body".split(" "),q=(new Date).getTime()+"_webodf_",g=new core.Base64;e.prototype=new function(){};e.prototype.constructor=e;e.namespaceURI=f;e.localName="document";a.prototype.load=function(){};a.prototype.getUrl=function(){return this.data?"data:;base64,"+g.toBase64(this.data):null};odf.OdfContainer=function r(g,k){function m(a){for(var b=a.firstChild,c;b;)c=b.nextSibling,b.nodeType===Node.ELEMENT_NODE? +m(b):b.nodeType===Node.PROCESSING_INSTRUCTION_NODE&&a.removeChild(b),b=c}function y(a,b){for(var c=a&&a.firstChild;c;)c.nodeType===Node.ELEMENT_NODE&&c.setAttributeNS(t,"scope",b),c=c.nextSibling}function s(a,b){var c=null,d,e,f;if(a)for(c=a.cloneNode(!0),d=c.firstChild;d;)e=d.nextSibling,d.nodeType===Node.ELEMENT_NODE&&(f=d.getAttributeNS(t,"scope"))&&f!==b&&c.removeChild(d),d=e;return c}function v(a){var b=I.rootElement.ownerDocument,c;if(a){m(a.documentElement);try{c=b.importNode(a.documentElement, +!0)}catch(d){}}return c}function x(a){I.state=a;if(I.onchange)I.onchange(I);if(I.onstatereadychange)I.onstatereadychange(I)}function F(a){$=null;I.rootElement=a;a.fontFaceDecls=n(a,f,"font-face-decls");a.styles=n(a,f,"styles");a.automaticStyles=n(a,f,"automatic-styles");a.masterStyles=n(a,f,"master-styles");a.body=n(a,f,"body");a.meta=n(a,f,"meta")}function E(a){a=v(a);var c=I.rootElement;a&&"document-styles"===a.localName&&a.namespaceURI===f?(c.fontFaceDecls=n(a,f,"font-face-decls"),b(c,c.fontFaceDecls), +c.styles=n(a,f,"styles"),b(c,c.styles),c.automaticStyles=n(a,f,"automatic-styles"),y(c.automaticStyles,"document-styles"),b(c,c.automaticStyles),c.masterStyles=n(a,f,"master-styles"),b(c,c.masterStyles),h.prefixStyleNames(c.automaticStyles,q,c.masterStyles)):x(r.INVALID)}function O(a){a=v(a);var c,d,e;if(a&&"document-content"===a.localName&&a.namespaceURI===f){c=I.rootElement;d=n(a,f,"font-face-decls");if(c.fontFaceDecls&&d)for(e=d.firstChild;e;)c.fontFaceDecls.appendChild(e),e=d.firstChild;else d&& +(c.fontFaceDecls=d,b(c,d));d=n(a,f,"automatic-styles");y(d,"document-content");if(c.automaticStyles&&d)for(e=d.firstChild;e;)c.automaticStyles.appendChild(e),e=d.firstChild;else d&&(c.automaticStyles=d,b(c,d));c.body=n(a,f,"body");b(c,c.body)}else x(r.INVALID)}function z(a){a=v(a);var c;a&&("document-meta"===a.localName&&a.namespaceURI===f)&&(c=I.rootElement,c.meta=n(a,f,"meta"),b(c,c.meta))}function P(a){a=v(a);var c;a&&("document-settings"===a.localName&&a.namespaceURI===f)&&(c=I.rootElement,c.settings= +n(a,f,"settings"),b(c,c.settings))}function C(a){a=v(a);var b;if(a&&"manifest"===a.localName&&a.namespaceURI===c)for(b=I.rootElement,b.manifest=a,a=b.manifest.firstChild;a;)a.nodeType===Node.ELEMENT_NODE&&("file-entry"===a.localName&&a.namespaceURI===c)&&(R[a.getAttributeNS(c,"full-path")]=a.getAttributeNS(c,"media-type")),a=a.nextSibling}function K(a){var b=a.shift(),c,d;b?(c=b[0],d=b[1],S.loadAsDOM(c,function(b,c){d(c);b||I.state===r.INVALID||K(a)})):x(r.DONE)}function M(a){var b="";odf.Namespaces.forEachPrefix(function(a, +c){b+=" xmlns:"+a+'="'+c+'"'});return''}function ca(){var a=new xmldom.LSSerializer,b=M("document-meta");a.filter=new odf.OdfNodeFilter;b+=a.writeToString(I.rootElement.meta,odf.Namespaces.namespaceMap);return b+""}function da(a,b){var d=document.createElementNS(c,"manifest:file-entry");d.setAttributeNS(c,"manifest:full-path",a);d.setAttributeNS(c,"manifest:media-type",b);return d}function aa(){var a= +runtime.parseXML(''),b=n(a,c,"manifest"),d=new xmldom.LSSerializer,e;for(e in R)R.hasOwnProperty(e)&&b.appendChild(da(e,R[e]));d.filter=new odf.OdfNodeFilter;return'\n'+d.writeToString(a,odf.Namespaces.namespaceMap)}function ba(){var a=new xmldom.LSSerializer,b=M("document-settings");a.filter=new odf.OdfNodeFilter;b+=a.writeToString(I.rootElement.settings,odf.Namespaces.namespaceMap); +return b+""}function ea(){var a=odf.Namespaces.namespaceMap,b=new xmldom.LSSerializer,c=s(I.rootElement.automaticStyles,"document-styles"),d=I.rootElement.masterStyles&&I.rootElement.masterStyles.cloneNode(!0),e=M("document-styles");h.removePrefixFromStyleNames(c,q,d);b.filter=new l(d,c);e+=b.writeToString(I.rootElement.fontFaceDecls,a);e+=b.writeToString(I.rootElement.styles,a);e+=b.writeToString(c,a);e+=b.writeToString(d,a);return e+""}function Q(){var a= +odf.Namespaces.namespaceMap,b=new xmldom.LSSerializer,c=s(I.rootElement.automaticStyles,"document-content"),e=M("document-content");b.filter=new d(I.rootElement.body,c);e+=b.writeToString(c,a);e+=b.writeToString(I.rootElement.body,a);return e+""}function W(a,b){runtime.loadXML(a,function(a,c){if(a)b(a);else{var d=v(c);d&&"document"===d.localName&&d.namespaceURI===f?(F(d),x(r.DONE)):x(r.INVALID)}})}function U(){function a(b,c){var e;c||(c=b);e=document.createElementNS(f,c); +d[b]=e;d.appendChild(e)}var b=new core.Zip("",null),c=runtime.byteArrayFromString("application/vnd.oasis.opendocument.text","utf8"),d=I.rootElement,e=document.createElementNS(f,"text");b.save("mimetype",c,!1,new Date);a("meta");a("settings");a("scripts");a("fontFaceDecls","font-face-decls");a("styles");a("automaticStyles","automatic-styles");a("masterStyles","master-styles");a("body");d.body.appendChild(e);x(r.DONE);return b}function N(){var a,b=new Date;a=runtime.byteArrayFromString(ba(),"utf8"); +S.save("settings.xml",a,!0,b);a=runtime.byteArrayFromString(ca(),"utf8");S.save("meta.xml",a,!0,b);a=runtime.byteArrayFromString(ea(),"utf8");S.save("styles.xml",a,!0,b);a=runtime.byteArrayFromString(Q(),"utf8");S.save("content.xml",a,!0,b);a=runtime.byteArrayFromString(aa(),"utf8");S.save("META-INF/manifest.xml",a,!0,b)}function D(a,b){N();S.writeAs(a,function(a){b(a)})}var I=this,S,R={},$;this.onstatereadychange=k;this.rootElement=this.state=this.onchange=null;this.setRootElement=F;this.getContentElement= +function(){var a;$||(a=I.rootElement.body,$=a.getElementsByTagNameNS(f,"text")[0]||a.getElementsByTagNameNS(f,"presentation")[0]||a.getElementsByTagNameNS(f,"spreadsheet")[0]);return $};this.getDocumentType=function(){var a=I.getContentElement();return a&&a.localName};this.getPart=function(b){return new a(b,R[b],I,S)};this.getPartData=function(a,b){S.load(a,b)};this.createByteArray=function(a,b){N();S.createByteArray(a,b)};this.saveAs=D;this.save=function(a){D(g,a)};this.getUrl=function(){return g}; +this.state=r.LOADING;this.rootElement=function(a){var b=document.createElementNS(a.namespaceURI,a.localName),c;a=new a;for(c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}(e);S=g?new core.Zip(g,function(a,b){S=b;a?W(g,function(b){a&&(S.error=a+"\n"+b,x(r.INVALID))}):K([["styles.xml",E],["content.xml",O],["meta.xml",z],["settings.xml",P],["META-INF/manifest.xml",C]])}):U()};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(a){return new odf.OdfContainer(a,null)};return odf.OdfContainer}(); // Input 34 /* @@ -721,9 +722,9 @@ this.state=r.LOADING;this.rootElement=function(a){var b=document.createElementNS @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("core.Base64");runtime.loadClass("xmldom.XPath");runtime.loadClass("odf.OdfContainer"); -odf.FontLoader=function(){function k(e,b,g,a,f){var d,c=0,l;for(l in e)if(e.hasOwnProperty(l)){if(c===g){d=l;break}c+=1}d?b.getPartData(e[d].href,function(c,l){if(c)runtime.log(c);else{var n="@font-face { font-family: '"+(e[d].family||d)+"'; src: url(data:application/x-font-ttf;charset=binary;base64,"+h.convertUTF8ArrayToBase64(l)+') format("truetype"); }';try{a.insertRule(n,a.cssRules.length)}catch(p){runtime.log("Problem inserting rule in CSS: "+runtime.toJson(p)+"\nRule: "+n)}}k(e,b,g+1,a,f)}): -f&&f()}var l=new xmldom.XPath,h=new core.Base64;odf.FontLoader=function(){this.loadFonts=function(e,b){for(var g=e.rootElement.fontFaceDecls;b.cssRules.length;)b.deleteRule(b.cssRules.length-1);if(g){var a={},f,d,c,h;if(g)for(g=l.getODFElementsWithXPath(g,"style:font-face[svg:font-face-src]",odf.Namespaces.resolvePrefix),f=0;f text|list-item > *:first-child:before {";if(W=z.getAttributeNS(v,"style-name")){z=p[W];$=P.getFirstNonWhitespaceChild(z);z=void 0;if($)if("list-level-style-number"===$.localName){z=$.getAttributeNS(y,"num-format");W=$.getAttributeNS(y, -"num-suffix");var ua="",ua={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},pa=void 0,pa=$.getAttributeNS(y,"num-prefix")||"",pa=ua.hasOwnProperty(z)?pa+(" counter(list, "+ua[z]+")"):z?pa+("'"+z+"';"):pa+" ''";W&&(pa+=" '"+W+"'");z=ua="content: "+pa+";"}else"list-level-style-image"===$.localName?z="content: none;":"list-level-style-bullet"===$.localName&&(z="content: '"+$.getAttributeNS(v,"bullet-char")+"';");$=z}if(E){for(z=k[E];z;)E=z,z=k[E];U+="counter-increment:"+ -E+";";$?($=$.replace("list",E),U+=$):U+="content:counter("+E+");"}else E="",$?($=$.replace("list",A),U+=$):U+="content: counter("+A+");",U+="counter-increment:"+A+";",h.insertRule("text|list#"+A+" {counter-reset:"+A+"}",h.cssRules.length);U+="}";k[A]=E;U&&h.insertRule(U,h.cssRules.length)}n.insertBefore(J,n.firstChild);x();D(e);if(!d&&(e=[S],ga.hasOwnProperty("statereadychange")))for(h=ga.statereadychange,n=0;n text|list-item > *:first-child:before {";if(X=x.getAttributeNS(v,"style-name")){x=n[X];H=P.getFirstNonWhitespaceChild(x);x=void 0;if(H)if("list-level-style-number"===H.localName){x=H.getAttributeNS(A,"num-format");X=H.getAttributeNS(A,"num-suffix");var va="",va={1:"decimal",a:"lower-latin",A:"upper-latin", +i:"lower-roman",I:"upper-roman"},qa=void 0,qa=H.getAttributeNS(A,"num-prefix")||"",qa=va.hasOwnProperty(x)?qa+(" counter(list, "+va[x]+")"):x?qa+("'"+x+"';"):qa+" ''";X&&(qa+=" '"+X+"'");x=va="content: "+qa+";"}else"list-level-style-image"===H.localName?x="content: none;":"list-level-style-bullet"===H.localName&&(x="content: '"+H.getAttributeNS(v,"bullet-char")+"';");H=x}if(C){for(x=m[C];x;)C=x,x=m[C];D+="counter-increment:"+C+";";H?(H=H.replace("list",C),D+=H):D+="content:counter("+C+");"}else C= +"",H?(H=H.replace("list",q),D+=H):D+="content: counter("+q+");",D+="counter-increment:"+q+";",h.insertRule("text|list#"+q+" {counter-reset:"+q+"}",h.cssRules.length);D+="}";m[q]=C;D&&h.insertRule(D,h.cssRules.length)}M.insertBefore(K,M.firstChild);y();E(g);if(!d&&(g=[Y],ha.hasOwnProperty("statereadychange")))for(h=ha.statereadychange,H=0;H + Copyright (C) 2012-2013 KO GmbH @licstart The JavaScript code in this page is free software: you can redistribute it @@ -909,12 +910,11 @@ ops.Server=function(){};ops.Server.prototype.connect=function(k,l){};ops.Server. @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.NowjsServer=function(){var k;this.getNowObject=function(){return k};this.getGenesisUrl=function(l){return"/session/"+l+"/genesis"};this.connect=function(l,h){function e(){"unavailable"===k.networkStatus?(runtime.log("connection to server unavailable."),h("unavailable")):"ready"!==k.networkStatus?b>l?(runtime.log("connection to server timed out."),h("timeout")):(b+=100,runtime.getWindow().setTimeout(e,100)):(runtime.log("connection to collaboration server established."),h("ready"))}var b=0;k|| -(k=runtime.getVariable("now"),void 0===k&&(k={networkStatus:"unavailable"}),e())};this.networkStatus=function(){return k?k.networkStatus:"unavailable"};this.login=function(l,h,e,b){k?k.login(l,h,e,b):b("Not connected to server")};this.joinSession=function(l,h,e,b){k.joinSession(l,h,function(b){k.memberid=b;e(b)},b)}}; +ops.Operation=function(){};ops.Operation.prototype.init=function(n){};ops.Operation.prototype.transform=function(n,m){};ops.Operation.prototype.execute=function(n){};ops.Operation.prototype.spec=function(){}; // Input 40 /* - Copyright (C) 2013 KO GmbH + Copyright (C) 2012-2013 KO GmbH @licstart The JavaScript code in this page is free software: you can redistribute it @@ -946,10 +946,7 @@ ops.NowjsServer=function(){var k;this.getNowObject=function(){return k};this.get @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -runtime.loadClass("core.Base64");runtime.loadClass("core.ByteArrayWriter"); -ops.PullBoxServer=function(k){function l(b,a){var f=new XMLHttpRequest,d=new core.ByteArrayWriter("utf8"),c=JSON.stringify(b);runtime.log("Sending message to server: "+c);d.appendString(c);d=d.getByteArray();f.open("POST",k.url,!0);f.onreadystatechange=function(){4===f.readyState&&((200>f.status||300<=f.status)&&0===f.status&&runtime.log("Status "+String(f.status)+": "+f.responseText||f.statusText),a(f.responseText))};d=d.buffer&&!f.sendAsBinary?d.buffer:runtime.byteArrayToString(d,"binary");try{f.sendAsBinary? -f.sendAsBinary(d):f.send(d)}catch(e){runtime.log("Problem with calling server: "+e+" "+d),a(e.message)}}var h=this,e,b=new core.Base64;k=k||{};k.url=k.url||"/WSER";this.getGenesisUrl=function(b){return"/session/"+b+"/genesis"};this.call=l;this.getToken=function(){return e};this.setToken=function(b){e=b};this.connect=function(b,a){a("ready")};this.networkStatus=function(){return"ready"};this.login=function(g,a,f,d){l({command:"login",args:{login:b.toBase64(g),password:b.toBase64(a)}},function(a){var b= -runtime.fromJson(a);runtime.log("Login reply: "+a);b.hasOwnProperty("token")?(e=b.token,runtime.log("Caching token: "+h.getToken()),f(b)):d(a)})};this.joinSession=function(b,a,f,d){l({command:"join_session",args:{user_id:b,es_id:a}},function(a){var b=runtime.fromJson(a);runtime.log("join_session reply: "+a);b.hasOwnProperty("success")&&b.success?f(b.member_id):d&&d()})}}; +ops.OpAddCursor=function(){var n=this,m,l;this.init=function(d){m=d.memberid;l=d.timestamp};this.transform=function(d,b){return[n]};this.execute=function(d){var b=d.getCursor(m);if(b)return!1;b=new ops.OdtCursor(m,d);d.addCursor(b);d.emit(ops.OdtDocument.signalCursorAdded,b);return!0};this.spec=function(){return{optype:"AddCursor",memberid:m,timestamp:l}}}; // Input 41 /* @@ -985,7 +982,9 @@ runtime.fromJson(a);runtime.log("Login reply: "+a);b.hasOwnProperty("token")?(e= @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.Operation=function(){};ops.Operation.prototype.init=function(k){};ops.Operation.prototype.transform=function(k,l){};ops.Operation.prototype.execute=function(k){};ops.Operation.prototype.spec=function(){}; +runtime.loadClass("core.DomUtils");runtime.loadClass("odf.OdfUtils"); +gui.StyleHelper=function(n){function m(b,e,a){var h=!0,f;b.collapsed?(f=b.startContainer,f.hasChildNodes()&&b.startOffsetc?-h.countBackwardSteps(-c, +f):0;a.move(c);b&&(f=0b?-h.countBackwardSteps(-b,f):0,a.move(f,!0));e.emit(ops.OdtDocument.signalCursorMoved,a);return!0};this.spec=function(){return{optype:"MoveCursor",memberid:m,timestamp:l,position:d,length:b}}}; // Input 45 /* - Copyright (C) 2012-2013 KO GmbH + Copyright (C) 2013 KO GmbH @licstart The JavaScript code in this page is free software: you can redistribute it @@ -1133,7 +1132,11 @@ c=a.getImpactedParagraphs(d);(new gui.StyleHelper(b.getFormatting())).applyStyle @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.OpRemoveCursor=function(){var k=this,l,h;this.init=function(e){l=e.memberid;h=e.timestamp};this.transform=function(e,b){var g=e.spec(),a=[k];"RemoveCursor"===g.optype&&g.memberid===l&&(a=[]);return a};this.execute=function(e){return e.removeCursor(l)?!0:!1};this.spec=function(){return{optype:"RemoveCursor",memberid:l,timestamp:h}}}; +ops.OpInsertTable=function(){function n(a,c){var d;if(1===t.length)d=t[0];else if(3===t.length)switch(a){case 0:d=t[0];break;case b-1:d=t[2];break;default:d=t[1]}else d=t[a];if(1===d.length)return d[0];if(3===d.length)switch(c){case 0:return d[0];case e-1:return d[2];default:return d[1]}return d[c]}var m=this,l,d,b,e,a,h,f,c,t;this.init=function(k){l=k.memberid;d=k.timestamp;a=parseInt(k.position,10);b=parseInt(k.initialRows,10);e=parseInt(k.initialColumns,10);h=k.tableName;f=k.tableStyleName;c=k.tableColumnStyleName; +t=k.tableCellStyleMatrix};this.transform=function(b,c){var d=b.spec(),e=[m];switch(d.optype){case "InsertTable":e=null;break;case "AddAnnotation":d.positionc?-f.countBackwardSteps(-c, -d):0;a.move(c);b&&(d=0b?-f.countBackwardSteps(-b,d):0,a.move(d,!0));g.emit(ops.OdtDocument.signalCursorMoved,a);return!0};this.spec=function(){return{optype:"MoveCursor",memberid:l,timestamp:h,position:e,length:b}}}; +ops.OpInsertText=function(){function n(a,b){var d=b.parentNode,c=b.nextSibling,e=[];a.getCursors().forEach(function(a){var c=a.getSelectedRange();!c||c.startContainer!==b&&c.endContainer!==b||e.push({cursor:a,startContainer:c.startContainer,startOffset:c.startOffset,endContainer:c.endContainer,endOffset:c.endOffset})});d.removeChild(b);d.insertBefore(b,c);e.forEach(function(a){var b=a.cursor.getSelectedRange();b.setStart(a.startContainer,a.startOffset);b.setEnd(a.endContainer,a.endOffset)})}var m= +this,l,d,b,e;this.init=function(a){l=a.memberid;d=a.timestamp;b=parseInt(a.position,10);e=a.text};this.merge=function(a){return"InsertText"===a.optype&&a.memberid===l&&a.position===b+e.length?(e+=a.text,d=a.timestamp,!0):!1};this.transform=function(a,d){var e=a.spec(),c=[m];switch(e.optype){case "InsertText":e.position + Copyright (C) 2012-2013 KO GmbH @licstart The JavaScript code in this page is free software: you can redistribute it @@ -1207,11 +1212,13 @@ d):0;a.move(c);b&&(d=0b?-f.countBackwardSteps(-b,d @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.OpInsertTable=function(){function k(a,c){var d;if(1===t.length)d=t[0];else if(3===t.length)switch(a){case 0:d=t[0];break;case b-1:d=t[2];break;default:d=t[1]}else d=t[a];if(1===d.length)return d[0];if(3===d.length)switch(c){case 0:return d[0];case g-1:return d[2];default:return d[1]}return d[c]}var l=this,h,e,b,g,a,f,d,c,t;this.init=function(m){h=m.memberid;e=m.timestamp;a=parseInt(m.position,10);b=parseInt(m.initialRows,10);g=parseInt(m.initialColumns,10);f=m.tableName;d=m.tableStyleName;c=m.tableColumnStyleName; -t=m.tableCellStyleMatrix};this.transform=function(b,c){var d=b.spec(),f=[l];switch(d.optype){case "InsertTable":f=null;break;case "AddAnnotation":d.position=a.textNode.length?null:a.textNode.splitText(a.offset));for(a=a.textNode;a!==f;)if(a=a.parentNode,c=a.cloneNode(!1),k){for(n&&c.appendChild(n);k.nextSibling;)c.appendChild(k.nextSibling); +a.parentNode.insertBefore(c,a.nextSibling);k=a;n=c}else a.parentNode.insertBefore(c,a),k=c,n=a;b.isListItem(n)&&(n=n.childNodes[0]);e.fixCursorPositions(m);e.getOdfCanvas().refreshSize();e.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:h,memberId:m,timeStamp:l});e.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:n,memberId:m,timeStamp:l});e.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"SplitParagraph",memberid:m,timestamp:l,position:d}}}; // Input 49 /* @@ -1287,13 +1292,8 @@ memberid:h,timestamp:e,position:b,text:g}}}; @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfUtils");runtime.loadClass("core.DomUtils"); -ops.OpRemoveText=function(){function k(a){function b(a){if(f.isCharacterElement(a))return!1;if(a.nodeType===Node.TEXT_NODE)return 0===a.textContent.length;for(a=a.firstChild;a;){if(!b(a))return!1;a=a.nextSibling}return!0}function e(g){g=d.mergeIntoParent(g);return!f.isParagraph(g)&&g!==a&&b(g)?e(g):g}this.isEmpty=b;this.mergeChildrenIntoParent=e}function l(b){var f=b.getPositionFilter(),e,h,n,l,k=a,w=b.getDOM().createRange();b=b.getIteratorAtPosition(g);e=b.container();for(h=b.unfilteredDomOffset();k&& -b.nextPosition();)n=b.container(),l=b.unfilteredDomOffset(),f.acceptPosition(b)===NodeFilter.FILTER_ACCEPT&&(k-=1);w.setStart(e,h);w.setEnd(n,l);d.splitBoundaries(w);return w}var h=this,e,b,g,a,f,d;this.init=function(c){runtime.assert(0<=c.length,"OpRemoveText only supports positive lengths");e=c.memberid;b=c.timestamp;g=parseInt(c.position,10);a=parseInt(c.length,10);f=new odf.OdfUtils;d=new core.DomUtils};this.transform=function(c,d){var f=c.spec(),l=g+a,n,k=[h];switch(f.optype){case "RemoveText":n= -f.position+f.length;n<=g?g-=f.length:f.position=a.textNode.length?null:a.textNode.splitText(a.offset));for(a=a.textNode;a!==d;)if(a=a.parentNode,c=a.cloneNode(!1),m){for(k&&c.appendChild(k);m.nextSibling;)c.appendChild(m.nextSibling); -a.parentNode.insertBefore(c,a.nextSibling);m=a;k=c}else a.parentNode.insertBefore(c,a),m=c,k=a;b.isListItem(k)&&(k=k.childNodes[0]);g.fixCursorPositions(l);g.getOdfCanvas().refreshSize();g.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:f,memberId:l,timeStamp:h});g.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:k,memberId:l,timeStamp:h});g.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"SplitParagraph",memberid:l,timestamp:h,position:e}}}; +ops.OpUpdateParagraphStyle=function(){function n(a,b){var c,d,e=b?b.split(","):[];for(c=0;ck?-g.countBackwardSteps(-k,c):0,m.move(c),h.emit(ops.OdtDocument.signalCursorMoved,m));h.getOdfCanvas().addAnnotation(f);return!0};this.spec=function(){return{optype:"AddAnnotation",memberid:l,timestamp:d,position:b, +length:e,name:a}}}; // Input 54 /* @@ -1486,88 +1488,11 @@ memberid:h,timestamp:e,styleName:b,setProperties:g}}}; @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.OpRemoveParagraphStyle=function(){function k(e){var a=[];e&&["style:parent-style-name","style:next-style-name"].forEach(function(f){e[f]===b&&a.push(f)});return a}var l=this,h,e,b;this.init=function(g){h=g.memberid;e=g.timestamp;b=g.styleName};this.transform=function(e,a){var f=e.spec(),d,c;d=[l];switch(f.optype){case "RemoveParagraphStyle":f.styleName===b&&(d=[]);break;case "AddParagraphStyle":case "UpdateParagraphStyle":c=k(f.setProperties);0 - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -ops.OpAddAnnotation=function(){function k(a,b,c){if(c=a.getPositionInTextNode(c,h))a=c.textNode,c.offset!==a.length&&a.splitText(c.offset),a.parentNode.insertBefore(b,a.nextSibling)}var l=this,h,e,b,g,a;this.init=function(f){h=f.memberid;e=parseInt(f.timestamp,10);b=parseInt(f.position,10);g=parseInt(f.length,10)||0;a=f.name};this.transform=function(a,d){var c=a.spec(),e=b+g,h=[l];switch(c.optype){case "AddAnnotation":c.positionm?-n.countBackwardSteps(-m,c):0,l.move(c),f.emit(ops.OdtDocument.signalCursorMoved,l));f.getOdfCanvas().addAnnotation(d);return!0};this.spec=function(){return{optype:"AddAnnotation",memberid:h,timestamp:e,position:b, -length:g,name:a}}}; -// Input 56 -/* - - Copyright (C) 2012-2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ runtime.loadClass("odf.Namespaces");runtime.loadClass("core.DomUtils"); -ops.OpRemoveAnnotation=function(){var k,l,h,e,b;this.init=function(g){k=g.memberid;l=g.timestamp;h=parseInt(g.position,10);e=parseInt(g.length,10);b=new core.DomUtils};this.transform=function(b,a){return null};this.execute=function(e){for(var a=e.getIteratorAtPosition(h).container(),f,d=null,c=null;a.namespaceURI!==odf.Namespaces.officens||"annotation"!==a.localName;)a=a.parentNode;if(null===a)return!1;d=a;(f=d.getAttributeNS(odf.Namespaces.officens,"name"))&&(c=b.getElementsByTagNameNS(e.getRootNode(), -odf.Namespaces.officens,"annotation-end").filter(function(a){return f===a.getAttributeNS(odf.Namespaces.officens,"name")})[0]||null);e.getOdfCanvas().forgetAnnotations();for(a=b.getElementsByTagNameNS(d,odf.Namespaces.webodfns+":names:cursor","cursor");a.length;)d.parentNode.insertBefore(a.pop(),d);d.parentNode.removeChild(d);c&&c.parentNode.removeChild(c);e.fixCursorPositions();e.getOdfCanvas().refreshAnnotations();return!0};this.spec=function(){return{optype:"RemoveAnnotation",memberid:k,timestamp:l, -position:h,length:e}}}; -// Input 57 +ops.OpRemoveAnnotation=function(){var n,m,l,d,b;this.init=function(e){n=e.memberid;m=e.timestamp;l=parseInt(e.position,10);d=parseInt(e.length,10);b=new core.DomUtils};this.transform=function(b,a){return null};this.execute=function(d){for(var a=d.getIteratorAtPosition(l).container(),h,f=null,c=null;a.namespaceURI!==odf.Namespaces.officens||"annotation"!==a.localName;)a=a.parentNode;if(null===a)return!1;f=a;(h=f.getAttributeNS(odf.Namespaces.officens,"name"))&&(c=b.getElementsByTagNameNS(d.getRootNode(), +odf.Namespaces.officens,"annotation-end").filter(function(a){return h===a.getAttributeNS(odf.Namespaces.officens,"name")})[0]||null);d.getOdfCanvas().forgetAnnotations();for(a=b.getElementsByTagNameNS(f,odf.Namespaces.webodfns+":names:cursor","cursor");a.length;)f.parentNode.insertBefore(a.pop(),f);f.parentNode.removeChild(f);c&&c.parentNode.removeChild(c);d.fixCursorPositions();d.getOdfCanvas().refreshAnnotations();return!0};this.spec=function(){return{optype:"RemoveAnnotation",memberid:n,timestamp:m, +position:l,length:d}}}; +// Input 55 /* Copyright (C) 2012-2013 KO GmbH @@ -1604,22 +1529,22 @@ position:h,length:e}}}; */ runtime.loadClass("ops.OpAddCursor");runtime.loadClass("ops.OpApplyDirectStyling");runtime.loadClass("ops.OpRemoveCursor");runtime.loadClass("ops.OpMoveCursor");runtime.loadClass("ops.OpInsertTable");runtime.loadClass("ops.OpInsertText");runtime.loadClass("ops.OpRemoveText");runtime.loadClass("ops.OpSplitParagraph");runtime.loadClass("ops.OpSetParagraphStyle");runtime.loadClass("ops.OpUpdateParagraphStyle");runtime.loadClass("ops.OpAddParagraphStyle");runtime.loadClass("ops.OpRemoveParagraphStyle"); runtime.loadClass("ops.OpAddAnnotation");runtime.loadClass("ops.OpRemoveAnnotation"); -ops.OperationFactory=function(){function k(h){return function(){return new h}}var l;this.register=function(h,e){l[h]=e};this.create=function(h){var e=null,b=l[h.optype];b&&(e=b(h),e.init(h));return e};l={AddCursor:k(ops.OpAddCursor),ApplyDirectStyling:k(ops.OpApplyDirectStyling),InsertTable:k(ops.OpInsertTable),InsertText:k(ops.OpInsertText),RemoveText:k(ops.OpRemoveText),SplitParagraph:k(ops.OpSplitParagraph),SetParagraphStyle:k(ops.OpSetParagraphStyle),UpdateParagraphStyle:k(ops.OpUpdateParagraphStyle), -AddParagraphStyle:k(ops.OpAddParagraphStyle),RemoveParagraphStyle:k(ops.OpRemoveParagraphStyle),MoveCursor:k(ops.OpMoveCursor),RemoveCursor:k(ops.OpRemoveCursor),AddAnnotation:k(ops.OpAddAnnotation),RemoveAnnotation:k(ops.OpRemoveAnnotation)}}; -// Input 58 +ops.OperationFactory=function(){function n(l){return function(){return new l}}var m;this.register=function(l,d){m[l]=d};this.create=function(l){var d=null,b=m[l.optype];b&&(d=b(l),d.init(l));return d};m={AddCursor:n(ops.OpAddCursor),ApplyDirectStyling:n(ops.OpApplyDirectStyling),InsertTable:n(ops.OpInsertTable),InsertText:n(ops.OpInsertText),RemoveText:n(ops.OpRemoveText),SplitParagraph:n(ops.OpSplitParagraph),SetParagraphStyle:n(ops.OpSetParagraphStyle),UpdateParagraphStyle:n(ops.OpUpdateParagraphStyle), +AddParagraphStyle:n(ops.OpAddParagraphStyle),RemoveParagraphStyle:n(ops.OpRemoveParagraphStyle),MoveCursor:n(ops.OpMoveCursor),RemoveCursor:n(ops.OpRemoveCursor),AddAnnotation:n(ops.OpAddAnnotation),RemoveAnnotation:n(ops.OpRemoveAnnotation)}}; +// Input 56 runtime.loadClass("core.Cursor");runtime.loadClass("core.PositionIterator");runtime.loadClass("core.PositionFilter");runtime.loadClass("core.LoopWatchDog");runtime.loadClass("odf.OdfUtils"); -gui.SelectionMover=function(k,l){function h(){u.setUnfilteredPosition(k.getNode(),0);return u}function e(a,b){var c,d=null;a&&(c=b?a[a.length-1]:a[0]);c&&(d={top:c.top,left:b?c.right:c.left,bottom:c.bottom});return d}function b(a,c,d,f){var g=a.nodeType;d.setStart(a,c);d.collapse(!f);f=e(d.getClientRects(),!0===f);!f&&0a?-1:1;for(a=Math.abs(a);0m?n.previousPosition():n.nextPosition());)if(K.check(),k.acceptPosition(n)===s&&(r+=1,p=n.container(),w=b(p,n.unfilteredDomOffset(),E),w.top!==Y)){if(w.top!==N&&N!==Y)break;N=w.top;w=Math.abs(T-w.left);if(null===q||wa?(d=k.previousPosition,f=-1):(d=k.nextPosition,f=1);for(e=b(k.container(),k.unfilteredDomOffset(),p);d.call(k);)if(c.acceptPosition(k)===s){if(w.getParagraphElement(k.getCurrentNode())!==m)break;g=b(k.container(),k.unfilteredDomOffset(),p);if(g.bottom!==e.bottom&&(e=g.top>=e.top&&g.bottome.bottom,!e))break;n+=f;e=g}p.detach();return n}function p(a,b){for(var c=0,d;a.parentNode!==b;)runtime.assert(null!==a.parentNode,"parent is null"), -a=a.parentNode;for(d=b.firstChild;d!==a;)c+=1,d=d.nextSibling;return c}function r(a,b,c){runtime.assert(null!==a,"SelectionMover.countStepsToPosition called with element===null");var d=h(),f=d.container(),e=d.unfilteredDomOffset(),g=0,k=new core.LoopWatchDog(1E3);d.setUnfilteredPosition(a,b);a=d.container();runtime.assert(Boolean(a),"SelectionMover.countStepsToPosition: positionIterator.container() returned null");b=d.unfilteredDomOffset();d.setUnfilteredPosition(f,e);var f=a,e=b,l=d.container(), -m=d.unfilteredDomOffset();if(f===l)f=m-e;else{var n=f.compareDocumentPosition(l);2===n?n=-1:4===n?n=1:10===n?(e=p(f,l),n=ef)for(;d.nextPosition()&&(k.check(),c.acceptPosition(d)===s&&(g+=1),d.container()!==a||d.unfilteredDomOffset()!==b););else if(0a?-1:1;for(a=Math.abs(a);0k?n.previousPosition():n.nextPosition());)if(I.check(),h.acceptPosition(n)===s&&(r+=1,p=n.container(),w=b(p,n.unfilteredDomOffset(),D),w.top!==W)){if(w.top!==N&&N!==W)break;N=w.top;w=Math.abs(U-w.left);if(null===q||wa?(d=h.previousPosition,e=-1):(d=h.nextPosition,e=1);for(f=b(h.container(),h.unfilteredDomOffset(),p);d.call(h);)if(c.acceptPosition(h)===s){if(w.getParagraphElement(h.getCurrentNode())!==k)break;g=b(h.container(),h.unfilteredDomOffset(),p);if(g.bottom!==f.bottom&&(f=g.top>=f.top&&g.bottomf.bottom,!f))break;n+=e;f=g}p.detach();return n}function p(a,b){for(var c=0,d;a.parentNode!==b;)runtime.assert(null!==a.parentNode,"parent is null"), +a=a.parentNode;for(d=b.firstChild;d!==a;)c+=1,d=d.nextSibling;return c}function r(a,b,c){runtime.assert(null!==a,"SelectionMover.countStepsToPosition called with element===null");var d=l(),e=d.container(),f=d.unfilteredDomOffset(),g=0,h=new core.LoopWatchDog(1E3);d.setUnfilteredPosition(a,b);a=d.container();runtime.assert(Boolean(a),"SelectionMover.countStepsToPosition: positionIterator.container() returned null");b=d.unfilteredDomOffset();d.setUnfilteredPosition(e,f);var e=a,f=b,k=d.container(), +m=d.unfilteredDomOffset();if(e===k)e=m-f;else{var n=e.compareDocumentPosition(k);2===n?n=-1:4===n?n=1:10===n?(f=p(e,k),n=fe)for(;d.nextPosition()&&(h.check(),c.acceptPosition(d)===s&&(g+=1),d.container()!==a||d.unfilteredDomOffset()!==b););else if(0 @@ -1655,13 +1580,13 @@ gui.SelectionMover.createPositionIterator(l);var a=l.ownerDocument.createRange() @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("ops.OpAddCursor");runtime.loadClass("ops.OpRemoveCursor");runtime.loadClass("ops.OpMoveCursor");runtime.loadClass("ops.OpInsertTable");runtime.loadClass("ops.OpInsertText");runtime.loadClass("ops.OpRemoveText");runtime.loadClass("ops.OpSplitParagraph");runtime.loadClass("ops.OpSetParagraphStyle");runtime.loadClass("ops.OpAddParagraphStyle");runtime.loadClass("ops.OpUpdateParagraphStyle");runtime.loadClass("ops.OpRemoveParagraphStyle"); -ops.OperationTransformer=function(){function k(h,e){for(var b,g,a,f=[],d=[];0=b&&(f=-e.movePointBackward(-b,a));h.handleUpdate();return f};this.handleUpdate=function(){};this.getStepCounter=function(){return e.getStepCounter()};this.getMemberId=function(){return k};this.getNode=function(){return b.getNode()};this.getAnchorNode=function(){return b.getAnchorNode()};this.getSelectedRange=function(){return b.getSelectedRange()}; -this.getOdtDocument=function(){return l};b=new core.Cursor(l.getDOM(),k);e=new gui.SelectionMover(b,l.getRootNode())}; -// Input 61 +ops.OdtCursor=function(n,m){var l=this,d,b;this.removeFromOdtDocument=function(){b.remove()};this.move=function(b,a){var h=0;0=b&&(h=-d.movePointBackward(-b,a));l.handleUpdate();return h};this.handleUpdate=function(){};this.getStepCounter=function(){return d.getStepCounter()};this.getMemberId=function(){return n};this.getNode=function(){return b.getNode()};this.getAnchorNode=function(){return b.getAnchorNode()};this.getSelectedRange=function(){return b.getSelectedRange()}; +this.getOdtDocument=function(){return m};b=new core.Cursor(m.getDOM(),n);d=new gui.SelectionMover(b,m.getRootNode())}; +// Input 59 /* Copyright (C) 2012 KO GmbH @@ -1696,20 +1621,20 @@ this.getOdtDocument=function(){return l};b=new core.Cursor(l.getDOM(),k);e=new g @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.EditInfo=function(k,l){function h(){var e=[],a;for(a in b)b.hasOwnProperty(a)&&e.push({memberid:a,time:b[a].time});e.sort(function(a,b){return a.time-b.time});return e}var e,b={};this.getNode=function(){return e};this.getOdtDocument=function(){return l};this.getEdits=function(){return b};this.getSortedEdits=function(){return h()};this.addEdit=function(e,a){b[e]={time:a}};this.clearEdits=function(){b={}};e=l.getDOM().createElementNS("urn:webodf:names:editinfo","editinfo");k.insertBefore(e,k.firstChild)}; -// Input 62 -gui.Avatar=function(k,l){var h=this,e,b,g;this.setColor=function(a){b.style.borderColor=a};this.setImageUrl=function(a){h.isVisible()?b.src=a:g=a};this.isVisible=function(){return"block"===e.style.display};this.show=function(){g&&(b.src=g,g=void 0);e.style.display="block"};this.hide=function(){e.style.display="none"};this.markAsFocussed=function(a){e.className=a?"active":""};(function(){var a=k.ownerDocument,f=a.documentElement.namespaceURI;e=a.createElementNS(f,"div");b=a.createElementNS(f,"img"); -b.width=64;b.height=64;e.appendChild(b);e.style.width="64px";e.style.height="70px";e.style.position="absolute";e.style.top="-80px";e.style.left="-34px";e.style.display=l?"block":"none";k.appendChild(e)})()}; -// Input 63 +ops.EditInfo=function(n,m){function l(){var d=[],a;for(a in b)b.hasOwnProperty(a)&&d.push({memberid:a,time:b[a].time});d.sort(function(a,b){return a.time-b.time});return d}var d,b={};this.getNode=function(){return d};this.getOdtDocument=function(){return m};this.getEdits=function(){return b};this.getSortedEdits=function(){return l()};this.addEdit=function(d,a){b[d]={time:a}};this.clearEdits=function(){b={}};d=m.getDOM().createElementNS("urn:webodf:names:editinfo","editinfo");n.insertBefore(d,n.firstChild)}; +// Input 60 +gui.Avatar=function(n,m){var l=this,d,b,e;this.setColor=function(a){b.style.borderColor=a};this.setImageUrl=function(a){l.isVisible()?b.src=a:e=a};this.isVisible=function(){return"block"===d.style.display};this.show=function(){e&&(b.src=e,e=void 0);d.style.display="block"};this.hide=function(){d.style.display="none"};this.markAsFocussed=function(a){d.className=a?"active":""};(function(){var a=n.ownerDocument,e=a.documentElement.namespaceURI;d=a.createElementNS(e,"div");b=a.createElementNS(e,"img"); +b.width=64;b.height=64;d.appendChild(b);d.style.width="64px";d.style.height="70px";d.style.position="absolute";d.style.top="-80px";d.style.left="-34px";d.style.display=m?"block":"none";n.appendChild(d)})()}; +// Input 61 runtime.loadClass("gui.Avatar");runtime.loadClass("ops.OdtCursor"); -gui.Caret=function(k,l,h){function e(g){f&&a.parentNode&&(!d||g)&&(g&&void 0!==c&&runtime.clearTimeout(c),d=!0,b.style.opacity=g||"0"===b.style.opacity?"1":"0",c=runtime.setTimeout(function(){d=!1;e(!1)},500))}var b,g,a,f=!1,d=!1,c;this.refreshCursorBlinking=function(){h||k.getSelectedRange().collapsed?(f=!0,e(!0)):(f=!1,b.style.opacity="0")};this.setFocus=function(){f=!0;g.markAsFocussed(!0);e(!0)};this.removeFocus=function(){f=!1;g.markAsFocussed(!1);b.style.opacity="0"};this.setAvatarImageUrl= -function(a){g.setImageUrl(a)};this.setColor=function(a){b.style.borderColor=a;g.setColor(a)};this.getCursor=function(){return k};this.getFocusElement=function(){return b};this.toggleHandleVisibility=function(){g.isVisible()?g.hide():g.show()};this.showHandle=function(){g.show()};this.hideHandle=function(){g.hide()};this.ensureVisible=function(){var a,c,d,f,e=k.getOdtDocument().getOdfCanvas().getElement().parentNode,g;d=e.offsetWidth-e.clientWidth+5;f=e.offsetHeight-e.clientHeight+5;g=b.getBoundingClientRect(); -a=g.left-d;c=g.top-f;d=g.right+d;f=g.bottom+f;g=e.getBoundingClientRect();cg.bottom&&(e.scrollTop+=f-g.bottom);ag.right&&(e.scrollLeft+=d-g.right)};(function(){var c=k.getOdtDocument().getDOM();b=c.createElementNS(c.documentElement.namespaceURI,"span");a=k.getNode();a.appendChild(b);g=new gui.Avatar(a,l)})()}; -// Input 64 +gui.Caret=function(n,m,l){function d(e){h&&a.parentNode&&(!f||e)&&(e&&void 0!==c&&runtime.clearTimeout(c),f=!0,b.style.opacity=e||"0"===b.style.opacity?"1":"0",c=runtime.setTimeout(function(){f=!1;d(!1)},500))}var b,e,a,h=!1,f=!1,c;this.refreshCursorBlinking=function(){l||n.getSelectedRange().collapsed?(h=!0,d(!0)):(h=!1,b.style.opacity="0")};this.setFocus=function(){h=!0;e.markAsFocussed(!0);d(!0)};this.removeFocus=function(){h=!1;e.markAsFocussed(!1);b.style.opacity="0"};this.setAvatarImageUrl= +function(a){e.setImageUrl(a)};this.setColor=function(a){b.style.borderColor=a;e.setColor(a)};this.getCursor=function(){return n};this.getFocusElement=function(){return b};this.toggleHandleVisibility=function(){e.isVisible()?e.hide():e.show()};this.showHandle=function(){e.show()};this.hideHandle=function(){e.hide()};this.ensureVisible=function(){var a,c,d,e,f=n.getOdtDocument().getOdfCanvas().getElement().parentNode,h;d=f.offsetWidth-f.clientWidth+5;e=f.offsetHeight-f.clientHeight+5;h=b.getBoundingClientRect(); +a=h.left-d;c=h.top-e;d=h.right+d;e=h.bottom+e;h=f.getBoundingClientRect();ch.bottom&&(f.scrollTop+=e-h.bottom);ah.right&&(f.scrollLeft+=d-h.right)};(function(){var c=n.getOdtDocument().getDOM();b=c.createElementNS(c.documentElement.namespaceURI,"span");a=n.getNode();a.appendChild(b);e=new gui.Avatar(a,m)})()}; +// Input 62 runtime.loadClass("core.EventNotifier"); -gui.ClickHandler=function(){function k(){h=0;e=null}var l,h=0,e=null,b=new core.EventNotifier([gui.ClickHandler.signalSingleClick,gui.ClickHandler.signalDoubleClick,gui.ClickHandler.signalTripleClick]);this.subscribe=function(e,a){b.subscribe(e,a)};this.handleMouseUp=function(g){var a=runtime.getWindow();e&&e.x===g.screenX&&e.y===g.screenY?(h+=1,1===h?b.emit(gui.ClickHandler.signalSingleClick,g):2===h?b.emit(gui.ClickHandler.signalDoubleClick,void 0):3===h&&(a.clearTimeout(l),b.emit(gui.ClickHandler.signalTripleClick, -void 0),k())):(b.emit(gui.ClickHandler.signalSingleClick,g),h=1,e={x:g.screenX,y:g.screenY},a.clearTimeout(l),l=a.setTimeout(k,400))}};gui.ClickHandler.signalSingleClick="click";gui.ClickHandler.signalDoubleClick="doubleClick";gui.ClickHandler.signalTripleClick="tripleClick";(function(){return gui.ClickHandler})(); -// Input 65 +gui.ClickHandler=function(){function n(){l=0;d=null}var m,l=0,d=null,b=new core.EventNotifier([gui.ClickHandler.signalSingleClick,gui.ClickHandler.signalDoubleClick,gui.ClickHandler.signalTripleClick]);this.subscribe=function(d,a){b.subscribe(d,a)};this.handleMouseUp=function(e){var a=runtime.getWindow();d&&d.x===e.screenX&&d.y===e.screenY?(l+=1,1===l?b.emit(gui.ClickHandler.signalSingleClick,e):2===l?b.emit(gui.ClickHandler.signalDoubleClick,void 0):3===l&&(a.clearTimeout(m),b.emit(gui.ClickHandler.signalTripleClick, +void 0),n())):(b.emit(gui.ClickHandler.signalSingleClick,e),l=1,d={x:e.screenX,y:e.screenY},a.clearTimeout(m),m=a.setTimeout(n,400))}};gui.ClickHandler.signalSingleClick="click";gui.ClickHandler.signalDoubleClick="doubleClick";gui.ClickHandler.signalTripleClick="tripleClick";(function(){return gui.ClickHandler})(); +// Input 63 /* Copyright (C) 2012-2013 KO GmbH @@ -1744,9 +1669,9 @@ void 0),k())):(b.emit(gui.ClickHandler.signalSingleClick,g),h=1,e={x:g.screenX,y @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -gui.KeyboardHandler=function(){function k(b,e){e||(e=l.None);return b+":"+e}var l=gui.KeyboardHandler.Modifier,h=null,e={};this.setDefault=function(b){h=b};this.bind=function(b,g,a){b=k(b,g);runtime.assert(!1===e.hasOwnProperty(b),"tried to overwrite the callback handler of key combo: "+b);e[b]=a};this.unbind=function(b,g){var a=k(b,g);delete e[a]};this.reset=function(){h=null;e={}};this.handleEvent=function(b){var g=b.keyCode,a=l.None;b.metaKey&&(a|=l.Meta);b.ctrlKey&&(a|=l.Ctrl);b.altKey&&(a|=l.Alt); -b.shiftKey&&(a|=l.Shift);g=k(g,a);g=e[g];a=!1;g?a=g():null!==h&&(a=h(b));a&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}};gui.KeyboardHandler.Modifier={None:0,Meta:1,Ctrl:2,Alt:4,Shift:8,MetaShift:9,CtrlShift:10,AltShift:12};gui.KeyboardHandler.KeyCode={Backspace:8,Tab:9,Clear:12,Enter:13,End:35,Home:36,Left:37,Up:38,Right:39,Down:40,Delete:46,A:65,B:66,I:73,U:85,Z:90};(function(){return gui.KeyboardHandler})(); -// Input 66 +gui.KeyboardHandler=function(){function n(b,d){d||(d=m.None);return b+":"+d}var m=gui.KeyboardHandler.Modifier,l=null,d={};this.setDefault=function(b){l=b};this.bind=function(b,e,a){b=n(b,e);runtime.assert(!1===d.hasOwnProperty(b),"tried to overwrite the callback handler of key combo: "+b);d[b]=a};this.unbind=function(b,e){var a=n(b,e);delete d[a]};this.reset=function(){l=null;d={}};this.handleEvent=function(b){var e=b.keyCode,a=m.None;b.metaKey&&(a|=m.Meta);b.ctrlKey&&(a|=m.Ctrl);b.altKey&&(a|=m.Alt); +b.shiftKey&&(a|=m.Shift);e=n(e,a);e=d[e];a=!1;e?a=e():null!==l&&(a=l(b));a&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}};gui.KeyboardHandler.Modifier={None:0,Meta:1,Ctrl:2,Alt:4,Shift:8,MetaShift:9,CtrlShift:10,AltShift:12};gui.KeyboardHandler.KeyCode={Backspace:8,Tab:9,Clear:12,Enter:13,End:35,Home:36,Left:37,Up:38,Right:39,Down:40,Delete:46,A:65,B:66,I:73,U:85,Z:90};(function(){return gui.KeyboardHandler})(); +// Input 64 /* Copyright (C) 2013 KO GmbH @@ -1782,74 +1707,38 @@ b.shiftKey&&(a|=l.Shift);g=k(g,a);g=e[g];a=!1;g?a=g():null!==h&&(a=h(b));a&&(b.p @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("odf.Namespaces");runtime.loadClass("xmldom.LSSerializer");runtime.loadClass("odf.OdfNodeFilter");runtime.loadClass("odf.TextSerializer"); -gui.Clipboard=function(){var k,l,h;this.setDataFromRange=function(e,b){var g=!0,a,f=e.clipboardData;a=runtime.getWindow();var d=b.startContainer.ownerDocument;!f&&a&&(f=a.clipboardData);f?(d=d.createElement("span"),d.appendChild(b.cloneContents()),a=f.setData("text/plain",l.writeToString(d)),g=g&&a,a=f.setData("text/html",k.writeToString(d,odf.Namespaces.namespaceMap)),g=g&&a,e.preventDefault()):g=!1;return g};k=new xmldom.LSSerializer;l=new odf.TextSerializer;h=new odf.OdfNodeFilter;k.filter=h;l.filter= -h}; -// Input 67 +gui.Clipboard=function(){var n,m,l;this.setDataFromRange=function(d,b){var e=!0,a,h=d.clipboardData;a=runtime.getWindow();var f=b.startContainer.ownerDocument;!h&&a&&(h=a.clipboardData);h?(f=f.createElement("span"),f.appendChild(b.cloneContents()),a=h.setData("text/plain",m.writeToString(f)),e=e&&a,a=h.setData("text/html",n.writeToString(f,odf.Namespaces.namespaceMap)),e=e&&a,d.preventDefault()):e=!1;return e};n=new xmldom.LSSerializer;m=new odf.TextSerializer;l=new odf.OdfNodeFilter;n.filter=l;m.filter= +l}; +// Input 65 runtime.loadClass("core.DomUtils");runtime.loadClass("odf.OdfUtils");runtime.loadClass("ops.OpAddCursor");runtime.loadClass("ops.OpRemoveCursor");runtime.loadClass("ops.OpMoveCursor");runtime.loadClass("ops.OpInsertText");runtime.loadClass("ops.OpRemoveText");runtime.loadClass("ops.OpSplitParagraph");runtime.loadClass("ops.OpSetParagraphStyle");runtime.loadClass("ops.OpRemoveAnnotation");runtime.loadClass("gui.ClickHandler");runtime.loadClass("gui.Clipboard");runtime.loadClass("gui.KeyboardHandler"); runtime.loadClass("gui.StyleHelper"); -gui.SessionController=function(){gui.SessionController=function(k,l){function h(a,b,c,d){var f="on"+b,e=!1;a.attachEvent&&(e=a.attachEvent(f,c));!e&&a.addEventListener&&(a.addEventListener(b,c,!1),e=!0);e&&!d||!a.hasOwnProperty(f)||(a[f]=c)}function e(a,b,c){var d="on"+b;a.detachEvent&&a.detachEvent(d,c);a.removeEventListener&&a.removeEventListener(b,c,!1);a[d]===c&&(a[d]=null)}function b(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function g(a,b){var c=new ops.OpMoveCursor;c.init({memberid:l, -position:a,length:b||0});return c}function a(a,b){var c=gui.SelectionMover.createPositionIterator(C.getRootNode()),d=C.getOdfCanvas().getElement(),f;f=a;if(!f)return null;for(;f!==d&&!("urn:webodf:names:cursor"===f.namespaceURI&&"cursor"===f.localName||"urn:webodf:names:editinfo"===f.namespaceURI&&"editinfo"===f.localName);)if(f=f.parentNode,!f)return null;f!==d&&a!==f&&(a=f.parentNode,b=Array.prototype.indexOf.call(a.childNodes,f));c.setUnfilteredPosition(a,b);return C.getDistanceFromCursor(l,c.container(), -c.unfilteredDomOffset())}function f(a){var b=C.getOdfCanvas().getElement(),c=C.getRootNode(),d=0;b.compareDocumentPosition(a)&Node.DOCUMENT_POSITION_PRECEDING||(a=gui.SelectionMover.createPositionIterator(c),a.moveToEnd(),c=a.container(),d=a.unfilteredDomOffset());return{node:c,offset:d}}function d(b){runtime.setTimeout(function(){var c;a:{var d=C.getOdfCanvas().getElement(),e=W.getSelection(),h,m,n,p;if(null===e.anchorNode&&null===e.focusNode){c=b.clientX;h=b.clientY;m=C.getDOM();m.caretRangeFromPoint? -(c=m.caretRangeFromPoint(c,h),h={container:c.startContainer,offset:c.startOffset}):m.caretPositionFromPoint?(c=m.caretPositionFromPoint(c,h),h={container:c.offsetNode,offset:c.offset}):h=null;if(!h){c=null;break a}c=h.container;h=h.offset;m=c;e=h}else c=e.anchorNode,h=e.anchorOffset,m=e.focusNode,e=e.focusOffset;runtime.assert(null!==c&&null!==m,"anchorNode is null or focusNode is null");n=la.containsNode(d,c);p=la.containsNode(d,m);n||p?(n||(n=f(c),c=n.node,h=n.offset),p||(n=f(m),m=n.node,e=n.offset), -d.focus(),c={anchorNode:c,anchorOffset:h,focusNode:m,focusOffset:e}):c=null}null!==c&&(d=a(c.anchorNode,c.anchorOffset),h=c.focusNode===c.anchorNode&&c.focusOffset===c.anchorOffset?d:a(c.focusNode,c.focusOffset),null!==h&&0!==h||null!==d&&0!==d)&&(c=C.getCursorPosition(l),d=g(c+d,h-d),k.enqueue(d))},0)}function c(a){d(a)}function t(){var a=C.getOdfCanvas().getElement(),b=/[A-Za-z0-9]/,c=0,d=0,f,e,h,m;if(la.containsNode(a,W.getSelection().focusNode)){a=gui.SelectionMover.createPositionIterator(C.getRootNode()); -f=C.getCursor(l).getNode();a.setUnfilteredPosition(f,0);if(a.previousPosition()&&(e=a.getCurrentNode(),e.nodeType===Node.TEXT_NODE))for(h=e.data.length-1;0<=h;h-=1){m=e.data[h];if(!b.test(m))break;c-=1}a.setUnfilteredPosition(f,0);if(a.nextPosition()&&(e=a.getCurrentNode(),e.nodeType===Node.TEXT_NODE))for(h=0;ha.length&&(a.position+=a.length,a.length=-a.length);return a}function Y(a){var b=new ops.OpRemoveText;b.init({memberid:l,position:a.position,length:a.length});return b}function T(){var a= -Q(C.getCursorSelection(l)),b=null;0===a.length?0 - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -ops.MemberModel=function(){};ops.MemberModel.prototype.getMemberDetailsAndUpdates=function(k,l){};ops.MemberModel.prototype.unsubscribeMemberDetailsUpdates=function(k,l){};ops.MemberModel.prototype.shutdown=function(){}; -// Input 69 +gui.SessionController=function(){gui.SessionController=function(n,m){function l(a,b,c,d){var e="on"+b,f=!1;a.attachEvent&&(f=a.attachEvent(e,c));!f&&a.addEventListener&&(a.addEventListener(b,c,!1),f=!0);f&&!d||!a.hasOwnProperty(e)||(a[e]=c)}function d(a,b,c){var d="on"+b;a.detachEvent&&a.detachEvent(d,c);a.removeEventListener&&a.removeEventListener(b,c,!1);a[d]===c&&(a[d]=null)}function b(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function e(a,b){var c=new ops.OpMoveCursor;c.init({memberid:m, +position:a,length:b||0});return c}function a(a,b){var c=gui.SelectionMover.createPositionIterator(B.getRootNode()),d=B.getOdfCanvas().getElement(),e;e=a;if(!e)return null;for(;e!==d&&!("urn:webodf:names:cursor"===e.namespaceURI&&"cursor"===e.localName||"urn:webodf:names:editinfo"===e.namespaceURI&&"editinfo"===e.localName);)if(e=e.parentNode,!e)return null;e!==d&&a!==e&&(a=e.parentNode,b=Array.prototype.indexOf.call(a.childNodes,e));c.setUnfilteredPosition(a,b);return B.getDistanceFromCursor(m,c.container(), +c.unfilteredDomOffset())}function h(a){var b=B.getOdfCanvas().getElement(),c=B.getRootNode(),d=0;b.compareDocumentPosition(a)&Node.DOCUMENT_POSITION_PRECEDING||(a=gui.SelectionMover.createPositionIterator(c),a.moveToEnd(),c=a.container(),d=a.unfilteredDomOffset());return{node:c,offset:d}}function f(b){ga&&runtime.setTimeout(function(){var c;a:{var d=B.getOdfCanvas().getElement(),f=X.getSelection(),g,k,l,p;if(null===f.anchorNode&&null===f.focusNode){c=b.clientX;g=b.clientY;k=B.getDOM();k.caretRangeFromPoint? +(c=k.caretRangeFromPoint(c,g),g={container:c.startContainer,offset:c.startOffset}):k.caretPositionFromPoint?(c=k.caretPositionFromPoint(c,g),g={container:c.offsetNode,offset:c.offset}):g=null;if(!g){c=null;break a}c=g.container;g=g.offset;k=c;f=g}else c=f.anchorNode,g=f.anchorOffset,k=f.focusNode,f=f.focusOffset;runtime.assert(null!==c&&null!==k,"anchorNode is null or focusNode is null");l=ma.containsNode(d,c);p=ma.containsNode(d,k);l||p?(l||(l=h(c),c=l.node,g=l.offset),p||(l=h(k),k=l.node,f=l.offset), +d.focus(),c={anchorNode:c,anchorOffset:g,focusNode:k,focusOffset:f}):c=null}null!==c&&(d=a(c.anchorNode,c.anchorOffset),g=c.focusNode===c.anchorNode&&c.focusOffset===c.anchorOffset?d:a(c.focusNode,c.focusOffset),null!==g&&0!==g||null!==d&&0!==d)&&(c=B.getCursorPosition(m),d=e(c+d,g-d),n.enqueue(d))},0)}function c(a){f(a)}function t(){var a=B.getOdfCanvas().getElement(),b=/[A-Za-z0-9]/,c=0,d=0,f,g;if(ma.containsNode(a,X.getSelection().focusNode)){a=gui.SelectionMover.createPositionIterator(B.getRootNode()); +f=B.getCursor(m).getNode();for(a.setUnfilteredPosition(f,0);a.previousPosition();)if(g=a.getCurrentNode(),g.nodeType===Node.TEXT_NODE){g=g.data[a.unfilteredDomOffset()];if(!b.test(g))break;c-=1}else if(g.namespaceURI!==odf.Namespaces.textns||"span"!==g.localName)break;a.setUnfilteredPosition(f,0);do if(g=a.getCurrentNode(),g.nodeType===Node.TEXT_NODE){g=g.data[a.unfilteredDomOffset()];if(!b.test(g))break;d+=1}else if(g.namespaceURI!==odf.Namespaces.textns||"span"!==g.localName)break;while(a.nextPosition()); +if(0!==c||0!==d)b=B.getCursorPosition(m),c=e(b+c,Math.abs(c)+Math.abs(d)),n.enqueue(c)}}function k(){var a=B.getOdfCanvas().getElement(),b,c;ma.containsNode(a,X.getSelection().focusNode)&&(c=B.getParagraphElement(B.getCursor(m).getNode()),a=B.getDistanceFromCursor(m,c,0),b=gui.SelectionMover.createPositionIterator(B.getRootNode()),b.moveToEndOfNode(c),c=B.getDistanceFromCursor(m,c,b.unfilteredDomOffset()),0!==a||0!==c)&&(b=B.getCursorPosition(m),a=e(b+a,Math.abs(a)+Math.abs(c)),n.enqueue(a))}function q(a){var b= +B.getCursorSelection(m),c=B.getCursor(m).getStepCounter();0!==a&&(a=0a.length&&(a.position+=a.length,a.length=-a.length); +return a}function W(a){var b=new ops.OpRemoveText;b.init({memberid:m,position:a.position,length:a.length});return b}function U(){var a=Q(B.getCursorSelection(m)),b=null;0===a.length?0 @@ -1884,8 +1773,8 @@ ops.MemberModel=function(){};ops.MemberModel.prototype.getMemberDetailsAndUpdate @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.TrivialMemberModel=function(){this.getMemberDetailsAndUpdates=function(k,l){l(k,null)};this.unsubscribeMemberDetailsUpdates=function(k,l){};this.shutdown=function(){}}; -// Input 70 +ops.MemberModel=function(){};ops.MemberModel.prototype.getMemberDetailsAndUpdates=function(n,m){};ops.MemberModel.prototype.unsubscribeMemberDetailsUpdates=function(n,m){};ops.MemberModel.prototype.close=function(n){}; +// Input 67 /* Copyright (C) 2012-2013 KO GmbH @@ -1920,49 +1809,8 @@ ops.TrivialMemberModel=function(){this.getMemberDetailsAndUpdates=function(k,l){ @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.NowjsMemberModel=function(k){var l={},h={},e=k.getNowObject();this.getMemberDetailsAndUpdates=function(b,g){var a=b.split("___")[0],f=l[a],d=h[a]||[],c;h[a]=d;runtime.assert(void 0!==g,"missing callback");for(c=0;c - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -ops.PullBoxMemberModel=function(k,l){function h(){var a,d=Object.keys(g);runtime.log("member-list request for : "+d.join(","));l.call({command:"query_memberdata_list",args:{es_id:k,member_ids:d}},function(c){var d=runtime.fromJson(c),e;runtime.log("member-list reply: "+c);if(d.hasOwnProperty("memberdata_list"))for(c=d.memberdata_list,a=0;a @@ -1997,8 +1845,8 @@ f);delete g[f];delete b[f];a:{var h;if(a){for(h in g)if(g.hasOwnProperty(h))brea @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.OperationRouter=function(){};ops.OperationRouter.prototype.setOperationFactory=function(k){};ops.OperationRouter.prototype.setPlaybackFunction=function(k){};ops.OperationRouter.prototype.push=function(k){};ops.OperationRouter.prototype.shutdown=function(k){}; -// Input 73 +ops.OperationRouter=function(){};ops.OperationRouter.prototype.setOperationFactory=function(n){};ops.OperationRouter.prototype.setPlaybackFunction=function(n){};ops.OperationRouter.prototype.push=function(n){};ops.OperationRouter.prototype.close=function(n){};ops.OperationRouter.prototype.getHasLocalUnsyncedOpsAndUpdates=function(n){};ops.OperationRouter.prototype.unsubscribeHasLocalUnsyncedOpsUpdates=function(n){}; +// Input 69 /* Copyright (C) 2012 KO GmbH @@ -2033,62 +1881,16 @@ ops.OperationRouter=function(){};ops.OperationRouter.prototype.setOperationFacto @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -ops.TrivialOperationRouter=function(){var k,l;this.setOperationFactory=function(h){k=h};this.setPlaybackFunction=function(h){l=h};this.push=function(h){h=h.spec();h.timestamp=(new Date).getTime();h=k.create(h);l(h)};this.shutdown=function(h){h()}}; -// Input 74 -ops.NowjsOperationRouter=function(k,l,h){function e(a){var e;e=b.create(a);runtime.log(" op in: "+runtime.toJson(a));if(null!==e)if(a=Number(a.server_seq),runtime.assert(!isNaN(a),"server seq is not a number"),a===f+1)for(g(e),f=a,c=0,e=f+1;d.hasOwnProperty(e);e+=1)g(d[e]),delete d[e],runtime.log("op with server seq "+a+" taken from hold (reordered)");else runtime.assert(a!==f+1,"received incorrect order from server"),runtime.assert(!d.hasOwnProperty(a),"reorder_queue has incoming op"),runtime.log("op with server seq "+ -a+" put on hold"),d[a]=e;else runtime.log("ignoring invalid incoming opspec: "+a)}var b,g,a=h.getNowObject(),f=-1,d={},c=0,t=1E3;this.setOperationFactory=function(a){b=a};this.setPlaybackFunction=function(a){g=a};a.ping=function(a){null!==l&&a(l)};a.receiveOp=function(a,b){a===k&&e(b)};this.push=function(b){b=b.spec();runtime.assert(null!==l,"Router sequence N/A without memberid");t+=1;b.client_nonce="C:"+l+":"+t;b.parent_op=f+"+"+c;c+=1;runtime.log("op out: "+runtime.toJson(b));a.deliverOp(k,b)}; -this.requestReplay=function(b){a.requestReplay(k,function(a){runtime.log("replaying: "+runtime.toJson(a));e(a)},function(a){runtime.log("replay done ("+a+" ops).");b&&b()})};this.shutdown=function(a){}}; -// Input 75 -/* - - Copyright (C) 2013 KO GmbH - - @licstart - The JavaScript code in this page 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. The code is distributed - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details. - - As additional permission under GNU AGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU GPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - As a special exception to the AGPL, any HTML file which merely makes function - calls to this code, and for that purpose includes it by reference shall be - deemed a separate work for copyright law purposes. In addition, the copyright - holders of this code give you permission to combine this code with free - software libraries that are released under the GNU LGPL. You may copy and - distribute such a system following the terms of the GNU AGPL for this code - and the LGPL for the libraries. If you modify this code, you may extend this - exception to your version of the code, but you are not obligated to do so. - If you do not wish to do so, delete this exception statement from your - version. - - This license applies to this entire compilation. - @licend - @source: http://www.webodf.org/ - @source: http://gitorious.org/webodf/webodf/ -*/ -runtime.loadClass("ops.OperationTransformer"); -ops.PullBoxOperationRouter=function(k,l,h){function e(a){var b,c,e,f=[];for(b=0;bl?(h(1,0),f=h(0.5,1E4-l),d=h(0.2,2E4-l)):1E4<=l&&2E4>l?(h(0.5,0),d=h(0.2,2E4-l)):h(0.2,0)};this.getEdits= -function(){return k.getEdits()};this.clearEdits=function(){k.clearEdits();g.setEdits([]);a.hasAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")&&a.removeAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")};this.getEditInfo=function(){return k};this.show=function(){a.style.display="block"};this.hide=function(){e.hideHandle();a.style.display="none"};this.showHandle=function(){g.show()};this.hideHandle=function(){g.hide()};(function(){var c=k.getOdtDocument().getDOM();a=c.createElementNS(c.documentElement.namespaceURI, -"div");a.setAttribute("class","editInfoMarker");a.onmouseover=function(){e.showHandle()};a.onmouseout=function(){e.hideHandle()};b=k.getNode();b.appendChild(a);g=new gui.EditInfoHandle(b);l||e.hide()})()}; -// Input 78 +gui.EditInfoMarker=function(n,m){function l(b,d){return runtime.getWindow().setTimeout(function(){a.style.opacity=b},d)}var d=this,b,e,a,h,f;this.addEdit=function(b,d){var k=Date.now()-d;n.addEdit(b,d);e.setEdits(n.getSortedEdits());a.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",b);if(h){var m=h;runtime.getWindow().clearTimeout(m)}f&&(m=f,runtime.getWindow().clearTimeout(m));1E4>k?(l(1,0),h=l(0.5,1E4-k),f=l(0.2,2E4-k)):1E4<=k&&2E4>k?(l(0.5,0),f=l(0.2,2E4-k)):l(0.2,0)};this.getEdits= +function(){return n.getEdits()};this.clearEdits=function(){n.clearEdits();e.setEdits([]);a.hasAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")&&a.removeAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")};this.getEditInfo=function(){return n};this.show=function(){a.style.display="block"};this.hide=function(){d.hideHandle();a.style.display="none"};this.showHandle=function(){e.show()};this.hideHandle=function(){e.hide()};(function(){var c=n.getOdtDocument().getDOM();a=c.createElementNS(c.documentElement.namespaceURI, +"div");a.setAttribute("class","editInfoMarker");a.onmouseover=function(){d.showHandle()};a.onmouseout=function(){d.hideHandle()};b=n.getNode();b.appendChild(a);e=new gui.EditInfoHandle(b);m||d.hide()})()}; +// Input 72 /* Copyright (C) 2012-2013 KO GmbH @@ -2124,13 +1926,13 @@ function(){return k.getEdits()};this.clearEdits=function(){k.clearEdits();g.setE @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("gui.Caret");runtime.loadClass("ops.TrivialMemberModel");runtime.loadClass("ops.EditInfo");runtime.loadClass("gui.EditInfoMarker");gui.SessionViewOptions=function(){this.caretBlinksOnRangeSelect=this.caretAvatarsInitiallyVisible=this.editInfoMarkersInitiallyVisible=!0}; -gui.SessionView=function(){return function(k,l,h){function e(a,b,d){function e(b,d,f){d=b+'[editinfo|memberid^="'+a+'"]'+f+d;a:{var g=c.firstChild;for(b=b+'[editinfo|memberid^="'+a+'"]'+f;g;){if(g.nodeType===Node.TEXT_NODE&&0===g.data.indexOf(b)){b=g;break a}g=g.nextSibling}b=null}b?b.data=d:c.appendChild(document.createTextNode(d))}e("div.editInfoMarker","{ background-color: "+d+"; }","");e("span.editInfoColor","{ background-color: "+d+"; }","");e("span.editInfoAuthor",'{ content: "'+b+'"; }',":before"); -e("dc|creator",'{ content: "'+b+'"; display: none;}',":before");e("dc|creator","{ background-color: "+d+"; }","")}function b(a){var b,c;for(c in t)t.hasOwnProperty(c)&&(b=t[c],a?b.show():b.hide())}function g(a){h.getCarets().forEach(function(b){a?b.showHandle():b.hideHandle()})}function a(a,b){var c=h.getCaret(a);void 0===b?runtime.log('MemberModel sent undefined data for member "'+a+'".'):(null===b&&(b={memberid:a,fullname:"Unknown Identity",color:"black",imageurl:"avatar-joe.png"}),c&&(c.setAvatarImageUrl(b.imageurl), -c.setColor(b.color)),e(a,b.fullname,b.color))}function f(b){var c=b.getMemberId(),d=l.getMemberModel();h.registerCursor(b,q,n);a(c,null);d.getMemberDetailsAndUpdates(c,a);runtime.log("+++ View here +++ eagerly created an Caret for '"+c+"'! +++")}function d(b){var c=!1,d;for(d in t)if(t.hasOwnProperty(d)&&t[d].getEditInfo().getEdits().hasOwnProperty(b)){c=!0;break}c||l.getMemberModel().unsubscribeMemberDetailsUpdates(b,a)}var c,t={},m=void 0!==k.editInfoMarkersInitiallyVisible?Boolean(k.editInfoMarkersInitiallyVisible): -!0,q=void 0!==k.caretAvatarsInitiallyVisible?Boolean(k.caretAvatarsInitiallyVisible):!0,n=void 0!==k.caretBlinksOnRangeSelect?Boolean(k.caretBlinksOnRangeSelect):!0;this.showEditInfoMarkers=function(){m||(m=!0,b(m))};this.hideEditInfoMarkers=function(){m&&(m=!1,b(m))};this.showCaretAvatars=function(){q||(q=!0,g(q))};this.hideCaretAvatars=function(){q&&(q=!1,g(q))};this.getSession=function(){return l};this.getCaret=function(a){return h.getCaret(a)};(function(){var a=l.getOdtDocument(),b=document.getElementsByTagName("head")[0]; -a.subscribe(ops.OdtDocument.signalCursorAdded,f);a.subscribe(ops.OdtDocument.signalCursorRemoved,d);a.subscribe(ops.OdtDocument.signalParagraphChanged,function(a){var b=a.paragraphElement,c=a.memberId;a=a.timeStamp;var d,e="",f=b.getElementsByTagNameNS("urn:webodf:names:editinfo","editinfo")[0];f?(e=f.getAttributeNS("urn:webodf:names:editinfo","id"),d=t[e]):(e=Math.random().toString(),d=new ops.EditInfo(b,l.getOdtDocument()),d=new gui.EditInfoMarker(d,m),f=b.getElementsByTagNameNS("urn:webodf:names:editinfo", -"editinfo")[0],f.setAttributeNS("urn:webodf:names:editinfo","id",e),t[e]=d);d.addEdit(c,new Date(a))});c=document.createElementNS(b.namespaceURI,"style");c.type="text/css";c.media="screen, print, handheld, projection";c.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));c.appendChild(document.createTextNode("@namespace dc url(http://purl.org/dc/elements/1.1/);"));b.appendChild(c)})()}}(); -// Input 79 +gui.SessionView=function(){return function(n,m,l){function d(a,b,d){function e(b,d,f){d=b+'[editinfo|memberid^="'+a+'"]'+f+d;a:{var g=c.firstChild;for(b=b+'[editinfo|memberid^="'+a+'"]'+f;g;){if(g.nodeType===Node.TEXT_NODE&&0===g.data.indexOf(b)){b=g;break a}g=g.nextSibling}b=null}b?b.data=d:c.appendChild(document.createTextNode(d))}e("div.editInfoMarker","{ background-color: "+d+"; }","");e("span.editInfoColor","{ background-color: "+d+"; }","");e("span.editInfoAuthor",'{ content: "'+b+'"; }',":before"); +e("dc|creator",'{ content: "'+b+'"; display: none;}',":before");e("dc|creator","{ background-color: "+d+"; }","")}function b(a){var b,c;for(c in t)t.hasOwnProperty(c)&&(b=t[c],a?b.show():b.hide())}function e(a){l.getCarets().forEach(function(b){a?b.showHandle():b.hideHandle()})}function a(a,b){var c=l.getCaret(a);void 0===b?runtime.log('MemberModel sent undefined data for member "'+a+'".'):(null===b&&(b={memberid:a,fullname:"Unknown Identity",color:"black",imageurl:"avatar-joe.png"}),c&&(c.setAvatarImageUrl(b.imageurl), +c.setColor(b.color)),d(a,b.fullname,b.color))}function h(b){var c=b.getMemberId(),d=m.getMemberModel();l.registerCursor(b,q,g);a(c,null);d.getMemberDetailsAndUpdates(c,a);runtime.log("+++ View here +++ eagerly created an Caret for '"+c+"'! +++")}function f(b){var c=!1,d;for(d in t)if(t.hasOwnProperty(d)&&t[d].getEditInfo().getEdits().hasOwnProperty(b)){c=!0;break}c||m.getMemberModel().unsubscribeMemberDetailsUpdates(b,a)}var c,t={},k=void 0!==n.editInfoMarkersInitiallyVisible?Boolean(n.editInfoMarkersInitiallyVisible): +!0,q=void 0!==n.caretAvatarsInitiallyVisible?Boolean(n.caretAvatarsInitiallyVisible):!0,g=void 0!==n.caretBlinksOnRangeSelect?Boolean(n.caretBlinksOnRangeSelect):!0;this.showEditInfoMarkers=function(){k||(k=!0,b(k))};this.hideEditInfoMarkers=function(){k&&(k=!1,b(k))};this.showCaretAvatars=function(){q||(q=!0,e(q))};this.hideCaretAvatars=function(){q&&(q=!1,e(q))};this.getSession=function(){return m};this.getCaret=function(a){return l.getCaret(a)};this.close=function(a){a()};(function(){var a=m.getOdtDocument(), +b=document.getElementsByTagName("head")[0];a.subscribe(ops.OdtDocument.signalCursorAdded,h);a.subscribe(ops.OdtDocument.signalCursorRemoved,f);a.subscribe(ops.OdtDocument.signalParagraphChanged,function(a){var b=a.paragraphElement,c=a.memberId;a=a.timeStamp;var d,e="",f=b.getElementsByTagNameNS("urn:webodf:names:editinfo","editinfo")[0];f?(e=f.getAttributeNS("urn:webodf:names:editinfo","id"),d=t[e]):(e=Math.random().toString(),d=new ops.EditInfo(b,m.getOdtDocument()),d=new gui.EditInfoMarker(d,k), +f=b.getElementsByTagNameNS("urn:webodf:names:editinfo","editinfo")[0],f.setAttributeNS("urn:webodf:names:editinfo","id",e),t[e]=d);d.addEdit(c,new Date(a))});c=document.createElementNS(b.namespaceURI,"style");c.type="text/css";c.media="screen, print, handheld, projection";c.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));c.appendChild(document.createTextNode("@namespace dc url(http://purl.org/dc/elements/1.1/);"));b.appendChild(c)})()}}(); +// Input 73 /* Copyright (C) 2012-2013 KO GmbH @@ -2166,27 +1968,27 @@ a.subscribe(ops.OdtDocument.signalCursorAdded,f);a.subscribe(ops.OdtDocument.sig @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("gui.Caret"); -gui.CaretManager=function(k){function l(a){return d.hasOwnProperty(a)?d[a]:null}function h(){return k.getSession().getOdtDocument().getOdfCanvas().getElement()}function e(a){a===k.getInputMemberId()&&h().removeAttribute("tabindex");delete d[a]}function b(a){a=a.getMemberId();a===k.getInputMemberId()&&(a=l(a))&&a.refreshCursorBlinking()}function g(a){a.memberId===k.getInputMemberId()&&(a=l(a.memberId))&&a.ensureVisible()}function a(){var a=l(k.getInputMemberId());a&&a.setFocus()}function f(){var a= -l(k.getInputMemberId());a&&a.removeFocus()}var d={};this.registerCursor=function(a,b,e){var f=a.getMemberId(),g=h();b=new gui.Caret(a,b,e);d[f]=b;f===k.getInputMemberId()&&(runtime.log("Starting to track input on new cursor of "+f),a.handleUpdate=b.ensureVisible,g.setAttribute("tabindex",0),g.focus());return b};this.getCaret=l;this.getCarets=function(){return Object.keys(d).map(function(a){return d[a]})};(function(){var c=k.getSession().getOdtDocument(),d=h();c.subscribe(ops.OdtDocument.signalParagraphChanged, -g);c.subscribe(ops.OdtDocument.signalCursorMoved,b);c.subscribe(ops.OdtDocument.signalCursorRemoved,e);d.onfocus=a;d.onblur=f})()}; -// Input 80 +gui.CaretManager=function(n){function m(a){return f.hasOwnProperty(a)?f[a]:null}function l(){return n.getSession().getOdtDocument().getOdfCanvas().getElement()}function d(a){a===n.getInputMemberId()&&l().removeAttribute("tabindex");delete f[a]}function b(a){a=a.getMemberId();a===n.getInputMemberId()&&(a=m(a))&&a.refreshCursorBlinking()}function e(a){a.memberId===n.getInputMemberId()&&(a=m(a.memberId))&&a.ensureVisible()}function a(){var a=m(n.getInputMemberId());a&&a.setFocus()}function h(){var a= +m(n.getInputMemberId());a&&a.removeFocus()}var f={};this.registerCursor=function(a,b,d){var e=a.getMemberId(),g=l();b=new gui.Caret(a,b,d);f[e]=b;e===n.getInputMemberId()&&(runtime.log("Starting to track input on new cursor of "+e),a.handleUpdate=b.ensureVisible,g.setAttribute("tabindex",0),g.focus());return b};this.getCaret=m;this.getCarets=function(){return Object.keys(f).map(function(a){return f[a]})};(function(){var c=n.getSession().getOdtDocument(),f=l();c.subscribe(ops.OdtDocument.signalParagraphChanged, +e);c.subscribe(ops.OdtDocument.signalCursorMoved,b);c.subscribe(ops.OdtDocument.signalCursorRemoved,d);f.onfocus=a;f.onblur=h})()}; +// Input 74 runtime.loadClass("xmldom.XPath");runtime.loadClass("odf.Namespaces"); -gui.PresenterUI=function(){var k=new xmldom.XPath,l=runtime.getWindow();return function(h){var e=this;e.setInitialSlideMode=function(){e.startSlideMode("single")};e.keyDownHandler=function(b){if(!b.target.isContentEditable&&"input"!==b.target.nodeName)switch(b.keyCode){case 84:e.toggleToolbar();break;case 37:case 8:e.prevSlide();break;case 39:case 32:e.nextSlide();break;case 36:e.firstSlide();break;case 35:e.lastSlide()}};e.root=function(){return e.odf_canvas.odfContainer().rootElement};e.firstSlide= -function(){e.slideChange(function(b,e){return 0})};e.lastSlide=function(){e.slideChange(function(b,e){return e-1})};e.nextSlide=function(){e.slideChange(function(b,e){return b+1b?-1:b-1})};e.slideChange=function(b){var g=e.getPages(e.odf_canvas.odfContainer().rootElement),a=-1,f=0;g.forEach(function(b){b=b[1];b.hasAttribute("slide_current")&&(a=f,b.removeAttribute("slide_current"));f+=1});b=b(a,g.length);-1===b&&(b=a);g[b][1].setAttribute("slide_current", -"1");document.getElementById("pagelist").selectedIndex=b;"cont"===e.slide_mode&&l.scrollBy(0,g[b][1].getBoundingClientRect().top-30)};e.selectSlide=function(b){e.slideChange(function(e,a){return b>=a||0>b?-1:b})};e.scrollIntoContView=function(b){var g=e.getPages(e.odf_canvas.odfContainer().rootElement);0!==g.length&&l.scrollBy(0,g[b][1].getBoundingClientRect().top-30)};e.getPages=function(b){b=b.getElementsByTagNameNS(odf.Namespaces.drawns,"page");var e=[],a;for(a=0;ab?-1:b-1})};d.slideChange=function(b){var e=d.getPages(d.odf_canvas.odfContainer().rootElement),a=-1,h=0;e.forEach(function(b){b=b[1];b.hasAttribute("slide_current")&&(a=h,b.removeAttribute("slide_current"));h+=1});b=b(a,e.length);-1===b&&(b=a);e[b][1].setAttribute("slide_current", +"1");document.getElementById("pagelist").selectedIndex=b;"cont"===d.slide_mode&&m.scrollBy(0,e[b][1].getBoundingClientRect().top-30)};d.selectSlide=function(b){d.slideChange(function(d,a){return b>=a||0>b?-1:b})};d.scrollIntoContView=function(b){var e=d.getPages(d.odf_canvas.odfContainer().rootElement);0!==e.length&&m.scrollBy(0,e[b][1].getBoundingClientRect().top-30)};d.getPages=function(b){b=b.getElementsByTagNameNS(odf.Namespaces.drawns,"page");var d=[],a;for(a=0;a=a.rangeCount||!p)||(a=a.getRangeAt(0),p.setPoint(a.startContainer,a.startOffset))}function g(){var a=k.ownerDocument.defaultView.getSelection(),b,c;a.removeAllRanges();p&&p.node()&&(b=p.node(),c=b.ownerDocument.createRange(), -c.setStart(b,p.position()),c.collapse(!0),a.addRange(c))}function a(a){var c=a.charCode||a.keyCode;if(p=null,p&&37===c)b(),p.stepBackward(),g();else if(16<=c&&20>=c||33<=c&&40>=c)return;e(a)}function f(a){e(a)}function d(a){for(var b=a.firstChild;b&&b!==a;)b.nodeType===Node.ELEMENT_NODE&&d(b),b=b.nextSibling||b.parentNode;var c,e,f,b=a.attributes;c="";for(f=b.length-1;0<=f;f-=1)e=b.item(f),c=c+" "+e.nodeName+'="'+e.nodeValue+'"';a.setAttribute("customns_name",a.nodeName);a.setAttribute("customns_atts", -c);b=a.firstChild;for(e=/^\s*$/;b&&b!==a;)c=b,b=b.nextSibling||b.parentNode,c.nodeType===Node.TEXT_NODE&&e.test(c.nodeValue)&&c.parentNode.removeChild(c)}function c(a,b){for(var d=a.firstChild,e,f,g;d&&d!==a;){if(d.nodeType===Node.ELEMENT_NODE)for(c(d,b),e=d.attributes,g=e.length-1;0<=g;g-=1)f=e.item(g),"http://www.w3.org/2000/xmlns/"!==f.namespaceURI||b[f.nodeValue]||(b[f.nodeValue]=f.localName);d=d.nextSibling||d.parentNode}}function t(){var a=k.ownerDocument.createElement("style"),b;b={};c(k,b); -var d={},e,f,g=0;for(e in b)if(b.hasOwnProperty(e)&&e){f=b[e];if(!f||d.hasOwnProperty(f)||"xmlns"===f){do f="ns"+g,g+=1;while(d.hasOwnProperty(f));b[e]=f}d[f]=!0}a.type="text/css";b="@namespace customns url(customns);\n"+m;a.appendChild(k.ownerDocument.createTextNode(b));l=l.parentNode.replaceChild(a,l)}var m,q,n,p=null;k.id||(k.id="xml"+String(Math.random()).substring(2));q="#"+k.id+" ";m=q+"*,"+q+":visited, "+q+":link {display:block; margin: 0px; margin-left: 10px; font-size: medium; color: black; background: white; font-variant: normal; font-weight: normal; font-style: normal; font-family: sans-serif; text-decoration: none; white-space: pre-wrap; height: auto; width: auto}\n"+ -q+":before {color: blue; content: '<' attr(customns_name) attr(customns_atts) '>';}\n"+q+":after {color: blue; content: '';}\n"+q+"{overflow: auto;}\n";(function(b){h(b,"click",f);h(b,"keydown",a);h(b,"drop",e);h(b,"dragend",e);h(b,"beforepaste",e);h(b,"paste",e)})(k);this.updateCSS=t;this.setXML=function(a){a=a.documentElement||a;n=a=k.ownerDocument.importNode(a,!0);for(d(a);k.lastChild;)k.removeChild(k.lastChild);k.appendChild(a);t();p=new core.PositionIterator(a)};this.getXML= -function(){return n}}; -// Input 82 +gui.XMLEdit=function(n,m){function l(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent?a.attachEvent("on"+b,c):a["on"+b]=c}function d(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function b(){var a=n.ownerDocument.defaultView.getSelection();!a||(0>=a.rangeCount||!p)||(a=a.getRangeAt(0),p.setPoint(a.startContainer,a.startOffset))}function e(){var a=n.ownerDocument.defaultView.getSelection(),b,c;a.removeAllRanges();p&&p.node()&&(b=p.node(),c=b.ownerDocument.createRange(), +c.setStart(b,p.position()),c.collapse(!0),a.addRange(c))}function a(a){var c=a.charCode||a.keyCode;if(p=null,p&&37===c)b(),p.stepBackward(),e();else if(16<=c&&20>=c||33<=c&&40>=c)return;d(a)}function h(a){d(a)}function f(a){for(var b=a.firstChild;b&&b!==a;)b.nodeType===Node.ELEMENT_NODE&&f(b),b=b.nextSibling||b.parentNode;var c,d,e,b=a.attributes;c="";for(e=b.length-1;0<=e;e-=1)d=b.item(e),c=c+" "+d.nodeName+'="'+d.nodeValue+'"';a.setAttribute("customns_name",a.nodeName);a.setAttribute("customns_atts", +c);b=a.firstChild;for(d=/^\s*$/;b&&b!==a;)c=b,b=b.nextSibling||b.parentNode,c.nodeType===Node.TEXT_NODE&&d.test(c.nodeValue)&&c.parentNode.removeChild(c)}function c(a,b){for(var d=a.firstChild,e,f,g;d&&d!==a;){if(d.nodeType===Node.ELEMENT_NODE)for(c(d,b),e=d.attributes,g=e.length-1;0<=g;g-=1)f=e.item(g),"http://www.w3.org/2000/xmlns/"!==f.namespaceURI||b[f.nodeValue]||(b[f.nodeValue]=f.localName);d=d.nextSibling||d.parentNode}}function t(){var a=n.ownerDocument.createElement("style"),b;b={};c(n,b); +var d={},e,f,g=0;for(e in b)if(b.hasOwnProperty(e)&&e){f=b[e];if(!f||d.hasOwnProperty(f)||"xmlns"===f){do f="ns"+g,g+=1;while(d.hasOwnProperty(f));b[e]=f}d[f]=!0}a.type="text/css";b="@namespace customns url(customns);\n"+k;a.appendChild(n.ownerDocument.createTextNode(b));m=m.parentNode.replaceChild(a,m)}var k,q,g,p=null;n.id||(n.id="xml"+String(Math.random()).substring(2));q="#"+n.id+" ";k=q+"*,"+q+":visited, "+q+":link {display:block; margin: 0px; margin-left: 10px; font-size: medium; color: black; background: white; font-variant: normal; font-weight: normal; font-style: normal; font-family: sans-serif; text-decoration: none; white-space: pre-wrap; height: auto; width: auto}\n"+ +q+":before {color: blue; content: '<' attr(customns_name) attr(customns_atts) '>';}\n"+q+":after {color: blue; content: '';}\n"+q+"{overflow: auto;}\n";(function(b){l(b,"click",h);l(b,"keydown",a);l(b,"drop",d);l(b,"dragend",d);l(b,"beforepaste",d);l(b,"paste",d)})(n);this.updateCSS=t;this.setXML=function(a){a=a.documentElement||a;g=a=n.ownerDocument.importNode(a,!0);for(f(a);n.lastChild;)n.removeChild(n.lastChild);n.appendChild(a);t();p=new core.PositionIterator(a)};this.getXML= +function(){return g}}; +// Input 76 /* Copyright (C) 2013 KO GmbH @@ -2221,9 +2023,9 @@ function(){return n}}; @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -gui.UndoManager=function(){};gui.UndoManager.prototype.subscribe=function(k,l){};gui.UndoManager.prototype.unsubscribe=function(k,l){};gui.UndoManager.prototype.setOdtDocument=function(k){};gui.UndoManager.prototype.saveInitialState=function(){};gui.UndoManager.prototype.resetInitialState=function(){};gui.UndoManager.prototype.setPlaybackFunction=function(k){};gui.UndoManager.prototype.hasUndoStates=function(){};gui.UndoManager.prototype.hasRedoStates=function(){}; -gui.UndoManager.prototype.moveForward=function(k){};gui.UndoManager.prototype.moveBackward=function(k){};gui.UndoManager.prototype.onOperationExecuted=function(k){};gui.UndoManager.signalUndoStackChanged="undoStackChanged";gui.UndoManager.signalUndoStateCreated="undoStateCreated";gui.UndoManager.signalUndoStateModified="undoStateModified";(function(){return gui.UndoManager})(); -// Input 83 +gui.UndoManager=function(){};gui.UndoManager.prototype.subscribe=function(n,m){};gui.UndoManager.prototype.unsubscribe=function(n,m){};gui.UndoManager.prototype.setOdtDocument=function(n){};gui.UndoManager.prototype.saveInitialState=function(){};gui.UndoManager.prototype.resetInitialState=function(){};gui.UndoManager.prototype.setPlaybackFunction=function(n){};gui.UndoManager.prototype.hasUndoStates=function(){};gui.UndoManager.prototype.hasRedoStates=function(){}; +gui.UndoManager.prototype.moveForward=function(n){};gui.UndoManager.prototype.moveBackward=function(n){};gui.UndoManager.prototype.onOperationExecuted=function(n){};gui.UndoManager.signalUndoStackChanged="undoStackChanged";gui.UndoManager.signalUndoStateCreated="undoStateCreated";gui.UndoManager.signalUndoStateModified="undoStateModified";(function(){return gui.UndoManager})(); +// Input 77 /* Copyright (C) 2013 KO GmbH @@ -2258,9 +2060,9 @@ gui.UndoManager.prototype.moveForward=function(k){};gui.UndoManager.prototype.mo @source: http://www.webodf.org/ @source: http://gitorious.org/webodf/webodf/ */ -gui.UndoStateRules=function(){function k(h){return h.spec().optype}function l(h){switch(k(h)){case "MoveCursor":case "AddCursor":case "RemoveCursor":return!1;default:return!0}}this.getOpType=k;this.isEditOperation=l;this.isPartOfOperationSet=function(h,e){if(l(h)){if(0===e.length)return!0;var b;if(b=l(e[e.length-1]))a:{b=e.filter(l);var g=k(h),a;b:switch(g){case "RemoveText":case "InsertText":a=!0;break b;default:a=!1}if(a&&g===k(b[0])){if(1===b.length){b=!0;break a}g=b[b.length-2].spec().position; -b=b[b.length-1].spec().position;a=h.spec().position;if(b===a-(b-g)){b=!0;break a}}b=!1}return b}return!0}}; -// Input 84 +gui.UndoStateRules=function(){function n(l){return l.spec().optype}function m(l){switch(n(l)){case "MoveCursor":case "AddCursor":case "RemoveCursor":return!1;default:return!0}}this.getOpType=n;this.isEditOperation=m;this.isPartOfOperationSet=function(l,d){if(m(l)){if(0===d.length)return!0;var b;if(b=m(d[d.length-1]))a:{b=d.filter(m);var e=n(l),a;b:switch(e){case "RemoveText":case "InsertText":a=!0;break b;default:a=!1}if(a&&e===n(b[0])){if(1===b.length){b=!0;break a}e=b[b.length-2].spec().position; +b=b[b.length-1].spec().position;a=l.spec().position;if(b===a-(b-e)){b=!0;break a}}b=!1}return b}return!0}}; +// Input 78 /* Copyright (C) 2013 KO GmbH @@ -2296,13 +2098,13 @@ b=b[b.length-1].spec().position;a=h.spec().position;if(b===a-(b-g)){b=!0;break a @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("core.DomUtils");runtime.loadClass("gui.UndoManager");runtime.loadClass("gui.UndoStateRules"); -gui.TrivialUndoManager=function(k){function l(){r.emit(gui.UndoManager.signalUndoStackChanged,{undoAvailable:a.hasUndoStates(),redoAvailable:a.hasRedoStates()})}function h(){q!==c&&q!==n[n.length-1]&&n.push(q)}function e(a){var b=a.previousSibling||a.nextSibling;a.parentNode.removeChild(a);f.normalizeTextNodes(b)}function b(a){return Object.keys(a).map(function(b){return a[b]})}function g(a){function c(a){var b=a.spec();if(f[b.memberid])switch(b.optype){case "AddCursor":d[b.memberid]||(d[b.memberid]= -a,delete f[b.memberid],g-=1);break;case "MoveCursor":e[b.memberid]||(e[b.memberid]=a)}}var d={},e={},f={},g,h=a.pop();m.getCursors().forEach(function(a){f[a.getMemberId()]=!0});for(g=Object.keys(f).length;h&&0 @@ -2338,22 +2140,22 @@ b.refreshCSS(),q=n[n.length-1]||c,l());return f}};gui.TrivialUndoManager.signalD @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("core.EventNotifier");runtime.loadClass("odf.OdfUtils");runtime.loadClass("gui.SelectionMover");runtime.loadClass("gui.StyleHelper");runtime.loadClass("core.PositionFilterChain"); -ops.OdtDocument=function(k){function l(){var a=k.odfContainer().getContentElement(),b=a&&a.localName;runtime.assert("text"===b,"Unsupported content element type '"+b+"'for OdtDocument");return a}function h(a){function b(a){for(;!(a.namespaceURI===odf.Namespaces.officens&&"text"===a.localName||a.namespaceURI===odf.Namespaces.officens&&"annotation"===a.localName);)a=a.parentNode;return a}this.acceptPosition=function(c){c=c.container();var e=d[a].getNode();return b(c)===b(e)?t:m}}function e(a){var b= -gui.SelectionMover.createPositionIterator(l());for(a+=1;0=d;d+=1){b=a.container();c=a.unfilteredDomOffset();if(b.nodeType===Node.TEXT_NODE&&" "===b.data[c]&&f.isSignificantWhitespace(b, -c)){runtime.assert(" "===b.data[c],"upgradeWhitespaceToElement: textNode.data[offset] should be a literal space");var g=b.ownerDocument.createElementNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0","text:s");g.appendChild(b.ownerDocument.createTextNode(" "));b.deleteData(c,1);0= 0");1===q.acceptPosition(c)?(f=c.container(),f.nodeType===Node.TEXT_NODE&&(e=f,g=0)):a+=1;for(;0=e;e+=1){b=a.container();c=a.unfilteredDomOffset();if(b.nodeType===Node.TEXT_NODE&&" "===b.data[c]&&h.isSignificantWhitespace(b, +c)){runtime.assert(" "===b.data[c],"upgradeWhitespaceToElement: textNode.data[offset] should be a literal space");var f=b.ownerDocument.createElementNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0","text:s");f.appendChild(b.ownerDocument.createTextNode(" "));b.deleteData(c,1);0= 0");1===q.acceptPosition(d)?(h=d.container(),h.nodeType===Node.TEXT_NODE&&(e=h,k=0)):b+=1;for(;0 @@ -2389,7 +2191,7 @@ ops.OdtDocument.signalStyleCreated="style/created";ops.OdtDocument.signalStyleDe @source: http://gitorious.org/webodf/webodf/ */ runtime.loadClass("ops.TrivialMemberModel");runtime.loadClass("ops.TrivialOperationRouter");runtime.loadClass("ops.OperationFactory");runtime.loadClass("ops.OdtDocument"); -ops.Session=function(k){var l=new ops.OperationFactory,h=new ops.OdtDocument(k),e=new ops.TrivialMemberModel,b=null;this.setMemberModel=function(b){e=b};this.setOperationFactory=function(e){l=e;b&&b.setOperationFactory(l)};this.setOperationRouter=function(e){b=e;e.setPlaybackFunction(function(a){a.execute(h);h.emit(ops.OdtDocument.signalOperationExecuted,a)});e.setOperationFactory(l)};this.getMemberModel=function(){return e};this.getOperationFactory=function(){return l};this.getOdtDocument=function(){return h}; -this.enqueue=function(e){b.push(e)};this.setOperationRouter(new ops.TrivialOperationRouter)}; -// Input 87 -var webodf_css="@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n@namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n@namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n@namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n@namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n@namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n@namespace table url(urn:oasis:names:tc:opendocument:xmlns:table:1.0);\n@namespace text url(urn:oasis:names:tc:opendocument:xmlns:text:1.0);\n@namespace runtimens url(urn:webodf); /* namespace for runtime only */\n@namespace cursor url(urn:webodf:names:cursor);\n@namespace editinfo url(urn:webodf:names:editinfo);\n@namespace annotation url(urn:webodf:names:annotation);\n@namespace dc url(http://purl.org/dc/elements/1.1/);\n\noffice|document > *, office|document-content > * {\n display: none;\n}\noffice|body, office|document {\n display: inline-block;\n position: relative;\n}\n\ntext|p, text|h {\n display: block;\n padding: 0;\n margin: 0;\n line-height: normal;\n position: relative;\n min-height: 1.3em; /* prevent empty paragraphs and headings from collapsing if they are empty */\n}\n*[runtimens|containsparagraphanchor] {\n position: relative;\n}\ntext|s {\n white-space: pre;\n}\ntext|tab {\n display: inline;\n white-space: pre;\n}\ntext|line-break {\n content: \" \";\n display: block;\n}\ntext|tracked-changes {\n /*Consumers that do not support change tracking, should ignore changes.*/\n display: none;\n}\noffice|binary-data {\n display: none;\n}\noffice|text {\n display: block;\n text-align: left;\n overflow: visible;\n word-wrap: break-word;\n}\n\noffice|text::selection {\n /** Let's not draw selection highlight that overflows into the office|text\n * node when selecting content across several paragraphs\n */\n background: transparent;\n}\n\noffice|spreadsheet {\n display: block;\n border-collapse: collapse;\n empty-cells: show;\n font-family: sans-serif;\n font-size: 10pt;\n text-align: left;\n page-break-inside: avoid;\n overflow: hidden;\n}\noffice|presentation {\n display: inline-block;\n text-align: left;\n}\n#shadowContent {\n display: inline-block;\n text-align: left;\n}\ndraw|page {\n display: block;\n position: relative;\n overflow: hidden;\n}\npresentation|notes, presentation|footer-decl, presentation|date-time-decl {\n display: none;\n}\n@media print {\n draw|page {\n border: 1pt solid black;\n page-break-inside: avoid;\n }\n presentation|notes {\n /*TODO*/\n }\n}\noffice|spreadsheet text|p {\n border: 0px;\n padding: 1px;\n margin: 0px;\n}\noffice|spreadsheet table|table {\n margin: 3px;\n}\noffice|spreadsheet table|table:after {\n /* show sheet name the end of the sheet */\n /*content: attr(table|name);*/ /* gives parsing error in opera */\n}\noffice|spreadsheet table|table-row {\n counter-increment: row;\n}\noffice|spreadsheet table|table-row:before {\n width: 3em;\n background: #cccccc;\n border: 1px solid black;\n text-align: center;\n content: counter(row);\n display: table-cell;\n}\noffice|spreadsheet table|table-cell {\n border: 1px solid #cccccc;\n}\ntable|table {\n display: table;\n}\ndraw|frame table|table {\n width: 100%;\n height: 100%;\n background: white;\n}\ntable|table-header-rows {\n display: table-header-group;\n}\ntable|table-row {\n display: table-row;\n}\ntable|table-column {\n display: table-column;\n}\ntable|table-cell {\n width: 0.889in;\n display: table-cell;\n word-break: break-all; /* prevent long words from extending out the table cell */\n}\ndraw|frame {\n display: block;\n}\ndraw|image {\n display: block;\n width: 100%;\n height: 100%;\n top: 0px;\n left: 0px;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n -moz-background-size: 100% 100%;\n}\n/* only show the first image in frame */\ndraw|frame > draw|image:nth-of-type(n+2) {\n display: none;\n}\ntext|list:before {\n display: none;\n content:\"\";\n}\ntext|list {\n counter-reset: list;\n}\ntext|list-item {\n display: block;\n}\ntext|number {\n display:none;\n}\n\ntext|a {\n color: blue;\n text-decoration: underline;\n cursor: pointer;\n}\ntext|note-citation {\n vertical-align: super;\n font-size: smaller;\n}\ntext|note-body {\n display: none;\n}\ntext|note:hover text|note-citation {\n background: #dddddd;\n}\ntext|note:hover text|note-body {\n display: block;\n left:1em;\n max-width: 80%;\n position: absolute;\n background: #ffffaa;\n}\nsvg|title, svg|desc {\n display: none;\n}\nvideo {\n width: 100%;\n height: 100%\n}\n\n/* below set up the cursor */\ncursor|cursor {\n display: inline;\n width: 0px;\n height: 1em;\n /* making the position relative enables the avatar to use\n the cursor as reference for its absolute position */\n position: relative;\n z-index: 1;\n}\ncursor|cursor > span {\n display: inline;\n position: absolute;\n top: 5%; /* push down the caret; 0px can do the job, 5% looks better, 10% is a bit over */\n height: 1em;\n border-left: 2px solid black;\n outline: none;\n}\n\ncursor|cursor > div {\n padding: 3px;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n border: none !important;\n border-radius: 5px;\n opacity: 0.3;\n}\n\ncursor|cursor > div > img {\n border-radius: 5px;\n}\n\ncursor|cursor > div.active {\n opacity: 0.8;\n}\n\ncursor|cursor > div:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 43%;\n}\n\n\n.editInfoMarker {\n position: absolute;\n width: 10px;\n height: 100%;\n left: -20px;\n opacity: 0.8;\n top: 0;\n border-radius: 5px;\n background-color: transparent;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n}\n.editInfoMarker:hover {\n box-shadow: 0px 0px 8px rgba(0, 0, 0, 1);\n}\n\n.editInfoHandle {\n position: absolute;\n background-color: black;\n padding: 5px;\n border-radius: 5px;\n opacity: 0.8;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n bottom: 100%;\n margin-bottom: 10px;\n z-index: 3;\n left: -25px;\n}\n.editInfoHandle:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 5px;\n}\n.editInfo {\n font-family: sans-serif;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n color: white;\n width: 100%;\n height: 12pt;\n}\n.editInfoColor {\n float: left;\n width: 10pt;\n height: 10pt;\n border: 1px solid white;\n}\n.editInfoAuthor {\n float: left;\n margin-left: 5pt;\n font-size: 10pt;\n text-align: left;\n height: 12pt;\n line-height: 12pt;\n}\n.editInfoTime {\n float: right;\n margin-left: 30pt;\n font-size: 8pt;\n font-style: italic;\n color: yellow;\n height: 12pt;\n line-height: 12pt;\n}\n\n.annotationWrapper {\n display: inline;\n position: relative;\n}\n\n.annotationRemoveButton:before {\n content: '\u00d7';\n color: white;\n padding: 5px;\n line-height: 1em;\n}\n\n.annotationRemoveButton {\n width: 20px;\n height: 20px;\n border-radius: 10px;\n background-color: black;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n position: absolute;\n top: -10px;\n left: -10px;\n z-index: 3;\n text-align: center;\n font-family: sans-serif;\n font-style: normal;\n font-weight: normal;\n text-decoration: none;\n font-size: 15px;\n}\n.annotationRemoveButton:hover {\n cursor: pointer;\n box-shadow: 0px 0px 5px rgba(0, 0, 0, 1);\n}\n\n.annotationNote {\n width: 4cm;\n position: absolute;\n display: inline;\n z-index: 10;\n}\n.annotationNote > office|annotation {\n display: block;\n}\n\n.annotationConnector {\n position: absolute;\n display: inline;\n z-index: 2;\n border-top: 1px dashed brown;\n}\n.annotationConnector.angular {\n -moz-transform-origin: left top;\n -webkit-transform-origin: left top;\n -ms-transform-origin: left top;\n transform-origin: left top;\n}\n.annotationConnector.horizontal {\n left: 0;\n}\n.annotationConnector.horizontal:before {\n content: '';\n display: inline;\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: brown transparent transparent transparent;\n top: -1px;\n left: -5px;\n}\n\noffice|annotation {\n width: 100%;\n height: 100%;\n display: none;\n background: rgb(198, 238, 184);\n background: -moz-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -webkit-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -o-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -ms-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: linear-gradient(180deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n box-shadow: 0 3px 4px -3px #ccc;\n}\n\noffice|annotation > dc|creator {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n color: white;\n background-color: brown;\n padding: 4px;\n}\noffice|annotation > dc|date {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n border: 4px solid transparent;\n}\noffice|annotation > text|list {\n display: block;\n padding: 5px;\n}\n\n/* This is very temporary CSS. This must go once\n * we start bundling webodf-default ODF styles for annotations.\n */\noffice|annotation text|p {\n font-size: 10pt;\n color: black;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n font-family: sans-serif;\n}\n\ndc|*::selection {\n background: transparent;\n}\ndc|*::-moz-selection {\n background: transparent;\n}\n\n#annotationsPane {\n background-color: #EAEAEA;\n width: 4cm;\n height: 100%;\n display: inline-block;\n position: absolute;\n outline: 1px solid #ccc;\n}\n\n.annotationHighlight {\n background-color: yellow;\n position: relative;\n}\n"; +ops.Session=function(n){var m=new ops.OperationFactory,l=new ops.OdtDocument(n),d=new ops.TrivialMemberModel,b=null;this.setMemberModel=function(b){d=b};this.setOperationFactory=function(d){m=d;b&&b.setOperationFactory(m)};this.setOperationRouter=function(d){b=d;d.setPlaybackFunction(function(a){a.execute(l);l.emit(ops.OdtDocument.signalOperationExecuted,a)});d.setOperationFactory(m)};this.getOperationRouter=function(){return b};this.getMemberModel=function(){return d};this.getOperationFactory=function(){return m}; +this.getOdtDocument=function(){return l};this.enqueue=function(d){b.push(d)};this.close=function(b){l.close(function(a){a?b(a):b()})};this.setOperationRouter(new ops.TrivialOperationRouter)}; +// Input 81 +var webodf_css="@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n@namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n@namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n@namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n@namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n@namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n@namespace table url(urn:oasis:names:tc:opendocument:xmlns:table:1.0);\n@namespace text url(urn:oasis:names:tc:opendocument:xmlns:text:1.0);\n@namespace runtimens url(urn:webodf); /* namespace for runtime only */\n@namespace cursor url(urn:webodf:names:cursor);\n@namespace editinfo url(urn:webodf:names:editinfo);\n@namespace annotation url(urn:webodf:names:annotation);\n@namespace dc url(http://purl.org/dc/elements/1.1/);\n\noffice|document > *, office|document-content > * {\n display: none;\n}\noffice|body, office|document {\n display: inline-block;\n position: relative;\n}\n\ntext|p, text|h {\n display: block;\n padding: 0;\n margin: 0;\n line-height: normal;\n position: relative;\n min-height: 1.3em; /* prevent empty paragraphs and headings from collapsing if they are empty */\n}\n*[runtimens|containsparagraphanchor] {\n position: relative;\n}\ntext|s {\n white-space: pre;\n}\ntext|tab {\n display: inline;\n white-space: pre;\n}\ntext|line-break {\n content: \" \";\n display: block;\n}\ntext|tracked-changes {\n /*Consumers that do not support change tracking, should ignore changes.*/\n display: none;\n}\noffice|binary-data {\n display: none;\n}\noffice|text {\n display: block;\n text-align: left;\n overflow: visible;\n word-wrap: break-word;\n}\n\noffice|text::selection {\n /** Let's not draw selection highlight that overflows into the office|text\n * node when selecting content across several paragraphs\n */\n background: transparent;\n}\noffice|text * draw|text-box {\n /** only for text documents */\n display: block;\n border: 1px solid #d3d3d3;\n}\noffice|spreadsheet {\n display: block;\n border-collapse: collapse;\n empty-cells: show;\n font-family: sans-serif;\n font-size: 10pt;\n text-align: left;\n page-break-inside: avoid;\n overflow: hidden;\n}\noffice|presentation {\n display: inline-block;\n text-align: left;\n}\n#shadowContent {\n display: inline-block;\n text-align: left;\n}\ndraw|page {\n display: block;\n position: relative;\n overflow: hidden;\n}\npresentation|notes, presentation|footer-decl, presentation|date-time-decl {\n display: none;\n}\n@media print {\n draw|page {\n border: 1pt solid black;\n page-break-inside: avoid;\n }\n presentation|notes {\n /*TODO*/\n }\n}\noffice|spreadsheet text|p {\n border: 0px;\n padding: 1px;\n margin: 0px;\n}\noffice|spreadsheet table|table {\n margin: 3px;\n}\noffice|spreadsheet table|table:after {\n /* show sheet name the end of the sheet */\n /*content: attr(table|name);*/ /* gives parsing error in opera */\n}\noffice|spreadsheet table|table-row {\n counter-increment: row;\n}\noffice|spreadsheet table|table-row:before {\n width: 3em;\n background: #cccccc;\n border: 1px solid black;\n text-align: center;\n content: counter(row);\n display: table-cell;\n}\noffice|spreadsheet table|table-cell {\n border: 1px solid #cccccc;\n}\ntable|table {\n display: table;\n}\ndraw|frame table|table {\n width: 100%;\n height: 100%;\n background: white;\n}\ntable|table-header-rows {\n display: table-header-group;\n}\ntable|table-row {\n display: table-row;\n}\ntable|table-column {\n display: table-column;\n}\ntable|table-cell {\n width: 0.889in;\n display: table-cell;\n word-break: break-all; /* prevent long words from extending out the table cell */\n}\ndraw|frame {\n display: block;\n}\ndraw|image {\n display: block;\n width: 100%;\n height: 100%;\n top: 0px;\n left: 0px;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n -moz-background-size: 100% 100%;\n}\n/* only show the first image in frame */\ndraw|frame > draw|image:nth-of-type(n+2) {\n display: none;\n}\ntext|list:before {\n display: none;\n content:\"\";\n}\ntext|list {\n counter-reset: list;\n}\ntext|list-item {\n display: block;\n}\ntext|number {\n display:none;\n}\n\ntext|a {\n color: blue;\n text-decoration: underline;\n cursor: pointer;\n}\ntext|note-citation {\n vertical-align: super;\n font-size: smaller;\n}\ntext|note-body {\n display: none;\n}\ntext|note:hover text|note-citation {\n background: #dddddd;\n}\ntext|note:hover text|note-body {\n display: block;\n left:1em;\n max-width: 80%;\n position: absolute;\n background: #ffffaa;\n}\nsvg|title, svg|desc {\n display: none;\n}\nvideo {\n width: 100%;\n height: 100%\n}\n\n/* below set up the cursor */\ncursor|cursor {\n display: inline;\n width: 0px;\n height: 1em;\n /* making the position relative enables the avatar to use\n the cursor as reference for its absolute position */\n position: relative;\n z-index: 1;\n}\ncursor|cursor > span {\n display: inline;\n position: absolute;\n top: 5%; /* push down the caret; 0px can do the job, 5% looks better, 10% is a bit over */\n height: 1em;\n border-left: 2px solid black;\n outline: none;\n}\n\ncursor|cursor > div {\n padding: 3px;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n border: none !important;\n border-radius: 5px;\n opacity: 0.3;\n}\n\ncursor|cursor > div > img {\n border-radius: 5px;\n}\n\ncursor|cursor > div.active {\n opacity: 0.8;\n}\n\ncursor|cursor > div:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 43%;\n}\n\n\n.editInfoMarker {\n position: absolute;\n width: 10px;\n height: 100%;\n left: -20px;\n opacity: 0.8;\n top: 0;\n border-radius: 5px;\n background-color: transparent;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n}\n.editInfoMarker:hover {\n box-shadow: 0px 0px 8px rgba(0, 0, 0, 1);\n}\n\n.editInfoHandle {\n position: absolute;\n background-color: black;\n padding: 5px;\n border-radius: 5px;\n opacity: 0.8;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n bottom: 100%;\n margin-bottom: 10px;\n z-index: 3;\n left: -25px;\n}\n.editInfoHandle:after {\n content: ' ';\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: black transparent transparent transparent;\n\n top: 100%;\n left: 5px;\n}\n.editInfo {\n font-family: sans-serif;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n color: white;\n width: 100%;\n height: 12pt;\n}\n.editInfoColor {\n float: left;\n width: 10pt;\n height: 10pt;\n border: 1px solid white;\n}\n.editInfoAuthor {\n float: left;\n margin-left: 5pt;\n font-size: 10pt;\n text-align: left;\n height: 12pt;\n line-height: 12pt;\n}\n.editInfoTime {\n float: right;\n margin-left: 30pt;\n font-size: 8pt;\n font-style: italic;\n color: yellow;\n height: 12pt;\n line-height: 12pt;\n}\n\n.annotationWrapper {\n display: inline;\n position: relative;\n}\n\n.annotationRemoveButton:before {\n content: '\u00d7';\n color: white;\n padding: 5px;\n line-height: 1em;\n}\n\n.annotationRemoveButton {\n width: 20px;\n height: 20px;\n border-radius: 10px;\n background-color: black;\n box-shadow: 0px 0px 5px rgba(50, 50, 50, 0.75);\n position: absolute;\n top: -10px;\n left: -10px;\n z-index: 3;\n text-align: center;\n font-family: sans-serif;\n font-style: normal;\n font-weight: normal;\n text-decoration: none;\n font-size: 15px;\n}\n.annotationRemoveButton:hover {\n cursor: pointer;\n box-shadow: 0px 0px 5px rgba(0, 0, 0, 1);\n}\n\n.annotationNote {\n width: 4cm;\n position: absolute;\n display: inline;\n z-index: 10;\n}\n.annotationNote > office|annotation {\n display: block;\n}\n\n.annotationConnector {\n position: absolute;\n display: inline;\n z-index: 2;\n border-top: 1px dashed brown;\n}\n.annotationConnector.angular {\n -moz-transform-origin: left top;\n -webkit-transform-origin: left top;\n -ms-transform-origin: left top;\n transform-origin: left top;\n}\n.annotationConnector.horizontal {\n left: 0;\n}\n.annotationConnector.horizontal:before {\n content: '';\n display: inline;\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n border-width: 8.7px 5px 0 5px;\n border-color: brown transparent transparent transparent;\n top: -1px;\n left: -5px;\n}\n\noffice|annotation {\n width: 100%;\n height: 100%;\n display: none;\n background: rgb(198, 238, 184);\n background: -moz-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -webkit-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -o-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: -ms-linear-gradient(90deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n background: linear-gradient(180deg, rgb(198, 238, 184) 30%, rgb(180, 196, 159) 100%);\n box-shadow: 0 3px 4px -3px #ccc;\n}\n\noffice|annotation > dc|creator {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n color: white;\n background-color: brown;\n padding: 4px;\n}\noffice|annotation > dc|date {\n display: block;\n font-size: 10pt;\n font-weight: normal;\n font-style: normal;\n font-family: sans-serif;\n border: 4px solid transparent;\n}\noffice|annotation > text|list {\n display: block;\n padding: 5px;\n}\n\n/* This is very temporary CSS. This must go once\n * we start bundling webodf-default ODF styles for annotations.\n */\noffice|annotation text|p {\n font-size: 10pt;\n color: black;\n font-weight: normal;\n font-style: normal;\n text-decoration: none;\n font-family: sans-serif;\n}\n\ndc|*::selection {\n background: transparent;\n}\ndc|*::-moz-selection {\n background: transparent;\n}\n\n#annotationsPane {\n background-color: #EAEAEA;\n width: 4cm;\n height: 100%;\n display: none;\n position: absolute;\n outline: 1px solid #ccc;\n}\n\n.annotationHighlight {\n background-color: yellow;\n position: relative;\n}\n";