3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4 <title>The source code</title>
5 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8 <body onload="prettyPrint();">
9 <pre class="prettyprint lang-js">/*!
10 * Ext JS Library 3.3.1
11 * Copyright(c) 2006-2010 Sencha Inc.
12 * licensing@sencha.com
13 * http://www.sencha.com/license
15 <div id="cls-Ext.ux.Reorderer"></div>/**
16 * @class Ext.ux.Reorderer
18 * Generic base class for handling reordering of items. This base class must be extended to provide the
19 * actual reordering functionality - the base class just sets up events and abstract logic functions.
20 * It will fire events and set defaults, deferring the actual reordering to a doReorder implementation.
21 * See Ext.ux.TabReorderer for an example.
23 Ext.ux.Reorderer = Ext.extend(Object, {
24 <div id="prop-Ext.ux.Reorderer-defaults"></div>/**
27 * Object containing default values for plugin configuration details. These can be overridden when
28 * constructing the plugin
31 <div id="cfg-Ext.ux.Reorderer-null"></div>/**
34 * If set to true, the rearranging of the toolbar items is animated
38 <div id="cfg-Ext.ux.Reorderer-null"></div>/**
39 * @cfg animationDuration
41 * The duration of the animation used to move other toolbar items out of the way
43 animationDuration: 0.2,
45 <div id="cfg-Ext.ux.Reorderer-null"></div>/**
46 * @cfg defaultReorderable
48 * True to make every toolbar draggable unless reorderable is specifically set to false.
49 * This defaults to false
51 defaultReorderable: false
54 <div id="method-Ext.ux.Reorderer-constructor"></div>/**
55 * Creates the plugin instance, applies defaults
57 * @param {Object} config Optional config object
59 constructor: function(config) {
60 Ext.apply(this, config || {}, this.defaults);
63 <div id="method-Ext.ux.Reorderer-init"></div>/**
64 * Initializes the plugin, stores a reference to the target
65 * @param {Mixed} target The target component which contains the reorderable items
67 init: function(target) {
68 <div id="prop-Ext.ux.Reorderer-target"></div>/**
71 * Reference to the target component which contains the reorderable items
77 var items = this.getItems(),
78 length = items.length,
81 for (i = 0; i < length; i++) {
82 this.createIfReorderable(items[i]);
86 <div id="method-Ext.ux.Reorderer-reorder"></div>/**
87 * Reorders the items in the target component according to the given mapping object. Example:
92 * Would move the item at index 1 to index 5, and the item at index 3 to index 2
93 * @param {Object} mappings Object containing current item index as key and new index as property
95 reorder: function(mappings) {
96 var target = this.target;
98 if (target.fireEvent('before-reorder', mappings, target, this) !== false) {
99 this.doReorder(mappings);
101 target.fireEvent('reorder', mappings, target, this);
105 <div id="method-Ext.ux.Reorderer-doReorder"></div>/**
106 * Abstract function to perform the actual reordering. This MUST be overridden in a subclass
107 * @param {Object} mappings Mappings of the old item indexes to new item indexes
109 doReorder: function(paramName) {
110 throw new Error("doReorder must be implemented in the Ext.ux.Reorderer subclass");
114 * Should create and return an Ext.dd.DD for the given item. This MUST be overridden in a subclass
115 * @param {Mixed} item The item to create a DD for. This could be a TabPanel tab, a Toolbar button, etc
116 * @return {Ext.dd.DD} The DD for the given item
118 createItemDD: function(item) {
119 throw new Error("createItemDD must be implemented in the Ext.ux.Reorderer subclass");
122 <div id="method-Ext.ux.Reorderer-createItemDD"></div>/**
123 * Sets up the given Toolbar item as a draggable
124 * @param {Mixed} button The item to make draggable (usually an Ext.Button instance)
126 createItemDD: function(button) {
127 var el = button.getEl(),
132 button.dd = new Ext.dd.DD(el, undefined, {
136 button.dd.constrainTo(tbar.getEl());
137 button.dd.setYConstraint(0, 0, 0);
139 Ext.apply(button.dd, {
140 b4StartDrag: function() {
141 this.startPosition = el.getXY();
143 //bump up the z index of the button being dragged but keep a reference to the original
144 this.startZIndex = el.getStyle('zIndex');
145 el.setStyle('zIndex', 10000);
147 button.suspendEvents();
150 onDrag: function(e) {
151 //calculate the button's index within the toolbar and its current midpoint
152 var buttonX = el.getXY()[0],
153 deltaX = buttonX - this.startPosition[0],
154 items = tbar.items.items,
155 oldIndex = items.indexOf(button),
158 //find which item in the toolbar the midpoint is currently over
159 for (var index = 0; index < items.length; index++) {
160 var item = items[index];
162 if (item.reorderable && item.id != button.id) {
163 //find the midpoint of the button
164 var box = item.getEl().getBox(),
165 midpoint = (me.buttonXCache[item.id] || box.x) + (box.width / 2),
166 movedLeft = oldIndex > index && deltaX < 0 && buttonX < midpoint,
167 movedRight = oldIndex < index && deltaX > 0 && (buttonX + el.getWidth()) > midpoint;
169 if (movedLeft || movedRight) {
170 me[movedLeft ? 'onMovedLeft' : 'onMovedRight'](button, index, oldIndex);
177 <div id="method-Ext.ux.Reorderer-endDrag"></div>/**
178 * After the drag has been completed, make sure the button being dragged makes it back to
179 * the correct location and resets its z index
181 endDrag: function() {
182 //we need to update the cache here for cases where the button was dragged but its
183 //position in the toolbar did not change
184 me.updateButtonXCache();
186 el.moveTo(me.buttonXCache[button.id], undefined, {
187 duration: me.animationDuration,
189 callback: function() {
190 button.resumeEvents();
192 tbar.fireEvent('reordered', button, tbar);
196 el.setStyle('zIndex', this.startZIndex);
203 * Creates a DD instance for a given item if it is reorderable
204 * @param {Mixed} item The item
206 createIfReorderable: function(item) {
207 if (this.defaultReorderable && item.reorderable == undefined) {
208 item.reorderable = true;
211 if (item.reorderable && !item.dd) {
213 this.createItemDD(item);
215 item.on('render', this.createItemDD.createDelegate(this, [item]), this, {single: true});
220 <div id="method-Ext.ux.Reorderer-getItems"></div>/**
221 * Returns an array of items which will be made draggable. This defaults to the contents of this.target.items,
222 * but can be overridden - e.g. for TabPanels
223 * @return {Array} The array of items which will be made draggable
225 getItems: function() {
226 return this.target.items.items;
229 <div id="method-Ext.ux.Reorderer-initEvents"></div>/**
230 * Adds before-reorder and reorder events to the target component
232 initEvents: function() {
233 this.target.addEvents(
234 <div id="event-Ext.ux.Reorderer-before-reorder"></div>/**
235 * @event before-reorder
236 * Fires before a reorder occurs. Return false to cancel
237 * @param {Object} mappings Mappings of the old item indexes to new item indexes
238 * @param {Mixed} component The target component
239 * @param {Ext.ux.TabReorderer} this The plugin instance
243 <div id="event-Ext.ux.Reorderer-reorder"></div>/**
245 * Fires after a reorder has occured.
246 * @param {Object} mappings Mappings of the old item indexes to the new item indexes
247 * @param {Mixed} component The target component
248 * @param {Ext.ux.TabReorderer} this The plugin instance
255 <div id="cls-Ext.ux.HBoxReorderer"></div>/**
256 * @class Ext.ux.HBoxReorderer
257 * @extends Ext.ux.Reorderer
260 Ext.ux.HBoxReorderer = Ext.extend(Ext.ux.Reorderer, {
261 <div id="method-Ext.ux.HBoxReorderer-init"></div>/**
262 * Initializes the plugin, decorates the container with additional functionality
264 init: function(container) {
265 <div id="prop-Ext.ux.HBoxReorderer-buttonXCache"></div>/**
266 * This is used to store the correct x value of each button in the array. We need to use this
267 * instead of the button's reported x co-ordinate because the buttons are animated when they move -
268 * if another onDrag is fired while the button is still moving, the comparison x value will be incorrect
270 this.buttonXCache = {};
274 add : function(container, item) {
275 this.createIfReorderable(item);
279 //super sets a reference to the toolbar in this.target
280 Ext.ux.HBoxReorderer.superclass.init.apply(this, arguments);
283 <div id="method-Ext.ux.HBoxReorderer-createItemDD"></div>/**
284 * Sets up the given Toolbar item as a draggable
285 * @param {Mixed} button The item to make draggable (usually an Ext.Button instance)
287 createItemDD: function(button) {
288 if (button.dd != undefined) {
292 var el = button.getEl(),
297 button.dd = new Ext.dd.DD(el, undefined, {
305 //if a button has a menu, it is disabled while dragging with this function
306 var menuDisabler = function() {
310 Ext.apply(button.dd, {
311 b4StartDrag: function() {
312 this.startPosition = el.getXY();
314 //bump up the z index of the button being dragged but keep a reference to the original
315 this.startZIndex = el.getStyle('zIndex');
316 el.setStyle('zIndex', 10000);
318 button.suspendEvents();
320 button.menu.on('beforeshow', menuDisabler, me);
324 startDrag: function() {
325 this.constrainTo(tbar.getEl());
326 this.setYConstraint(0, 0, 0);
329 onDrag: function(e) {
330 //calculate the button's index within the toolbar and its current midpoint
331 var buttonX = el.getXY()[0],
332 deltaX = buttonX - this.startPosition[0],
333 items = tbar.items.items,
334 length = items.length,
335 oldIndex = items.indexOf(button),
336 newIndex, index, item;
338 //find which item in the toolbar the midpoint is currently over
339 for (index = 0; index < length; index++) {
342 if (item.reorderable && item.id != button.id) {
343 //find the midpoint of the button
344 var box = item.getEl().getBox(),
345 midpoint = (me.buttonXCache[item.id] || box.x) + (box.width / 2),
346 movedLeft = oldIndex > index && deltaX < 0 && buttonX < midpoint,
347 movedRight = oldIndex < index && deltaX > 0 && (buttonX + el.getWidth()) > midpoint;
349 if (movedLeft || movedRight) {
350 me[movedLeft ? 'onMovedLeft' : 'onMovedRight'](button, index, oldIndex);
357 <div id="method-Ext.ux.HBoxReorderer-endDrag"></div>/**
358 * After the drag has been completed, make sure the button being dragged makes it back to
359 * the correct location and resets its z index
361 endDrag: function() {
362 //we need to update the cache here for cases where the button was dragged but its
363 //position in the toolbar did not change
364 me.updateButtonXCache();
366 el.moveTo(me.buttonXCache[button.id], el.getY(), {
367 duration: me.animationDuration,
369 callback: function() {
370 button.resumeEvents();
372 button.menu.un('beforeshow', menuDisabler, me);
375 tbar.fireEvent('reordered', button, tbar);
379 el.setStyle('zIndex', this.startZIndex);
384 onMovedLeft: function(item, newIndex, oldIndex) {
385 var tbar = this.target,
386 items = tbar.items.items,
387 length = items.length,
390 if (newIndex != undefined && newIndex != oldIndex) {
391 //move the button currently under drag to its new location
392 tbar.remove(item, false);
393 tbar.insert(newIndex, item);
395 //set the correct x location of each item in the toolbar
396 this.updateButtonXCache();
397 for (index = 0; index < length; index++) {
398 var obj = items[index],
399 newX = this.buttonXCache[obj.id];
402 item.dd.startPosition[0] = newX;
404 var el = obj.getEl();
406 el.moveTo(newX, el.getY(), {
407 duration: this.animationDuration
414 onMovedRight: function(item, newIndex, oldIndex) {
415 this.onMovedLeft.apply(this, arguments);
420 * Updates the internal cache of button X locations.
422 updateButtonXCache: function() {
423 var tbar = this.target,
425 totalX = tbar.getEl().getBox(true).x;
427 items.each(function(item) {
428 this.buttonXCache[item.id] = totalX;
430 totalX += item.getEl().getWidth();