1 /**
  2  * Copyright (C) 2012 KO GmbH <copyright@kogmbh.com>
  3  *
  4  * @licstart
  5  * This file is part of WebODF.
  6  *
  7  * WebODF is free software: you can redistribute it and/or modify it
  8  * under the terms of the GNU Affero General Public License (GNU AGPL)
  9  * as published by the Free Software Foundation, either version 3 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * WebODF is distributed in the hope that it will be useful, but
 13  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU Affero General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Affero General Public License
 18  * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 19  * @licend
 20  *
 21  * @source: http://www.webodf.org/
 22  * @source: https://github.com/kogmbh/WebODF/
 23  */
 24 
 25 /*global ops, runtime, core*/
 26 
 27 /*
 28  * route the operations.
 29  * this implementation immediately passes them to the
 30  * playback function.
 31  * other implementations might want to send them to a
 32  * server and wait for foreign ops.
 33  */
 34 
 35 /**
 36  * @constructor
 37  * @implements ops.OperationRouter
 38  */
 39 ops.TrivialOperationRouter = function TrivialOperationRouter() {
 40     "use strict";
 41 
 42     var events = new core.EventNotifier([
 43             ops.OperationRouter.signalProcessingBatchStart,
 44             ops.OperationRouter.signalProcessingBatchEnd
 45         ]),
 46         /**@type{!ops.OperationFactory}*/
 47         operationFactory,
 48         playbackFunction,
 49         /**@type{number}*/
 50         groupIdentifier = 0;
 51 
 52     /**
 53      * Sets the factory to use to create operation instances from operation specs.
 54      *
 55      * @param {!ops.OperationFactory} f
 56      * @return {undefined}
 57      */
 58     this.setOperationFactory = function (f) {
 59         operationFactory = f;
 60     };
 61 
 62     /**
 63      * Sets the method which should be called to apply operations.
 64      *
 65      * @param {!function(!ops.Operation):boolean} playback_func
 66      * @return {undefined}
 67      */
 68     this.setPlaybackFunction = function (playback_func) {
 69         playbackFunction = playback_func;
 70     };
 71 
 72     /**
 73      * Brings the locally created operations into the game.
 74      *
 75      * @param {!Array.<!ops.Operation>} operations
 76      * @return {undefined}
 77      */
 78     this.push = function (operations) {
 79         // This is an extremely simplistic and VERY temporary implementation of operation grouping.
 80         // In order to improve undo behaviour, the undo manager requires knowledge about what groups
 81         // of operations were queued together, so these can be stored in a single undo state.
 82         // The current implementation is only designed for a localeditor instance & the TrivialUndoManager.
 83         // TODO redesign this concept to work with collaborative editing
 84         groupIdentifier += 1;
 85         events.emit(ops.OperationRouter.signalProcessingBatchStart, {});
 86         operations.forEach(function (op) {
 87             var /**@type{?ops.Operation}*/
 88                 timedOp,
 89                 opspec = op.spec();
 90 
 91             opspec.timestamp = Date.now();
 92             timedOp = operationFactory.create(opspec);
 93             timedOp.group = "g" + groupIdentifier;
 94 
 95             // TODO: handle return flag in error case
 96             playbackFunction(timedOp);
 97         });
 98         events.emit(ops.OperationRouter.signalProcessingBatchEnd, {});
 99     };
100 
101     /**
102      * @param {function()} cb
103      */
104     this.close = function (cb) {
105         cb();
106     };
107 
108     /**
109      * @param {!string} eventId
110      * @param {!Function} cb
111      * @return {undefined}
112      */
113     this.subscribe = function (eventId, cb) {
114         events.subscribe(eventId, cb);
115     };
116 
117     /**
118      * @param {!string} eventId
119      * @param {!Function} cb
120      * @return {undefined}
121      */
122     this.unsubscribe = function (eventId, cb) {
123         events.unsubscribe(eventId, cb);
124     };
125 
126     /**
127      * @return {!boolean}
128      */
129     this.hasLocalUnsyncedOps = function () {
130         return false;
131     };
132 
133     /**
134      * @return {!boolean}
135      */
136     this.hasSessionHostConnection = function () {
137         return true;
138     };
139 };
140