Browse files

Some cleanup done, removed MooEditable; more fixes and improvements; …

…implemented Gadget deletion; reactivated mouse-over tooltips in "All Gadgets"
  • Loading branch information...
1 parent 9cffbec commit 9e0cfcb1e43951578413e1d3f70279cff97843ce @p2k p2k committed Aug 29, 2009
Showing with 886 additions and 1,895 deletions.
  1. +3 −3 NOTICE
  2. +1 −1 amqp_rpc_server.py
  3. +0 −181 media/css/MooEditable.css
  4. +35 −7 media/css/pygowave-client-style.css
  5. +1 −5 media/css/style.css
  6. BIN media/images/delete_gadget.png
  7. BIN media/images/leave.png
  8. BIN media/images/mooeditable-toolbarbuttons-tango.png
  9. BIN media/images/wavelogo.png
  10. BIN media/images/wavelogo_banner.png
  11. BIN media/images/wavelogo_small.png
  12. +0 −1,202 media/js/MooEditable.js
  13. +3 −1 media/js/pycow.js
  14. +50 −2 pygowave_client/cache/model/model.js
  15. +39 −39 pygowave_client/cache/operations/operations.js
  16. BIN pygowave_client/locale/de/LC_MESSAGES/djangojs.mo
  17. +207 −19 pygowave_client/locale/de/LC_MESSAGES/djangojs.po
  18. +9 −28 pygowave_client/src/controller/controller.js
  19. +45 −3 pygowave_client/src/model/model.py
  20. +70 −41 pygowave_client/src/operations/operations.py
  21. +244 −136 pygowave_client/src/view/blip_editor.js
  22. +3 −1 pygowave_client/src/view/debug_tools.js
  23. +36 −8 pygowave_client/src/view/gadgets.js
  24. +1 −1 pygowave_client/src/view/selection.js
  25. +35 −5 pygowave_client/src/view/view.js
  26. +3 −29 pygowave_client/templatetags/{pygowave_client.py → pygowave_client_scripts.py}
  27. +70 −41 pygowave_server/common/operations.py
  28. +1 −97 pygowave_server/engine.py
  29. +21 −4 pygowave_server/models.py
  30. 0 pygowave_server/ops.py
  31. +1 −1 pygowave_server/views.py
  32. +0 −30 templates/pygowave_server/contacts/search_participants.html
  33. +2 −2 templates/pygowave_server/gadgets/all_gadgets.html
  34. +6 −6 templates/pygowave_server/project_status.html
  35. +0 −2 templates/pygowave_server/waves/on_the_wave.html
View
6 NOTICE
@@ -12,6 +12,6 @@ http://www.bitbucket.org/ubernostrum/django-registration/wiki/
This software makes use of MooTools developed by Valerio Proietti
as well as MochaUI by Greg Houston.
-This software uses a modified version of MooEditable, a rich-text editor
-written in MooTools by cheeaun. The original software is available from
-http://cheeaun.github.com/mooeditable/
+This software includes parts of the Oxygen iconset which is released under the
+Creative Commons Attribution-NonCommercial-NoDerivs 2.5 License.
+http://www.oxygen-icons.org/
View
2 amqp_rpc_server.py
@@ -286,7 +286,7 @@ def handle_participant_message(self, wavelet, pconn, message):
self.emit(pconn, "OPERATION_MESSAGE_BUNDLE_ACK", {"version": wavelet.version, "blipsums": blipsums})
self.broadcast(wavelet, "OPERATION_MESSAGE_BUNDLE", {"version": wavelet.version, "operations": newdelta.serialize(), "blipsums": blipsums}, [pconn])
- logger.info("[%s/%d@%s] Processed delta #%d -> v%d" % (participant.name, pconn.id, wavelet.wave.id, version, wavelet.version))
+ logger.debug("[%s/%d@%s] Processed delta #%d -> v%d" % (participant.name, pconn.id, wavelet.wave.id, version, wavelet.version))
else:
logger.error("[%s/%d@%s] Unknown message: %s" % (participant.name, pconn.id, wavelet.wave.id, message))
View
181 media/css/MooEditable.css
@@ -1,181 +0,0 @@
-.mooeditable-container{
- position: relative;
- /*border: 2px solid #ddd;*/
- border-bottom: 2px solid #ddd;
-}
-
-.mooeditable-ui-toolbar{
- color: inherit;
- background-color: #eee;
- padding: 2px;
-}
-
-.mooeditable-ui-toolbar:after{
- content: ".";
- display: block;
- height: 0;
- clear: both;
- visibility: hidden;
-}
-
-.mooeditable-ui-toolbar .toolbar-item,
-.mooeditable-ui-toolbar .toolbar-separator{
- display: -moz-inline-box;
- display: inline-block;
- vertical-align: middle;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button{
- cursor: pointer;
- border: 0;
- width: auto;
- height: auto;
- margin: 2px;
- padding: 2px;
- vertical-align: middle;
- color: inherit;
- background-color: transparent;
-}
-* html .mooeditable-ui-toolbar .mooeditable-ui-button{ /* IE6 */
- width: 24px;
- overflow: visible;
- padding: 2px 4px;
-}
-*:first-child+html .mooeditable-ui-toolbar .mooeditable-ui-button{ /* IE7 */
- min-width: 24px;
- overflow: visible;
- padding: 2px 4px;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button.active,
-.mooeditable-ui-toolbar .mooeditable-ui-button.onActive{
- color: inherit;
- background-color: #ddd;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button:hover,
-.mooeditable-ui-toolbar .mooeditable-ui-button.hover{
- color: inherit;
- background-color: #fff;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button.disabled{
- cursor: default;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button.disabled:hover{
- color: inherit;
- background-color: transparent;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button .button-icon{
- display: -moz-inline-box;
- display: inline-block;
- width: 16px;
- height: 16px;
- vertical-align: middle;
- color: inherit;
- background: transparent url(../images/mooeditable-toolbarbuttons-tango.png) no-repeat 0 -8px;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button .button-text{
- display: none;
- font-size: 13px;
- vertical-align: middle;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button-text .button-icon{
- display: none;
-}
-.mooeditable-ui-toolbar .mooeditable-ui-button-text .button-text{
- display: inline;
-}
-
-.mooeditable-ui-toolbar .mooeditable-ui-button-icon-text{
- width: auto;
-}
-.mooeditable-ui-toolbar .mooeditable-ui-button-icon-text .button-text{
- display: inline;
- margin-left: 4px;
-}
-
-.mooeditable-ui-toolbar .toolbar-separator{
- width: 1px;
- height: 24px;
- margin: 2px;
- text-indent: -999em;
- color: inherit;
- background-color: #fafafa;
-}
-
-.mooeditable-ui-toolbar .bold-item .button-icon{ background-position: 0 0; }
-.mooeditable-ui-toolbar .createlink-item .button-icon{ background-position: 0 -16px; }
-.mooeditable-ui-toolbar .indent-item .button-icon{ background-position: 0 -32px; }
-.mooeditable-ui-toolbar .insertorderedlist-item .button-icon{ background-position: 0 -48px; }
-.mooeditable-ui-toolbar .insertunorderedlist-item .button-icon{ background-position: 0 -64px; }
-.mooeditable-ui-toolbar .italic-item .button-icon{ background-position: 0 -80px; }
-.mooeditable-ui-toolbar .outdent-item .button-icon{ background-position: 0 -96px; }
-.mooeditable-ui-toolbar .redo-item .button-icon{ background-position: 0 -112px; }
-.mooeditable-ui-toolbar .strikethrough-item .button-icon{ background-position: 0 -128px; }
-.mooeditable-ui-toolbar .toggleview-item .button-icon{ background-position: 0 -144px; }
-.mooeditable-ui-toolbar .underline-item .button-icon{ background-position: 0 -160px; }
-.mooeditable-ui-toolbar .undo-item .button-icon{ background-position: 0 -176px; }
-.mooeditable-ui-toolbar .unlink-item .button-icon{ background-position: 0 -192px; }
-.mooeditable-ui-toolbar .urlimage-item .button-icon{ background-position: 0 -208px; }
-
-.mooeditable-iframe{
- margin: 0;
- padding: 0;
- border: 0;
- width: 100%;
-}
-
-.mooeditable-textarea{
- margin: 0 !important;
- padding: 0 !important;
- border: 0 !important;
- width: 100% !important;
- resize: none !important; /* disable resizable textareas in Webkit */
- outline: 0 !important; /* disable focus ring in Safari */
-}
-
-.mooeditable-ui-dialog{
- color: inherit;
- background-color: #ddd;
- position: absolute;
- display: block;
- cursor: default;
- font-size: 12px;
- z-index: 100;
- width: 100%;
-}
-
-.mooeditable-ui-dialog .dialog-content{
- padding: 4px 10px;
-}
-
-.mooeditable-ui-dialog .dialog-content *{
- vertical-align: middle;
-}
-
-.mooeditable-ui-dialog input{
- margin: 0 8px;
-}
-
-.mooeditable-ui-dialog input.text{
- width: 300px;
-}
-
-.mooeditable-ui-button-overlay{
- color: inherit;
- background-color: #ddd;
- font-size: 12px;
- z-index: 100;
- outline: 0;
- -moz-outline: 0;
- -webkit-outline: 0;
-}
-
-.mooeditable-ui-button-overlay .overlay-content{
- padding: 10px;
-}
View
42 media/css/pygowave-client-style.css
@@ -262,29 +262,52 @@
width: 100%;
height: auto;
cursor: text;
- overflow: auto;
- font-size: 1.3em;
+ overflow: visible;
+ font-size: 1.2em;
outline: none;
- padding-bottom: 2px;
+ padding-top: 2px;
border-bottom: 1px solid #B8C6D9;
+ position: relative;
}
.blip_editor_widget p
{
line-height: normal !important;
margin-left: 5px;
margin-bottom: 0;
- margin-top: 2px;
+ margin-bottom: 2px;
padding: 0;
}
.blip_editor_widget .gadget_element
{
- width: 90%;
- height: 400px;
margin-left: 5px;
+ margin-right: 5px;
margin-top: 2px;
- border: 1px solid black;
+ margin-bottom: 2px;
+ padding: 5px;
+ border-top: 1px dotted #CCCCCC;
+ border-left: 1px dotted #CCCCCC;
+ position: relative;
+}
+
+.blip_editor_widget .gadget_element iframe
+{
+ width: 100%;
+ height: 200px;
+ border: 0;
+}
+
+.blip_editor_widget .gadget_element .delete_box
+{
+ width: 16px;
+ height: 16px;
+ background-image: url(../images/delete_gadget.png);
+ background-repeat: no-repeat;
+ position: absolute;
+ right: 0;
+ top: 2px;
+ cursor: pointer;
}
.search_widget
@@ -427,7 +450,11 @@
.error_overlay
{
width: 100%;
+ height: 100%;
overflow: hidden;
+ position: absolute;
+ top: 0;
+ left: 0;
}
.error_overlay .bg_div
@@ -453,6 +480,7 @@
padding-left: 31px;
padding-top: 7px;
padding-bottom: 7px;
+ font-size: 0.9em;
}
.error_overlay button
View
6 media/css/style.css
@@ -241,18 +241,14 @@ p
font-weight: bold;
}
-#tooltip
+.tooltip
{
background-color: #EEEEEE;
border: 1px solid #111111;
opacity: 0.85;
padding: 5px;
position: absolute;
z-index: 3000;
-}
-
-#tooltip .body
-{
font-size: 1.2em;
}
View
BIN media/images/delete_gadget.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN media/images/leave.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN media/images/mooeditable-toolbarbuttons-tango.png
Deleted file not rendered
View
BIN media/images/wavelogo.png
Deleted file not rendered
View
BIN media/images/wavelogo_banner.png
Deleted file not rendered
View
BIN media/images/wavelogo_small.png
Deleted file not rendered
View
1,202 media/js/MooEditable.js
@@ -1,1202 +0,0 @@
-/*
-Script: MooEditable.js
- Class for creating a WYSIWYG editor, for contentEditable-capable browsers.
-
-License:
- MIT-style license.
-
-Copyright:
- Copyright (c) 2007-2009 [Lim Chee Aun](http://cheeaun.com).
-
-Build: %build%
-
-Credits:
- - Code inspired by Stefan's work [Safari Supports Content Editing!](http://www.xs4all.nl/~hhijdra/stefan/ContentEditable.html) from [safari gets contentEditable](http://walkah.net/blog/walkah/safari-gets-contenteditable)
- - Main reference from Peter-Paul Koch's [execCommand compatibility](http://www.quirksmode.org/dom/execCommand.html)
- - Some ideas and code inspired by [TinyMCE](http://tinymce.moxiecode.com/)
- - Some functions inspired by Inviz's [Most tiny wysiwyg you ever seen](http://forum.mootools.net/viewtopic.php?id=746), [mooWyg (Most tiny WYSIWYG 2.0)](http://forum.mootools.net/viewtopic.php?id=5740)
- - Some regex from Cameron Adams's [widgEditor](http://widgeditor.googlecode.com/)
- - Some code from Juan M Martinez's [jwysiwyg](http://jwysiwyg.googlecode.com/)
- - Some reference from MoxieForge's [PunyMCE](http://punymce.googlecode.com/)
- - IE support referring Robert Bredlau's [Rich Text Editing](http://www.rbredlau.com/drupal/node/6)
- - Tango icons from the [Tango Desktop Project](http://tango.freedesktop.org/)
- - Additional Tango icons from Jimmacs' [Tango OpenOffice](http://www.gnome-look.org/content/show.php/Tango+OpenOffice?content=54799)
-*/
-
-var MooEditable = new Class({
-
- Implements: [Events, Options],
-
- options: {
- toolbar: true,
- cleanup: true,
- paragraphise: true,
- xhtml : true,
- semantics : true,
- actions: 'bold italic underline strikethrough | insertunorderedlist insertorderedlist indent outdent | undo redo | createlink unlink | urlimage | toggleview',
- handleSubmit: true,
- handleLabel: true,
- baseCSS: 'html{ height: 100%; cursor: text } body{ font-family: sans-serif; border: 0; }',
- extraCSS: '',
- externalCSS: '',
- html: '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><style>{BASECSS} {EXTRACSS}</style>{EXTERNALCSS}</head><body>{CONTENT}</body></html>'
- },
-
- initialize: function(el, options){
- this.setOptions(options);
- this.textarea = $(el);
- this.textarea.store('MooEditable', this);
- this.actions = this.options.actions.clean().split(' ');
- this.keys = {};
- this.dialogs = {};
- this.actions.each(function(action){
- var act = MooEditable.Actions[action];
- if (!act) return;
- if (act.options){
- var key = act.options.shortcut;
- if (key) this.keys[key] = action;
- }
- if (act.dialogs){
- $each(act.dialogs, function(dialog, name){
- dialog = dialog.attempt(this);
- dialog.name = action + ':' + name;
- if ($type(this.dialogs[action]) != 'object') this.dialogs[action] = {};
- this.dialogs[action][name] = dialog;
- }, this);
- }
- if (act.events){
- $each(act.events, function(fn, event){
- this.addEvent(event, fn);
- }, this);
- }
- }.bind(this));
- this.render();
- },
-
- toElement: function(){
- return this.textarea;
- },
-
- render: function(){
- var self = this;
-
- // Dimensions
- var dimensions = this.textarea.getSize();
-
- // Build the container
- this.container = new Element('div', {
- id: (this.textarea.id) ? this.textarea.id + '-mooeditable-container' : null,
- 'class': 'mooeditable-container',
- styles: {
- width: dimensions.x
- }
- });
-
- // Override all textarea styles
- this.textarea.addClass('mooeditable-textarea').setStyle('height', dimensions.y);
-
- // Build the iframe
- this.iframe = new IFrame({
- 'class': 'mooeditable-iframe',
- src: 'javascript:""', // Workaround for HTTPs warning in IE6/7
- styles: {
- height: dimensions.y
- }
- });
-
- this.toolbar = new MooEditable.UI.Toolbar({
- onItemAction: function(){
- var args = $splat(arguments);
- var item = args[0];
- self.action(item.name, args);
- }
- });
- this.attach.delay(1, this);
-
- // Update the event for textarea's corresponding labels
- if (this.options.handleLabel && this.textarea.id) $$('label[for="'+this.textarea.id+'"]').addEvent('click', function(e){
- if (self.mode != 'iframe') return;
- e.preventDefault();
- self.focus();
- });
-
- // Update & cleanup content before submit
- if (this.options.handleSubmit){
- this.form = this.textarea.getParent('form');
- if (!this.form) return;
- this.form.addEvent('submit', function(){
- if (self.mode == 'iframe') self.saveContent();
- });
- }
-
- this.fireEvent('render', this);
- },
-
- attach: function(){
- var self = this;
-
- // Assign view mode
- this.mode = 'iframe';
-
- // Editor iframe state
- this.editorDisabled = false;
-
- // Put textarea inside container
- this.container.wraps(this.textarea);
-
- this.textarea.setStyle('display', 'none');
-
- this.iframe.setStyle('display', '').inject(this.textarea, 'before');
-
- $each(this.dialogs, function(action, name){
- $each(action, function(dialog){
- $(dialog).inject(self.iframe, 'before');
- var range;
- dialog.addEvents({
- open: function(){
- range = self.selection.getRange();
- self.editorDisabled = true;
- self.toolbar.disable(name);
- self.fireEvent('dialogOpen', this);
- },
- close: function(){
- self.toolbar.enable();
- self.editorDisabled = false;
- self.focus();
- if (range) self.selection.setRange(range);
- self.fireEvent('dialogClose', this);
- }
- });
- });
- });
-
- // contentWindow and document references
- this.win = this.iframe.contentWindow;
- this.doc = this.win.document;
-
- // Build the content of iframe
- var docHTML = this.options.html.substitute({
- BASECSS: this.options.baseCSS,
- EXTRACSS: this.options.extraCSS,
- EXTERNALCSS: (this.options.externalCSS) ? '<link rel="stylesheet" href="' + this.options.externalCSS + '">': '',
- CONTENT: this.cleanup(this.textarea.get('value'))
- });
- this.doc.open();
- this.doc.write(docHTML);
- this.doc.close();
-
- // Turn on Design Mode
- // IE fired load event twice if designMode is set
- (Browser.Engine.trident) ? this.doc.body.contentEditable = true : this.doc.designMode = 'On';
-
- // Mootoolize window, document and body
- if (!this.win.$family) new Window(this.win);
- if (!this.doc.$family) new Document(this.doc);
- $(this.doc.body);
-
- // Bind all events
- this.doc.addEvents({
- mouseup: this.editorMouseUp.bind(this),
- mousedown: this.editorMouseDown.bind(this),
- contextmenu: this.editorContextMenu.bind(this),
- click: this.editorClick.bind(this),
- dbllick: this.editorDoubleClick.bind(this),
- keypress: this.editorKeyPress.bind(this),
- keyup: this.editorKeyUp.bind(this),
- keydown: this.editorKeyDown.bind(this)
- });
- this.textarea.addEvent('keypress', this.textarea.retrieve('mooeditable:textareaKeyListener', this.keyListener.bind(this)));
-
- // Fix window focus event not firing on Firefox 2
- if (Browser.Engine.gecko && Browser.Engine.version == 18) this.doc.addEvent('focus', function(){
- self.win.fireEvent('focus').focus();
- });
-
- // styleWithCSS, not supported in IE and Opera
- if (!(/trident|presto/i).test(Browser.Engine.name)){
- var styleCSS = function(){
- self.execute('styleWithCSS', false, false);
- self.doc.removeEvent('focus', styleCSS);
- };
- this.win.addEvent('focus', styleCSS);
- }
-
- if (this.options.toolbar){
- $(this.toolbar).inject(this.container, 'top');
- this.toolbar.render(this.actions);
- }
-
- this.selection = new MooEditable.Selection(this.win);
-
- this.fireEvent('attach', this);
-
- return this;
- },
-
- detach: function(){
- this.saveContent();
- this.textarea.setStyle('display', '').removeClass('mooeditable-textarea').inject(this.container, 'before');
- this.textarea.removeEvent('keypress', this.textarea.retrieve('mooeditable:textareaKeyListener'));
- this.container.dispose();
- this.fireEvent('detach', this);
- return this;
- },
-
- editorMouseUp: function(e){
- if (this.editorDisabled){
- e.stop();
- return;
- }
-
- if (this.options.toolbar) this.checkStates();
-
- this.fireEvent('editorMouseUp', [e, this]);
- },
-
- editorMouseDown: function(e){
- if (this.editorDisabled){
- e.stop();
- return;
- }
-
- this.fireEvent('editorMouseDown', [e, this]);
- },
-
- editorContextMenu: function(e){
- if (this.editorDisabled){
- e.stop();
- return;
- }
-
- this.fireEvent('editorContextMenu', [e, this]);
- },
-
- editorClick: function(e){
- // make images selectable and draggable in Safari
- if (Browser.Engine.webkit){
- var el = e.target;
- if (el.get('tag') == 'img'){
- this.selection.selectNode(el);
- }
- }
-
- this.fireEvent('editorClick', [e, this]);
- },
-
- editorDoubleClick: function(e){
- this.fireEvent('editorDoubleClick', [e, this]);
- },
-
- editorKeyPress: function(e){
- if (this.editorDisabled){
- e.stop();
- return;
- }
-
- this.keyListener(e);
-
- this.fireEvent('editorKeyPress', [e, this]);
- },
-
- editorKeyUp: function(e){
- if (this.editorDisabled){
- e.stop();
- return;
- }
-
- if (this.options.toolbar) this.checkStates();
-
- this.fireEvent('editorKeyUp', [e, this]);
- },
-
- editorKeyDown: function(e){
- if (this.editorDisabled){
- e.stop();
- return;
- }
-
- this.fireEvent('editorKeyDown', [e, this]);
-
- if (e.key == 'enter'){
- if (this.options.paragraphise){
- if (e.shift && Browser.Engine.webkit){
- var s = this.selection;
- var r = s.getRange();
-
- // Insert BR element
- var br = this.doc.createElement('br');
- r.insertNode(br);
-
- // Place caret after BR
- r.setStartAfter(br);
- r.setEndAfter(br);
- s.setRange(r);
-
- // Could not place caret after BR then insert an nbsp entity and move the caret
- if (s.getSelection().focusNode == br.previousSibling){
- var nbsp = this.doc.createTextNode('\u00a0');
- var p = br.parentNode;
- var ns = br.nextSibling;
- (ns) ? p.insertBefore(nbsp, ns) : p.appendChild(nbsp);
- s.selectNode(nbsp);
- s.collapse(1);
- }
-
- // Scroll to new position, scrollIntoView can't be used due to bug: http://bugs.webkit.org/show_bug.cgi?id=16117
- this.win.scrollTo(0, Element.getOffsets(s.getRange().startContainer).y);
-
- e.preventDefault();
- } else if (Browser.Engine.gecko || Browser.Engine.webkit){
- var node = this.selection.getNode();
- var blockEls = /^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD)$/;
- var isBlock = node.getParents().include(node).some(function(el){
- return el.nodeName.test(blockEls);
- });
- if (!isBlock) this.execute('insertparagraph');
- }
- } else {
- if (Browser.Engine.trident){
- var r = this.selection.getRange();
- var node = this.selection.getNode();
- if (r && node.get('tag') != 'li'){
- this.selection.insertContent('<br>');
- this.selection.collapse(false);
- }
- e.preventDefault();
- }
- }
- }
- },
-
- keyListener: function(e){
- var key = (Browser.Platform.mac) ? e.meta : e.control;
- if (!key || !this.keys[e.key]) return;
- e.preventDefault();
- var item = this.toolbar.getItem(this.keys[e.key]);
- item.action(e);
- },
-
- focus: function(){
- (this.mode == 'iframe' ? this.win : this.textarea).focus();
- this.fireEvent('focus', this);
- return this;
- },
-
- action: function(command, args){
- var action = MooEditable.Actions[command];
- if (action.command && $type(action.command) == 'function'){
- action.command.run(args, this);
- } else {
- this.focus();
- this.execute(command, false, args);
- if (this.mode == 'iframe') this.checkStates();
- }
- },
-
- execute: function(command, param1, param2){
- if (this.busy) return;
- this.busy = true;
- this.doc.execCommand(command, param1, param2);
- this.saveContent();
- this.busy = false;
- return false;
- },
-
- toggleView: function(){
- this.fireEvent('beforeToggleView', this);
- if (this.mode == 'textarea'){
- this.mode = 'iframe';
- this.iframe.setStyle('display', '');
- this.setContent(this.textarea.value);
- this.textarea.setStyle('display', 'none');
- } else {
- this.saveContent();
- this.mode = 'textarea';
- this.textarea.setStyle('display', '');
- this.iframe.setStyle('display', 'none');
- }
- this.fireEvent('toggleView', this);
- this.focus.delay(10, this);
- return this;
- },
-
- getContent: function(){
- return this.cleanup(this.doc.body.get('html'));
- },
-
- setContent: function(newContent){
- this.doc.body.set('html', newContent);
- return this;
- },
-
- saveContent: function(){
- if (this.mode == 'iframe') this.textarea.set('value', this.getContent());
- return this;
- },
-
- checkStates: function(){
- this.actions.each(function(action){
- var item = this.toolbar.getItem(action);
- if (!item) return;
- item.deactivate();
-
- var states = MooEditable.Actions[action]['states'];
- if (!states) return;
-
- var el = this.selection.getNode();
- if (!el) return;
-
- // custom checkState
- if ($type(states) == 'function'){
- states.attempt(el, item);
- return;
- }
-
- try{
- if (this.doc.queryCommandState(action)){
- item.activate();
- return;
- }
- } catch(e) {}
-
- if (states.tags){
- do {
- if ($type(el) != 'element') break;
- var tag = el.tagName.toLowerCase();
- if (states.tags.contains(tag)){
- item.activate(tag);
- break;
- }
- }
- while ((el = el.parentNode));
- }
-
- if (states.css){
- var blockEls = /^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD)$/;
- do {
- if ($type(el) != 'element') break;
- var found = false;
- for (var prop in states.css){
- var css = states.css[prop];
- if ($(el).getStyle(prop).contains(css)){
- item.activate(css);
- found = true;
- }
- }
- if (found || el.tagName.test(blockEls)) break;
- }
- while ((el = el.parentNode));
- }
- }.bind(this));
- },
-
- cleanup: function(source){
- if (!this.options.cleanup) return source.trim();
-
- do {
- var oSource = source;
-
- // Webkit cleanup
- source = source.replace(/<br class\="webkit-block-placeholder">/gi, "<br />");
- source = source.replace(/<span class="Apple-style-span">(.*)<\/span>/gi, '$1');
- source = source.replace(/ class="Apple-style-span"/gi, '');
- source = source.replace(/<span style="">/gi, '');
-
- // Remove padded paragraphs
- source = source.replace(/<p>\s*<br ?\/?>\s*<\/p>/gi, '<p>\u00a0</p>');
- source = source.replace(/<p>(&nbsp;|\s)*<\/p>/gi, '<p>\u00a0</p>');
- if (!this.options.semantics){
- source = source.replace(/\s*<br ?\/?>\s*<\/p>/gi, '</p>');
- }
-
- // Replace improper BRs (only if XHTML : true)
- if (this.options.xhtml){
- source = source.replace(/<br>/gi, "<br />");
- }
-
- if (this.options.semantics){
- //remove divs from <li>
- if (Browser.Engine.trident){
- source = source.replace(/<li>\s*<div>(.+?)<\/div><\/li>/g, '<li>$1</li>');
- }
- //remove stupid apple divs
- if (Browser.Engine.webkit){
- source = source.replace(/^([\w\s]+.*?)<div>/i, '<p>$1</p><div>');
- source = source.replace(/<div>(.+?)<\/div>/ig, '<p>$1</p>');
- }
-
- //<p> tags around a list will get moved to after the list
- if (['gecko', 'presto', 'webkit'].contains(Browser.Engine.name)){
- //not working properly in safari?
- source = source.replace(/<p>[\s\n]*(<(?:ul|ol)>.*?<\/(?:ul|ol)>)(.*?)<\/p>/ig, '$1<p>$2</p>');
- source = source.replace(/<\/(ol|ul)>\s*(?!<(?:p|ol|ul|img).*?>)((?:<[^>]*>)?\w.*)$/g, '</$1><p>$2</p>');
- }
-
- source = source.replace(/<br[^>]*><\/p>/g, '</p>'); //remove <br>'s that end a paragraph here.
- source = source.replace(/<p>\s*(<img[^>]+>)\s*<\/p>/ig, '$1\n'); //if a <p> only contains <img>, remove the <p> tags
-
- //format the source
- source = source.replace(/<p([^>]*)>(.*?)<\/p>(?!\n)/g, '<p$1>$2</p>\n'); //break after paragraphs
- source = source.replace(/<\/(ul|ol|p)>(?!\n)/g, '</$1>\n'); //break after </p></ol></ul> tags
- source = source.replace(/><li>/g, '>\n\t<li>'); //break and indent <li>
- source = source.replace(/([^\n])<\/(ol|ul)>/g, '$1\n</$2>'); //break before </ol></ul> tags
- source = source.replace(/([^\n])<img/ig, '$1\n<img'); //move images to their own line
- source = source.replace(/^\s*$/g, ''); //delete empty lines in the source code (not working in opera)
- }
-
- // Remove leading and trailing BRs
- source = source.replace(/<br ?\/?>$/gi, '');
- source = source.replace(/^<br ?\/?>/gi, '');
-
- // Remove useless BRs
- source = source.replace(/><br ?\/?>/gi, '>');
-
- // Remove BRs right before the end of blocks
- source = source.replace(/<br ?\/?>\s*<\/(h1|h2|h3|h4|h5|h6|li|p)/gi, '</$1');
-
- // Semantic conversion
- source = source.replace(/<span style="font-weight: bold;">(.*)<\/span>/gi, '<strong>$1</strong>');
- source = source.replace(/<span style="font-style: italic;">(.*)<\/span>/gi, '<em>$1</em>');
- source = source.replace(/<b\b[^>]*>(.*?)<\/b[^>]*>/gi, '<strong>$1</strong>');
- source = source.replace(/<i\b[^>]*>(.*?)<\/i[^>]*>/gi, '<em>$1</em>');
- source = source.replace(/<u\b[^>]*>(.*?)<\/u[^>]*>/gi, '<span style="text-decoration: underline;">$1</span>');
-
- // Replace uppercase element names with lowercase
- source = source.replace(/<[^> ]*/g, function(match){return match.toLowerCase();});
-
- // Replace uppercase attribute names with lowercase
- source = source.replace(/<[^>]*>/g, function(match){
- match = match.replace(/ [^=]+=/g, function(match2){return match2.toLowerCase();});
- return match;
- });
-
- // Put quotes around unquoted attributes
- source = source.replace(/<[^>]*>/g, function(match){
- match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
- return match;
- });
-
- //make img tags xhtml compatable
- // if (this.options.xhtml){
- // source = source.replace(/(<(?:img|input)[^/>]*)>/g, '$1 />');
- // }
-
- //remove double <p> tags and empty <p> tags
- source = source.replace(/<p>(?:\s*)<p>/g, '<p>');
- source = source.replace(/<\/p>\s*<\/p>/g, '</p>');
-
- // Final trim
- source = source.trim();
- }
- while (source != oSource);
-
- return source;
- }
-
-});
-
-MooEditable.Selection = new Class({
-
- initialize: function(win){
- this.win = win;
- },
-
- getSelection: function(){
- this.win.focus();
- return (this.win.getSelection) ? this.win.getSelection() : this.win.document.selection;
- },
-
- getRange: function(){
- var s = this.getSelection();
-
- if (!s) return null;
-
- try {
- return s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : null);
- } catch(e) {
- // IE bug when used in frameset
- return this.doc.body.createTextRange();
- }
- },
-
- setRange: function(range){
- if (range.select){
- $try(function(){
- range.select();
- });
- } else {
- var s = this.getSelection();
- if (s.addRange){
- s.removeAllRanges();
- s.addRange(range);
- }
- }
- },
-
- selectNode: function(node, collapse){
- var r = this.getRange();
- var s = this.getSelection();
-
- if (r.moveToElementText){
- $try(function(){
- r.moveToElementText(node);
- r.select();
- });
- } else if (s.addRange){
- collapse ? r.selectNodeContents(node) : r.selectNode(node);
- s.removeAllRanges();
- s.addRange(r);
- } else {
- s.setBaseAndExtent(node, 0, node, 1);
- }
-
- return node;
- },
-
- isCollapsed: function(){
- var r = this.getRange();
- if (r.item) return false;
- return r.boundingWidth == 0 || this.getSelection().isCollapsed;
- },
-
- collapse: function(toStart){
- var r = this.getRange();
- var s = this.getSelection();
-
- if (r.select){
- r.collapse(toStart);
- r.select();
- } else {
- toStart ? s.collapseToStart() : s.collapseToEnd();
- }
- },
-
- getContent: function(){
- var r = this.getRange();
- var body = new Element('body');
-
- if (this.isCollapsed()) return '';
-
- if (r.cloneContents){
- body.appendChild(r.cloneContents());
- } else if ($defined(r.item) || $defined(r.htmlText)){
- body.set('html', r.item ? r.item(0).outerHTML : r.htmlText);
- } else {
- body.set('html', r.toString());
- }
-
- var content = body.get('html');
- return content;
- },
-
- getText : function(){
- var r = this.getRange();
- var s = this.getSelection();
-
- return this.isCollapsed() ? '' : r.text || (s.toString ? s.toString() : '');
- },
-
- getNode: function(){
- var r = this.getRange();
-
- if (!Browser.Engine.trident){
- var el = null;
-
- if (r){
- el = r.commonAncestorContainer;
-
- // Handle selection a image or other control like element such as anchors
- if (!r.collapsed)
- if (r.startContainer == r.endContainer)
- if (r.startOffset - r.endOffset < 2)
- if (r.startContainer.hasChildNodes())
- el = r.startContainer.childNodes[r.startOffset];
-
- while ($type(el) != 'element') el = el.parentNode;
- }
-
- return $(el);
- }
-
- return $(r.item ? r.item(0) : r.parentElement());
- },
-
- insertContent: function(content){
- if (Browser.Engine.trident){
- var r = this.getRange();
- r.pasteHTML(content);
- r.collapse(false);
- r.select();
- } else {
- this.win.document.execCommand('insertHTML', false, content);
- }
- }
-
-});
-
-MooEditable.UI = {};
-
-MooEditable.UI.Toolbar= new Class({
-
- Implements: [Events, Options],
-
- options: {
- /*
- onItemAction: $empty,
- */
- 'class': ''
- },
-
- initialize: function(options){
- this.setOptions(options);
- this.el = new Element('div', {'class': 'mooeditable-ui-toolbar ' + this.options['class']});
- this.items = {};
- this.content = null;
- },
-
- toElement: function(){
- return this.el;
- },
-
- render: function(actions){
- if (this.content){
- this.el.adopt(this.content);
- } else {
- this.content = actions.map(function(action){
- return (action == '|') ? this.addSeparator() : this.addItem(action);
- }.bind(this));
- }
- return this;
- },
-
- addItem: function(action){
- var self = this;
- var act = MooEditable.Actions[action];
- if (!act) return;
- var type = act.type || 'button';
- var options = act.options || {};
- var item = new MooEditable.UI[type.camelCase().capitalize()]($extend(options, {
- name: action,
- 'class': action + '-item toolbar-item',
- title: act.title,
- onAction: self.itemAction.bind(self)
- }));
- this.items[action] = item;
- $(item).inject(this.el);
- return item;
- },
-
- getItem: function(action){
- return this.items[action];
- },
-
- addSeparator: function(){
- return new Element('span', {'class': 'toolbar-separator'}).inject(this.el);
- },
-
- itemAction: function(){
- this.fireEvent('itemAction', arguments);
- },
-
- disable: function(except){
- $each(this.items, function(item){
- (item.name == except) ? item.activate() : item.deactivate().disable();
- });
- return this;
- },
-
- enable: function(){
- $each(this.items, function(item){
- item.enable();
- });
- return this;
- },
-
- show: function(){
- this.el.setStyle('display', '');
- return this;
- },
-
- hide: function(){
- this.el.setStyle('display', 'none');
- return this;
- }
-
-});
-
-MooEditable.UI.Button = new Class({
-
- Implements: [Events, Options],
-
- options: {
- /*
- onAction: $empty,
- */
- title: '',
- name: '',
- text: 'Button',
- 'class': '',
- shortcut: '',
- mode: 'icon'
- },
-
- initialize: function(options){
- this.setOptions(options);
- this.name = this.options.name;
- this.render();
- },
-
- toElement: function(){
- return this.el;
- },
-
- render: function(){
- var self = this;
- var key = (Browser.Platform.mac) ? 'Cmd' : 'Ctrl';
- var shortcut = (this.options.shortcut) ? ' ( ' + key + '+' + this.options.shortcut.toUpperCase() + ' )' : '';
- var text = this.options.title || name;
- var title = text + shortcut;
- this.el = new Element('button', {
- 'class': 'mooeditable-ui-button ' + self.options['class'],
- title: title,
- html: '<span class="button-icon"></span><span class="button-text">' + text + '</span>',
- events: {
- click: self.click.bind(self),
- mousedown: function(e){ e.preventDefault(); }
- }
- });
- if (this.options.mode != 'icon') this.el.addClass('mooeditable-ui-button-' + this.options.mode);
-
- this.active = false;
- this.disabled = false;
-
- // add hover effect for IE
- if (Browser.Engine.trident) this.el.addEvents({
- mouseenter: function(e){ this.addClass('hover'); },
- mouseleave: function(e){ this.removeClass('hover'); }
- });
-
- return this;
- },
-
- click: function(e){
- e.preventDefault();
- if (this.disabled) return;
- this.action(e);
- },
-
- action: function(){
- this.fireEvent('action', [this].concat($A(arguments)));
- },
-
- enable: function(){
- if (this.active) this.el.removeClass('onActive');
- if (!this.disabled) return;
- this.disabled = false;
- this.el.removeClass('disabled').set({
- disabled: false,
- opacity: 1
- });
- return this;
- },
-
- disable: function(){
- if (this.disabled) return;
- this.disabled = true;
- this.el.addClass('disabled').set({
- disabled: true,
- opacity: 0.4
- });
- return this;
- },
-
- activate: function(){
- if (this.disabled) return;
- this.active = true;
- this.el.addClass('onActive');
- return this;
- },
-
- deactivate: function(){
- this.active = false;
- this.el.removeClass('onActive');
- return this;
- }
-
-});
-
-MooEditable.UI.Dialog = new Class({
-
- Implements: [Events, Options],
-
- options:{
- /*
- onOpen: $empty,
- onClose: $empty,
- */
- 'class': '',
- contentClass: ''
- },
-
- initialize: function(html, options){
- this.setOptions(options);
- this.html = html;
-
- var self = this;
- this.el = new Element('div', {
- 'class': 'mooeditable-ui-dialog ' + self.options['class'],
- html: '<div class="dialog-content ' + self.options.contentClass + '">' + html + '</div>',
- styles: {
- 'display': 'none'
- },
- events: {
- click: self.click.bind(self)
- }
- });
- },
-
- toElement: function(){
- return this.el;
- },
-
- click: function(){
- this.fireEvent('click', arguments);
- return this;
- },
-
- open: function(){
- this.el.setStyle('display', '');
- this.fireEvent('open', this);
- return this;
- },
-
- close: function(){
- this.el.setStyle('display', 'none');
- this.fireEvent('close', this);
- return this;
- }
-
-});
-
-MooEditable.UI.AlertDialog = function(alertText){
- if (!alertText) return;
- var html = alertText + ' <button class="dialog-ok-button">OK</button>';
- return new MooEditable.UI.Dialog(html, {
- 'class': 'mooeditable-alert-dialog',
- onOpen: function(){
- var button = this.el.getElement('.dialog-ok-button');
- (function(){
- button.focus();
- }).delay(10);
- },
- onClick: function(e){
- e.preventDefault();
- if (e.target.tagName.toLowerCase() != 'button') return;
- if ($(e.target).hasClass('dialog-ok-button')) this.close();
- }
- });
-};
-
-MooEditable.UI.PromptDialog = function(questionText, answerText, fn){
- if (!questionText) return;
- var html = '<label class="dialog-label">' + questionText
- + ' <input type="text" class="text dialog-input" value="' + answerText + '">'
- + '</label> <button class="dialog-button dialog-ok-button">OK</button>'
- + '<button class="dialog-button dialog-cancel-button">Cancel</button>';
- return new MooEditable.UI.Dialog(html, {
- 'class': 'mooeditable-prompt-dialog',
- onOpen: function(){
- var input = this.el.getElement('.dialog-input');
- (function(){
- input.focus();
- input.select();
- }).delay(10);
- },
- onClick: function(e){
- e.preventDefault();
- if (e.target.tagName.toLowerCase() != 'button') return;
- var button = $(e.target);
- var input = this.el.getElement('.dialog-input');
- if (button.hasClass('dialog-cancel-button')){
- input.set('value', answerText);
- this.close();
- } else if (button.hasClass('dialog-ok-button')){
- var answer = input.get('value');
- input.set('value', answerText);
- this.close();
- if (fn) fn.attempt(answer, this);
- }
- }
- });
-};
-
-MooEditable.Actions = new Hash({
-
- bold: {
- title: 'Bold',
- options: {
- shortcut: 'b'
- },
- states: {
- tags: ['b', 'strong'],
- css: {'font-weight': 'bold'}
- }
- },
-
- italic: {
- title: 'Italic',
- options: {
- shortcut: 'i'
- },
- states: {
- tags: ['i', 'em'],
- css: {'font-style': 'italic'}
- }
- },
-
- underline: {
- title: 'Underline',
- options: {
- shortcut: 'u'
- },
- states: {
- tags: ['u'],
- css: {'text-decoration': 'underline'}
- }
- },
-
- strikethrough: {
- title: 'Strikethrough',
- options: {
- shortcut: 's'
- },
- states: {
- tags: ['s', 'strike'],
- css: {'text-decoration': 'line-through'}
- }
- },
-
- insertunorderedlist: {
- title: 'Unordered List',
- states: {
- tags: ['ul']
- }
- },
-
- insertorderedlist: {
- title: 'Ordered List',
- states: {
- tags: ['ol']
- }
- },
-
- indent: {
- title: 'Indent',
- states: {
- tags: ['blockquote']
- }
- },
-
- outdent: {
- title: 'Outdent'
- },
-
- undo: {
- title: 'Undo',
- options: {
- shortcut: 'z'
- }
- },
-
- redo: {
- title: 'Redo',
- options: {
- shortcut: 'y'
- }
- },
-
- unlink: {
- title: 'Remove Hyperlink'
- },
-
- createlink: {
- title: 'Add Hyperlink',
- options: {
- shortcut: 'l'
- },
- states: {
- tags: ['a']
- },
- dialogs: {
- alert: MooEditable.UI.AlertDialog.pass('Please select the text you wish to hyperlink.'),
- prompt: function(editor){
- return MooEditable.UI.PromptDialog('Enter URL', 'http://', function(url){
- editor.execute('createlink', false, url.trim());
- });
- }
- },
- command: function(){
- if (this.selection.isCollapsed()){
- this.dialogs.createlink.alert.open();
- } else {
- var text = this.selection.getText();
- var url = /^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i;
- var prompt = this.dialogs.createlink.prompt;
- if (url.test(text)) prompt.el.getElement('.mooeditable-dialog-input').set('value', text);
- prompt.open();
- }
- }
- },
-
- urlimage: {
- title: 'Add Image',
- options: {
- shortcut: 'm'
- },
- dialogs: {
- prompt: function(editor){
- return MooEditable.UI.PromptDialog('Enter image URL', 'http://', function(url){
- editor.execute("insertimage", false, url.trim());
- });
- }
- },
- command: function(){
- this.dialogs.urlimage.prompt.open();
- }
- },
-
- toggleview: {
- title: 'Toggle View',
- command: function(){
- (this.mode == 'textarea') ? this.toolbar.enable() : this.toolbar.disable('toggleview');
- this.toggleView();
- }
- }
-
-});
-
-MooEditable.Actions.Settings = {};
-
-Element.Properties.mooeditable = {
-
- set: function(options){
- return this.eliminate('mooeditable').store('mooeditable:options', options);
- },
-
- get: function(options){
- if (options || !this.retrieve('mooeditable')){
- if (options || !this.retrieve('mooeditable:options')) this.set('mooeditable', options);
- this.store('mooeditable', new MooEditable(this, this.retrieve('mooeditable:options')));
- }
- return this.retrieve('mooeditable');
- }
-
-};
-
-Element.implement({
-
- mooEditable: function(options){
- return this.get('mooeditable', options);
- }
-
-});
View
4 media/js/pycow.js
@@ -48,7 +48,9 @@ len = function (obj) {
* If the argument is a string, the return value is the same object.
*/
str = function (obj) {
- if ($defined(obj.__str__))
+ if (!$defined(obj))
+ return "null";
+ else if ($defined(obj.__str__))
return obj.__str__();
else if ($type(obj) == "number")
return String(obj);
View
52 pygowave_client/cache/model/model.js
@@ -454,7 +454,7 @@ pygowave.model = (function() {
this._properties.set("fields", new Hash());
var fields = this._properties.get("fields");
fields.update(delta);
- for (var __iter0_ = new _Iterator(this._properties); __iter0_.hasNext();) {
+ for (var __iter0_ = new _Iterator(fields); __iter0_.hasNext();) {
var value = __iter0_.next();
var key = __iter0_.key();
if (value == null)
@@ -614,6 +614,25 @@ pygowave.model = (function() {
},
/**
+ * Returns the Elements between the start and end index.
+ *
+ * @function {public Element[]} elementsWithin
+ * @param {int} start Start index
+ * @param {int} end End index
+ */
+ elementsWithin: function (start, end) {
+ var lst = [];
+ for (var __iter0_ = new XRange(len(this._elements)); __iter0_.hasNext();) {
+ var i = __iter0_.next();
+ var elt = this._elements[i];
+ if (elt.position() >= start && elt.position() < end)
+ lst.append(elt);
+ }
+ delete __iter0_;
+ return lst;
+ },
+
+ /**
* Returns all Elements of this Blip.
*
* @function {public Element[]} allElements
@@ -798,7 +817,8 @@ pygowave.model = (function() {
checkSync: function (sum) {
if (this._outofsync)
return false;
- if (sha_constructor(this._content.encode("utf-8")).hexdigest() != sum) {
+ var mysum = sha_constructor(this._content.encode("utf-8")).hexdigest();
+ if (mysum != sum) {
this.fireEvent("outOfSync");
this._outofsync = true;
return false;
@@ -1095,6 +1115,34 @@ pygowave.model = (function() {
this._setStatus("clean");
else
this._setStatus("invalid");
+ },
+
+ /**
+ * Apply the operations on the wavelet.
+ *
+ * @function {public} applyOperations
+ * @param {pygowave.operations.Operation[]} ops List of operations to apply
+ */
+ applyOperations: function (ops) {
+ for (var __iter0_ = new _Iterator(ops); __iter0_.hasNext();) {
+ var op = __iter0_.next();
+ if (op.blipId != "") {
+ var blip = this.blipById(op.blipId);
+ if (op.type == pygowave.operations.DOCUMENT_DELETE)
+ blip.deleteText(op.index, op.property);
+ else if (op.type == pygowave.operations.DOCUMENT_INSERT)
+ blip.insertText(op.index, op.property);
+ else if (op.type == pygowave.operations.DOCUMENT_ELEMENT_DELETE)
+ blip.deleteElement(op.index);
+ else if (op.type == pygowave.operations.DOCUMENT_ELEMENT_INSERT)
+ blip.insertElement(op.index, op.property.type, op.property.properties);
+ else if (op.type == pygowave.operations.DOCUMENT_ELEMENT_DELTA)
+ blip.applyElementDelta(op.index, op.property);
+ else if (op.type == pygowave.operations.DOCUMENT_ELEMENT_SETPREF)
+ blip.setElementUserpref(op.index, op.property.key, op.property.value);
+ }
+ }
+ delete __iter0_;
}
});
View
78 pygowave_client/cache/operations/operations.js
@@ -62,25 +62,25 @@ pygowave.operations = (function() {
*
* @constructor {public} initialize
* @param {String} op_type Type of operation
- * @param {String} wave_id The id of the wave that this operation is to
+ * @param {String} waveId The id of the wave that this operation is to
* be applied.
- * @param {String} wavelet_id The id of the wavelet that this operation is
+ * @param {String} waveletId The id of the wavelet that this operation is
* to be applied.
- * @param {optional String} blip_id The optional id of the blip that this
+ * @param {optional String} blipId The optional id of the blip that this
* operation is to be applied.
* @param {optional int} index Optional integer index for content-based
* operations.
* @param {optional Object} prop A weakly typed property object is based
* on the context of this operation.
*/
- initialize: function (op_type, wave_id, wavelet_id, blip_id, index, prop) {
- if (!$defined(blip_id)) blip_id = "";
+ initialize: function (op_type, waveId, waveletId, blipId, index, prop) {
+ if (!$defined(blipId)) blipId = "";
if (!$defined(index)) index = -1;
if (!$defined(prop)) prop = null;
this.type = op_type;
- this.wave_id = wave_id;
- this.wavelet_id = wavelet_id;
- this.blip_id = blip_id;
+ this.waveId = waveId;
+ this.waveletId = waveletId;
+ this.blipId = blipId;
this.index = index;
this.property = prop;
},
@@ -91,7 +91,7 @@ pygowave.operations = (function() {
* @function {public Boolean} clone
*/
clone: function () {
- return new Operation(this.type, this.wave_id, this.wavelet_id, this.blip_id, this.index, this.property);
+ return new Operation(this.type, this.waveId, this.waveletId, this.blipId, this.index, this.property);
},
/**
@@ -115,7 +115,7 @@ pygowave.operations = (function() {
* @param {Operation} other_op
*/
isCompatibleTo: function (other_op) {
- if (this.wave_id != other_op.wave_id || this.wavelet_id != other_op.wavelet_id || this.blip_id != this.blip_id)
+ if (this.waveId != other_op.waveId || this.waveletId != other_op.waveletId || this.blipId != this.blipId)
return false;
return true;
},
@@ -179,23 +179,23 @@ pygowave.operations = (function() {
},
/**
- * Serialize this operation into a dictionary.
+ * Serialize this operation into a dictionary. Official robots API format.
*
* @function {public String} serialize
*/
serialize: function () {
return {
type: this.type,
- wave_id: this.wave_id,
- wavelet_id: this.wavelet_id,
- blip_id: this.blip_id,
+ waveId: this.waveId,
+ waveletId: this.waveletId,
+ blipId: this.blipId,
index: this.index,
property: this.property
};
},
__repr__: function () {
- return "%s(\"%s\",%d,%s)".sprintf(this.type.lower(), this.blip_id, this.index, repr(this.property));
+ return "%s(\"%s\",%d,%s)".sprintf(this.type.lower(), this.blipId, this.index, repr(this.property));
}
});
/**
@@ -204,7 +204,7 @@ pygowave.operations = (function() {
* @function {public static Operation} unserialize
*/
Operation.unserialize = function (obj) {
- return new Operation(obj.type, obj.wave_id, obj.wavelet_id, obj.blip_id, obj.index, obj.property);
+ return new Operation(obj.type, obj.waveId, obj.waveletId, obj.blipId, obj.index, obj.property);
};
/**
@@ -254,12 +254,12 @@ pygowave.operations = (function() {
* Initializes the op manager with a wave and wavelet ID.
*
* @constructor {public} initialize
- * @param {String} wave_id The ID of the wave
- * @param {String} wavelet_id The ID of the wavelet
+ * @param {String} waveId The ID of the wave
+ * @param {String} waveletId The ID of the wavelet
*/
- initialize: function (wave_id, wavelet_id) {
- this.wave_id = wave_id;
- this.wavelet_id = wavelet_id;
+ initialize: function (waveId, waveletId) {
+ this.waveId = waveId;
+ this.waveletId = waveletId;
this.operations = [];
},
@@ -584,37 +584,37 @@ pygowave.operations = (function() {
* Requests to insert content into a document at a specific location.
*
* @function {public} documentInsert
- * @param {String} blip_id The blip id that this operation is applied to
+ * @param {String} blipId The blip id that this operation is applied to
* @param {int} index The position insert the content at in ths document
* @param {String} content The content to insert
*/
- documentInsert: function (blip_id, index, content) {
- this.__insert(new Operation(DOCUMENT_INSERT, this.wave_id, this.wavelet_id, blip_id, index, content));
+ documentInsert: function (blipId, index, content) {
+ this.__insert(new Operation(DOCUMENT_INSERT, this.waveId, this.waveletId, blipId, index, content));
},
/**
* Requests to delete content in a given range.
*
* @function {public} documentDelete
- * @param {String} blip_id The blip id that this operation is applied to
+ * @param {String} blipId The blip id that this operation is applied to
* @param {int} start Start of the range
* @param {int} end End of the range
*/
- documentDelete: function (blip_id, start, end) {
- this.__insert(new Operation(DOCUMENT_DELETE, this.wave_id, this.wavelet_id, blip_id, start, end - start));
+ documentDelete: function (blipId, start, end) {
+ this.__insert(new Operation(DOCUMENT_DELETE, this.waveId, this.waveletId, blipId, start, end - start));
},
/**
* Requests to insert an element at the given position.
*
* @function {public} documentElementInsert
- * @param {String} blip_id The blip id that this operation is applied to
+ * @param {String} blipId The blip id that this operation is applied to
* @param {int} index Position of the new element
* @param {String} type Element type
* @param {Object} properties Element properties
*/
- documentElementInsert: function (blip_id, index, type, properties) {
- this.__insert(new Operation(DOCUMENT_ELEMENT_INSERT, this.wave_id, this.wavelet_id, blip_id, index, {
+ documentElementInsert: function (blipId, index, type, properties) {
+ this.__insert(new Operation(DOCUMENT_ELEMENT_INSERT, this.waveId, this.waveletId, blipId, index, {
type: type,
properties: properties
}));
@@ -624,36 +624,36 @@ pygowave.operations = (function() {
* Requests to delete an element from the given position.
*
* @function {public} documentElementDelete
- * @param {String} blip_id The blip id that this operation is applied to
+ * @param {String} blipId The blip id that this operation is applied to
* @param {int} index Position of the element to delete
*/
- documentElementDelete: function (blip_id, index) {
- this.__insert(new Operation(DOCUMENT_ELEMENT_DELETE, this.wave_id, this.wavelet_id, blip_id, index, null));
+ documentElementDelete: function (blipId, index) {
+ this.__insert(new Operation(DOCUMENT_ELEMENT_DELETE, this.waveId, this.waveletId, blipId, index, null));
},
/**
* Requests to apply a delta to the element at the given position.
*
* @function {public} documentElementDelta
- * @param {String} blip_id The blip id that this operation is applied to
+ * @param {String} blipId The blip id that this operation is applied to
* @param {int} index Position of the element
* @param {Object} delta Delta to apply to the element
*/
- documentElementDelta: function (blip_id, index, delta) {
- this.__insert(new Operation(DOCUMENT_ELEMENT_DELTA, this.wave_id, this.wavelet_id, blip_id, index, delta));
+ documentElementDelta: function (blipId, index, delta) {
+ this.__insert(new Operation(DOCUMENT_ELEMENT_DELTA, this.waveId, this.waveletId, blipId, index, delta));
},
/**
* Requests to set a UserPref of the element at the given position.
*
* @function {public} documentElementSetpref
- * @param {String} blip_id The blip id that this operation is applied to
+ * @param {String} blipId The blip id that this operation is applied to
* @param {int} index Position of the element
* @param {Object} key Name of the UserPref
* @param {Object} value Value of the UserPref
*/
- documentElementSetpref: function (blip_id, index, key, value) {
- this.__insert(new Operation(DOCUMENT_ELEMENT_SETPREF, this.wave_id, this.wavelet_id, blip_id, index, {
+ documentElementSetpref: function (blipId, index, key, value) {
+ this.__insert(new Operation(DOCUMENT_ELEMENT_SETPREF, this.waveId, this.waveletId, blipId, index, {
key: key,
value: value
}));
View
BIN pygowave_client/locale/de/LC_MESSAGES/djangojs.mo
Binary file not shown.
View
226 pygowave_client/locale/de/LC_MESSAGES/djangojs.po
@@ -3,11 +3,12 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
+#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-06-16 11:46+0200\n"
+"POT-Creation-Date: 2009-08-27 12:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,34 +17,221 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Language: de_DE\n"
-#: pygowave-client.js:43
+#: controller/controller.js:156
+#, fuzzy
+
+#, perl-format
+msgid "The connection was lost.<br/><br/>Error code: %d"
+msgstr "Die Verbindung wurde getrennt.<br/><br/>Fehlercode: %d"
+
+#: controller/controller.js:167
+#, fuzzy
+
+#, perl-format
+msgid "A connection error occured.<br/><br/>Error code: %d"
+msgstr "Ein Verbindungsfehler ist aufgetreten.<br/><br/>Fehlercode: %d"
+
+#: view/blip_editor.js:241
+msgid ""
+"Sorry, but this Blip Editor has gone out of sync with the internal "
+"representation. Please click resync."
+msgstr ""
+"Es tut uns leid, aber dieser Blip-Editor ist nicht mehr synchron mit der "
+"internen Darstellung. Bitte klicke auf \"Resync\"."
+
+#: view/blip_editor.js:242
+msgid "Resync"
+msgstr "Resync"
+
+#: view/blip_editor.js:247
+msgid ""
+"The text content could not be rendered correctly. This may be a bug or you "
+"are using an unsupported browser."
+msgstr ""
+"Der Text konnte nicht korrekt gerendert werden. Dies kann ein Programmfehler "
+"sein oder du verwendest einen nicht unterstützten Browser."
+
+#: view/blip_editor.js:248
+msgid "Dismiss"
+msgstr "Ausblenden"
+
+#: view/blip_editor.js:254
+msgid ""
+"Unfortunately, this Blip has gone out of sync with the server. You have to "
+"reload the page to be able to use it again."
+msgstr ""
+"Unglücklicherweise ist dieser Blip nicht mehr synchron zum Server. Du musst "
+"die Seite neu laden, um ihn wieder verwenden zu können."
+
+#: view/blip_editor.js:255
+msgid "Reload"
+msgstr "Neu laden"
+
+#: view/debug_tools.js:95
+msgid "Operations Viewer (Debug)"
+msgstr "Operations Viewer (Debug)"
+
+#: view/debug_tools.js:156
+msgid "Unblock"
+msgstr "Unblock"
+
+#: view/debug_tools.js:160
+msgid "Block"
+msgstr "Block"
+
+#: view/debug_tools.js:345
+msgid "Status: Waiting for acknowledgement"
+msgstr "Status: Warte auf Bestätigung"
+
+#: view/debug_tools.js:349
+msgid "Status: Document in sync with server"
+msgstr "Status: Dokument ist synchron zum Server"
+
+#: view/debug_tools.js:353
+msgid "Status: Document not in sync with server"
+msgstr "Status: Dokument ist nicht synchron zum Server"
+
+#: view/debug_tools.js:366
+#, fuzzy
+
+#, perl-format
+msgid "Position: %d"
+msgstr "Position: %d"
+
+#: view/debug_tools.js:368
+#, fuzzy
+
+#, perl-format
+msgid "Selected: %d-%d"
+msgstr "Auswahl: %d-%d"
+
+#: view/gadgets.js:53
+msgid "Choose a Gadget from the list below:"
+msgstr "Wähle ein Gadget aus der Liste:"
+
+#: view/gadgets.js:63 view/participants.js:223
msgid "Cancel"
msgstr "Abbrechen"
-#: pygowave-client.js:48
+#: view/gadgets.js:64 view/participants.js:224 view/view.js:474
msgid "OK"
msgstr "OK"
-#: pygowave-client.js:50
-msgid "Please search and select a participant from the list."
-msgstr "Bitte suche und wähle dann einen Teilnehmer aus der Liste."
+#: view/gadgets.js:67 view/view.js:205
+msgid "Add Gadget"
+msgstr "Gadget hinzufügen"
-#: pygowave-client.js:65
+#: view/gadgets.js:86 view/gadgets.js.py:176
+msgid "Loading..."
+msgstr "Bitte warten..."
+
+#: view/gadgets.js:113
+msgid "You must choose a gadget from the list first."
+msgstr "Du musst zu erst ein Gadget aus der Liste wählen."
+
+#: view/gadgets.js:113 view/participants.js:280
+msgid "Notice"
+msgstr "Hinweis"
+
+#: view/gadgets.js:133
+msgid "(Please choose...)"
+msgstr "(Bitte wählen...)"
+
+#: view/gadgets.js:160 view/gadgets.js.py:164
+msgid "Description"
+msgstr "Beschreibung"
+
+#: view/gadgets.js:164
+#, fuzzy
+
+#, perl-format
+msgid "Uploaded by %s"
+msgstr "Hochgeladen von %s"
+
+#: view/gadgets.js:278
+#, fuzzy
+
+#, perl-format
+msgid "Gadget #%d at index %d says:"
+msgstr "Gadget #%d bei Index %d sagt:"
+
+#: view/participants.js:230 view/participants.js.py:417
msgid "Add participant"
msgstr "Teilnehmer hinzufügen"
-#: pygowave-client.js:65
-msgid "Search"
-msgstr "Suche"
+#: view/participants.js:280
+msgid "You must select a participant from your search results first."
+msgstr ""
+"Du musst zu erst einen Teilnehmer aus deinen Suchergebnissen auswählen."
+
+#: view/participants.js:393
+#, fuzzy
-#: pygowave-client.js:108
+#, perl-format
+msgid "Please enter at least %d letters."
+msgstr "Bitte mindestens %d Buchstaben eingeben."
+
+#: view/selection.js:357
msgid ""
-"Do you really want to leave the Wave?\n"
-"\n"
-"Warning: If you do so, you cannot come back\n"
-"to this wave unless someone adds you again."
+"Internet Explorer bug:\n"
+"Could not create Selection object from TextRange!"
msgstr ""
-"Willst du die Wave wirklich verlassen?\n"
-"\n"
-"Warnung: Wenn du das tust kannst du nicht mehr zu dieser\n"
-"Wave zurückkehren, es sei denn, jemand fügt dich wieder hinzu."
+"Internet Explorer Bug:\n"
+"Konnte kein Selection-Objekt aus TextRange erstellen!"
+
+#: view/view.js:206
+msgid "Add a gadget to the blip"
+msgstr "Füge dem Blip ein Gadget hinzu"
+
+#: view/view.js:439
+msgid "Shit happens..."
+msgstr "Dumm gelaufen..."
+
+#: view/view.js:440
+msgid "Oh well"
+msgstr "Tja..."
+
+#: view/view.js:453
+msgid ""
+"Do you really want to leave the Wave?<br/>\n"
+"<br/>\n"
+"Warning: If you do so, you cannot come back to this wave unless someone adds "
+"you again."
+msgstr ""
+"Willst du das Wave wirklich verlassen?<br/>\n"
+"<br/>\n"
+"Warnung: Wenn du das tust, kannst du nicht mehr zu diesem Wave zurückkehren, "
+"bis dich jemand wieder hinzufügt."
+
+#: view/view.js:454
+msgid "Please confirm"
+msgstr "Bitte bestätigen"
+
+#: view/view.js:496
+msgid "Yes"
+msgstr "Ja"
+
+#: view/view.js:498
+msgid "No"
+msgstr "Nein"
+
+#: view/view.js:582
+msgid "The WaveletWidget for Wavelet '%s' was not found."
+msgstr "Das WaveletWidget für Wavelet '%s' wurde nicht gefunden."
+
+#: view/view.js:583
+msgid "Sorry, but..."
+msgstr "Entschuldigung, aber..."
+
+#: view/view.js:584
+msgid "I see"
+msgstr "Ach so"
+
+#: view/view.js:591
+msgid "You must be inside of a Blip to add a Gadget."
+msgstr "Du musst dich innerhalb eines Blips befinden, um ein Gadget hinzuzufügen."
+
+#: view/view.js:600
+msgid "You must place your cursor inside the text to mark the Gadget's insertion point."
+msgstr "Du musst deinen Cursor innerhalb des Textes platzieren, um den Einfügepunkt des Gadgets zu markieren."
+
View
37 pygowave_client/src/controller/controller.js
@@ -440,38 +440,19 @@ pygowave.controller = $defined(pygowave.controller) ? pygowave.controller : new
var delta = new pygowave.operations.OpManager(wavelet.waveId(), wavelet.id());
delta.unserialize(serial_ops);
+ var ops = new Array();
+
// Iterate over all operations
for (var incoming = new _Iterator(delta.operations); incoming.hasNext(); ) {
// Transform pending operations, iterate over results
- for (var tr1 = new _Iterator(mpending.transform(incoming.next())); tr1.hasNext(); ) {
- // Transform cached operations, iterate over results
- for (var tr2 = new _Iterator(mcached.transform(tr1.next())); tr2.hasNext(); ) {
- var op = tr2.next();
- if (op.isNull()) continue;
- // Apply operation
- switch (op.type) {
- case pygowave.operations.DOCUMENT_INSERT:
- wavelet.blipById(op.blip_id).insertText(op.index, op.property);
- break;
- case pygowave.operations.DOCUMENT_DELETE:
- wavelet.blipById(op.blip_id).deleteText(op.index, op.property);
- break;
- case pygowave.operations.DOCUMENT_ELEMENT_INSERT:
- wavelet.blipById(op.blip_id).insertElement(op.index, op.property.type, op.property.properties);
- break;
- case pygowave.operations.DOCUMENT_ELEMENT_DELETE:
- wavelet.blipById(op.blip_id).deleteElement(op.index);
- break;
- case pygowave.operations.DOCUMENT_ELEMENT_DELTA:
- wavelet.blipById(op.blip_id).applyElementDelta(op.index, op.property);
- break;
- case pygowave.operations.DOCUMENT_ELEMENT_SETPREF:
- wavelet.blipById(op.blip_id).setElementUserpref(op.index, op.property.key, op.property.value);
- break;
- }
- }
+ for (var tr = new _Iterator(mpending.transform(incoming.next())); tr.hasNext(); ) {
+ // Transform cached operations, save results
+ ops.extend(mcached.transform(tr.next()));
}
}
+
+ // Apply operations