locomotive-aloha-rails 0.20.1.2 → 0.20.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/Rakefile +1 -1
  2. data/lib/aloha/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/aloha/css/aloha.css +3 -0
  4. data/vendor/assets/javascripts/aloha/css/ext-aloha.css +3 -0
  5. data/vendor/assets/javascripts/aloha/lib/aloha-bootstrap.js +4565 -3934
  6. data/vendor/assets/javascripts/aloha/lib/aloha.js +1357 -702
  7. data/vendor/assets/javascripts/aloha/lib/aloha/command.js +16 -13
  8. data/vendor/assets/javascripts/aloha/lib/aloha/core.js +23 -3
  9. data/vendor/assets/javascripts/aloha/lib/aloha/ecma5shims.js +23 -7
  10. data/vendor/assets/javascripts/aloha/lib/aloha/editable.js +57 -14
  11. data/vendor/assets/javascripts/aloha/lib/aloha/engine.js +9 -5
  12. data/vendor/assets/javascripts/aloha/lib/aloha/floatingmenu.js +288 -96
  13. data/vendor/assets/javascripts/aloha/lib/aloha/jquery.js +11 -1
  14. data/vendor/assets/javascripts/aloha/lib/aloha/markup.js +318 -40
  15. data/vendor/assets/javascripts/aloha/lib/aloha/repositorymanager.js +11 -10
  16. data/vendor/assets/javascripts/aloha/lib/aloha/selection.js +20 -1
  17. data/vendor/assets/javascripts/aloha/lib/aloha/sidebar.js +11 -1
  18. data/vendor/assets/javascripts/aloha/lib/jquery-plugin.js +10 -7
  19. data/vendor/assets/javascripts/aloha/lib/util/dom.js +18 -6
  20. data/vendor/assets/javascripts/aloha/lib/util/range.js +6 -6
  21. data/vendor/assets/javascripts/aloha/lib/vendor/ext-3.2.1/ext-all-debug.js +26 -2
  22. data/vendor/assets/javascripts/aloha/lib/vendor/jquery.store.js +39 -15
  23. data/vendor/assets/javascripts/aloha/plugins/common/abbr/lib/abbr-plugin.js +1 -0
  24. data/vendor/assets/javascripts/aloha/plugins/common/align/lib/align-plugin.js +344 -334
  25. data/vendor/assets/javascripts/aloha/plugins/common/block/css/block.css +65 -12
  26. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/block-plugin.js +12 -15
  27. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/block.js +796 -180
  28. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/blockcontenthandler.js +54 -13
  29. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/blockmanager.js +315 -78
  30. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/editor.js +111 -8
  31. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/editormanager.js +2 -0
  32. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/jquery-ui-1.8.16.custom.min.js +198 -0
  33. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/sidebarattributeeditor.js +7 -20
  34. data/vendor/assets/javascripts/aloha/plugins/common/characterpicker/lib/characterpicker-plugin.js +15 -3
  35. data/vendor/assets/javascripts/aloha/plugins/common/contenthandler/lib/sanitizecontenthandler.js +3 -2
  36. data/vendor/assets/javascripts/aloha/plugins/common/contenthandler/lib/wordcontenthandler.js +111 -5
  37. data/vendor/assets/javascripts/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml-plugin.js +29 -0
  38. data/vendor/assets/javascripts/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml.js +306 -0
  39. data/vendor/assets/javascripts/aloha/plugins/common/format/lib/format-plugin.js +59 -5
  40. data/vendor/assets/javascripts/aloha/plugins/common/format/nls/i18n.js +1 -1
  41. data/vendor/assets/javascripts/aloha/plugins/common/horizontalruler/lib/horizontalruler-plugin.js +18 -3
  42. data/vendor/assets/javascripts/aloha/plugins/common/image/img/crop-buttons.gif +0 -0
  43. data/vendor/assets/javascripts/aloha/plugins/common/image/lib/image-plugin.js +1629 -1601
  44. data/vendor/assets/javascripts/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.css +11 -0
  45. data/vendor/assets/javascripts/aloha/plugins/common/link/extra/linklist.js +8 -6
  46. data/vendor/assets/javascripts/aloha/plugins/common/link/lib/link-plugin.js +26 -10
  47. data/vendor/assets/javascripts/aloha/plugins/common/list/nls/de/i18n.js +5 -1
  48. data/vendor/assets/javascripts/aloha/plugins/common/paste/lib/paste-plugin.js +3 -4
  49. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-cell.js +13 -12
  50. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-plugin.js +108 -61
  51. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-selection.js +61 -1
  52. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table.js +1 -0
  53. data/vendor/assets/javascripts/aloha/plugins/common/table/nls/de/i18n.js +28 -1
  54. data/vendor/assets/javascripts/aloha/plugins/common/table/nls/i18n.js +36 -10
  55. data/vendor/assets/javascripts/aloha/plugins/extra/browser/css/browser.jqgrid.css +292 -292
  56. data/vendor/assets/javascripts/aloha/plugins/extra/browser/lib/browser.js +28 -5
  57. data/vendor/assets/javascripts/aloha/plugins/extra/browser/lib/locale.js +2 -2
  58. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/grid.locale.de.js +6 -1
  59. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/grid.locale.en.js +5 -0
  60. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/jquery.jqGrid.js +5 -0
  61. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/jquery.jstree.js +6 -1
  62. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/jquery.ui.js +6 -1
  63. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/ui-layout.js +6 -1
  64. data/vendor/assets/javascripts/aloha/plugins/extra/cite/lib/cite-plugin.js +18 -4
  65. data/vendor/assets/javascripts/aloha/plugins/extra/formatlesspaste/lib/formatlesspaste-plugin.js +1 -1
  66. data/vendor/assets/javascripts/aloha/plugins/extra/linkbrowser/lib/linkbrowser-plugin.js +14 -2
  67. data/vendor/assets/javascripts/aloha/plugins/extra/numerated-headers/demo/js/aloha-config.js +2 -2
  68. data/vendor/assets/javascripts/aloha/plugins/extra/toc/lib/toc-plugin.js +382 -0
  69. data/vendor/assets/javascripts/aloha/plugins/extra/toc/nls/de/i18n.js +3 -0
  70. data/vendor/assets/javascripts/aloha/plugins/extra/toc/nls/i18n.js +4 -0
  71. metadata +15 -11
  72. data/vendor/assets/javascripts/aloha/plugins/extra/toc/i18n/de.json +0 -1
  73. data/vendor/assets/javascripts/aloha/plugins/extra/toc/i18n/en.json +0 -1
  74. data/vendor/assets/javascripts/aloha/plugins/extra/toc/src/toc.js +0 -350
@@ -14,13 +14,22 @@ function(jQuery, ContentHandlerManager, BlockManager) {
14
14
  * @class Special block content handler
15
15
  *
16
16
  * The blog content handler handles pasting of blocks in editables. Pasted
17
- * block markup will be replaced by a freshly rendered block instance.
17
+ * block markup will be replaced by a newly created block instance.
18
18
  */
19
19
  var BlockContentHandler = ContentHandlerManager.createHandler(
20
20
  /** @lends block.BlockContentHandler */
21
21
  {
22
22
  /**
23
23
  * Handle the pasting. Remove all unwanted stuff.
24
+ *
25
+ * There are two main cases which we need to distinguish:
26
+ * 1) Aloha Blocks are selected, and crtl+c is pressed then. In this case, *only the block* is copied / pasted.
27
+ * 2) Text is selected, but the selection also spans an aloha block.
28
+ *
29
+ * Generally, case 2) seems to work without bigger problems in Webkit / Firefox, while
30
+ * case 1) results in very much undesired and inconsistent behavior. If 1) happens,
31
+ * the property "data-aloha-block-copy-only-block" is set to "true"; so we can kick in and
32
+ * do additional cleanups.
24
33
  * @param {jQuery} content
25
34
  */
26
35
  handleContent: function( content ) {
@@ -30,27 +39,59 @@ function(jQuery, ContentHandlerManager, BlockManager) {
30
39
  content = jQuery( '<div>' ).append(content);
31
40
  }
32
41
 
42
+ if (content.find('.aloha-block[data-aloha-block-copy-only-block="true"]').length > 0) {
43
+ // We are in case 1; so some more cleanup is needed (at least in webkit and firefox).
44
+
45
+ // Webkit seems to *duplicate* the block when copying. The duplicated
46
+ // block has *no ID property* set, that's how we can find and discard it.
47
+ // Very ugly!
48
+ content.find('.aloha-block:not([id])').remove();
49
+ // Further cleanup for Webkit, removing empty nodes. Quite hacky!
50
+ content.find('.aloha-block + span:empty').remove();
51
+ content.find('div:empty').remove();
52
+ // (another) Hack for Webkit, removing superfluous BR
53
+ content.find('br.Apple-interchange-newline').remove();
54
+
55
+ // Firefox adds a <br> directly before the .aloha-block...
56
+ content.find('.aloha-block').prev('br').remove();
57
+
58
+ // Chrome (at least) sometimes adds an empty <br> inside an (otherwise empty) span
59
+ content.find('div > br:only-child').parent().remove();
60
+
61
+ }
62
+
33
63
  content.find('.aloha-block').each(function() {
34
64
  var oldBlock = jQuery(this);
35
65
 
36
- // TODO: use block.serialize();
66
+ var elementAttributes = {}; // all attributes except data-*
67
+ var blockAttributes = {}; // all data* attributes
68
+ jQuery.each(oldBlock[0].attributes, function(k, v) {
69
+ if (v.nodeName === 'id') return;
70
+
71
+ if (v.nodeName.match(/^data-/)) {
72
+ blockAttributes[v.nodeName.substr(5)] = v.nodeValue;
73
+ } else {
74
+ elementAttributes[v.nodeName] = v.nodeValue;
75
+ }
76
+ });
37
77
 
38
- var dataAttributes = {};
39
- jQuery.each(oldBlock.data(), function(k, v) {
40
- dataAttributes['data-' + k] = v;
41
- })
78
+ var newBlockId = GENTICS.Utils.guid();
42
79
 
43
80
  var newBlock = jQuery('<' + this.tagName + '/>')
44
- .attr(jQuery.extend({
45
- about: oldBlock.attr('about'),
46
- 'class': oldBlock.attr('class')
47
- }, dataAttributes))
48
- .removeClass('aloha-block-active');
81
+ .attr(elementAttributes)
82
+ .attr('id', newBlockId)
83
+ .removeClass('aloha-block-active')
84
+ .removeClass('aloha-block')
85
+ .html(oldBlock.html());
49
86
 
50
87
  oldBlock.replaceWith(newBlock);
51
- BlockManager._blockify(newBlock);
88
+
89
+ // We need to blockify the contents with a timeout, as we need the connected DOM node for it.
90
+ window.setTimeout(function() {
91
+ BlockManager._blockify(jQuery('#' + newBlockId), blockAttributes);
92
+ }, 50);
52
93
  });
53
-
94
+
54
95
  return content.html();
55
96
  }
56
97
  });
@@ -13,6 +13,8 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
13
13
  GENTICS = window.GENTICS;
14
14
 
15
15
  /**
16
+ * This is the block manager, which is the central entity for maintaining the lifecycle of blocks.
17
+ *
16
18
  * @name block.blockmanager
17
19
  * @class Block manager singleton
18
20
  */
@@ -32,8 +34,11 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
32
34
  * @param {AbstractBlock} the block to be deleted
33
35
  */
34
36
 
37
+ /**
38
+ * Default settings for blocks
39
+ */
35
40
  defaults: {
36
- 'block-type': 'DefaultBlock'
41
+ 'aloha-block-type': 'DefaultBlock'
37
42
  },
38
43
 
39
44
  /**
@@ -48,37 +53,47 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
48
53
  */
49
54
  blocks: null,
50
55
 
51
- activeBlocks: null,
56
+ /**
57
+ * Array of currently highlighted blocks
58
+ * @type Array
59
+ */
60
+ _highlightedBlocks: null,
61
+
62
+ /**
63
+ * Reference to the currently active block, if any
64
+ * @type AbstractBlock
65
+ */
66
+ _activeBlock: null,
52
67
 
68
+ /**************************
69
+ * SECTION: Initialization
70
+ **************************/
53
71
  /**
72
+ * Constructor. called immediately.
73
+ *
54
74
  * @constructor
55
75
  */
56
76
  _constructor: function() {
57
77
  FloatingMenu.createScope('Aloha.Block');
58
78
  this.blockTypes = new Registry();
59
79
  this.blocks = new Registry();
60
- this.activeBlocks = {};
80
+ this._highlightedBlocks = {};
61
81
  },
62
82
 
63
83
  /**
64
- * Register initial event handlers
84
+ * Register initial event handlers. Called from block-plugin when plugin
85
+ * is loaded.
65
86
  *
66
87
  * @private
67
88
  */
68
89
  registerEventHandlers: function() {
69
90
  var that = this;
91
+ this._registerEventHandlersForDeactivatingAlohaBlock();
92
+ this._registerEventHandlersForDeterminingCurrentlyActiveBlock();
93
+ this._registerEventHandlersForBlockDeletion();
94
+ this._registerEventHandlersForCutCopyPaste();
70
95
 
71
- // Register event handlers for deactivating an Aloha Block
72
- jQuery(document).bind('click', function(event) {
73
- if (that.activeBlocks == {}) return;
74
- if (jQuery(event.target).parents('.aloha-sidebar-bar, .aloha-block-do-not-deactivate, .aloha-floatingmenu').length > 0
75
- || jQuery(event.target).is('.aloha-sidebar-bar, .aloha-block-do-not-deactivate, .aloha-floatingmenu')) {
76
- // If we are inside the sidebar, the floating menu or other elements which should not trigger the block deactivation, we do an early return.
77
- return;
78
- }
79
- BlockManager._deactivateActiveBlocks();
80
- });
81
-
96
+ // TODO: not sure if we still need the code below. it is somehow related to caret handling
82
97
  Aloha.bind('aloha-selection-changed', function(evt, selection, originalEvent) {
83
98
  // the following line is needed to de-select blocks when navigating over them using the mouse cursors.
84
99
  // We only want to execute it though, if we are not inside a block, as it would otherwise
@@ -86,64 +101,276 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
86
101
  if (selection && jQuery(selection.getCommonAncestorContainer()).parents('.aloha-block').length > 0) {
87
102
  return;
88
103
  }
89
- that._deactivateActiveBlocks();
104
+ that._deactivateHighlightedBlocks();
90
105
  });
91
106
  },
92
107
 
93
108
  /**
94
- * Blockify a given element with the instance defaults
95
- * Directly called when one does jQuery.alohaBlock(instanceDefaults)
96
- *
97
- * @private
109
+ * Register the event handlers which deactivate aloha blocks when the user clicks outside a block
98
110
  */
99
- _blockify: function(element, instanceDefaults) {
100
- var attributes, block;
101
- element = jQuery(element);
111
+ _registerEventHandlersForDeactivatingAlohaBlock: function() {
112
+ var that = this;
102
113
 
103
- // TODO: check if object is already Block-ified
114
+ jQuery(document).bind('click', function(event) {
115
+ if (that._highlightedBlocks == {}) return;
116
+ if (jQuery(event.target).closest('.aloha-sidebar-bar, .aloha-block-do-not-deactivate, .aloha-floatingmenu, .aloha-block').length > 0) {
117
+ // If we are inside the sidebar, the floating menu or other elements which should not trigger the block deactivation, we do an early return.
118
+ return;
119
+ }
120
+ that._deactivateHighlightedBlocks();
121
+ });
122
+ },
123
+
124
+ /**
125
+ * Register the event handler which listens to block-selection-change, and
126
+ * sets _activeBlock accordingly.
127
+ */
128
+ _registerEventHandlersForDeterminingCurrentlyActiveBlock: function() {
129
+ var that = this;
130
+ this.bind('block-selection-change', function(highlightedBlocks) {
131
+ if (highlightedBlocks.length > 0) {
132
+ that._activeBlock = highlightedBlocks[0];
133
+ } else {
134
+ that._activeBlock = null;
135
+ }
136
+ });
137
+ },
104
138
 
105
- attributes = this.getConfig(element, instanceDefaults);
139
+ /**
140
+ * Implementation of block deletions, both when the block is the only selected element,
141
+ * and when the block is part of a bigger selection which should be deleted.
142
+ */
143
+ _registerEventHandlersForBlockDeletion: function() {
144
+ var that = this;
106
145
 
107
- element.contentEditable(false);
146
+ // This case executes in:
147
+ // - Chrome
148
+ // - Firefox
149
+ // - IE9
150
+ // - IE7+8 for inline blocks and for block-level blocks which are part of a bigger selection
151
+ // it does NOT execute in the following cases:
152
+ // - IE7+8 for block-level blocks which are NOT part of a bigger selection. This case is handled separately below.
153
+ Aloha.bind('aloha-command-will-execute', function(e, data) {
154
+ var commandId = data.commandId;
155
+
156
+ // Internet Explorer *magically* sets the range to the "Body" object after deselecting everything. yeah :-D
157
+ var onlyBlockSelected = (Aloha.getSelection().getRangeCount() === 0) // Firefox / Chrome
158
+ || (Aloha.getSelection().getRangeCount() === 1 && Aloha.getSelection().getRangeAt(0).endContainer === Aloha.getSelection().getRangeAt(0).startContainer && Aloha.getSelection().getRangeAt(0).endContainer === jQuery('body')[0]) // Internet explorer: Inline Elements
159
+ || (Aloha.getSelection().getRangeCount() === 1 && Aloha.getSelection().getRangeAt(0).endContainer === Aloha.getSelection().getRangeAt(0).startContainer && Aloha.getSelection().getRangeAt(0).startOffset + 1 === Aloha.getSelection().getRangeAt(0).endOffset); // Internet explorer: Block level elements
160
+
161
+ if (that._activeBlock && (commandId === 'delete' || commandId === 'forwarddelete') && onlyBlockSelected) {
162
+ // Deletion when a block is currently selected
163
+
164
+ // In this case, the default command shall not be executed.
165
+ data.preventDefault = true;
166
+ that._activeBlock.destroy();
167
+ } else if (!that._activeBlock && (commandId === 'delete' || commandId === 'forwarddelete') && Aloha.getSelection().getRangeCount() === 1 && Aloha.getSelection().getRangeAt(0).collapsed === false) {
168
+ // Deletion when a block is inside a bigger selection currently
169
+ // In this case, we check if we find an aloha-block. If yes, we delete it right away as the browser does not delete it correctly by default
170
+ var traverseSelectionTree;
171
+ traverseSelectionTree = function(selectionTree) {
172
+ var el;
173
+ for (var i=0, l=selectionTree.length; i<l; i++) {
174
+ el = selectionTree[i];
175
+ if (el.domobj.nodeType === 1) { // DOM node
176
+ var $el = jQuery(el.domobj);
177
+ if (el.selection === 'full' && $el.is('.aloha-block')) {
178
+ $el.remove();
179
+ } else {
180
+ traverseSelectionTree(el.children);
181
+ }
182
+ }
183
+ }
184
+ };
185
+ traverseSelectionTree(Aloha.Selection.getSelectionTree());
186
+ }
187
+ });
108
188
 
109
- if (!this.blockTypes.has(attributes['block-type'])) {
110
- Aloha.Log.error('block/blockmanager', 'Block Type ' + attributes['block-type'] + ' not found!');
111
- return;
112
- }
189
+ // - IE7/8 Workaround
190
+ // - deletion of blocks inside block collection
191
+ jQuery(window.document).keydown(function(e) {
113
192
 
114
- block = new (this.blockTypes.get(attributes['block-type']))(element);
115
- block.element.addClass('aloha-block-' + attributes['block-type']);
193
+ // Pressing DEL or BACKSPACE in a sidebar attribute editor form input
194
+ // causes the destruction of the block;
195
+ // if the keypress comes from a form element do nothing
196
+ if ( typeof e.srcElement !== 'undefined' && typeof e.srcElement.form !== 'undefined' ) {
197
+ return true;
198
+ }
116
199
 
117
- // Save attributes on block, but ignore jquery attribute.
118
- jQuery.each(attributes, function(k, v) {
119
- if (k.indexOf('jQuery') === 0) return;
120
- block.attr(k, v, true);
200
+ // If a block is active AND DEL or BACKSPACE key pressed, AND we are not inside a nested editable (FIX for IE7/8)
201
+ if (that._activeBlock && (e.which === 46 || e.which === 8) && that._activeBlock._isInsideNestedEditable === false) {
202
+ // ...and active block is INSIDE editable
203
+
204
+ // BROWSER QUIRK WORKAROUND
205
+ // - IE7+IE8 for block-level blocks which are NOT part of a bigger selection.
206
+ // TODO as we're going to remove Ext this browser checks should be made with jQuery
207
+ if ((Ext.isIE8 || Ext.isIE7) && that._activeBlock.$element.parents('.aloha-editable,.aloha-block').first().hasClass('aloha-editable')) {
208
+ that._activeBlock.destroy();
209
+ e.preventDefault();
210
+ return false;
211
+ } else if(that._activeBlock.shouldDestroy()) {
212
+ // .. in this case, the block should be destroyed because it
213
+ // is part of a block collection.
214
+
215
+ that._activeBlock.destroy();
216
+ e.preventDefault();
217
+ return false;
218
+ }
219
+ }
121
220
  });
221
+ },
122
222
 
123
- // Remove the attributes from the child element, as they have been moved to the parent element.
124
- jQuery.each(element.data(), function(k, v) {
125
- element.removeAttr('data-' + k);
223
+ /**
224
+ * Implementation of cut/copy; selecting the currently active block.
225
+ *
226
+ * When pasting, the blockcontenthandler is triggered. This takes care of the pasting process.
227
+ */
228
+ _registerEventHandlersForCutCopyPaste: function() {
229
+ var that = this,
230
+ currentlyCopying = false,
231
+ currentlyCutting = false,
232
+ selectionBeforeCopying = null;
233
+
234
+ jQuery(window.document).keydown(function(e) {
235
+ // IF: Ctrl/Command C pressed -- COPY
236
+ if (that._activeBlock && (e.ctrlKey || e.metaKey) && e.which === 67) {
237
+ currentlyCopying = true;
238
+ //selectionBeforeCopying = new GENTICS.Utils.RangeObject(true);
239
+ that._activeBlock.$element.attr('data-aloha-block-copy-only-block', 'true');
240
+ GENTICS.Utils.Dom.selectDomNode(that._activeBlock.$element[0]);
241
+ }
242
+
243
+ // IF: Ctrl/Command X pressed -- CUT
244
+ if (that._activeBlock && (e.ctrlKey || e.metaKey) && e.which === 88) {
245
+ currentlyCutting = true;
246
+ //selectionBeforeCopying = new GENTICS.Utils.RangeObject(true);
247
+ that._activeBlock.$element.attr('data-aloha-block-copy-only-block', 'true');
248
+ GENTICS.Utils.Dom.selectDomNode(that._activeBlock.$element[0]);
249
+ }
126
250
  });
127
- element.removeAttr('about');
251
+ jQuery(window.document).keyup(function(e) {
252
+ // IF: Release of ctrl / command C
253
+ if (!currentlyCutting && currentlyCopying && (e.which === 67 || e.which === 18 || e.which === 91)) {
254
+ currentlyCopying = false;
255
+ that._activeBlock.$element.removeAttr('data-aloha-block-copy-only-block');
256
+ if (selectionBeforeCopying) {
257
+ //selectionBeforeCopying.select();
258
+ selectionBeforeCopying = null;
259
+ }
260
+ }
261
+ // IF: Release of ctrl / command X
262
+ if (currentlyCutting && (e.which === 67 || e.which === 18 || e.which === 88)) {
263
+ currentlyCutting = false;
264
+ }
265
+ });
266
+ },
128
267
 
129
- // Register block
130
- this.blocks.register(block.getId(), block);
268
+ /**
269
+ * Initialize Block Level Drag/Drop for all editables. We need to do this
270
+ * inside the Block Manager, as we want all editables to become possible
271
+ * drop targets for block-level aloha blocks.
272
+ */
273
+ initializeBlockLevelDragDrop: function() {
274
+ var that = this;
275
+ jQuery.each(Aloha.editables, function(i, editable) {
276
+ that.createBlockLevelSortableForEditableOrBlockCollection(editable.obj);
277
+ });
278
+ Aloha.bind('aloha-editable-created', function(e, editable) {
279
+ that.createBlockLevelSortableForEditableOrBlockCollection(editable.obj);
280
+ });
281
+ },
131
282
 
132
- block._renderAndSetContent();
283
+ /**
284
+ * We make editables or block collections sortable using jQuery UI here, if we
285
+ * did not do this before.
286
+ *
287
+ * This is an internal method a user should never call!
288
+ */
289
+ createBlockLevelSortableForEditableOrBlockCollection: function($editableOrBlockCollection) {
290
+ if (!$editableOrBlockCollection.hasClass('aloha-block-blocklevel-sortable')) {
291
+
292
+ // We only want to make "block-level" aloha blocks sortable. According to the docs,
293
+ // sortable.cancel should have a CSS selector and if this matches, the element is only
294
+ // a drop target but NOT draggable. However, passing :not(.aloha-block) does not work somehow :-(
295
+ //
296
+ // Thus, we implemented the following alternative:
297
+ // Every "block-level" aloha block drag handle gets a new CSS class, and we only select this as
298
+ // drag handle. As only "block-level" aloha blocks have this CSS class, this will also only make
299
+ // aloha blocks draggable.
300
+ $editableOrBlockCollection.addClass('aloha-block-blocklevel-sortable').sortable({
301
+ revert: 100,
302
+ handle: '.aloha-block-draghandle-blocklevel',
303
+ connectWith: '.aloha-block-blocklevel-sortable' // we want to be able to drag an element to other editables
304
+ });
305
+
306
+
307
+ // Hack for Internet Explorer 8:
308
+ // If you first click inside an editable, and THEN want to drag a block-level block,
309
+ // it sometimes occurs that the *whole editable* is selected and should be dragged away.
310
+ // This breaks dragging of Aloha Blocks.
311
+ // Bugfix: We disable the "ondragstart" event on every editable.
312
+ // However, as the "ondragstart" is also fired when a nested (inline) editable is moved using drag/drop,
313
+ // we need to allow this case.
314
+ $editableOrBlockCollection.get(0).ondragstart = function (e, ui) {
315
+ if (!ui || !ui.helper || !ui.helper.is('.aloha-block')) {
316
+ // You tried to move something else than an aloha block
317
+ return false;
318
+ }
319
+ };
320
+ }
321
+ },
322
+
323
+ /**************************
324
+ * SECTION: Blockify / Block Access
325
+ **************************/
326
+
327
+ /**
328
+ * Register the given block type
329
+ *
330
+ * @param {String} Identifier
331
+ * @param {Class} A class that extends block.block.AbstractBlock
332
+ * @api
333
+ */
334
+ registerBlockType: function(identifier, blockType) {
335
+ FloatingMenu.createScope('Aloha.Block.' + identifier, 'Aloha.Block');
336
+ this.blockTypes.register(identifier, blockType);
133
337
  },
134
338
 
135
339
  /**
136
- * Deactivate all active blocks
340
+ * Blockify a given element with the instance defaults
341
+ * Directly called when one does jQuery.alohaBlock(instanceDefaults)
137
342
  *
138
343
  * @private
139
344
  */
140
- _deactivateActiveBlocks: function() {
141
- jQuery.each(jQuery.extend({}, this.activeBlocks), function(id) {
142
- var block = BlockManager.getBlock(id);
143
- if (block) {
144
- block.deactivate();
145
- }
345
+ _blockify: function(element, instanceDefaults) {
346
+ var attributes, block, $element;
347
+ $element = jQuery(element);
348
+
349
+ var tagName = $element[0].tagName.toLowerCase();
350
+ if (tagName !== 'span' && tagName !== 'div') {
351
+ Aloha.Log.error('block/blockmanager', 'Blocks can only be created from <div> or <span> element. You passed ' + tagName + '.');
352
+ return;
353
+ }
354
+
355
+ // TODO: check if object is already Block-ified
356
+
357
+ attributes = this.getConfig($element, instanceDefaults);
358
+
359
+ if (!this.blockTypes.has(attributes['aloha-block-type'])) {
360
+ Aloha.Log.error('block/blockmanager', 'Block Type ' + attributes['aloha-block-type'] + ' not found!');
361
+ return;
362
+ }
363
+
364
+ block = new (this.blockTypes.get(attributes['aloha-block-type']))($element);
365
+ block.$element.addClass('aloha-block-' + attributes['aloha-block-type']);
366
+ jQuery.each(attributes, function(k, v) {
367
+ // We use the private API here, as we need to be able to set internal properties as well, and we do not want to trigger renering.
368
+ block._setAttribute(k, v);
146
369
  });
370
+
371
+
372
+ // Register block
373
+ this.blocks.register(block.getId(), block);
147
374
  },
148
375
 
149
376
  /**
@@ -152,32 +379,33 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
152
379
  * @private
153
380
  */
154
381
  getConfig: function(blockElement, instanceDefaults) {
155
- // TODO: merge from plugin settings
156
- // TODO: What about double matches / overrides / multiple selectors applying?
157
- var settingsDefaults = {};
158
-
159
382
  return jQuery.extend(
160
383
  {},
161
384
  this.defaults,
162
- settingsDefaults,
163
385
  instanceDefaults,
164
- blockElement.data(),
165
- { // Override the "about" property
166
- about: blockElement.attr('about')
167
- }
386
+ blockElement.data()
168
387
  );
169
388
  },
170
389
 
171
390
  /**
172
- * Get a Block instance by id or DOM node
391
+ * Get a Block instance by id or DOM node. The DOM node can be either
392
+ * the DOM node of the wrapping element ($_element), the jQuery object of it,
393
+ * or the ID string.
173
394
  *
174
395
  * @param {String|DOMNode} idOrDomNode
175
396
  * @return {block.block.AbstractBlock} Block instance
397
+ * @api
176
398
  */
177
399
  getBlock: function(idOrDomNode) {
178
- var id;
400
+ var id, domNode;
179
401
  if (typeof idOrDomNode === 'object') {
180
- id = jQuery(idOrDomNode).attr('id');
402
+ domNode = jQuery(idOrDomNode);
403
+ if (domNode.hasClass('aloha-block-inner')) {
404
+ // We are at the inner block wrapper, so we have to go up one level,
405
+ // to find the block itself
406
+ domNode = domNode.parent();
407
+ }
408
+ id = domNode.attr('id');
181
409
  } else {
182
410
  id = idOrDomNode;
183
411
  }
@@ -186,7 +414,8 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
186
414
  },
187
415
 
188
416
  /**
189
- * Unregister (e.g. remove) the given block
417
+ * Unregister (e.g. remove) the given block. Do not call directly,
418
+ * instead use .destroy() on the block.
190
419
  *
191
420
  * @param {Object|String} blockOrBlockId Block or block id
192
421
  */
@@ -200,38 +429,46 @@ function(Aloha, jQuery, FloatingMenu, Observable, Registry) {
200
429
  this.blocks.unregister(blockOrBlockId);
201
430
  },
202
431
 
432
+
433
+ /**************************
434
+ * Internal helpers
435
+ **************************/
436
+
203
437
  /**
204
- * Register the given block type
438
+ * Deactivate all highlighted blocks
205
439
  *
206
- * @param {String} Identifier
207
- * @param {Class} A class that extends block.block.AbstractBlock
440
+ * @private
208
441
  */
209
- registerBlockType: function(identifier, blockType) {
210
- FloatingMenu.createScope('Aloha.Block.' + identifier, 'Aloha.Block');
211
- this.blockTypes.register(identifier, blockType);
442
+ _deactivateHighlightedBlocks: function() {
443
+ jQuery.each(jQuery.extend({}, this._highlightedBlocks), function(id) {
444
+ var block = BlockManager.getBlock(id);
445
+ if (block) {
446
+ block.deactivate();
447
+ }
448
+ });
212
449
  },
213
450
 
214
451
  /**
215
- * Get all active blocks indexed by block id
452
+ * Get all highlighted blocks indexed by block id
216
453
  *
217
454
  * @return {Object}
218
455
  */
219
- getActiveBlocks: function() {
220
- var activeBlocks = {};
456
+ _getHighlightedBlocks: function() {
457
+ var _highlightedBlocks = {};
221
458
  jQuery.each(this.blocks.getEntries(), function(blockId, block) {
222
459
  if (block.isActive()) {
223
- activeBlocks[blockId] = block;
460
+ _highlightedBlocks[blockId] = block;
224
461
  }
225
462
  });
226
- return activeBlocks;
463
+ return _highlightedBlocks;
227
464
  },
228
465
 
229
- _setActive: function(block) {
230
- this.activeBlocks[block.id] = true;
466
+ _setHighlighted: function(block) {
467
+ this._highlightedBlocks[block.id] = true;
231
468
  },
232
469
 
233
- _setInactive: function(block) {
234
- delete this.activeBlocks[block.id];
470
+ _setUnhighlighted: function(block) {
471
+ delete this._highlightedBlocks[block.id];
235
472
  }
236
473
  }))();
237
474