
de.agilecoders.wicket.markup.html.references.js.jquerypp-1.0b.js Maven / Gradle / Ivy
(function() {
var event = jQuery.event,
//helper that finds handlers by type and calls back a function, this is basically handle
// events - the events object
// types - an array of event types to look for
// callback(type, handlerFunc, selector) - a callback
// selector - an optional selector to filter with, if there, matches by selector
// if null, matches anything, otherwise, matches with no selector
findHelper = function( events, types, callback, selector ) {
var t, type, typeHandlers, all, h, handle,
namespaces, namespace,
match;
for ( t = 0; t < types.length; t++ ) {
type = types[t];
all = type.indexOf(".") < 0;
if (!all ) {
namespaces = type.split(".");
type = namespaces.shift();
namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
}
typeHandlers = (events[type] || []).slice(0);
for ( h = 0; h < typeHandlers.length; h++ ) {
handle = typeHandlers[h];
match = (all || namespace.test(handle.namespace));
if(match){
if(selector){
if (handle.selector === selector ) {
callback(type, handle.origHandler || handle.handler);
}
} else if (selector === null){
callback(type, handle.origHandler || handle.handler, handle.selector);
}
else if (!handle.selector ) {
callback(type, handle.origHandler || handle.handler);
}
}
}
}
};
/**
* Finds event handlers of a given type on an element.
* @param {HTMLElement} el
* @param {Array} types an array of event names
* @param {String} [selector] optional selector
* @return {Array} an array of event handlers
*/
event.find = function( el, types, selector ) {
var events = ( $._data(el) || {} ).events,
handlers = [],
t, liver, live;
if (!events ) {
return handlers;
}
findHelper(events, types, function( type, handler ) {
handlers.push(handler);
}, selector);
return handlers;
};
/**
* Finds all events. Group by selector.
* @param {HTMLElement} el the element
* @param {Array} types event types
*/
event.findBySelector = function( el, types ) {
var events = $._data(el).events,
selectors = {},
//adds a handler for a given selector and event
add = function( selector, event, handler ) {
var select = selectors[selector] || (selectors[selector] = {}),
events = select[event] || (select[event] = []);
events.push(handler);
};
if (!events ) {
return selectors;
}
//first check live:
/*$.each(events.live || [], function( i, live ) {
if ( $.inArray(live.origType, types) !== -1 ) {
add(live.selector, live.origType, live.origHandler || live.handler);
}
});*/
//then check straight binds
findHelper(events, types, function( type, handler, selector ) {
add(selector || "", type, handler);
}, null);
return selectors;
};
event.supportTouch = "ontouchend" in document;
$.fn.respondsTo = function( events ) {
if (!this.length ) {
return false;
} else {
//add default ?
return event.find(this[0], $.isArray(events) ? events : [events]).length > 0;
}
};
$.fn.triggerHandled = function( event, data ) {
event = (typeof event == "string" ? $.Event(event) : event);
this.trigger(event, data);
return event.handled;
};
/**
* Only attaches one event handler for all types ...
* @param {Array} types llist of types that will delegate here
* @param {Object} startingEvent the first event to start listening to
* @param {Object} onFirst a function to call
*/
event.setupHelper = function( types, startingEvent, onFirst ) {
if (!onFirst ) {
onFirst = startingEvent;
startingEvent = null;
}
var add = function( handleObj ) {
var bySelector, selector = handleObj.selector || "";
if ( selector ) {
bySelector = event.find(this, types, selector);
if (!bySelector.length ) {
$(this).delegate(selector, startingEvent, onFirst);
}
}
else {
//var bySelector = event.find(this, types, selector);
if (!event.find(this, types, selector).length ) {
event.add(this, startingEvent, onFirst, {
selector: selector,
delegate: this
});
}
}
},
remove = function( handleObj ) {
var bySelector, selector = handleObj.selector || "";
if ( selector ) {
bySelector = event.find(this, types, selector);
if (!bySelector.length ) {
$(this).undelegate(selector, startingEvent, onFirst);
}
}
else {
if (!event.find(this, types, selector).length ) {
event.remove(this, startingEvent, onFirst, {
selector: selector,
delegate: this
});
}
}
};
$.each(types, function() {
event.special[this] = {
add: add,
remove: remove,
setup: function() {},
teardown: function() {}
};
});
};
})(jQuery);
(function( $ ) {
$.event.reverse = function(name, attributes) {
var bound = $(),
count = 0;
$.event.special[name] = {
setup: function() {
// add and sort the resizers array
// don't add window because it can't be compared easily
if ( this !== window ) {
bound.push(this);
$.unique(bound);
}
// returns false if the window
return this !== window;
},
teardown: function() {
// we shouldn't have to sort
bound = bound.not(this);
// returns false if the window
return this !== window;
},
add: function( handleObj ) {
var origHandler = handleObj.handler;
handleObj.origHandler = origHandler;
handleObj.handler = function( ev, data ) {
var isWindow = this === window;
if(attributes && attributes.handler) {
var result = attributes.handler.apply(this, arguments);
if(result === true) {
return;
}
}
// if this is the first handler for this event ...
if ( count === 0 ) {
// prevent others from doing what we are about to do
count++;
var where = data === false ? ev.target : this
// trigger all this element's handlers
$.event.handle.call(where, ev);
if ( ev.isPropagationStopped() ) {
count--;
return;
}
// get all other elements within this element that listen to move
// and trigger their resize events
var index = bound.index(this),
length = bound.length,
child, sub;
// if index == -1 it's the window
while (++index < length && (child = bound[index]) && (isWindow || $.contains(where, child)) ) {
// call the event
$.event.handle.call(child, ev);
if ( ev.isPropagationStopped() ) {
// move index until the item is not in the current child
while (++index < length && (sub = bound[index]) ) {
if (!$.contains(child, sub) ) {
// set index back one
index--;
break
}
}
}
}
// prevent others from responding
ev.stopImmediatePropagation();
count--;
} else {
handleObj.origHandler.call(this, ev, data);
}
}
}
};
// automatically bind on these
$([document, window]).bind(name, function() {});
return $.event.special[name];
}
})(jQuery);
(function($){
/**
* @function jQuery.fn.triggerAsync
* @parent jQuery.event.pause
* @plugin jquery/event/default
*
* `jQuery.fn.triggerAsync(type, [data], [success], [prevented]` triggers an event and calls success
* when the event has finished propagating through the DOM and no other handler
* called `event.preventDefault()` or returned `false`.
*
* $('#panel').triggerAsync('show', function() {
* $('#panel').show();
* });
*
* You can also provide a callback that gets called if `event.preventDefault()` was called on the event:
*
* $('panel').triggerAsync('show', function(){
* $('#panel').show();
* },function(){
* $('#other').addClass('error');
* });
*
* @param {String} type The type of event
* @param {Object} data The data for the event
* @param {Function} success a callback function which occurs upon success
* @param {Function} prevented a callback function which occurs if preventDefault was called
*/
$.fn.triggerAsync = function(type, data, success, prevented){
if(typeof data == 'function'){
success = data;
data = undefined;
}
if ( this[0] ) {
// Create a new jQuery event object and store the original preventDefault
var event = $.Event( type ),
old = event.preventDefault;
event.preventDefault = function(){
old.apply(this, arguments);
// call the prevented callback when event.preventDefault is called
prevented && prevented(this)
}
// Trigger the event with the success callback as the success handler
jQuery.event.trigger( {type: type, _success: success}, data, this[0] );
} else{
// If we have no elements call the success callback right away
success.call(this);
}
return this;
}
/**
* @add jQuery.event.special
*/
//cache default types for performance
var types = {}, rnamespaces= /\.(.*)$/, $event = $.event;
/**
* @attribute default
* @parent specialevents
* @plugin jquery/event/default
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/default/default.js
* @test jquery/event/default/qunit.html
*
*/
$event.special["default"] = {
add: function( handleObj ) {
//save the type
types[handleObj.namespace.replace(rnamespaces,"")] = true;
},
setup: function() {return true}
}
// overwrite trigger to allow default types
var oldTrigger = $event.trigger;
$event.trigger = function defaultTriggerer( event, data, elem, onlyHandlers){
// Event object or event type
var type = event.type || event,
// Caller can pass in an Event, Object, or just an event type string
event = typeof event === "object" ?
// jQuery.Event object
event[ jQuery.expando ] ? event :
// Object literal
new jQuery.Event( type, event ) :
// Just the event type (string)
new jQuery.Event( type),
res = oldTrigger.call($.event, event, data, elem, onlyHandlers);
if(!onlyHandlers && !event.isDefaultPrevented() && event.type.indexOf("default") !== 0) {
// Trigger the default. event
oldTrigger("default."+event.type, data, elem)
if(event._success){
event._success(event)
}
}
// code for paused
if( event.isPaused && event.isPaused() ){
// set back original stuff
event.isDefaultPrevented =
event.pausedState.isDefaultPrevented;
event.isPropagationStopped =
event.pausedState.isPropagationStopped;
}
return res;
};
})(jQuery);
(function($){
var getSetZero = function(v){ return v !== undefined ? (this.array[0] = v) : this.array[0] },
getSetOne = function(v){ return v !== undefined ? (this.array[1] = v) : this.array[1]};
/**
* @class jQuery.Vector
* @parent jquerypp
*
* `jQuery.Vector` represents a multi dimensional vector with shorthand methods for
* working with two dimensions.
*
* It is mainly used in [jQuery.event.drag drag] & [jQuery.event.drop drop] events.
*
* @constructor creates a new vector instance from the arguments. Example:
*
* new jQuery.Vector(1,2)
*/
$.Vector = function(arr) {
var array = $.isArray(arr) ? arr : $.makeArray(arguments);
this.update(array);
};
$.Vector.prototype =
/* @Prototype*/
{
/**
* Applys the function to every item in the vector and returns a new vector.
*
* @param {Function} f The function to apply
* @return {jQuery.Vector} A new $.Vector instance
*/
app: function( f ) {
var i, newArr = [];
for ( i = 0; i < this.array.length; i++ ) {
newArr.push(f(this.array[i], i));
}
return new $.Vector(newArr);
},
/**
* Adds two vectors together and returns a new instance. Example:
*
* new $.Vector(1,2).plus(2,3) //-> (3, 5)
* new $.Vector(3,5).plus(new Vector(4,5)) //-> (7, 10)
*
* @return {$.Vector}
*/
plus: function() {
var i, args = arguments[0] instanceof $.Vector ? arguments[0].array : $.makeArray(arguments),
arr = this.array.slice(0),
vec = new $.Vector();
for ( i = 0; i < args.length; i++ ) {
arr[i] = (arr[i] ? arr[i] : 0) + args[i];
}
return vec.update(arr);
},
/**
* Subtract one vector from another and returns a new instance. Example:
*
* new $.Vector(4, 5).minus(2, 1) //-> (2, 4)
*
* @return {jQuery.Vector}
*/
minus: function() {
var i, args = arguments[0] instanceof $.Vector ? arguments[0].array : $.makeArray(arguments),
arr = this.array.slice(0),
vec = new $.Vector();
for ( i = 0; i < args.length; i++ ) {
arr[i] = (arr[i] ? arr[i] : 0) - args[i];
}
return vec.update(arr);
},
/**
* Returns the current vector if it is equal to the vector passed in.
*
* `null` if otherwise.
*
* @return {jQuery.Vector}
*/
equals: function() {
var i, args = arguments[0] instanceof $.Vector ? arguments[0].array : $.makeArray(arguments),
arr = this.array.slice(0),
vec = new $.Vector();
for ( i = 0; i < args.length; i++ ) {
if ( arr[i] != args[i] ) {
return null;
}
}
return vec.update(arr);
},
/**
* Returns the first value of the vector.
* You can also access the same value through the following aliases the
* [jQuery.Vector.prototype.left vector.left()] and [jQuery.Vector.prototype.left vector.width()]
* aliases.
*
* For example:
*
* var v = new $.Vector(2, 5);
* v.x() //-> 2
* v.left() //-> 2
* v.width() //-> 2
*
* @return {Number} The first value of the vector
*/
x: getSetZero,
/**
* @hide
* Alias for [jQuery.Vector.prototype.x].
*
* @return {Number}
*/
left: getSetZero,
/**
* @hide
* Alias for [jQuery.Vector.prototype.x].
*
* @return {Number}
*/
width: getSetZero,
/**
* Returns the second value of the vector.
* You can also access the same value through the [jQuery.Vector.prototype.top vector.top()]
* and [jQuery.Vector.prototype.height vector.height()] aliases.
*
* For example:
*
* var v = new $.Vector(2, 5);
* v.y() //-> 5
* v.top() //-> 5
* v.height() //-> 5
*
* @return {Number} The first value of the vector
*/
y: getSetOne,
/**
* @hide
* Alias for [jQuery.Vector.prototype.y].
*
* @return {Number}
*/
top: getSetOne,
/**
* @hide
* Alias for [jQuery.Vector.prototype.y].
*
* @return {Number}
*/
height: getSetOne,
/**
* Returns a string representation of the vector in the form of (x,y,...)
*
* var v = new $.Vector(4, 6, 1, 3);
* v.toString() //-> (4, 6, 1, 3)
*
* @return {String}
*/
toString: function() {
return "(" + this.array.join(', ') + ")";
},
/**
* Replaces the vectors contents
*
* var v = new $.Vector(2, 3);
*
* @param {Object} array
*/
update: function( array ) {
var i;
if ( this.array ) {
for ( i = 0; i < this.array.length; i++ ) {
delete this.array[i];
}
}
this.array = array;
for ( i = 0; i < array.length; i++ ) {
this[i] = this.array[i];
}
return this;
}
};
$.Event.prototype.vector = function() {
var
// Get the first touch element for touch events
touches = "ontouchend" in document && this.originalEvent.touches.length ? this.originalEvent.touches[0] : this;
if ( this.originalEvent.synthetic ) {
var doc = document.documentElement,
body = document.body;
return new $.Vector(touches.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0),
touches.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0));
} else {
return new $.Vector(touches.pageX, touches.pageY);
}
};
$.fn.offsetv = function() {
if ( this[0] == window ) {
return new $.Vector(window.pageXOffset ? window.pageXOffset : document.documentElement.scrollLeft, window.pageYOffset ? window.pageYOffset : document.documentElement.scrollTop);
} else {
var offset = this.offset();
return new $.Vector(offset.left, offset.top);
}
};
$.fn.dimensionsv = function( which ) {
if ( this[0] == window || !which ) {
return new $.Vector(this.width(), this.height());
}
else {
return new $.Vector(this[which + "Width"](), this[which + "Height"]());
}
};
})(jQuery);
(function($){
/**
* @function jQuery.fn.compare
* @parent jQuery.compare
*
* Compare two elements and return a bitmask as a number representing the following conditions:
*
* - `000000` -> __0__: Elements are identical
* - `000001` -> __1__: The nodes are in different documents (or one is outside of a document)
* - `000010` -> __2__: #bar precedes #foo
* - `000100` -> __4__: #foo precedes #bar
* - `001000` -> __8__: #bar contains #foo
* - `010000` -> __16__: #foo contains #bar
*
* You can check for any of these conditions using a bitwise AND:
*
* if( $('#foo').compare($('#bar')) & 2 ) {
* console.log("#bar precedes #foo")
* }
*
* @param {HTMLElement|jQuery} element an element or jQuery collection to compare against.
* @return {Number} A number representing a bitmask deatiling how the elements are positioned from each other.
*/
// See http://ejohn.org/blog/comparing-document-position/
jQuery.fn.compare = function(element){ //usually
try{
// Firefox 3 throws an error with XUL - we can't use compare then
element = element.jquery ? element[0] : element;
}catch(e){
return null;
}
// make sure we aren't coming from XUL element
if (window.HTMLElement) {
var s = HTMLElement.prototype.toString.call(element)
if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]' || s === '[object Window]') {
return null;
}
}
if(this[0].compareDocumentPosition){
// For browsers that support it, use compareDocumentPosition
// https://developer.mozilla.org/en/DOM/Node.compareDocumentPosition
return this[0].compareDocumentPosition(element);
}
// this[0] contains element
if(this[0] == document && element != document) return 8;
var number =
// this[0] contains element
(this[0] !== element && this[0].contains(element) && 16) +
// element contains this[0]
(this[0] != element && element.contains(this[0]) && 8),
docEl = document.documentElement;
// Use the sourceIndex
if(this[0].sourceIndex){
// this[0] precedes element
number += (this[0].sourceIndex < element.sourceIndex && 4)
// element precedes foo[0]
number += (this[0].sourceIndex > element.sourceIndex && 2)
// The nodes are in different documents
number += (this[0].ownerDocument !== element.ownerDocument ||
(this[0] != docEl && this[0].sourceIndex <= 0 ) ||
(element != docEl && element.sourceIndex <= 0 )) && 1
}
return number;
}
})(jQuery);
(function($){
// Checks if x and y coordinates are within a box with left, top, width and height
var withinBox = function(x, y, left, top, width, height ){
return (y >= top &&
y < top + height &&
x >= left &&
x < left + width);
}
/**
* @function jQuery.fn.within
* @parent jQuery.within
* @plugin jquery/dom/within
*
* Returns all elements matching the selector that touch a given point:
*
* // get all elements that touch 200x200.
* $('*').within(200, 200);
*
* @param {Number} left the position from the left of the page
* @param {Number} top the position from the top of the page
* @param {Boolean} [useOffsetCache=false] cache the dimensions and offset of the elements.
* @return {jQuery} a jQuery collection of elements whos area
* overlaps the element position.
*/
$.fn.within= function(left, top, useOffsetCache) {
var ret = []
this.each(function(){
var q = jQuery(this);
if (this == document.documentElement) {
return ret.push(this);
}
// uses either the cached offset or .offset()
var offset = useOffsetCache ?
jQuery.data(this,"offsetCache") || jQuery.data(this,"offsetCache", q.offset()) :
q.offset();
// Check if the given coordinates are within the area of the current element
var res = withinBox(left, top, offset.left, offset.top,
this.offsetWidth, this.offsetHeight );
if (res) {
// Add it to the results
ret.push(this);
}
});
return this.pushStack( jQuery.unique( ret ), "within", left+","+top );
}
/**
* @function jQuery.fn.withinBox
* @parent jQuery.within
*
* Returns all elements matching the selector that have a given area in common:
*
* $('*').withinBox(200, 200, 100, 100)
*
* @param {Number} left the position from the left of the page
* @param {Number} top the position from the top of the page
* @param {Number} width the width of the area
* @param {Number} height the height of the area
* @param {Boolean} [useOffsetCache=false] cache the dimensions and offset of the elements.
* @return {jQuery} a jQuery collection of elements whos area
* overlaps the element position.
*/
$.fn.withinBox = function(left, top, width, height, useOffsetCache){
var ret = []
this.each(function(){
var q = jQuery(this);
if(this == document.documentElement) return ret.push(this);
// use cached offset or .offset()
var offset = cache ?
jQuery.data(this,"offset") ||
jQuery.data(this,"offset", q.offset()) :
q.offset();
var ew = q.width(), eh = q.height(),
// Checks if the element offset is within the given box
res = !( (offset.top > top+height) || (offset.top +eh < top) || (offset.left > left+width ) || (offset.left+ew < left));
if(res)
ret.push(this);
});
return this.pushStack( jQuery.unique( ret ), "withinBox", jQuery.makeArray(arguments).join(",") );
}
})(jQuery);
(function( $ ) {
//modify live
//steal the live handler ....
var bind = function( object, method ) {
var args = Array.prototype.slice.call(arguments, 2);
return function() {
var args2 = [this].concat(args, $.makeArray(arguments));
return method.apply(object, args2);
};
},
event = $.event,
// function to clear the window selection if there is one
clearSelection = window.getSelection ? function(){
window.getSelection().removeAllRanges()
} : function(){},
supportTouch = "ontouchend" in document,
// Use touch events or map it to mouse events
startEvent = supportTouch ? "touchstart" : "mousedown",
stopEvent = supportTouch ? "touchend" : "mouseup",
moveEvent = supportTouch ? "touchmove" : "mousemove",
// On touchmove events the default (scrolling) event has to be prevented
preventTouchScroll = function(ev) {
ev.preventDefault();
};
/**
* @class jQuery.Drag
* @parent jQuery.event.drag
* @plugin jquery/event/drag
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/drag/drag.js
* @test jquery/event/drag/qunit.html
*
* The `$.Drag` constructor is never called directly but an instance of `$.Drag` is passed as the second argument
* to the `dragdown`, `draginit`, `dragmove`, `dragend`, `dragover` and `dragout` event handlers:
*
* $('#dragger').on('draginit', function(el, drag) {
* // drag -> $.Drag
* });
*/
$.Drag = function() {};
/**
* @Static
*/
$.extend($.Drag, {
lowerName: "drag",
current: null,
distance: 0,
/**
* Called when someone mouses down on a draggable object.
* Gathers all callback functions and creates a new Draggable.
* @hide
*/
mousedown: function( ev, element ) {
var isLeftButton = ev.button === 0 || ev.button == 1,
doEvent = isLeftButton || supportTouch;
if (!doEvent || this.current ) {
return;
}
//create Drag
var drag = new $.Drag(),
delegate = ev.delegateTarget || element,
selector = ev.handleObj.selector,
self = this;
this.current = drag;
drag.setup({
element: element,
delegate: ev.delegateTarget || element,
selector: ev.handleObj.selector,
moved: false,
_distance: this.distance,
callbacks: {
dragdown: event.find(delegate, ["dragdown"], selector),
draginit: event.find(delegate, ["draginit"], selector),
dragover: event.find(delegate, ["dragover"], selector),
dragmove: event.find(delegate, ["dragmove"], selector),
dragout: event.find(delegate, ["dragout"], selector),
dragend: event.find(delegate, ["dragend"], selector)
},
destroyed: function() {
self.current = null;
}
}, ev);
}
});
/**
* @Prototype
*/
$.extend($.Drag.prototype, {
setup: function( options, ev ) {
$.extend(this, options);
this.element = $(this.element);
this.event = ev;
this.moved = false;
this.allowOtherDrags = false;
var mousemove = bind(this, this.mousemove),
mouseup = bind(this, this.mouseup);
this._mousemove = mousemove;
this._mouseup = mouseup;
this._distance = options.distance ? options.distance : 0;
//where the mouse is located
this.mouseStartPosition = ev.vector();
$(document).bind(moveEvent, mousemove);
$(document).bind(stopEvent, mouseup);
if(supportTouch) {
// On touch devices we want to disable scrolling
$(document).bind(moveEvent, preventTouchScroll);
}
if (!this.callEvents('down', this.element, ev) ) {
this.noSelection(this.delegate);
//this is for firefox
clearSelection();
}
},
/**
* @attribute element
* A reference to the element that is being dragged. For example:
*
* $('.draggable').on('draginit', function(ev, drag) {
* drag.element.html('I am the drag element');
* });
*/
/**
* Unbinds listeners and allows other drags ...
* @hide
*/
destroy: function() {
// Unbind the mouse handlers attached for dragging
$(document).unbind(moveEvent, this._mousemove);
$(document).unbind(stopEvent, this._mouseup);
if(supportTouch) {
// Enable scrolling again for touch devices when the drag is done
$(document).unbind(moveEvent, preventTouchScroll);
}
if (!this.moved ) {
this.event = this.element = null;
}
if(!supportTouch) {
this.selection(this.delegate);
}
this.destroyed();
},
mousemove: function( docEl, ev ) {
if (!this.moved ) {
var dist = Math.sqrt( Math.pow( ev.pageX - this.event.pageX, 2 ) + Math.pow( ev.pageY - this.event.pageY, 2 ));
// Don't initialize the drag if it hasn't been moved the minimum distance
if(dist < this._distance){
return false;
}
// Otherwise call init and indicate that the drag has moved
this.init(this.element, ev);
this.moved = true;
}
var pointer = ev.vector();
if ( this._start_position && this._start_position.equals(pointer) ) {
return;
}
this.draw(pointer, ev);
},
mouseup: function( docEl, event ) {
//if there is a current, we should call its dragstop
if ( this.moved ) {
this.end(event);
}
this.destroy();
},
/**
* The `drag.noSelection(element)` method turns off text selection during a drag event.
* This method is called by default unless a event is listening to the 'dragdown' event.
*
* ## Example
*
* $('div.drag').bind('dragdown', function(elm,event,drag){
* drag.noSelection();
* });
*
* @param [elm] an element to prevent selection on. Defaults to the dragable element.
*/
noSelection: function(elm) {
elm = elm || this.delegate
document.documentElement.onselectstart = function() {
// Disables selection
return false;
};
document.documentElement.unselectable = "on";
this.selectionDisabled = (this.selectionDisabled ? this.selectionDisabled.add(elm) : $(elm));
this.selectionDisabled.css('-moz-user-select', '-moz-none');
},
/**
* @hide
* `drag.selection()` method turns on text selection that was previously turned off during the drag event.
* This method is always called.
*
* ## Example
*
* $('div.drag').bind('dragdown', function(elm,event,drag){
* drag.selection();
* });
*/
selection: function() {
if(this.selectionDisabled) {
document.documentElement.onselectstart = function() {};
document.documentElement.unselectable = "off";
this.selectionDisabled.css('-moz-user-select', '');
}
},
init: function( element, event ) {
element = $(element);
//the element that has been clicked on
var startElement = (this.movingElement = (this.element = $(element)));
//if a mousemove has come after the click
//if the drag has been cancelled
this._cancelled = false;
this.event = event;
/**
* @attribute mouseElementPosition
* The position of start of the cursor on the element
*/
this.mouseElementPosition = this.mouseStartPosition.minus(this.element.offsetv()); //where the mouse is on the Element
this.callEvents('init', element, event);
// Check what they have set and respond accordingly if they canceled
if ( this._cancelled === true ) {
return;
}
// if they set something else as the element
this.startPosition = startElement != this.movingElement ? this.movingElement.offsetv() : this.currentDelta();
this.makePositioned(this.movingElement);
// Adjust the drag elements z-index to a high value
this.oldZIndex = this.movingElement.css('zIndex');
this.movingElement.css('zIndex', 1000);
if (!this._only && this.constructor.responder ) {
// calls $.Drop.prototype.compile if there is a drop element
this.constructor.responder.compile(event, this);
}
},
makePositioned: function( that ) {
var style, pos = that.css('position');
// Position properly, set top and left to 0px for Opera
if (!pos || pos == 'static' ) {
style = {
position: 'relative'
};
if ( window.opera ) {
style.top = '0px';
style.left = '0px';
}
that.css(style);
}
},
callEvents: function( type, element, event, drop ) {
var i, cbs = this.callbacks[this.constructor.lowerName + type];
for ( i = 0; i < cbs.length; i++ ) {
cbs[i].call(element, event, this, drop);
}
return cbs.length;
},
/**
* Returns the position of the movingElement by taking its top and left.
* @hide
* @return {$.Vector}
*/
currentDelta: function() {
return new $.Vector(parseInt(this.movingElement.css('left'), 10) || 0, parseInt(this.movingElement.css('top'), 10) || 0);
},
//draws the position of the dragmove object
draw: function( pointer, event ) {
// only drag if we haven't been cancelled;
if ( this._cancelled ) {
return;
}
clearSelection();
/**
* @attribute location
* `drag.location` is a [jQuery.Vector] specifying where the element should be in the page. This
* takes into account the start position of the cursor on the element.
*
* If the drag is going to be moved to an unacceptable location, you can call preventDefault in
* dragmove to prevent it from being moved there.
*
* $('.mover').bind("dragmove", function(ev, drag){
* if(drag.location.top() < 100){
* ev.preventDefault()
* }
* });
*
* You can also set the location to where it should be on the page.
*
*/
// the offset between the mouse pointer and the representative that the user asked for
this.location = pointer.minus(this.mouseElementPosition);
// call move events
this.move(event);
if ( this._cancelled ) {
return;
}
if (!event.isDefaultPrevented() ) {
this.position(this.location);
}
// fill in
if (!this._only && this.constructor.responder ) {
this.constructor.responder.show(pointer, this, event);
}
},
/**
* `drag.position( newOffsetVector )` sets the position of the movingElement. This is overwritten by
* the [$.Drag::scrolls], [$.Drag::limit] and [$.Drag::step] plugins
* to make sure the moving element scrolls some element
* or stays within some boundary. This function is exposed and documented so you could do the same.
*
* The following approximates how step does it:
*
* var oldPosition = $.Drag.prototype.position;
* $.Drag.prototype.position = function( offsetPositionv ) {
* if(this._step){
* // change offsetPositionv to be on the step value
* }
*
* oldPosition.call(this, offsetPosition)
* }
*
* @param {jQuery.Vector} newOffsetv the new [$.Drag::location] of the element.
*/
position: function( newOffsetv ) { //should draw it on the page
var style, dragged_element_css_offset = this.currentDelta(),
// the drag element's current left + top css attributes
// the vector between the movingElement's page and css positions
// this can be thought of as the original offset
dragged_element_position_vector = this.movingElement.offsetv().minus(dragged_element_css_offset);
this.required_css_position = newOffsetv.minus(dragged_element_position_vector);
this.offsetv = newOffsetv;
style = this.movingElement[0].style;
if (!this._cancelled && !this._horizontal ) {
style.top = this.required_css_position.top() + "px";
}
if (!this._cancelled && !this._vertical ) {
style.left = this.required_css_position.left() + "px";
}
},
move: function( event ) {
this.callEvents('move', this.element, event);
},
over: function( event, drop ) {
this.callEvents('over', this.element, event, drop);
},
out: function( event, drop ) {
this.callEvents('out', this.element, event, drop);
},
/**
* Called on drag up
* @hide
* @param {Event} event a mouseup event signalling drag/drop has completed
*/
end: function( event ) {
// If canceled do nothing
if ( this._cancelled ) {
return;
}
// notify the responder - usually a $.Drop instance
if (!this._only && this.constructor.responder ) {
this.constructor.responder.end(event, this);
}
this.callEvents('end', this.element, event);
if ( this._revert ) {
var self = this;
// animate moving back to original position
this.movingElement.animate({
top: this.startPosition.top() + "px",
left: this.startPosition.left() + "px"
}, function() {
self.cleanup.apply(self, arguments);
});
}
else {
this.cleanup();
}
this.event = null;
},
/**
* Cleans up drag element after drag drop.
* @hide
*/
cleanup: function() {
this.movingElement.css({
zIndex: this.oldZIndex
});
if ( this.movingElement[0] !== this.element[0] &&
!this.movingElement.has(this.element[0]).length &&
!this.element.has(this.movingElement[0]).length ) {
this.movingElement.css({
display: 'none'
});
}
if ( this._removeMovingElement ) {
// Remove the element when using drag.ghost()
this.movingElement.remove();
}
this.movingElement = this.element = this.event = null;
},
/**
* `drag.cancel()` stops a drag motion from from running. This also stops any other events from firing, meaning
* that "dragend" will not be called.
*
* $("#todos").on(".handle", "draginit", function( ev, drag ) {
* if(drag.movingElement.hasClass("evil")){
* drag.cancel();
* }
* })
*
*/
cancel: function() {
this._cancelled = true;
if (!this._only && this.constructor.responder ) {
// clear the drops
this.constructor.responder.clear(this.event.vector(), this, this.event);
}
this.destroy();
},
/**
* `drag.ghost( [parent] )` clones the element and uses it as the
* moving element, leaving the original dragged element in place. The `parent` option can
* be used to specify where the ghost element should be temporarily added into the
* DOM. This method should be called in "draginit".
*
* $("#todos").on(".handle", "draginit", function( ev, drag ) {
* drag.ghost();
* })
*
* @param {HTMLElement} [parent] the parent element of the newly created ghost element. If not provided the
* ghost element is added after the moving element.
* @return {jQuery.fn} the ghost element to do whatever you want with it.
*/
ghost: function( parent ) {
// create a ghost by cloning the source element and attach the clone to the dom after the source element
var ghost = this.movingElement.clone().css('position', 'absolute');
if( parent ) {
$(parent).append(ghost);
} else {
$(this.movingElement).after(ghost)
}
ghost.width(this.movingElement.width()).height(this.movingElement.height());
// put the ghost in the right location ...
ghost.offset(this.movingElement.offset())
// store the original element and make the ghost the dragged element
this.movingElement = ghost;
this.noSelection(ghost)
this._removeMovingElement = true;
return ghost;
},
/**
* `drag.representative( element, [offsetX], [offsetY])` tells the drag motion to use
* a different element than the one that began the drag motion.
*
* For example, instead of
* dragging an drag-icon of a todo element, you want to move some other representation of
* the todo element (or elements). To do this you might:
*
* $("#todos").on(".handle", "draginit", function( ev, drag ) {
* // create what we'll drag
* var rep = $('').text("todos")
* .appendTo(document.body)
* // indicate we want our mouse on the top-right of it
* drag.representative(rep, rep.width(), 0);
* })
*
* @param {HTMLElement} element the element you want to actually drag. This should be
* already in the DOM.
* @param {Number} offsetX the x position where you want your mouse on the representative element (defaults to 0)
* @param {Number} offsetY the y position where you want your mouse on the representative element (defaults to 0)
* @return {drag} returns the drag object for chaining.
*/
representative: function( element, offsetX, offsetY ) {
this._offsetX = offsetX || 0;
this._offsetY = offsetY || 0;
var p = this.mouseStartPosition;
// Just set the representative as the drag element
this.movingElement = $(element);
this.movingElement.css({
top: (p.y() - this._offsetY) + "px",
left: (p.x() - this._offsetX) + "px",
display: 'block',
position: 'absolute'
}).show();
this.noSelection(this.movingElement)
this.mouseElementPosition = new $.Vector(this._offsetX, this._offsetY);
return this;
},
/**
* `drag.revert([val])` makes the [$.Drag::representative representative] element revert back to it
* original position after the drag motion has completed. The revert is done with an animation.
*
* $("#todos").on(".handle","dragend",function( ev, drag ) {
* drag.revert();
* })
*
* @param {Boolean} [val] optional, set to false if you don't want to revert.
* @return {drag} the drag object for chaining
*/
revert: function( val ) {
this._revert = val === undefined ? true : val;
return this;
},
/**
* `drag.vertical()` isolates the drag to vertical movement. For example:
*
* $("#images").on(".thumbnail","draginit", function(ev, drag){
* drag.vertical();
* });
*
* Call `vertical()` in "draginit" or "dragdown".
*
* @return {drag} the drag object for chaining.
*/
vertical: function() {
this._vertical = true;
return this;
},
/**
* `drag.horizontal()` isolates the drag to horizontal movement. For example:
*
* $("#images").on(".thumbnail","draginit", function(ev, drag){
* drag.horizontal();
* });
*
* Call `horizontal()` in "draginit" or "dragdown".
*
* @return {drag} the drag object for chaining.
*/
horizontal: function() {
this._horizontal = true;
return this;
},
/**
* `drag.only([only])` indicates if you __only__ want a drag motion and the drag should
* not notify drops. The default value is `false`. Call it with no arguments or pass it true
* to prevent drop events.
*
* $("#images").on(".thumbnail","dragdown", function(ev, drag){
* drag.only();
* });
*
* @param {Boolean} [only] true if you want to prevent drops, false if otherwise.
* @return {Boolean} the current value of only.
*/
only: function( only ) {
return (this._only = (only === undefined ? true : only));
},
/**
* `distance([val])` sets or reads the distance the mouse must move before a drag motion is started. This should be set in
* "dragdown" and delays "draginit" being called until the distance is covered. The distance
* is measured in pixels. The default distance is 0 pixels meaning the drag motion starts on the first
* mousemove after a mousedown.
*
* Set this to make drag motion a little "stickier" to start.
*
* $("#images").on(".thumbnail","dragdown", function(ev, drag){
* drag.distance(10);
* });
*
* @param {Number} [val] The number of pixels the mouse must move before "draginit" is called.
* @return {drag|Number} returns the drag instance for chaining if the drag value is being set or the
* distance value if the distance is being read.
*/
distance: function(val){
if(val !== undefined){
this._distance = val;
return this;
}else{
return this._distance
}
}
});
/**
* @add jQuery.event.special
*/
event.setupHelper([
/**
* @attribute dragdown
* @parent jQuery.event.drag
*
* `dragdown` is called when a drag movement has started on a mousedown.
* The event handler gets an instance of [jQuery.Drag] passed as the second
* parameter. Listening to `dragdown` allows you to customize
* the behavior of a drag motion, especially when `draginit` should be called.
*
* $(".handles").delegate("dragdown", function(ev, drag){
* // call draginit only when the mouse has moved 20 px
* drag.distance(20);
* })
*
* Typically, when a drag motion is started, `event.preventDefault` is automatically
* called, preventing text selection. However, if you listen to
* `dragdown`, this default behavior is not called. You are responsible for calling it
* if you want it (you probably do).
*
* ### Why might you not want to call `preventDefault`?
*
* You might want it if you want to allow text selection on element
* within the drag element. Typically these are input elements.
*
* $(".handles").delegate("dragdown", function(ev, drag){
* if(ev.target.nodeName === "input"){
* drag.cancel();
* } else {
* ev.preventDefault();
* }
* })
*/
'dragdown',
/**
* @attribute draginit
* @parent jQuery.event.drag
*
* `draginit` is triggered when the drag motion starts. Use it to customize the drag behavior
* using the [jQuery.Drag] instance passed as the second parameter:
*
* $(".draggable").on('draginit', function(ev, drag) {
* // Only allow vertical drags
* drag.vertical();
* // Create a draggable copy of the element
* drag.ghost();
* });
*/
'draginit',
/**
* @attribute dragover
* @parent jQuery.event.drag
*
* `dragover` is triggered when a drag is over a [jQuery.event.drop drop element].
* The event handler gets an instance of [jQuery.Drag] passed as the second
* parameter and an instance of [jQuery.Drop] passed as the third argument:
*
* $('.draggable').on('dragover', function(ev, drag, drop) {
* // Add the drop-here class indicating that the drag
* // can be dropped here
* drag.element.addClass('drop-here');
* });
*/
'dragover',
/**
* @attribute dragmove
* @parent jQuery.event.drag
*
* `dragmove` is triggered when the drag element moves (similar to a mousemove).
* The event handler gets an instance of [jQuery.Drag] passed as the second
* parameter.
* Use [jQuery.Drag::location] to determine the current position
* as a [jQuery.Vector vector].
*
* For example, `dragmove` can be used to create a draggable element to resize
* a container:
*
* $('.resizer').on('dragmove', function(ev, drag) {
* $('#container').width(drag.location.x())
* .height(drag.location.y());
* });
*/
'dragmove',
/**
* @attribute dragout
* @parent jQuery.event.drag
*
* `dragout` is called when the drag leaves a drop point.
* The event handler gets an instance of [jQuery.Drag] passed as the second
* parameter.
*
* $('.draggable').on('dragout', function(ev, drag) {
* // Remove the drop-here class
* // (e.g. crossing the drag element out indicating that it
* // can't be dropped here
* drag.element.removeClass('drop-here');
* });
*/
'dragout',
/**
* @attribute dragend
* @parent jQuery.event.drag
*
* `dragend` is called when the drag motion is done.
* The event handler gets an instance of [jQuery.Drag] passed as the second
* parameter.
*
* $('.draggable').on('dragend', function(ev, drag)
* // Clean up when the drag motion is done
* });
*/
'dragend'], startEvent, function( e ) {
$.Drag.mousedown.call($.Drag, e, this);
});
})(jQuery);
(function( $ ) {
var getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
// The following variables are used to convert camelcased attribute names
// into dashed names, e.g. borderWidth to border-width
rupper = /([A-Z])/g,
rdashAlpha = /-([a-z])/ig,
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
},
// Returns the computed style for an elementn
getStyle = function( elem ) {
if ( getComputedStyle ) {
return getComputedStyle(elem, null);
}
else if ( elem.currentStyle ) {
return elem.currentStyle;
}
},
// Checks for float px and numeric values
rfloat = /float/i,
rnumpx = /^-?\d+(?:px)?$/i,
rnum = /^-?\d/;
// Returns a list of styles for a given element
$.styles = function( el, styles ) {
if (!el ) {
return null;
}
var currentS = getStyle(el),
oldName, val, style = el.style,
results = {},
i = 0,
left, rsLeft, camelCase, name;
// Go through each style
for (; i < styles.length; i++ ) {
name = styles[i];
oldName = name.replace(rdashAlpha, fcamelCase);
if ( rfloat.test(name) ) {
name = jQuery.support.cssFloat ? "float" : "styleFloat";
oldName = "cssFloat";
}
// If we have getComputedStyle available
if ( getComputedStyle ) {
// convert camelcased property names to dashed name
name = name.replace(rupper, "-$1").toLowerCase();
// use getPropertyValue of the current style object
val = currentS.getPropertyValue(name);
// default opacity is 1
if ( name === "opacity" && val === "" ) {
val = "1";
}
results[oldName] = val;
} else {
// Without getComputedStyles
camelCase = name.replace(rdashAlpha, fcamelCase);
results[oldName] = currentS[name] || currentS[camelCase];
// convert to px
if (!rnumpx.test(results[oldName]) && rnum.test(results[oldName]) ) {
// Remember the original values
left = style.left;
rsLeft = el.runtimeStyle.left;
// Put in the new values to get a computed value out
el.runtimeStyle.left = el.currentStyle.left;
style.left = camelCase === "fontSize" ? "1em" : (results[oldName] || 0);
results[oldName] = style.pixelLeft + "px";
// Revert the changed values
style.left = left;
el.runtimeStyle.left = rsLeft;
}
}
}
return results;
};
/**
* @function jQuery.fn.styles
* @parent jQuery.styles
* @plugin jQuery.styles
*
* Returns a set of computed styles. Pass the names of the styles you want to
* retrieve as arguments:
*
* $("div").styles('float','display')
* // -> { cssFloat: "left", display: "block" }
*
* @param {String} style pass the names of the styles to retrieve as the argument list
* @return {Object} an object of `style` : `value` pairs
*/
$.fn.styles = function() {
// Pass the arguments as an array to $.styles
return $.styles(this[0], $.makeArray(arguments));
};
})(jQuery);
(function($){
var event = $.event;
/**
* @add jQuery.event.special
*/
var eventNames = [
/**
* @attribute dropover
* @parent jQuery.event.drop
*
* `dropover` is triggered when a [jQuery.event.drag drag] is first moved onto this
* drop element.
* The event handler gets an instance of [jQuery.Drag] passed as the second and a
* [jQuery.Drop] as the third parameter.
* This event can be used to highlight the element when a drag is moved over it:
*
* $('.droparea').on('dropover', function(ev, drop, drag) {
* $(this).addClass('highlight');
* });
*/
"dropover",
/**
* @attribute dropon
* @parent jQuery.event.drop
*
* `dropon` is triggered when a drag is dropped on a drop element.
* The event handler gets an instance of [jQuery.Drag] passed as the second and a
* [jQuery.Drop] as the third parameter.
*
* $('.droparea').on('dropon', function(ev, drop, drag) {
* $(this).html('Dropped: ' + drag.element.text());
* });
*/
"dropon",
/**
* @attribute dropout
* @parent jQuery.event.drop
*
* `dropout` is called when a drag is moved out of this drop element.
* The event handler gets an instance of [jQuery.Drag] passed as the second and a
* [jQuery.Drop] as the third parameter.
*
* $('.droparea').on('dropover', function(ev, drop, drag) {
* // Remove the drop element highlight
* $(this).removeClass('highlight');
* });
*/
"dropout",
/**
* @attribute dropinit
* @parent jQuery.event.drop
*
* `dropinit` is called when a drag motion starts and the drop elements are initialized.
* The event handler gets an instance of [jQuery.Drag] passed as the second and a
* [jQuery.Drop] as the third parameter.
* Calling [jQuery.Drop.prototype.cancel drop.cancel()] prevents the element from
* being dropped on:
*
* $('.droparea').on('dropover', function(ev, drop, drag) {
* if(drag.element.hasClass('not-me')) {
* drop.cancel();
* }
* });
*/
"dropinit",
/**
* @attribute dropmove
* @parent jQuery.event.drop
*
* `dropmove` is triggered repeatedly when a drag is moved over a drop
* (similar to a mousemove).
* The event handler gets an instance of [jQuery.Drag] passed as the second and a
* [jQuery.Drop] as the third parameter.
*
* $('.droparea').on('dropmove', function(ev, drop, drag) {
* $(this).html(drag.location.x() + '/' + drag.location.y());
* });
*/
"dropmove",
/**
* @attribute dropend
* @parent jQuery.event.drop
*
* `dropend` is called when the drag motion is done for this drop element.
* The event handler gets an instance of [jQuery.Drag] passed as the second and a
* [jQuery.Drop] as the third parameter.
*
*
* $('.droparea').on('dropend', function(ev, drop, drag) {
* // Remove the drop element highlight
* $(this).removeClass('highlight');
* });
*/
"dropend"];
/**
* @class jQuery.Drop
* @parent jQuery.event.drop
* @plugin jquery/event/drop
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/drop/drop.js
* @test jquery/event/drag/qunit.html
*
* The `jQuery.Drop` constructor is never called directly but an instance is passed to the
* to the `dropinit`, `dropover`, `dropmove`, `dropon`, and `dropend` event handlers as the
* third argument (the second will be the [jQuery.Drag]):
*
* $('#dropper').on('dropover', function(el, drop, drag) {
* // drop -> $.Drop
* // drag -> $.Drag
* });
*/
$.Drop = function(callbacks, element){
jQuery.extend(this,callbacks);
this.element = $(element);
}
// add the elements ...
$.each(eventNames, function(){
event.special[this] = {
add: function( handleObj ) {
//add this element to the compiles list
var el = $(this), current = (el.data("dropEventCount") || 0);
el.data("dropEventCount", current+1 )
if(current==0){
$.Drop.addElement(this);
}
},
remove: function() {
var el = $(this), current = (el.data("dropEventCount") || 0);
el.data("dropEventCount", current-1 )
if(current<=1){
$.Drop.removeElement(this);
}
}
}
});
$.extend($.Drop,{
/**
* @static
*/
lowerName: "drop",
_rootElements: [], //elements that are listening for drops
_elements: $(), //elements that can be dropped on
last_active: [],
endName: "dropon",
// adds an element as a 'root' element
// this element might have events that we need to respond to
addElement: function( el ) {
// check other elements
for(var i =0; i < this._rootElements.length ; i++ ){
if(el ==this._rootElements[i]) return;
}
this._rootElements.push(el);
},
removeElement: function( el ) {
for(var i =0; i < this._rootElements.length ; i++ ){
if(el == this._rootElements[i]){
this._rootElements.splice(i,1)
return;
}
}
},
/**
* @hide
* For a list of affected drops, sorts them by which is deepest in the DOM first.
*/
sortByDeepestChild: function( a, b ) {
// Use jQuery.compare to compare two elements
var compare = a.element.compare(b.element);
if(compare & 16 || compare & 4) return 1;
if(compare & 8 || compare & 2) return -1;
return 0;
},
/**
* @hide
* Tests if a drop is within the point.
*/
isAffected: function( point, moveable, responder ) {
return ((responder.element != moveable.element) && (responder.element.within(point[0], point[1], responder._cache).length == 1));
},
/**
* @hide
* Calls dropout and sets last active to null
* @param {Object} drop
* @param {Object} drag
* @param {Object} event
*/
deactivate: function( responder, mover, event ) {
mover.out(event, responder)
responder.callHandlers(this.lowerName+'out',responder.element[0], event, mover)
},
/**
* @hide
* Calls dropover
* @param {Object} drop
* @param {Object} drag
* @param {Object} event
*/
activate: function( responder, mover, event ) { //this is where we should call over
mover.over(event, responder)
responder.callHandlers(this.lowerName+'over',responder.element[0], event, mover);
},
move: function( responder, mover, event ) {
responder.callHandlers(this.lowerName+'move',responder.element[0], event, mover)
},
/**
* `$.Drop.compile()` gets all elements that are droppable and adds them to a list.
*
* This should be called if and when new drops are added to the page
* during the motion of a single drag.
*
* This is called by default when a drag motion starts.
*
* ## Use
*
* After adding an element or drop, call compile.
*
* $("#midpoint").bind("dropover",function(){
* // when a drop hovers over midpoint,
* // make drop a drop.
* $("#drop").bind("dropover", function(){
*
* });
* $.Drop.compile();
* });
*/
compile: function( event, drag ) {
// if we called compile w/o a current drag
if(!this.dragging && !drag){
return;
}else if(!this.dragging){
this.dragging = drag;
this.last_active = [];
}
var el,
drops,
selector,
dropResponders,
newEls = [],
dragging = this.dragging;
// go to each root element and look for drop elements
for(var i=0; i < this._rootElements.length; i++){ //for each element
el = this._rootElements[i]
// gets something like {"": ["dropinit"], ".foo" : ["dropover","dropmove"] }
var drops = $.event.findBySelector(el, eventNames)
// get drop elements by selector
for(selector in drops){
dropResponders = selector ? jQuery(selector, el) : [el];
// for each drop element
for(var e= 0; e < dropResponders.length; e++){
// add the callbacks to the element's Data
// there already might be data, so we merge it
if( this.addCallbacks(dropResponders[e], drops[selector], dragging) ){
newEls.push(dropResponders[e])
};
}
}
}
// once all callbacks are added, call init on everything ...
this.add(newEls, event, dragging)
},
// adds the drag callbacks object to the element or merges other callbacks ...
// returns true or false if the element is new ...
// onlyNew lets only new elements add themselves
addCallbacks : function(el, callbacks, onlyNew){
var origData = $.data(el,"_dropData");
if(!origData){
$.data(el,"_dropData", new $.Drop(callbacks, el));
return true;
}else if(!onlyNew){
var origCbs = origData;
// merge data
for(var eventName in callbacks){
origCbs[eventName] = origCbs[eventName] ?
origCbs[eventName].concat(callbacks[eventName]) :
callbacks[eventName];
}
return false;
}
},
// calls init on each element's drags.
// if its cancelled it's removed
// adds to the current elements ...
add: function( newEls, event, drag , dragging) {
var i = 0,
drop;
while(i < newEls.length){
drop = $.data(newEls[i],"_dropData");
drop.callHandlers(this.lowerName+'init', newEls[i], event, drag)
if(drop._canceled){
newEls.splice(i,1)
}else{
i++;
}
}
this._elements.push.apply(this._elements, newEls)
},
show: function( point, moveable, event ) {
var element = moveable.element;
if(!this._elements.length) return;
var respondable,
affected = [],
propagate = true,
i = 0,
j,
la,
toBeActivated,
aff,
oldLastActive = this.last_active,
responders = [],
self = this,
drag;
// what's still affected ... we can also move element out here
while( i < this._elements.length){
drag = $.data(this._elements[i],"_dropData");
if (!drag) {
this._elements.splice(i, 1)
}
else {
i++;
if (self.isAffected(point, moveable, drag)) {
affected.push(drag);
}
}
}
// we should only trigger on lowest children
affected.sort(this.sortByDeepestChild);
event.stopRespondPropagate = function(){
propagate = false;
}
toBeActivated = affected.slice();
// all these will be active
this.last_active = affected;
// deactivate everything in last_active that isn't active
for (j = 0; j < oldLastActive.length; j++) {
la = oldLastActive[j];
i = 0;
while((aff = toBeActivated[i])){
if(la == aff){
toBeActivated.splice(i,1);break;
}else{
i++;
}
}
if(!aff){
this.deactivate(la, moveable, event);
}
if(!propagate) return;
}
for(var i =0; i < toBeActivated.length; i++){
this.activate(toBeActivated[i], moveable, event);
if(!propagate) return;
}
// activate everything in affected that isn't in last_active
for (i = 0; i < affected.length; i++) {
this.move(affected[i], moveable, event);
if(!propagate) return;
}
},
end: function( event, moveable ) {
var responder, la,
endName = this.lowerName+'end',
dropData;
// call dropon
// go through the actives ... if you are over one, call dropped on it
for(var i = 0; i < this.last_active.length; i++){
la = this.last_active[i]
if( this.isAffected(event.vector(), moveable, la) && la[this.endName]){
la.callHandlers(this.endName, null, event, moveable);
}
}
// call dropend
for(var r =0; r range
*
* @return {$.Range} A $.Range instance for the selected element
*/
function(){
return $.Range(this[0])
}
var convertType = function(type){
return type.replace(/([a-z])([a-z]+)/gi, function(all,first, next){
return first+next.toLowerCase()
}).replace(/_/g,"");
},
// reverses things like START_TO_END into END_TO_START
reverse = function(type){
return type.replace(/^([a-z]+)_TO_([a-z]+)/i, function(all, first, last){
return last+"_TO_"+first;
});
},
getWindow = function( element ) {
return element ? element.ownerDocument.defaultView || element.ownerDocument.parentWindow : window
},
bisect = function(el, start, end){
//split the start and end ... figure out who is touching ...
if(end-start == 1){
return
}
},
support = {};
/**
* @Class jQuery.Range
* @parent jQuery.Range
*
* Depending on the object passed, the selected text will be different.
*
* @param {TextRange|HTMLElement|Point} [range] An object specifiying a
* range. Depending on the object, the selected text will be different. $.Range supports the
* following types
*
* - __undefined or null__ - returns a range with nothing selected
* - __HTMLElement__ - returns a range with the node's text selected
* - __Point__ - returns a range at the point on the screen. The point can be specified like:
*
* //client coordinates
* {clientX: 200, clientY: 300}
*
* //page coordinates
* {pageX: 200, pageY: 300}
* {top: 200, left: 300}
*
* - __TextRange__ a raw text range object.
*/
$.Range = function(range){
// If it's called w/o new, call it with new!
if(this.constructor !== $.Range){
return new $.Range(range);
}
// If we are passed a jQuery-wrapped element, get the raw element
if(range && range.jquery){
range = range[0];
}
// If we have an element, or nothing
if(!range || range.nodeType){
// create a range
this.win = getWindow(range)
if(this.win.document.createRange){
this.range = this.win.document.createRange()
}else{
this.range = this.win.document.body.createTextRange()
}
// if we have an element, make the range select it
if(range){
this.select(range)
}
}
// if we are given a point
else if (range.clientX != null || range.pageX != null || range.left != null) {
this.moveToPoint(range);
}
// if we are given a touch event
else if (range.originalEvent && range.originalEvent.touches && range.originalEvent.touches.length) {
this.moveToPoint(range.originalEvent.touches[0])
}
// if we are a normal event
else if (range.originalEvent && range.originalEvent.changedTouches && range.originalEvent.changedTouches.length) {
this.moveToPoint(range.originalEvent.changedTouches[0])
}
// given a TextRange or something else?
else {
this.range = range;
}
};
/**
* @static
*/
$.Range.
/**
* `$.Range.current([element])` returns the currently selected range
* (using [window.getSelection](https://developer.mozilla.org/en/nsISelection)).
*
* var range = $.Range.current()
* range.start().offset // -> selection start offset
* range.end().offset // -> selection end offset
*
* @param {HTMLElement} [el] an optional element used to get selection for a given window.
* @return {jQuery.Range} The range instance.
*/
current = function(el){
var win = getWindow(el),
selection;
if(win.getSelection){
// If we can get the selection
selection = win.getSelection()
return new $.Range( selection.rangeCount ? selection.getRangeAt(0) : win.document.createRange())
} else {
// Otherwise use document.selection
return new $.Range( win.document.selection.createRange() );
}
};
$.extend($.Range.prototype,
/** @prototype **/
{
/**
* `range.moveToPoint(point)` moves the range end and start position to a specific point.
* A point can be specified like:
*
* //client coordinates
* {clientX: 200, clientY: 300}
*
* //page coordinates
* {pageX: 200, pageY: 300}
* {top: 200, left: 300}
*
* @param point The point to move the range to
* @return {$.Range}
*/
moveToPoint : function(point){
var clientX = point.clientX, clientY = point.clientY
if(!clientX){
var off = scrollOffset();
clientX = (point.pageX || point.left || 0 ) - off.left;
clientY = (point.pageY || point.top || 0 ) - off.top;
}
if(support.moveToPoint){
this.range = $.Range().range
this.range.moveToPoint(clientX, clientY);
return this;
}
// it's some text node in this range ...
var parent = document.elementFromPoint(clientX, clientY);
//typically it will be 'on' text
for(var n=0; n < parent.childNodes.length; n++){
var node = parent.childNodes[n];
if(node.nodeType === 3 || node.nodeType === 4){
var range = $.Range(node),
length = range.toString().length;
// now lets start moving the end until the boundingRect is within our range
for(var i = 1; i < length+1; i++){
var rect = range.end(i).rect();
if(rect.left <= clientX && rect.left+rect.width >= clientX &&
rect.top <= clientY && rect.top+rect.height >= clientY ){
range.start(i-1);
this.range = range.range;
return this;
}
}
}
}
// if not 'on' text, recursively go through and find out when we shift to next
// 'line'
var previous;
iterate(parent.childNodes, function(textNode){
var range = $.Range(textNode);
if(range.rect().top > point.clientY){
return false;
}else{
previous = range;
}
});
if(previous){
previous.start(previous.toString().length);
this.range = previous.range;
}else{
this.range = $.Range(parent).range
}
},
window : function(){
return this.win || window;
},
/**
* `range.overlaps([elRange])` returns `true` if any portion of these two ranges overlap.
*
* var foo = document.getElementById('foo');
*
* $.Range(foo.childNodes[0]).overlaps(foo.childNodes[1]) //-> false
*
* @param {jQuery.Range} elRange The range to compare
* @return {Boolean} true if part of the ranges overlap, false if otherwise.
*/
overlaps : function(elRange){
if(elRange.nodeType){
elRange = $.Range(elRange).select(elRange);
}
//if the start is within the element ...
var startToStart = this.compare("START_TO_START", elRange),
endToEnd = this.compare("END_TO_END", elRange)
// if we wrap elRange
if(startToStart <=0 && endToEnd >=0){
return true;
}
// if our start is inside of it
if( startToStart >= 0 &&
this.compare("START_TO_END", elRange) <= 0 ) {
return true;
}
// if our end is inside of elRange
if(this.compare("END_TO_START", elRange) >= 0 &&
endToEnd <= 0 ) {
return true;
}
return false;
},
/**
* `range.collapse([toStart])` collapses a range to one of its boundary points.
* See [range.collapse](https://developer.mozilla.org/en/DOM/range.collapse).
*
* $('#foo').range().collapse()
*
* @param {Boolean} [toStart] true if to the start of the range, false if to the
* end. Defaults to false.
* @return {jQuery.Range} returns the range for chaining.
*/
collapse : function(toStart){
this.range.collapse(toStart === undefined ? true : toStart);
return this;
},
/**
* `range.toString()` returns the text of the range.
*
* currentText = $.Range.current().toString()
*
* @return {String} The text content of this range
*/
toString : function(){
return typeof this.range.text == "string" ? this.range.text : this.range.toString();
},
/**
* `range.start([start])` gets or sets the start of the range.
*
* If a value is not provided, start returns the range's starting container and offset like:
*
* $('#foo').range().start()
* //-> {container: fooElement, offset: 0 }
*
* If a set value is provided, it can set the range. The start of the range is set differently
* depending on the type of set value:
*
* - __Object__ - an object with the new starting container and offset like
*
* $.Range().start({container: $('#foo')[0], offset: 20})
*
* - __Number__ - the new offset value. The container is kept the same.
*
* - __String__ - adjusts the offset by converting the string offset to a number and adding it to the current
* offset. For example, the following moves the offset forward four characters:
*
* $('#foo').range().start("+4")
*
* Note that `start` can return a text node. To get the containing element use this:
*
* var startNode = range.start().container;
* if( startNode.nodeType === Node.TEXT_NODE ||
* startNode.nodeType === Node.CDATA_SECTION_NODE ) {
* startNode = startNode.parentNode;
* }
* $(startNode).addClass('highlight');
*
* @param {Object|String|Number} [set] a set value if setting the start of the range or nothing if reading it.
* @return {jQuery.Range|Object} if setting the start, the range is returned for chaining, otherwise, the
* start offset and container are returned.
*/
start : function(set){
// return start
if(set === undefined){
if(this.range.startContainer){
return {
container : this.range.startContainer,
offset : this.range.startOffset
}
}else{
// Get the start parent element
var start = this.clone().collapse().parent();
// used to get the start element offset
var startRange = $.Range(start).select(start).collapse();
startRange.move("END_TO_START", this);
return {
container : start,
offset : startRange.toString().length
}
}
} else {
if (this.range.setStart) {
// supports setStart
if(typeof set == 'number'){
this.range.setStart(this.range.startContainer, set)
} else if(typeof set == 'string') {
var res = callMove(this.range.startContainer, this.range.startOffset, parseInt(set,10))
this.range.setStart(res.node, res.offset );
} else {
this.range.setStart(set.container, set.offset)
}
} else {
if(typeof set == "string"){
this.range.moveStart('character', parseInt(set,10))
} else {
// get the current end container
var container = this.start().container,
offset
if(typeof set == "number") {
offset = set
} else {
container = set.container
offset = set.offset
}
var newPoint = $.Range(container).collapse();
//move it over offset characters
newPoint.range.move(offset);
this.move("START_TO_START",newPoint);
}
}
return this;
}
},
/**
* `range.end([end])` gets or sets the end of the range.
* It takes similar options as [jQuery.Range::start start]:
*
* - __Object__ - an object with the new end container and offset like
*
* $.Range().end({container: $('#foo')[0], offset: 20})
*
* - __Number__ - the new offset value. The container is kept the same.
*
* - __String__ - adjusts the offset by converting the string offset to a number and adding it to the current
* offset. For example, the following moves the offset forward four characters:
*
* $('#foo').range().end("+4")
*
* Note that `end` can return a text node. To get the containing element use this:
*
* var startNode = range.end().container;
* if( startNode.nodeType === Node.TEXT_NODE ||
* startNode.nodeType === Node.CDATA_SECTION_NODE ) {
* startNode = startNode.parentNode;
* }
* $(startNode).addClass('highlight');
*
* @param {Object|String|Number} [set] a set value if setting the end of the range or nothing if reading it.
*/
end : function(set){
// read end
if (set === undefined) {
if (this.range.startContainer) {
return {
container: this.range.endContainer,
offset: this.range.endOffset
}
}
else {
var
// Get the end parent element
end = this.clone().collapse(false).parent(),
// used to get the end elements offset
endRange = $.Range(end).select(end).collapse();
endRange.move("END_TO_END", this);
return {
container: end,
offset: endRange.toString().length
}
}
} else {
if (this.range.setEnd) {
if(typeof set == 'number'){
this.range.setEnd(this.range.endContainer, set)
} else if(typeof set == 'string') {
var res = callMove(this.range.endContainer, this.range.endOffset, parseInt(set,10))
this.range.setEnd(res.node, res.offset );
} else {
this.range.setEnd(set.container, set.offset)
}
} else {
if(typeof set == "string"){
this.range.moveEnd('character', parseInt(set,10));
} else {
// get the current end container
var container = this.end().container,
offset
if(typeof set == "number") {
offset = set
} else {
container = set.container
offset = set.offset
}
var newPoint = $.Range(container).collapse();
//move it over offset characters
newPoint.range.move(offset);
this.move("END_TO_START",newPoint);
}
}
return this;
}
},
/**
* `range.parent()` returns the most common ancestor element of
* the endpoints in the range. This will return a text element if the range is
* within a text element. In this case, to get the containing element use this:
*
* var parent = range.parent();
* if( parent.nodeType === Node.TEXT_NODE ||
* parent.nodeType === Node.CDATA_SECTION_NODE ) {
* parent = startNode.parentNode;
* }
* $(parent).addClass('highlight');
*
* @return {HTMLNode} the TextNode or HTMLElement
* that fully contains the range
*/
parent : function(){
if(this.range.commonAncestorContainer){
return this.range.commonAncestorContainer;
} else {
var parentElement = this.range.parentElement(),
range = this.range;
// IE's parentElement will always give an element, we want text ranges
iterate(parentElement.childNodes, function(txtNode){
if($.Range(txtNode).range.inRange( range ) ){
// swap out the parentElement
parentElement = txtNode;
return false;
}
});
return parentElement;
}
},
/**
* `range.rect([from])` returns the bounding rectangle of this range.
*
* @param {String} [from] - where the coordinates should be
* positioned from. By default, coordinates are given from the client viewport.
* But if 'page' is given, they are provided relative to the page.
*
* @return {TextRectangle} - The client rects.
*/
rect : function(from){
var rect = this.range.getBoundingClientRect();
// for some reason in webkit this gets a better value
if(!rect.height && !rect.width){
rect = this.range.getClientRects()[0]
}
if(from === 'page'){
// Add the scroll offset
var off = scrollOffset();
rect = $.extend({}, rect);
rect.top += off.top;
rect.left += off.left;
}
return rect;
},
/**
* `range.rects(from)` returns the client rects.
*
* @param {String} [from] how the rects coordinates should be given (viewport or page). Provide 'page' for
* rect coordinates from the page.
* @return {Array} The client rects
*/
rects : function(from){
// order rects by size
var rects = $.map($.makeArray( this.range.getClientRects() ).sort(function(rect1, rect2){
return rect2.width*rect2.height - rect1.width*rect1.height;
}), function(rect){
return $.extend({}, rect)
}),
i=0,j,
len = rects.length;
// safari returns overlapping client rects
//
// - big rects can contain 2 smaller rects
// - some rects can contain 0 - width rects
// - we don't want these 0 width rects
while(i < rects.length){
var cur = rects[i],
found = false;
j = i+1;
while( j < rects.length ){
if( withinRect( cur, rects[j] ) ) {
if(!rects[j].width){
rects.splice(j,1)
} else {
found = rects[j];
break;
}
} else {
j++;
}
}
if(found){
rects.splice(i,1)
}else{
i++;
}
}
// safari will be return overlapping ranges ...
if(from == 'page'){
var off = scrollOffset();
return $.each(rects, function(ith, item){
item.top += off.top;
item.left += off.left;
})
}
return rects;
}
});
(function(){
//method branching ....
var fn = $.Range.prototype,
range = $.Range().range;
/**
* @function compare
*
* `range.compare(type, compareRange)` compares one range to another range.
*
* ## Example
*
* // compare the highlight element's start position
* // to the start of the current range
* $('#highlight')
* .range()
* .compare('START_TO_START', $.Range.current())
*
*
*
* @param {String} type Specifies the boundary of the
* range and the compareRange
to compare.
*
* - `"START_TO_START"` - the start of the range and the start of compareRange
* - `"START_TO_END"` - the start of the range and the end of compareRange
* - `"END_TO_END"` - the end of the range and the end of compareRange
* - `"END_TO_START"` - the end of the range and the start of compareRange
*
* @param {$.Range} compareRange The other range
* to compare against.
* @return {Number} a number indicating if the range
* boundary is before,
* after, or equal to compareRange
's
* boundary where:
*
* - -1 - the range boundary comes before the compareRange boundary
* - 0 - the boundaries are equal
* - 1 - the range boundary comes after the compareRange boundary
*/
fn.compare = range.compareBoundaryPoints ?
function(type, range){
return this.range.compareBoundaryPoints(this.window().Range[reverse( type )], range.range)
}:
function(type, range){
return this.range.compareEndPoints(convertType(type), range.range)
}
/**
* @function move
*
* `range.move([referenceRange])` moves the endpoints of a range relative to another range.
*
* // Move the current selection's end to the
* // end of the #highlight element
* $.Range.current().move('END_TO_END',
* $('#highlight').range() )
*
*
* @param {String} type a string indicating the ranges boundary point
* to move to which referenceRange boundary point where:
*
* - `"START_TO_START"` - the start of the range moves to the start of referenceRange
* - `"START\_TO\_END"` - the start of the range move to the end of referenceRange
* - `"END_TO_END"` - the end of the range moves to the end of referenceRange
* - `"END_TO_START"` - the end of the range moves to the start of referenceRange
*
* @param {jQuery.Range} referenceRange
* @return {jQuery.Range} the original range for chaining
*/
fn.move = range.setStart ?
function(type, range){
var rangesRange = range.range;
switch(type){
case "START_TO_END" :
this.range.setStart(rangesRange.endContainer, rangesRange.endOffset)
break;
case "START_TO_START" :
this.range.setStart(rangesRange.startContainer, rangesRange.startOffset)
break;
case "END_TO_END" :
this.range.setEnd(rangesRange.endContainer, rangesRange.endOffset)
break;
case "END_TO_START" :
this.range.setEnd(rangesRange.startContainer, rangesRange.startOffset)
break;
}
return this;
}:
function(type, range){
this.range.setEndPoint(convertType(type), range.range)
return this;
};
var cloneFunc = range.cloneRange ? "cloneRange" : "duplicate",
selectFunc = range.selectNodeContents ? "selectNodeContents" : "moveToElementText";
fn.
/**
* `range.clone()` clones the range and returns a new $.Range
* object:
*
* var range = new $.Range(document.getElementById('text'));
* var newRange = range.clone();
* range.start('+2');
* range.select();
*
* @return {jQuery.Range} returns the range as a $.Range.
*/
clone = function(){
return $.Range( this.range[cloneFunc]() );
};
fn.
/**
* @function
*
* `range.select([el])` selects an element with this range. If nothing
* is provided, makes the current range appear as if the user has selected it.
*
* This works with text nodes. For example with:
*
* This is a text
*
* $.Range can select `is a` like this:
*
* var range = new $.Range(document.getElementById('text'));
* range.start('+5');
* range.end('-5');
* range.select();
*
* @param {HTMLElement} [el] The element in which this range should be selected
* @return {jQuery.Range} the range for chaining.
*/
select = range.selectNodeContents ? function(el){
if(!el){
var selection = this.window().getSelection();
selection.removeAllRanges();
selection.addRange(this.range);
}else {
this.range.selectNodeContents(el);
}
return this;
} : function(el){
if(!el){
this.range.select()
} else if(el.nodeType === 3){
//select this node in the element ...
var parent = el.parentNode,
start = 0,
end;
iterate(parent.childNodes, function(txtNode){
if(txtNode === el){
end = start + txtNode.nodeValue.length;
return false;
} else {
start = start + txtNode.nodeValue.length
}
})
this.range.moveToElementText(parent);
this.range.moveEnd('character', end - this.range.text.length)
this.range.moveStart('character', start);
} else {
this.range.moveToElementText(el);
}
return this;
};
})();
// helpers -----------------
// iterates through a list of elements, calls cb on every text node
// if cb returns false, exits the iteration
var iterate = function(elems, cb){
var elem, start;
for (var i = 0; elems[i]; i++) {
elem = elems[i];
// Get the text from text nodes and CDATA nodes
if (elem.nodeType === 3 || elem.nodeType === 4) {
if (cb(elem) === false) {
return false;
}
// Traverse everything else, except comment nodes
}
else
if (elem.nodeType !== 8) {
if (iterate(elem.childNodes, cb) === false) {
return false;
}
}
}
},
isText = function(node){
return node.nodeType === 3 || node.nodeType === 4
},
iteratorMaker = function(toChildren, toNext){
return function( node, mustMoveRight ) {
// first try down
if(node[toChildren] && !mustMoveRight){
return isText(node[toChildren]) ?
node[toChildren] :
arguments.callee(node[toChildren])
} else if(node[toNext]) {
return isText(node[toNext]) ?
node[toNext] :
arguments.callee(node[toNext])
} else if(node.parentNode){
return arguments.callee(node.parentNode, true)
}
}
},
getNextTextNode = iteratorMaker("firstChild","nextSibling"),
getPrevTextNode = iteratorMaker("lastChild","previousSibling"),
callMove = function(container, offset, howMany){
if(isText(container)){
return move(container, offset+howMany)
} else {
return container.childNodes[offset] ?
move(container.childNodes[offset] , howMany) :
move(container.lastChild, howMany , true)
return
}
},
move = function(from, howMany){
var mover = howMany < 0 ?
getPrevTextNode : getNextTextNode;
howMany = Math.abs(howMany);
if(!isText(from)){
from = mover(from)
}
while(from && howMany >= from.nodeValue.length){
hasMany = howMany- from.nodeValue.length;
from = mover(from)
}
return {
node: from,
offset: mover === getNextTextNode ?
howMany :
from.nodeValue.length - howMany
}
},
supportWhitespace,
isWhitespace = function(el){
if(supportWhitespace == null){
supportWhitespace = 'isElementContentWhitespace' in el;
}
return (supportWhitespace? el.isElementContentWhitespace :
(el.nodeType === 3 && '' == el.data.trim()));
},
// if a point is within a rectangle
within = function(rect, point){
return rect.left <= point.clientX && rect.left + rect.width >= point.clientX &&
rect.top <= point.clientY &&
rect.top + rect.height >= point.clientY
},
// if a rectangle is within another rectangle
withinRect = function(outer, inner){
return within(outer, {
clientX: inner.left,
clientY: inner.top
}) && //top left
within(outer, {
clientX: inner.left + inner.width,
clientY: inner.top
}) && //top right
within(outer, {
clientX: inner.left,
clientY: inner.top + inner.height
}) && //bottom left
within(outer, {
clientX: inner.left + inner.width,
clientY: inner.top + inner.height
}) //bottom right
},
// gets the scroll offset from a window
scrollOffset = function( win){
var win = win ||window;
doc = win.document.documentElement, body = win.document.body;
return {
left: (doc && doc.scrollLeft || body && body.scrollLeft || 0) + (doc.clientLeft || 0),
top: (doc && doc.scrollTop || body && body.scrollTop || 0) + (doc.clientTop || 0)
};
};
support.moveToPoint = !!$.Range().range.moveToPoint
})(jQuery);
(function( $ ) {
var
// bind on the window window resizes to happen
win = $(window),
windowWidth = 0,
windowHeight = 0,
timer;
$(function() {
windowWidth = win.width();
windowHeight = win.height();
});
$.event.reverse('resize', {
handler : function(ev, data) {
var isWindow = this === window;
// if we are the window and a real resize has happened
// then we check if the dimensions actually changed
// if they did, we will wait a brief timeout and
// trigger resize on the window
// this is for IE, to prevent window resize 'infinate' loop issues
if ( isWindow && ev.originalEvent ) {
var width = win.width(),
height = win.height();
if ((width != windowWidth || height != windowHeight)) {
//update the new dimensions
windowWidth = width;
windowHeight = height;
clearTimeout(timer)
timer = setTimeout(function() {
win.trigger("resize");
}, 1);
}
return true;
}
}
});
})(jQuery);
(function($) {
var
//margin is inside border
weird = /button|select/i,
getBoxes = {},
checks = {
width: ["Left", "Right"],
height: ['Top', 'Bottom'],
oldOuterHeight: $.fn.outerHeight,
oldOuterWidth: $.fn.outerWidth,
oldInnerWidth: $.fn.innerWidth,
oldInnerHeight: $.fn.innerHeight
};
$.each({
/**
* @function jQuery.fn.outerWidth
* @parent jQuery.dimensions
*
* `jQuery.fn.outerWidth([value], [includeMargins])` lets you set
* the outer width of an object where:
*
* outerWidth = width + padding + border + (margin)
*
* And can be used like:
*
* $("#foo").outerWidth(100); //sets outer width
* $("#foo").outerWidth(100, true); // uses margins
* $("#foo").outerWidth(); //returns outer width
* $("#foo").outerWidth(true); //returns outer width + margins
*
* When setting the outerWidth, it adjusts the width of the element.
* If *includeMargin* is set to `true` margins will also be included.
* It is also possible to animate the outer width:
*
* $('#foo').animate({ outerWidth: 200 });
*
* @param {Number} [width] The width to set
* @param {Boolean} [includeMargin=false] Makes setting the outerWidth adjust
* for margins.
* @return {jQuery|Number} Returns the outer width or the jQuery wrapped elements
* if you are setting the outer width.
*/
width:
/**
* @function jQuery.fn.innerWidth
* @parent jQuery.dimensions
*
* `jQuery.fn.innerWidth([value])` lets you set the inner width of an element where
*
* innerWidth = width + padding
*
* Use it like:
*
* $("#foo").innerWidth(100); //sets inner width
* $("#foo").outerWidth(); // returns inner width
*
* Or in an animation like:
*
* $('#foo').animate({ innerWidth : 200 });
*
* Setting inner width adjusts the width of the element.
*
* @param {Number} [width] The inner width to set
* @return {jQuery|Number} Returns the inner width or the jQuery wrapped elements
* if you are setting the inner width.
*/
"Width",
/**
* @function jQuery.fn.outerHeight
* @parent jQuery.dimensions
*
* `jQuery.fn.outerHeight([value], [includeMargins])` lets
* you set the outer height of an object where:
*
* outerHeight = height + padding + border + (margin)
*
* And can be used like:
*
* $("#foo").outerHeight(100); //sets outer height
* $("#foo").outerHeight(100, true); // uses margins
* $("#foo").outerHeight(); //returns outer height
* $("#foo").outerHeight(true); //returns outer height + margins
*
* When setting the outerHeight, it adjusts the height of the element.
* If *includeMargin* is set to `true` margins will also be included.
* It is also possible to animate the outer heihgt:
*
* $('#foo').animate({ outerHeight : 200 });
*
* @param {Number} [height] The height to set
* @param {Boolean} [includeMargin=false] Makes setting the outerHeight adjust
* for margins.
* @return {jQuery|Number} Returns the outer height or the jQuery wrapped elements
* if you are setting the outer height.
*/
height:
/**
* @function jQuery.fn.innerHeight
* @parent jQuery.dimensions
*
* `jQuery.fn.innerHeight([value])` lets you set the inner height of an element where
*
* innerHeight = height + padding
*
* Use it like:
*
* $("#foo").innerHeight(100); //sets inner height
* $("#foo").outerHeight(); // returns inner height
*
* Or in an animation like:
*
* $('#foo').animate({ innerHeight : 200 });
*
* Setting inner height adjusts the height of the element.
*
* @param {Number} [height] The inner height to set
* @return {jQuery|Number} Returns the inner height or the jQuery wrapped elements
* if you are setting the inner height.
*/
// for each 'height' and 'width'
"Height" }, function(lower, Upper) {
//used to get the padding and border for an element in a given direction
getBoxes[lower] = function(el, boxes) {
var val = 0;
if (!weird.test(el.nodeName)) {
//make what to check for ....
var myChecks = [];
$.each(checks[lower], function() {
var direction = this;
$.each(boxes, function(name, val) {
if (val)
myChecks.push(name + direction+ (name == 'border' ? "Width" : "") );
})
})
$.each($.styles(el, myChecks), function(name, value) {
val += (parseFloat(value) || 0);
})
}
return val;
}
//getter / setter
$.fn["outer" + Upper] = function(v, margin) {
var first = this[0];
if (typeof v == 'number') {
// Setting the value
first && this[lower](v - getBoxes[lower](first, {padding: true, border: true, margin: margin}))
return this;
} else {
// Return the old value
return first ? checks["oldOuter" + Upper].call(this, v) : null;
}
}
$.fn["inner" + Upper] = function(v) {
var first = this[0];
if (typeof v == 'number') {
// Setting the value
first&& this[lower](v - getBoxes[lower](first, { padding: true }))
return this;
} else {
// Return the old value
return first ? checks["oldInner" + Upper].call(this, v) : null;
}
}
//provides animations
var animate = function(boxes){
// Return the animation function
return function(fx){
if (fx.state == 0) {
fx.start = $(fx.elem)[lower]();
fx.end = fx.end - getBoxes[lower](fx.elem,boxes);
}
fx.elem.style[lower] = (fx.pos * (fx.end - fx.start) + fx.start) + "px"
}
}
$.fx.step["outer" + Upper] = animate({padding: true, border: true})
$.fx.step["outer" + Upper+"Margin"] = animate({padding: true, border: true, margin: true})
$.fx.step["inner" + Upper] = animate({padding: true})
})
})(jQuery);
(function($){
/**
* @page jQuery.toJSON jQuery.toJSON
* @parent jquerymx.lang
*
* jQuery.toJSON( json-serializble )
*
* Converts the given argument into a JSON respresentation.
*
* If an object has a "toJSON" function, that will
* be used to get the representation.
* Non-integer/string keys are skipped in the
* object, as are keys that point to a function.
*
* json-serializble:
* The *thing* to be converted.
*/
$.toJSON = function(o, replacer, space, recurse)
{
if (typeof(JSON) == 'object' && JSON.stringify)
return JSON.stringify(o, replacer, space);
if (!recurse && $.isFunction(replacer))
o = replacer("", o);
if (typeof space == "number")
space = " ".substring(0, space);
space = (typeof space == "string") ? space.substring(0, 10) : "";
var type = typeof(o);
if (o === null)
return "null";
if (type == "undefined" || type == "function")
return undefined;
if (type == "number" || type == "boolean")
return o + "";
if (type == "string")
return $.quoteString(o);
if (type == 'object')
{
if (typeof o.toJSON == "function")
return $.toJSON( o.toJSON(), replacer, space, true );
if (o.constructor === Date)
{
var month = o.getUTCMonth() + 1;
if (month < 10) month = '0' + month;
var day = o.getUTCDate();
if (day < 10) day = '0' + day;
var year = o.getUTCFullYear();
var hours = o.getUTCHours();
if (hours < 10) hours = '0' + hours;
var minutes = o.getUTCMinutes();
if (minutes < 10) minutes = '0' + minutes;
var seconds = o.getUTCSeconds();
if (seconds < 10) seconds = '0' + seconds;
var milli = o.getUTCMilliseconds();
if (milli < 100) milli = '0' + milli;
if (milli < 10) milli = '0' + milli;
return '"' + year + '-' + month + '-' + day + 'T' +
hours + ':' + minutes + ':' + seconds +
'.' + milli + 'Z"';
}
var process = ($.isFunction(replacer)) ?
function (k, v) { return replacer(k, v); } :
function (k, v) { return v; },
nl = (space) ? "\n" : "",
sp = (space) ? " " : "";
if (o.constructor === Array)
{
var ret = [];
for (var i = 0; i < o.length; i++)
ret.push(( $.toJSON( process(i, o[i]), replacer, space, true ) || "null" ).replace(/^/gm, space));
return "[" + nl + ret.join("," + nl) + nl + "]";
}
var pairs = [], proplist;
if ($.isArray(replacer)) {
proplist = $.map(replacer, function (v) {
return (typeof v == "string" || typeof v == "number") ?
v + "" :
null;
});
}
for (var k in o) {
var name, val, type = typeof k;
if (proplist && $.inArray(k + "", proplist) == -1)
continue;
if (type == "number")
name = '"' + k + '"';
else if (type == "string")
name = $.quoteString(k);
else
continue; //skip non-string or number keys
val = $.toJSON( process(k, o[k]), replacer, space, true );
if (typeof val == "undefined")
continue; //skip pairs where the value is a function.
pairs.push((name + ":" + sp + val).replace(/^/gm, space));
}
return "{" + nl + pairs.join("," + nl) + nl + "}";
}
};
/**
* @function jQuery.evalJSON
* Evaluates a given piece of json source.
**/
$.evalJSON = function(src)
{
if (typeof(JSON) == 'object' && JSON.parse)
return JSON.parse(src);
return eval("(" + src + ")");
};
/**
* @function jQuery.secureEvalJSON
* Evals JSON in a way that is *more* secure.
**/
$.secureEvalJSON = function(src)
{
if (typeof(JSON) == 'object' && JSON.parse)
return JSON.parse(src);
var filtered = src;
filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
if (/^[\],:{}\s]*$/.test(filtered))
return eval("(" + src + ")");
else
throw new SyntaxError("Error parsing JSON, source is not valid.");
};
/**
* @function jQuery.quoteString
*
* Returns a string-repr of a string, escaping quotes intelligently.
* Mostly a support function for toJSON.
*
* Examples:
*
* jQuery.quoteString("apple") //-> "apple"
*
* jQuery.quoteString('"Where are we going?", she asked.')
* // -> "\"Where are we going?\", she asked."
**/
$.quoteString = function(string)
{
if (string.match(_escapeable))
{
return '"' + string.replace(_escapeable, function (a)
{
var c = _meta[a];
if (typeof c === 'string') return c;
c = a.charCodeAt();
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
}) + '"';
}
return '"' + string + '"';
};
var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
var _meta = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
};
})(jQuery);
(function($){
var isPhantom = /Phantom/.test(navigator.userAgent),
supportTouch = !isPhantom && "ontouchend" in document,
scrollEvent = "touchmove scroll",
// Use touch events or map it to mouse events
touchStartEvent = supportTouch ? "touchstart" : "mousedown",
touchStopEvent = supportTouch ? "touchend" : "mouseup",
touchMoveEvent = supportTouch ? "touchmove" : "mousemove",
data = function(event){
var d = event.originalEvent.touches ?
event.originalEvent.touches[ 0 ] :
event;
return {
time: (new Date).getTime(),
coords: [ d.pageX, d.pageY ],
origin: $( event.target )
};
};
/**
* @add jQuery.event.swipe
*/
var swipe = $.event.swipe = {
/**
* @attribute delay
* Delay is the upper limit of time the swipe motion can take in milliseconds. This defaults to 500.
*
* A user must perform the swipe motion in this much time.
*/
delay : 500,
/**
* @attribute max
* The maximum distance the pointer must travel in pixels. The default is 75 pixels.
*/
max : 75,
/**
* @attribute min
* The minimum distance the pointer must travel in pixels. The default is 30 pixels.
*/
min : 30
};
$.event.setupHelper( [
/**
* @hide
* @attribute swipe
*/
"swipe",
/**
* @hide
* @attribute swipeleft
*/
'swipeleft',
/**
* @hide
* @attribute swiperight
*/
'swiperight',
/**
* @hide
* @attribute swipeup
*/
'swipeup',
/**
* @hide
* @attribute swipedown
*/
'swipedown'], touchStartEvent, function(ev){
var
// update with data when the event was started
start = data(ev),
stop,
delegate = ev.delegateTarget || ev.currentTarget,
selector = ev.handleObj.selector,
entered = this;
function moveHandler(event){
if ( !start ) {
return;
}
// update stop with the data from the current event
stop = data(event);
// prevent scrolling
if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) {
event.preventDefault();
}
};
// Attach to the touch move events
$(document.documentElement).bind(touchMoveEvent, moveHandler)
.one(touchStopEvent, function(event){
$(this).unbind( touchMoveEvent, moveHandler);
// if start and stop contain data figure out if we have a swipe event
if ( start && stop ) {
// calculate the distance between start and stop data
var deltaX = Math.abs(start.coords[0] - stop.coords[0]),
deltaY = Math.abs(start.coords[1] - stop.coords[1]),
distance = Math.sqrt(deltaX*deltaX+deltaY*deltaY);
// check if the delay and distance are matched
if ( stop.time - start.time < swipe.delay && distance >= swipe.min ) {
var events = ['swipe'];
// check if we moved horizontally
if( deltaX >= swipe.min && deltaY < swipe.min) {
// based on the x coordinate check if we moved left or right
events.push( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" );
} else
// check if we moved vertically
if(deltaY >= swipe.min && deltaX < swipe.min){
// based on the y coordinate check if we moved up or down
events.push( start.coords[1] < stop.coords[1] ? "swipedown" : "swipeup" );
}
// trigger swipe events on this guy
$.each($.event.find(delegate, events, selector), function(){
this.call(entered, ev, {start : start, end: stop})
})
}
}
// reset start and stop
start = stop = undefined;
})
});
})(jQuery);
(function($){
var current,
rnamespaces = /\.(.*)$/,
returnFalse = function(){return false},
returnTrue = function(){return true};
$.Event.prototype.isPaused = returnFalse
/**
* @function jQuery.Event.prototype.pause
* @parent jQuery.event.pause
*
* `event.paused()` pauses an event (to be resumed later):
*
* $('.tab').on('show', function(ev) {
* ev.pause();
* // Resume the event after 1 second
* setTimeout(function() {
* ev.resume();
* }, 1000);
* });
*/
$.Event.prototype.pause = function(){
// stop the event from continuing temporarily
// keep the current state of the event ...
this.pausedState = {
isDefaultPrevented : this.isDefaultPrevented() ?
returnTrue : returnFalse,
isPropagationStopped : this.isPropagationStopped() ?
returnTrue : returnFalse
};
this.stopImmediatePropagation();
this.preventDefault();
this.isPaused = returnTrue;
};
/**
* @function jQuery.Event.prototype.resume
* @parent jQuery.event.pause
*
* `event.resume()` resumes a paused event:
*
* $('.tab').on('show', function(ev) {
* ev.pause();
* // Resume the event after 1 second
* setTimeout(function() {
* ev.resume();
* }, 1000);
* });
*/
$.Event.prototype.resume = function(){
// temporarily remove all event handlers of this type
var handleObj = this.handleObj,
currentTarget = this.currentTarget;
// temporarily overwrite special handle
var origType = jQuery.event.special[ handleObj.origType ],
origHandle = origType && origType.handle;
if(!origType){
jQuery.event.special[ handleObj.origType ] = {};
}
jQuery.event.special[ handleObj.origType ].handle = function(ev){
// remove this once we have passed the handleObj
if(ev.handleObj === handleObj && ev.currentTarget === currentTarget){
if(!origType){
delete jQuery.event.special[ handleObj.origType ];
} else {
jQuery.event.special[ handleObj.origType ].handle = origHandle;
}
}
}
delete this.pausedState;
// reset stuff
this.isPaused = this.isImmediatePropagationStopped = returnFalse;
if(!this.isPropagationStopped()){
// fire the event again, no events will get fired until
// same currentTarget / handler
$.event.trigger(this, [], this.target);
}
};
})(jQuery);
(function($){
var keymap = {},
reverseKeyMap = {},
currentBrowser = jQuery.uaMatch(navigator.userAgent).browser;
/**
* @hide
* @parent jQuery.Event.prototype.key
*
* Allows you to set alternate key maps or overwrite existing key codes.
* For example::
*
* $.event.key({"~" : 177});
*
* @param {Object} map A map of character - keycode pairs.
*/
$.event.key = function(browser, map){
if(browser === undefined) {
return keymap;
}
if(map === undefined) {
map = browser;
browser = currentBrowser;
}
// extend the keymap
if(!keymap[browser]) {
keymap[browser] = {};
}
$.extend(keymap[browser], map);
// and also update the reverse keymap
if(!reverseKeyMap[browser]) {
reverseKeyMap[browser] = {};
}
for(var name in map){
reverseKeyMap[browser][map[name]] = name;
}
};
$.event.key({
// backspace
'\b':'8',
// tab
'\t':'9',
// enter
'\r':'13',
// special
'shift':'16','ctrl':'17','alt':'18',
// others
'pause-break':'19',
'caps':'20',
'escape':'27',
'num-lock':'144',
'scroll-lock':'145',
'print' : '44',
// navigation
'page-up':'33','page-down':'34','end':'35','home':'36',
'left':'37','up':'38','right':'39','down':'40','insert':'45','delete':'46',
// normal characters
' ':'32',
'0':'48','1':'49','2':'50','3':'51','4':'52','5':'53','6':'54','7':'55','8':'56','9':'57',
'a':'65','b':'66','c':'67','d':'68','e':'69','f':'70','g':'71','h':'72','i':'73','j':'74','k':'75','l':'76','m':'77',
'n':'78','o':'79','p':'80','q':'81','r':'82','s':'83','t':'84','u':'85','v':'86','w':'87','x':'88','y':'89','z':'90',
// normal-characters, numpad
'num0':'96','num1':'97','num2':'98','num3':'99','num4':'100','num5':'101','num6':'102','num7':'103','num8':'104','num9':'105',
'*':'106','+':'107','-':'109','.':'110',
// normal-characters, others
'/':'111',
';':'186',
'=':'187',
',':'188',
'-':'189',
'.':'190',
'/':'191',
'`':'192',
'[':'219',
'\\':'220',
']':'221',
"'":'222',
// ignore these, you shouldn't use them
'left window key':'91','right window key':'92','select key':'93',
'f1':'112','f2':'113','f3':'114','f4':'115','f5':'116','f6':'117',
'f7':'118','f8':'119','f9':'120','f10':'121','f11':'122','f12':'123'
});
/**
* @parent jQuery.event.key
* @plugin jquery/event/key
* @function jQuery.Event.prototype.keyName
*
* Returns a string representation of the key pressed:
*
* $("input").on('keypress', function(ev){
* if(ev.keyName() == 'ctrl') {
* $(this).addClass('highlight');
* }
* });
*
* The key names mapped by default can be found in the [jQuery.event.key jQuery.event.key overview].
*
* @return {String} The string representation of of the key pressed.
*/
jQuery.Event.prototype.keyName = function(){
var event = this,
test = /\w/,
// It can be either keyCode or charCode.
// Look both cases up in the reverse key map and converted to a string
key_Key = reverseKeyMap[currentBrowser][(event.keyCode || event.which)+""],
char_Key = String.fromCharCode(event.keyCode || event.which),
key_Char = event.charCode && reverseKeyMap[currentBrowser][event.charCode+""],
char_Char = event.charCode && String.fromCharCode(event.charCode);
if( char_Char && test.test(char_Char) ) {
// string representation of event.charCode
return char_Char.toLowerCase()
}
if( key_Char && test.test(key_Char) ) {
// reverseKeyMap representation of event.charCode
return char_Char.toLowerCase()
}
if( char_Key && test.test(char_Key) ) {
// string representation of event.keyCode
return char_Key.toLowerCase()
}
if( key_Key && test.test(key_Key) ) {
// reverseKeyMap representation of event.keyCode
return key_Key.toLowerCase()
}
if (event.type == 'keypress'){
// keypress doesn't capture everything
return event.keyCode ? String.fromCharCode(event.keyCode) : String.fromCharCode(event.which)
}
if (!event.keyCode && event.which) {
// event.which
return String.fromCharCode(event.which)
}
// default
return reverseKeyMap[currentBrowser][event.keyCode+""]
}
})(jQuery);
(function($){
/**
* @class jQuery.Hover
* @plugin jquery/event/hover
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/hover/hover.js
* @parent jQuery.event.hover
*
* Creates a new hover. The constructor should not be called directly.
*
* An instance of `$.Hover` is passed as the second argument to each
* [jQuery.event.hover] event handler:
*
* $('#menu').on("hoverinit", function(ev, hover) {
* // Set the hover distance to 20px
* hover.distance(20);
* });
*/
$.Hover = function(){
this._delay = $.Hover.delay;
this._distance = $.Hover.distance;
this._leave = $.Hover.leave
};
/**
* @Static
*/
$.extend($.Hover,{
/**
* @attribute delay
*
* `$.Hover.delay` is the delay (in milliseconds) after which the hover is
* activated by default.
*
* Set this value as a global default. The default is 100ms.
*
* // Set the global hover delay to 1 second
* $.Hover.delay = 1000;
*/
delay: 100,
/**
* @attribute distance
*
* `$.Hover.distance` is the maximum distance (in pixels) that the mouse is allowed to
* travel within the time of [jQuery.Hover.delay] in order to activate a hover.
*
* Set this value as a global default. The default is 10px.
*
* // Set the global hover distance to 1 pixel
* $.Hover.distance = 1;
*/
distance: 10,
leave : 0
})
/**
* @Prototype
*/
$.extend($.Hover.prototype,{
/**
* `hover.delay(time)` sets the delay (in ms) for this hover.
* This method should only be used in [jQuery.event.hover.hoverinit hoverinit]:
*
* $('.hoverable').on('hoverinit', function(ev, hover) {
* // Set the delay to 500ms
* hover.delay(500);
* });
*
* @param {Number} delay the number of milliseconds used to determine a hover
* @return {$.Hover} The hover object
*/
delay: function( delay ) {
this._delay = delay;
return this;
},
/**
* `hover.distance(px) sets the maximum distance (in pixels) the mouse is allowed to travel in order to activate
* the hover. This method should only be used in [jQuery.event.hover.hoverinit hoverinit]:
*
* $('.hoverable').on('hoverinit', function(ev, hover) {
* // Set the distance to 1px
* hover.distance(1);
* });
*
* @param {Number} distance the max distance in pixels a mouse can move to be considered a hover
* @return {$.Hover} The hover object
*/
distance: function( distance ) {
this._distance = distance;
return this;
},
/**
* `hover.leave(delay)` sets a delay for how long the hover should stay active after the mouse left.
* This method should only be used in [jQuery.event.hover.hoverinit hoverinit]:
*
* $('.hoverable').on('hoverinit', function(ev, hover) {
* // Stay active for another second after the mouse left
* hover.leave(1000);
* });
*
* @param {Number} delay the number of milliseconds the hover should stay active after the mouse leaves
* @return {$.Hover} The hover object
*/
leave : function(leave){
this._leave = leave;
return this;
}
})
var event = $.event,
handle = event.handle,
onmouseenter = function(ev){
// now start checking mousemoves to update location
var delegate = ev.delegateTarget || ev.currentTarget;
var selector = ev.handleObj.selector;
// prevents another mouseenter until current has run its course
if($.data(delegate,"_hover"+selector)) {
return;
}
$.data(delegate,"_hover"+selector, true)
var loc = {
pageX : ev.pageX,
pageY : ev.pageY
},
// The current distance
dist = 0,
// Timer that checks for the distance travelled
timer,
enteredEl = this,
// If we are hovered
hovered = false,
// The previous event
lastEv = ev,
// The $.Hover instance passed to events
hover = new $.Hover(),
// timer if hover.leave has been called
leaveTimer,
// Callback for triggering hoverleave
callHoverLeave = function(){
$.each(event.find(delegate, ["hoverleave"], selector), function(){
this.call(enteredEl, ev, hover)
})
cleanUp();
},
mousemove = function(ev){
clearTimeout(leaveTimer);
// Update the distance and location
dist += Math.pow( ev.pageX-loc.pageX, 2 ) + Math.pow( ev.pageY-loc.pageY, 2 );
loc = {
pageX : ev.pageX,
pageY : ev.pageY
}
lastEv = ev
},
mouseleave = function(ev){
clearTimeout(timer);
if(hovered) {
// go right away
if(hover._leave === 0){
callHoverLeave();
}else{
clearTimeout(leaveTimer);
// leave the hover after the time set in hover.leave(time)
leaveTimer = setTimeout(function(){
callHoverLeave();
}, hover._leave)
}
}else{
cleanUp();
}
},
cleanUp = function(){
// Unbind all events and data
$(enteredEl).unbind("mouseleave",mouseleave)
$(enteredEl).unbind("mousemove",mousemove);
$.removeData(delegate,"_hover"+selector)
};
// Bind the mousemove event
$(enteredEl).bind("mousemove",mousemove).bind("mouseleave", mouseleave);
// call hoverinit for each element with the hover instance
$.each(event.find(delegate, ["hoverinit"], selector), function(){
this.call(enteredEl, ev, hover)
})
timer = setTimeout(function(){
// check that we aren't moving around
if(dist < hover._distance && $(enteredEl).queue().length == 0){
$.each(event.find(delegate, ["hoverenter"], selector), function(){
this.call(enteredEl, lastEv, hover)
})
hovered = true;
return;
}else{
// Reset distance and timer
dist = 0;
timer = setTimeout(arguments.callee, hover._delay)
}
}, hover._delay)
};
/**
* @add jQuery.event.special
*/
// Attach events
event.setupHelper( [
/**
* @attribute hoverinit
* @parent jQuery.event.hover
*
* `hoverinit` is called when a hover is about to start (on `mouseenter`). Listen for `hoverinit` events to configure
* [jQuery.Hover::delay delay] and [jQuery.Hover::distance distance]
* for this specific event:
*
* $(".option").on("hoverinit", function(ev, hover){
* //set the distance to 10px
* hover.distance(10);
* //set the delay to 200ms
* hover.delay(10);
* // End the hover one second after the mouse leaves
* hover.leave(1000);
* })
*/
"hoverinit",
/**
* @attribute hoverenter
* @parent jQuery.event.hover
*
* `hoverenter` events are called when the mouses less than [jQuery.Hover.prototype.distance] pixels in
* [jQuery.Hover.prototype.delay delay] milliseconds.
*
* $(".option").on("hoverenter", function(ev, hover){
* $(this).addClass("hovering");
* })
*/
"hoverenter",
/**
* @attribute hoverleave
* @parent jQuery.event.hover
*
* `hoverleave` is called when the mouse leaves an element that has been hovered.
*
* $(".option").on("hoverleave", function(ev, hover){
* $(this).removeClass("hovering");
* })
*/
"hoverleave",
/**
* @attribute hovermove
* @parent jQuery.event.hover
*
* `hovermove` is called when a `mousemove` occurs on an element that has been hovered.
*
* $(".option").on("hovermove", function(ev, hover){
* // not sure why you would want to listen for this
* // but we provide it just in case
* })
*/
"hovermove"], "mouseenter", onmouseenter )
})(jQuery);
(function () {
// http://bitovi.com/blog/2012/04/faster-jquery-event-fix.html
// https://gist.github.com/2377196
// IE 8 has Object.defineProperty but it only defines DOM Nodes. According to
// http://kangax.github.com/es5-compat-table/#define-property-ie-note
// All browser that have Object.defineProperties also support Object.defineProperty properly
if(Object.defineProperties) {
var
// Use defineProperty on an object to set the value and return it
set = function (obj, prop, val) {
if(val !== undefined) {
Object.defineProperty(obj, prop, {
value : val
});
}
return val;
},
// special converters
special = {
pageX : function (original) {
var eventDoc = this.target.ownerDocument || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
return original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
},
pageY : function (original) {
var eventDoc = this.target.ownerDocument || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
return original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
},
relatedTarget : function (original) {
if(!original) {
return;
}
return original.fromElement === this.target ? original.toElement : original.fromElement;
},
metaKey : function (originalEvent) {
return originalEvent.ctrlKey;
},
which : function (original) {
return original.charCode != null ? original.charCode : original.keyCode;
}
};
// Get all properties that should be mapped
jQuery.each(jQuery.event.keyHooks.props.concat(jQuery.event.mouseHooks.props).concat(jQuery.event.props), function (i, prop) {
if (prop !== "target") {
(function () {
Object.defineProperty(jQuery.Event.prototype, prop, {
get : function () {
// get the original value, undefined when there is no original event
var originalValue = this.originalEvent && this.originalEvent[prop];
// overwrite getter lookup
return this['_' + prop] !== undefined ? this['_' + prop] : set(this, prop,
// if we have a special function and no value
special[prop] && originalValue === undefined ?
// call the special function
special[prop].call(this, this.originalEvent) :
// use the original value
originalValue)
},
set : function (newValue) {
// Set the property with underscore prefix
this['_' + prop] = newValue;
}
});
})();
}
});
jQuery.event.fix = function (event) {
if (event[ jQuery.expando ]) {
return event;
}
// Create a jQuery event with at minimum a target and type set
var originalEvent = event,
event = jQuery.Event(originalEvent);
event.target = originalEvent.target;
// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
if (!event.target) {
event.target = originalEvent.srcElement || document;
}
// Target should not be a text node (#504, Safari)
if (event.target.nodeType === 3) {
event.target = event.target.parentNode;
}
return event;
}
}
})(jQuery);
(function( $ ) {
var round = function( x, m ) {
return Math.round(x / m) * m;
}
$.Drag.prototype.
/**
* @function step
* @plugin jquery/event/drag/step
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/drag/step/step.js
* makes the drag move in steps of amount pixels.
*
* drag.step({x: 5}, $('foo'), "xy")
*
* ## Demo
*
* @demo jquery/event/drag/step/step.html
*
* @param {number|Object} amount make the drag move the amount in pixels from the top-left of container.
*
* If the amount is a `number`, the drag will move step-wise that number pixels in both
* dimensions. If it's an object like `{x: 20, y: 10}` the drag will move in steps 20px from
* left to right and 10px up and down.
*
* @param {jQuery} [container] the container to move in reference to. If not provided, the document is used.
* @param {String} [center] Indicates how to position the drag element in relationship to the container.
*
* - If nothing is provided, places the top left corner of the drag element at
* 'amount' intervals from the top left corner of the container.
* - If 'x' is provided, it centers the element horizontally on the top-left corner.
* - If 'y' is provided, it centers the element vertically on the top-left corner of the container.
* - If 'xy' is provided, it centers the element on the top-left corner of the container.
*
* @return {jQuery.Drag} the drag object for chaining.
*/
step = function( amount, container, center ) {
//on draws ... make sure this happens
if ( typeof amount == 'number' ) {
amount = {
x: amount,
y: amount
}
}
container = container || $(document.body);
this._step = amount;
var styles = container.styles("borderTopWidth", "paddingTop", "borderLeftWidth", "paddingLeft");
var top = parseInt(styles.borderTopWidth) + parseInt(styles.paddingTop),
left = parseInt(styles.borderLeftWidth) + parseInt(styles.paddingLeft);
this._step.offset = container.offsetv().plus(left, top);
this._step.center = center;
return this;
};
var oldPosition = $.Drag.prototype.position;
$.Drag.prototype.position = function( offsetPositionv ) {
//adjust required_css_position accordingly
if ( this._step ) {
var step = this._step,
center = step.center && step.center.toLowerCase(),
movingSize = this.movingElement.dimensionsv('outer'),
lot = step.offset.top()- (center && center != 'x' ? movingSize.height() / 2 : 0),
lof = step.offset.left() - (center && center != 'y' ? movingSize.width() / 2 : 0);
if ( this._step.x ) {
offsetPositionv.left(Math.round(lof + round(offsetPositionv.left() - lof, this._step.x)))
}
if ( this._step.y ) {
offsetPositionv.top(Math.round(lot + round(offsetPositionv.top() - lot, this._step.y)))
}
}
oldPosition.call(this, offsetPositionv)
}
})(jQuery);
(function($){ //needs drop to determine if respondable
/**
* @add jQuery.Drag.prototype
*/
$.Drag.prototype.
/**
* @plugin jquery/event/drag/scroll
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/drag/scroll/scroll.js
*
* `drag.scrolls(elements, [options])` scroll elements with
* a scroll bar as the drag moves to borders.
*
* The following sets up the drag motions to scroll `#todos` and the window. Scrolling will
* start 50px away from a boundary and the speed will increase to 50px of scroll every 15ms.
*
* $('#todos').on(".todo","draginit", function(ev, drag){
* drag.scrolls($('#todos').add(window), {
* distance : 50,
* delta : function(diff) { return (50 - diff) / 2},
* direction : "y"
* })
* })
*
* @param {jQuery} elements an array of elements to scroll. The window can be in this array.
* @param {Object} [options] changes the default settings.
*
* - `distance` {number} 30 - how many pixels away from a boundry where we start scrolling
* - `delta(diff)` {Function} - returns how far we should scroll. It is passed how many pixels the cursor is
* from the boundry.
* - `direction` {String} - direction scrolling should happen. "xy" is the default.
*/
scrolls = function(elements, options){
var elements = $(elements);
for(var i = 0 ; i < elements.length; i++){
this.constructor.responder._elements.push( elements.eq(i).data("_dropData", new $.Scrollable(elements[i], options) )[0] )
}
},
$.Scrollable = function(element, options){
this.element = jQuery(element);
this.options = $.extend({
// when we should start scrolling
distance : 30,
// how far we should move
delta : function(diff, distance){
return (distance - diff) / 2;
},
direction: "xy"
}, options);
this.x = this.options.direction.indexOf("x") != -1;
this.y = this.options.direction.indexOf("y") != -1;
}
$.extend($.Scrollable.prototype,{
init: function( element ) {
this.element = jQuery(element);
},
callHandlers: function( method, el, ev, drag ) {
this[method](el || this.element[0], ev, this, drag)
},
dropover: function() {
},
dropon: function() {
this.clear_timeout();
},
dropout: function() {
this.clear_timeout();
},
dropinit: function() {
},
dropend: function() {},
clear_timeout: function() {
if(this.interval){
clearTimeout(this.interval)
this.interval = null;
}
},
distance: function( diff ) {
return (30 - diff) / 2;
},
dropmove: function( el, ev, drop, drag ) {
//if we were about to call a move, clear it.
this.clear_timeout();
//position of the mouse
var mouse = ev.vector(),
//get the object we are going to get the boundries of
location_object = $(el == document.documentElement ? window : el),
//get the dimension and location of that object
dimensions = location_object.dimensionsv('outer'),
position = location_object.offsetv(),
//how close our mouse is to the boundries
bottom = position.y()+dimensions.y() - mouse.y(),
top = mouse.y() - position.y(),
right = position.x()+dimensions.x() - mouse.x(),
left = mouse.x() - position.x(),
//how far we should scroll
dx =0, dy =0,
distance = this.options.distance;
//check if we should scroll
if(bottom < distance && this.y)
dy = this.options.delta(bottom,distance);
else if(top < distance && this.y)
dy = -this.options.delta(top,distance)
if(right < distance && this.options && this.x)
dx = this.options.delta(right,distance);
else if(left < distance && this.x)
dx = -this.options.delta(left,distance);
//if we should scroll
if(dx || dy){
//set a timeout that will create a mousemove on that object
var self = this;
this.interval = setTimeout( function(){
self.move($(el), drag.movingElement, dx, dy, ev, ev.clientX, ev.clientY, ev.screenX, ev.screenY)
},15)
}
},
/**
* Scrolls an element then calls mouse a mousemove in the same location.
* @hide
*/
move: function( scroll_element, drag_element, dx, dy, ev/*, x,y,sx, sy*/ ) {
scroll_element.scrollTop( scroll_element.scrollTop() + dy);
scroll_element.scrollLeft(scroll_element.scrollLeft() + dx);
drag_element.trigger(
$.event.fix({type: "mousemove",
clientX: ev.clientX,
clientY: ev.clientY,
screenX: ev.screenX,
screenY: ev.screenY,
pageX: ev.pageX,
pageY: ev.pageY}))
//drag_element.synthetic('mousemove',{clientX: x, clientY: y, screenX: sx, screenY: sy})
}
})
})(jQuery);
(function( $ ) {
$.Drag.prototype
/**
* @function limit
* @plugin jquery/event/drag/limit
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/event/event/drag/limit/limit.js
* `drag.limit(container, [center])` limits a drag to a containing element.
*
* $("#todos").on(".todo","draginit", function( ev, drag ) {
* drag.limit($("#todos").parent())
* })
*
* @param {jQuery} container the jQuery-wrapped container element you do not want the drag element to escape.
* @param {String} [center] can set the limit to the center of the object. Can be
* 'x', 'y' or 'both'. By default it will keep the outer edges of the moving element within the
* container element. If you provide x, it will keep the horizontal center of the moving element
* within the container element. If you provide y, it will keep the vertical center of the moving
* element within the container element. If you provide both, it will keep the center of the
* moving element within the containing element.
* @return {drag} returns the drag for chaining.
*/
.limit = function( container, center ) {
//on draws ... make sure this happens
var styles = container.styles('borderTopWidth', 'paddingTop', 'borderLeftWidth', 'paddingLeft'),
paddingBorder = new $.Vector(
parseInt(styles.borderLeftWidth, 10) + parseInt(styles.paddingLeft, 10) || 0, parseInt(styles.borderTopWidth, 10) + parseInt(styles.paddingTop, 10) || 0);
this._limit = {
offset: container.offsetv().plus(paddingBorder),
size: container.dimensionsv(),
center : center === true ? 'both' : center
};
return this;
};
var oldPosition = $.Drag.prototype.position;
$.Drag.prototype.position = function( offsetPositionv ) {
//adjust required_css_position accordingly
if ( this._limit ) {
var limit = this._limit,
center = limit.center && limit.center.toLowerCase(),
movingSize = this.movingElement.dimensionsv('outer'),
halfHeight = center && center != 'x' ? movingSize.height() / 2 : 0,
halfWidth = center && center != 'y' ? movingSize.width() / 2 : 0,
lot = limit.offset.top(),
lof = limit.offset.left(),
height = limit.size.height(),
width = limit.size.width();
//check if we are out of bounds ...
//above
if ( offsetPositionv.top()+halfHeight < lot ) {
offsetPositionv.top(lot - halfHeight);
}
//below
if ( offsetPositionv.top() + movingSize.height() - halfHeight > lot + height ) {
offsetPositionv.top(lot + height - movingSize.height() + halfHeight);
}
//left
if ( offsetPositionv.left()+halfWidth < lof ) {
offsetPositionv.left(lof - halfWidth);
}
//right
if ( offsetPositionv.left() + movingSize.width() -halfWidth > lof + width ) {
offsetPositionv.left(lof + width - movingSize.left()+halfWidth);
}
}
oldPosition.call(this, offsetPositionv);
};
})(jQuery);
(function( $ ) {
/**
* @attribute destroyed
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/dom/destroyed/destroyed.js
* @test jquery/event/destroyed/qunit.html
*/
// Store the old jQuery.cleanData
var oldClean = jQuery.cleanData;
// Overwrites cleanData which is called by jQuery on manipulation methods
$.cleanData = function( elems ) {
for ( var i = 0, elem;
(elem = elems[i]) !== undefined; i++ ) {
// Trigger the destroyed event
$(elem).triggerHandler("destroyed");
}
// Call the old jQuery.cleanData
oldClean(elems);
};
})(jQuery);
(function($){
var getWindow = function( element ) {
return element ? element.ownerDocument.defaultView || element.ownerDocument.parentWindow : window
},
// A helper that uses range to abstract out getting the current start and endPos.
getElementsSelection = function(el, win){
// get a copy of the current range and a range that spans the element
var current = $.Range.current(el).clone(),
entireElement = $.Range(el).select(el);
// if there is no overlap, there is nothing selected
if(!current.overlaps(entireElement)){
return null;
}
// if the current range starts before our element
if(current.compare("START_TO_START", entireElement) < 1){
// the selection within the element begins at 0
startPos = 0;
// move the current range to start at our element
current.move("START_TO_START",entireElement);
}else{
// Make a copy of the element's range.
// Move it's end to the start of the selected range
// The length of the copy is the start of the selected
// range.
fromElementToCurrent =entireElement.clone();
fromElementToCurrent.move("END_TO_START", current);
startPos = fromElementToCurrent.toString().length
}
// If the current range ends after our element
if(current.compare("END_TO_END", entireElement) >= 0){
// the end position is the last character
endPos = entireElement.toString().length
}else{
// otherwise, it's the start position plus the current range
// TODO: this doesn't seem like it works if current
// extends to the left of the element.
endPos = startPos+current.toString().length
}
return {
start: startPos,
end : endPos,
width : endPos - startPos
};
},
// Text selection works differently for selection in an input vs
// normal html elements like divs, spans, and ps.
// This function branches between the various methods of getting the selection.
getSelection = function(el){
var win = getWindow(el);
// `selectionStart` means this is an input element in a standards browser.
if (el.selectionStart !== undefined) {
if(document.activeElement
&& document.activeElement != el
&& el.selectionStart == el.selectionEnd
&& el.selectionStart == 0){
return {start: el.value.length, end: el.value.length, width: 0};
}
return {start: el.selectionStart, end: el.selectionEnd, width: el.selectionEnd - el.selectionStart};
}
// getSelection means a 'normal' element in a standards browser.
else if(win.getSelection){
return getElementsSelection(el, win)
} else{
// IE will freak out, where there is no way to detect it, so we provide a callback if it does.
try {
// The following typically works for input elements in IE:
if (el.nodeName.toLowerCase() == 'input') {
var real = getWindow(el).document.selection.createRange(),
r = el.createTextRange();
r.setEndPoint("EndToStart", real);
var start = r.text.length
return {
start: start,
end: start + real.text.length,
width: real.text.length
}
}
// This works on textareas and other elements
else {
var res = getElementsSelection(el,win)
if(!res){
return res;
}
// we have to clean up for ie's textareas which don't count for
// newlines correctly
var current = $.Range.current().clone(),
r2 = current.clone().collapse().range,
r3 = current.clone().collapse(false).range;
r2.moveStart('character', -1)
r3.moveStart('character', -1)
// if we aren't at the start, but previous is empty, we are at start of newline
if (res.startPos != 0 && r2.text == "") {
res.startPos += 2;
}
// do a similar thing for the end of the textarea
if (res.endPos != 0 && r3.text == "") {
res.endPos += 2;
}
return res
}
}catch(e){
return {start: el.value.length, end: el.value.length, width: 0};
}
}
},
// Selects text within an element. Depending if it's a form element or
// not, or a standards based browser or not, we do different things.
select = function( el, start, end ) {
var win = getWindow(el);
// IE behaves bad even if it sorta supports
// getSelection so we have to try the IE methods first. barf.
if(el.setSelectionRange){
if(end === undefined){
el.focus();
el.setSelectionRange(start, start);
} else {
el.select();
el.selectionStart = start;
el.selectionEnd = end;
}
} else if (el.createTextRange) {
var r = el.createTextRange();
r.moveStart('character', start);
end = end || start;
r.moveEnd('character', end - el.value.length);
r.select();
} else if(win.getSelection){
var doc = win.document,
sel = win.getSelection(),
range = doc.createRange(),
ranges = [start, end !== undefined ? end : start];
getCharElement([el],ranges);
range.setStart(ranges[0].el, ranges[0].count);
range.setEnd(ranges[1].el, ranges[1].count);
// removeAllRanges is necessary for webkit
sel.removeAllRanges();
sel.addRange(range);
} else if(win.document.body.createTextRange){ //IE's weirdness
var range = document.body.createTextRange();
range.moveToElementText(el);
range.collapse()
range.moveStart('character', start)
range.moveEnd('character', end !== undefined ? end : start)
range.select();
}
},
// If one of the range values is within start and len, replace the range
// value with the element and its offset.
replaceWithLess = function(start, len, range, el){
if(typeof range[0] === 'number' && range[0] < len){
range[0] = {
el: el,
count: range[0] - start
};
}
if(typeof range[1] === 'number' && range[1] <= len){
range[1] = {
el: el,
count: range[1] - start
};;
}
},
getCharElement = function( elems , range, len ) {
var elem,
start;
len = len || 0;
for ( var i = 0; elems[i]; i++ ) {
elem = elems[i];
// Get the text from text nodes and CDATA nodes
if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
start = len
len += elem.nodeValue.length;
//check if len is now greater than what's in counts
replaceWithLess(start, len, range, elem )
// Traverse everything else, except comment nodes
} else if ( elem.nodeType !== 8 ) {
len = getCharElement( elem.childNodes, range, len );
}
}
return len;
};
/**
* @parent jQuery.selection
* @function jQuery.fn.selection
*
* Set or retrieve the currently selected text range. It works on all elements:
*
* $('#text').selection(8, 12)
* $('#text').selection() // -> { start : 8, end : 12, width: 4 }
*
* @param {Number} [start] Start position of the selection range
* @param {Number} [end] End position of the selection range
* @return {Object|jQuery} Returns either the jQuery object when setting the selection or
* an object containing
*
* - __start__ - The number of characters from the start of the element to the start of the selection.
* - __end__ - The number of characters from the start of the element to the end of the selection.
* - __width__ - The width of the selection range.
*
* when no arguments are passed.
*/
$.fn.selection = function(start, end){
if(start !== undefined){
return this.each(function(){
select(this, start, end)
})
}else{
return getSelection(this[0])
}
};
// for testing
$.fn.selection.getCharElement = getCharElement;
})(jQuery);
(function( $ ) {
var
// use to parse bracket notation like my[name][attribute]
keyBreaker = /[^\[\]]+/g,
// converts values that look like numbers and booleans and removes empty strings
convertValue = function( value ) {
if ( $.isNumeric( value )) {
return parseFloat( value );
} else if ( value === 'true') {
return true;
} else if ( value === 'false' ) {
return false;
} else if ( value === '' ) {
return undefined;
}
return value;
},
// Access nested data
nestData = function( elem, type, data, parts, value, seen, fullName ) {
var name = parts.shift();
// Keep track of the dot separated fullname. Used to uniquely track seen values
// and if they should be converted to an array or not
fullName = fullName ? fullName + '.' + name : name;
if (parts.length ) {
if ( ! data[ name ] ) {
data[ name ] = {};
}
// Recursive call
nestData( elem, type, data[ name ], parts, value, seen, fullName);
} else {
// Handle same name case, as well as "last checkbox checked"
// case
if ( fullName in seen && type != "radio" && ! $.isArray( data[ name ] )) {
if ( name in data ) {
data[ name ] = [ data[name] ];
} else {
data[ name ] = [];
}
} else {
seen[ fullName ] = true;
}
// Finally, assign data
if ( ( type == "radio" || type == "checkbox" ) && ! elem.is(":checked") ) {
return
}
if ( ! data[ name ] ) {
data[ name ] = value;
} else {
data[ name ].push( value );
}
}
};
/**
* @function jQuery.fn.formParams
* @parent jQuery.formParams
* @plugin jquery/dom/form_params
* @test jquery/dom/form_params/qunit.html
*
* Returns a JavaScript object for values in a form.
* It creates nested objects by using bracket notation in the form element name.
*
* @param {Object} [params] If an object is passed, the form will be repopulated
* with the values of the object based on the name of the inputs within
* the form
* @param {Boolean} [convert=false] True if strings that look like numbers
* and booleans should be converted and if empty string should not be added
* to the result.
* @return {Object} An object of name-value pairs.
*/
$.fn.extend({
formParams: function( params ) {
var convert;
// Quick way to determine if something is a boolean
if ( !! params === params ) {
convert = params;
params = null;
}
if ( params ) {
return this.setParams( params );
} else {
return this.getParams( convert );
}
},
setParams: function( params ) {
// Find all the inputs
this.find("[name]").each(function() {
var value = params[ $(this).attr("name") ],
$this;
// Don't do all this work if there's no value
if ( value !== undefined ) {
$this = $(this);
// Nested these if statements for performance
if ( $this.is(":radio") ) {
if ( $this.val() == value ) {
$this.attr("checked", true);
}
} else if ( $this.is(":checkbox") ) {
// Convert single value to an array to reduce
// complexity
value = $.isArray( value ) ? value : [value];
if ( $.inArray( $this.val(), value ) > -1) {
$this.attr("checked", true);
}
} else {
$this.val( value );
}
}
});
},
getParams: function( convert ) {
var data = {},
// This is used to keep track of the checkbox names that we've
// already seen, so we know that we should return an array if
// we see it multiple times. Fixes last checkbox checked bug.
seen = {},
current;
this.find("[name]:not(:disabled)").each(function() {
var $this = $(this),
type = $this.attr("type"),
name = $this.attr("name"),
value = $this.val(),
parts;
// Don't accumulate submit buttons and nameless elements
if ( type == "submit" || ! name ) {
return;
}
// Figure out name parts
parts = name.match( keyBreaker );
if ( ! parts.length ) {
parts = [name];
}
// Convert the value
if ( convert ) {
value = convertValue( value );
}
// Assign data recursively
nestData( $this, type, data, parts, value, seen );
});
return data;
}
});
})(jQuery);
(function( $ ) {
//evil things we should ignore
var matches = /script|td/,
// if we are trying to fill the page
isThePage = function( el ) {
return el === document || el === document.documentElement || el === window || el === document.body
},
//if something lets margins bleed through
bleeder = function( el ) {
if ( el[0] == window ) {
return false;
}
var styles = el.styles('borderBottomWidth', 'paddingBottom')
return !parseInt(styles.borderBottomWidth) && !parseInt(styles.paddingBottom)
},
//gets the bottom of this element
bottom = function( el, offset ) {
//where offsetTop starts
return el.outerHeight() + offset(el);
}
pageOffset = function( el ) {
return el.offset().top
},
offsetTop = function( el ) {
return el[0].offsetTop;
},
inFloat = function( el, parent ) {
while ( el && el != parent ) {
var flt = $(el).css('float')
if ( flt == 'left' || flt == 'right' ) {
return flt;
}
el = el.parentNode
}
},
/**
* @function jQuery.fn.fills
* @parent jQuery.fills
* @test jquery/dom/fills/funcunit.html
* @plugin jquery/dom/fills
*
* Fills a parent element's height with the current element.
* This is extremely useful for complex layout, especially when you want to account for line-wrapping.
*
* ## Basic Example
*
* If you have the following html:
*
*
* I am a long heading.
* I'm a child.
*
*
* The follow makes `#child` fill up `#box`:
*
* $('#child').can_ui_layout_fill("#box")
*
* ## Limitations
*
* Fill currently does not well with:
*
* - Bleeding margins - Where margins leak through parent elements
* because the parent elements do not have a padding or border.
*
* - Tables - You shouldn't be using tables to do layout anyway.
*
* - Floated Elements - the child element has `float: left` or `float: right`
*
*
* @param {HTMLElement|selector|Object} [parent] the parent element
* to fill, defaults to the element's parent.
*
* The following fills the parent to `#child`:
*
* $('#child').fills()
*
* A selector can also be pased. This selector is passed to jQuery's
* closet method. The following matches the first `#parent` element that
* is a parentNode of `#child`:
*
* $('#child').fills("#parent")
*
* An element or window can also be passed. The following will make
* `#child` big enough so the entire window is filled:
*
* $('#child').fills(window)
*
* If you pass an object, the following options are available:
*
* - __parent__ - The parent element selector or jQuery object
* - __className__ - A class name to add to the element that fills
* - __all__ - Reset the parents height when resizing
*
* @return {jQuery} the original jQuery collection for chaining.
*/
filler = $.fn.fills = function( parent ) {
var options = parent;
options || (options = {});
if(typeof options == 'string'){
options = this.closest(options)
}
if ( options.jquery || options.nodeName ) {
options = {parent: options };
}
// Set the parent
options.parent || (options.parent = $(this).parent());
options.parent = $(options.parent)
// setup stuff on every element
if(options.className) {
this.addClass(options.className)
}
var thePage = isThePage(options.parent[0]);
if ( thePage ) {
options.parent = $(window)
}
this.each(function(){
var evData = {
filler: $(this),
inFloat: inFloat(this, thePage ? document.body : options.parent[0]),
options: options
},
cb = function() {
filler.parentResize.apply(this, arguments)
}
// Attach to the `resize` event
$(options.parent).bind('resize', evData, cb);
$(this).bind('destroyed', evData, function( ev ) {
if(options.className) {
$(ev.target).removeClass(options.className)
}
$(options.parent).unbind('resize', cb)
});
});
// resize to get things going
var func = function() {
options.parent.resize();
}
if ( $.isReady ) {
func();
} else {
$(func)
}
return this;
};
$.extend(filler, {
parentResize : function( ev ) {
if (ev.data.filler.is(':hidden')) {
return;
}
var parent = $(this),
isWindow = this == window,
container = (isWindow ? $(document.body) : parent),
//if the parent bleeds margins, we don't care what the last element's margin is
isBleeder = bleeder(parent),
children = container.children().filter(function() {
if ( matches.test(this.nodeName.toLowerCase()) ) {
return false;
}
var get = $.styles(this, ['position', 'display']);
return get.position !== "absolute" && get.position !== "fixed"
&& get.display !== "none" && !jQuery.expr.filters.hidden(this)
}),
last = children.eq(-1),
first,
parentHeight = parent.height() - (isWindow ? parseInt(container.css('marginBottom'), 10) || 0 : 0),
currentSize;
var div = ''
if ( isBleeder ) {
//temporarily add a small div to use to figure out the 'bleed-through' margin
//of the last element
last = $(div).appendTo(container);
}
//for performance, we want to figure out the currently used height of the parent element
// as quick as possible
// we can use either offsetTop or offset depending ...
if ( last && last.length > 0 ) {
if ( last.offsetParent()[0] === container[0] ) {
currentSize = last[0].offsetTop + last.outerHeight();
} else if (last.offsetParent()[0] === container.offsetParent()[0]) {
// add pos abs for IE7 but
// might need to adjust for the addition of first's hheight
var curLast =last[0].offsetTop;
first = $(div).prependTo(container);
currentSize = ( curLast + last.outerHeight() ) - first[0].offsetTop;
first.remove();
} else {
// add first so we know where to start from .. do not bleed in this case
first = $(div).prependTo(container);
currentSize = ( last.offset().top + last.outerHeight() ) - first.offset().top;
first.remove();
}
}
// what the difference between the parent height and what we are going to take up is
var delta = parentHeight - currentSize,
// the current height of the object
fillerHeight = ev.data.filler.height();
//adjust the height
if ( ev.data.options.all ) {
// we don't care about anything else, we are likely absolutely positioned
// we need to fill the parent width
// temporarily collapse, then expand
ev.data.filler.height(0).width(0);
var parentWidth = parent.width(),
parentHeight = parent.height();
ev.data.filler.outerHeight(parentHeight);
ev.data.filler.outerWidth(parentWidth);
} else {
ev.data.filler.height(fillerHeight + delta)
}
//remove the temporary element
if ( isBleeder ) {
last.remove();
}
}
});
})(jQuery);
(function() {
/**
* @function jQuery.cookie
* @parent jquerypp
* @plugin jquery/dom/cookie
* @author Klaus Hartl/[email protected]
*
* `jQuery.cookie(name, [value], [options])` lets you create, read and remove cookies. It is the
* [jQuery cookie plugin](https://github.com/carhartl/jquery-cookie) written by [Klaus Hartl](stilbuero.de)
* and dual licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php)
* and [GPL](http://www.gnu.org/licenses/gpl.html) licenses.
*
* ## Examples
*
* Set the value of a cookie.
*
* $.cookie('the_cookie', 'the_value');
*
* Create a cookie with all available options.
*
* $.cookie('the_cookie', 'the_value', {
* expires: 7,
* path: '/',
* domain: 'jquery.com',
* secure: true
* });
*
* Create a session cookie.
*
* $.cookie('the_cookie', 'the_value');
*
* Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
*
* $.cookie('the_cookie', null);
*
* Get the value of a cookie.
*
* $.cookie('the_cookie');
*
* @param {String} [name] The name of the cookie.
* @param {String} [value] The value of the cookie.
* @param {Object} [options] An object literal containing key/value pairs to provide optional cookie attributes. Values can be:
*
* - `expires` - Either an integer specifying the expiration date from now on in days or a Date object. If a negative value is specified (e.g. a date in the past), the cookie will be deleted. If set to null or omitted, the cookie will be a session cookie and will not be retained when the the browser exits.
* - `domain` - The domain name
* - `path` - The value of the path atribute of the cookie (default: path of page that created the cookie).
* - `secure` - If true, the secure attribute of the cookie will be set and the cookie transmission will require a secure protocol (like HTTPS).
*
* @return {String} the value of the cookie or {undefined} when setting the cookie.
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') {
// name and value given, set cookie
options = options ||
{};
if (value === null) {
value = '';
options.expires = -1;
}
// convert value to JSON string
if (typeof value == 'object' && jQuery.toJSON) {
value = jQuery.toJSON(value);
}
var expires = '';
// Set expiry
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
}
else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// CAUTION: Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
// Set the cookie name=value;expires=;path=;domain=;secure-
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
}
else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
// Get the cookie value
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
// Parse JSON from the cookie into an object
if (jQuery.evalJSON && cookieValue && cookieValue.match(/^\s*\{/)) {
try {
cookieValue = jQuery.evalJSON(cookieValue);
}
catch (e) {
}
}
return cookieValue;
}
};
})(jQuery);
(function ($) {
// Overwrites `jQuery.fn.animate` to use CSS 3 animations if possible
var
// The global animation counter
animationNum = 0,
// The stylesheet for our animations
styleSheet = null,
// The animation cache
cache = [],
// Stores the browser properties like transition end event name and prefix
browser = null,
// Store the original $.fn.animate
oldanimate = $.fn.animate,
// Return the stylesheet, create it if it doesn't exists
getStyleSheet = function () {
if(!styleSheet) {
var style = document.createElement('style');
style.setAttribute("type", "text/css");
style.setAttribute("media", "screen");
document.getElementsByTagName('head')[0].appendChild(style);
if (!window.createPopup) { /* For Safari */
style.appendChild(document.createTextNode(''));
}
styleSheet = style.sheet;
}
return styleSheet;
},
//removes an animation rule from a sheet
removeAnimation = function (sheet, name) {
for (var j = sheet.cssRules.length - 1; j >= 0; j--) {
var rule = sheet.cssRules[j];
// 7 means the keyframe rule
if (rule.type === 7 && rule.name == name) {
sheet.deleteRule(j)
return;
}
}
},
// Returns whether the animation should be passed to the original $.fn.animate.
passThrough = function (props, ops) {
var nonElement = !(this[0] && this[0].nodeType),
isInline = !nonElement && $(this).css("display") === "inline" && $(this).css("float") === "none";
for (var name in props) {
// jQuery does something with these values
if (props[name] == 'show' || props[name] == 'hide' || props[name] == 'toggle'
// Arrays for individual easing
|| $.isArray(props[name])
// Negative values not handled the same
|| props[name] < 0
// unit-less value
|| name == 'zIndex' || name == 'z-index'
) {
return true;
}
}
return props.jquery === true || getBrowser() === null ||
// Animating empty properties
$.isEmptyObject(props) ||
// We can't do custom easing
ops.length == 4 || typeof ops[2] == 'string' ||
// Second parameter is an object - we can only handle primitives
$.isPlainObject(ops) ||
// Inline and non elements
isInline || nonElement;
},
// Gets a CSS number (with px added as the default unit if the value is a number)
cssValue = function(origName, value) {
if (typeof value === "number" && !$.cssNumber[ origName ]) {
return value += "px";
}
return value;
},
// Feature detection borrowed by http://modernizr.com/
getBrowser = function(){
if(!browser) {
var t,
el = document.createElement('fakeelement'),
transitions = {
'transition': {
transitionEnd : 'transitionEnd',
prefix : ''
},
// 'OTransition': {
// transitionEnd : 'oTransitionEnd',
// prefix : '-o-'
// },
// 'MSTransition': {
// transitionEnd : 'msTransitionEnd',
// prefix : '-ms-'
// },
'MozTransition': {
transitionEnd : 'animationend',
prefix : '-moz-'
},
'WebkitTransition': {
transitionEnd : 'webkitAnimationEnd',
prefix : '-webkit-'
}
}
for(t in transitions){
if( el.style[t] !== undefined ){
browser = transitions[t];
}
}
}
return browser;
},
// Properties that Firefox can't animate if set to 'auto':
// https://bugzilla.mozilla.org/show_bug.cgi?id=571344
// Provides a converter that returns the actual value
ffProps = {
top : function(el) {
return el.position().top;
},
left : function(el) {
return el.position().left;
},
width : function(el) {
return el.width();
},
height : function(el) {
return el.height();
},
fontSize : function(el) {
return '1em';
}
},
// Add browser specific prefix
addPrefix = function(properties) {
var result = {};
$.each(properties, function(name, value) {
result[getBrowser().prefix + name] = value;
});
return result;
},
// Returns the animation name for a given style. It either uses a cached
// version or adds it to the stylesheet, removing the oldest style if the
// cache has reached a certain size.
getAnimation = function(style) {
var sheet, name, last;
// Look up the cached style, set it to that name and reset age if found
// increment the age for any other animation
$.each(cache, function(i, animation) {
if(style === animation.style) {
name = animation.name;
animation.age = 0;
} else {
animation.age += 1;
}
});
if(!name) { // Add a new style
sheet = getStyleSheet();
name = "jquerypp_animation_" + (animationNum++);
// get the last sheet and insert this rule into it
sheet.insertRule("@" + getBrowser().prefix + "keyframes " + name + ' ' + style,
(sheet.cssRules && sheet.cssRules.length) || 0);
cache.push({
name : name,
style : style,
age : 0
});
// Sort the cache by age
cache.sort(function(first, second) {
return first.age - second.age;
});
// Remove the last (oldest) item from the cache if it has more than 20 items
if(cache.length > 20) {
last = cache.pop();
removeAnimation(sheet, last.name);
}
}
return name;
};
/**
* @function $.fn.animate
* @parent $.animate
*
* Animate CSS properties using native CSS animations, if possible.
* Uses the original [$.fn.animate()](http://api.$.com/animate/) otherwise.
*
* @param {Object} props The CSS properties to animate
* @param {Integer|String|Object} [speed=400] The animation duration in ms.
* Will use $.fn.animate if a string or object is passed
* @param {Function} [callback] A callback to execute once the animation is complete
* @return {jQuery} The jQuery element
*/
$.fn.animate = function (props, speed, easing, callback) {
//default to normal animations if browser doesn't support them
if (passThrough.apply(this, arguments)) {
return oldanimate.apply(this, arguments);
}
var optall = jQuery.speed(speed, easing, callback);
// Add everything to the animation queue
this.queue(optall.queue, function(done) {
var
//current CSS values
current,
// The list of properties passed
properties = [],
to = "",
prop,
self = $(this),
duration = optall.duration,
//the animation keyframe name
animationName,
// The key used to store the animation hook
dataKey,
//the text for the keyframe
style = "{ from {",
// The animation end event handler.
// Will be called both on animation end and after calling .stop()
animationEnd = function (currentCSS, exec) {
self.css(currentCSS);
self.css(addPrefix({
"animation-duration" : "",
"animation-name" : "",
"animation-fill-mode" : "",
"animation-play-state" : ""
}));
// Call the original callback
if (optall.old && exec) {
// Call success, pass the DOM element as the this reference
optall.old.call(self[0], true)
}
$.removeData(self, dataKey, true);
}
for(prop in props) {
properties.push(prop);
}
if(getBrowser().prefix === '-moz-') {
// Normalize 'auto' properties in FF
$.each(properties, function(i, prop) {
var converter = ffProps[$.camelCase(prop)];
if(converter && self.css(prop) == 'auto') {
self.css(prop, converter(self));
}
});
}
// Use $.styles
current = self.styles.apply(self, properties);
$.each(properties, function(i, cur) {
// Convert a camelcased property name
var name = cur.replace(/([A-Z]|^ms)/g, "-$1" ).toLowerCase();
style += name + " : " + cssValue(cur, current[cur]) + "; ";
to += name + " : " + cssValue(cur, props[cur]) + "; ";
});
style += "} to {" + to + " }}";
animationName = getAnimation(style);
dataKey = animationName + '.run';
// Add a hook which will be called when the animation stops
$._data(this, dataKey, {
stop : function(gotoEnd) {
// Pause the animation
self.css(addPrefix({
'animation-play-state' : 'paused'
}));
// Unbind the animation end handler
self.off(getBrowser().transitionEnd, animationEnd);
if(!gotoEnd) {
// We were told not to finish the animation
// Call animationEnd but set the CSS to the current computed style
animationEnd(self.styles.apply(self, properties), false);
} else {
// Finish animaion
animationEnd(props, true);
}
}
});
// set this element to point to that animation
self.css(addPrefix({
"animation-duration" : duration + "ms",
"animation-name" : animationName,
"animation-fill-mode": "forwards"
}));
// Attach the transition end event handler to run only once
self.one(getBrowser().transitionEnd, function() {
// Call animationEnd using the passed properties
animationEnd(props, true);
done();
});
});
return this;
};
})(jQuery)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy