Changeset 8032
- Timestamp:
- 06/02/2008 09:01:42 PM (18 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
-
wp-admin/edit-form-advanced.php (modified) (1 diff)
-
wp-admin/includes/post.php (modified) (1 diff)
-
wp-includes/js/jquery/ui.core.js (modified) (1 diff)
-
wp-includes/js/jquery/ui.sortable.js (modified) (2 diffs)
-
wp-includes/js/jquery/ui.tabs.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-admin/edit-form-advanced.php
r8011 r8032 92 92 <p> 93 93 <select name='post_status' id='post_status' tabindex='4'> 94 <?php if ( current_user_can('publish_posts') ) : // Contributors only get "Unpublished" and "Pending Review" ?> 94 <?php 95 // only show the publish menu item if they are allowed to publish posts or they are allowed to edit this post (accounts for 'edit_published_posts' capability) 96 if ( current_user_can('publish_posts') OR ( $post->post_status == 'publish' AND current_user_can('edit_post', $post->ID) ) ) : 97 ?> 95 98 <option<?php selected( $post->post_status, 'publish' ); selected( $post->post_status, 'private' );?> value='publish'><?php _e('Published') ?></option> 96 99 <?php if ( 'future' == $post->post_status ) : ?> -
trunk/wp-admin/includes/post.php
r8011 r8032 58 58 $_POST['post_status'] = 'draft'; 59 59 60 $previous_status = get_post_field('post_status', $_POST['ID']); 61 62 // Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published. 63 // Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts. 60 64 if ( 'page' == $_POST['post_type'] ) { 61 65 if ( 'publish' == $_POST['post_status'] && !current_user_can( 'publish_pages' ) ) 62 66 $_POST['post_status'] = 'pending'; 63 67 } else { 64 if ( 'publish' == $_POST['post_status'] && !current_user_can( 'publish_posts' ) ) 65 $_POST['post_status'] = 'pending'; 68 if ( 'publish' == $_POST['post_status'] && !current_user_can( 'publish_posts' ) ) : 69 // Stop attempts to publish new posts, but allow already published posts to be saved if appropriate. 70 if ( $previous_status != 'publish' OR !current_user_can( 'edit_published_posts') ) 71 $_POST['post_status'] = 'pending'; 72 endif; 66 73 } 67 74 -
trunk/wp-includes/js/jquery/ui.core.js
r7973 r8032 8 8 * http://docs.jquery.com/UI 9 9 * 10 * $Id: ui.core.js 5 634 2008-05-19 20:53:51Z joern.zaefferer$10 * $Id: ui.core.js 5587 2008-05-13 19:56:42Z scott.gonzalez $ 11 11 */ 12 12 ;(function($) { 13 14 $.ui = { 15 plugin: { 16 add: function(module, option, set) { 17 var proto = $.ui[module].prototype; 18 for(var i in set) { 19 proto.plugins[i] = proto.plugins[i] || []; 20 proto.plugins[i].push([option, set[i]]); 21 } 22 }, 23 call: function(instance, name, args) { 24 var set = instance.plugins[name]; 25 if(!set) { return; } 26 27 for (var i = 0; i < set.length; i++) { 28 if (instance.options[set[i][0]]) { 29 set[i][1].apply(instance.element, args); 30 } 31 } 32 } 33 }, 34 cssCache: {}, 35 css: function(name) { 36 if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; } 37 var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body'); 38 39 //if (!$.browser.safari) 40 //tmp.appendTo('body'); 41 42 //Opera and Safari set width and height to 0px instead of auto 43 //Safari returns rgba(0,0,0,0) when bgcolor is not set 44 $.ui.cssCache[name] = !!( 45 (!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 46 !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor'))) 47 ); 48 try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){} 49 return $.ui.cssCache[name]; 50 }, 51 disableSelection: function(e) { 52 e.unselectable = "on"; 53 e.onselectstart = function() { return false; }; 54 if (e.style) { e.style.MozUserSelect = "none"; } 55 }, 56 enableSelection: function(e) { 57 e.unselectable = "off"; 58 e.onselectstart = function() { return true; }; 59 if (e.style) { e.style.MozUserSelect = ""; } 60 }, 61 hasScroll: function(e, a) { 62 var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false; 63 if (e[scroll] > 0) return true; e[scroll] = 1; 64 has = e[scroll] > 0 ? true : false; e[scroll] = 0; 65 return has; 66 } 67 }; 68 69 70 /** jQuery core modifications and additions **/ 71 72 var _remove = $.fn.remove; 73 $.fn.remove = function() { 74 $("*", this).add(this).trigger("remove"); 75 return _remove.apply(this, arguments ); 76 }; 77 78 // $.widget is a factory to create jQuery plugins 79 // taking some boilerplate code out of the plugin code 80 // created by Scott González and Jörn Zaefferer 81 function getter(namespace, plugin, method) { 82 var methods = $[namespace][plugin].getter || []; 83 methods = (typeof methods == "string" ? methods.split(/,?\s+/) : methods); 84 return ($.inArray(method, methods) != -1); 85 } 86 87 var widgetPrototype = { 88 init: function() {}, 89 destroy: function() { 90 this.element.removeData(this.widgetName); 91 }, 92 93 getData: function(key) { 94 return this.options[key]; 95 }, 96 setData: function(key, value) { 97 this.options[key] = value; 98 }, 99 100 enable: function() { 101 this.setData('disabled', false); 102 }, 103 disable: function() { 104 this.setData('disabled', true); 105 } 106 }; 107 108 $.widget = function(name, prototype) { 109 var namespace = name.split(".")[0]; 110 name = name.split(".")[1]; 111 // create plugin method 112 $.fn[name] = function(options) { 113 var isMethodCall = (typeof options == 'string'), 114 args = Array.prototype.slice.call(arguments, 1); 115 116 if (isMethodCall && getter(namespace, name, options)) { 117 var instance = $.data(this[0], name); 118 return (instance ? instance[options].apply(instance, args) 119 : undefined); 120 } 121 122 return this.each(function() { 123 var instance = $.data(this, name); 124 if (!instance) { 125 $.data(this, name, new $[namespace][name](this, options)); 126 } else if (isMethodCall) { 127 instance[options].apply(instance, args); 128 } 129 }); 130 }; 131 132 // create widget constructor 133 $[namespace][name] = function(element, options) { 134 var self = this; 135 136 this.widgetName = name; 137 138 this.options = $.extend({}, $[namespace][name].defaults, options); 139 this.element = $(element) 140 .bind('setData.' + name, function(e, key, value) { 141 return self.setData(key, value); 142 }) 143 .bind('getData.' + name, function(e, key) { 144 return self.getData(key); 145 }) 146 .bind('remove', function() { 147 return self.destroy(); 148 }); 149 this.init(); 150 }; 151 152 // add widget prototype 153 $[namespace][name].prototype = $.extend({}, widgetPrototype, prototype); 154 }; 155 156 157 /** Mouse Interaction Plugin **/ 158 159 $.widget("ui.mouse", { 160 init: function() { 161 var self = this; 162 163 this.element 164 .bind('mousedown.mouse', function() { return self.click.apply(self, arguments); }) 165 .bind('mouseup.mouse', function() { (self.timer && clearTimeout(self.timer)); }) 166 .bind('click.mouse', function() { if(self.initialized) { self.initialized = false; return false; } }); 167 //Prevent text selection in IE 168 if ($.browser.msie) { 169 this.unselectable = this.element.attr('unselectable'); 170 this.element.attr('unselectable', 'on'); 13 14 $.ui = { 15 plugin: { 16 add: function(module, option, set) { 17 var proto = $.ui[module].prototype; 18 for(var i in set) { 19 proto.plugins[i] = proto.plugins[i] || []; 20 proto.plugins[i].push([option, set[i]]); 171 21 } 172 22 }, 173 destroy: function() { 174 this.element.unbind('.mouse').removeData("mouse"); 175 ($.browser.msie && this.element.attr('unselectable', this.unselectable)); 176 }, 177 trigger: function() { return this.click.apply(this, arguments); }, 178 click: function(e) { 179 180 if( e.which != 1 //only left click starts dragging 181 || $.inArray(e.target.nodeName.toLowerCase(), this.options.dragPrevention || []) != -1 // Prevent execution on defined elements 182 || (this.options.condition && !this.options.condition.apply(this.options.executor || this, [e, this.element])) //Prevent execution on condition 183 ) { return true; } 184 185 var self = this; 186 this.initialized = false; 187 var initialize = function() { 188 self._MP = { left: e.pageX, top: e.pageY }; // Store the click mouse position 189 $(document).bind('mouseup.mouse', function() { return self.stop.apply(self, arguments); }); 190 $(document).bind('mousemove.mouse', function() { return self.drag.apply(self, arguments); }); 191 192 if(!self.initalized && Math.abs(self._MP.left-e.pageX) >= self.options.distance || Math.abs(self._MP.top-e.pageY) >= self.options.distance) { 193 (self.options.start && self.options.start.call(self.options.executor || self, e, self.element)); 194 (self.options.drag && self.options.drag.call(self.options.executor || self, e, this.element)); //This is actually not correct, but expected 195 self.initialized = true; 23 call: function(instance, name, args) { 24 var set = instance.plugins[name]; 25 if(!set) { return; } 26 27 for (var i = 0; i < set.length; i++) { 28 if (instance.options[set[i][0]]) { 29 set[i][1].apply(instance.element, args); 196 30 } 197 };198 199 if(this.options.delay) {200 if(this.timer) { clearTimeout(this.timer); }201 this.timer = setTimeout(initialize, this.options.delay);202 } else {203 initialize();204 31 } 205 32 } 33 }, 34 cssCache: {}, 35 css: function(name) { 36 if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; } 37 var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body'); 38 39 //if (!$.browser.safari) 40 //tmp.appendTo('body'); 41 42 //Opera and Safari set width and height to 0px instead of auto 43 //Safari returns rgba(0,0,0,0) when bgcolor is not set 44 $.ui.cssCache[name] = !!( 45 (!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 46 !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor'))) 47 ); 48 try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){} 49 return $.ui.cssCache[name]; 50 }, 51 disableSelection: function(e) { 52 e.unselectable = "on"; 53 e.onselectstart = function() { return false; }; 54 if (e.style) { e.style.MozUserSelect = "none"; } 55 }, 56 enableSelection: function(e) { 57 e.unselectable = "off"; 58 e.onselectstart = function() { return true; }; 59 if (e.style) { e.style.MozUserSelect = ""; } 60 }, 61 hasScroll: function(e, a) { 62 var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false; 63 if (e[scroll] > 0) return true; e[scroll] = 1; 64 has = e[scroll] > 0 ? true : false; e[scroll] = 0; 65 return has; 66 } 67 }; 68 69 70 /** jQuery core modifications and additions **/ 71 72 var _remove = $.fn.remove; 73 $.fn.remove = function() { 74 $("*", this).add(this).trigger("remove"); 75 return _remove.apply(this, arguments ); 76 }; 77 78 // $.widget is a factory to create jQuery plugins 79 // taking some boilerplate code out of the plugin code 80 // created by Scott González and Jörn Zaefferer 81 function getter(namespace, plugin, method) { 82 var methods = $[namespace][plugin].getter || []; 83 methods = (typeof methods == "string" ? methods.split(/,?\s+/) : methods); 84 return ($.inArray(method, methods) != -1); 85 } 86 87 var widgetPrototype = { 88 init: function() {}, 89 destroy: function() { 90 this.element.removeData(this.widgetName); 91 }, 92 93 getData: function(key) { 94 return this.options[key]; 95 }, 96 setData: function(key, value) { 97 this.options[key] = value; 98 }, 99 100 enable: function() { 101 this.setData('disabled', false); 102 }, 103 disable: function() { 104 this.setData('disabled', true); 105 } 106 }; 107 108 $.widget = function(name, prototype) { 109 var namespace = name.split(".")[0]; 110 name = name.split(".")[1]; 111 // create plugin method 112 $.fn[name] = function(options) { 113 var isMethodCall = (typeof options == 'string'), 114 args = Array.prototype.slice.call(arguments, 1); 115 116 if (isMethodCall && getter(namespace, name, options)) { 117 var instance = $.data(this[0], name); 118 return (instance ? instance[options].apply(instance, args) 119 : undefined); 120 } 121 122 return this.each(function() { 123 var instance = $.data(this, name); 124 if (!instance) { 125 $.data(this, name, new $[namespace][name](this, options)); 126 } else if (isMethodCall) { 127 instance[options].apply(instance, args); 128 } 129 }); 130 }; 131 132 // create widget constructor 133 $[namespace][name] = function(element, options) { 134 var self = this; 135 136 this.widgetName = name; 137 138 this.options = $.extend({}, $[namespace][name].defaults, options); 139 this.element = $(element) 140 .bind('setData.' + name, function(e, key, value) { 141 return self.setData(key, value); 142 }) 143 .bind('getData.' + name, function(e, key) { 144 return self.getData(key); 145 }) 146 .bind('remove', function() { 147 return self.destroy(); 148 }); 149 this.init(); 150 }; 151 152 // add widget prototype 153 $[namespace][name].prototype = $.extend({}, widgetPrototype, prototype); 154 }; 155 156 157 /** Mouse Interaction Plugin **/ 158 159 $.ui.mouse = { 160 mouseInit: function() { 161 var self = this; 162 163 this.element.bind('mousedown.'+this.widgetName, function(e) { 164 return self.mouseDown(e); 165 }); 166 167 // Prevent text selection in IE 168 if ($.browser.msie) { 169 this._mouseUnselectable = this.element.attr('unselectable'); 170 this.element.attr('unselectable', 'on'); 171 } 172 173 this.started = false; 174 }, 175 176 // TODO: make sure destroying one instance of mouse doesn't mess with 177 // other instances of mouse 178 mouseDestroy: function() { 179 this.element.unbind('.'+this.widgetName); 180 181 // Restore text selection in IE 182 ($.browser.msie 183 && this.element.attr('unselectable', this._mouseUnselectable)); 184 }, 185 186 mouseDown: function(e) { 187 // we may have missed mouseup (out of window) 188 (this._mouseStarted && this.mouseUp(e)); 189 190 this._mouseDownEvent = e; 191 192 var self = this, 193 btnIsLeft = (e.which == 1), 194 elIsCancel = ($(e.target).is(this.options.cancel)); 195 if (!btnIsLeft || elIsCancel) { 196 return true; 197 } 198 199 this._mouseDelayMet = !this.options.delay; 200 if (!this._mouseDelayMet) { 201 this._mouseDelayTimer = setTimeout(function() { 202 self._mouseDelayMet = true; 203 }, this.options.delay); 204 } 205 206 // these delegates are required to keep context 207 this._mouseMoveDelegate = function(e) { 208 return self.mouseMove(e); 209 }; 210 this._mouseUpDelegate = function(e) { 211 return self.mouseUp(e); 212 }; 213 $(document) 214 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) 215 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); 216 217 return false; 218 }, 219 220 mouseMove: function(e) { 221 // IE mouseup check - mouseup happened when mouse was out of window 222 if ($.browser.msie && !e.button) { 223 return this.mouseUp(e); 224 } 225 226 if (this._mouseStarted) { 227 this.mouseDrag(e); 206 228 return false; 207 208 }, 209 stop: function(e) { 210 211 if(!this.initialized) { 212 return $(document).unbind('mouseup.mouse').unbind('mousemove.mouse'); 213 } 214 215 (this.options.stop && this.options.stop.call(this.options.executor || this, e, this.element)); 216 217 $(document).unbind('mouseup.mouse').unbind('mousemove.mouse'); 218 return false; 219 220 }, 221 drag: function(e) { 222 223 var o = this.options; 224 if ($.browser.msie && !e.button) { 225 return this.stop.call(this, e); // IE mouseup check 226 } 227 228 if(!this.initialized && (Math.abs(this._MP.left-e.pageX) >= o.distance || Math.abs(this._MP.top-e.pageY) >= o.distance)) { 229 (o.start && o.start.call(o.executor || this, e, this.element)); 230 this.initialized = true; 231 } else { 232 if(!this.initialized) { return false; } 233 } 234 235 (o.drag && o.drag.call(this.options.executor || this, e, this.element)); 236 return false; 237 238 } 239 }); 240 229 } 230 231 if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) { 232 this._mouseStarted = 233 (this.mouseStart(this._mouseDownEvent, e) !== false); 234 (this._mouseStarted || this.mouseUp(e)); 235 } 236 237 return !this._mouseStarted; 238 }, 239 240 mouseUp: function(e) { 241 $(document) 242 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) 243 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); 244 245 if (this._mouseStarted) { 246 this._mouseStarted = false; 247 this.mouseStop(e); 248 } 249 250 return false; 251 }, 252 253 mouseDistanceMet: function(e) { 254 return (Math.max( 255 Math.abs(this._mouseDownEvent.pageX - e.pageX), 256 Math.abs(this._mouseDownEvent.pageY - e.pageY) 257 ) >= this.options.distance 258 ); 259 }, 260 261 mouseDelayMet: function(e) { 262 return this._mouseDelayMet; 263 }, 264 265 // These are placeholder methods, to be overriden by extending plugin 266 mouseStart: function(e) {}, 267 mouseDrag: function(e) {}, 268 mouseStop: function(e) {} 269 }; 270 271 $.ui.mouse.defaults = { 272 cancel: null, 273 distance: 0, 274 delay: 0 275 }; 276 241 277 })(jQuery); -
trunk/wp-includes/js/jquery/ui.sortable.js
r7973 r8032 14 14 */ 15 15 ;(function($) { 16 17 function contains(a, b) { 18 var safari2 = $.browser.safari && $.browser.version < 522; 19 if (a.contains && !safari2) { 20 return a.contains(b); 21 } 22 if (a.compareDocumentPosition) 23 return !!(a.compareDocumentPosition(b) & 16); 24 while (b = b.parentNode) 25 if (b == a) return true; 26 return false; 27 }; 28 29 $.widget("ui.sortable", $.extend($.ui.mouse, { 30 init: function() { 31 32 var o = this.options; 33 this.containerCache = {}; 34 this.element.addClass("ui-sortable"); 16 35 17 function contains(a, b) { 18 var safari2 = $.browser.safari && $.browser.version < 522; 19 if (a.contains && !safari2) { 20 return a.contains(b); 21 } 22 if (a.compareDocumentPosition) 23 return !!(a.compareDocumentPosition(b) & 16); 24 while (b = b.parentNode) 25 if (b == a) return true; 26 return false; 27 }; 28 29 $.widget("ui.sortable", { 30 init: function() { 31 32 var o = this.options; 33 this.containerCache = {}; 34 this.element.addClass("ui-sortable"); 35 36 //Get the items 37 this.refresh(); 38 39 //Let's determine if the items are floating 40 this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; 36 //Get the items 37 this.refresh(); 38 39 //Let's determine if the items are floating 40 this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; 41 42 //Let's determine the parent's offset 43 if(!(/(relative|absolute|fixed)/).test(this.element.css('position'))) this.element.css('position', 'relative'); 44 this.offset = this.element.offset(); 45 46 //Initialize mouse events for interaction 47 this.mouseInit(); 48 49 }, 50 plugins: {}, 51 ui: function(inst) { 52 return { 53 helper: (inst || this)["helper"], 54 placeholder: (inst || this)["placeholder"] || $([]), 55 position: (inst || this)["position"], 56 absolutePosition: (inst || this)["positionAbs"], 57 options: this.options, 58 element: this.element, 59 item: (inst || this)["currentItem"], 60 sender: inst ? inst.element : null 61 }; 62 }, 63 propagate: function(n,e,inst, noPropagation) { 64 $.ui.plugin.call(this, n, [e, this.ui(inst)]); 65 if(!noPropagation) this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]); 66 }, 67 serialize: function(o) { 68 69 70 71 var items = ($.isFunction(this.options.items) ? this.options.items.call(this.element) : $(this.options.items, this.element)).not('.ui-sortable-helper'); //Only the items of the sortable itself 72 var str = []; o = o || {}; 73 74 items.each(function() { 75 var res = ($(this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); 76 if(res) str.push((o.key || res[1])+'[]='+(o.key ? res[1] : res[2])); 77 }); 78 79 return str.join('&'); 80 81 }, 82 toArray: function(attr) { 83 var items = ($.isFunction(this.options.items) ? this.options.items.call(this.element) : $(this.options.items, this.element)).not('.ui-sortable-helper'); //Only the items of the sortable itself 84 var ret = []; 85 86 items.each(function() { ret.push($(this).attr(attr || 'id')); }); 87 return ret; 88 }, 89 enable: function() { 90 this.element.removeClass("ui-sortable-disabled"); 91 this.options.disabled = false; 92 }, 93 disable: function() { 94 this.element.addClass("ui-sortable-disabled"); 95 this.options.disabled = true; 96 }, 97 /* Be careful with the following core functions */ 98 intersectsWith: function(item) { 99 100 var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width, 101 y1 = this.positionAbs.top, y2 = y1 + this.helperProportions.height; 102 var l = item.left, r = l + item.width, 103 t = item.top, b = t + item.height; 104 105 if(this.options.tolerance == "pointer") { 106 return (y1 + this.offset.click.top > t && y1 + this.offset.click.top < b && x1 + this.offset.click.left > l && x1 + this.offset.click.left < r); 107 } else { 108 109 return (l < x1 + (this.helperProportions.width / 2) // Right Half 110 && x2 - (this.helperProportions.width / 2) < r // Left Half 111 && t < y1 + (this.helperProportions.height / 2) // Bottom Half 112 && y2 - (this.helperProportions.height / 2) < b ); // Top Half 113 114 } 115 116 }, 117 intersectsWithEdge: function(item) { 118 var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width, 119 y1 = this.positionAbs.top, y2 = y1 + this.helperProportions.height; 120 var l = item.left, r = l + item.width, 121 t = item.top, b = t + item.height; 122 123 if(this.options.tolerance == "pointer" || (this.options.tolerance == "guess" && this.currentItem[0]['offset'+(this.floating ? 'Width' : 'Height')] > item.item[0]['offset'+(this.floating ? 'Width' : 'Height')])) { 124 125 if(!(y1 + this.offset.click.top > t && y1 + this.offset.click.top < b && x1 + this.offset.click.left > l && x1 + this.offset.click.left < r)) return false; 41 126 42 //Let's determine the parent's offset 43 if(!(/(relative|absolute|fixed)/).test(this.element.css('position'))) this.element.css('position', 'relative'); 44 this.offset = this.element.offset(); 45 46 //Initialize mouse events for interaction 47 this.element.mouse({ 48 executor: this, 49 delay: o.delay, 50 distance: o.distance || 1, 51 dragPrevention: o.prevention ? o.prevention.toLowerCase().split(',') : ['input','textarea','button','select','option'], 52 start: this.start, 53 stop: this.stop, 54 drag: this.drag, 55 condition: function(e) { 56 57 if(this.options.disabled || this.options.type == 'static') return false; 58 59 //Find out if the clicked node (or one of its parents) is a actual item in this.items 60 var currentItem = null, nodes = $(e.target).parents().each(function() { 61 if($.data(this, 'sortable-item')) { 62 currentItem = $(this); 63 return false; 64 } 65 }); 66 if($.data(e.target, 'sortable-item')) currentItem = $(e.target); 67 68 if(!currentItem) return false; 69 if(this.options.handle) { 70 var validHandle = false; 71 $(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; }); 72 if(!validHandle) return false; 73 } 74 75 this.currentItem = currentItem; 76 return true; 77 78 } 79 }); 127 if(this.floating) { 128 if(x1 + this.offset.click.left > l && x1 + this.offset.click.left < l + item.width/2) return 2; 129 if(x1 + this.offset.click.left > l+item.width/2 && x1 + this.offset.click.left < r) return 1; 130 } else { 131 if(y1 + this.offset.click.top > t && y1 + this.offset.click.top < t + item.height/2) return 2; 132 if(y1 + this.offset.click.top > t+item.height/2 && y1 + this.offset.click.top < b) return 1; 133 } 134 135 } else { 136 137 if (!(l < x1 + (this.helperProportions.width / 2) // Right Half 138 && x2 - (this.helperProportions.width / 2) < r // Left Half 139 && t < y1 + (this.helperProportions.height / 2) // Bottom Half 140 && y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half 80 141 81 }, 82 plugins: {}, 83 ui: function(inst) { 84 return { 85 helper: (inst || this)["helper"], 86 placeholder: (inst || this)["placeholder"] || $([]), 87 position: (inst || this)["position"].current, 88 absolutePosition: (inst || this)["position"].absolute, 89 instance: this, 90 options: this.options, 91 element: this.element, 92 item: (inst || this)["currentItem"], 93 sender: inst ? inst.element : null 94 }; 95 }, 96 propagate: function(n,e,inst) { 97 $.ui.plugin.call(this, n, [e, this.ui(inst)]); 98 this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]); 99 }, 100 serialize: function(o) { 101 102 var items = $(this.options.items, this.element).not('.ui-sortable-helper'); //Only the items of the sortable itself 103 var str = []; o = o || {}; 104 105 items.each(function() { 106 var res = ($(this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); 107 if(res) str.push((o.key || res[1])+'[]='+(o.key ? res[1] : res[2])); 108 }); 109 110 return str.join('&'); 111 112 }, 113 toArray: function(attr) { 114 var items = $(this.options.items, this.element).not('.ui-sortable-helper'); //Only the items of the sortable itself 115 var ret = []; 116 117 items.each(function() { ret.push($(this).attr(attr || 'id')); }); 118 return ret; 119 }, 120 enable: function() { 121 this.element.removeClass("ui-sortable-disabled"); 122 this.options.disabled = false; 123 }, 124 disable: function() { 125 this.element.addClass("ui-sortable-disabled"); 126 this.options.disabled = true; 127 }, 128 /* Be careful with the following core functions */ 129 intersectsWith: function(item) { 130 131 var x1 = this.position.absolute.left, x2 = x1 + this.helperProportions.width, 132 y1 = this.position.absolute.top, y2 = y1 + this.helperProportions.height; 133 var l = item.left, r = l + item.width, 134 t = item.top, b = t + item.height; 135 136 if(this.options.tolerance == "pointer") { 137 return (y1 + this.clickOffset.top > t && y1 + this.clickOffset.top < b && x1 + this.clickOffset.left > l && x1 + this.clickOffset.left < r); 142 if(this.floating) { 143 if(x2 > l && x1 < l) return 2; //Crosses left edge 144 if(x1 < r && x2 > r) return 1; //Crosses right edge 138 145 } else { 139 140 return (l < x1 + (this.helperProportions.width / 2) // Right Half 141 && x2 - (this.helperProportions.width / 2) < r // Left Half 142 && t < y1 + (this.helperProportions.height / 2) // Bottom Half 143 && y2 - (this.helperProportions.height / 2) < b ); // Top Half 144 146 if(y2 > t && y1 < t) return 1; //Crosses top edge 147 if(y1 < b && y2 > b) return 2; //Crosses bottom edge 145 148 } 146 147 }, 148 intersectsWithEdge: function(item) { 149 var x1 = this.position.absolute.left, x2 = x1 + this.helperProportions.width, 150 y1 = this.position.absolute.top, y2 = y1 + this.helperProportions.height; 151 var l = item.left, r = l + item.width, 152 t = item.top, b = t + item.height; 153 154 if(this.options.tolerance == "pointer") { 155 156 if(!(y1 + this.clickOffset.top > t && y1 + this.clickOffset.top < b && x1 + this.clickOffset.left > l && x1 + this.clickOffset.left < r)) return false; 157 158 if(this.floating) { 159 if(x1 + this.clickOffset.left > l && x1 + this.clickOffset.left < l + item.width/2) return 2; 160 if(x1 + this.clickOffset.left > l+item.width/2 && x1 + this.clickOffset.left < r) return 1; 161 } else { 162 if(y1 + this.clickOffset.top > t && y1 + this.clickOffset.top < t + item.height/2) return 2; 163 if(y1 + this.clickOffset.top > t+item.height/2 && y1 + this.clickOffset.top < b) return 1; 164 } 165 166 } else { 167 168 if (!(l < x1 + (this.helperProportions.width / 2) // Right Half 169 && x2 - (this.helperProportions.width / 2) < r // Left Half 170 && t < y1 + (this.helperProportions.height / 2) // Bottom Half 171 && y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half 172 173 if(this.floating) { 174 if(x2 > l && x1 < l) return 2; //Crosses left edge 175 if(x1 < r && x2 > r) return 1; //Crosses right edge 176 } else { 177 if(y2 > t && y1 < t) return 1; //Crosses top edge 178 if(y1 < b && y2 > b) return 2; //Crosses bottom edge 179 } 180 181 } 182 183 return false; 184 185 }, 186 //This method checks approximately if the item is dragged in a container, but doesn't touch any items 187 inEmptyZone: function(container) { 188 189 if(!$(container.options.items, container.element).length) { 190 return container.options.dropOnEmpty ? true : false; 191 }; 192 193 var last = $(container.options.items, container.element).not('.ui-sortable-helper'); last = $(last[last.length-1]); 194 var top = last.offset()[this.floating ? 'left' : 'top'] + last[0][this.floating ? 'offsetWidth' : 'offsetHeight']; 195 return (this.position.absolute[this.floating ? 'left' : 'top'] > top); 196 }, 197 refresh: function() { 198 this.refreshItems(); 199 this.refreshPositions(); 200 }, 201 refreshItems: function() { 202 203 this.items = []; 204 this.containers = [this]; 205 var items = this.items; 206 var queries = [$(this.options.items, this.element)]; 207 208 if(this.options.connectWith) { 209 for (var i = this.options.connectWith.length - 1; i >= 0; i--){ 210 var cur = $(this.options.connectWith[i]); 211 for (var j = cur.length - 1; j >= 0; j--){ 212 var inst = $.data(cur[j], 'sortable'); 213 if(inst && !inst.options.disabled) { 214 queries.push($(inst.options.items, inst.element)); 215 this.containers.push(inst); 216 } 217 }; 218 }; 219 } 220 221 for (var i = queries.length - 1; i >= 0; i--){ 222 queries[i].each(function() { 223 $.data(this, 'sortable-item', true); // Data for target checking (mouse manager) 224 items.push({ 225 item: $(this), 226 width: 0, height: 0, 227 left: 0, top: 0 228 }); 229 }); 230 }; 231 232 }, 233 refreshPositions: function(fast) { 234 for (var i = this.items.length - 1; i >= 0; i--){ 235 var t = this.items[i].item; 236 if(!fast) this.items[i].width = (this.options.toleranceElement ? $(this.options.toleranceElement, t) : t).outerWidth(); 237 if(!fast) this.items[i].height = (this.options.toleranceElement ? $(this.options.toleranceElement, t) : t).outerHeight(); 238 var p = (this.options.toleranceElement ? $(this.options.toleranceElement, t) : t).offset(); 239 this.items[i].left = p.left; 240 this.items[i].top = p.top; 241 }; 242 for (var i = this.containers.length - 1; i >= 0; i--){ 243 var p =this.containers[i].element.offset(); 244 this.containers[i].containerCache.left = p.left; 245 this.containers[i].containerCache.top = p.top; 246 this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); 247 this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); 248 }; 249 }, 250 destroy: function() { 251 this.element 252 .removeClass("ui-sortable ui-sortable-disabled") 253 .removeData("sortable") 254 .unbind(".sortable") 255 .mouse("destroy"); 256 257 for ( var i = this.items.length - 1; i >= 0; i-- ) 258 this.items[i].item.removeData("sortable-item"); 259 }, 260 createPlaceholder: function(that) { 261 (that || this).placeholderElement = this.options.placeholderElement ? $(this.options.placeholderElement, (that || this).currentItem) : (that || this).currentItem; 262 (that || this).placeholder = $('<div></div>') 263 .addClass(this.options.placeholder) 264 .appendTo('body') 265 .css({ position: 'absolute' }) 266 .css((that || this).placeholderElement.offset()) 267 .css({ width: (that || this).placeholderElement.outerWidth(), height: (that || this).placeholderElement.outerHeight() }) 268 ; 269 }, 270 contactContainers: function(e) { 271 for (var i = this.containers.length - 1; i >= 0; i--){ 272 273 if(this.intersectsWith(this.containers[i].containerCache)) { 274 if(!this.containers[i].containerCache.over) { 275 276 277 if(this.currentContainer != this.containers[i]) { 278 279 //When entering a new container, we will find the item with the least distance and append our item near it 280 var dist = 10000; var itemWithLeastDistance = null; var base = this.position.absolute[this.containers[i].floating ? 'left' : 'top']; 281 for (var j = this.items.length - 1; j >= 0; j--) { 282 if(!contains(this.containers[i].element[0], this.items[j].item[0])) continue; 283 var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; 284 if(Math.abs(cur - base) < dist) { 285 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; 286 } 287 } 288 289 //We also need to exchange the placeholder 290 if(this.placeholder) this.placeholder.remove(); 291 if(this.containers[i].options.placeholder) { 292 this.containers[i].createPlaceholder(this); 293 } else { 294 this.placeholder = null; this.placeholderElement = null; 295 } 296 297 298 itemWithLeastDistance ? this.rearrange(e, itemWithLeastDistance) : this.rearrange(e, null, this.containers[i].element); 299 this.propagate("change", e); //Call plugins and callbacks 300 this.containers[i].propagate("change", e, this); //Call plugins and callbacks 301 this.currentContainer = this.containers[i]; 302 303 } 304 305 this.containers[i].propagate("over", e, this); 306 this.containers[i].containerCache.over = 1; 307 } 308 } else { 309 if(this.containers[i].containerCache.over) { 310 this.containers[i].propagate("out", e, this); 311 this.containers[i].containerCache.over = 0; 312 } 313 } 314 315 }; 316 }, 317 start: function(e,el) { 318 319 var o = this.options; 320 this.currentContainer = this; 321 this.refresh(); 322 323 //Create and append the visible helper 324 this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : this.currentItem.clone(); 325 if(!this.helper.parents('body').length) this.helper.appendTo(o.appendTo || this.currentItem[0].parentNode); //Add the helper to the DOM if that didn't happen already 326 this.helper.css({ position: 'absolute', clear: 'both' }).addClass('ui-sortable-helper'); //Position it absolutely and add a helper class 327 328 //Prepare variables for position generation 329 $.extend(this, { 330 offsetParent: this.helper.offsetParent(), 331 offsets: { 332 absolute: this.currentItem.offset() 333 }, 334 mouse: { 335 start: { top: e.pageY, left: e.pageX } 336 }, 337 margins: { 338 top: parseInt(this.currentItem.css("marginTop")) || 0, 339 left: parseInt(this.currentItem.css("marginLeft")) || 0 340 } 341 }); 342 343 //The relative click offset 344 this.offsets.parent = this.offsetParent.offset(); 345 this.clickOffset = { left: e.pageX - this.offsets.absolute.left, top: e.pageY - this.offsets.absolute.top }; 346 347 this.originalPosition = { 348 left: this.offsets.absolute.left - this.offsets.parent.left - this.margins.left, 349 top: this.offsets.absolute.top - this.offsets.parent.top - this.margins.top 350 } 351 352 //Generate a flexible offset that will later be subtracted from e.pageX/Y 353 //I hate margins - they need to be removed before positioning the element absolutely.. 354 this.offset = { 355 left: e.pageX - this.originalPosition.left, 356 top: e.pageY - this.originalPosition.top 357 }; 358 359 //Save the first time position 360 $.extend(this, { 361 position: { 362 current: { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left }, 363 absolute: { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top }, 364 dom: this.currentItem.prev()[0] 365 } 366 }); 367 368 //If o.placeholder is used, create a new element at the given position with the class 369 if(o.placeholder) this.createPlaceholder(); 370 371 this.propagate("start", e); //Call plugins and callbacks 372 this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Save and store the helper proportions 373 374 //If we have something in cursorAt, we'll use it 375 if(o.cursorAt) { 376 if(o.cursorAt.top != undefined || o.cursorAt.bottom != undefined) { 377 this.offset.top -= this.clickOffset.top - (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom)); 378 this.clickOffset.top = (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom)); 379 } 380 if(o.cursorAt.left != undefined || o.cursorAt.right != undefined) { 381 this.offset.left -= this.clickOffset.left - (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right)); 382 this.clickOffset.left = (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right)); 383 } 384 } 385 386 if(this.options.placeholder != 'clone') $(this.currentItem).css('visibility', 'hidden'); //Set the original element visibility to hidden to still fill out the white space 387 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i].propagate("activate", e, this); } //Post 'activate' events to possible containers 388 389 //Prepare possible droppables 390 if($.ui.ddmanager) $.ui.ddmanager.current = this; 391 if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e); 392 393 this.dragging = true; 394 return false; 395 396 }, 397 stop: function(e) { 398 399 this.propagate("stop", e); //Call plugins and trigger callbacks 400 if(this.position.dom != this.currentItem.prev()[0]) this.propagate("update", e); //Trigger update callback if the DOM position has changed 401 if(!contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element 402 this.propagate("remove", e); 403 for (var i = this.containers.length - 1; i >= 0; i--){ 404 if(contains(this.containers[i].element[0], this.currentItem[0])) { 405 this.containers[i].propagate("update", e, this); 406 this.containers[i].propagate("receive", e, this); 149 150 } 151 152 return false; 153 154 }, 155 refresh: function() { 156 this.refreshItems(); 157 this.refreshPositions(); 158 }, 159 refreshItems: function() { 160 161 this.items = []; 162 this.containers = [this]; 163 var items = this.items; 164 var queries = [$.isFunction(this.options.items) ? this.options.items.call(this.element) : $(this.options.items, this.element)]; 165 166 if(this.options.connectWith) { 167 for (var i = this.options.connectWith.length - 1; i >= 0; i--){ 168 var cur = $(this.options.connectWith[i]); 169 for (var j = cur.length - 1; j >= 0; j--){ 170 var inst = $.data(cur[j], 'sortable'); 171 if(inst && !inst.options.disabled) { 172 queries.push($.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element)); 173 this.containers.push(inst); 407 174 } 408 175 }; 409 176 }; 410 411 //Post events to containers 412 for (var i = this.containers.length - 1; i >= 0; i--){ 413 this.containers[i].propagate("deactivate", e, this); 177 } 178 179 for (var i = queries.length - 1; i >= 0; i--){ 180 queries[i].each(function() { 181 $.data(this, 'sortable-item', true); // Data for target checking (mouse manager) 182 items.push({ 183 item: $(this), 184 width: 0, height: 0, 185 left: 0, top: 0 186 }); 187 }); 188 }; 189 190 }, 191 refreshPositions: function(fast) { 192 for (var i = this.items.length - 1; i >= 0; i--){ 193 var t = this.items[i].item; 194 if(!fast) this.items[i].width = (this.options.toleranceElement ? $(this.options.toleranceElement, t) : t).outerWidth(); 195 if(!fast) this.items[i].height = (this.options.toleranceElement ? $(this.options.toleranceElement, t) : t).outerHeight(); 196 var p = (this.options.toleranceElement ? $(this.options.toleranceElement, t) : t).offset(); 197 this.items[i].left = p.left; 198 this.items[i].top = p.top; 199 }; 200 for (var i = this.containers.length - 1; i >= 0; i--){ 201 var p =this.containers[i].element.offset(); 202 this.containers[i].containerCache.left = p.left; 203 this.containers[i].containerCache.top = p.top; 204 this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); 205 this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); 206 }; 207 }, 208 destroy: function() { 209 this.element 210 .removeClass("ui-sortable ui-sortable-disabled") 211 .removeData("sortable") 212 .unbind(".sortable"); 213 this.mouseDestroy(); 214 215 for ( var i = this.items.length - 1; i >= 0; i-- ) 216 this.items[i].item.removeData("sortable-item"); 217 }, 218 createPlaceholder: function(that) { 219 220 var self = that || this, o = self.options; 221 222 if(o.placeholder.constructor == String) { 223 var className = o.placeholder; 224 o.placeholder = { 225 element: function() { 226 return $('<div></div>').addClass(className)[0]; 227 }, 228 update: function(i, p) { 229 p.css(i.offset()).css({ width: i.outerWidth(), height: i.outerHeight() }); 230 } 231 }; 232 } 233 234 self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)).appendTo('body').css({ position: 'absolute' }); 235 o.placeholder.update.call(self.element, self.currentItem, self.placeholder); 236 }, 237 contactContainers: function(e) { 238 for (var i = this.containers.length - 1; i >= 0; i--){ 239 240 if(this.intersectsWith(this.containers[i].containerCache)) { 241 if(!this.containers[i].containerCache.over) { 242 243 244 if(this.currentContainer != this.containers[i]) { 245 246 //When entering a new container, we will find the item with the least distance and append our item near it 247 var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top']; 248 for (var j = this.items.length - 1; j >= 0; j--) { 249 if(!contains(this.containers[i].element[0], this.items[j].item[0])) continue; 250 var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; 251 if(Math.abs(cur - base) < dist) { 252 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; 253 } 254 } 255 256 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled 257 continue; 258 259 //We also need to exchange the placeholder 260 if(this.placeholder) this.placeholder.remove(); 261 if(this.containers[i].options.placeholder) { 262 this.containers[i].createPlaceholder(this); 263 } else { 264 this.placeholder = null;; 265 } 266 267 268 itemWithLeastDistance ? this.rearrange(e, itemWithLeastDistance) : this.rearrange(e, null, this.containers[i].element); 269 this.propagate("change", e); //Call plugins and callbacks 270 this.containers[i].propagate("change", e, this); //Call plugins and callbacks 271 this.currentContainer = this.containers[i]; 272 273 } 274 275 this.containers[i].propagate("over", e, this); 276 this.containers[i].containerCache.over = 1; 277 } 278 } else { 414 279 if(this.containers[i].containerCache.over) { 415 280 this.containers[i].propagate("out", e, this); … … 418 283 } 419 284 420 //If we are using droppables, inform the manager about the drop 421 if ($.ui.ddmanager && !this.options.dropBehaviour) $.ui.ddmanager.drop(this, e); 285 }; 286 }, 287 mouseStart: function(e, overrideHandle, noActivation) { 288 289 var o = this.options; 290 this.currentContainer = this; 291 292 if(this.options.disabled || this.options.type == 'static') return false; 293 294 //Find out if the clicked node (or one of its parents) is a actual item in this.items 295 var currentItem = null, nodes = $(e.target).parents().each(function() { 296 if($.data(this, 'sortable-item')) { 297 currentItem = $(this); 298 return false; 299 } 300 }); 301 if($.data(e.target, 'sortable-item')) currentItem = $(e.target); 302 303 if(!currentItem) return false; 304 if(this.options.handle && !overrideHandle) { 305 var validHandle = false; 306 $(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; }); 307 if(!validHandle) return false; 308 } 422 309 423 this.dragging = false; 424 if(this.cancelHelperRemoval) return false; 425 $(this.currentItem).css('visibility', ''); 426 if(this.placeholder) this.placeholder.remove(); 427 this.helper.remove(); 428 429 return false; 310 this.currentItem = currentItem; 311 312 this.refresh(); 313 314 //Create and append the visible helper 315 this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : this.currentItem.clone(); 316 if(!this.helper.parents('body').length) this.helper.appendTo((o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)); //Add the helper to the DOM if that didn't happen already 317 this.helper.css({ position: 'absolute', clear: 'both' }).addClass('ui-sortable-helper'); //Position it absolutely and add a helper class 318 319 /* 320 * - Position generation - 321 * This block generates everything position related - it's the core of draggables. 322 */ 323 324 this.margins = { //Cache the margins 325 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), 326 top: (parseInt(this.currentItem.css("marginTop"),10) || 0) 327 }; 328 329 this.offset = this.currentItem.offset(); //The element's absolute position on the page 330 this.offset = { //Substract the margins from the element's absolute offset 331 top: this.offset.top - this.margins.top, 332 left: this.offset.left - this.margins.left 333 }; 334 335 this.offset.click = { //Where the click happened, relative to the element 336 left: e.pageX - this.offset.left, 337 top: e.pageY - this.offset.top 338 }; 339 340 this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); //Get the offsetParent and cache its position 341 342 this.offset.parent = { //Store its position plus border 343 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), 344 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) 345 }; 346 347 this.originalPosition = this.generatePosition(e); //Generate the original position 348 this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };//Cache the helper size 349 350 if(o.cursorAt) { 351 if(o.cursorAt.left != undefined) this.offset.click.left = o.cursorAt.left; 352 if(o.cursorAt.right != undefined) this.offset.click.left = this.helperProportions.width - o.cursorAt.right; 353 if(o.cursorAt.top != undefined) this.offset.click.top = o.cursorAt.top; 354 if(o.cursorAt.bottom != undefined) this.offset.click.top = this.helperProportions.height - o.cursorAt.bottom; 355 } 356 357 this.domPosition = this.currentItem.prev()[0]; //Cache the former DOM position 358 359 /* 360 * - Position constraining - 361 * Here we prepare position constraining like grid and containment. 362 */ 363 364 if(o.containment) { 365 if(o.containment == 'parent') o.containment = this.helper[0].parentNode; 366 if(o.containment == 'document') this.containment = [0,0,$(document).width(), ($(document).height() || document.body.parentNode.scrollHeight)]; 367 if(!(/^(document|window|parent)$/).test(o.containment)) { 368 var ce = $(o.containment)[0]; 369 var co = $(o.containment).offset(); 370 371 this.containment = [ 372 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.parent.left, 373 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.parent.top, 374 co.left+Math.max(ce.scrollWidth,ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.currentItem.css("marginRight"),10) || 0), 375 co.top+Math.max(ce.scrollHeight,ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.currentItem.css("marginBottom"),10) || 0) 376 ]; 377 } 378 } 379 380 //If o.placeholder is used, create a new element at the given position with the class 381 if(o.placeholder) this.createPlaceholder(); 382 383 //Call plugins and callbacks 384 this.propagate("start", e); 385 this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };//Recache the helper size 386 387 if(this.options.placeholder != 'clone') this.currentItem.css('visibility', 'hidden'); //Set the original element visibility to hidden to still fill out the white space 388 389 if(!noActivation) { 390 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i].propagate("activate", e, this); } //Post 'activate' events to possible containers 391 } 392 393 //Prepare possible droppables 394 if($.ui.ddmanager) $.ui.ddmanager.current = this; 395 if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e); 396 397 this.dragging = true; 398 399 this.mouseDrag(e); //Execute the drag once - this causes the helper not to be visible before getting its correct position 400 return true; 401 402 403 }, 404 convertPositionTo: function(d, pos) { 405 if(!pos) pos = this.position; 406 var mod = d == "absolute" ? 1 : -1; 407 return { 408 top: ( 409 pos.top // the calculated relative position 410 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) 411 - (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) * mod // The offsetParent's scroll position 412 + this.margins.top * mod //Add the margin (you don't want the margin counting in intersection methods) 413 ), 414 left: ( 415 pos.left // the calculated relative position 416 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) 417 - (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft) * mod // The offsetParent's scroll position 418 + this.margins.left * mod //Add the margin (you don't want the margin counting in intersection methods) 419 ) 420 }; 421 }, 422 generatePosition: function(e) { 423 424 var o = this.options; 425 var position = { 426 top: ( 427 e.pageY // The absolute mouse position 428 - this.offset.click.top // Click offset (relative to the element) 429 - this.offset.parent.top // The offsetParent's offset without borders (offset + border) 430 + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) // The offsetParent's scroll position, not if the element is fixed 431 ), 432 left: ( 433 e.pageX // The absolute mouse position 434 - this.offset.click.left // Click offset (relative to the element) 435 - this.offset.parent.left // The offsetParent's offset without borders (offset + border) 436 + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft) // The offsetParent's scroll position, not if the element is fixed 437 ) 438 }; 439 440 if(!this.originalPosition) return position; //If we are not dragging yet, we won't check for options 441 442 /* 443 * - Position constraining - 444 * Constrain the position to a mix of grid, containment. 445 */ 446 if(this.containment) { 447 if(position.left < this.containment[0]) position.left = this.containment[0]; 448 if(position.top < this.containment[1]) position.top = this.containment[1]; 449 if(position.left > this.containment[2]) position.left = this.containment[2]; 450 if(position.top > this.containment[3]) position.top = this.containment[3]; 451 } 452 453 if(o.grid) { 454 var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1]; 455 position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; 430 456 431 }, 432 drag: function(e) { 433 434 //Compute the helpers position 435 this.position.current = { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left }; 436 this.position.absolute = { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top }; 437 438 //Rearrange 439 for (var i = this.items.length - 1; i >= 0; i--) { 440 var intersection = this.intersectsWithEdge(this.items[i]); 441 if(!intersection) continue; 457 var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0]; 458 position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; 459 } 460 461 return position; 462 }, 463 mouseDrag: function(e) { 464 465 466 //Compute the helpers position 467 this.position = this.generatePosition(e); 468 this.positionAbs = this.convertPositionTo("absolute"); 469 470 //Rearrange 471 for (var i = this.items.length - 1; i >= 0; i--) { 472 var intersection = this.intersectsWithEdge(this.items[i]); 473 if(!intersection) continue; 474 475 if(this.items[i].item[0] != this.currentItem[0] //cannot intersect with itself 476 && this.currentItem[intersection == 1 ? "next" : "prev"]()[0] != this.items[i].item[0] //no useless actions that have been done before 477 && !contains(this.currentItem[0], this.items[i].item[0]) //no action if the item moved is the parent of the item checked 478 && (this.options.type == 'semi-dynamic' ? !contains(this.element[0], this.items[i].item[0]) : true) 479 ) { 442 480 443 if(this.items[i].item[0] != this.currentItem[0] //cannot intersect with itself 444 && this.currentItem[intersection == 1 ? "next" : "prev"]()[0] != this.items[i].item[0] //no useless actions that have been done before 445 && !contains(this.currentItem[0], this.items[i].item[0]) //no action if the item moved is the parent of the item checked 446 && (this.options.type == 'semi-dynamic' ? !contains(this.element[0], this.items[i].item[0]) : true) 447 ) { 448 449 this.direction = intersection == 1 ? "down" : "up"; 450 this.rearrange(e, this.items[i]); 451 this.propagate("change", e); //Call plugins and callbacks 452 break; 481 this.direction = intersection == 1 ? "down" : "up"; 482 this.rearrange(e, this.items[i]); 483 this.propagate("change", e); //Call plugins and callbacks 484 break; 485 } 486 } 487 488 //Post events to containers 489 this.contactContainers(e); 490 491 //Call plugins and callbacks 492 this.propagate("sort", e); 493 494 if(!this.options.axis || this.options.axis == "x") this.helper[0].style.left = this.position.left+'px'; 495 if(!this.options.axis || this.options.axis == "y") this.helper[0].style.top = this.position.top+'px'; 496 497 //Interconnect with droppables 498 if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); 499 500 return false; 501 502 }, 503 mouseStop: function(e, noPropagation) { 504 505 //If we are using droppables, inform the manager about the drop 506 if ($.ui.ddmanager && !this.options.dropBehaviour) 507 $.ui.ddmanager.drop(this, e); 508 509 if(this.options.revert) { 510 var self = this; 511 var cur = self.currentItem.offset(); 512 513 //Also animate the placeholder if we have one 514 if(self.placeholder) self.placeholder.animate({ opacity: 'hide' }, (parseInt(this.options.revert, 10) || 500)-50); 515 516 $(this.helper).animate({ 517 left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), 518 top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) 519 }, parseInt(this.options.revert, 10) || 500, function() { 520 self.propagate("stop", e, null, noPropagation); 521 self.clear(e); 522 }); 523 } else { 524 this.propagate("stop", e, null, noPropagation); 525 this.clear(e, noPropagation); 526 } 527 528 return false; 529 530 }, 531 clear: function(e, noPropagation) { 532 533 if(this.domPosition != this.currentItem.prev()[0]) this.propagate("update", e, null, noPropagation); //Trigger update callback if the DOM position has changed 534 if(!contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element 535 this.propagate("remove", e, null, noPropagation); 536 for (var i = this.containers.length - 1; i >= 0; i--){ 537 if(contains(this.containers[i].element[0], this.currentItem[0])) { 538 this.containers[i].propagate("update", e, this, noPropagation); 539 this.containers[i].propagate("receive", e, this, noPropagation); 453 540 } 541 }; 542 }; 543 544 //Post events to containers 545 for (var i = this.containers.length - 1; i >= 0; i--){ 546 this.containers[i].propagate("deactivate", e, this, noPropagation); 547 if(this.containers[i].containerCache.over) { 548 this.containers[i].propagate("out", e, this); 549 this.containers[i].containerCache.over = 0; 454 550 } 455 456 //Post events to containers 457 this.contactContainers(e); 458 459 //Interconnect with droppables 460 if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); 461 462 this.propagate("sort", e); //Call plugins and callbacks 463 this.helper.css({ left: this.position.current.left+'px', top: this.position.current.top+'px' }); // Stick the helper to the cursor 464 return false; 465 466 }, 467 rearrange: function(e, i, a) { 468 a ? a.append(this.currentItem) : i.item[this.direction == 'down' ? 'before' : 'after'](this.currentItem); 469 this.refreshPositions(true); //Precompute after each DOM insertion, NOT on mousemove 470 if(this.placeholderElement) this.placeholder.css(this.placeholderElement.offset()); 471 if(this.placeholderElement && this.placeholderElement.is(":visible")) this.placeholder.css({ width: this.placeholderElement.outerWidth(), height: this.placeholderElement.outerHeight() }); 472 } 473 }); 474 475 $.extend($.ui.sortable, { 476 getter: "serialize toArray", 477 defaults: { 478 items: '> *', 479 zIndex: 1000 480 } 481 }); 482 483 551 } 552 553 this.dragging = false; 554 if(this.cancelHelperRemoval) return false; 555 $(this.currentItem).css('visibility', ''); 556 if(this.placeholder) this.placeholder.remove(); 557 this.helper.remove(); 558 559 return true; 560 561 }, 562 rearrange: function(e, i, a) { 563 a ? a.append(this.currentItem) : i.item[this.direction == 'down' ? 'before' : 'after'](this.currentItem); 564 this.refreshPositions(true); //Precompute after each DOM insertion, NOT on mousemove 565 if(this.options.placeholder) this.options.placeholder.update.call(this.element, this.currentItem, this.placeholder); 566 } 567 })); 568 569 $.extend($.ui.sortable, { 570 getter: "serialize toArray", 571 defaults: { 572 tolerance: "guess", 573 distance: 0, 574 delay: 0, 575 cancel: ":input,button", 576 items: '> *', 577 zIndex: 1000, 578 dropOnEmpty: true, 579 appendTo: "parent" 580 } 581 }); 582 484 583 /* 485 584 * Sortable Extensions 486 585 */ 487 586 488 $.ui.plugin.add("sortable", "cursor", { 489 start: function(e, ui) { 490 var t = $('body'); 491 if (t.css("cursor")) ui.options._cursor = t.css("cursor"); 492 t.css("cursor", ui.options.cursor); 493 }, 494 stop: function(e, ui) { 495 if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); 496 } 497 }); 498 499 $.ui.plugin.add("sortable", "zIndex", { 500 start: function(e, ui) { 501 var t = ui.helper; 502 if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); 503 t.css('zIndex', ui.options.zIndex); 504 }, 505 stop: function(e, ui) { 506 if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); 507 } 508 }); 509 510 $.ui.plugin.add("sortable", "opacity", { 511 start: function(e, ui) { 512 var t = ui.helper; 513 if(t.css("opacity")) ui.options._opacity = t.css("opacity"); 514 t.css('opacity', ui.options.opacity); 515 }, 516 stop: function(e, ui) { 517 if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); 518 } 519 }); 520 521 522 $.ui.plugin.add("sortable", "revert", { 523 stop: function(e, ui) { 524 var self = ui.instance; 525 self.cancelHelperRemoval = true; 526 var cur = self.currentItem.offset(); 527 var op = self.helper.offsetParent().offset(); 528 if(ui.instance.options.zIndex) ui.helper.css('zIndex', ui.instance.options.zIndex); //Do the zIndex again because it already was resetted by the plugin above on stop 529 530 //Also animate the placeholder if we have one 531 if(ui.instance.placeholder) ui.instance.placeholder.animate({ opacity: 'hide' }, parseInt(ui.options.revert, 10) || 500); 532 533 534 ui.helper.animate({ 535 left: cur.left - op.left - self.margins.left, 536 top: cur.top - op.top - self.margins.top 537 }, parseInt(ui.options.revert, 10) || 500, function() { 538 self.currentItem.css('visibility', 'visible'); 539 window.setTimeout(function() { 540 if(self.placeholder) self.placeholder.remove(); 541 self.helper.remove(); 542 if(ui.options._zIndex) ui.helper.css('zIndex', ui.options._zIndex); 543 }, 50); 544 }); 545 } 546 }); 547 587 $.ui.plugin.add("sortable", "cursor", { 588 start: function(e, ui) { 589 var t = $('body'); 590 if (t.css("cursor")) ui.options._cursor = t.css("cursor"); 591 t.css("cursor", ui.options.cursor); 592 }, 593 stop: function(e, ui) { 594 if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); 595 } 596 }); 597 598 $.ui.plugin.add("sortable", "zIndex", { 599 start: function(e, ui) { 600 var t = ui.helper; 601 if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); 602 t.css('zIndex', ui.options.zIndex); 603 }, 604 stop: function(e, ui) { 605 if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); 606 } 607 }); 608 609 $.ui.plugin.add("sortable", "opacity", { 610 start: function(e, ui) { 611 var t = ui.helper; 612 if(t.css("opacity")) ui.options._opacity = t.css("opacity"); 613 t.css('opacity', ui.options.opacity); 614 }, 615 stop: function(e, ui) { 616 if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); 617 } 618 }); 619 620 $.ui.plugin.add("sortable", "scroll", { 621 start: function(e, ui) { 622 var o = ui.options; 623 var i = $(this).data("sortable"); 624 o.scrollSensitivity = o.scrollSensitivity || 20; 625 o.scrollSpeed = o.scrollSpeed || 20; 548 626 549 $.ui.plugin.add("sortable", "containment", { 550 start: function(e, ui) { 551 552 var o = ui.options; 553 if((o.containment.left != undefined || o.containment.constructor == Array) && !o._containment) return; 554 if(!o._containment) o._containment = o.containment; 555 556 if(o._containment == 'parent') o._containment = this[0].parentNode; 557 if(o._containment == 'sortable') o._containment = this[0]; 558 if(o._containment == 'document') { 559 o.containment = [ 560 0, 561 0, 562 $(document).width(), 563 ($(document).height() || document.body.parentNode.scrollHeight) 564 ]; 565 } else { //I'm a node, so compute top/left/right/bottom 566 567 var ce = $(o._containment); 568 var co = ce.offset(); 569 570 o.containment = [ 571 co.left, 572 co.top, 573 co.left+(ce.outerWidth() || ce[0].scrollWidth), 574 co.top+(ce.outerHeight() || ce[0].scrollHeight) 575 ]; 576 } 577 578 }, 579 sort: function(e, ui) { 580 581 var o = ui.options; 582 var h = ui.helper; 583 var c = o.containment; 584 var self = ui.instance; 585 var borderLeft = (parseInt(self.offsetParent.css("borderLeftWidth"), 10) || 0); 586 var borderRight = (parseInt(self.offsetParent.css("borderRightWidth"), 10) || 0); 587 var borderTop = (parseInt(self.offsetParent.css("borderTopWidth"), 10) || 0); 588 var borderBottom = (parseInt(self.offsetParent.css("borderBottomWidth"), 10) || 0); 589 590 if(c.constructor == Array) { 591 if((self.position.absolute.left < c[0])) self.position.current.left = c[0] - self.offsets.parent.left - self.margins.left; 592 if((self.position.absolute.top < c[1])) self.position.current.top = c[1] - self.offsets.parent.top - self.margins.top; 593 if(self.position.absolute.left - c[2] + self.helperProportions.width >= 0) self.position.current.left = c[2] - self.offsets.parent.left - self.helperProportions.width - self.margins.left - borderLeft - borderRight; 594 if(self.position.absolute.top - c[3] + self.helperProportions.height >= 0) self.position.current.top = c[3] - self.offsets.parent.top - self.helperProportions.height - self.margins.top - borderTop - borderBottom; 595 } else { 596 if((ui.position.left < c.left)) self.position.current.left = c.left; 597 if((ui.position.top < c.top)) self.position.current.top = c.top; 598 if(ui.position.left - self.offsetParent.innerWidth() + self.helperProportions.width + c.right + borderLeft + borderRight >= 0) self.position.current.left = self.offsetParent.innerWidth() - self.helperProportions.width - c.right - borderLeft - borderRight; 599 if(ui.position.top - self.offsetParent.innerHeight() + self.helperProportions.height + c.bottom + borderTop + borderBottom >= 0) self.position.current.top = self.offsetParent.innerHeight() - self.helperProportions.height - c.bottom - borderTop - borderBottom; 600 } 601 602 } 603 }); 604 605 $.ui.plugin.add("sortable", "axis", { 606 sort: function(e, ui) { 607 var o = ui.options; 608 if(o.constraint) o.axis = o.constraint; //Legacy check 609 o.axis == 'x' ? ui.instance.position.current.top = ui.instance.originalPosition.top : ui.instance.position.current.left = ui.instance.originalPosition.left; 610 } 611 }); 612 613 $.ui.plugin.add("sortable", "scroll", { 614 start: function(e, ui) { 615 var o = ui.options; 616 o.scrollSensitivity = o.scrollSensitivity || 20; 617 o.scrollSpeed = o.scrollSpeed || 20; 618 619 ui.instance.overflowY = function(el) { 620 do { if((/auto|scroll/).test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); 621 return $(document); 622 }(this); 623 ui.instance.overflowX = function(el) { 624 do { if((/auto|scroll/).test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); 625 return $(document); 626 }(this); 627 628 if(ui.instance.overflowY[0] != document && ui.instance.overflowY[0].tagName != 'HTML') ui.instance.overflowYstart = ui.instance.overflowY[0].scrollTop; 629 if(ui.instance.overflowX[0] != document && ui.instance.overflowX[0].tagName != 'HTML') ui.instance.overflowXstart = ui.instance.overflowX[0].scrollLeft; 630 631 }, 632 sort: function(e, ui) { 633 634 var o = ui.options; 635 var i = ui.instance; 636 637 if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { 638 if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) 639 i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed; 640 if((ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) 641 i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed; 642 } else { 643 //$(document.body).append('<p>'+(e.pageY - $(document).scrollTop())+'</p>'); 644 if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) 645 $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 646 if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) 647 $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 648 } 649 650 if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { 651 if(i.overflowX[0].offsetWidth - (ui.position.left - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity) 652 i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed; 653 if((ui.position.top - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity) 654 i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed; 655 } else { 656 if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) 657 $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 658 if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) 659 $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 660 } 661 662 //ui.instance.recallOffset(e); 663 i.offset = { 664 left: i.mouse.start.left - i.originalPosition.left + (i.overflowXstart !== undefined ? i.overflowXstart - i.overflowX[0].scrollLeft : 0), 665 top: i.mouse.start.top - i.originalPosition.top + (i.overflowYstart !== undefined ? i.overflowYstart - i.overflowX[0].scrollTop : 0) 666 }; 667 668 } 669 }); 627 i.overflowY = function(el) { 628 do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); 629 return $(document); 630 }(i.currentItem); 631 i.overflowX = function(el) { 632 do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); 633 return $(document); 634 }(i.currentItem); 635 636 if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') i.overflowYOffset = i.overflowY.offset(); 637 if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') i.overflowXOffset = i.overflowX.offset(); 638 639 }, 640 sort: function(e, ui) { 641 642 var o = ui.options; 643 var i = $(this).data("sortable"); 644 645 if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { 646 if((i.overflowYOffset.top + i.overflowY[0].offsetHeight) - e.pageY < o.scrollSensitivity) 647 i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed; 648 if(e.pageY - i.overflowYOffset.top < o.scrollSensitivity) 649 i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed; 650 } else { 651 if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) 652 $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 653 if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) 654 $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 655 } 656 657 if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { 658 if((i.overflowXOffset.left + i.overflowX[0].offsetWidth) - e.pageX < o.scrollSensitivity) 659 i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed; 660 if(e.pageX - i.overflowXOffset.left < o.scrollSensitivity) 661 i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed; 662 } else { 663 if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) 664 $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 665 if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) 666 $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 667 } 668 669 } 670 }); 670 671 671 672 })(jQuery); -
trunk/wp-includes/js/jquery/ui.tabs.js
r7973 r8032 14 14 */ 15 15 ;(function($) { 16 17 $.widget("ui.tabs", { 18 init: function() { 19 this.options.event += '.tabs'; // namespace event 16 17 $.widget("ui.tabs", { 18 init: function() { 19 this.options.event += '.tabs'; // namespace event 20 21 // create tabs 22 this.tabify(true); 23 }, 24 setData: function(key, value) { 25 if ((/^selected/).test(key)) 26 this.select(value); 27 else { 28 this.options[key] = value; 29 this.tabify(); 30 } 31 }, 32 length: function() { 33 return this.$tabs.length; 34 }, 35 tabId: function(a) { 36 return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') 37 || this.options.idPrefix + $.data(a); 38 }, 39 ui: function(tab, panel) { 40 return { 41 instance: this, 42 options: this.options, 43 tab: tab, 44 panel: panel 45 }; 46 }, 47 tabify: function(init) { 48 49 this.$lis = $('li:has(a[href])', this.element); 50 this.$tabs = this.$lis.map(function() { return $('a', this)[0]; }); 51 this.$panels = $([]); 52 53 var self = this, o = this.options; 54 55 this.$tabs.each(function(i, a) { 56 // inline tab 57 if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash 58 self.$panels = self.$panels.add(a.hash); 59 // remote tab 60 else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#" 61 $.data(a, 'href.tabs', a.href); // required for restore on destroy 62 $.data(a, 'load.tabs', a.href); // mutable 63 var id = self.tabId(a); 64 a.href = '#' + id; 65 var $panel = $('#' + id); 66 if (!$panel.length) { 67 $panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass) 68 .insertAfter( self.$panels[i - 1] || self.element ); 69 $panel.data('destroy.tabs', true); 70 } 71 self.$panels = self.$panels.add( $panel ); 72 } 73 // invalid tab href 74 else 75 o.disabled.push(i + 1); 76 }); 77 78 if (init) { 79 80 // attach necessary classes for styling if not present 81 this.element.addClass(o.navClass); 82 this.$panels.each(function() { 83 var $this = $(this); 84 $this.addClass(o.panelClass); 85 }); 86 87 // Selected tab 88 // use "selected" option or try to retrieve: 89 // 1. from fragment identifier in url 90 // 2. from cookie 91 // 3. from selected class attribute on <li> 92 if (o.selected === undefined) { 93 if (location.hash) { 94 this.$tabs.each(function(i, a) { 95 if (a.hash == location.hash) { 96 o.selected = i; 97 // prevent page scroll to fragment 98 if ($.browser.msie || $.browser.opera) { // && !o.remote 99 var $toShow = $(location.hash), toShowId = $toShow.attr('id'); 100 $toShow.attr('id', ''); 101 setTimeout(function() { 102 $toShow.attr('id', toShowId); // restore id 103 }, 500); 104 } 105 scrollTo(0, 0); 106 return false; // break 107 } 108 }); 109 } 110 else if (o.cookie) { 111 var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10); 112 if (index && self.$tabs[index]) 113 o.selected = index; 114 } 115 else if (self.$lis.filter('.' + o.selectedClass).length) 116 o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] ); 117 } 118 o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default 119 120 // Take disabling tabs via class attribute from HTML 121 // into account and update option properly. 122 // A selected tab cannot become disabled. 123 o.disabled = $.unique(o.disabled.concat( 124 $.map(this.$lis.filter('.' + o.disabledClass), 125 function(n, i) { return self.$lis.index(n); } ) 126 )).sort(); 127 if ($.inArray(o.selected, o.disabled) != -1) 128 o.disabled.splice($.inArray(o.selected, o.disabled), 1); 20 129 21 // create tabs 22 this.tabify(true); 23 }, 24 setData: function(key, value) { 25 if ((/^selected/).test(key)) 26 this.select(value); 27 else { 28 this.options[key] = value; 29 this.tabify(); 30 } 31 }, 32 length: function() { 33 return this.$tabs.length; 34 }, 35 tabId: function(a) { 36 return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') 37 || this.options.idPrefix + $.data(a); 38 }, 39 ui: function(tab, panel) { 40 return { 41 instance: this, 42 options: this.options, 43 tab: tab, 44 panel: panel 45 }; 46 }, 47 tabify: function(init) { 48 49 this.$lis = $('li:has(a[href])', this.element); 50 this.$tabs = this.$lis.map(function() { return $('a', this)[0]; }); 51 this.$panels = $([]); 52 53 var self = this, o = this.options; 54 55 this.$tabs.each(function(i, a) { 56 // inline tab 57 if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash 58 self.$panels = self.$panels.add(a.hash); 59 // remote tab 60 else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#" 61 $.data(a, 'href.tabs', a.href); // required for restore on destroy 62 $.data(a, 'load.tabs', a.href); // mutable 63 var id = self.tabId(a); 64 a.href = '#' + id; 65 var $panel = $('#' + id); 66 if (!$panel.length) { 67 $panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass) 68 .insertAfter( self.$panels[i - 1] || self.element ); 69 $panel.data('destroy.tabs', true); 70 } 71 self.$panels = self.$panels.add( $panel ); 72 } 73 // invalid tab href 130 // highlight selected tab 131 this.$panels.addClass(o.hideClass); 132 this.$lis.removeClass(o.selectedClass); 133 if (o.selected !== null) { 134 this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before 135 this.$lis.eq(o.selected).addClass(o.selectedClass); 136 137 // seems to be expected behavior that the show callback is fired 138 var onShow = function() { 139 $(self.element).triggerHandler('tabsshow', 140 [self.ui(self.$tabs[o.selected], self.$panels[o.selected])], o.show); 141 }; 142 143 // load if remote tab 144 if ($.data(this.$tabs[o.selected], 'load.tabs')) 145 this.load(o.selected, onShow); 146 // just trigger show event 74 147 else 75 o.disabled.push(i + 1); 148 onShow(); 149 150 } 151 152 // clean up to avoid memory leaks in certain versions of IE 6 153 $(window).bind('unload', function() { 154 self.$tabs.unbind('.tabs'); 155 self.$lis = self.$tabs = self.$panels = null; 76 156 }); 77 157 78 if (init) { 79 80 // attach necessary classes for styling if not present 81 this.element.addClass(o.navClass); 82 this.$panels.each(function() { 83 var $this = $(this); 84 $this.addClass(o.panelClass); 85 }); 86 87 // Selected tab 88 // use "selected" option or try to retrieve: 89 // 1. from fragment identifier in url 90 // 2. from cookie 91 // 3. from selected class attribute on <li> 92 if (o.selected === undefined) { 93 if (location.hash) { 94 this.$tabs.each(function(i, a) { 95 if (a.hash == location.hash) { 96 o.selected = i; 97 // prevent page scroll to fragment 98 if ($.browser.msie || $.browser.opera) { // && !o.remote 99 var $toShow = $(location.hash), toShowId = $toShow.attr('id'); 100 $toShow.attr('id', ''); 101 setTimeout(function() { 102 $toShow.attr('id', toShowId); // restore id 103 }, 500); 104 } 105 scrollTo(0, 0); 106 return false; // break 107 } 108 }); 109 } 110 else if (o.cookie) { 111 var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10); 112 if (index && self.$tabs[index]) 113 o.selected = index; 114 } 115 else if (self.$lis.filter('.' + o.selectedClass).length) 116 o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] ); 117 } 118 o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default 119 120 // Take disabling tabs via class attribute from HTML 121 // into account and update option properly. 122 // A selected tab cannot become disabled. 123 o.disabled = $.unique(o.disabled.concat( 124 $.map(this.$lis.filter('.' + o.disabledClass), 125 function(n, i) { return self.$lis.index(n); } ) 126 )).sort(); 127 if ($.inArray(o.selected, o.disabled) != -1) 128 o.disabled.splice($.inArray(o.selected, o.disabled), 1); 129 130 // highlight selected tab 131 this.$panels.addClass(o.hideClass); 132 this.$lis.removeClass(o.selectedClass); 133 if (o.selected !== null) { 134 this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before 135 this.$lis.eq(o.selected).addClass(o.selectedClass); 136 137 // seems to be expected behavior that the show callback is fired 138 var onShow = function() { 139 $(self.element).triggerHandler('tabsshow', 140 [self.ui(self.$tabs[o.selected], self.$panels[o.selected])], o.show); 141 }; 142 143 // load if remote tab 144 if ($.data(this.$tabs[o.selected], 'load.tabs')) 145 this.load(o.selected, onShow); 146 // just trigger show event 147 else 148 onShow(); 149 150 } 151 152 // clean up to avoid memory leaks in certain versions of IE 6 153 $(window).bind('unload', function() { 154 self.$tabs.unbind('.tabs'); 155 self.$lis = self.$tabs = self.$panels = null; 156 }); 157 158 } 159 160 // disable tabs 161 for (var i = 0, li; li = this.$lis[i]; i++) 162 $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass); 163 164 // reset cache if switching from cached to not cached 165 if (o.cache === false) 166 this.$tabs.removeData('cache.tabs'); 167 168 // set up animations 169 var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal'; 170 if (o.fx && o.fx.constructor == Array) 171 hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx; 172 else 173 hideFx = showFx = o.fx || baseFx; 174 175 // reset some styles to maintain print style sheets etc. 176 var resetCSS = { display: '', overflow: '', height: '' }; 177 if (!$.browser.msie) // not in IE to prevent ClearType font issue 178 resetCSS.opacity = ''; 179 180 // Hide a tab, animation prevents browser scrolling to fragment, 181 // $show is optional. 182 function hideTab(clicked, $hide, $show) { 183 $hide.animate(hideFx, hideFx.duration || baseDuration, function() { // 184 $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. 185 if ($.browser.msie && hideFx.opacity) 186 $hide[0].style.filter = ''; 187 if ($show) 188 showTab(clicked, $show, $hide); 189 }); 190 } 191 192 // Show a tab, animation prevents browser scrolling to fragment, 193 // $hide is optional. 194 function showTab(clicked, $show, $hide) { 195 if (showFx === baseFx) 196 $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels 197 $show.animate(showFx, showFx.duration || baseDuration, function() { 198 $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. 199 if ($.browser.msie && showFx.opacity) 200 $show[0].style.filter = ''; 201 202 // callback 203 $(self.element).triggerHandler('tabsshow', 204 [self.ui(clicked, $show[0])], o.show); 205 206 }); 207 } 208 209 // switch a tab 210 function switchTab(clicked, $li, $hide, $show) { 211 /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click 212 $.ajaxHistory.update(clicked.hash); 213 }*/ 214 $li.addClass(o.selectedClass) 215 .siblings().removeClass(o.selectedClass); 216 hideTab(clicked, $hide, $show); 217 } 218 219 // attach tab event handler, unbind to avoid duplicates from former tabifying... 220 this.$tabs.unbind('.tabs').bind(o.event, function() { 221 222 //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click 223 var $li = $(this).parents('li:eq(0)'), 224 $hide = self.$panels.filter(':visible'), 225 $show = $(this.hash); 226 227 // If tab is already selected and not unselectable or tab disabled or 228 // or is already loading or click callback returns false stop here. 229 // Check if click handler returns false last so that it is not executed 230 // for a disabled or loading tab! 231 if (($li.hasClass(o.selectedClass) && !o.unselect) 232 || $li.hasClass(o.disabledClass) 233 || $(this).hasClass(o.loadingClass) 234 || $(self.element).triggerHandler('tabsselect', [self.ui(this, $show[0])], o.select) === false 235 ) { 158 } 159 160 // disable tabs 161 for (var i = 0, li; li = this.$lis[i]; i++) 162 $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass); 163 164 // reset cache if switching from cached to not cached 165 if (o.cache === false) 166 this.$tabs.removeData('cache.tabs'); 167 168 // set up animations 169 var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal'; 170 if (o.fx && o.fx.constructor == Array) 171 hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx; 172 else 173 hideFx = showFx = o.fx || baseFx; 174 175 // reset some styles to maintain print style sheets etc. 176 var resetCSS = { display: '', overflow: '', height: '' }; 177 if (!$.browser.msie) // not in IE to prevent ClearType font issue 178 resetCSS.opacity = ''; 179 180 // Hide a tab, animation prevents browser scrolling to fragment, 181 // $show is optional. 182 function hideTab(clicked, $hide, $show) { 183 $hide.animate(hideFx, hideFx.duration || baseDuration, function() { // 184 $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. 185 if ($.browser.msie && hideFx.opacity) 186 $hide[0].style.filter = ''; 187 if ($show) 188 showTab(clicked, $show, $hide); 189 }); 190 } 191 192 // Show a tab, animation prevents browser scrolling to fragment, 193 // $hide is optional. 194 function showTab(clicked, $show, $hide) { 195 if (showFx === baseFx) 196 $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels 197 $show.animate(showFx, showFx.duration || baseDuration, function() { 198 $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. 199 if ($.browser.msie && showFx.opacity) 200 $show[0].style.filter = ''; 201 202 // callback 203 $(self.element).triggerHandler('tabsshow', 204 [self.ui(clicked, $show[0])], o.show); 205 206 }); 207 } 208 209 // switch a tab 210 function switchTab(clicked, $li, $hide, $show) { 211 /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click 212 $.ajaxHistory.update(clicked.hash); 213 }*/ 214 $li.addClass(o.selectedClass) 215 .siblings().removeClass(o.selectedClass); 216 hideTab(clicked, $hide, $show); 217 } 218 219 // attach tab event handler, unbind to avoid duplicates from former tabifying... 220 this.$tabs.unbind('.tabs').bind(o.event, function() { 221 222 //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click 223 var $li = $(this).parents('li:eq(0)'), 224 $hide = self.$panels.filter(':visible'), 225 $show = $(this.hash); 226 227 // If tab is already selected and not unselectable or tab disabled or 228 // or is already loading or click callback returns false stop here. 229 // Check if click handler returns false last so that it is not executed 230 // for a disabled or loading tab! 231 if (($li.hasClass(o.selectedClass) && !o.unselect) 232 || $li.hasClass(o.disabledClass) 233 || $(this).hasClass(o.loadingClass) 234 || $(self.element).triggerHandler('tabsselect', [self.ui(this, $show[0])], o.select) === false 235 ) { 236 this.blur(); 237 return false; 238 } 239 240 self.options.selected = self.$tabs.index(this); 241 242 // if tab may be closed 243 if (o.unselect) { 244 if ($li.hasClass(o.selectedClass)) { 245 self.options.selected = null; 246 $li.removeClass(o.selectedClass); 247 self.$panels.stop(); 248 hideTab(this, $hide); 249 this.blur(); 250 return false; 251 } else if (!$hide.length) { 252 self.$panels.stop(); 253 var a = this; 254 self.load(self.$tabs.index(this), function() { 255 $li.addClass(o.selectedClass).addClass(o.unselectClass); 256 showTab(a, $show); 257 }); 236 258 this.blur(); 237 259 return false; 238 260 } 239 240 self.options.selected = self.$tabs.index(this); 241 242 // if tab may be closed 243 if (o.unselect) { 244 if ($li.hasClass(o.selectedClass)) { 245 self.options.selected = null; 246 $li.removeClass(o.selectedClass); 247 self.$panels.stop(); 248 hideTab(this, $hide); 249 this.blur(); 250 return false; 251 } else if (!$hide.length) { 252 self.$panels.stop(); 253 var a = this; 254 self.load(self.$tabs.index(this), function() { 255 $li.addClass(o.selectedClass).addClass(o.unselectClass); 256 showTab(a, $show); 261 } 262 263 if (o.cookie) 264 $.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie); 265 266 // stop possibly running animations 267 self.$panels.stop(); 268 269 // show new tab 270 if ($show.length) { 271 272 // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled 273 /*if ($.browser.msie && o.bookmarkable) { 274 var showId = this.hash.replace('#', ''); 275 $show.attr('id', ''); 276 setTimeout(function() { 277 $show.attr('id', showId); // restore id 278 }, 0); 279 }*/ 280 281 var a = this; 282 self.load(self.$tabs.index(this), $hide.length ? 283 function() { 284 switchTab(a, $li, $hide, $show); 285 } : 286 function() { 287 $li.addClass(o.selectedClass); 288 showTab(a, $show); 289 } 290 ); 291 292 // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash 293 /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0; 294 var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0; 295 setTimeout(function() { 296 scrollTo(scrollX, scrollY); 297 }, 0);*/ 298 299 } else 300 throw 'jQuery UI Tabs: Mismatching fragment identifier.'; 301 302 // Prevent IE from keeping other link focussed when using the back button 303 // and remove dotted border from clicked link. This is controlled in modern 304 // browsers via CSS, also blur removes focus from address bar in Firefox 305 // which can become a usability and annoying problem with tabsRotate. 306 if ($.browser.msie) 307 this.blur(); 308 309 //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE 310 return false; 311 312 }); 313 314 // disable click if event is configured to something else 315 if (!(/^click/).test(o.event)) 316 this.$tabs.bind('click.tabs', function() { return false; }); 317 318 }, 319 add: function(url, label, index) { 320 if (index == undefined) 321 index = this.$tabs.length; // append by default 322 323 var o = this.options; 324 var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)); 325 $li.data('destroy.tabs', true); 326 327 var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] ); 328 329 // try to find an existing element before creating a new one 330 var $panel = $('#' + id); 331 if (!$panel.length) { 332 $panel = $(o.panelTemplate).attr('id', id) 333 .addClass(o.hideClass) 334 .data('destroy.tabs', true); 335 } 336 $panel.addClass(o.panelClass); 337 if (index >= this.$lis.length) { 338 $li.appendTo(this.element); 339 $panel.appendTo(this.element[0].parentNode); 340 } else { 341 $li.insertBefore(this.$lis[index]); 342 $panel.insertBefore(this.$panels[index]); 343 } 344 345 o.disabled = $.map(o.disabled, 346 function(n, i) { return n >= index ? ++n : n }); 347 348 this.tabify(); 349 350 if (this.$tabs.length == 1) { 351 $li.addClass(o.selectedClass); 352 $panel.removeClass(o.hideClass); 353 var href = $.data(this.$tabs[0], 'load.tabs'); 354 if (href) 355 this.load(index, href); 356 } 357 358 // callback 359 this.element.triggerHandler('tabsadd', 360 [this.ui(this.$tabs[index], this.$panels[index])], o.add 361 ); 362 }, 363 remove: function(index) { 364 var o = this.options, $li = this.$lis.eq(index).remove(), 365 $panel = this.$panels.eq(index).remove(); 366 367 // If selected tab was removed focus tab to the right or 368 // in case the last tab was removed the tab to the left. 369 if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) 370 this.select(index + (index + 1 < this.$tabs.length ? 1 : -1)); 371 372 o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), 373 function(n, i) { return n >= index ? --n : n }); 374 375 this.tabify(); 376 377 // callback 378 this.element.triggerHandler('tabsremove', 379 [this.ui($li.find('a')[0], $panel[0])], o.remove 380 ); 381 }, 382 enable: function(index) { 383 var o = this.options; 384 if ($.inArray(index, o.disabled) == -1) 385 return; 386 387 var $li = this.$lis.eq(index).removeClass(o.disabledClass); 388 if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2... 389 $li.css('display', 'inline-block'); 390 setTimeout(function() { 391 $li.css('display', 'block'); 392 }, 0); 393 } 394 395 o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); 396 397 // callback 398 this.element.triggerHandler('tabsenable', 399 [this.ui(this.$tabs[index], this.$panels[index])], o.enable 400 ); 401 402 }, 403 disable: function(index) { 404 var self = this, o = this.options; 405 if (index != o.selected) { // cannot disable already selected tab 406 this.$lis.eq(index).addClass(o.disabledClass); 407 408 o.disabled.push(index); 409 o.disabled.sort(); 410 411 // callback 412 this.element.triggerHandler('tabsdisable', 413 [this.ui(this.$tabs[index], this.$panels[index])], o.disable 414 ); 415 } 416 }, 417 select: function(index) { 418 if (typeof index == 'string') 419 index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] ); 420 this.$tabs.eq(index).trigger(this.options.event); 421 }, 422 load: function(index, callback) { // callback is for internal usage only 423 424 var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0], 425 bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs'); 426 427 callback = callback || function() {}; 428 429 // no remote or from cache - just finish with callback 430 if (!url || !bypassCache && $.data(a, 'cache.tabs')) { 431 callback(); 432 return; 433 } 434 435 // load remote from here on 436 437 var inner = function(parent) { 438 var $parent = $(parent), $inner = $parent.find('*:last'); 439 return $inner.length && $inner || $parent; 440 }; 441 var cleanup = function() { 442 self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass) 443 .each(function() { 444 if (o.spinner) 445 inner(this).parent().html(inner(this).data('label.tabs')); 257 446 }); 258 this.blur(); 259 return false; 260 } 261 } 262 263 if (o.cookie) 264 $.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie); 265 266 // stop possibly running animations 267 self.$panels.stop(); 268 269 // show new tab 270 if ($show.length) { 271 272 // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled 273 /*if ($.browser.msie && o.bookmarkable) { 274 var showId = this.hash.replace('#', ''); 275 $show.attr('id', ''); 276 setTimeout(function() { 277 $show.attr('id', showId); // restore id 278 }, 0); 279 }*/ 280 281 var a = this; 282 self.load(self.$tabs.index(this), $hide.length ? 283 function() { 284 switchTab(a, $li, $hide, $show); 285 } : 286 function() { 287 $li.addClass(o.selectedClass); 288 showTab(a, $show); 289 } 290 ); 291 292 // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash 293 /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0; 294 var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0; 295 setTimeout(function() { 296 scrollTo(scrollX, scrollY); 297 }, 0);*/ 298 299 } else 300 throw 'jQuery UI Tabs: Mismatching fragment identifier.'; 301 302 // Prevent IE from keeping other link focussed when using the back button 303 // and remove dotted border from clicked link. This is controlled in modern 304 // browsers via CSS, also blur removes focus from address bar in Firefox 305 // which can become a usability and annoying problem with tabsRotate. 306 if ($.browser.msie) 307 this.blur(); 308 309 //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE 310 return false; 311 447 self.xhr = null; 448 }; 449 450 if (o.spinner) { 451 var label = inner(a).html(); 452 inner(a).wrapInner('<em></em>') 453 .find('em').data('label.tabs', label).html(o.spinner); 454 } 455 456 var ajaxOptions = $.extend({}, o.ajaxOptions, { 457 url: url, 458 success: function(r, s) { 459 $(a.hash).html(r); 460 cleanup(); 461 462 if (o.cache) 463 $.data(a, 'cache.tabs', true); // if loaded once do not load them again 464 465 // callbacks 466 $(self.element).triggerHandler('tabsload', 467 [self.ui(self.$tabs[index], self.$panels[index])], o.load 468 ); 469 o.ajaxOptions.success && o.ajaxOptions.success(r, s); 470 471 // This callback is required because the switch has to take 472 // place after loading has completed. Call last in order to 473 // fire load before show callback... 474 callback(); 475 } 476 }); 477 if (this.xhr) { 478 // terminate pending requests from other tabs and restore tab label 479 this.xhr.abort(); 480 cleanup(); 481 } 482 $a.addClass(o.loadingClass); 483 setTimeout(function() { // timeout is again required in IE, "wait" for id being restored 484 self.xhr = $.ajax(ajaxOptions); 485 }, 0); 486 487 }, 488 url: function(index, url) { 489 this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url); 490 }, 491 destroy: function() { 492 var o = this.options; 493 this.element.unbind('.tabs') 494 .removeClass(o.navClass).removeData('tabs'); 495 this.$tabs.each(function() { 496 var href = $.data(this, 'href.tabs'); 497 if (href) 498 this.href = href; 499 var $this = $(this).unbind('.tabs'); 500 $.each(['href', 'load', 'cache'], function(i, prefix) { 501 $this.removeData(prefix + '.tabs'); 312 502 }); 313 314 // disable click if event is configured to something else 315 if (!(/^click/).test(o.event)) 316 this.$tabs.bind('click.tabs', function() { return false; }); 317 318 }, 319 add: function(url, label, index) { 320 if (index == undefined) 321 index = this.$tabs.length; // append by default 322 323 var o = this.options; 324 var $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{label\}/, label)); 325 $li.data('destroy.tabs', true); 326 327 var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] ); 328 329 // try to find an existing element before creating a new one 330 var $panel = $('#' + id); 331 if (!$panel.length) { 332 $panel = $(o.panelTemplate).attr('id', id) 333 .addClass(o.hideClass) 334 .data('destroy.tabs', true); 335 } 336 $panel.addClass(o.panelClass); 337 if (index >= this.$lis.length) { 338 $li.appendTo(this.element); 339 $panel.appendTo(this.element[0].parentNode); 340 } else { 341 $li.insertBefore(this.$lis[index]); 342 $panel.insertBefore(this.$panels[index]); 343 } 344 345 o.disabled = $.map(o.disabled, 346 function(n, i) { return n >= index ? ++n : n }); 347 348 this.tabify(); 349 350 if (this.$tabs.length == 1) { 351 $li.addClass(o.selectedClass); 352 $panel.removeClass(o.hideClass); 353 var href = $.data(this.$tabs[0], 'load.tabs'); 354 if (href) 355 this.load(index, href); 356 } 357 358 // callback 359 this.element.triggerHandler('tabsadd', 360 [this.ui(this.$tabs[index], this.$panels[index])], o.add 361 ); 362 }, 363 remove: function(index) { 364 var o = this.options, $li = this.$lis.eq(index).remove(), 365 $panel = this.$panels.eq(index).remove(); 366 367 // If selected tab was removed focus tab to the right or 368 // in case the last tab was removed the tab to the left. 369 if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) 370 this.select(index + (index + 1 < this.$tabs.length ? 1 : -1)); 371 372 o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), 373 function(n, i) { return n >= index ? --n : n }); 374 375 this.tabify(); 376 377 // callback 378 this.element.triggerHandler('tabsremove', 379 [this.ui($li.find('a')[0], $panel[0])], o.remove 380 ); 381 }, 382 enable: function(index) { 383 var o = this.options; 384 if ($.inArray(index, o.disabled) == -1) 385 return; 386 387 var $li = this.$lis.eq(index).removeClass(o.disabledClass); 388 if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2... 389 $li.css('display', 'inline-block'); 390 setTimeout(function() { 391 $li.css('display', 'block'); 392 }, 0); 393 } 394 395 o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); 396 397 // callback 398 this.element.triggerHandler('tabsenable', 399 [this.ui(this.$tabs[index], this.$panels[index])], o.enable 400 ); 401 402 }, 403 disable: function(index) { 404 var self = this, o = this.options; 405 if (index != o.selected) { // cannot disable already selected tab 406 this.$lis.eq(index).addClass(o.disabledClass); 407 408 o.disabled.push(index); 409 o.disabled.sort(); 410 411 // callback 412 this.element.triggerHandler('tabsdisable', 413 [this.ui(this.$tabs[index], this.$panels[index])], o.disable 414 ); 415 } 416 }, 417 select: function(index) { 418 if (typeof index == 'string') 419 index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] ); 420 this.$tabs.eq(index).trigger(this.options.event); 421 }, 422 load: function(index, callback) { // callback is for internal usage only 423 424 var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0], 425 bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs'); 426 427 callback = callback || function() {}; 428 429 // no remote or from cache - just finish with callback 430 if (!url || !bypassCache && $.data(a, 'cache.tabs')) { 431 callback(); 432 return; 433 } 434 435 // load remote from here on 436 437 var inner = function(parent) { 438 var $parent = $(parent), $inner = $parent.find('*:last'); 439 return $inner.length && $inner || $parent; 440 }; 441 var cleanup = function() { 442 self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass) 443 .each(function() { 444 if (o.spinner) 445 inner(this).parent().html(inner(this).data('label.tabs')); 446 }); 447 self.xhr = null; 448 }; 449 450 if (o.spinner) { 451 var label = inner(a).html(); 452 inner(a).wrapInner('<em></em>') 453 .find('em').data('label.tabs', label).html(o.spinner); 454 } 455 456 var ajaxOptions = $.extend({}, o.ajaxOptions, { 457 url: url, 458 success: function(r, s) { 459 $(a.hash).html(r); 460 cleanup(); 461 462 if (o.cache) 463 $.data(a, 'cache.tabs', true); // if loaded once do not load them again 464 465 // callbacks 466 $(self.element).triggerHandler('tabsload', 467 [self.ui(self.$tabs[index], self.$panels[index])], o.load 468 ); 469 o.ajaxOptions.success && o.ajaxOptions.success(r, s); 470 471 // This callback is required because the switch has to take 472 // place after loading has completed. Call last in order to 473 // fire load before show callback... 474 callback(); 475 } 476 }); 477 if (this.xhr) { 478 // terminate pending requests from other tabs and restore tab label 479 this.xhr.abort(); 480 cleanup(); 481 } 482 $a.addClass(o.loadingClass); 483 setTimeout(function() { // timeout is again required in IE, "wait" for id being restored 484 self.xhr = $.ajax(ajaxOptions); 485 }, 0); 486 487 }, 488 url: function(index, url) { 489 this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url); 490 }, 491 destroy: function() { 492 var o = this.options; 493 this.element.unbind('.tabs') 494 .removeClass(o.navClass).removeData('tabs'); 495 this.$tabs.each(function() { 496 var href = $.data(this, 'href.tabs'); 497 if (href) 498 this.href = href; 499 var $this = $(this).unbind('.tabs'); 500 $.each(['href', 'load', 'cache'], function(i, prefix) { 501 $this.removeData(prefix + '.tabs'); 502 }); 503 }); 504 this.$lis.add(this.$panels).each(function() { 505 if ($.data(this, 'destroy.tabs')) 506 $(this).remove(); 507 else 508 $(this).removeClass([o.selectedClass, o.unselectClass, 509 o.disabledClass, o.panelClass, o.hideClass].join(' ')); 510 }); 511 } 512 }); 513 514 $.ui.tabs.defaults = { 515 // basic setup 516 unselect: false, 517 event: 'click', 518 disabled: [], 519 cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } 520 // TODO history: false, 521 522 // Ajax 523 spinner: 'Loading…', 524 cache: false, 525 idPrefix: 'ui-tabs-', 526 ajaxOptions: {}, 527 528 // animations 529 fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } 530 531 // templates 532 tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>', 533 panelTemplate: '<div></div>', 534 535 // CSS classes 536 navClass: 'ui-tabs-nav', 537 selectedClass: 'ui-tabs-selected', 538 unselectClass: 'ui-tabs-unselect', 539 disabledClass: 'ui-tabs-disabled', 540 panelClass: 'ui-tabs-panel', 541 hideClass: 'ui-tabs-hide', 542 loadingClass: 'ui-tabs-loading' 543 }; 544 545 $.ui.tabs.getter = "length"; 503 }); 504 this.$lis.add(this.$panels).each(function() { 505 if ($.data(this, 'destroy.tabs')) 506 $(this).remove(); 507 else 508 $(this).removeClass([o.selectedClass, o.unselectClass, 509 o.disabledClass, o.panelClass, o.hideClass].join(' ')); 510 }); 511 } 512 }); 513 514 $.ui.tabs.defaults = { 515 // basic setup 516 unselect: false, 517 event: 'click', 518 disabled: [], 519 cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } 520 // TODO history: false, 521 522 // Ajax 523 spinner: 'Loading…', 524 cache: false, 525 idPrefix: 'ui-tabs-', 526 ajaxOptions: {}, 527 528 // animations 529 fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } 530 531 // templates 532 tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>', 533 panelTemplate: '<div></div>', 534 535 // CSS classes 536 navClass: 'ui-tabs-nav', 537 selectedClass: 'ui-tabs-selected', 538 unselectClass: 'ui-tabs-unselect', 539 disabledClass: 'ui-tabs-disabled', 540 panelClass: 'ui-tabs-panel', 541 hideClass: 'ui-tabs-hide', 542 loadingClass: 'ui-tabs-loading' 543 }; 544 545 $.ui.tabs.getter = "length"; 546 546 547 547 /* … … 549 549 */ 550 550 551 /*552 * Rotate553 */554 $.extend($.ui.tabs.prototype, {555 rotation: null,556 rotate: function(ms, continuing) {557 558 continuing = continuing || false;559 560 var self = this, t = this.options.selected;561 562 function start() {563 self.rotation = setInterval(function() {564 t = ++t < self.$tabs.length ? t : 0;565 self.select(t);566 }, ms);567 }568 569 function stop(e) {570 if (!e || e.clientX) { // only in case of a true click571 clearInterval(self.rotation);572 }573 }574 575 // start interval576 if (ms) {577 start();578 if (!continuing)579 this.$tabs.bind(this.options.event, stop);580 else581 this.$tabs.bind(this.options.event, function() {582 stop();583 t = self.options.selected;584 start();585 });586 }587 // stop interval588 else {589 stop();590 this.$tabs.unbind(this.options.event, stop);591 }592 }593 });551 /* 552 * Rotate 553 */ 554 $.extend($.ui.tabs.prototype, { 555 rotation: null, 556 rotate: function(ms, continuing) { 557 558 continuing = continuing || false; 559 560 var self = this, t = this.options.selected; 561 562 function start() { 563 self.rotation = setInterval(function() { 564 t = ++t < self.$tabs.length ? t : 0; 565 self.select(t); 566 }, ms); 567 } 568 569 function stop(e) { 570 if (!e || e.clientX) { // only in case of a true click 571 clearInterval(self.rotation); 572 } 573 } 574 575 // start interval 576 if (ms) { 577 start(); 578 if (!continuing) 579 this.$tabs.bind(this.options.event, stop); 580 else 581 this.$tabs.bind(this.options.event, function() { 582 stop(); 583 t = self.options.selected; 584 start(); 585 }); 586 } 587 // stop interval 588 else { 589 stop(); 590 this.$tabs.unbind(this.options.event, stop); 591 } 592 } 593 }); 594 594 595 595 })(jQuery);
Note: See TracChangeset
for help on using the changeset viewer.