update webodf

This commit is contained in:
Tobias Hintze 2013-08-06 10:46:47 +02:00
parent fc7c1e02a5
commit 8c71d3a436
9 changed files with 3231 additions and 1977 deletions

View File

@ -59,8 +59,9 @@ define("webodf/editor/Editor", [
* cursorRemovedCallback:function(!string)=, * cursorRemovedCallback:function(!string)=,
* registerCallbackForShutdown:function(!function())= }} args * registerCallbackForShutdown:function(!function())= }} args
* @param {!ops.Server=} server * @param {!ops.Server=} server
* @param {!ServerFactory=} serverFactory
*/ */
function Editor(args, server) { function Editor(args, server, serverFactory) {
var self = this, var self = this,
// Private // Private
@ -102,7 +103,8 @@ define("webodf/editor/Editor", [
inviteButton, inviteButton,
viewOptions = { viewOptions = {
editInfoMarkersInitiallyVisible: networked, editInfoMarkersInitiallyVisible: networked,
caretAvatarsInitiallyVisible: networked caretAvatarsInitiallyVisible: networked,
caretBlinksOnRangeSelect: true
}, },
peopleListDiv = document.getElementById('peopleList'); peopleListDiv = document.getElementById('peopleList');
@ -153,6 +155,8 @@ define("webodf/editor/Editor", [
editorSession.startEditing(); editorSession.startEditing();
return; return;
} }
// Allow annotations
odfCanvas.enableAnnotations(true);
if (!memberid) { if (!memberid) {
// legacy - memberid should be passed in the constructor // legacy - memberid should be passed in the constructor
@ -266,10 +270,10 @@ define("webodf/editor/Editor", [
self.loadSession = function (sessionId, editorReadyCallback) { self.loadSession = function (sessionId, editorReadyCallback) {
initGuiAndDoc(server.getGenesisUrl(sessionId), function () { initGuiAndDoc(server.getGenesisUrl(sessionId), function () {
// get router and user model // get router and user model
opRouter = opRouter || server.createOperationRouter(sessionId, memberid); opRouter = opRouter || serverFactory.createOperationRouter(sessionId, memberid, server);
session.setOperationRouter(opRouter); session.setOperationRouter(opRouter);
userModel = userModel || server.createUserModel(); userModel = userModel || serverFactory.createUserModel(server);
session.setUserModel(userModel); session.setUserModel(userModel);
opRouter.requestReplay(function done() { opRouter.requestReplay(function done() {

View File

@ -45,11 +45,12 @@ define("webodf/editor/EditorSession", [
runtime.loadClass("ops.OdtDocument"); runtime.loadClass("ops.OdtDocument");
runtime.loadClass("ops.Session"); runtime.loadClass("ops.Session");
runtime.loadClass("odf.OdfCanvas"); runtime.loadClass("odf.OdfCanvas");
runtime.loadClass("gui.CaretFactory"); runtime.loadClass("gui.CaretManager");
runtime.loadClass("gui.Caret"); runtime.loadClass("gui.Caret");
runtime.loadClass("gui.SessionController"); runtime.loadClass("gui.SessionController");
runtime.loadClass("gui.SessionView"); runtime.loadClass("gui.SessionView");
runtime.loadClass("gui.TrivialUndoManager"); runtime.loadClass("gui.TrivialUndoManager");
runtime.loadClass("gui.StyleHelper");
runtime.loadClass("core.EventNotifier"); runtime.loadClass("core.EventNotifier");
/** /**
@ -67,6 +68,7 @@ define("webodf/editor/EditorSession", [
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",
formatting = odtDocument.getFormatting(), formatting = odtDocument.getFormatting(),
styleHelper = new gui.StyleHelper(formatting),
eventNotifier = new core.EventNotifier([ eventNotifier = new core.EventNotifier([
EditorSession.signalUserAdded, EditorSession.signalUserAdded,
EditorSession.signalUserRemoved, EditorSession.signalUserRemoved,
@ -79,7 +81,7 @@ define("webodf/editor/EditorSession", [
this.sessionController = new gui.SessionController(session, memberid); this.sessionController = new gui.SessionController(session, memberid);
this.sessionView = new gui.SessionView(config.viewOptions, session, new gui.CaretFactory(self.sessionController)); this.sessionView = new gui.SessionView(config.viewOptions, session, new gui.CaretManager(self.sessionController));
this.availableFonts = []; this.availableFonts = [];
/* /*
@ -188,6 +190,7 @@ define("webodf/editor/EditorSession", [
if (info.paragraphElement !== currentParagraphNode) { if (info.paragraphElement !== currentParagraphNode) {
return; return;
} }
self.emit(EditorSession.signalParagraphChanged, info);
checkParagraphStyleName(); checkParagraphStyleName();
} }
@ -276,18 +279,40 @@ define("webodf/editor/EditorSession", [
return formatting.getAvailableParagraphStyles(); return formatting.getAvailableParagraphStyles();
}; };
this.getCurrentSelectionStyle = function () { this.isBold = function () {
var cursor = odtDocument.getCursor(memberid), var cursor = odtDocument.getCursor(memberid);
selectedRange;
// no own cursor yet/currently added? // no own cursor yet/currently added?
if (!cursor) { if (!cursor) {
return []; return false;
} }
selectedRange = cursor.getSelectedRange(); return styleHelper.isBold(cursor.getSelectedRange());
if (selectedRange.collapsed) { };
return [formatting.getAppliedStylesForElement(cursor.getNode())];
this.isItalic = function () {
var cursor = odtDocument.getCursor(memberid);
// no own cursor yet/currently added?
if (!cursor) {
return false;
} }
return formatting.getAppliedStyles(selectedRange); return styleHelper.isItalic(cursor.getSelectedRange());
};
this.hasUnderline = function () {
var cursor = odtDocument.getCursor(memberid);
// no own cursor yet/currently added?
if (!cursor) {
return false;
}
return styleHelper.hasUnderline(cursor.getSelectedRange());
};
this.hasStrikeThrough = function () {
var cursor = odtDocument.getCursor(memberid);
// no own cursor yet/currently added?
if (!cursor) {
return false;
}
return styleHelper.hasStrikeThrough(cursor.getSelectedRange());
}; };
this.getCurrentParagraphStyle = function () { this.getCurrentParagraphStyle = function () {
@ -295,13 +320,35 @@ define("webodf/editor/EditorSession", [
}; };
this.formatSelection = function (value) { this.formatSelection = function (value) {
var op = new ops.OpApplyStyle(), var op = new ops.OpApplyDirectStyling(),
selection = self.getCursorSelection(); selection = self.getCursorSelection();
op.init({ op.init({
memberid: memberid, memberid: memberid,
position: selection.position, position: selection.position,
length: selection.length, length: selection.length,
info: value setProperties: value
});
session.enqueue(op);
};
/**
* Adds an annotation to the document based on the current selection
* @return {undefined}
*/
this.addAnnotation = function () {
var op = new ops.OpAddAnnotation(),
selection = self.getCursorSelection(),
length = selection.length,
position = selection.position;
position = length >= 0 ? position : position + length;
length = Math.abs(length);
op.init({
memberid: memberid,
position: position,
length: length,
name: memberid + Date.now()
}); });
session.enqueue(op); session.enqueue(op);
}; };
@ -379,14 +426,30 @@ define("webodf/editor/EditorSession", [
*/ */
this.cloneParagraphStyle = function (styleName, newStyleDisplayName) { this.cloneParagraphStyle = function (styleName, newStyleDisplayName) {
var newStyleName = uniqueParagraphStyleNCName(newStyleDisplayName), var newStyleName = uniqueParagraphStyleNCName(newStyleDisplayName),
op; styleNode = odtDocument.getParagraphStyleElement(styleName),
formatting = odtDocument.getFormatting(),
op, setProperties, attributes, i;
op = new ops.OpCloneParagraphStyle(); setProperties = formatting.getStyleAttributes(styleNode);
// copy any attributes directly on the style
attributes = styleNode.attributes;
for (i = 0; i < attributes.length; i += 1) {
// skip...
// * style:display-name -> not copied, set to new string below
// * style:name -> not copied, set from op by styleName property
// * style:family -> "paragraph" always, set by op
if (!/^(style:display-name|style:name|style:family)/.test(attributes[i].name)) {
setProperties[attributes[i].name] = attributes[i].value;
}
}
setProperties['style:display-name'] = newStyleDisplayName;
op = new ops.OpAddParagraphStyle();
op.init({ op.init({
memberid: memberid, memberid: memberid,
styleName: styleName, styleName: newStyleName,
newStyleName: newStyleName, setProperties: setProperties
newStyleDisplayName: newStyleDisplayName
}); });
session.enqueue(op); session.enqueue(op);

View File

@ -54,7 +54,11 @@ function SessionListView(sessionList, sessionListDiv, cb) {
sessionDiv.appendChild(fullnameTextNode); sessionDiv.appendChild(fullnameTextNode);
sessionDiv.sessionId = sessionDetails.id; // TODO: namespace? sessionDiv.sessionId = sessionDetails.id; // TODO: namespace?
sessionDiv.style.cursor = "pointer"; // TODO: do not set on each element, use CSS
sessionDiv.onclick = function () { 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); cb(sessionDetails.id);
}; };

View File

@ -47,7 +47,7 @@
* *
*/ */
/*global runtime, require, document, alert, net, window, NowjsSessionList, PullBoxSessionList, SessionListView, ops */ /*global runtime, require, document, alert, net, window, SessionListView, ops */
// define the namespace/object we want to provide // define the namespace/object we want to provide
// this is the first line of API, the user gets. // this is the first line of API, the user gets.
@ -62,6 +62,7 @@ var webodfEditor = (function () {
}; };
var editorInstance = null, var editorInstance = null,
serverFactory = null,
server = null, server = null,
booting = false, booting = false,
loadedFilename; loadedFilename;
@ -78,22 +79,31 @@ var webodfEditor = (function () {
* @return {undefined} * @return {undefined}
*/ */
function connectNetwork(backend, callback) { function connectNetwork(backend, callback) {
if (backend === "pullbox") { function createServer(ServerFactory) {
runtime.loadClass("ops.PullBoxServer"); serverFactory = new ServerFactory();
server = new ops.PullBoxServer(); server = serverFactory.createServer();
} else if (backend === "nowjs") { server.connect(8000, callback);
runtime.loadClass("ops.NowjsServer"); }
server = new ops.NowjsServer();
} else if (backend === "owncloud") { switch (backend) {
runtime.loadClass("ops.PullBoxServer"); case "pullbox":
server = new ops.PullBoxServer({url: "./office/ajax/otpoll.php"}); require({ }, ["webodf/editor/server/pullbox/serverFactory"], createServer);
server.getGenesisUrl = function(sid) { break;
return "/owncloud/index.php/apps/files/download/welcome.odt"; case "nowjs":
}; require({ }, ["webodf/editor/server/nowjs/serverFactory"], createServer);
} else { break;
callback("unavailable"); case "owncloud":
require({ }, ["webodf/editor/server/pullbox/serverFactory"], function (ServerFactory) {
serverFactory = new ServerFactory();
server = serverFactory.createServer({url: "./office/ajax/otpoll.php"});
server.getGenesisUrl = function(sid) {
return "/owncloud/index.php/apps/files/download/welcome.odt";
};
server.connect(8000, callback);
});
default:
callback("unavailable");
} }
server.connect(8000, callback);
} }
/** /**
@ -261,7 +271,7 @@ var webodfEditor = (function () {
function (Editor) { function (Editor) {
// TODO: the networkSecurityToken needs to be retrieved via now.login // TODO: the networkSecurityToken needs to be retrieved via now.login
// (but this is to be implemented later) // (but this is to be implemented later)
editorInstance = new Editor(editorOptions, server); editorInstance = new Editor(editorOptions, server, serverFactory);
// load the document and get called back when it's live // load the document and get called back when it's live
editorInstance.loadSession(sessionId, function (editorSession) { editorInstance.loadSession(sessionId, function (editorSession) {
@ -299,8 +309,7 @@ var webodfEditor = (function () {
function showSessions() { function showSessions() {
var sessionListDiv = document.getElementById("sessionList"), var sessionListDiv = document.getElementById("sessionList"),
// sessionList = new NowjsSessionList(server), sessionList = new serverFactory.createSessionList(server),
sessionList = new PullBoxSessionList(server),
sessionListView = new SessionListView(sessionList, sessionListDiv, enterSession); sessionListView = new SessionListView(sessionList, sessionListDiv, enterSession);
// hide login view // hide login view

View File

@ -55,7 +55,7 @@ define("webodf/editor/widgets", [
], function (ready, MenuItem, DropDownMenu, Button, DropDownButton, Toolbar) { ], function (ready, MenuItem, DropDownMenu, Button, DropDownButton, Toolbar) {
ready(function () { ready(function () {
var loadButton, saveButton, dropDownMenu, menuButton, paragraphStylesMenuItem, dialog, toolbar, simpleStyles, currentStyle, zoomSlider, var loadButton, saveButton, dropDownMenu, menuButton, paragraphStylesMenuItem, dialog, toolbar, simpleStyles, currentStyle, zoomSlider,
undoRedoMenu; undoRedoMenu, annotateButton;
dropDownMenu = new DropDownMenu({}); dropDownMenu = new DropDownMenu({});
paragraphStylesMenuItem = new MenuItem({ paragraphStylesMenuItem = new MenuItem({
@ -136,6 +136,16 @@ define("webodf/editor/widgets", [
} }
}); });
menuButton.placeAt(toolbar); menuButton.placeAt(toolbar);
annotateButton = new Button({
label: translator('annotate'),
showLabel: false,
iconClass: 'dijitIconBookmark',
onClick: function () {
editorSession.addAnnotation();
}
});
annotateButton.placeAt(toolbar);
}); });
}); });
}; };

View File

@ -65,12 +65,90 @@ define("webodf/editor/widgets/paragraphStylesDialog", [], function () {
deleteButton, deleteButton,
cloneTooltip, cloneTooltip,
cloneDropDown, cloneDropDown,
newStyleName = null; newStyleName = null,
/**
* Mapping of the properties from edit pane properties to the attributes of style:text-properties
* @const@type{Array.<!{propertyName:string,attributeName:string,unit:string}>}
*/
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.<!{propertyName:string,attributeName:string,unit:string}>}
*/
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.<!{propertyName:string,attributeName:string,unit:string}>} 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;
}
}
return result;
}
function accept() { function accept() {
editorSession.updateParagraphStyle(stylePicker.value(), { editorSession.updateParagraphStyle(stylePicker.value(), {
paragraphProperties: alignmentPane.value(), "style:paragraph-properties": mappedProperties(alignmentPane.value(), paragraphPropertyMapping),
textProperties: fontEffectsPane.value() "style:text-properties": mappedProperties(fontEffectsPane.value(), textPropertyMapping)
}); });
dialog.hide(); dialog.hide();

View File

@ -106,30 +106,12 @@ define("webodf/editor/widgets/simpleStyles",
}); });
function checkStyleButtons() { function checkStyleButtons() {
var fontWeight, fontStyle, underline, strikethrough, appliedStyles;
appliedStyles = editorSession.getCurrentSelectionStyle();
fontWeight = false;
fontStyle = false;
underline = false;
strikethrough = false;
appliedStyles.forEach(function(appliedStyle) {
var textProperties = appliedStyle['style:text-properties'];
if (textProperties) {
fontWeight = fontWeight || textProperties['fo:font-weight'] === 'bold';
fontStyle = fontStyle || textProperties['fo:font-style'] === 'italic';
underline = underline || textProperties['style:text-underline-style'] === 'solid';
strikethrough = strikethrough || textProperties['style:text-line-through-style'] === 'solid';
}
});
// The 3rd parameter is false to avoid firing onChange when setting the value // The 3rd parameter is false to avoid firing onChange when setting the value
// programmatically. // programmatically.
boldButton.set('checked', fontWeight, false); boldButton.set('checked', editorSession.isBold(), false);
italicButton.set('checked', fontStyle, false); italicButton.set('checked', editorSession.isItalic(), false);
underlineButton.set('checked', underline, false); underlineButton.set('checked', editorSession.hasUnderline(), false);
strikethroughButton.set('checked', strikethrough, false); strikethroughButton.set('checked', editorSession.hasStrikeThrough(), false);
} }
editorSession.subscribe(EditorSession.signalCursorMoved, checkStyleButtons); editorSession.subscribe(EditorSession.signalCursorMoved, checkStyleButtons);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long