First take on proper destruction of WebODF Editor instance

pull/1/head
Friedrich W. H. Kossebau 11 years ago
parent 9c0a0c854a
commit 8527506d90

@ -1,5 +1,3 @@
@namespace text url(urn:oasis:names:tc:opendocument:xmlns:text:1.0);
html, body, #mainContainer { html, body, #mainContainer {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -25,12 +23,6 @@ html, body, #mainContainer {
z-index: 4; z-index: 4;
} }
#menubar {
border: none;
overflow: hidden;
background-color: #E6E6E7;
}
#toolbar { #toolbar {
overflow: hidden; overflow: hidden;
} }
@ -169,28 +161,6 @@ div.memberListLabel[fullname]:before {
opacity: 0.9; opacity: 0.9;
} }
#chat {
padding: 0px;
text-align: center;
position: relative;
}
#chat > #inputArea {
padding-top: 3px;
padding-bottom: 3px;
width: 100%;
background-color: #eee;
position: absolute;
bottom: 0px;
}
#inputArea > #widget_chatInput {
width: 95%;
border-radius: 10px;
padding: 3px;
box-shadow: inset 0 0 1px #888;
}
.dijitDialog { .dijitDialog {
border: none !important; border: none !important;
box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important; box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important;

@ -79,7 +79,7 @@ var documentsMain = {
documentsMain.webodfEditorInstance = new Editor({}, documentsMain.webodfServerInstance, serverFactory); documentsMain.webodfEditorInstance = new Editor({}, documentsMain.webodfServerInstance, serverFactory);
// load the document and get called back when it's live // load the document and get called back when it's live
documentsMain.webodfEditorInstance.loadSession(response.es_id, memberId, function() { documentsMain.webodfEditorInstance.openSession(response.es_id, memberId, function() {
documentsMain.webodfEditorInstance.startEditing(); documentsMain.webodfEditorInstance.startEditing();
}); });
}); });
@ -150,21 +150,23 @@ var documentsMain = {
//close editor //close editor
documentsMain.webodfEditorInstance.endEditing(); documentsMain.webodfEditorInstance.endEditing();
documentsMain.webodfEditorInstance.closeDocument(function() { documentsMain.webodfEditorInstance.close(function() {
// successfull shutdown - all is good. // successfull shutdown - all is good.
// TODO: proper session leaving call to server, either by webodfServerInstance or custom // TODO: proper session leaving call to server, either by webodfServerInstance or custom
// documentsMain.webodfServerInstance.leaveSession(sessionId, memberId, function() { // documentsMain.webodfServerInstance.leaveSession(sessionId, memberId, function() {
documentsMain.webodfEditorInstance.destroy(function() {
// Fade out odf-toolbar // Fade out odf-toolbar
$('#odf-toolbar').fadeOut('slow'); $('#odf-toolbar').fadeOut('slow');
// Fade out editor // Fade out editor
$('#mainContainer').fadeOut('slow', function() { $('#mainContainer').fadeOut('slow', function() {
$('#mainContainer').remove(); $('#mainContainer').remove();
$('#odf-canvas').remove(); $('#odf-toolbar').remove();
$('.actions,#file_access_panel').fadeIn('slow'); $('.actions,#file_access_panel').fadeIn('slow');
$('.documentslist, #emptyfolder').fadeIn('slow'); $('.documentslist, #emptyfolder').fadeIn('slow');
$(document.body).removeClass('claro'); $(document.body).removeClass('claro');
}); });
});
// }); // });
}); });
}, },

@ -1,4 +1,5 @@
/** /**
* @license
* Copyright (C) 2013 KO GmbH <copyright@kogmbh.com> * Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
* *
* @licstart * @licstart
@ -31,6 +32,7 @@
* @source: http://www.webodf.org/ * @source: http://www.webodf.org/
* @source: http://gitorious.org/webodf/webodf/ * @source: http://gitorious.org/webodf/webodf/
*/ */
/*global runtime, define, document, odf, ops, window, gui, alert, saveAs, Blob */ /*global runtime, define, document, odf, ops, window, gui, alert, saveAs, Blob */
define("webodf/editor/Editor", [ define("webodf/editor/Editor", [
@ -66,6 +68,7 @@ define("webodf/editor/Editor", [
// Private // Private
session, session,
editorSession, editorSession,
mainContainer,
memberListView, memberListView,
toolbarTools, toolbarTools,
loadOdtFile = args.loadCallback, loadOdtFile = args.loadCallback,
@ -112,7 +115,7 @@ define("webodf/editor/Editor", [
/** /**
* create the editor, load the starting document, * open the document,
* call editorReadyCallback once everything is done. * call editorReadyCallback once everything is done.
* *
* @param {!string} docUrl * @param {!string} docUrl
@ -120,7 +123,7 @@ define("webodf/editor/Editor", [
* @param {!function()} editorReadyCallback * @param {!function()} editorReadyCallback
* @return {undefined} * @return {undefined}
*/ */
this.loadDocument = function (docUrl, memberId, editorReadyCallback) { this.openDocument = function (docUrl, memberId, editorReadyCallback) {
initDocLoading(docUrl, memberId, editorReadyCallback); initDocLoading(docUrl, memberId, editorReadyCallback);
}; };
@ -151,8 +154,8 @@ define("webodf/editor/Editor", [
}; };
/** /**
* create the editor, load the starting document of an * open the initial document of an editing-session,
* editing-session, request a replay of previous operations, call * request a replay of previous operations, call
* editorReadyCallback once everything is done. * editorReadyCallback once everything is done.
* *
* @param {!string} sessionId * @param {!string} sessionId
@ -160,7 +163,7 @@ define("webodf/editor/Editor", [
* @param {!function()} editorReadyCallback * @param {!function()} editorReadyCallback
* @return {undefined} * @return {undefined}
*/ */
this.loadSession = function (sessionId, memberId, editorReadyCallback) { this.openSession = function (sessionId, memberId, editorReadyCallback) {
initDocLoading(server.getGenesisUrl(sessionId), memberId, function () { initDocLoading(server.getGenesisUrl(sessionId), memberId, function () {
var opRouter, memberModel; var opRouter, memberModel;
// overwrite router and member model // overwrite router and member model
@ -185,26 +188,27 @@ define("webodf/editor/Editor", [
* @param {!function(!Object=)} callback, passing an error object in case of error * @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined} * @return {undefined}
*/ */
this.closeDocument = function (callback) { this.close = function (callback) {
runtime.assert(session, "session should exist here."); runtime.assert(session, "session should exist here.");
if (memberListView) {
memberListView.setEditorSession(undefined);
}
// TODO: there is a better pattern for this instead of unrolling // TODO: there is a better pattern for this instead of unrolling
session.getOperationRouter().close(function(err) { editorSession.close(function(err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
session.getMemberModel().close(function(err) { session.close(function(err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
editorSession.close(function(err) { // now also destroy session, will not be reused for new document
if (memberListView) {
memberListView.setEditorSession(undefined);
}
editorSession.destroy(function(err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
editorSession = undefined; editorSession = undefined;
session.close(function(err) { session.destroy(function(err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
@ -245,10 +249,45 @@ define("webodf/editor/Editor", [
editorSession.sessionController.endEditing(); editorSession.sessionController.endEditing();
}; };
/**
* @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined}
*/
this.destroy = function (callback) {
var destroyMemberListView = memberListView ? memberListView.destroy : function(cb) { cb(); };
// TODO: decide if some forced close should be done here instead of enforcing proper API usage
runtime.assert(!session, "session should not exist here.");
// TODO: investigate what else needs to be done
mainContainer.destroyRecursive(true);
destroyMemberListView(function(err) {
if (err) {
callback(err);
} else {
toolbarTools.destroy(function(err) {
if (err) {
callback(err);
} else {
odfCanvas.destroy(function(err) {
if (err) {
callback(err);
} else {
document.translator = null;
document.translateContent = null;
callback();
}
});
}
});
}
});
};
// init // init
function init() { function init() {
var mainContainer, var editorPane, memberListPane,
editorPane, memberListPane,
inviteButton, inviteButton,
canvasElement = document.getElementById("canvas"), canvasElement = document.getElementById("canvas"),
memberListElement = document.getElementById('memberList'), memberListElement = document.getElementById('memberList'),
@ -317,11 +356,10 @@ define("webodf/editor/Editor", [
if (window.inviteButtonProxy) { if (window.inviteButtonProxy) {
inviteButton = document.getElementById('inviteButton'); inviteButton = document.getElementById('inviteButton');
if (inviteButton) { runtime.assert(inviteButton, 'missing "inviteButton" div in HTML');
inviteButton.innerText = translator("inviteMembers"); inviteButton.innerText = translator("inviteMembers");
inviteButton.style.display = "block"; inviteButton.style.display = "block";
inviteButton.onclick = window.inviteButtonProxy.clicked; inviteButton.onclick = window.inviteButtonProxy.clicked;
}
} }
toolbarTools = new ToolBarTools({ toolbarTools = new ToolBarTools({

@ -32,7 +32,9 @@
* @source: http://www.webodf.org/ * @source: http://www.webodf.org/
* @source: http://gitorious.org/webodf/webodf/ * @source: http://gitorious.org/webodf/webodf/
*/ */
/*global define, runtime, core, gui, ops, document */ /*global define, runtime, core, gui, ops, document */
define("webodf/editor/EditorSession", [ define("webodf/editor/EditorSession", [
"dojo/text!resources/fonts/fonts.css" "dojo/text!resources/fonts/fonts.css"
], function (fontsCSS) { // fontsCSS is retrieved as a string, using dojo's text retrieval AMD plugin ], function (fontsCSS) { // fontsCSS is retrieved as a string, using dojo's text retrieval AMD plugin
@ -65,8 +67,10 @@ define("webodf/editor/EditorSession", [
currentParagraphNode = null, currentParagraphNode = null,
currentNamedStyleName = null, currentNamedStyleName = null,
currentStyleName = null, currentStyleName = null,
caretManager,
odtDocument = session.getOdtDocument(), odtDocument = session.getOdtDocument(),
textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0", textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
fontStyles = document.createElement('style'),
formatting = odtDocument.getFormatting(), formatting = odtDocument.getFormatting(),
styleHelper = new gui.StyleHelper(formatting), styleHelper = new gui.StyleHelper(formatting),
eventNotifier = new core.EventNotifier([ eventNotifier = new core.EventNotifier([
@ -81,7 +85,8 @@ define("webodf/editor/EditorSession", [
this.sessionController = new gui.SessionController(session, localMemberId); this.sessionController = new gui.SessionController(session, localMemberId);
this.sessionView = new gui.SessionView(config.viewOptions, session, new gui.CaretManager(self.sessionController)); caretManager = new gui.CaretManager(self.sessionController);
this.sessionView = new gui.SessionView(config.viewOptions, session, caretManager);
this.availableFonts = []; this.availableFonts = [];
/* /*
@ -194,36 +199,34 @@ define("webodf/editor/EditorSession", [
checkParagraphStyleName(); checkParagraphStyleName();
} }
// Custom signals, that make sense in the Editor context. We do not want to expose webodf's ops signals to random bits of the editor UI. function onCursorAdded(cursor) {
odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, function (cursor) {
self.emit(EditorSession.signalMemberAdded, cursor.getMemberId()); self.emit(EditorSession.signalMemberAdded, cursor.getMemberId());
trackCursor(cursor); trackCursor(cursor);
}); }
odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, function (memberId) { function onCursorRemoved(memberId) {
self.emit(EditorSession.signalMemberRemoved, memberId); self.emit(EditorSession.signalMemberRemoved, memberId);
}); }
odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, function (cursor) { function onCursorMoved(cursor) {
// Emit 'cursorMoved' only when *I* am moving the cursor, not the other users // Emit 'cursorMoved' only when *I* am moving the cursor, not the other users
if (cursor.getMemberId() === localMemberId) { if (cursor.getMemberId() === localMemberId) {
self.emit(EditorSession.signalCursorMoved, cursor); self.emit(EditorSession.signalCursorMoved, cursor);
trackCursor(cursor);
} }
}); }
odtDocument.subscribe(ops.OdtDocument.signalStyleCreated, function (newStyleName) { function onStyleCreated(newStyleName) {
self.emit(EditorSession.signalStyleCreated, newStyleName); self.emit(EditorSession.signalStyleCreated, newStyleName);
}); }
odtDocument.subscribe(ops.OdtDocument.signalStyleDeleted, function (styleName) { function onStyleDeleted(styleName) {
self.emit(EditorSession.signalStyleDeleted, styleName); self.emit(EditorSession.signalStyleDeleted, styleName);
}); }
odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, function (styleName) { function onParagraphStyleModified(styleName) {
self.emit(EditorSession.signalParagraphStyleModified, styleName); self.emit(EditorSession.signalParagraphStyleModified, styleName);
}); }
odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, trackCurrentParagraph);
/** /**
* Call all subscribers for the given event with the specified argument * Call all subscribers for the given event with the specified argument
@ -527,24 +530,64 @@ define("webodf/editor/EditorSession", [
undoManager.moveForward(1); undoManager.moveForward(1);
}; };
this.subscribe(EditorSession.signalCursorMoved, trackCursor); /**
* @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined}
*/
this.close = function (callback) {
callback();
/*
self.sessionView.close(function(err) {
if (err) {
callback(err);
} else {
caretManager.close(function(err) {
if (err) {
callback(err);
} else {
self.sessionController.close(callback);
}
});
}
});
*/
};
/** /**
* @param {!function(!Object=)} callback, passing an error object in case of error * @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined} * @return {undefined}
*/ */
this.close = function(callback) { this.destroy = function(callback) {
self.sessionController.close(function(err) { var head = document.getElementsByTagName('head')[0];
head.removeChild(fontStyles);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
odtDocument.unsubscribe(ops.OdtDocument.signalStyleCreated, onStyleCreated);
odtDocument.unsubscribe(ops.OdtDocument.signalStyleDeleted, onStyleDeleted);
odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, trackCurrentParagraph);
odtDocument.unsubscribe(ops.OdtDocument.signalUndoStackChanged, undoStackModified);
self.sessionView.destroy(function(err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
delete self.sessionController; delete self.sessionView;
self.sessionView.close(function(err) { caretManager.destroy(function(err) {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
delete self.sessionView; self.sessionController.destroy(function(err) {
callback(); if (err) {
callback(err);
} else {
delete self.sessionController;
callback();
}
});
} }
}); });
} }
@ -552,12 +595,22 @@ define("webodf/editor/EditorSession", [
}; };
function init() { function init() {
var head = document.getElementsByTagName('head')[0], var head = document.getElementsByTagName('head')[0];
fontStyles = document.createElement('style');
// TODO: fonts.css should be rather done by odfCanvas, or?
fontStyles.type = 'text/css'; fontStyles.type = 'text/css';
fontStyles.media = 'screen, print, handheld, projection'; fontStyles.media = 'screen, print, handheld, projection';
fontStyles.appendChild(document.createTextNode(fontsCSS)); fontStyles.appendChild(document.createTextNode(fontsCSS));
head.appendChild(fontStyles); head.appendChild(fontStyles);
// Custom signals, that make sense in the Editor context. We do not want to expose webodf's ops signals to random bits of the editor UI.
odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
odtDocument.subscribe(ops.OdtDocument.signalStyleCreated, onStyleCreated);
odtDocument.subscribe(ops.OdtDocument.signalStyleDeleted, onStyleDeleted);
odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, trackCurrentParagraph);
odtDocument.subscribe(ops.OdtDocument.signalUndoStackChanged, undoStackModified); odtDocument.subscribe(ops.OdtDocument.signalUndoStackChanged, undoStackModified);
} }

@ -152,17 +152,17 @@ define("webodf/editor/MemberListView",
function removeMember(memberId) { function removeMember(memberId) {
editorSession.unsubscribeMemberDetailsUpdates(memberId, updateAvatarButton); editorSession.unsubscribeMemberDetailsUpdates(memberId, updateAvatarButton);
removeAvatarButton(memberId); removeAvatarButton(memberId);
}; }
/** function disconnectFromEditorSession() {
* @param {!EditorSession} session var node, nextNode;
* @return {undefined}
*/
this.setEditorSession = function(session) {
var node = memberListDiv.firstChild, nextNode;
if (editorSession) { if (editorSession) {
// unsubscribe from editorSession
editorSession.unsubscribe(EditorSession.signalMemberAdded, addMember);
editorSession.unsubscribe(EditorSession.signalMemberRemoved, removeMember);
// remove all current avatars // remove all current avatars
node = memberListDiv.firstChild;
while (node) { while (node) {
nextNode = node.nextSibling; nextNode = node.nextSibling;
if (node.memberId) { if (node.memberId) {
@ -171,15 +171,30 @@ define("webodf/editor/MemberListView",
memberListDiv.removeChild(node); memberListDiv.removeChild(node);
node = nextNode; node = nextNode;
} }
// unsubscribe from old editorSession
editorSession.unsubscribe(EditorSession.signalMemberAdded, addMember);
editorSession.unsubscribe(EditorSession.signalMemberRemoved, removeMember);
} }
}
/**
* @param {!EditorSession} session
* @return {undefined}
*/
this.setEditorSession = function(session) {
disconnectFromEditorSession();
editorSession = session; editorSession = session;
if (editorSession) { if (editorSession) {
editorSession.subscribe(EditorSession.signalMemberAdded, addMember); editorSession.subscribe(EditorSession.signalMemberAdded, addMember);
editorSession.subscribe(EditorSession.signalMemberRemoved, removeMember); editorSession.subscribe(EditorSession.signalMemberRemoved, removeMember);
} }
}; };
/**
* @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined}
*/
this.destroy = function (callback) {
disconnectFromEditorSession();
callback();
};
}; };
}); });

@ -49,9 +49,10 @@ ServerFactory.prototype.createServer = function () {"use strict"; };
* @param {!string} sessionId * @param {!string} sessionId
* @param {!string} memberId * @param {!string} memberId
* @param {!ops.Server} server * @param {!ops.Server} server
* @param {!odf.OdfContainer} odfContainer TODO: needed for pullbox writing to server at end, find better solution
* @return {!ops.OperationRouter} * @return {!ops.OperationRouter}
*/ */
ServerFactory.prototype.createOperationRouter = function (sessionId, memberId, server) {"use strict"; }; ServerFactory.prototype.createOperationRouter = function (sessionId, memberId, server, odfContainer) {"use strict"; };
/** /**
* @param {!string} sessionId * @param {!string} sessionId

@ -81,6 +81,16 @@ define("webodf/editor/widgets", [
} }
}; };
/**
* @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined}
*/
this.destroy = function (callback) {
// TODO: investigate what else needs to be done
toolbar.destroyRecursive(true);
callback();
};
// init // init
ready(function () { ready(function () {
toolbar = new Toolbar({}, "toolbar"); toolbar = new Toolbar({}, "toolbar");

@ -8479,7 +8479,11 @@ odf.OdfCanvas = function() {
updateCSS() updateCSS()
} }
}; };
this.css = css this.css = css;
this.destroy = function(callback) {
css.parentNode.removeChild(css);
callback()
}
} }
function listenEvent(eventTarget, eventType, eventHandler) { function listenEvent(eventTarget, eventType, eventHandler) {
if(eventTarget.addEventListener) { if(eventTarget.addEventListener) {
@ -8493,6 +8497,20 @@ odf.OdfCanvas = function() {
} }
} }
} }
function removeEvent(eventTarget, eventType, eventHandler) {
var onVariant = "on" + eventType;
if(eventTarget.removeEventListener) {
eventTarget.removeEventListener(eventType, eventHandler, false)
}else {
if(eventTarget.detachEvent) {
eventTarget.detachEvent(onVariant, eventHandler)
}else {
if(eventTarget[onVariant] === eventHandler) {
eventTarget[onVariant] = null
}
}
}
}
function SelectionWatcher(element) { function SelectionWatcher(element) {
var selection = [], listeners = []; var selection = [], listeners = [];
function isAncestorOf(ancestor, descendant) { function isAncestorOf(ancestor, descendant) {
@ -8568,12 +8586,17 @@ odf.OdfCanvas = function() {
} }
listeners.push(handler) listeners.push(handler)
}; };
this.destroy = function(callback) {
removeEvent(element, "mouseup", checkSelection);
removeEvent(element, "keyup", checkSelection);
removeEvent(element, "keydown", checkSelection);
callback()
};
listenEvent(element, "mouseup", checkSelection); listenEvent(element, "mouseup", checkSelection);
listenEvent(element, "keyup", checkSelection); listenEvent(element, "keyup", checkSelection);
listenEvent(element, "keydown", 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, sizer, 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;
false, annotationManager;
function clear(element) { function clear(element) {
while(element.firstChild) { while(element.firstChild) {
element.removeChild(element.firstChild) element.removeChild(element.firstChild)
@ -8725,17 +8748,6 @@ odf.OdfCanvas = function() {
modifyTableCell(node) modifyTableCell(node)
} }
} }
function modifyAnnotations(odffragment) {
var annotationNodes = domUtils.getElementsByTagNameNS(odffragment, officens, "annotation"), annotationEnds = domUtils.getElementsByTagNameNS(odffragment, officens, "annotation-end"), currentAnnotationName, i;
function matchAnnotationEnd(element) {
return currentAnnotationName === element.getAttributeNS(officens, "name")
}
for(i = 0;i < annotationNodes.length;i += 1) {
currentAnnotationName = annotationNodes[i].getAttributeNS(officens, "name");
annotationManager.addAnnotation({node:annotationNodes[i], end:annotationEnds.filter(matchAnnotationEnd)[0] || null})
}
annotationManager.rerenderAnnotations()
}
function modifyLinks(odffragment) { function modifyLinks(odffragment) {
var i, links, node; var i, links, node;
function modifyLink(node) { function modifyLink(node) {
@ -8984,12 +8996,7 @@ odf.OdfCanvas = function() {
odf.OdfCanvas = function OdfCanvas(element) { odf.OdfCanvas = function OdfCanvas(element) {
runtime.assert(element !== null && element !== undefined, "odf.OdfCanvas constructor needs DOM element"); runtime.assert(element !== null && element !== undefined, "odf.OdfCanvas constructor needs DOM element");
runtime.assert(element.ownerDocument !== null && element.ownerDocument !== undefined, "odf.OdfCanvas constructor needs DOM"); runtime.assert(element.ownerDocument !== null && element.ownerDocument !== undefined, "odf.OdfCanvas constructor needs DOM");
var self = this, doc = (element.ownerDocument), odfcontainer, formatting = new odf.Formatting, selectionWatcher = new SelectionWatcher(element), pageSwitcher, fontcss, stylesxmlcss, positioncss, editable = false, zoomLevel = 1, eventHandlers = {}, editparagraph, loadingQueue = new LoadingQueue; var self = this, doc = (element.ownerDocument), odfcontainer, formatting = new odf.Formatting, selectionWatcher = new SelectionWatcher(element), pageSwitcher, sizer, annotationsPane, allowAnnotations = false, annotationManager, webodfcss, fontcss, stylesxmlcss, positioncss, editable = false, zoomLevel = 1, eventHandlers = {}, editparagraph, loadingQueue = new LoadingQueue;
addWebODFStyleSheet(doc);
pageSwitcher = new PageSwitcher(addStyleSheet(doc));
fontcss = addStyleSheet(doc);
stylesxmlcss = addStyleSheet(doc);
positioncss = addStyleSheet(doc);
function loadImages(container, odffragment, stylesheet) { function loadImages(container, odffragment, stylesheet) {
var i, images, node; var i, images, node;
function loadImage(name, container, node, stylesheet) { function loadImage(name, container, node, stylesheet) {
@ -9084,6 +9091,17 @@ odf.OdfCanvas = function() {
sizer.insertBefore(shadowContent, sizer.firstChild); sizer.insertBefore(shadowContent, sizer.firstChild);
fixContainerSize() fixContainerSize()
} }
function modifyAnnotations(odffragment) {
var annotationNodes = domUtils.getElementsByTagNameNS(odffragment, officens, "annotation"), annotationEnds = domUtils.getElementsByTagNameNS(odffragment, officens, "annotation-end"), currentAnnotationName, i;
function matchAnnotationEnd(element) {
return currentAnnotationName === element.getAttributeNS(officens, "name")
}
for(i = 0;i < annotationNodes.length;i += 1) {
currentAnnotationName = annotationNodes[i].getAttributeNS(officens, "name");
annotationManager.addAnnotation({node:annotationNodes[i], end:annotationEnds.filter(matchAnnotationEnd)[0] || null})
}
annotationManager.rerenderAnnotations()
}
function handleAnnotations(odfnode) { function handleAnnotations(odfnode) {
if(allowAnnotations) { if(allowAnnotations) {
if(!annotationsPane.parentNode) { if(!annotationsPane.parentNode) {
@ -9328,7 +9346,33 @@ odf.OdfCanvas = function() {
}; };
this.getElement = function() { this.getElement = function() {
return element return element
};
this.destroy = function(callback) {
var head = doc.getElementsByTagName("head")[0];
if(annotationsPane.parentNode) {
annotationsPane.parentNode.removeChild(annotationsPane)
}
element.removeChild(sizer);
head.removeChild(webodfcss);
head.removeChild(fontcss);
head.removeChild(stylesxmlcss);
head.removeChild(positioncss);
selectionWatcher.destroy(function(err) {
if(err) {
callback(err)
}else {
pageSwitcher.destroy(callback)
}
})
};
function init() {
webodfcss = addWebODFStyleSheet(doc);
pageSwitcher = new PageSwitcher(addStyleSheet(doc));
fontcss = addStyleSheet(doc);
stylesxmlcss = addStyleSheet(doc);
positioncss = addStyleSheet(doc)
} }
init()
}; };
return odf.OdfCanvas return odf.OdfCanvas
}(); }();
@ -11916,6 +11960,10 @@ ops.EditInfo = function EditInfo(container, odtDocument) {
this.clearEdits = function() { this.clearEdits = function() {
editHistory = {} editHistory = {}
}; };
this.destroy = function(callback) {
container.removeChild(editInfoNode);
callback()
};
function init() { function init() {
var editInfons = "urn:webodf:names:editinfo", dom = odtDocument.getDOM(); var editInfons = "urn:webodf:names:editinfo", dom = odtDocument.getDOM();
editInfoNode = dom.createElementNS(editInfons, "editinfo"); editInfoNode = dom.createElementNS(editInfons, "editinfo");
@ -11951,6 +11999,10 @@ gui.Avatar = function Avatar(parentElement, avatarInitiallyVisible) {
this.markAsFocussed = function(isFocussed) { this.markAsFocussed = function(isFocussed) {
handle.className = isFocussed ? "active" : "" handle.className = isFocussed ? "active" : ""
}; };
this.destroy = function(callback) {
parentElement.removeChild(handle);
callback()
};
function init() { function init() {
var document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI; var document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI;
handle = document.createElementNS(htmlns, "div"); handle = document.createElementNS(htmlns, "div");
@ -12056,6 +12108,16 @@ gui.Caret = function Caret(cursor, avatarInitiallyVisible, blinkOnRangeSelect) {
} }
} }
}; };
this.destroy = function(callback) {
avatar.destroy(function(err) {
if(err) {
callback(err)
}else {
cursorNode.removeChild(span);
callback()
}
})
};
function init() { function init() {
var dom = cursor.getOdtDocument().getDOM(), htmlns = dom.documentElement.namespaceURI; var dom = cursor.getOdtDocument().getDOM(), htmlns = dom.documentElement.namespaceURI;
span = dom.createElementNS(htmlns, "span"); span = dom.createElementNS(htmlns, "span");
@ -12925,7 +12987,7 @@ gui.SessionController = function() {
this.getUndoManager = function() { this.getUndoManager = function() {
return undoManager return undoManager
}; };
this.close = function(callback) { this.destroy = function(callback) {
callback() callback()
}; };
function init() { function init() {
@ -13230,6 +13292,10 @@ gui.EditInfoHandle = function EditInfoHandle(parentElement) {
this.hide = function() { this.hide = function() {
handle.style.display = "none" handle.style.display = "none"
}; };
this.destroy = function(callback) {
parentElement.removeChild(handle);
callback()
};
function init() { function init() {
handle = document.createElementNS(htmlns, "div"); handle = document.createElementNS(htmlns, "div");
handle.setAttribute("class", "editInfoHandle"); handle.setAttribute("class", "editInfoHandle");
@ -13238,6 +13304,40 @@ gui.EditInfoHandle = function EditInfoHandle(parentElement) {
} }
init() init()
}; };
/*
Copyright (C) 2012-2013 KO GmbH <copyright@kogmbh.com>
@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.EditInfo"); runtime.loadClass("ops.EditInfo");
runtime.loadClass("gui.EditInfoHandle"); runtime.loadClass("gui.EditInfoHandle");
gui.EditInfoMarker = function EditInfoMarker(editInfo, initialVisibility) { gui.EditInfoMarker = function EditInfoMarker(editInfo, initialVisibility) {
@ -13303,6 +13403,16 @@ gui.EditInfoMarker = function EditInfoMarker(editInfo, initialVisibility) {
this.hideHandle = function() { this.hideHandle = function() {
handle.hide() handle.hide()
}; };
this.destroy = function(callback) {
editInfoNode.removeChild(marker);
handle.destroy(function(err) {
if(err) {
callback(err)
}else {
editInfo.destroy(callback)
}
})
};
function init() { function init() {
var dom = editInfo.getOdtDocument().getDOM(), htmlns = dom.documentElement.namespaceURI; var dom = editInfo.getOdtDocument().getDOM(), htmlns = dom.documentElement.namespaceURI;
marker = dom.createElementNS(htmlns, "div"); marker = dom.createElementNS(htmlns, "div");
@ -13504,16 +13614,39 @@ gui.SessionView = function() {
session.getMemberModel().unsubscribeMemberDetailsUpdates(memberid, renderMemberData) session.getMemberModel().unsubscribeMemberDetailsUpdates(memberid, renderMemberData)
} }
} }
this.close = function(callback) { function onParagraphChanged(info) {
callback() highlightEdit(info.paragraphElement, info.memberId, info.timeStamp)
}
this.destroy = function(callback) {
var odtDocument = session.getOdtDocument(), memberModel = session.getMemberModel(), editInfoArray = Object.keys(editInfoMap).map(function(keyname) {
return editInfoMap[keyname]
});
odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
caretManager.getCarets().forEach(function(caret) {
memberModel.unsubscribeMemberDetailsUpdates(caret.getCursor().getMemberId(), renderMemberData)
});
avatarInfoStyles.parentNode.removeChild(avatarInfoStyles);
(function destroyEditInfo(i, err) {
if(err) {
callback(err)
}else {
if(i < editInfoArray.length) {
editInfoArray[i].destroy(function(err) {
destroyEditInfo(i + 1, err)
})
}else {
callback()
}
}
})(0, undefined)
}; };
function init() { function init() {
var odtDocument = session.getOdtDocument(), head = document.getElementsByTagName("head")[0]; var odtDocument = session.getOdtDocument(), head = document.getElementsByTagName("head")[0];
odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded); odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved); odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, function(info) { odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
highlightEdit(info.paragraphElement, info.memberId, info.timeStamp)
});
avatarInfoStyles = document.createElementNS(head.namespaceURI, "style"); avatarInfoStyles = document.createElementNS(head.namespaceURI, "style");
avatarInfoStyles.type = "text/css"; avatarInfoStyles.type = "text/css";
avatarInfoStyles.media = "screen, print, handheld, projection"; avatarInfoStyles.media = "screen, print, handheld, projection";
@ -13565,6 +13698,11 @@ gui.CaretManager = function CaretManager(sessionController) {
function getCaret(memberId) { function getCaret(memberId) {
return carets.hasOwnProperty(memberId) ? carets[memberId] : null return carets.hasOwnProperty(memberId) ? carets[memberId] : null
} }
function getCarets() {
return Object.keys(carets).map(function(memberid) {
return carets[memberid]
})
}
function getCanvasElement() { function getCanvasElement() {
return sessionController.getSession().getOdtDocument().getOdfCanvas().getElement() return sessionController.getSession().getOdtDocument().getOdfCanvas().getElement()
} }
@ -13616,13 +13754,30 @@ gui.CaretManager = function CaretManager(sessionController) {
return caret return caret
}; };
this.getCaret = getCaret; this.getCaret = getCaret;
this.getCarets = function() { this.getCarets = getCarets;
return Object.keys(carets).map(function(memberid) { this.destroy = function(callback) {
return carets[memberid] var odtDocument = sessionController.getSession().getOdtDocument(), canvasElement = getCanvasElement(), caretArray = getCarets();
}) odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, refreshLocalCaretBlinking);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, removeCaret);
canvasElement.onfocus = null;
canvasElement.onblur = null;
(function destroyCaret(i, err) {
if(err) {
callback(err)
}else {
if(i < caretArray.length) {
caretArray[i].destroy(function(err) {
destroyCaret(i + 1, err)
})
}else {
callback()
}
}
})(0, undefined)
}; };
function init() { function init() {
var session = sessionController.getSession(), odtDocument = session.getOdtDocument(), canvasElement = getCanvasElement(); var odtDocument = sessionController.getSession().getOdtDocument(), canvasElement = getCanvasElement();
odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible); odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible);
odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, refreshLocalCaretBlinking); odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, refreshLocalCaretBlinking);
odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, removeCaret); odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, removeCaret);
@ -14763,6 +14918,9 @@ ops.OdtDocument = function OdtDocument(odfCanvas) {
this.close = function(callback) { this.close = function(callback) {
callback() callback()
}; };
this.destroy = function(callback) {
callback()
};
function init() { function init() {
filter = new TextPositionFilter; filter = new TextPositionFilter;
odfUtils = new odf.OdfUtils odfUtils = new odf.OdfUtils
@ -14839,9 +14997,6 @@ ops.Session = function Session(odfCanvas) {
}); });
opRouter.setOperationFactory(operationFactory) opRouter.setOperationFactory(operationFactory)
}; };
this.getOperationRouter = function() {
return operationRouter
};
this.getMemberModel = function() { this.getMemberModel = function() {
return memberModel return memberModel
}; };
@ -14855,14 +15010,23 @@ ops.Session = function Session(odfCanvas) {
operationRouter.push(operation) operationRouter.push(operation)
}; };
this.close = function(callback) { this.close = function(callback) {
odtDocument.close(function(err) { operationRouter.close(function(err) {
if(err) { if(err) {
callback(err) callback(err)
}else { }else {
callback() memberModel.close(function(err) {
if(err) {
callback(err)
}else {
odtDocument.close(callback)
}
})
} }
}) })
}; };
this.destroy = function(callback) {
odtDocument.destroy(callback)
};
function init() { function init() {
self.setOperationRouter(new ops.TrivialOperationRouter) self.setOperationRouter(new ops.TrivialOperationRouter)
} }

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save