| |
1 /*** |
| |
2 Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) |
| |
3 Mochi-ized By Thomas Herve (_firstname_@nimail.org) |
| |
4 |
| |
5 See scriptaculous.js for full license. |
| |
6 |
| |
7 ***/ |
| |
8 |
| |
9 if (typeof(dojo) != 'undefined') { |
| |
10 dojo.provide('MochiKit.DragAndDrop'); |
| |
11 dojo.require('MochiKit.Base'); |
| |
12 dojo.require('MochiKit.DOM'); |
| |
13 dojo.require('MochiKit.Iter'); |
| |
14 } |
| |
15 |
| |
16 if (typeof(JSAN) != 'undefined') { |
| |
17 JSAN.use("MochiKit.Base", []); |
| |
18 JSAN.use("MochiKit.DOM", []); |
| |
19 JSAN.use("MochiKit.Iter", []); |
| |
20 } |
| |
21 |
| |
22 try { |
| |
23 if (typeof(MochiKit.Base) == 'undefined' || |
| |
24 typeof(MochiKit.DOM) == 'undefined' || |
| |
25 typeof(MochiKit.Iter) == 'undefined') { |
| |
26 throw ""; |
| |
27 } |
| |
28 } catch (e) { |
| |
29 throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM and MochiKit.Iter!"; |
| |
30 } |
| |
31 |
| |
32 if (typeof(MochiKit.Sortable) == 'undefined') { |
| |
33 MochiKit.Sortable = {}; |
| |
34 } |
| |
35 |
| |
36 MochiKit.Sortable.NAME = 'MochiKit.Sortable'; |
| |
37 MochiKit.Sortable.VERSION = '1.4'; |
| |
38 |
| |
39 MochiKit.Sortable.__repr__ = function () { |
| |
40 return '[' + this.NAME + ' ' + this.VERSION + ']'; |
| |
41 }; |
| |
42 |
| |
43 MochiKit.Sortable.toString = function () { |
| |
44 return this.__repr__(); |
| |
45 }; |
| |
46 |
| |
47 MochiKit.Sortable.EXPORT = [ |
| |
48 ]; |
| |
49 |
| |
50 MochiKit.DragAndDrop.EXPORT_OK = [ |
| |
51 "Sortable" |
| |
52 ]; |
| |
53 |
| |
54 MochiKit.Sortable.Sortable = { |
| |
55 /*** |
| |
56 |
| |
57 Manage sortables. Mainly use the create function to add a sortable. |
| |
58 |
| |
59 ***/ |
| |
60 sortables: {}, |
| |
61 |
| |
62 _findRootElement: function (element) { |
| |
63 while (element.tagName.toUpperCase() != "BODY") { |
| |
64 if (element.id && MochiKit.Sortable.Sortable.sortables[element.id]) { |
| |
65 return element; |
| |
66 } |
| |
67 element = element.parentNode; |
| |
68 } |
| |
69 }, |
| |
70 |
| |
71 /** @id MochiKit.Sortable.Sortable.options */ |
| |
72 options: function (element) { |
| |
73 element = MochiKit.Sortable.Sortable._findRootElement(MochiKit.DOM.getElement(element)); |
| |
74 if (!element) { |
| |
75 return; |
| |
76 } |
| |
77 return MochiKit.Sortable.Sortable.sortables[element.id]; |
| |
78 }, |
| |
79 |
| |
80 /** @id MochiKit.Sortable.Sortable.destroy */ |
| |
81 destroy: function (element){ |
| |
82 var s = MochiKit.Sortable.Sortable.options(element); |
| |
83 var b = MochiKit.Base; |
| |
84 var d = MochiKit.DragAndDrop; |
| |
85 |
| |
86 if (s) { |
| |
87 MochiKit.Signal.disconnect(s.startHandle); |
| |
88 MochiKit.Signal.disconnect(s.endHandle); |
| |
89 b.map(function (dr) { |
| |
90 d.Droppables.remove(dr); |
| |
91 }, s.droppables); |
| |
92 b.map(function (dr) { |
| |
93 dr.destroy(); |
| |
94 }, s.draggables); |
| |
95 |
| |
96 delete MochiKit.Sortable.Sortable.sortables[s.element.id]; |
| |
97 } |
| |
98 }, |
| |
99 |
| |
100 /** @id MochiKit.Sortable.Sortable.create */ |
| |
101 create: function (element, options) { |
| |
102 element = MochiKit.DOM.getElement(element); |
| |
103 var self = MochiKit.Sortable.Sortable; |
| |
104 |
| |
105 /** @id MochiKit.Sortable.Sortable.options */ |
| |
106 options = MochiKit.Base.update({ |
| |
107 |
| |
108 /** @id MochiKit.Sortable.Sortable.element */ |
| |
109 element: element, |
| |
110 |
| |
111 /** @id MochiKit.Sortable.Sortable.tag */ |
| |
112 tag: 'li', // assumes li children, override with tag: 'tagname' |
| |
113 |
| |
114 /** @id MochiKit.Sortable.Sortable.dropOnEmpty */ |
| |
115 dropOnEmpty: false, |
| |
116 |
| |
117 /** @id MochiKit.Sortable.Sortable.tree */ |
| |
118 tree: false, |
| |
119 |
| |
120 /** @id MochiKit.Sortable.Sortable.treeTag */ |
| |
121 treeTag: 'ul', |
| |
122 |
| |
123 /** @id MochiKit.Sortable.Sortable.overlap */ |
| |
124 overlap: 'vertical', // one of 'vertical', 'horizontal' |
| |
125 |
| |
126 /** @id MochiKit.Sortable.Sortable.constraint */ |
| |
127 constraint: 'vertical', // one of 'vertical', 'horizontal', false |
| |
128 // also takes array of elements (or ids); or false |
| |
129 |
| |
130 /** @id MochiKit.Sortable.Sortable.containment */ |
| |
131 containment: [element], |
| |
132 |
| |
133 /** @id MochiKit.Sortable.Sortable.handle */ |
| |
134 handle: false, // or a CSS class |
| |
135 |
| |
136 /** @id MochiKit.Sortable.Sortable.only */ |
| |
137 only: false, |
| |
138 |
| |
139 /** @id MochiKit.Sortable.Sortable.hoverclass */ |
| |
140 hoverclass: null, |
| |
141 |
| |
142 /** @id MochiKit.Sortable.Sortable.ghosting */ |
| |
143 ghosting: false, |
| |
144 |
| |
145 /** @id MochiKit.Sortable.Sortable.scroll */ |
| |
146 scroll: false, |
| |
147 |
| |
148 /** @id MochiKit.Sortable.Sortable.scrollSensitivity */ |
| |
149 scrollSensitivity: 20, |
| |
150 |
| |
151 /** @id MochiKit.Sortable.Sortable.scrollSpeed */ |
| |
152 scrollSpeed: 15, |
| |
153 |
| |
154 /** @id MochiKit.Sortable.Sortable.format */ |
| |
155 format: /^[^_]*_(.*)$/, |
| |
156 |
| |
157 /** @id MochiKit.Sortable.Sortable.onChange */ |
| |
158 onChange: MochiKit.Base.noop, |
| |
159 |
| |
160 /** @id MochiKit.Sortable.Sortable.onUpdate */ |
| |
161 onUpdate: MochiKit.Base.noop, |
| |
162 |
| |
163 /** @id MochiKit.Sortable.Sortable.accept */ |
| |
164 accept: null |
| |
165 }, options); |
| |
166 |
| |
167 // clear any old sortable with same element |
| |
168 self.destroy(element); |
| |
169 |
| |
170 // build options for the draggables |
| |
171 var options_for_draggable = { |
| |
172 revert: true, |
| |
173 ghosting: options.ghosting, |
| |
174 scroll: options.scroll, |
| |
175 scrollSensitivity: options.scrollSensitivity, |
| |
176 scrollSpeed: options.scrollSpeed, |
| |
177 constraint: options.constraint, |
| |
178 handle: options.handle |
| |
179 }; |
| |
180 |
| |
181 if (options.starteffect) { |
| |
182 options_for_draggable.starteffect = options.starteffect; |
| |
183 } |
| |
184 |
| |
185 if (options.reverteffect) { |
| |
186 options_for_draggable.reverteffect = options.reverteffect; |
| |
187 } else if (options.ghosting) { |
| |
188 options_for_draggable.reverteffect = function (innerelement) { |
| |
189 innerelement.style.top = 0; |
| |
190 innerelement.style.left = 0; |
| |
191 }; |
| |
192 } |
| |
193 |
| |
194 if (options.endeffect) { |
| |
195 options_for_draggable.endeffect = options.endeffect; |
| |
196 } |
| |
197 |
| |
198 if (options.zindex) { |
| |
199 options_for_draggable.zindex = options.zindex; |
| |
200 } |
| |
201 |
| |
202 // build options for the droppables |
| |
203 var options_for_droppable = { |
| |
204 overlap: options.overlap, |
| |
205 containment: options.containment, |
| |
206 hoverclass: options.hoverclass, |
| |
207 onhover: self.onHover, |
| |
208 tree: options.tree, |
| |
209 accept: options.accept |
| |
210 } |
| |
211 |
| |
212 var options_for_tree = { |
| |
213 onhover: self.onEmptyHover, |
| |
214 overlap: options.overlap, |
| |
215 containment: options.containment, |
| |
216 hoverclass: options.hoverclass, |
| |
217 accept: options.accept |
| |
218 } |
| |
219 |
| |
220 // fix for gecko engine |
| |
221 MochiKit.DOM.removeEmptyTextNodes(element); |
| |
222 |
| |
223 options.draggables = []; |
| |
224 options.droppables = []; |
| |
225 |
| |
226 // drop on empty handling |
| |
227 if (options.dropOnEmpty || options.tree) { |
| |
228 new MochiKit.DragAndDrop.Droppable(element, options_for_tree); |
| |
229 options.droppables.push(element); |
| |
230 } |
| |
231 MochiKit.Base.map(function (e) { |
| |
232 // handles are per-draggable |
| |
233 var handle = options.handle ? |
| |
234 MochiKit.DOM.getFirstElementByTagAndClassName(null, |
| |
235 options.handle, e) : e; |
| |
236 options.draggables.push( |
| |
237 new MochiKit.DragAndDrop.Draggable(e, |
| |
238 MochiKit.Base.update(options_for_draggable, |
| |
239 {handle: handle}))); |
| |
240 new MochiKit.DragAndDrop.Droppable(e, options_for_droppable); |
| |
241 if (options.tree) { |
| |
242 e.treeNode = element; |
| |
243 } |
| |
244 options.droppables.push(e); |
| |
245 }, (self.findElements(element, options) || [])); |
| |
246 |
| |
247 if (options.tree) { |
| |
248 MochiKit.Base.map(function (e) { |
| |
249 new MochiKit.DragAndDrop.Droppable(e, options_for_tree); |
| |
250 e.treeNode = element; |
| |
251 options.droppables.push(e); |
| |
252 }, (self.findTreeElements(element, options) || [])); |
| |
253 } |
| |
254 |
| |
255 // keep reference |
| |
256 self.sortables[element.id] = options; |
| |
257 |
| |
258 options.lastValue = self.serialize(element); |
| |
259 options.startHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'start', |
| |
260 MochiKit.Base.partial(self.onStart, element)); |
| |
261 options.endHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'end', |
| |
262 MochiKit.Base.partial(self.onEnd, element)); |
| |
263 }, |
| |
264 |
| |
265 /** @id MochiKit.Sortable.Sortable.onStart */ |
| |
266 onStart: function (element, draggable) { |
| |
267 var self = MochiKit.Sortable.Sortable; |
| |
268 var options = self.options(element); |
| |
269 options.lastValue = self.serialize(options.element); |
| |
270 }, |
| |
271 |
| |
272 /** @id MochiKit.Sortable.Sortable.onEnd */ |
| |
273 onEnd: function (element, draggable) { |
| |
274 var self = MochiKit.Sortable.Sortable; |
| |
275 self.unmark(); |
| |
276 var options = self.options(element); |
| |
277 if (options.lastValue != self.serialize(options.element)) { |
| |
278 options.onUpdate(options.element); |
| |
279 } |
| |
280 }, |
| |
281 |
| |
282 // return all suitable-for-sortable elements in a guaranteed order |
| |
283 |
| |
284 /** @id MochiKit.Sortable.Sortable.findElements */ |
| |
285 findElements: function (element, options) { |
| |
286 return MochiKit.Sortable.Sortable.findChildren( |
| |
287 element, options.only, options.tree ? true : false, options.tag); |
| |
288 }, |
| |
289 |
| |
290 /** @id MochiKit.Sortable.Sortable.findTreeElements */ |
| |
291 findTreeElements: function (element, options) { |
| |
292 return MochiKit.Sortable.Sortable.findChildren( |
| |
293 element, options.only, options.tree ? true : false, options.treeTag); |
| |
294 }, |
| |
295 |
| |
296 /** @id MochiKit.Sortable.Sortable.findChildren */ |
| |
297 findChildren: function (element, only, recursive, tagName) { |
| |
298 if (!element.hasChildNodes()) { |
| |
299 return null; |
| |
300 } |
| |
301 tagName = tagName.toUpperCase(); |
| |
302 if (only) { |
| |
303 only = MochiKit.Base.flattenArray([only]); |
| |
304 } |
| |
305 var elements = []; |
| |
306 MochiKit.Base.map(function (e) { |
| |
307 if (e.tagName && |
| |
308 e.tagName.toUpperCase() == tagName && |
| |
309 (!only || |
| |
310 MochiKit.Iter.some(only, function (c) { |
| |
311 return MochiKit.DOM.hasElementClass(e, c); |
| |
312 }))) { |
| |
313 elements.push(e); |
| |
314 } |
| |
315 if (recursive) { |
| |
316 var grandchildren = MochiKit.Sortable.Sortable.findChildren(e, only, recursive, tagName); |
| |
317 if (grandchildren && grandchildren.length > 0) { |
| |
318 elements = elements.concat(grandchildren); |
| |
319 } |
| |
320 } |
| |
321 }, element.childNodes); |
| |
322 return elements; |
| |
323 }, |
| |
324 |
| |
325 /** @id MochiKit.Sortable.Sortable.onHover */ |
| |
326 onHover: function (element, dropon, overlap) { |
| |
327 if (MochiKit.DOM.isParent(dropon, element)) { |
| |
328 return; |
| |
329 } |
| |
330 var self = MochiKit.Sortable.Sortable; |
| |
331 |
| |
332 if (overlap > .33 && overlap < .66 && self.options(dropon).tree) { |
| |
333 return; |
| |
334 } else if (overlap > 0.5) { |
| |
335 self.mark(dropon, 'before'); |
| |
336 if (dropon.previousSibling != element) { |
| |
337 var oldParentNode = element.parentNode; |
| |
338 element.style.visibility = 'hidden'; // fix gecko rendering |
| |
339 dropon.parentNode.insertBefore(element, dropon); |
| |
340 if (dropon.parentNode != oldParentNode) { |
| |
341 self.options(oldParentNode).onChange(element); |
| |
342 } |
| |
343 self.options(dropon.parentNode).onChange(element); |
| |
344 } |
| |
345 } else { |
| |
346 self.mark(dropon, 'after'); |
| |
347 var nextElement = dropon.nextSibling || null; |
| |
348 if (nextElement != element) { |
| |
349 var oldParentNode = element.parentNode; |
| |
350 element.style.visibility = 'hidden'; // fix gecko rendering |
| |
351 dropon.parentNode.insertBefore(element, nextElement); |
| |
352 if (dropon.parentNode != oldParentNode) { |
| |
353 self.options(oldParentNode).onChange(element); |
| |
354 } |
| |
355 self.options(dropon.parentNode).onChange(element); |
| |
356 } |
| |
357 } |
| |
358 }, |
| |
359 |
| |
360 _offsetSize: function (element, type) { |
| |
361 if (type == 'vertical' || type == 'height') { |
| |
362 return element.offsetHeight; |
| |
363 } else { |
| |
364 return element.offsetWidth; |
| |
365 } |
| |
366 }, |
| |
367 |
| |
368 /** @id MochiKit.Sortable.Sortable.onEmptyHover */ |
| |
369 onEmptyHover: function (element, dropon, overlap) { |
| |
370 var oldParentNode = element.parentNode; |
| |
371 var self = MochiKit.Sortable.Sortable; |
| |
372 var droponOptions = self.options(dropon); |
| |
373 |
| |
374 if (!MochiKit.DOM.isParent(dropon, element)) { |
| |
375 var index; |
| |
376 |
| |
377 var children = self.findElements(dropon, {tag: droponOptions.tag, |
| |
378 only: droponOptions.only}); |
| |
379 var child = null; |
| |
380 |
| |
381 if (children) { |
| |
382 var offset = self._offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); |
| |
383 |
| |
384 for (index = 0; index < children.length; index += 1) { |
| |
385 if (offset - self._offsetSize(children[index], droponOptions.overlap) >= 0) { |
| |
386 offset -= self._offsetSize(children[index], droponOptions.overlap); |
| |
387 } else if (offset - (self._offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { |
| |
388 child = index + 1 < children.length ? children[index + 1] : null; |
| |
389 break; |
| |
390 } else { |
| |
391 child = children[index]; |
| |
392 break; |
| |
393 } |
| |
394 } |
| |
395 } |
| |
396 |
| |
397 dropon.insertBefore(element, child); |
| |
398 |
| |
399 self.options(oldParentNode).onChange(element); |
| |
400 droponOptions.onChange(element); |
| |
401 } |
| |
402 }, |
| |
403 |
| |
404 /** @id MochiKit.Sortable.Sortable.unmark */ |
| |
405 unmark: function () { |
| |
406 var m = MochiKit.Sortable.Sortable._marker; |
| |
407 if (m) { |
| |
408 MochiKit.Style.hideElement(m); |
| |
409 } |
| |
410 }, |
| |
411 |
| |
412 /** @id MochiKit.Sortable.Sortable.mark */ |
| |
413 mark: function (dropon, position) { |
| |
414 // mark on ghosting only |
| |
415 var d = MochiKit.DOM; |
| |
416 var self = MochiKit.Sortable.Sortable; |
| |
417 var sortable = self.options(dropon.parentNode); |
| |
418 if (sortable && !sortable.ghosting) { |
| |
419 return; |
| |
420 } |
| |
421 |
| |
422 if (!self._marker) { |
| |
423 self._marker = d.getElement('dropmarker') || |
| |
424 document.createElement('DIV'); |
| |
425 MochiKit.Style.hideElement(self._marker); |
| |
426 d.addElementClass(self._marker, 'dropmarker'); |
| |
427 self._marker.style.position = 'absolute'; |
| |
428 document.getElementsByTagName('body').item(0).appendChild(self._marker); |
| |
429 } |
| |
430 var offsets = MochiKit.Position.cumulativeOffset(dropon); |
| |
431 self._marker.style.left = offsets.x + 'px'; |
| |
432 self._marker.style.top = offsets.y + 'px'; |
| |
433 |
| |
434 if (position == 'after') { |
| |
435 if (sortable.overlap == 'horizontal') { |
| |
436 self._marker.style.left = (offsets.x + dropon.clientWidth) + 'px'; |
| |
437 } else { |
| |
438 self._marker.style.top = (offsets.y + dropon.clientHeight) + 'px'; |
| |
439 } |
| |
440 } |
| |
441 MochiKit.Style.showElement(self._marker); |
| |
442 }, |
| |
443 |
| |
444 _tree: function (element, options, parent) { |
| |
445 var self = MochiKit.Sortable.Sortable; |
| |
446 var children = self.findElements(element, options) || []; |
| |
447 |
| |
448 for (var i = 0; i < children.length; ++i) { |
| |
449 var match = children[i].id.match(options.format); |
| |
450 |
| |
451 if (!match) { |
| |
452 continue; |
| |
453 } |
| |
454 |
| |
455 var child = { |
| |
456 id: encodeURIComponent(match ? match[1] : null), |
| |
457 element: element, |
| |
458 parent: parent, |
| |
459 children: [], |
| |
460 position: parent.children.length, |
| |
461 container: self._findChildrenElement(children[i], options.treeTag.toUpperCase()) |
| |
462 } |
| |
463 |
| |
464 /* Get the element containing the children and recurse over it */ |
| |
465 if (child.container) { |
| |
466 self._tree(child.container, options, child) |
| |
467 } |
| |
468 |
| |
469 parent.children.push (child); |
| |
470 } |
| |
471 |
| |
472 return parent; |
| |
473 }, |
| |
474 |
| |
475 /* Finds the first element of the given tag type within a parent element. |
| |
476 Used for finding the first LI[ST] within a L[IST]I[TEM].*/ |
| |
477 _findChildrenElement: function (element, containerTag) { |
| |
478 if (element && element.hasChildNodes) { |
| |
479 containerTag = containerTag.toUpperCase(); |
| |
480 for (var i = 0; i < element.childNodes.length; ++i) { |
| |
481 if (element.childNodes[i].tagName.toUpperCase() == containerTag) { |
| |
482 return element.childNodes[i]; |
| |
483 } |
| |
484 } |
| |
485 } |
| |
486 return null; |
| |
487 }, |
| |
488 |
| |
489 /** @id MochiKit.Sortable.Sortable.tree */ |
| |
490 tree: function (element, options) { |
| |
491 element = MochiKit.DOM.getElement(element); |
| |
492 var sortableOptions = MochiKit.Sortable.Sortable.options(element); |
| |
493 options = MochiKit.Base.update({ |
| |
494 tag: sortableOptions.tag, |
| |
495 treeTag: sortableOptions.treeTag, |
| |
496 only: sortableOptions.only, |
| |
497 name: element.id, |
| |
498 format: sortableOptions.format |
| |
499 }, options || {}); |
| |
500 |
| |
501 var root = { |
| |
502 id: null, |
| |
503 parent: null, |
| |
504 children: new Array, |
| |
505 container: element, |
| |
506 position: 0 |
| |
507 } |
| |
508 |
| |
509 return MochiKit.Sortable.Sortable._tree(element, options, root); |
| |
510 }, |
| |
511 |
| |
512 /** |
| |
513 * Specifies the sequence for the Sortable. |
| |
514 * @param {Node} element Element to use as the Sortable. |
| |
515 * @param {Object} newSequence New sequence to use. |
| |
516 * @param {Object} options Options to use fro the Sortable. |
| |
517 */ |
| |
518 setSequence: function (element, newSequence, options) { |
| |
519 var self = MochiKit.Sortable.Sortable; |
| |
520 var b = MochiKit.Base; |
| |
521 element = MochiKit.DOM.getElement(element); |
| |
522 options = b.update(self.options(element), options || {}); |
| |
523 |
| |
524 var nodeMap = {}; |
| |
525 b.map(function (n) { |
| |
526 var m = n.id.match(options.format); |
| |
527 if (m) { |
| |
528 nodeMap[m[1]] = [n, n.parentNode]; |
| |
529 } |
| |
530 n.parentNode.removeChild(n); |
| |
531 }, self.findElements(element, options)); |
| |
532 |
| |
533 b.map(function (ident) { |
| |
534 var n = nodeMap[ident]; |
| |
535 if (n) { |
| |
536 n[1].appendChild(n[0]); |
| |
537 delete nodeMap[ident]; |
| |
538 } |
| |
539 }, newSequence); |
| |
540 }, |
| |
541 |
| |
542 /* Construct a [i] index for a particular node */ |
| |
543 _constructIndex: function (node) { |
| |
544 var index = ''; |
| |
545 do { |
| |
546 if (node.id) { |
| |
547 index = '[' + node.position + ']' + index; |
| |
548 } |
| |
549 } while ((node = node.parent) != null); |
| |
550 return index; |
| |
551 }, |
| |
552 |
| |
553 /** @id MochiKit.Sortable.Sortable.sequence */ |
| |
554 sequence: function (element, options) { |
| |
555 element = MochiKit.DOM.getElement(element); |
| |
556 var self = MochiKit.Sortable.Sortable; |
| |
557 var options = MochiKit.Base.update(self.options(element), options || {}); |
| |
558 |
| |
559 return MochiKit.Base.map(function (item) { |
| |
560 return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; |
| |
561 }, MochiKit.DOM.getElement(self.findElements(element, options) || [])); |
| |
562 }, |
| |
563 |
| |
564 /** |
| |
565 * Serializes the content of a Sortable. Useful to send this content through a XMLHTTPRequest. |
| |
566 * These options override the Sortable options for the serialization only. |
| |
567 * @param {Node} element Element to serialize. |
| |
568 * @param {Object} options Serialization options. |
| |
569 */ |
| |
570 serialize: function (element, options) { |
| |
571 element = MochiKit.DOM.getElement(element); |
| |
572 var self = MochiKit.Sortable.Sortable; |
| |
573 options = MochiKit.Base.update(self.options(element), options || {}); |
| |
574 var name = encodeURIComponent(options.name || element.id); |
| |
575 |
| |
576 if (options.tree) { |
| |
577 return MochiKit.Base.flattenArray(MochiKit.Base.map(function (item) { |
| |
578 return [name + self._constructIndex(item) + "[id]=" + |
| |
579 encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); |
| |
580 }, self.tree(element, options).children)).join('&'); |
| |
581 } else { |
| |
582 return MochiKit.Base.map(function (item) { |
| |
583 return name + "[]=" + encodeURIComponent(item); |
| |
584 }, self.sequence(element, options)).join('&'); |
| |
585 } |
| |
586 } |
| |
587 }; |
| |
588 |