comparison js/dnd-library.js @ 17:1a77f87927dd

Fixed :empty custom selector behavior in IE, a little refactoring, etc.
author David Eads <eads@chicagotech.org>
date Wed, 04 Mar 2009 13:29:31 -0600
parents bb68dc3ad56f
children 0d557e6e73f7
comparison
equal deleted inserted replaced
16:bb68dc3ad56f 17:1a77f87927dd
9 9
10 /** 10 /**
11 * Extend jQuery a bit 11 * Extend jQuery a bit
12 * 12 *
13 * We add a selector to look for "empty" elements (empty elements in TinyMCE 13 * We add a selector to look for "empty" elements (empty elements in TinyMCE
14 * often have non-breaking spaces and <br /> tags). 14 * often have non-breaking spaces and <br /> tags). An exception is required
15 * to make this work in IE.
15 */ 16 */
16 (function($) { 17 (function($) {
17 // Custom selectors 18 // Custom selectors
18 $.extend($.expr[":"], { 19 $.extend($.expr[":"], {
19 'empty' : function(a, i, m) { 20 'empty' : function(a, i, m) {
20 var text = $(a).html(); 21 return !$(a).filter(function(i) {
21 text.replace(/\u00a0/g,''); // Remove &nbsp; 22 return !$(this).is('br');
22 $('br', $(text)).remove(); // Remove breaks 23 }).length && !$.trim(a.textContent || a.innerText||$(a).text()||"");
23 return !$.trim(text);
24 } 24 }
25 }); 25 });
26 }) (jQuery); 26 }) (jQuery);
27 27
28 Drupal.behaviors.dndLibrary = function(context) { 28 Drupal.behaviors.dndLibrary = function(context) {
29 $('.dnd-library-wrapper', context).each(function() { 29 $('.dnd-library-wrapper', context).each(function() {
30 var $this = $(this); 30 var $this = $(this);
31 31
32 // This is a bad hack to lop off '-dnd-library' from the id to get the editor name 32 // This is a bad hack to lop off '-dnd-library' from the id to get the editor name
33 var editor = this.id.slice(0, -12); 33 var $editor = $('#' + this.id.slice(0, -12));
34
34 35
35 // Bind Drag and Drop plugin invocation to events emanating from Wysiwyg 36 // Bind Drag and Drop plugin invocation to events emanating from Wysiwyg
36 $('#' + editor).bind('wysiwygAttach', Drupal.behaviors.dndLibrary.attach_library); 37 $editor.bind('wysiwygAttach', Drupal.behaviors.dndLibrary.attach_library);
37 $('#' + editor).bind('wysiwygDetach', Drupal.behaviors.dndLibrary.detach_library); 38 $editor.bind('wysiwygDetach', Drupal.behaviors.dndLibrary.detach_library);
39
40 // Add basic hover behavior to editor items
41 $('.editor-item', context).hover(function() {
42 var $this = $(this);
43 var p = $('#edit-body-wrapper').position();
44 var preview = $(Drupal.settings.dndLibraryPreviews[this.id]).css({
45 'position' : 'absolute',
46 'top' : p.top + 150,
47 'left' : p.left + $('#edit-body-wrapper').width() + 150,
48 'display' : 'none',
49 'width' : '300px',
50 'background-color' : '#ddd',
51 'border' : '3px solid #999',
52 'padding' : '4px',
53 'z-index' : 10
54 });
55 $('body').prepend(preview);
56 preview.fadeIn('slow');
57 }, function() {
58 $('#' + this.id.replace(/test/,'preview')).fadeOut('fast', function() { $(this).remove(); });
59 });
38 60
39 // Ajax pager 61 // Ajax pager
40 $('.pager a', $this).click(function(e, data) { 62 $('.pager a', $this).click(function() {
41 $.getJSON(this.href, function(data) { 63 $.getJSON(this.href, function(data) {
42 $('.header', $this).html(data.header); 64 Drupal.behaviors.dndLibrary.refreshLibrary.call($this.get(0), data, $editor);
43 $('.library', $this).html(data.library);
44 //$('.footer', $this).html(data.footer);
45 for (editor_id in data.editor_representations) {
46 Drupal.settings.dndEditorRepresentations[editor_id] = data.editor_representations[editor_id];
47 }
48 var params = Drupal.wysiwyg.instances[editor];
49 $('#' + editor).trigger('wysiwygDetach', params);
50 $('#' + editor).trigger('wysiwygAttach', params);
51 }); 65 });
66
67 // Reattach behaviors
68 Drupal.behaviors.dndLibrary();
69
52 return false; 70 return false;
53 }); 71 });
72
73 // Preload images in editor representations
74 var cached = $.data($editor, 'dnd_preload') || {};
75 for (editor_id in Drupal.settings.dndEditorRepresentations) {
76 if (!cached[editor_id]) {
77 $representation = $(Drupal.settings.dndEditorRepresentations[editor_id]);
78 if ($representation.is('img') && $representation.get(0).src) {
79 $representation.attr('src', $representation.get(0).src);
80 } else {
81 $('img', $representation).each(function() {
82 this.attr('src', this.src);
83 });
84 }
85 }
86 }
87 $.data($editor, 'dnd_preload', cached);
54 }); 88 });
55 } 89 }
90
91 Drupal.behaviors.dndLibrary.refreshLibrary = function(data, editor) {
92 $this = $(this);
93
94 $('.header', $this).html(data.header);
95 $('.library', $this).html(data.library);
96 $('.footer', $this).html(data.footer);
97
98 var params = Drupal.wysiwyg.instances[editor.get(0).id];
99 editor.trigger('wysiwygDetach', params);
100 editor.trigger('wysiwygAttach', params);
101
102 for (editor_id in data.editor_representations) {
103 Drupal.settings.dndEditorRepresentations[editor_id] = data.editor_representations[editor_id];
104 }
105 for (preview_id in data.library_previews) {
106 Drupal.settings.dndLibraryPreviews[preview_id] = data.library_previews[preview_id];
107 }
108 }
109
56 110
57 // Dynamically compose a callback based on the editor name 111 // Dynamically compose a callback based on the editor name
58 Drupal.behaviors.dndLibrary.attach_library = function(e, data) { 112 Drupal.behaviors.dndLibrary.attach_library = function(e, data) {
113 var settings = $.extend({idSelector: Drupal.behaviors.dndLibrary.idSelector}, Drupal.settings.dndEnabledLibraries[data.field]);
59 var editor_fn = 'attach_' + data.editor; 114 var editor_fn = 'attach_' + data.editor;
60 if ($.isFunction(window.Drupal.behaviors.dndLibrary[editor_fn])) { 115 if ($.isFunction(window.Drupal.behaviors.dndLibrary[editor_fn])) {
61 window.Drupal.behaviors.dndLibrary[editor_fn](data, Drupal.settings.dndEnabledLibraries[data.field]); 116 window.Drupal.behaviors.dndLibrary[editor_fn](data, settings);
62 } 117 }
63 } 118 }
64 119
65 // Do garbage collection on detach 120 // Do garbage collection on detach
66 Drupal.behaviors.dndLibrary.detach_library = function(e, data) { 121 Drupal.behaviors.dndLibrary.detach_library = function(e, data) {
72 127
73 // Basic textareas 128 // Basic textareas
74 Drupal.behaviors.dndLibrary.attach_none = function(data, settings) { 129 Drupal.behaviors.dndLibrary.attach_none = function(data, settings) {
75 settings = $.extend({ 130 settings = $.extend({
76 targets: $('#'+ data.field), 131 targets: $('#'+ data.field),
77 procressTextAreaDrop: function(target, clicked, representation_id, e, data) { 132 processTextAreaDrop: function(target, clicked, representation_id, e, data) {
78 var snippet = Drupal.settings.dndEditorRepresentations[representation_id]; 133 var snippet = '<p class="dnd-dropped-wrapper">' + Drupal.settings.dndEditorRepresentations[representation_id] + '</p>';
79 $(target).replaceSelection(snippet, true); 134 $(target).replaceSelection(snippet, true);
80 } 135 }
81 }, settings); 136 }, settings);
82 $(settings.drop_selector).dnd(settings); 137 $(settings.drop_selector).dnd(settings);
83 } 138 }
99 } 154 }
100 }, 100); 155 }, 100);
101 } 156 }
102 } 157 }
103 158
159 Drupal.behaviors.dndLibrary.idSelector = function(element) {
160 if ($(element).is('img')) {
161 return $.url.setUrl(element.src).param('dnd_id');
162 }
163 return false;
164 }
165
104 // Really attach TinyMCE 166 // Really attach TinyMCE
105 Drupal.behaviors.dndLibrary._attach_tinymce = function(data, settings, tiny_instance) { 167 Drupal.behaviors.dndLibrary._attach_tinymce = function(data, settings, tiny_instance) {
106 var ed = tiny_instance, dom = ed.dom, s = ed.selection; 168 var ed = tiny_instance, dom = ed.dom, s = ed.selection;
107 169
108 settings = $.extend({ 170 settings = $.extend({
109 targets: $('#'+ data.field +'-wrapper iframe'), 171 targets: $('#'+ data.field +'-wrapper iframe'),
110 idSelector: function(element) {
111 if ($(element).is('img')) {
112 return $.url.setUrl(element.src).param('dnd_id');
113 }
114 return false;
115 },
116 interval: 100, 172 interval: 100,
117 processIframeDrop: function(target, dragged, dropped, representation_id) { 173 processIframeDrop: function(target, dragged, dropped, representation_id) {
118 var representation = Drupal.settings.dndEditorRepresentations[representation_id]; 174 var representation = Drupal.settings.dndEditorRepresentations[representation_id];
119 var $target = $(target), $dropped = $(dropped), $dragged = $(dragged), block; 175 var $target = $(target), $dropped = $(dropped), $dragged = $(dragged), block;
120 176
133 // Create an element to insert 189 // Create an element to insert
134 var insert = dom.create('p', {'class' : 'dnd-dropped-wrapper', 'id' : 'dnd-inserted'}, representation); 190 var insert = dom.create('p', {'class' : 'dnd-dropped-wrapper', 'id' : 'dnd-inserted'}, representation);
135 191
136 // The no-parent case 192 // The no-parent case
137 if ($(block).is('body')) { 193 if ($(block).is('body')) {
138
139 s.setNode(insert); 194 s.setNode(insert);
140 } 195 }
141 else { 196 else {
142 var old_id = block.id; 197 var old_id = block.id;
143 block.id = 'target-block'; 198 block.id = 'target-block';
146 // @TODO is finding the parent broken in safari?? 201 // @TODO is finding the parent broken in safari??
147 $block.after('<p class="dnd-dropped-wrapper" id="dnd-inserted">' + representation + '</p>'); 202 $block.after('<p class="dnd-dropped-wrapper" id="dnd-inserted">' + representation + '</p>');
148 203
149 // The active target block should be empty 204 // The active target block should be empty
150 if ($('#target-block:empty', $target.contents()).length > 0) { 205 if ($('#target-block:empty', $target.contents()).length > 0) {
151 var c = dom.get('target-block'); 206 $('#target-block', $target.contents()).remove();
152 s.select(dom.get('target-block'));
153 ed.execCommand('Delete', false, null);
154 dom.remove(c);
155 } else if (old_id) { 207 } else if (old_id) {
156 block.id = old_id; 208 block.id = old_id;
157 } else { 209 } else {
158 $block.removeAttr('id'); 210 $block.removeAttr('id');
159 } 211 }