locomotive-aloha-rails 0.20.1.2 → 0.20.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -86,19 +86,22 @@ function( Aloha, Registry, Engine, Dom, ContentHandlerManager ) {
86
86
  }
87
87
 
88
88
  Engine.execCommand( commandId, showUi, value, range );
89
-
90
- // Read range after engine modification
91
- range = Aloha.getSelection().getRangeAt( 0 );
92
-
93
- // FIX: doCleanup should work with W3C range
94
- var startnode = range.commonAncestorContainer.parentNode;
95
- var rangeObject = new window.GENTICS.Utils.RangeObject();
96
- rangeObject.startContainer = range.startContainer;
97
- rangeObject.startOffset = range.startOffset;
98
- rangeObject.endContainer = range.endContainer;
99
- rangeObject.endOffset = range.endOffset;
100
- Dom.doCleanup({merge:true, removeempty: false}, rangeObject, startnode);
101
- rangeObject.select();
89
+
90
+ if ( Aloha.getSelection().getRangeCount() ) {
91
+ // Read range after engine modification
92
+ range = Aloha.getSelection().getRangeAt( 0 );
93
+
94
+ // FIX: doCleanup should work with W3C range
95
+ var startnode = range.commonAncestorContainer.parentNode;
96
+ var rangeObject = new window.GENTICS.Utils.RangeObject();
97
+ rangeObject.startContainer = range.startContainer;
98
+ rangeObject.startOffset = range.startOffset;
99
+ rangeObject.endContainer = range.endContainer;
100
+ rangeObject.endOffset = range.endOffset;
101
+ Dom.doCleanup({merge:true, removeempty: false}, rangeObject, startnode);
102
+ rangeObject.select();
103
+ }
104
+
102
105
  Aloha.trigger('aloha-command-executed', commandId);
103
106
  },
104
107
 
@@ -28,6 +28,12 @@ define(
28
28
  function ( jQuery, PluginManager ) {
29
29
 
30
30
 
31
+ // Aloha Editor does not support Internet Explorer 6. ExtJS style fixes for
32
+ // IE6 which are applied through the "ext-ie6" class cause visual bugs in
33
+ // IE9, and so we remove it so that IE6 fixes are not applied.
34
+ Aloha.ready(function() {
35
+ jQuery('.ext-ie6').removeClass('ext-ie6');
36
+ });
31
37
 
32
38
  //----------------------------------------
33
39
  // Private variables
@@ -227,6 +233,8 @@ function ( jQuery, PluginManager ) {
227
233
  * Fetches plugins the user wants to have loaded. Returns all plugins the user
228
234
  * has specified with the data-plugins property as array, with the bundle
229
235
  * name in front.
236
+ * It's also possible to use 'Aloha.settings.plugins.load' to define the plugins
237
+ * to load.
230
238
  *
231
239
  * @return array
232
240
  * @internal
@@ -236,13 +244,20 @@ function ( jQuery, PluginManager ) {
236
244
  var
237
245
  plugins = jQuery('[data-aloha-plugins]').data('aloha-plugins');
238
246
 
247
+ // load aloha plugins from config
248
+ if ( typeof Aloha.settings.plugins != 'undefined' && typeof Aloha.settings.plugins.load != 'undefined' ) {
249
+ plugins = Aloha.settings.plugins.load;
250
+ if (plugins instanceof Array) {
251
+ return plugins;
252
+ }
253
+ }
254
+
239
255
  // Determine Plugins
240
256
  if ( typeof plugins === 'string' && plugins !== "") {
241
257
  return plugins.replace(/\s+/g, '').split(',');
242
258
  }
243
259
  // Return
244
260
  return [];
245
-
246
261
  },
247
262
 
248
263
  /**
@@ -521,6 +536,7 @@ function ( jQuery, PluginManager ) {
521
536
 
522
537
  /**
523
538
  * Determines the Aloha Url
539
+ * Uses Aloha.settings.baseUrl if set.
524
540
  * @method
525
541
  * @return {String} alohaUrl
526
542
  */
@@ -528,7 +544,11 @@ function ( jQuery, PluginManager ) {
528
544
  // aloha base path is defined by a script tag with 2 data attributes
529
545
  var requireJs = jQuery('[data-aloha-plugins]'),
530
546
  baseUrl = ( requireJs.length ) ? requireJs[0].src.replace( /\/?aloha.js$/ , '' ) : '';
531
-
547
+
548
+ if ( typeof Aloha.settings.baseUrl === "string" ) {
549
+ baseUrl = Aloha.settings.baseUrl;
550
+ }
551
+
532
552
  return baseUrl;
533
553
  },
534
554
 
@@ -557,4 +577,4 @@ function ( jQuery, PluginManager ) {
557
577
  });
558
578
 
559
579
  return Aloha;
560
- });
580
+ });
@@ -1,6 +1,18 @@
1
+ /**
2
+ * ecma5schims.js - Shim for ECMA5 compatibility
3
+ * (http://en.wikipedia.org/wiki/Shim_%28computing%29)
4
+ *
5
+ * A shim library that implements common functions that are missing on some
6
+ * environments in order to complete ECMA5 compatibility across all major
7
+ * browsers.
8
+ *
9
+ * TODO: This code needs to be refactored so as to conform to Aloha coding
10
+ * standards. It is also severly lacking in documentation. Please take
11
+ * note of: https://github.com/alohaeditor/Aloha-Editor/wiki/Commit-Checklist .
12
+ */
1
13
 
2
- define([],
3
- function(){
14
+ define([], function(){
15
+
4
16
 
5
17
  var shims = {
6
18
  // Function bind
@@ -236,12 +248,16 @@ function(){
236
248
  if (node2 != useNode2) useNode2.parentNode.removeChild(useNode2);
237
249
  return result;
238
250
 
239
-
240
251
  //node.ownerDocument gives the document object, which isn't the right info for a disconnect
241
- function getRootParent(node) {
242
- do { var parent = node; }
243
- while (node = node.parentNode);
244
- return parent;
252
+ function getRootParent( node ) {
253
+ var parent = null;
254
+
255
+ if ( node ) {
256
+ do { parent = node; }
257
+ while ( node = node.parentNode );
258
+ }
259
+
260
+ return parent;
245
261
  }
246
262
 
247
263
  //Compare Position - MIT Licensed, John Resig; http://ejohn.org/blog/comparing-document-position/
@@ -52,6 +52,12 @@ define( [
52
52
  Aloha.settings.contentHandler = {};
53
53
  }
54
54
 
55
+ var defaultContentSerializer = function(editableElement){
56
+ return jQuery(editableElement).html();
57
+ };
58
+
59
+ var contentSerializer = defaultContentSerializer;
60
+
55
61
  /**
56
62
  * Editable object
57
63
  * @namespace Aloha
@@ -76,8 +82,9 @@ define( [
76
82
 
77
83
  // delimiters, timer and idle for smartContentChange
78
84
  // smartContentChange triggers -- tab: '\u0009' - space: '\u0020' - enter: 'Enter'
85
+ // backspace: U+0008 - delete: U+007F
79
86
  this.sccDelimiters = [ ':', ';', '.', '!', '?', ',',
80
- unescape( '%u0009' ), unescape( '%u0020' ), 'Enter' ];
87
+ unescape( '%u0009' ), unescape( '%u0020' ), unescape( '%u0008' ), unescape( '%u007F' ), 'Enter' ];
81
88
  this.sccIdle = 5000;
82
89
  this.sccDelay = 500;
83
90
  this.sccTimerIdle = false;
@@ -200,8 +207,13 @@ define( [
200
207
  // if it does not handle the keyStroke it returns true and therefore all other
201
208
  // events (incl. browser's) continue
202
209
  me.obj.keydown( function( event ) {
210
+ var letEventPass = Markup.preProcessKeyStrokes( event );
203
211
  me.keyCode = event.which;
204
- return Markup.preProcessKeyStrokes( event );
212
+ if (!letEventPass) {
213
+ // the event will not proceed to key press, therefore trigger smartContentChange
214
+ me.smartContentChange( event );
215
+ }
216
+ return letEventPass;
205
217
  } );
206
218
 
207
219
  // handle keypress
@@ -688,19 +700,32 @@ define( [
688
700
  this.removePlaceholder( clonedObj );
689
701
  PluginManager.makeClean( clonedObj );
690
702
 
691
- /*
692
- //also deactivated for now. like initEditable. just in case ...
693
- var content = clonedObj.html()
694
- if ( typeof Aloha.settings.contentHandler.getContents === 'undefined' ) {
695
- Aloha.settings.contentHandler.getContents = Aloha.defaults.contentHandler.getContents;
703
+ return asObject ? clonedObj.contents() : contentSerializer(clonedObj[0]);
704
+ },
705
+
706
+ /**
707
+ * Set the contents of this editable as a HTML string
708
+ * @param content as html
709
+ * @param return as object or html string
710
+ * @return contents of the editable
711
+ */
712
+ setContents: function( content, asObject ) {
713
+ var reactivate = null;
714
+
715
+ if ( Aloha.getActiveEditable() === this ) {
716
+ Aloha.deactivateEditable();
717
+ reactivate = this;
718
+ }
719
+
720
+ this.obj.html( content );
721
+
722
+ if ( null !== reactivate ) {
723
+ reactivate.activate();
696
724
  }
697
- content = ContentHandlerManager.handleContent( content, {
698
- contenthandler: Aloha.settings.contentHandler.getContents
699
- } );
700
- clonedObj.html( content );
701
- */
702
725
 
703
- return asObject ? clonedObj.contents() : clonedObj.html();
726
+ this.smartContentChange({type : 'set-contents'});
727
+
728
+ return asObject ? this.obj.contents() : contentSerializer(this.obj[0]);
704
729
  },
705
730
 
706
731
  /**
@@ -849,6 +874,24 @@ define( [
849
874
  this.snapshotContent = this.getContents();
850
875
  return ret;
851
876
  }
852
-
853
877
  } );
878
+
879
+ /**
880
+ * Sets the serializer function to be used for the contents of all editables.
881
+ *
882
+ * The default content serializer will just call the jQuery.html()
883
+ * function on the editable element (which gets the innerHTML property).
884
+ *
885
+ * This method is a static class method and will affect the result
886
+ * of editable.getContents() for all editables that have been or
887
+ * will be constructed.
888
+ *
889
+ * @param serializerFunction
890
+ * A function that accepts a DOM element and returns the serialized
891
+ * XHTML of the element contents (excluding the start and end tag of
892
+ * the passed element).
893
+ */
894
+ Aloha.Editable.setContentSerializer = function( serializerFunction ) {
895
+ contentSerializer = serializerFunction;
896
+ };
854
897
  } );
@@ -6252,6 +6252,7 @@ commands["delete"] = {
6252
6252
 
6253
6253
  // collapse whitespace sequences
6254
6254
  collapseWhitespace(node, range);
6255
+ offset = range.startOffset;
6255
6256
 
6256
6257
  // "If node is a Text node and offset is not zero, call collapse(node,
6257
6258
  // offset) on the Selection. Then delete the contents of the range with
@@ -6845,6 +6846,7 @@ commands.forwarddelete = {
6845
6846
 
6846
6847
  // collapse whitespace in the node, if it is a text node
6847
6848
  collapseWhitespace(node, range);
6849
+ offset = range.startOffset;
6848
6850
 
6849
6851
  // "If node is a Text node and offset is not node's length:"
6850
6852
  if (node.nodeType == $_.Node.TEXT_NODE
@@ -7641,11 +7643,13 @@ commands.insertparagraph = {
7641
7643
  // container name) on the context object."
7642
7644
  var newContainer = document.createElement(newContainerName);
7643
7645
 
7644
- // "Copy all attributes of container to new container."
7645
- for (var i = 0; i < container.attributes.length; i++) {
7646
- if (typeof newContainer.setAttributeNS === 'function') {
7646
+ // "Copy all non empty attributes of the container to new container."
7647
+ for ( var i = 0; i < container.attributes.length; i++ ) {
7648
+ if ( typeof newContainer.setAttributeNS === 'function' ) {
7647
7649
  newContainer.setAttributeNS(container.attributes[i].namespaceURI, container.attributes[i].name, container.attributes[i].value);
7648
- } else {
7650
+ } else if ( container.attributes[i].value.length > 0
7651
+ && container.attributes[i].value != 'null'
7652
+ && container.attributes[i].value > 0) {
7649
7653
  newContainer.setAttribute(container.attributes[i].name, container.attributes[i].value);
7650
7654
  }
7651
7655
  }
@@ -8303,4 +8307,4 @@ return {
8303
8307
  queryCommandSupported: myQueryCommandSupported
8304
8308
  }
8305
8309
  }); // end define
8306
- // vim: foldmarker=@{,@} foldmethod=marker
8310
+ // vim: foldmarker=@{,@} foldmethod=marker
@@ -64,8 +64,7 @@ function(Aloha, jQuery, Ext, Class, console) {
64
64
  getExtComponent: function () {
65
65
  var that = this;
66
66
 
67
- if (typeof this.extPanel === 'undefined') {
68
- // generate the panel here
67
+ if (!this.extPanel) {
69
68
  this.extPanel = new Ext.Panel({
70
69
  'tbar' : [],
71
70
  'title' : this.label,
@@ -73,13 +72,15 @@ function(Aloha, jQuery, Ext, Class, console) {
73
72
  'bodyStyle': 'display:none',
74
73
  'autoScroll': true
75
74
  });
75
+ }
76
76
 
77
- // add the groups
78
- jQuery.each(this.groups, function(index, group) {
79
- // let each group generate its ext component and add them to the panel
77
+ jQuery.each(this.groups, function(index, group) {
78
+ // let each group generate its ext component and add them to
79
+ // the panel once.
80
+ if (!group.extButtonGroup) {
80
81
  that.extPanel.getTopToolbar().add(group.getExtComponent());
81
- });
82
- }
82
+ }
83
+ });
83
84
 
84
85
  return this.extPanel;
85
86
  },
@@ -192,6 +193,7 @@ function(Aloha, jQuery, Ext, Class, console) {
192
193
  'columns' : columnCount,
193
194
  'items': items
194
195
  });
196
+
195
197
  // jQuery.each(this.fields, function(id, field){
196
198
  // that.buttons.push(field);
197
199
  // });
@@ -265,6 +267,73 @@ function(Aloha, jQuery, Ext, Class, console) {
265
267
  }
266
268
  });
267
269
 
270
+ //=========================================================================
271
+ //
272
+ // Floating Menu
273
+ //
274
+ //=========================================================================
275
+
276
+ var lastFloatingMenuPos = {
277
+ top: null,
278
+ left: null
279
+ };
280
+
281
+ /**
282
+ * Handler for window scroll event. Positions the floating menu
283
+ * appropriately.
284
+ *
285
+ * @param {Aloha.FloatingMenu} floatingmenu
286
+ */
287
+ function onWindowScroll( floatingmenu ) {
288
+ if ( !Aloha.activeEditable ) {
289
+ return;
290
+ }
291
+
292
+ var element = floatingmenu.obj;
293
+ var editablePos = Aloha.activeEditable.obj.offset();
294
+ var isTopAligned = floatingmenu.behaviour === 'topalign';
295
+ var isAppended = floatingmenu.behaviour === 'append';
296
+ var isManuallyPinned = floatingmenu.pinned
297
+ && ( parseInt( element.css( 'left' ), 10 )
298
+ != ( editablePos.left
299
+ + floatingmenu.horizontalOffset
300
+ ) );
301
+
302
+ // no calculation when pinned manually or has behaviour 'append'
303
+ if ( isTopAligned && isManuallyPinned || isAppended ) {
304
+ return;
305
+ }
306
+
307
+ var floatingmenuHeight = element.height();
308
+ var scrollTop = jQuery( document ).scrollTop();
309
+
310
+ // This value is what the top position of the floating menu *would* be
311
+ // if we tried to position it above the active editable.
312
+ var floatingmenuTop = editablePos.top - floatingmenuHeight
313
+ + floatingmenu.marginTop
314
+ - floatingmenu.topalignOffset;
315
+
316
+ // The floating menu does not fit in the space between the top of the
317
+ // viewport and the editable, so position it at the top of the viewport
318
+ // and over the editable.
319
+ if ( scrollTop > floatingmenuTop ) {
320
+ editablePos.top = isTopAligned
321
+ ? scrollTop + floatingmenu.marginTop
322
+ : floatingmenu.marginTop;
323
+
324
+ // There is enough space on top of the editable to fit the entire
325
+ // floating menu, so we do so.
326
+ } else if ( scrollTop <= floatingmenuTop ) {
327
+ editablePos.top -= floatingmenuHeight
328
+ + ( isTopAligned
329
+ ? floatingmenu.marginTop +
330
+ floatingmenu.topalignOffset
331
+ : 0 );
332
+ }
333
+
334
+ floatingmenu.floatTo( editablePos );
335
+ }
336
+
268
337
  /**
269
338
  * Aloha's Floating Menu
270
339
  * @namespace Aloha
@@ -344,16 +413,30 @@ function(Aloha, jQuery, Ext, Class, console) {
344
413
  window: jQuery(window),
345
414
 
346
415
  /**
347
- * define floating menu float behaviour. meant to be adjusted via
348
- * GENTICS.Aloha.settings.floatingmenu.behaviour
349
- * set it to 'float' for standard behaviour, or 'topalign' for a fixed fm
416
+ * Aloha.settings.floatingmenu.behaviour
417
+ *
418
+ * Is used to define the floating menu (fm) float behaviour.
419
+ *
420
+ * available:
421
+ * 'float' (default) the fm will float next to the position where the caret is,
422
+ * 'topalign' the fm is fixed above the contentEditable which is active,
423
+ * 'append' the fm is appended to the defined 'element' element position (top/left)
350
424
  */
351
425
  behaviour: 'float',
352
426
 
427
+ /**
428
+ * Aloha.settings.floatingmenu.element
429
+ *
430
+ * Is used to define the element where the floating menu is positioned when
431
+ * Aloha.settings.floatingmenu.behaviour is set to 'append'
432
+ *
433
+ */
434
+ element: 'floatingmenu',
435
+
353
436
  /**
354
437
  * topalign offset to be used for topalign behavior
355
438
  */
356
- topalignOffset: 90,
439
+ topalignOffset: 0,
357
440
 
358
441
  /**
359
442
  * topalign offset to be used for topalign behavior
@@ -364,7 +447,7 @@ function(Aloha, jQuery, Ext, Class, console) {
364
447
  * will only be hounoured when behaviour is set to 'topalign'. Adds a margin,
365
448
  * so the floating menu is not directly attached to the top of the page
366
449
  */
367
- marginTop: 0,
450
+ marginTop: 10,
368
451
 
369
452
  /**
370
453
  * Define whether the floating menu shall be draggable or not via Aloha.settings.floatingmanu.draggable
@@ -372,6 +455,12 @@ function(Aloha, jQuery, Ext, Class, console) {
372
455
  */
373
456
  draggable: true,
374
457
 
458
+ /**
459
+ * Define whether the floating menu shall be pinned or not via Aloha.settings.floatingmanu.pin
460
+ * Default is: false
461
+ */
462
+ pin: false,
463
+
375
464
  /**
376
465
  * A list of all buttons that have been added to the floatingmenu
377
466
  * This needs to be tracked, as adding buttons twice will break the fm
@@ -391,38 +480,58 @@ function(Aloha, jQuery, Ext, Class, console) {
391
480
  init: function() {
392
481
 
393
482
  // check for behaviour setting of the floating menu
394
- if (Aloha.settings.floatingmenu) {
395
-
396
- if (typeof Aloha.settings.floatingmenu.draggable === 'boolean') {
483
+ if ( Aloha.settings.floatingmenu ) {
484
+ if ( typeof Aloha.settings.floatingmenu.draggable ===
485
+ 'boolean' ) {
397
486
  this.draggable = Aloha.settings.floatingmenu.draggable;
398
487
  }
399
- if (typeof Aloha.settings.floatingmenu.behaviour === 'string') {
488
+
489
+ if ( typeof Aloha.settings.floatingmenu.behaviour ===
490
+ 'string' ) {
400
491
  this.behaviour = Aloha.settings.floatingmenu.behaviour;
401
492
  }
402
- if (typeof Aloha.settings.floatingmenu.topalignOffset !== 'undefined') {
403
- this.topalignOffset = Aloha.settings.floatingmenu.topalignOffset;
493
+
494
+ if ( typeof Aloha.settings.floatingmenu.topalignOffset !==
495
+ 'undefined' ) {
496
+ this.topalignOffset = parseInt(
497
+ Aloha.settings.floatingmenu.topalignOffset, 10 );
404
498
  }
405
- if (typeof Aloha.settings.floatingmenu.horizontalOffset !== 'undefined') {
406
- this.horizontalOffset = Aloha.settings.floatingmenu.horizontalOffset;
499
+
500
+ if ( typeof Aloha.settings.floatingmenu.horizontalOffset !==
501
+ 'undefined' ) {
502
+ this.horizontalOffset = parseInt(
503
+ Aloha.settings.floatingmenu.horizontalOffset , 10 );
407
504
  }
408
- if (typeof Aloha.settings.floatingmenu.marginTop === 'number') {
409
- this.marginTop = Aloha.settings.floatingmenu.marginTop;
505
+
506
+ if ( typeof Aloha.settings.floatingmenu.marginTop ===
507
+ 'number' ) {
508
+ this.marginTop = parseInt(
509
+ Aloha.settings.floatingmenu.marginTop , 10 );
410
510
  }
411
- //We just check for undefined
412
- if (typeof Aloha.settings.floatingmenu.width !== 'undefined') {
413
- //Try to pars it
414
- try {
415
- var parsed = parseInt(Aloha.settings.floatingmenu.width);
416
- this.width = Aloha.settings.floatingmenu.width;
417
- } catch(e) {
418
- //do nothing.
419
- }
511
+
512
+ if ( typeof Aloha.settings.floatingmenu.element ===
513
+ 'string' ) {
514
+ this.element = Aloha.settings.floatingmenu.element;
515
+ }
516
+ if ( typeof Aloha.settings.floatingmenu.pin ===
517
+ 'boolean' ) {
518
+ this.pin = Aloha.settings.floatingmenu.pin;
519
+ }
520
+
521
+
522
+ if ( typeof Aloha.settings.floatingmenu.width !==
523
+ 'undefined' ) {
524
+ this.width = parseInt( Aloha.settings.floatingmenu.width,
525
+ 10 );
420
526
  }
421
527
  }
422
528
 
423
529
  jQuery.storage = new jQuery.store();
530
+
424
531
  this.currentScope = 'Aloha.global';
532
+
425
533
  var that = this;
534
+
426
535
  this.window.unload(function () {
427
536
  // store fm position if the panel is pinned to be able to restore it next time
428
537
  if (that.pinned) {
@@ -462,7 +571,7 @@ function(Aloha, jQuery, Ext, Class, console) {
462
571
  });
463
572
 
464
573
  if (typeof Aloha.settings.toolbar === 'object') {
465
- this.fromConfig = true;
574
+ this.fromConfig = true;
466
575
  }
467
576
  },
468
577
 
@@ -580,6 +689,10 @@ function(Aloha, jQuery, Ext, Class, console) {
580
689
  that.left = this.x;
581
690
  that.top = top;
582
691
 
692
+ // store the last floating menu position when the floating menu was dragged around
693
+ lastFloatingMenuPos.left = that.left;
694
+ lastFloatingMenuPos.top = that.top;
695
+
583
696
  this.panel.setPosition(this.x, top);
584
697
  that.refreshShadow();
585
698
  this.panel.shadow.show();
@@ -630,8 +743,10 @@ function(Aloha, jQuery, Ext, Class, console) {
630
743
  });
631
744
 
632
745
  // adapt the shadow
633
- that.extTabPanel.shadow.show();
634
- that.refreshShadow();
746
+ if (that.extTabPanel.isVisible()) {
747
+ that.extTabPanel.shadow.show();
748
+ that.refreshShadow();
749
+ }
635
750
  }
636
751
  }
637
752
  },
@@ -640,6 +755,7 @@ function(Aloha, jQuery, Ext, Class, console) {
640
755
 
641
756
 
642
757
  }
758
+
643
759
  // add the tabs
644
760
  jQuery.each(this.tabs, function(index, tab) {
645
761
  // let each tab generate its ext component and add them to the panel
@@ -651,8 +767,10 @@ function(Aloha, jQuery, Ext, Class, console) {
651
767
  });
652
768
 
653
769
  // add the dropshadow
654
- this.extTabPanel.shadow = jQuery('<div id="aloha-floatingmenu-shadow" class="aloha-shadow">&#160;</div>');
655
- jQuery('body').append(this.extTabPanel.shadow);
770
+ if (!this.extTabPanel.shadow) {
771
+ this.extTabPanel.shadow = jQuery('<div id="aloha-floatingmenu-shadow" class="aloha-shadow">&#160;</div>').hide();
772
+ jQuery('body').append(this.extTabPanel.shadow);
773
+ }
656
774
 
657
775
  // add an empty pin tab item, store reference
658
776
  pinTab = this.extTabPanel.add({
@@ -686,7 +804,7 @@ function(Aloha, jQuery, Ext, Class, console) {
686
804
  this.obj = jQuery(this.extTabPanel.getEl().dom);
687
805
 
688
806
  if (jQuery.storage.get('Aloha.FloatingMenu.pinned') == 'true') {
689
- this.togglePin();
807
+ //this.togglePin();
690
808
 
691
809
  this.top = parseInt(jQuery.storage.get('Aloha.FloatingMenu.top'),10);
692
810
  this.left = parseInt(jQuery.storage.get('Aloha.FloatingMenu.left'),10);
@@ -715,13 +833,26 @@ function(Aloha, jQuery, Ext, Class, console) {
715
833
  this.obj.mousedown(function (e) {
716
834
  e.originalEvent.stopSelectionUpdate = true;
717
835
  Aloha.eventHandled = true;
718
- // e.stopSelectionUpdate = true;
836
+ //e.stopSelectionUpdate = true;
719
837
  });
838
+
720
839
  this.obj.mouseup(function (e) {
721
840
  e.originalEvent.stopSelectionUpdate = true;
722
841
  Aloha.eventHandled = false;
723
842
  });
724
843
 
844
+ jQuery( window ).scroll(function() {
845
+ onWindowScroll( that );
846
+ });
847
+
848
+ // don't display the drag handle bar / pin when floating menu is not draggable
849
+ if ( !that.draggable ) {
850
+ jQuery('.aloha-floatingmenu').hover( function() {
851
+ jQuery(this).css({background: 'none'});
852
+ jQuery('.aloha-floatingmenu-pin').hide();
853
+ });
854
+ }
855
+
725
856
  // adjust float behaviour
726
857
  if (this.behaviour === 'float') {
727
858
  // listen to selectionChanged event
@@ -733,56 +864,85 @@ function(Aloha, jQuery, Ext, Class, console) {
733
864
  }
734
865
  }
735
866
  });
736
- } else if (this.behaviour === 'topalign') {
867
+ } else if (this.behaviour === 'append' ) {
868
+ var p = jQuery( "#" + that.element );
869
+ var position = p.offset();
870
+
871
+ if ( !position ) {
872
+ Aloha.Log.warn(that, 'Invalid element HTML ID for floating menu: ' + that.element);
873
+ return false;
874
+ }
875
+
876
+ // set the position so that it does not float on the first editable activation
877
+ this.floatTo( position );
878
+
879
+ if ( this.pin ) {
880
+ this.togglePin( true );
881
+ }
882
+
883
+ Aloha.bind( 'aloha-editable-activated', function( event, data ) {
884
+ if ( that.pinned ) {
885
+ return;
886
+ }
887
+ that.floatTo( position );
888
+ });
889
+
890
+ } else if ( this.behaviour === 'topalign' ) {
737
891
  // topalign will retain the user's pinned status
738
892
  // TODO maybe the pin should be hidden in that case?
739
- this.togglePin(false);
740
-
741
- // float the fm to each editable that is activated
742
- Aloha.bind('aloha-editable-activated', function(event, data) {
743
- var p = data.editable.obj.offset();
744
- p.top -= that.topalignOffset;
745
- p.left += that.horizontalOffset;
746
- if (p.top < jQuery(document).scrollTop()) {
747
- // scrollpos is below top of editable
748
- that.obj.css('top', jQuery(document).scrollTop() + that.marginTop);
749
- that.obj.css('left', p.left);
750
- that.togglePin(true);
751
- } else {
752
- // scroll pos is above top of editable
753
- that.floatTo(p);
754
- }
755
- });
893
+ this.togglePin( false );
756
894
 
757
- // fm scroll behaviour
758
- jQuery(window).scroll(function () {
759
- if (!Aloha.activeEditable) {
760
- return;
761
- }
762
- var pos = Aloha.activeEditable.obj.offset(),
763
- fmHeight = that.obj.height(),
764
- scrollTop = jQuery(document).scrollTop();
765
-
766
- if (scrollTop > (pos.top - fmHeight - 6 - that.marginTop)) {
767
- // scroll pos is lower than top of editable
768
- that.togglePin(true);
769
- that.obj.css('top', that.marginTop);
770
- } else if (scrollTop <= (pos.top - fmHeight - 6 - that.marginTop)) {
771
- // scroll pos is above top of editable
772
- if (that.behaviour === 'topalign') {
773
- pos.top = Aloha.activeEditable.obj.offset().top - that.topalignOffset;
774
- pos.left = Aloha.activeEditable.obj.offset().left + that.horizontalOffset;
895
+ // Float the menu to the editable that is activated.
896
+ Aloha.bind( 'aloha-editable-activated', function( event, data ) {
897
+ if ( that.pinned ) {
898
+ return;
899
+ }
900
+
901
+ // FIXME: that.obj.height() does not return the correct
902
+ // height of the editable. We need to fix this, and
903
+ // not hard-code the height as we currently do.
904
+ var editable = data.editable.obj;
905
+ var floatingmenuHeight = 90;
906
+ var editablePos = editable.offset();
907
+ var isFloatingmenuAboveViewport = ( (
908
+ editablePos.top - floatingmenuHeight )
909
+ < jQuery( document ).scrollTop() );
910
+
911
+ if ( isFloatingmenuAboveViewport ) {
912
+ // Since we don't have space to place the floatingmenu
913
+ // above the editable, we want to place it over the
914
+ // editable instead. But if the editable is shorter
915
+ // than the floatingmenu, it would be completely
916
+ // covered by it, and so, in such cases, we position
917
+ // the editable at the bottom of the short editable.
918
+ editablePos.top = ( editable.height()
919
+ < floatingmenuHeight )
920
+ ? editablePos.top + editable.height()
921
+ : jQuery( document ).scrollTop();
922
+
923
+ editablePos.top += that.marginTop;
775
924
  } else {
776
- pos.top -= fmHeight + 6;
925
+ editablePos.top -= floatingmenuHeight
926
+ + that.topalignOffset;
777
927
  }
778
- that.togglePin(false);
779
- that.floatTo(pos);
780
- } else if (scrollTop > pos.top + Aloha.activeEditable.obj.height() - fmHeight) {
781
- // scroll pos is below editable
782
- that.togglePin(false);
783
- }
784
- });
785
- }
928
+
929
+ editablePos.left += that.horizontalOffset;
930
+
931
+ var HORIZONTAL_PADDING = 10;
932
+ // Calculate by how much the floating menu is pocking
933
+ // outside the width of the viewport. A positive number
934
+ // means that it is outside the viewport, negative means
935
+ // it is within the viewport.
936
+ var overhang = ( ( editablePos.left + that.width
937
+ + HORIZONTAL_PADDING ) - jQuery(window).width() );
938
+
939
+ if ( overhang > 0 ) {
940
+ editablePos.left -= overhang;
941
+ }
942
+
943
+ that.floatTo( editablePos );
944
+ });
945
+ }
786
946
  },
787
947
 
788
948
  /**
@@ -961,6 +1121,11 @@ function(Aloha, jQuery, Ext, Class, console) {
961
1121
  Aloha.Log.debug(this, 'doLayout called for FloatingMenu, scope is ' + this.currentScope);
962
1122
  }
963
1123
 
1124
+ // if there's no floatingmenu don't do anything
1125
+ if ( typeof this.extTabPanel === 'undefined' ) {
1126
+ return false;
1127
+ }
1128
+
964
1129
  var that = this,
965
1130
  firstVisibleTab = false,
966
1131
  activeExtTab = this.extTabPanel.getActiveTab(),
@@ -1186,7 +1351,10 @@ function(Aloha, jQuery, Ext, Class, console) {
1186
1351
 
1187
1352
  // if the floating menu would be placed higher than the top of the screen...
1188
1353
  if ( top < scrollTop) {
1189
- top += 50 + GENTICS.Utils.Position.ScrollCorrection.top;
1354
+ top += 80 + GENTICS.Utils.Position.ScrollCorrection.top;
1355
+ // 80px if editable element is eg h1; 50px was fine for p;
1356
+ // todo: maybe just use GENTICS.Utils.Position.ScrollCorrection.top with a better value?
1357
+ // check where this is also used ...
1190
1358
  }
1191
1359
 
1192
1360
  // if the floating menu would float off the bottom of the screen
@@ -1220,24 +1388,47 @@ function(Aloha, jQuery, Ext, Class, console) {
1220
1388
  return;
1221
1389
  }
1222
1390
 
1223
- var that = this,
1224
- fmpos = this.obj.offset();
1391
+ var floatingmenu = this,
1392
+ fmpos = this.obj.offset(),
1393
+ lastLeft,
1394
+ lastTop;
1395
+
1396
+ if ( lastFloatingMenuPos.left === null ) {
1397
+ lastLeft = fmpos.left;
1398
+ lastTop = fmpos.top;
1399
+ } else {
1400
+ lastLeft = lastFloatingMenuPos.left;
1401
+ lastTop = lastFloatingMenuPos.top;
1402
+ }
1225
1403
 
1226
- // move to the new position
1227
- if (fmpos.left != position.left || fmpos.top != position.top) {
1228
- this.obj.animate({
1229
- top: position.top,
1404
+ // Place the floatingmenu to the last place the user had seen it,
1405
+ // then animate it into its new position.
1406
+ if ( lastLeft != position.left || lastTop != position.top ) {
1407
+ this.obj.offset({
1408
+ left: lastLeft,
1409
+ top: lastTop
1410
+ });
1411
+
1412
+ this.obj.animate( {
1413
+ top: position.top,
1230
1414
  left: position.left
1231
1415
  }, {
1232
1416
  queue : false,
1233
- step : function (step, props) {
1417
+ step : function( step, props ) {
1234
1418
  // update position reference
1235
- if (props.prop == 'top') {
1236
- that.top = props.now;
1237
- } else if (props.prop == 'left') {
1238
- that.left = props.now;
1419
+ if ( props.prop === 'top' ) {
1420
+ floatingmenu.top = props.now;
1421
+ } else if ( props.prop === 'left' ) {
1422
+ floatingmenu.left = props.now;
1239
1423
  }
1240
- that.refreshShadow(false);
1424
+
1425
+ floatingmenu.refreshShadow( false );
1426
+ },
1427
+ complete: function() {
1428
+ // When the animation is over, remember the floatingmenu's
1429
+ // final resting position.
1430
+ lastFloatingMenuPos.left = floatingmenu.left;
1431
+ lastFloatingMenuPos.top = floatingmenu.top;
1241
1432
  }
1242
1433
  });
1243
1434
  }
@@ -1302,3 +1493,4 @@ function(Aloha, jQuery, Ext, Class, console) {
1302
1493
 
1303
1494
  return menu;
1304
1495
  });
1496
+