Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixes, improvements, documentations.

  • Loading branch information...
commit 42231d91df7b16638ec19baea3c0dd2aa32681b5 1 parent 3c3332c
p2k authored
3  pygowave_client/cache/model/model.js
@@ -720,8 +720,9 @@ pygowave.model = (function() {
720 720 insertElement: function (index, type, properties, noevent) {
721 721 if (!$defined(noevent)) noevent = false;
722 722 this.insertText(index, "\n", true);
  723 + var elt = null;
723 724 if (type == 2)
724   - var elt = new GadgetElement(this, null, index, properties);
  725 + elt = new GadgetElement(this, null, index, properties);
725 726 else
726 727 elt = new Element(this, null, index, type, properties);
727 728 this._elements.append(elt);
105 pygowave_client/cache/operations/operations.js
@@ -115,7 +115,7 @@ pygowave.operations = (function() {
115 115 * @param {Operation} other_op
116 116 */
117 117 isCompatibleTo: function (other_op) {
118   - if (this.waveId != other_op.waveId || this.waveletId != other_op.waveletId || this.blipId != this.blipId)
  118 + if (this.waveId != other_op.waveId || this.waveletId != other_op.waveletId || this.blipId != other_op.blipId)
119 119 return false;
120 120 return true;
121 121 },
@@ -174,8 +174,39 @@ pygowave.operations = (function() {
174 174 * @param {int} value
175 175 */
176 176 resize: function (value) {
177   - if (this.type == DOCUMENT_DELETE)
178   - this.property = value;
  177 + if (this.type == DOCUMENT_DELETE) {
  178 + if (value > 0)
  179 + this.property = value;
  180 + else
  181 + this.property = 0;
  182 + }
  183 + },
  184 +
  185 + /**
  186 + * DOCUMENT_INSERT: Inserts the string into the property.
  187 + *
  188 + * Other operations: No effect.
  189 + *
  190 + * @function {public} insertString
  191 + * @param {int} pos Position to insert the string
  192 + * @param {String} s String to insert
  193 + */
  194 + insertString: function (pos, s) {
  195 + if (this.type == DOCUMENT_INSERT)
  196 + this.property = this.property.slice(0, pos) + s + this.property.slice(pos);
  197 + },
  198 +
  199 + /**
  200 + * DOCUMENT_INSERT: Deletes a substring from the property.
  201 + *
  202 + * Other operations: No effect.
  203 + * @function {public} deleteString
  204 + * @param {int} pos Position to delete the substring
  205 + * @param {int} length Amout of characters to remove
  206 + */
  207 + deleteString: function (pos, length) {
  208 + if (this.type == DOCUMENT_INSERT)
  209 + this.property = this.property.slice(0, pos) + this.property.slice(pos + length);
179 210 },
180 211
181 212 /**
@@ -519,57 +550,59 @@ pygowave.operations = (function() {
519 550 if (i >= 0) {
520 551 op = this.operations[i];
521 552 if (newop.type == DOCUMENT_INSERT && op.type == DOCUMENT_INSERT) {
522   - if (newop.index == op.index) {
523   - op.property = newop.property + op.property;
524   - this.fireEvent("operationChanged", i);
525   - return;
526   - }
527   - var end = op.index + len(op.property);
528   - if (newop.index == end) {
529   - op.property += newop.property;
530   - this.fireEvent("operationChanged", i);
531   - return;
532   - }
533   - if (op.index < newop.index && newop.index < end) {
534   - op.property = op.property.slice(0, newop.index - op.index) + newop.property + op.property.slice(newop.index - op.index);
  553 + if (newop.index >= op.index && newop.index <= (op.index + op.length())) {
  554 + op.insertString(newop.index - op.index, newop.property);
535 555 this.fireEvent("operationChanged", i);
536 556 return;
537 557 }
538 558 }
539   - if (newop.type == DOCUMENT_DELETE && op.type == DOCUMENT_INSERT) {
540   - if (newop.index == op.index) {
541   - var l = len(op.property);
542   - op.property = op.property.slice(newop.property);
543   - if (op.property == "") {
  559 + else if (newop.type == DOCUMENT_DELETE && op.type == DOCUMENT_INSERT) {
  560 + if (newop.index >= op.index && newop.index < (op.index + op.length())) {
  561 + var remain = op.length() - (newop.index - op.index);
  562 + if (remain > newop.length()) {
  563 + op.deleteString(newop.index - op.index, newop.length());
  564 + newop.resize(0);
  565 + }
  566 + else {
  567 + op.deleteString(newop.index - op.index, remain);
  568 + newop.resize(newop.length() - remain);
  569 + }
  570 + if (op.isNull()) {
544 571 this.fireEvent("beforeOperationsRemoved", [i, i]);
545 572 this.operations.pop(i);
546 573 this.fireEvent("afterOperationsRemoved", [i, i]);
  574 + i--;
547 575 }
548 576 else
549 577 this.fireEvent("operationChanged", i);
550   - newop.property -= l;
551   - if (newop.property <= 0)
  578 + if (newop.isNull())
552 579 return;
553 580 }
554   - end = op.index + len(op.property);
555   - if (op.index < newop.index && newop.index < end) {
556   - l = len(op.property) - (newop.index - op.index + newop.property);
557   - op.property = op.property.slice(0, newop.index - op.index) + op.property.slice(newop.index - op.index + newop.property);
558   - this.fireEvent("operationChanged", i);
559   - newop.property = -l;
560   - if (newop.property <= 0)
561   - return;
  581 + else if (newop.index < op.index && newop.index + newop.length() > op.index) {
  582 + if (newop.index + newop.length() >= (op.index + op.length())) {
  583 + newop.resize(newop.length() - op.length());
  584 + this.fireEvent("beforeOperationsRemoved", [i, i]);
  585 + this.operations.pop(i);
  586 + this.fireEvent("afterOperationsRemoved", [i, i]);
  587 + i--;
  588 + }
  589 + else {
  590 + var dlength = newop.index + newop.length() - op.index;
  591 + newop.resize(newop.length() - dlength);
  592 + op.deleteString(0, dlength);
  593 + this.fireEvent("operationChanged", i);
  594 + }
562 595 }
563 596 }
564   - if (newop.type == DOCUMENT_DELETE && op.type == DOCUMENT_DELETE) {
  597 + else if (newop.type == DOCUMENT_DELETE && op.type == DOCUMENT_DELETE) {
565 598 if (newop.index == op.index) {
566   - op.property += newop.property;
  599 + op.resize(op.length() + newop.length());
567 600 this.fireEvent("operationChanged", i);
568 601 return;
569 602 }
570   - if (newop.index == (op.index - newop.property)) {
571   - op.index -= newop.property;
572   - op.property += newop.property;
  603 + if (newop.index == (op.index - newop.length())) {
  604 + op.index -= newop.length();
  605 + op.resize(op.length() + newop.length());
573 606 this.fireEvent("operationChanged", i);
574 607 return;
575 608 }
1  pygowave_client/src/model/model.py
@@ -679,6 +679,7 @@ def insertElement(self, index, type, properties, noevent = False):
679 679 """
680 680
681 681 self.insertText(index, "\n", True)
  682 + elt = None
682 683 if type == 2:
683 684 elt = GadgetElement(self, None, index, properties)
684 685 else:
96 pygowave_client/src/operations/operations.py
@@ -146,7 +146,7 @@ def isCompatibleTo(self, other_op):
146 146 # DOCUMENT_INSERT DOCUMENT_DELETE DOCUMENT_ELEMENT_INSERT DOCUMENT_ELEMENT_DELETE DOCUMENT_ELEMENT_DELTA DOCUMENT_ELEMENT_SETPREF
147 147 if self.waveId != other_op.waveId \
148 148 or self.waveletId != other_op.waveletId \
149   - or self.blipId != self.blipId:
  149 + or self.blipId != other_op.blipId:
150 150 return False
151 151 return True
152 152
@@ -201,7 +201,35 @@ def resize(self, value):
201 201 @param {int} value
202 202 """
203 203 if self.type == DOCUMENT_DELETE:
204   - self.property = value
  204 + if value > 0:
  205 + self.property = value
  206 + else:
  207 + self.property = 0
  208 +
  209 + def insertString(self, pos, s):
  210 + """
  211 + DOCUMENT_INSERT: Inserts the string into the property.
  212 +
  213 + Other operations: No effect.
  214 +
  215 + @function {public} insertString
  216 + @param {int} pos Position to insert the string
  217 + @param {String} s String to insert
  218 + """
  219 + if self.type == DOCUMENT_INSERT:
  220 + self.property = self.property[:pos] + s + self.property[pos:]
  221 +
  222 + def deleteString(self, pos, length):
  223 + """
  224 + DOCUMENT_INSERT: Deletes a substring from the property.
  225 +
  226 + Other operations: No effect.
  227 + @function {public} deleteString
  228 + @param {int} pos Position to delete the substring
  229 + @param {int} length Amout of characters to remove
  230 + """
  231 + if self.type == DOCUMENT_INSERT:
  232 + self.property = self.property[:pos] + self.property[pos+length:]
205 233
206 234 def serialize(self):
207 235 """
@@ -359,9 +387,9 @@ def transform(self, input_op):
359 387 if op.index >= end:
360 388 op.index -= myop.length()
361 389 elif op.index + op.length() <= end: # and op.index < end
  390 + myop.resize(myop.length() - op.length())
362 391 op_lst.pop(j)
363 392 j -= 1
364   - myop.resize(myop.length() - op.length())
365 393 if myop.isNull():
366 394 self.fireEvent("beforeOperationsRemoved", [i, i])
367 395 self.operations.pop(i)
@@ -529,48 +557,48 @@ def __insert(self, newop):
529 557 if i >= 0:
530 558 op = self.operations[i]
531 559 if newop.type == DOCUMENT_INSERT and op.type == DOCUMENT_INSERT:
532   - if newop.index == op.index: # Prepending
533   - op.property = newop.property + op.property
534   - self.fireEvent("operationChanged", i)
535   - return
536   - end = op.index + len(op.property)
537   - if newop.index == end: # Appending
538   - op.property += newop.property
  560 + if newop.index >= op.index and newop.index <= op.index+op.length():
  561 + op.insertString(newop.index-op.index, newop.property)
539 562 self.fireEvent("operationChanged", i)
540 563 return
541   - if op.index < newop.index and newop.index < end: # Inserting
542   - op.property = op.property[:newop.index-op.index] + newop.property + op.property[newop.index-op.index:]
543   - self.fireEvent("operationChanged", i)
544   - return
545   - if newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_INSERT:
546   - if newop.index == op.index: # Delete from start
547   - l = len(op.property)
548   - op.property = op.property[newop.property:]
549   - if op.property == "":
  564 + elif newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_INSERT:
  565 + if newop.index >= op.index and newop.index < op.index+op.length():
  566 + remain = op.length() - (newop.index - op.index)
  567 + if remain > newop.length():
  568 + op.deleteString(newop.index - op.index, newop.length())
  569 + newop.resize(0)
  570 + else:
  571 + op.deleteString(newop.index - op.index, remain)
  572 + newop.resize(newop.length() - remain)
  573 + if op.isNull():
550 574 self.fireEvent("beforeOperationsRemoved", [i, i])
551 575 self.operations.pop(i)
552 576 self.fireEvent("afterOperationsRemoved", [i, i])
  577 + i -= 1
553 578 else:
554 579 self.fireEvent("operationChanged", i)
555   - newop.property -= l
556   - if newop.property <= 0: # Deleted less than last op's length
  580 + if newop.isNull():
557 581 return
558   - end = op.index + len(op.property)
559   - if op.index < newop.index and newop.index < end: # Delete from within
560   - l = len(op.property) - (newop.index - op.index + newop.property)
561   - op.property = op.property[:newop.index - op.index] + op.property[newop.index - op.index + newop.property:]
562   - self.fireEvent("operationChanged", i)
563   - newop.property = -l
564   - if newop.property <= 0: # Deleted less than last op's length
565   - return
566   - if newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_DELETE:
  582 + elif newop.index < op.index and newop.index+newop.length() > op.index:
  583 + if newop.index+newop.length() >= op.index+op.length():
  584 + newop.resize(newop.length() - op.length())
  585 + self.fireEvent("beforeOperationsRemoved", [i, i])
  586 + self.operations.pop(i)
  587 + self.fireEvent("afterOperationsRemoved", [i, i])
  588 + i -= 1
  589 + else:
  590 + dlength = newop.index+newop.length() - op.index
  591 + newop.resize(newop.length() - dlength)
  592 + op.deleteString(0, dlength)
  593 + self.fireEvent("operationChanged", i)
  594 + elif newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_DELETE:
567 595 if newop.index == op.index: # Delete at start
568   - op.property += newop.property
  596 + op.resize(op.length() + newop.length())
569 597 self.fireEvent("operationChanged", i)
570 598 return
571   - if newop.index == op.index-newop.property: # Deleta at end
572   - op.index -= newop.property
573   - op.property += newop.property
  599 + if newop.index == op.index-newop.length(): # Delete at end
  600 + op.index -= newop.length()
  601 + op.resize(op.length() + newop.length())
574 602 self.fireEvent("operationChanged", i)
575 603 return
576 604
177 pygowave_client/src/view/gadgets.js
@@ -220,8 +220,10 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
220 220
221 221 window.gadget_rpc.registerModuleHandler(gadgetElement.id(), this);
222 222 this._wavelet.addEvent('participantsChanged', this._onParticipantsChanged);
223   - this._gadgetElement.addEvent('stateChange', this._onStateChange);
224   - this._gadgetElement.addEvent('setUserPref', this._onSetUserPref);
  223 + this._gadgetElement.addEvents({
  224 + 'stateChange': this._onStateChange,
  225 + 'setUserPref': this._onSetUserPref
  226 + });
225 227
226 228 var contentElement = new Element('div', {'class': 'gadget_element'});
227 229 contentElement.contentEditable = "false";
@@ -241,20 +243,50 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
241 243
242 244 this.parent(parentElement, contentElement, where);
243 245 },
244   -
  246 + /**
  247 + * Overridden from {@link pygowave.view.Widget.dispose Widget.dispose}.<br/>
  248 + * Removes the widget from the DOM, sets the parentElement to null and
  249 + * disconnects from the Wavelet and GadgetElement.
  250 + *
  251 + * @function {public Widget} dispose
  252 + * @return Returns a reference to this widget.
  253 + */
245 254 dispose: function () {
246 255 this.parent();
247 256 this._wavelet.removeEvent('participantsChanged', this._onParticipantsChanged);
  257 + this._gadgetElement.removeEvents({
  258 + 'stateChange': this._onStateChange,
  259 + 'setUserPref': this._onSetUserPref
  260 + });
248 261 window.gadget_rpc.unregisterModuleHandler(this._gadgetElement.id());
  262 + this._callbacksOnLoad.empty();
  263 + this._callbacksRegistered.empty();
  264 + return this;
249 265 },
250   -
  266 + /**
  267 + * Returns the GadgetElement which is rendered by this widget.
  268 + *
  269 + * @function {public pygowave.model.GadgetElement} element
  270 + */
251 271 element: function () {
252 272 return this._gadgetElement;
253 273 },
  274 + /**
  275 + * Returns the logical position within the Blip text of the rendered
  276 + * GadgetElement.
  277 + *
  278 + * @function {public int} position
  279 + */
254 280 position: function () {
255 281 return this._gadgetElement.position();
256 282 },
257 283
  284 + /**
  285 + * Callback from iframe on load. Invokes onLoad callbacks of the
  286 + * rendered Gadget.
  287 + *
  288 + * @function {private} _onGadgetLoaded
  289 + */
258 290 _onGadgetLoaded: function () {
259 291 for (var it = new _Iterator(this._callbacksOnLoad); it.hasNext(); ) {
260 292 var callback = it.next();
@@ -265,6 +297,12 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
265 297 this._onStateChange();
266 298 this.adjustHeight();
267 299 },
  300 + /**
  301 + * Callback from wavelet model on participants change. Forwards to the
  302 + * rendered Gadget.
  303 + *
  304 + * @function {private} _onParticipantsChanged
  305 + */
268 306 _onParticipantsChanged: function () {
269 307 this.invokeCallbacks(
270 308 "wave_participants",
@@ -275,12 +313,31 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
275 313 }
276 314 );
277 315 },
  316 + /**
  317 + * Callback from model on state change. Forwards to the rendered Gadget.
  318 + *
  319 + * @function {private} _onStateChange
  320 + */
278 321 _onStateChange: function () {
279 322 this.invokeCallbacks("wave_gadget_state", this._gadgetElement.fields());
280 323 },
  324 + /**
  325 + * Callback from model on userpref setting. Forwards to the rendered Gadget.
  326 + *
  327 + * @function {private} _onSetUserPref
  328 + * @param {String} key
  329 + * @param {String} value
  330 + */
281 331 _onSetUserPref: function (key, value) {
282 332 this.invokeCallbacks("set_pref", ["unknown", key, value]);
283 333 },
  334 + /**
  335 + * Invoke registered callbacks of the rendered Gadget.
  336 + *
  337 + * @function {public} invokeCallbacks
  338 + * @param {String} serviceName Name of the service to invoke
  339 + * @param {Object} var_args List of arguments to pass
  340 + */
284 341 invokeCallbacks: function (serviceName, var_args) {
285 342 if (!this._callbacksRegistered.has(serviceName))
286 343 return;
@@ -291,6 +348,16 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
291 348 }
292 349 },
293 350
  351 + /**
  352 + * Callback from GadgetRPCHandler. Reacts to "wave_gadget_state" and
  353 + * "wave_log" calls.
  354 + *
  355 + * @function {private} call
  356 + * @param {int} targetId ID of the target gadget or null for the parent
  357 + * @param {String} serviceName Name of the service to call
  358 + * @param {optional Function} callback Callback function if applicable
  359 + * @param {optional Object} var_args Arguments of the call
  360 + */
294 361 call: function (targetId, serviceName, callback, var_args) {
295 362 if (targetId == null) {
296 363 switch (serviceName) {
@@ -306,14 +373,38 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
306 373 }
307 374 }
308 375 },
  376 + /**
  377 + * Callback from GadgetRPCHandler. Registers an arbitrary service
  378 + * handler, but only "wave_participants", "wave_gadget_state" and
  379 + * "set_pref" will actually be called.
  380 + *
  381 + * @function {private} register
  382 + * @param {String} serviceName Name of the service to register
  383 + * @param {Function} handler Function to be called for the service
  384 + */
309 385 register: function (serviceName, handler) {
310 386 if (!this._callbacksRegistered.has(serviceName))
311 387 this._callbacksRegistered.set(serviceName, new Array());
312 388 this._callbacksRegistered.get(serviceName).push(handler);
313 389 },
  390 + /**
  391 + * Callback from GadgetRPCHandler. Registers a callback to be invoked
  392 + * on Gadget load.
  393 + *
  394 + * @function {private} registerOnLoadHandler
  395 + * @param {Function} callback Function to be called on gadget load
  396 + */
314 397 registerOnLoadHandler: function (callback) {
315 398 this._callbacksOnLoad.push(callback);
316 399 },
  400 + /**
  401 + * Callback from GadgetRPCHandler. Adjusts the height of the container
  402 + * iframe.
  403 + *
  404 + * @function {private} adjustHeight
  405 + * @param {optional int} opt_height Height to be set. If missing tries
  406 + * to calculate the optimal value from the document height.
  407 + */
317 408 adjustHeight: function (opt_height) {
318 409 if ($defined(opt_height))
319 410 this._gadgetFrame.setStyle('height', opt_height);
@@ -324,6 +415,14 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
324 415 }catch(e){}
325 416 }
326 417 },
  418 + /**
  419 + * Callback from GadgetRPCHandler. Sets a UserPref value.
  420 + *
  421 + * @function {private} set_pref
  422 + * @param {int} moduleId ID of the module that invoked this callback
  423 + * @param {String} key
  424 + * @param {String} value
  425 + */
327 426 set_pref: function (key, value) {
328 427 this._view.fireEvent('elementSetUserpref', [this._wavelet.id(), this._blipId, this._gadgetElement.position(), key, value]);
329 428 }
@@ -347,35 +446,93 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
347 446 this._modules = new Hash();
348 447 },
349 448
  449 + /**
  450 + * Registers a new module handler with the given ID. The handler must
  451 + * support all callback functions (call, register, registerOnLoadHandler,
  452 + * adjustHeight, set_pref) which will be invoked from the underlying
  453 + * Gadget.
  454 + *
  455 + * @function {public} registerModuleHandler
  456 + * @function {int} moduleId ID of the module to handle
  457 + * @function {Object} handler Module handler object which receives calls
  458 + */
350 459 registerModuleHandler: function (moduleId, handler) {
351 460 this._modules.set(moduleId, handler);
352 461 },
353   -
  462 + /**
  463 + * Unregisters an existing module handler with the given ID.
  464 + *
  465 + * @function {public} unregisterModuleHandler
  466 + * @param {int} moduleId ID of the module
  467 + */
354 468 unregisterModuleHandler: function (moduleId) {
355 469 this._modules.erase(moduleId);
356 470 },
357 471
358   -
  472 + /**
  473 + * Callback from modules (i.e. Gadgets) to trigger a specific function.
  474 + * Forwards to the associated module handler.
  475 + *
  476 + * @function {private} call
  477 + * @param {int} moduleId ID of the module that invoked this callback
  478 + * @param {int} targetId ID of the target gadget or null for the parent
  479 + * @param {String} serviceName Name of the service to call
  480 + * @param {optional Function} callback Callback function if applicable
  481 + * @param {optional Object} var_args Arguments of the call
  482 + */
359 483 call: function (moduleId, targetId, serviceName, callback, var_args) {
360 484 if (this._modules.has(moduleId))
361 485 this._modules[moduleId].call(targetId, serviceName, callback, var_args);
362 486 },
363   -
  487 + /**
  488 + * Callback from modules (i.e. Gadgets) to register a service callback.
  489 + * Forwards to the associated module handler.
  490 + *
  491 + * @function {private} register
  492 + * @param {int} moduleId ID of the module that invoked this callback
  493 + * @param {String} serviceName Name of the service to register
  494 + * @param {Function} handler Function to be called for the service
  495 + */
364 496 register: function (moduleId, serviceName, handler) {
365 497 if (this._modules.has(moduleId))
366 498 this._modules[moduleId].register(serviceName, handler);
367 499 },
368   -
  500 + /**
  501 + * Callback from modules (i.e. Gadgets) to register a callback which
  502 + * is invoked if the module was loaded.
  503 + * Forwards to the associated module handler.
  504 + *
  505 + * @function {private} registerOnLoadHandler
  506 + * @param {int} moduleId ID of the module that invoked this callback
  507 + * @param {Function} callback Function to be called on module load
  508 + */
369 509 registerOnLoadHandler: function (moduleId, callback) {
370 510 if (this._modules.has(moduleId))
371 511 this._modules[moduleId].registerOnLoadHandler(callback);
372 512 },
373   -
  513 + /**
  514 + * Callback from modules (i.e. Gadgets) to issue an hight adjustment
  515 + * of the container frame.
  516 + * Forwards to the associated module handler.
  517 + *
  518 + * @function {private} adjustHeight
  519 + * @param {int} moduleId ID of the module that invoked this callback
  520 + * @param {optional int} opt_height Height to be set. If missing tries
  521 + * to calculate the optimal value from the document height.
  522 + */
374 523 adjustHeight: function (moduleId, opt_height) {
375 524 if (this._modules.has(moduleId))
376 525 this._modules[moduleId].adjustHeight(opt_height);
377 526 },
378   -
  527 + /**
  528 + * Callback from modules (i.e. Gadgets) to set a UserPref value.
  529 + * Forwards to the associated module handler.
  530 + *
  531 + * @function {private} set_pref
  532 + * @param {int} moduleId ID of the module that invoked this callback
  533 + * @param {String} key
  534 + * @param {String} value
  535 + */
379 536 set_pref: function (moduleId, key, value) {
380 537 if (this._modules.has(moduleId))
381 538 this._modules[moduleId].set_pref(key, value);
96 pygowave_server/common/operations.py
@@ -146,7 +146,7 @@ def isCompatibleTo(self, other_op):
146 146 # DOCUMENT_INSERT DOCUMENT_DELETE DOCUMENT_ELEMENT_INSERT DOCUMENT_ELEMENT_DELETE DOCUMENT_ELEMENT_DELTA DOCUMENT_ELEMENT_SETPREF
147 147 if self.waveId != other_op.waveId \
148 148 or self.waveletId != other_op.waveletId \
149   - or self.blipId != self.blipId:
  149 + or self.blipId != other_op.blipId:
150 150 return False
151 151 return True
152 152
@@ -201,7 +201,35 @@ def resize(self, value):
201 201 @param {int} value
202 202 """
203 203 if self.type == DOCUMENT_DELETE:
204   - self.property = value
  204 + if value > 0:
  205 + self.property = value
  206 + else:
  207 + self.property = 0
  208 +
  209 + def insertString(self, pos, s):
  210 + """
  211 + DOCUMENT_INSERT: Inserts the string into the property.
  212 +
  213 + Other operations: No effect.
  214 +
  215 + @function {public} insertString
  216 + @param {int} pos Position to insert the string
  217 + @param {String} s String to insert
  218 + """
  219 + if self.type == DOCUMENT_INSERT:
  220 + self.property = self.property[:pos] + s + self.property[pos:]
  221 +
  222 + def deleteString(self, pos, length):
  223 + """
  224 + DOCUMENT_INSERT: Deletes a substring from the property.
  225 +
  226 + Other operations: No effect.
  227 + @function {public} deleteString
  228 + @param {int} pos Position to delete the substring
  229 + @param {int} length Amout of characters to remove
  230 + """
  231 + if self.type == DOCUMENT_INSERT:
  232 + self.property = self.property[:pos] + self.property[pos+length:]
205 233
206 234 def serialize(self):
207 235 """
@@ -359,9 +387,9 @@ def transform(self, input_op):
359 387 if op.index >= end:
360 388 op.index -= myop.length()
361 389 elif op.index + op.length() <= end: # and op.index < end
  390 + myop.resize(myop.length() - op.length())
362 391 op_lst.pop(j)
363 392 j -= 1
364   - myop.resize(myop.length() - op.length())
365 393 if myop.isNull():
366 394 self.fireEvent("beforeOperationsRemoved", [i, i])
367 395 self.operations.pop(i)
@@ -529,48 +557,48 @@ def __insert(self, newop):
529 557 if i >= 0:
530 558 op = self.operations[i]
531 559 if newop.type == DOCUMENT_INSERT and op.type == DOCUMENT_INSERT:
532   - if newop.index == op.index: # Prepending
533   - op.property = newop.property + op.property
534   - self.fireEvent("operationChanged", i)
535   - return
536   - end = op.index + len(op.property)
537   - if newop.index == end: # Appending
538   - op.property += newop.property
  560 + if newop.index >= op.index and newop.index <= op.index+op.length():
  561 + op.insertString(newop.index-op.index, newop.property)
539 562 self.fireEvent("operationChanged", i)
540 563 return
541   - if op.index < newop.index and newop.index < end: # Inserting
542   - op.property = op.property[:newop.index-op.index] + newop.property + op.property[newop.index-op.index:]
543   - self.fireEvent("operationChanged", i)
544   - return
545   - if newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_INSERT:
546   - if newop.index == op.index: # Delete from start
547   - l = len(op.property)
548   - op.property = op.property[newop.property:]
549   - if op.property == "":
  564 + elif newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_INSERT:
  565 + if newop.index >= op.index and newop.index < op.index+op.length():
  566 + remain = op.length() - (newop.index - op.index)
  567 + if remain > newop.length():
  568 + op.deleteString(newop.index - op.index, newop.length())
  569 + newop.resize(0)
  570 + else:
  571 + op.deleteString(newop.index - op.index, remain)
  572 + newop.resize(newop.length() - remain)
  573 + if op.isNull():
550 574 self.fireEvent("beforeOperationsRemoved", [i, i])
551 575 self.operations.pop(i)
552 576 self.fireEvent("afterOperationsRemoved", [i, i])
  577 + i -= 1
553 578 else:
554 579 self.fireEvent("operationChanged", i)
555   - newop.property -= l
556   - if newop.property <= 0: # Deleted less than last op's length
  580 + if newop.isNull():
557 581 return
558   - end = op.index + len(op.property)
559   - if op.index < newop.index and newop.index < end: # Delete from within
560   - l = len(op.property) - (newop.index - op.index + newop.property)
561   - op.property = op.property[:newop.index - op.index] + op.property[newop.index - op.index + newop.property:]
562   - self.fireEvent("operationChanged", i)
563   - newop.property = -l
564   - if newop.property <= 0: # Deleted less than last op's length
565   - return
566   - if newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_DELETE:
  582 + elif newop.index < op.index and newop.index+newop.length() > op.index:
  583 + if newop.index+newop.length() >= op.index+op.length():
  584 + newop.resize(newop.length() - op.length())
  585 + self.fireEvent("beforeOperationsRemoved", [i, i])
  586 + self.operations.pop(i)
  587 + self.fireEvent("afterOperationsRemoved", [i, i])
  588 + i -= 1
  589 + else:
  590 + dlength = newop.index+newop.length() - op.index
  591 + newop.resize(newop.length() - dlength)
  592 + op.deleteString(0, dlength)
  593 + self.fireEvent("operationChanged", i)
  594 + elif newop.type == DOCUMENT_DELETE and op.type == DOCUMENT_DELETE:
567 595 if newop.index == op.index: # Delete at start
568   - op.property += newop.property
  596 + op.resize(op.length() + newop.length())
569 597 self.fireEvent("operationChanged", i)
570 598 return
571   - if newop.index == op.index-newop.property: # Deleta at end
572   - op.index -= newop.property
573   - op.property += newop.property
  599 + if newop.index == op.index-newop.length(): # Delete at end
  600 + op.index -= newop.length()
  601 + op.resize(op.length() + newop.length())
574 602 self.fireEvent("operationChanged", i)
575 603 return
576 604
1  settings.py
@@ -41,6 +41,7 @@
41 41 WAVE_DOMAIN = 'localhost'
42 42
43 43 LOGIN_URL = '/pygowave/accounts/login/'
  44 +LOGIN_REDIRECT_URL = '/pygowave/home/'
44 45
45 46 # Set to False to enable some non-localhost features
46 47 IS_LOCAL = True
12 templates/registration/activate.html
@@ -6,12 +6,18 @@
6 6 {% block container_class %}container_narrow{% endblock %}
7 7 {% block content %}
8 8 <h1>{% trans "Account activation" %}</h1>
9   - <p>
10 9 {% if account %}
  10 + <p>
11 11 {% trans "Congratulations! Your account was activated. Have fun." %}
12 12 {% track_event "registration" "account activated" %}
  13 + </p>
  14 + <p>
  15 + <a href="{% url django.contrib.auth.views.login %}">{% trans "Login" %} &raquo;</a>
  16 + </p>
13 17 {% else %}
14   - {% trans "Sorry, your account could not be activated. I don't care why this happened." %}
15   - {% endif %}
  18 + <p>
  19 + {% trans "Sorry, your account could not be activated. Please contact the
  20 + server administrator." %}
16 21 </p>
  22 + {% endif %}
17 23 {% endblock %}

0 comments on commit 42231d9

Please sign in to comment.
Something went wrong with that request. Please try again.