Portotyping of edit screen with face detection.

This commit is contained in:
Knut Forkalsrud 2011-03-13 18:00:20 -07:00
parent 45fc47f099
commit fc7f13daad
8 changed files with 2216 additions and 0 deletions

View file

@ -0,0 +1,415 @@
var ccv = {
pre : function (image) {
if (image.tagName.toLowerCase() == "img") {
var canvas = document.createElement("canvas");
document.body.appendChild(image);
canvas.width = image.offsetWidth;
canvas.style.width = image.offsetWidth.toString() + "px";
canvas.height = image.offsetHeight;
canvas.style.height = image.offsetHeight.toString() + "px";
document.body.removeChild(image);
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
return canvas;
}
return image;
},
grayscale : function (canvas) {
var ctx = canvas.getContext("2d");
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var pix1, pix2, pix = canvas.width * canvas.height * 4;
while (pix > 0)
data[pix -= 4] = data[pix1 = pix + 1] = data[pix2 = pix + 2] = (data[pix] * 0.3 + data[pix1] * 0.59 + data[pix2] * 0.11);
ctx.putImageData(imageData, 0, 0);
return canvas;
},
__get_named_arguments : function (params, names) {
if (params.length > 1) {
var new_params = {};
for (var i = 0; i < names.length; i++)
new_params[names[i]] = params[i];
return new_params;
}
return params[0];
},
__worker_scripts : {},
spawn : function (pre, script, params, post, complete, worker_num) {
var params = ccv.__get_named_arguments(arguments, ["pre", "script", "params", "post", "complete"]);
var worker = new Worker("ccv.js");
worker.onmessage = function (event) {
params.complete(params.post((typeof event.data == "string") ? JSON.parse(event.data) : event.data));
};
var msg = { "data" : params.pre(),
"script" : params.script,
"params" : params.params,
"id" : 0,
"worker_num" : params.worker_num };
try {
worker.postMessage(msg);
} catch (e) {
worker.postMessage(JSON.stringify(msg));
}
return worker;
},
array_group : function (seq, gfunc) {
var i, j;
var node = new Array(seq.length);
for (i = 0; i < seq.length; i++)
node[i] = {"parent" : -1,
"element" : seq[i],
"rank" : 0};
for (i = 0; i < seq.length; i++)
{
if (!node[i].element)
continue;
var root = i;
while (node[root].parent != -1)
root = node[root].parent;
for (j = 0; j < seq.length; j++)
{
if( i != j && node[j].element && gfunc(node[i].element, node[j].element))
{
var root2 = j;
while (node[root2].parent != -1)
root2 = node[root2].parent;
if(root2 != root)
{
if(node[root].rank > node[root2].rank)
node[root2].parent = root;
else
{
node[root].parent = root2;
if (node[root].rank == node[root2].rank)
node[root2].rank++;
root = root2;
}
/* compress path from node2 to the root: */
var temp, node2 = j;
while (node[node2].parent != -1)
{
temp = node2;
node2 = node[node2].parent;
node[temp].parent = root;
}
/* compress path from node to the root: */
node2 = i;
while (node[node2].parent != -1)
{
temp = node2;
node2 = node[node2].parent;
node[temp].parent = root;
}
}
}
}
}
var idx = new Array(seq.length);
var class_idx = 0;
for(i = 0; i < seq.length; i++)
{
j = -1;
var node1 = i;
if(node[node1].element)
{
while (node[node1].parent != -1)
node1 = node[node1].parent;
if(node[node1].rank >= 0)
node[node1].rank = ~class_idx++;
j = ~node[node1].rank;
}
idx[i] = j;
}
return {"index" : idx, "cat" : class_idx};
},
detect_objects : function (canvas, cascade, interval, min_neighbors, complete, worker_num, setup) {
var params = ccv.__get_named_arguments(arguments, ["canvas", "cascade", "interval", "min_neighbors", "complete", "worker_num", "setup"]);
if (!params.setup) {
var cascade = params.cascade;
var scale = Math.pow(2, 1 / (params.interval + 1));
var next = params.interval + 1;
var scale_upto = Math.floor(Math.log(Math.min(params.canvas.width / cascade.width, params.canvas.height / cascade.height)) / Math.log(scale));
}
var pre = function () {
var pyr = new Array((scale_upto + next * 2) * 4);
var ret = new Array((scale_upto + next * 2) * 4);
pyr[0] = params.canvas;
ret[0] = { "width" : pyr[0].width,
"height" : pyr[0].height,
"data" : pyr[0].getContext("2d").getImageData(0, 0, pyr[0].width, pyr[0].height).data };
var i;
for (i = 1; i <= params.interval; i++) {
pyr[i * 4] = document.createElement("canvas");
pyr[i * 4].width = Math.floor(pyr[0].width / Math.pow(scale, i));
pyr[i * 4].height = Math.floor(pyr[0].height / Math.pow(scale, i));
pyr[i * 4].getContext("2d").drawImage(pyr[0], 0, 0, pyr[0].width, pyr[0].height, 0, 0, pyr[i * 4].width, pyr[i * 4].height);
ret[i * 4] = { "width" : pyr[i * 4].width,
"height" : pyr[i * 4].height,
"data" : pyr[i * 4].getContext("2d").getImageData(0, 0, pyr[i * 4].width, pyr[i * 4].height).data };
}
for (i = next; i < scale_upto + next * 2; i++) {
pyr[i * 4] = document.createElement("canvas");
pyr[i * 4].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
pyr[i * 4].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
pyr[i * 4].getContext("2d").drawImage(pyr[i * 4 - next * 4], 0, 0, pyr[i * 4 - next * 4].width, pyr[i * 4 - next * 4].height, 0, 0, pyr[i * 4].width, pyr[i * 4].height);
ret[i * 4] = { "width" : pyr[i * 4].width,
"height" : pyr[i * 4].height,
"data" : pyr[i * 4].getContext("2d").getImageData(0, 0, pyr[i * 4].width, pyr[i * 4].height).data };
}
for (i = next * 2; i < scale_upto + next * 2; i++) {
pyr[i * 4 + 1] = document.createElement("canvas");
pyr[i * 4 + 1].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
pyr[i * 4 + 1].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
pyr[i * 4 + 1].getContext("2d").drawImage(pyr[i * 4 - next * 4], 1, 0, pyr[i * 4 - next * 4].width - 1, pyr[i * 4 - next * 4].height, 0, 0, pyr[i * 4 + 1].width - 2, pyr[i * 4 + 1].height);
ret[i * 4 + 1] = { "width" : pyr[i * 4 + 1].width,
"height" : pyr[i * 4 + 1].height,
"data" : pyr[i * 4 + 1].getContext("2d").getImageData(0, 0, pyr[i * 4 + 1].width, pyr[i * 4 + 1].height).data };
pyr[i * 4 + 2] = document.createElement("canvas");
pyr[i * 4 + 2].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
pyr[i * 4 + 2].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
pyr[i * 4 + 2].getContext("2d").drawImage(pyr[i * 4 - next * 4], 0, 1, pyr[i * 4 - next * 4].width, pyr[i * 4 - next * 4].height - 1, 0, 0, pyr[i * 4 + 2].width, pyr[i * 4 + 2].height - 2);
ret[i * 4 + 2] = { "width" : pyr[i * 4 + 2].width,
"height" : pyr[i * 4 + 2].height,
"data" : pyr[i * 4 + 2].getContext("2d").getImageData(0, 0, pyr[i * 4 + 2].width, pyr[i * 4 + 2].height).data };
pyr[i * 4 + 3] = document.createElement("canvas");
pyr[i * 4 + 3].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
pyr[i * 4 + 3].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
pyr[i * 4 + 3].getContext("2d").drawImage(pyr[i * 4 - next * 4], 1, 1, pyr[i * 4 - next * 4].width - 1, pyr[i * 4 - next * 4].height - 1, 0, 0, pyr[i * 4 + 3].width - 2, pyr[i * 4 + 3].height - 2);
ret[i * 4 + 3] = { "width" : pyr[i * 4 + 3].width,
"height" : pyr[i * 4 + 3].height,
"data" : pyr[i * 4 + 3].getContext("2d").getImageData(0, 0, pyr[i * 4 + 3].width, pyr[i * 4 + 3].height).data };
}
for (i = 0; i < cascade.stage_classifier.length; i++)
cascade.stage_classifier[i].orig_feature = cascade.stage_classifier[i].feature;
return ret;
};
var work = function (pyr, params, id, worker_num) {
var cascade = params.cascade;
var scale = Math.pow(2, 1 / (params.interval + 1));
var next = params.interval + 1;
var scale_upto = Math.floor(Math.log(Math.min(pyr[0].width / cascade.width, pyr[0].height / cascade.height)) / Math.log(scale));
var i, j, k, x, y, q;
var scale_x = 1, scale_y = 1;
var dx = [0, 1, 0, 1];
var dy = [0, 0, 1, 1];
var seq = [];
for (i = 0; i < scale_upto; i++) {
var qw = pyr[i * 4 + next * 8].width - Math.floor(cascade.width / 4);
var qh = pyr[i * 4 + next * 8].height - Math.floor(cascade.height / 4);
var step = [pyr[i * 4].width * 4, pyr[i * 4 + next * 4].width * 4, pyr[i * 4 + next * 8].width * 4];
var paddings = [pyr[i * 4].width * 16 - qw * 16,
pyr[i * 4 + next * 4].width * 8 - qw * 8,
pyr[i * 4 + next * 8].width * 4 - qw * 4];
for (j = 0; j < cascade.stage_classifier.length; j++) {
var orig_feature = cascade.stage_classifier[j].orig_feature;
var feature = cascade.stage_classifier[j].feature = new Array(cascade.stage_classifier[j].count);
for (k = 0; k < cascade.stage_classifier[j].count; k++) {
feature[k] = {"size" : orig_feature[k].size,
"px" : new Array(orig_feature[k].size),
"pz" : new Array(orig_feature[k].size),
"nx" : new Array(orig_feature[k].size),
"nz" : new Array(orig_feature[k].size)};
for (q = 0; q < orig_feature[k].size; q++) {
feature[k].px[q] = orig_feature[k].px[q] * 4 + orig_feature[k].py[q] * step[orig_feature[k].pz[q]];
feature[k].pz[q] = orig_feature[k].pz[q];
feature[k].nx[q] = orig_feature[k].nx[q] * 4 + orig_feature[k].ny[q] * step[orig_feature[k].nz[q]];
feature[k].nz[q] = orig_feature[k].nz[q];
}
}
}
for (q = 0; q < 4; q++) {
var u8 = [pyr[i * 4].data, pyr[i * 4 + next * 4].data, pyr[i * 4 + next * 8 + q].data];
var u8o = [dx[q] * 8 + dy[q] * pyr[i * 4].width * 8, dx[q] * 4 + dy[q] * pyr[i * 4 + next * 4].width * 4, 0];
for (y = 0; y < qh; y++) {
for (x = 0; x < qw; x++) {
var sum = 0;
var flag = true;
for (j = 0; j < cascade.stage_classifier.length; j++) {
sum = 0;
var alpha = cascade.stage_classifier[j].alpha;
var feature = cascade.stage_classifier[j].feature;
for (k = 0; k < cascade.stage_classifier[j].count; k++) {
var feature_k = feature[k];
var p, pmin = u8[feature_k.pz[0]][u8o[feature_k.pz[0]] + feature_k.px[0]];
var n, nmax = u8[feature_k.nz[0]][u8o[feature_k.nz[0]] + feature_k.nx[0]];
if (pmin <= nmax) {
sum += alpha[k * 2];
} else {
var f, shortcut = true;
for (f = 0; f < feature_k.size; f++) {
if (feature_k.pz[f] >= 0) {
p = u8[feature_k.pz[f]][u8o[feature_k.pz[f]] + feature_k.px[f]];
if (p < pmin) {
if (p <= nmax) {
shortcut = false;
break;
}
pmin = p;
}
}
if (feature_k.nz[f] >= 0) {
n = u8[feature_k.nz[f]][u8o[feature_k.nz[f]] + feature_k.nx[f]];
if (n > nmax) {
if (pmin <= n) {
shortcut = false;
break;
}
nmax = n;
}
}
}
sum += (shortcut) ? alpha[k * 2 + 1] : alpha[k * 2];
}
}
if (sum < cascade.stage_classifier[j].threshold) {
flag = false;
break;
}
}
if (flag) {
seq.push({"x" : (x * 4 + dx[q] * 2) * scale_x,
"y" : (y * 4 + dy[q] * 2) * scale_y,
"width" : cascade.width * scale_x,
"height" : cascade.height * scale_y,
"neighbor" : 1,
"confidence" : sum});
}
u8o[0] += 16;
u8o[1] += 8;
u8o[2] += 4;
}
u8o[0] += paddings[0];
u8o[1] += paddings[1];
u8o[2] += paddings[2];
}
}
scale_x *= scale;
scale_y *= scale;
}
return seq;
};
var post = function (seq) {
var i, j;
for (i = 0; i < cascade.stage_classifier.length; i++)
cascade.stage_classifier[i].feature = cascade.stage_classifier[i].orig_feature;
if (!(params.min_neighbors > 0))
return seq;
else {
var result = ccv.array_group(seq, function (r1, r2) {
var distance = Math.floor(r1.width * 0.25 + 0.5);
return r2.x <= r1.x + distance &&
r2.x >= r1.x - distance &&
r2.y <= r1.y + distance &&
r2.y >= r1.y - distance &&
r2.width <= Math.floor(r1.width * 1.5 + 0.5) &&
Math.floor(r2.width * 1.5 + 0.5) >= r1.width;
});
var ncomp = result.cat;
var idx_seq = result.index;
var comps = new Array(ncomp + 1);
for (i = 0; i < comps.length; i++)
comps[i] = {"neighbors" : 0,
"x" : 0,
"y" : 0,
"width" : 0,
"height" : 0,
"confidence" : 0};
// count number of neighbors
for(i = 0; i < seq.length; i++)
{
var r1 = seq[i];
var idx = idx_seq[i];
if (comps[idx].neighbors == 0)
comps[idx].confidence = r1.confidence;
++comps[idx].neighbors;
comps[idx].x += r1.x;
comps[idx].y += r1.y;
comps[idx].width += r1.width;
comps[idx].height += r1.height;
comps[idx].confidence = Math.max(comps[idx].confidence, r1.confidence);
}
var seq2 = [];
// calculate average bounding box
for(i = 0; i < ncomp; i++)
{
var n = comps[i].neighbors;
if (n >= params.min_neighbors)
seq2.push({"x" : (comps[i].x * 2 + n) / (2 * n),
"y" : (comps[i].y * 2 + n) / (2 * n),
"width" : (comps[i].width * 2 + n) / (2 * n),
"height" : (comps[i].height * 2 + n) / (2 * n),
"neighbors" : comps[i].neighbors,
"confidence" : comps[i].confidence});
}
var result_seq = [];
// filter out small face rectangles inside large face rectangles
for(i = 0; i < seq2.length; i++)
{
var r1 = seq2[i];
var flag = true;
for(j = 0; j < seq2.length; j++)
{
var r2 = seq2[j];
var distance = Math.floor(r2.width * 0.25 + 0.5);
if(i != j &&
r1.x >= r2.x - distance &&
r1.y >= r2.y - distance &&
r1.x + r1.width <= r2.x + r2.width + distance &&
r1.y + r1.height <= r2.y + r2.height + distance &&
(r2.neighbors > Math.max(3, r1.neighbors) || r1.neighbors < 3))
{
flag = false;
break;
}
}
if(flag)
result_seq.push(r1);
}
return result_seq;
}
};
if (params.setup) {
ccv.__worker_scripts.detect_objects = work;
} else {
if (params.complete === undefined) {
return post(work(pre(), params, 0, 1));
} else {
ccv.spawn(pre, "detect_objects", { "cascade" : params.cascade,
"interval" : params.interval,
"min_neighbors" : params.min_neighbors }, post, params.complete, params.worker_num);
}
}
}
}
onmessage = function (event) {
var data = (typeof event.data == "string") ? JSON.parse(event.data) : event.data;
ccv[data.script]({"setup" : true});
var result = ccv.__worker_scripts[data.script](data.data, data.params, data.id, data.worker_num);
try {
postMessage(result);
} catch (e) {
postMessage(JSON.stringify(result));
}
}

File diff suppressed because one or more lines are too long

308
src/main/webapp/assets/jquery.ui.core.js vendored Normal file
View file

@ -0,0 +1,308 @@
/*!
* jQuery UI 1.8.6
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI
*/
(function( $, undefined ) {
// prevent duplicate loading
// this is only a problem because we proxy existing functions
// and we don't want to double proxy them
$.ui = $.ui || {};
if ( $.ui.version ) {
return;
}
$.extend( $.ui, {
version: "1.8.6",
keyCode: {
ALT: 18,
BACKSPACE: 8,
CAPS_LOCK: 20,
COMMA: 188,
COMMAND: 91,
COMMAND_LEFT: 91, // COMMAND
COMMAND_RIGHT: 93,
CONTROL: 17,
DELETE: 46,
DOWN: 40,
END: 35,
ENTER: 13,
ESCAPE: 27,
HOME: 36,
INSERT: 45,
LEFT: 37,
MENU: 93, // COMMAND_RIGHT
NUMPAD_ADD: 107,
NUMPAD_DECIMAL: 110,
NUMPAD_DIVIDE: 111,
NUMPAD_ENTER: 108,
NUMPAD_MULTIPLY: 106,
NUMPAD_SUBTRACT: 109,
PAGE_DOWN: 34,
PAGE_UP: 33,
PERIOD: 190,
RIGHT: 39,
SHIFT: 16,
SPACE: 32,
TAB: 9,
UP: 38,
WINDOWS: 91 // COMMAND
}
});
// plugins
$.fn.extend({
_focus: $.fn.focus,
focus: function( delay, fn ) {
return typeof delay === "number" ?
this.each(function() {
var elem = this;
setTimeout(function() {
$( elem ).focus();
if ( fn ) {
fn.call( elem );
}
}, delay );
}) :
this._focus.apply( this, arguments );
},
scrollParent: function() {
var scrollParent;
if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
scrollParent = this.parents().filter(function() {
return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
}).eq(0);
} else {
scrollParent = this.parents().filter(function() {
return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
}).eq(0);
}
return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
},
zIndex: function( zIndex ) {
if ( zIndex !== undefined ) {
return this.css( "zIndex", zIndex );
}
if ( this.length ) {
var elem = $( this[ 0 ] ), position, value;
while ( elem.length && elem[ 0 ] !== document ) {
// Ignore z-index if position is set to a value where z-index is ignored by the browser
// This makes behavior of this function consistent across browsers
// WebKit always returns auto if the element is positioned
position = elem.css( "position" );
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
// IE returns 0 when zIndex is not specified
// other browsers return a string
// we ignore the case of nested elements with an explicit value of 0
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
value = parseInt( elem.css( "zIndex" ), 10 );
if ( !isNaN( value ) && value !== 0 ) {
return value;
}
}
elem = elem.parent();
}
}
return 0;
},
disableSelection: function() {
return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
".ui-disableSelection", function( event ) {
event.preventDefault();
});
},
enableSelection: function() {
return this.unbind( ".ui-disableSelection" );
}
});
$.each( [ "Width", "Height" ], function( i, name ) {
var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
type = name.toLowerCase(),
orig = {
innerWidth: $.fn.innerWidth,
innerHeight: $.fn.innerHeight,
outerWidth: $.fn.outerWidth,
outerHeight: $.fn.outerHeight
};
function reduce( elem, size, border, margin ) {
$.each( side, function() {
size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
if ( border ) {
size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
}
if ( margin ) {
size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
}
});
return size;
}
$.fn[ "inner" + name ] = function( size ) {
if ( size === undefined ) {
return orig[ "inner" + name ].call( this );
}
return this.each(function() {
$( this ).css( type, reduce( this, size ) + "px" );
});
};
$.fn[ "outer" + name] = function( size, margin ) {
if ( typeof size !== "number" ) {
return orig[ "outer" + name ].call( this, size );
}
return this.each(function() {
$( this).css( type, reduce( this, size, true, margin ) + "px" );
});
};
});
// selectors
function visible( element ) {
return !$( element ).parents().andSelf().filter(function() {
return $.curCSS( this, "visibility" ) === "hidden" ||
$.expr.filters.hidden( this );
}).length;
}
$.extend( $.expr[ ":" ], {
data: function( elem, i, match ) {
return !!$.data( elem, match[ 3 ] );
},
focusable: function( element ) {
var nodeName = element.nodeName.toLowerCase(),
tabIndex = $.attr( element, "tabindex" );
if ( "area" === nodeName ) {
var map = element.parentNode,
mapName = map.name,
img;
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
return false;
}
img = $( "img[usemap=#" + mapName + "]" )[0];
return !!img && visible( img );
}
return ( /input|select|textarea|button|object/.test( nodeName )
? !element.disabled
: "a" == nodeName
? element.href || !isNaN( tabIndex )
: !isNaN( tabIndex ))
// the element and all of its ancestors must be visible
&& visible( element );
},
tabbable: function( element ) {
var tabIndex = $.attr( element, "tabindex" );
return ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( ":focusable" );
}
});
// support
$(function() {
var body = document.body,
div = body.appendChild( div = document.createElement( "div" ) );
$.extend( div.style, {
minHeight: "100px",
height: "auto",
padding: 0,
borderWidth: 0
});
$.support.minHeight = div.offsetHeight === 100;
$.support.selectstart = "onselectstart" in div;
// set display to none to avoid a layout bug in IE
// http://dev.jquery.com/ticket/4014
body.removeChild( div ).style.display = "none";
});
// deprecated
$.extend( $.ui, {
// $.ui.plugin is deprecated. Use the proxy pattern instead.
plugin: {
add: function( module, option, set ) {
var proto = $.ui[ module ].prototype;
for ( var i in set ) {
proto.plugins[ i ] = proto.plugins[ i ] || [];
proto.plugins[ i ].push( [ option, set[ i ] ] );
}
},
call: function( instance, name, args ) {
var set = instance.plugins[ name ];
if ( !set || !instance.element[ 0 ].parentNode ) {
return;
}
for ( var i = 0; i < set.length; i++ ) {
if ( instance.options[ set[ i ][ 0 ] ] ) {
set[ i ][ 1 ].apply( instance.element, args );
}
}
}
},
// will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
contains: function( a, b ) {
return document.compareDocumentPosition ?
a.compareDocumentPosition( b ) & 16 :
a !== b && a.contains( b );
},
// only used by resizable
hasScroll: function( el, a ) {
//If overflow is hidden, the element might have extra content, but the user wants to hide it
if ( $( el ).css( "overflow" ) === "hidden") {
return false;
}
var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
has = false;
if ( el[ scroll ] > 0 ) {
return true;
}
// TODO: determine which cases actually cause this to happen
// if the element doesn't have the scroll set, see if it's possible to
// set the scroll
el[ scroll ] = 1;
has = ( el[ scroll ] > 0 );
el[ scroll ] = 0;
return has;
},
// these are odd functions, fix the API or move into individual plugins
isOverAxis: function( x, reference, size ) {
//Determines when x coordinate is over "b" element axis
return ( x > reference ) && ( x < ( reference + size ) );
},
isOver: function( y, x, top, left, height, width ) {
//Determines when x, y coordinates is over "b" element
return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
}
});
})( jQuery );

View file

@ -0,0 +1,147 @@
/*!
* jQuery UI Mouse 1.8.6
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Mouse
*
* Depends:
* jquery.ui.widget.js
*/
(function( $, undefined ) {
$.widget("ui.mouse", {
options: {
cancel: ':input,option',
distance: 1,
delay: 0
},
_mouseInit: function() {
var self = this;
this.element
.bind('mousedown.'+this.widgetName, function(event) {
return self._mouseDown(event);
})
.bind('click.'+this.widgetName, function(event) {
if(self._preventClickEvent) {
self._preventClickEvent = false;
event.stopImmediatePropagation();
return false;
}
});
this.started = false;
},
// TODO: make sure destroying one instance of mouse doesn't mess with
// other instances of mouse
_mouseDestroy: function() {
this.element.unbind('.'+this.widgetName);
},
_mouseDown: function(event) {
// don't let more than one widget handle mouseStart
// TODO: figure out why we have to use originalEvent
event.originalEvent = event.originalEvent || {};
if (event.originalEvent.mouseHandled) { return; }
// we may have missed mouseup (out of window)
(this._mouseStarted && this._mouseUp(event));
this._mouseDownEvent = event;
var self = this,
btnIsLeft = (event.which == 1),
elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
return true;
}
this.mouseDelayMet = !this.options.delay;
if (!this.mouseDelayMet) {
this._mouseDelayTimer = setTimeout(function() {
self.mouseDelayMet = true;
}, this.options.delay);
}
if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
this._mouseStarted = (this._mouseStart(event) !== false);
if (!this._mouseStarted) {
event.preventDefault();
return true;
}
}
// these delegates are required to keep context
this._mouseMoveDelegate = function(event) {
return self._mouseMove(event);
};
this._mouseUpDelegate = function(event) {
return self._mouseUp(event);
};
$(document)
.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
event.preventDefault();
event.originalEvent.mouseHandled = true;
return true;
},
_mouseMove: function(event) {
// IE mouseup check - mouseup happened when mouse was out of window
if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
return this._mouseUp(event);
}
if (this._mouseStarted) {
this._mouseDrag(event);
return event.preventDefault();
}
if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
this._mouseStarted =
(this._mouseStart(this._mouseDownEvent, event) !== false);
(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
}
return !this._mouseStarted;
},
_mouseUp: function(event) {
$(document)
.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
if (this._mouseStarted) {
this._mouseStarted = false;
this._preventClickEvent = (event.target == this._mouseDownEvent.target);
this._mouseStop(event);
}
return false;
},
_mouseDistanceMet: function(event) {
return (Math.max(
Math.abs(this._mouseDownEvent.pageX - event.pageX),
Math.abs(this._mouseDownEvent.pageY - event.pageY)
) >= this.options.distance
);
},
_mouseDelayMet: function(event) {
return this.mouseDelayMet;
},
// These are placeholder methods, to be overriden by extending plugin
_mouseStart: function(event) {},
_mouseDrag: function(event) {},
_mouseStop: function(event) {},
_mouseCapture: function(event) { return true; }
});
})(jQuery);

View file

@ -0,0 +1,10 @@
/*
* jQuery UI Selectable 1.8.6
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Selectable#theming
*/
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }

View file

@ -0,0 +1,266 @@
/*
* jQuery UI Selectable 1.8.6
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Selectables
*
* Depends:
* jquery.ui.core.js
* jquery.ui.mouse.js
* jquery.ui.widget.js
*/
(function( $, undefined ) {
$.widget("ui.selectable", $.ui.mouse, {
options: {
appendTo: 'body',
autoRefresh: true,
distance: 0,
filter: '*',
tolerance: 'touch'
},
_create: function() {
var self = this;
this.element.addClass("ui-selectable");
this.dragged = false;
// cache selectee children based on filter
var selectees;
this.refresh = function() {
selectees = $(self.options.filter, self.element[0]);
selectees.each(function() {
var $this = $(this);
var pos = $this.offset();
$.data(this, "selectable-item", {
element: this,
$element: $this,
left: pos.left,
top: pos.top,
right: pos.left + $this.outerWidth(),
bottom: pos.top + $this.outerHeight(),
startselected: false,
selected: $this.hasClass('ui-selected'),
selecting: $this.hasClass('ui-selecting'),
unselecting: $this.hasClass('ui-unselecting')
});
});
};
this.refresh();
this.selectees = selectees.addClass("ui-selectee");
this._mouseInit();
this.helper = $("<div class='ui-selectable-helper'></div>");
},
destroy: function() {
this.selectees
.removeClass("ui-selectee")
.removeData("selectable-item");
this.element
.removeClass("ui-selectable ui-selectable-disabled")
.removeData("selectable")
.unbind(".selectable");
this._mouseDestroy();
return this;
},
_mouseStart: function(event) {
var self = this;
this.opos = [event.pageX, event.pageY];
if (this.options.disabled)
return;
var options = this.options;
this.selectees = $(options.filter, this.element[0]);
this._trigger("start", event);
$(options.appendTo).append(this.helper);
// position helper (lasso)
this.helper.css({
"left": event.clientX,
"top": event.clientY,
"width": 0,
"height": 0
});
if (options.autoRefresh) {
this.refresh();
}
this.selectees.filter('.ui-selected').each(function() {
var selectee = $.data(this, "selectable-item");
selectee.startselected = true;
if (!event.metaKey) {
selectee.$element.removeClass('ui-selected');
selectee.selected = false;
selectee.$element.addClass('ui-unselecting');
selectee.unselecting = true;
// selectable UNSELECTING callback
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
});
$(event.target).parents().andSelf().each(function() {
var selectee = $.data(this, "selectable-item");
if (selectee) {
var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected');
selectee.$element
.removeClass(doSelect ? "ui-unselecting" : "ui-selected")
.addClass(doSelect ? "ui-selecting" : "ui-unselecting");
selectee.unselecting = !doSelect;
selectee.selecting = doSelect;
selectee.selected = doSelect;
// selectable (UN)SELECTING callback
if (doSelect) {
self._trigger("selecting", event, {
selecting: selectee.element
});
} else {
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
return false;
}
});
},
_mouseDrag: function(event) {
var self = this;
this.dragged = true;
if (this.options.disabled)
return;
var options = this.options;
var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
this.selectees.each(function() {
var selectee = $.data(this, "selectable-item");
//prevent helper from being selected if appendTo: selectable
if (!selectee || selectee.element == self.element[0])
return;
var hit = false;
if (options.tolerance == 'touch') {
hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
} else if (options.tolerance == 'fit') {
hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
}
if (hit) {
// SELECT
if (selectee.selected) {
selectee.$element.removeClass('ui-selected');
selectee.selected = false;
}
if (selectee.unselecting) {
selectee.$element.removeClass('ui-unselecting');
selectee.unselecting = false;
}
if (!selectee.selecting) {
selectee.$element.addClass('ui-selecting');
selectee.selecting = true;
// selectable SELECTING callback
self._trigger("selecting", event, {
selecting: selectee.element
});
}
} else {
// UNSELECT
if (selectee.selecting) {
if (event.metaKey && selectee.startselected) {
selectee.$element.removeClass('ui-selecting');
selectee.selecting = false;
selectee.$element.addClass('ui-selected');
selectee.selected = true;
} else {
selectee.$element.removeClass('ui-selecting');
selectee.selecting = false;
if (selectee.startselected) {
selectee.$element.addClass('ui-unselecting');
selectee.unselecting = true;
}
// selectable UNSELECTING callback
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
}
if (selectee.selected) {
if (!event.metaKey && !selectee.startselected) {
selectee.$element.removeClass('ui-selected');
selectee.selected = false;
selectee.$element.addClass('ui-unselecting');
selectee.unselecting = true;
// selectable UNSELECTING callback
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
}
}
});
return false;
},
_mouseStop: function(event) {
var self = this;
this.dragged = false;
var options = this.options;
$('.ui-unselecting', this.element[0]).each(function() {
var selectee = $.data(this, "selectable-item");
selectee.$element.removeClass('ui-unselecting');
selectee.unselecting = false;
selectee.startselected = false;
self._trigger("unselected", event, {
unselected: selectee.element
});
});
$('.ui-selecting', this.element[0]).each(function() {
var selectee = $.data(this, "selectable-item");
selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
selectee.selecting = false;
selectee.selected = true;
selectee.startselected = true;
self._trigger("selected", event, {
selected: selectee.element
});
});
this._trigger("stop", event);
this.helper.remove();
return false;
}
});
$.extend($.ui.selectable, {
version: "1.8.6"
});
})(jQuery);

View file

@ -0,0 +1,262 @@
/*!
* jQuery UI Widget 1.8.6
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Widget
*/
(function( $, undefined ) {
// jQuery 1.4+
if ( $.cleanData ) {
var _cleanData = $.cleanData;
$.cleanData = function( elems ) {
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
$( elem ).triggerHandler( "remove" );
}
_cleanData( elems );
};
} else {
var _remove = $.fn.remove;
$.fn.remove = function( selector, keepData ) {
return this.each(function() {
if ( !keepData ) {
if ( !selector || $.filter( selector, [ this ] ).length ) {
$( "*", this ).add( [ this ] ).each(function() {
$( this ).triggerHandler( "remove" );
});
}
}
return _remove.call( $(this), selector, keepData );
});
};
}
$.widget = function( name, base, prototype ) {
var namespace = name.split( "." )[ 0 ],
fullName;
name = name.split( "." )[ 1 ];
fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
// create selector for plugin
$.expr[ ":" ][ fullName ] = function( elem ) {
return !!$.data( elem, name );
};
$[ namespace ] = $[ namespace ] || {};
$[ namespace ][ name ] = function( options, element ) {
// allow instantiation without initializing for simple inheritance
if ( arguments.length ) {
this._createWidget( options, element );
}
};
var basePrototype = new base();
// we need to make the options hash a property directly on the new instance
// otherwise we'll modify the options hash on the prototype that we're
// inheriting from
// $.each( basePrototype, function( key, val ) {
// if ( $.isPlainObject(val) ) {
// basePrototype[ key ] = $.extend( {}, val );
// }
// });
basePrototype.options = $.extend( true, {}, basePrototype.options );
$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
namespace: namespace,
widgetName: name,
widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
widgetBaseClass: fullName
}, prototype );
$.widget.bridge( name, $[ namespace ][ name ] );
};
$.widget.bridge = function( name, object ) {
$.fn[ name ] = function( options ) {
var isMethodCall = typeof options === "string",
args = Array.prototype.slice.call( arguments, 1 ),
returnValue = this;
// allow multiple hashes to be passed on init
options = !isMethodCall && args.length ?
$.extend.apply( null, [ true, options ].concat(args) ) :
options;
// prevent calls to internal methods
if ( isMethodCall && options.charAt( 0 ) === "_" ) {
return returnValue;
}
if ( isMethodCall ) {
this.each(function() {
var instance = $.data( this, name ),
methodValue = instance && $.isFunction( instance[options] ) ?
instance[ options ].apply( instance, args ) :
instance;
// TODO: add this back in 1.9 and use $.error() (see #5972)
// if ( !instance ) {
// throw "cannot call methods on " + name + " prior to initialization; " +
// "attempted to call method '" + options + "'";
// }
// if ( !$.isFunction( instance[options] ) ) {
// throw "no such method '" + options + "' for " + name + " widget instance";
// }
// var methodValue = instance[ options ].apply( instance, args );
if ( methodValue !== instance && methodValue !== undefined ) {
returnValue = methodValue;
return false;
}
});
} else {
this.each(function() {
var instance = $.data( this, name );
if ( instance ) {
instance.option( options || {} )._init();
} else {
$.data( this, name, new object( options, this ) );
}
});
}
return returnValue;
};
};
$.Widget = function( options, element ) {
// allow instantiation without initializing for simple inheritance
if ( arguments.length ) {
this._createWidget( options, element );
}
};
$.Widget.prototype = {
widgetName: "widget",
widgetEventPrefix: "",
options: {
disabled: false
},
_createWidget: function( options, element ) {
// $.widget.bridge stores the plugin instance, but we do it anyway
// so that it's stored even before the _create function runs
$.data( element, this.widgetName, this );
this.element = $( element );
this.options = $.extend( true, {},
this.options,
this._getCreateOptions(),
options );
var self = this;
this.element.bind( "remove." + this.widgetName, function() {
self.destroy();
});
this._create();
this._trigger( "create" );
this._init();
},
_getCreateOptions: function() {
return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
},
_create: function() {},
_init: function() {},
destroy: function() {
this.element
.unbind( "." + this.widgetName )
.removeData( this.widgetName );
this.widget()
.unbind( "." + this.widgetName )
.removeAttr( "aria-disabled" )
.removeClass(
this.widgetBaseClass + "-disabled " +
"ui-state-disabled" );
},
widget: function() {
return this.element;
},
option: function( key, value ) {
var options = key;
if ( arguments.length === 0 ) {
// don't return a reference to the internal hash
return $.extend( {}, this.options );
}
if (typeof key === "string" ) {
if ( value === undefined ) {
return this.options[ key ];
}
options = {};
options[ key ] = value;
}
this._setOptions( options );
return this;
},
_setOptions: function( options ) {
var self = this;
$.each( options, function( key, value ) {
self._setOption( key, value );
});
return this;
},
_setOption: function( key, value ) {
this.options[ key ] = value;
if ( key === "disabled" ) {
this.widget()
[ value ? "addClass" : "removeClass"](
this.widgetBaseClass + "-disabled" + " " +
"ui-state-disabled" )
.attr( "aria-disabled", value );
}
return this;
},
enable: function() {
return this._setOption( "disabled", false );
},
disable: function() {
return this._setOption( "disabled", true );
},
_trigger: function( type, event, data ) {
var callback = this.options[ type ];
event = $.Event( event );
event.type = ( type === this.widgetEventPrefix ?
type :
this.widgetEventPrefix + type ).toLowerCase();
data = data || {};
// copy original event properties over to the new event
// this would happen if we could call $.event.fix instead of $.Event
// but we don't have a way to force an event to be fixed multiple times
if ( event.originalEvent ) {
for ( var i = $.event.props.length, prop; i; ) {
prop = $.event.props[ --i ];
event[ prop ] = event.originalEvent[ prop ];
}
}
this.element.trigger( event, data );
return !( $.isFunction(callback) &&
callback.call( this.element[0], event, data ) === false ||
event.isDefaultPrevented() );
}
};
})( jQuery );

View file

@ -0,0 +1,807 @@
<ul class="UIAPIPlugin-toc">
<li><a href="#overview">Overview</a></li>
<li><a href="#options">Options</a></li>
<li><a href="#events">Events</a></li>
<li><a href="#methods">Methods</a></li>
<li><a href="#theming">Theming</a></li>
</ul>
<div class="UIAPIPlugin">
<h1>jQuery UI Selectable</h1>
<div id="overview">
<h2 class="top-header">Overview</h2>
<div id="overview-main">
<p>The jQuery UI Selectable plugin allows for elements to be selected by dragging a box (sometimes called a lasso) with the mouse over the elements. Also, elements can be selected by click or drag while holding the Ctrl/Meta key, allowing for multiple (non-contiguous) selections.</p>
</div>
<div id="overview-dependencies">
<h3>Dependencies</h3>
<ul>
<li>UI Core</li>
</ul>
</div>
<div id="overview-example">
<h3>Example</h3>
<div id="overview-example" class="example">
<ul><li><a href="#demo"><span>Demo</span></a></li><li><a href="#source"><span>View Source</span></a></li></ul>
<p><div id="demo" class="tabs-container" rel="">
A simple jQuery UI Selectable.<br />
</p>
<pre>$(&quot;#selectable&quot;).selectable();
</pre>
<p></div><div id="source" class="tabs-container">
</p>
<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;link href=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;/&gt;
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js&quot;&gt;&lt;/script&gt;
&lt;style type=&quot;text/css&quot;&gt;
#selectable .ui-selecting {
background: silver;
}
#selectable .ui-selected {
background: gray;
}
&lt;/style&gt;
&lt;script&gt;
$(document).ready(function() {
$(&quot;#selectable&quot;).selectable();
});
&lt;/script&gt;
&lt;/head&gt;
&lt;body style="font-size:62.5%;"&gt;
&lt;ul id=&quot;selectable&quot;&gt;
&lt;li&gt;Item 1&lt;/li&gt;
&lt;li&gt;Item 2&lt;/li&gt;
&lt;li&gt;Item 3&lt;/li&gt;
&lt;li&gt;Item 4&lt;/li&gt;
&lt;li&gt;Item 5&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p></div>
</p><p></div>
</div>
</div>
<div id="options">
<h2 class="top-header">Options</h2>
<ul class="options-list">
<li class="option" id="option-disabled">
<div class="option-header">
<h3 class="option-name"><a href="#option-disabled">disabled</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">Boolean</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">false</dd>
</dl>
</div>
<div class="option-description">
<p>Disables (true) or enables (false) the selectable. Can be set when initialising (first creating) the selectable.</p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>disabled</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ disabled: true });</code></pre>
</dd>
<dt>
Get or set the <code>disabled</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var disabled = $( ".selector" ).selectable( "option", "disabled" );
//setter
$( ".selector" ).selectable( "option", "disabled", true );</code></pre>
</dd>
</dl>
</div>
</li>
<li class="option" id="option-autoRefresh">
<div class="option-header">
<h3 class="option-name"><a href="#option-autoRefresh">autoRefresh</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">Boolean</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">true</dd>
</dl>
</div>
<div class="option-description">
<p>This determines whether to refresh (recalculate) the position and size of each selectee at the beginning of each select operation. If you have many many items, you may want to set this to false and call the refresh method manually.</p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>autoRefresh</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ autoRefresh: false });</code></pre>
</dd>
<dt>
Get or set the <code>autoRefresh</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var autoRefresh = $( ".selector" ).selectable( "option", "autoRefresh" );
//setter
$( ".selector" ).selectable( "option", "autoRefresh", false );</code></pre>
</dd>
</dl>
</div>
</li>
<li class="option" id="option-cancel">
<div class="option-header">
<h3 class="option-name"><a href="#option-cancel">cancel</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">Selector</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">':input,option'</dd>
</dl>
</div>
<div class="option-description">
<p>Prevents selecting if you start on elements matching the selector.</p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>cancel</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ cancel: ':input,option' });</code></pre>
</dd>
<dt>
Get or set the <code>cancel</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var cancel = $( ".selector" ).selectable( "option", "cancel" );
//setter
$( ".selector" ).selectable( "option", "cancel", ':input,option' );</code></pre>
</dd>
</dl>
</div>
</li>
<li class="option" id="option-delay">
<div class="option-header">
<h3 class="option-name"><a href="#option-delay">delay</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">Integer</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">0</dd>
</dl>
</div>
<div class="option-description">
<p>Time in milliseconds to define when the selecting should start. It helps preventing unwanted selections when clicking on an element.</p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>delay</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ delay: 20 });</code></pre>
</dd>
<dt>
Get or set the <code>delay</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var delay = $( ".selector" ).selectable( "option", "delay" );
//setter
$( ".selector" ).selectable( "option", "delay", 20 );</code></pre>
</dd>
</dl>
</div>
</li>
<li class="option" id="option-distance">
<div class="option-header">
<h3 class="option-name"><a href="#option-distance">distance</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">Integer</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">0</dd>
</dl>
</div>
<div class="option-description">
<p>Tolerance, in pixels, for when selecting should start. If specified, selecting will not start until after mouse is dragged beyond distance.</p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>distance</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ distance: 20 });</code></pre>
</dd>
<dt>
Get or set the <code>distance</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var distance = $( ".selector" ).selectable( "option", "distance" );
//setter
$( ".selector" ).selectable( "option", "distance", 20 );</code></pre>
</dd>
</dl>
</div>
</li>
<li class="option" id="option-filter">
<div class="option-header">
<h3 class="option-name"><a href="#option-filter">filter</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">Selector</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">'*'</dd>
</dl>
</div>
<div class="option-description">
<p>The matching child elements will be made selectees (able to be selected).</p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>filter</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ filter: 'li' });</code></pre>
</dd>
<dt>
Get or set the <code>filter</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var filter = $( ".selector" ).selectable( "option", "filter" );
//setter
$( ".selector" ).selectable( "option", "filter", 'li' );</code></pre>
</dd>
</dl>
</div>
</li>
<li class="option" id="option-tolerance">
<div class="option-header">
<h3 class="option-name"><a href="#option-tolerance">tolerance</a></h3>
<dl>
<dt class="option-type-label">Type:</dt>
<dd class="option-type">String</dd>
<dt class="option-default-label">Default:</dt>
<dd class="option-default">'touch'</dd>
</dl>
</div>
<div class="option-description">
<p>Possible values: 'touch', 'fit'.
</p>
<ul>
<li><b>fit</b>: draggable overlaps the droppable entirely</li>
<li><b>touch</b>: draggable overlaps the droppable any amount</li>
</ul>
<p></p>
</div>
<div class="option-examples">
<h4>Code examples</h4>
<dl class="option-examples-list">
<dt>
Initialize a selectable with the <code>tolerance</code> option specified.
</dt>
<dd>
<pre><code>$( ".selector" ).selectable({ tolerance: 'fit' });</code></pre>
</dd>
<dt>
Get or set the <code>tolerance</code> option, after init.
</dt>
<dd>
<pre><code>//getter
var tolerance = $( ".selector" ).selectable( "option", "tolerance" );
//setter
$( ".selector" ).selectable( "option", "tolerance", 'fit' );</code></pre>
</dd>
</dl>
</div>
</li>
</ul>
</div>
<div id="events">
<h2 class="top-header">Events</h2>
<ul class="events-list">
<li class="event" id="event-selected">
<div class="event-header">
<h3 class="event-name"><a href="#event-selected">selected</a></h3>
<dl>
<dt class="event-type-label">Type:</dt>
<dd class="event-type">selectableselected</dd>
</dl>
</div>
<div class="event-description">
<p>This event is triggered at the end of the select operation, on each element added to the selection.</p>
</div>
<div class="event-examples">
<h4>Code examples</h4>
<dl class="event-examples-list">
<dt>
Supply a callback function to handle the <code>selected</code> event as an init option.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).selectable({
selected: function(event, ui) { ... }
});</code></pre>
</dd>
<dt>
Bind to the <code>selected</code> event by type: <code>selectableselected</code>.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).bind( &quot;selectableselected&quot;, function(event, ui) {
...
});</code></pre>
</dd>
</dl>
</div>
</li>
<li class="event" id="event-selecting">
<div class="event-header">
<h3 class="event-name"><a href="#event-selecting">selecting</a></h3>
<dl>
<dt class="event-type-label">Type:</dt>
<dd class="event-type">selectableselecting</dd>
</dl>
</div>
<div class="event-description">
<p>This event is triggered during the select operation, on each element added to the selection.</p>
</div>
<div class="event-examples">
<h4>Code examples</h4>
<dl class="event-examples-list">
<dt>
Supply a callback function to handle the <code>selecting</code> event as an init option.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).selectable({
selecting: function(event, ui) { ... }
});</code></pre>
</dd>
<dt>
Bind to the <code>selecting</code> event by type: <code>selectableselecting</code>.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).bind( &quot;selectableselecting&quot;, function(event, ui) {
...
});</code></pre>
</dd>
</dl>
</div>
</li>
<li class="event" id="event-start">
<div class="event-header">
<h3 class="event-name"><a href="#event-start">start</a></h3>
<dl>
<dt class="event-type-label">Type:</dt>
<dd class="event-type">selectablestart</dd>
</dl>
</div>
<div class="event-description">
<p>This event is triggered at the beginning of the select operation.</p>
</div>
<div class="event-examples">
<h4>Code examples</h4>
<dl class="event-examples-list">
<dt>
Supply a callback function to handle the <code>start</code> event as an init option.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).selectable({
start: function(event, ui) { ... }
});</code></pre>
</dd>
<dt>
Bind to the <code>start</code> event by type: <code>selectablestart</code>.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).bind( &quot;selectablestart&quot;, function(event, ui) {
...
});</code></pre>
</dd>
</dl>
</div>
</li>
<li class="event" id="event-stop">
<div class="event-header">
<h3 class="event-name"><a href="#event-stop">stop</a></h3>
<dl>
<dt class="event-type-label">Type:</dt>
<dd class="event-type">selectablestop</dd>
</dl>
</div>
<div class="event-description">
<p>This event is triggered at the end of the select operation.</p>
</div>
<div class="event-examples">
<h4>Code examples</h4>
<dl class="event-examples-list">
<dt>
Supply a callback function to handle the <code>stop</code> event as an init option.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).selectable({
stop: function(event, ui) { ... }
});</code></pre>
</dd>
<dt>
Bind to the <code>stop</code> event by type: <code>selectablestop</code>.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).bind( &quot;selectablestop&quot;, function(event, ui) {
...
});</code></pre>
</dd>
</dl>
</div>
</li>
<li class="event" id="event-unselected">
<div class="event-header">
<h3 class="event-name"><a href="#event-unselected">unselected</a></h3>
<dl>
<dt class="event-type-label">Type:</dt>
<dd class="event-type">selectableunselected</dd>
</dl>
</div>
<div class="event-description">
<p>This event is triggered at the end of the select operation, on each element removed from the selection.</p>
</div>
<div class="event-examples">
<h4>Code examples</h4>
<dl class="event-examples-list">
<dt>
Supply a callback function to handle the <code>unselected</code> event as an init option.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).selectable({
unselected: function(event, ui) { ... }
});</code></pre>
</dd>
<dt>
Bind to the <code>unselected</code> event by type: <code>selectableunselected</code>.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).bind( &quot;selectableunselected&quot;, function(event, ui) {
...
});</code></pre>
</dd>
</dl>
</div>
</li>
<li class="event" id="event-unselecting">
<div class="event-header">
<h3 class="event-name"><a href="#event-unselecting">unselecting</a></h3>
<dl>
<dt class="event-type-label">Type:</dt>
<dd class="event-type">selectableunselecting</dd>
</dl>
</div>
<div class="event-description">
<p>This event is triggered during the select operation, on each element removed from the selection.</p>
</div>
<div class="event-examples">
<h4>Code examples</h4>
<dl class="event-examples-list">
<dt>
Supply a callback function to handle the <code>unselecting</code> event as an init option.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).selectable({
unselecting: function(event, ui) { ... }
});</code></pre>
</dd>
<dt>
Bind to the <code>unselecting</code> event by type: <code>selectableunselecting</code>.
</dt>
<dd>
<pre><code>$( &quot;.selector&quot; ).bind( &quot;selectableunselecting&quot;, function(event, ui) {
...
});</code></pre>
</dd>
</dl>
</div>
</li>
</ul>
</div>
<div id="methods">
<h2 class="top-header">Methods</h2>
<ul class="methods-list">
<li class="method" id="method-destroy">
<div class="method-header">
<h3 class="method-name"><a href="#method-destroy">destroy</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "destroy"
)</dd>
</dl>
</div>
<div class="method-description">
<p>Remove the selectable functionality completely. This will return the element back to its pre-init state.</p>
</div>
</li>
<li class="method" id="method-disable">
<div class="method-header">
<h3 class="method-name"><a href="#method-disable">disable</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "disable"
)</dd>
</dl>
</div>
<div class="method-description">
<p>Disable the selectable.</p>
</div>
</li>
<li class="method" id="method-enable">
<div class="method-header">
<h3 class="method-name"><a href="#method-enable">enable</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "enable"
)</dd>
</dl>
</div>
<div class="method-description">
<p>Enable the selectable.</p>
</div>
</li>
<li class="method" id="method-option">
<div class="method-header">
<h3 class="method-name"><a href="#method-option">option</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "option"
, optionName
, <span class="optional">[</span>value<span class="optional">] </span>
)</dd>
</dl>
</div>
<div class="method-description">
<p>Get or set any selectable option. If no value is specified, will act as a getter.</p>
</div>
</li>
<li class="method" id="method-option">
<div class="method-header">
<h3 class="method-name"><a href="#method-option">option</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "option"
, options
)</dd>
</dl>
</div>
<div class="method-description">
<p>Set multiple selectable options at once by providing an options object.</p>
</div>
</li>
<li class="method" id="method-widget">
<div class="method-header">
<h3 class="method-name"><a href="#method-widget">widget</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "widget"
)</dd>
</dl>
</div>
<div class="method-description">
<p>Returns the .ui-selectable element.</p>
</div>
</li>
<li class="method" id="method-refresh">
<div class="method-header">
<h3 class="method-name"><a href="#method-refresh">refresh</a></h3>
<dl>
<dt class="method-signature-label">Signature:</dt>
<dd class="method-signature">.selectable( "refresh"
)</dd>
</dl>
</div>
<div class="method-description">
<p>Refresh the position and size of each selectee element. This method can be used to manually recalculate the position and size of each selectee element. Very useful if autoRefresh is set to false.</p>
</div>
</li>
</ul>
</div>
<div id="theming">
<h2 class="top-header">Theming</h2>
<p>The jQuery UI Selectable plugin uses the jQuery UI CSS Framework to style its look and feel, including colors and background textures. We recommend using the ThemeRoller tool to create and download custom themes that are easy to build and maintain.
</p>
<p>If a deeper level of customization is needed, there are widget-specific classes referenced within the jquery.ui.selectable.css stylesheet that can be modified. These classes are highlighed in bold below.
</p>
<h3>Sample markup with jQuery UI CSS Framework classes</h3>
&lt;ul class=&quot;<strong>ui-selectable</strong>&quot;&gt;<br />
&#160;&#160;&#160;&lt;li class=&quot;<strong>ui-selectee</strong>&quot;&gt;&lt;/li&gt;<br />
&#160;&#160;&#160;&lt;li class=&quot;<strong>ui-selectee</strong>&quot;&gt;&lt;/li&gt;<br />
&#160;&#160;&#160;&lt;li class=&quot;<strong>ui-selectee</strong>&quot;&gt;&lt;/li&gt;<br />
&lt;/ul&gt;
<p class="theme-note">
<strong>
Note: This is a sample of markup generated by the selectable plugin, not markup you should use to create a selectable. The only markup needed for that is <br />&lt;ul&gt;<br />
&#160;&#160;&#160;&lt;li&gt;&lt;/li&gt;<br />
&#160;&#160;&#160;&lt;li&gt;&lt;/li&gt;<br />
&#160;&#160;&#160;&lt;li&gt;&lt;/li&gt;<br />
&lt;/ul&gt;.
</strong>
</p>
</div>
</div>
</p><!--
Pre-expand include size: 33182 bytes
Post-expand include size: 51437 bytes
Template argument size: 26605 bytes
Maximum: 2097152 bytes
-->
<!-- Saved in parser cache with key jqdocs_docs:pcache:idhash:3771-1!1!0!!en!2 and timestamp 20101025034632 -->