comparison js/dnd.js @ 15:7a5f74482ee3

More cross browser work, garbage collection for timers, etc.
author David Eads <eads@chicagotech.org>
date Mon, 02 Mar 2009 23:22:37 -0600
parents ef7ad7b5baa4
children bb68dc3ad56f
comparison
equal deleted inserted replaced
14:ef7ad7b5baa4 15:7a5f74482ee3
29 * The class to apply to links and images tagged as droppable. This class 29 * The class to apply to links and images tagged as droppable. This class
30 * should have a style rule in the editor that sets display to 'none' for 30 * should have a style rule in the editor that sets display to 'none' for
31 * the best experience. 31 * the best experience.
32 * 32 *
33 * idSelector: 33 * idSelector:
34 * A callback that parses a unique id out of a droppable element. B y default 34 * A callback that parses a unique id out of a droppable element. By default
35 * this uses the id of the element, but one could parse out an ID based on 35 * this uses the id of the element, but one could parse out an ID based on
36 * any part of the URL, interior markup, etc. 36 * any part of the URL, interior markup, etc.
37 * 37 *
38 * renderRepresentation: 38 * renderRepresentation:
39 * A callback that defines the mechanism for rendering a representation of 39 * A callback that defines the mechanism for rendering a representation of
77 */ 77 */
78 78
79 (function($) { 79 (function($) {
80 $.fn.dnd = function(opt) { 80 $.fn.dnd = function(opt) {
81 opt = $.extend({}, { 81 opt = $.extend({}, {
82 dropWrapper: '<p class="dnd-dropped"></p>', 82 interval: 250,
83 dropWrapper: '<p class="dnd-dropped-wrapper"></p>',
83 insertBefore: false, 84 insertBefore: false,
84 insertAfter: false, 85 insertAfter: false,
85 processedClass: 'dnd-processed', 86 processedClass: 'dnd-processed',
86 interval: 100, 87 ignoreClass: 'dnd-dropped',
87
88 processTargets: function(targets) { 88 processTargets: function(targets) {
89 return targets.each(function() { 89 return targets.each(function() {
90 //$('head', $(this).contents()).append('<style type="text/css">.dnd-processed { display: none; }</style>'); 90 $('head', $(this).contents()).append('<style type="text/css">img { display: none; } img.dnd-dropped {display: block; }</style>');
91 //@TODO use jQuery.rules()
92 return this; 91 return this;
93 }); 92 });
94 }, 93 },
95 94
96 // Must return a string 95 // Must return a string
115 } 114 }
116 $.data(target, representation_id +'_count', count); 115 $.data(target, representation_id +'_count', count);
117 return '<span id="dnd-' + representation_id +'-'+ count +'">' + representation_id + '</span>'; 116 return '<span id="dnd-' + representation_id +'-'+ count +'">' + representation_id + '</span>';
118 }, 117 },
119 118
120 // Back out markup to render in place after parent container 119 preprocessDrop: function(target, drop) { return drop; },
121 preprocessDrop: function(target, drop) {
122 return drop;
123 var old_parent = false;
124 var element_id = '';
125
126 var parents = drop.parents();
127 for (var i=0; i < parents.length; i++) {
128 if ($(parents[i]).is('body')) {
129 element_id = $(drop).get(0).id;
130 $(old_parent).after(drop.clone());
131 drop.remove();
132 }
133 old_parent = parents[i];
134 }
135 return $('#'+ element_id, $(target).contents());
136 },
137
138 postprocessDrop: function(target, drop, element) { 120 postprocessDrop: function(target, drop, element) {
139 $(element).addClass('dnd-inserted'); 121 $(element).addClass('dnd-inserted');
140 } 122 }
141 123
142 }, opt); 124 }, opt);
163 145
164 // We need to differentiate behavior based on the targets... I guess. 146 // We need to differentiate behavior based on the targets... I guess.
165 targets.each(function() { 147 targets.each(function() {
166 if ($(this).is('iframe')) { 148 if ($(this).is('iframe')) {
167 var target = this; 149 var target = this;
168 var selector = 'img[src='+ element.src +']'; 150
151 var selector = 'img:not(.' + opt.ignoreClass + ')';
169 152
170 // Watch the iframe for changes 153 // Watch the iframe for changes
171 var t = setInterval(function() { 154 var t = setInterval(function() {
172 $('img', $(target).contents()).each(function() { 155 $(selector, $(target).contents()).each(function() {
173 if (opt.idSelector(this) == representation_id) { 156 if (opt.idSelector(this) == representation_id) {
174 var drop = opt.preprocessDrop(target, $(this)); // Must return a jquery object 157 var drop = opt.preprocessDrop(target, $(this)); // Must return a jquery object
175 var representation = opt.renderRepresentation(target, drop, representation_id); 158 var representation = opt.renderRepresentation(target, drop, representation_id);
176 if (representation) { 159 if (representation) {
177 if (opt.dropWrapper) { 160 // Breaks IE 7!
161 /*if (opt.dropWrapper) {
178 drop.wrap(opt.dropWrapper); 162 drop.wrap(opt.dropWrapper);
179 } 163 }*/
180 if (opt.insertBefore) { 164 if (opt.insertBefore) {
181 drop.before(opt.insertBefore); 165 drop.before(opt.insertBefore);
182 } 166 }
183 if (opt.insertAfter) { 167 if (opt.insertAfter) {
184 drop.after(opt.insertAfter); 168 drop.after(opt.insertAfter);
185 } 169 }
186 drop.replaceWith(representation); 170 drop.replaceWith(representation);
187 opt.postprocessDrop(target, drop, element); 171 opt.postprocessDrop(target, drop, element);
188 } 172 }
189 } 173 }
190 }); 174 });
191 }, opt.interval); 175 }, opt.interval);
192 // @TODO track the timer with $.data() so we can clear it? 176
177 // Track current active timers -- this means you can implement
178 // your own garbage collection for specific interactions, such
179 // as paging.
180 var data = $(document).data('dnd_timers');
181 if (data) {
182 data[data.length] = t;
183 } else {
184 data = new Array();
185 data[0] = t;
186 }
187 $(document).data('dnd_timers', data);
188
193 } else if ($(this).is('textarea')) { 189 } else if ($(this).is('textarea')) {
194 //console.log('@TODO handle textareas via.... regexp?'); 190 //console.log('@TODO handle textareas via.... regexp?');
195 } 191 }
196 }); 192 });
197 } 193 }