web/wp-includes/js/jcrop/jquery.Jcrop.dev.js
changeset 1 0d28b7c10758
equal deleted inserted replaced
0:0d9a58d2c515 1:0d28b7c10758
       
     1 /**
       
     2  * jquery.Jcrop.js v0.9.8
       
     3  * jQuery Image Cropping Plugin
       
     4  * @author Kelly Hallman <khallman@gmail.com>
       
     5  * Copyright (c) 2008-2009 Kelly Hallman - released under MIT License {{{
       
     6  *
       
     7  * Permission is hereby granted, free of charge, to any person
       
     8  * obtaining a copy of this software and associated documentation
       
     9  * files (the "Software"), to deal in the Software without
       
    10  * restriction, including without limitation the rights to use,
       
    11  * copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    12  * copies of the Software, and to permit persons to whom the
       
    13  * Software is furnished to do so, subject to the following
       
    14  * conditions:
       
    15 
       
    16  * The above copyright notice and this permission notice shall be
       
    17  * included in all copies or substantial portions of the Software.
       
    18 
       
    19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
       
    21  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       
    22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    23  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       
    24  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
       
    25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
       
    26  * OTHER DEALINGS IN THE SOFTWARE.
       
    27 
       
    28  * }}}
       
    29  */
       
    30 
       
    31 (function($) {
       
    32 
       
    33 $.Jcrop = function(obj,opt)
       
    34 {
       
    35 	// Initialization {{{
       
    36 
       
    37 	// Sanitize some options {{{
       
    38 	var obj = obj, opt = opt;
       
    39 
       
    40 	if (typeof(obj) !== 'object') obj = $(obj)[0];
       
    41 	if (typeof(opt) !== 'object') opt = { };
       
    42 
       
    43 	// Some on-the-fly fixes for MSIE...sigh
       
    44 	if (!('trackDocument' in opt))
       
    45 	{
       
    46 		opt.trackDocument = $.browser.msie ? false : true;
       
    47 		if ($.browser.msie && $.browser.version.split('.')[0] == '8')
       
    48 			opt.trackDocument = true;
       
    49 	}
       
    50 
       
    51 	if (!('keySupport' in opt))
       
    52 			opt.keySupport = $.browser.msie ? false : true;
       
    53 		
       
    54 	// }}}
       
    55 	// Extend the default options {{{
       
    56 	var defaults = {
       
    57 
       
    58 		// Basic Settings
       
    59 		trackDocument:		false,
       
    60 		baseClass:			'jcrop',
       
    61 		addClass:			null,
       
    62 
       
    63 		// Styling Options
       
    64 		bgColor:			'black',
       
    65 		bgOpacity:			.6,
       
    66 		borderOpacity:		.4,
       
    67 		handleOpacity:		.5,
       
    68 
       
    69 		handlePad:			5,
       
    70 		handleSize:			9,
       
    71 		handleOffset:		5,
       
    72 		edgeMargin:			14,
       
    73 
       
    74 		aspectRatio:		0,
       
    75 		keySupport:			true,
       
    76 		cornerHandles:		true,
       
    77 		sideHandles:		true,
       
    78 		drawBorders:		true,
       
    79 		dragEdges:			true,
       
    80 
       
    81 		boxWidth:			0,
       
    82 		boxHeight:			0,
       
    83 
       
    84 		boundary:			8,
       
    85 		animationDelay:		20,
       
    86 		swingSpeed:			3,
       
    87 
       
    88 		allowSelect:		true,
       
    89 		allowMove:			true,
       
    90 		allowResize:		true,
       
    91 
       
    92 		minSelect:			[ 0, 0 ],
       
    93 		maxSize:			[ 0, 0 ],
       
    94 		minSize:			[ 0, 0 ],
       
    95 
       
    96 		// Callbacks / Event Handlers
       
    97 		onChange: function() { },
       
    98 		onSelect: function() { }
       
    99 
       
   100 	};
       
   101 	var options = defaults;
       
   102 	setOptions(opt);
       
   103 
       
   104 	// }}}
       
   105 	// Initialize some jQuery objects {{{
       
   106 
       
   107 	var $origimg = $(obj);
       
   108 	var $img = $origimg.clone().removeAttr('id').css({ position: 'absolute' });
       
   109 
       
   110 	$img.width($origimg.width());
       
   111 	$img.height($origimg.height());
       
   112 	$origimg.after($img).hide();
       
   113 
       
   114 	presize($img,options.boxWidth,options.boxHeight);
       
   115 
       
   116 	var boundx = $img.width(),
       
   117 		boundy = $img.height(),
       
   118 
       
   119 		$div = $('<div />')
       
   120 			.width(boundx).height(boundy)
       
   121 			.addClass(cssClass('holder'))
       
   122 			.css({
       
   123 				position: 'relative',
       
   124 				backgroundColor: options.bgColor
       
   125 			}).insertAfter($origimg).append($img);
       
   126 	;
       
   127 	
       
   128 	if (options.addClass) $div.addClass(options.addClass);
       
   129 	//$img.wrap($div);
       
   130 
       
   131 	var $img2 = $('<img />')/*{{{*/
       
   132 			.attr('src',$img.attr('src'))
       
   133 			.css('position','absolute')
       
   134 			.width(boundx).height(boundy)
       
   135 	;/*}}}*/
       
   136 	var $img_holder = $('<div />')/*{{{*/
       
   137 		.width(pct(100)).height(pct(100))
       
   138 		.css({
       
   139 			zIndex: 310,
       
   140 			position: 'absolute',
       
   141 			overflow: 'hidden'
       
   142 		})
       
   143 		.append($img2)
       
   144 	;/*}}}*/
       
   145 	var $hdl_holder = $('<div />')/*{{{*/
       
   146 		.width(pct(100)).height(pct(100))
       
   147 		.css('zIndex',320);
       
   148 	/*}}}*/
       
   149 	var $sel = $('<div />')/*{{{*/
       
   150 		.css({
       
   151 			position: 'absolute',
       
   152 			zIndex: 300
       
   153 		})
       
   154 		.insertBefore($img)
       
   155 		.append($img_holder,$hdl_holder)
       
   156 	;/*}}}*/
       
   157 
       
   158 	var bound = options.boundary;
       
   159 	var $trk = newTracker().width(boundx+(bound*2)).height(boundy+(bound*2))
       
   160 		.css({ position: 'absolute', top: px(-bound), left: px(-bound), zIndex: 290 })
       
   161 		.mousedown(newSelection);	
       
   162 	
       
   163 	/* }}} */
       
   164 	// Set more variables {{{
       
   165 
       
   166 	var xlimit, ylimit, xmin, ymin;
       
   167 	var xscale, yscale, enabled = true;
       
   168 	var docOffset = getPos($img),
       
   169 		// Internal states
       
   170 		btndown, lastcurs, dimmed, animating,
       
   171 		shift_down;
       
   172 
       
   173 	// }}}
       
   174 		
       
   175 
       
   176 		// }}}
       
   177 	// Internal Modules {{{
       
   178 
       
   179 	var Coords = function()/*{{{*/
       
   180 	{
       
   181 		var x1 = 0, y1 = 0, x2 = 0, y2 = 0, ox, oy;
       
   182 
       
   183 		function setPressed(pos)/*{{{*/
       
   184 		{
       
   185 			var pos = rebound(pos);
       
   186 			x2 = x1 = pos[0];
       
   187 			y2 = y1 = pos[1];
       
   188 		};
       
   189 		/*}}}*/
       
   190 		function setCurrent(pos)/*{{{*/
       
   191 		{
       
   192 			var pos = rebound(pos);
       
   193 			ox = pos[0] - x2;
       
   194 			oy = pos[1] - y2;
       
   195 			x2 = pos[0];
       
   196 			y2 = pos[1];
       
   197 		};
       
   198 		/*}}}*/
       
   199 		function getOffset()/*{{{*/
       
   200 		{
       
   201 			return [ ox, oy ];
       
   202 		};
       
   203 		/*}}}*/
       
   204 		function moveOffset(offset)/*{{{*/
       
   205 		{
       
   206 			var ox = offset[0], oy = offset[1];
       
   207 
       
   208 			if (0 > x1 + ox) ox -= ox + x1;
       
   209 			if (0 > y1 + oy) oy -= oy + y1;
       
   210 
       
   211 			if (boundy < y2 + oy) oy += boundy - (y2 + oy);
       
   212 			if (boundx < x2 + ox) ox += boundx - (x2 + ox);
       
   213 
       
   214 			x1 += ox;
       
   215 			x2 += ox;
       
   216 			y1 += oy;
       
   217 			y2 += oy;
       
   218 		};
       
   219 		/*}}}*/
       
   220 		function getCorner(ord)/*{{{*/
       
   221 		{
       
   222 			var c = getFixed();
       
   223 			switch(ord)
       
   224 			{
       
   225 				case 'ne': return [ c.x2, c.y ];
       
   226 				case 'nw': return [ c.x, c.y ];
       
   227 				case 'se': return [ c.x2, c.y2 ];
       
   228 				case 'sw': return [ c.x, c.y2 ];
       
   229 			}
       
   230 		};
       
   231 		/*}}}*/
       
   232 		function getFixed()/*{{{*/
       
   233 		{
       
   234 			if (!options.aspectRatio) return getRect();
       
   235 			// This function could use some optimization I think...
       
   236 			var aspect = options.aspectRatio,
       
   237 				min_x = options.minSize[0]/xscale, 
       
   238 				min_y = options.minSize[1]/yscale,
       
   239 				max_x = options.maxSize[0]/xscale, 
       
   240 				max_y = options.maxSize[1]/yscale,
       
   241 				rw = x2 - x1,
       
   242 				rh = y2 - y1,
       
   243 				rwa = Math.abs(rw),
       
   244 				rha = Math.abs(rh),
       
   245 				real_ratio = rwa / rha,
       
   246 				xx, yy
       
   247 			;
       
   248 			if (max_x == 0) { max_x = boundx * 10 }
       
   249 			if (max_y == 0) { max_y = boundy * 10 }
       
   250 			if (real_ratio < aspect)
       
   251 			{
       
   252 				yy = y2;
       
   253 				w = rha * aspect;
       
   254 				xx = rw < 0 ? x1 - w : w + x1;
       
   255 
       
   256 				if (xx < 0)
       
   257 				{
       
   258 					xx = 0;
       
   259 					h = Math.abs((xx - x1) / aspect);
       
   260 					yy = rh < 0 ? y1 - h: h + y1;
       
   261 				}
       
   262 				else if (xx > boundx)
       
   263 				{
       
   264 					xx = boundx;
       
   265 					h = Math.abs((xx - x1) / aspect);
       
   266 					yy = rh < 0 ? y1 - h : h + y1;
       
   267 				}
       
   268 			}
       
   269 			else
       
   270 			{
       
   271 				xx = x2;
       
   272 				h = rwa / aspect;
       
   273 				yy = rh < 0 ? y1 - h : y1 + h;
       
   274 				if (yy < 0)
       
   275 				{
       
   276 					yy = 0;
       
   277 					w = Math.abs((yy - y1) * aspect);
       
   278 					xx = rw < 0 ? x1 - w : w + x1;
       
   279 				}
       
   280 				else if (yy > boundy)
       
   281 				{
       
   282 					yy = boundy;
       
   283 					w = Math.abs(yy - y1) * aspect;
       
   284 					xx = rw < 0 ? x1 - w : w + x1;
       
   285 				}
       
   286 			}
       
   287 
       
   288 			// Magic %-)
       
   289 			if(xx > x1) { // right side
       
   290 			  if(xx - x1 < min_x) {
       
   291 				xx = x1 + min_x;
       
   292 			  } else if (xx - x1 > max_x) {
       
   293 				xx = x1 + max_x;
       
   294 			  }
       
   295 			  if(yy > y1) {
       
   296 				yy = y1 + (xx - x1)/aspect;
       
   297 			  } else {
       
   298 				yy = y1 - (xx - x1)/aspect;
       
   299 			  }
       
   300 			} else if (xx < x1) { // left side
       
   301 			  if(x1 - xx < min_x) {
       
   302 				xx = x1 - min_x
       
   303 			  } else if (x1 - xx > max_x) {
       
   304 				xx = x1 - max_x;
       
   305 			  }
       
   306 			  if(yy > y1) {
       
   307 				yy = y1 + (x1 - xx)/aspect;
       
   308 			  } else {
       
   309 				yy = y1 - (x1 - xx)/aspect;
       
   310 			  }
       
   311 			}
       
   312 
       
   313 			if(xx < 0) {
       
   314 				x1 -= xx;
       
   315 				xx = 0;
       
   316 			} else  if (xx > boundx) {
       
   317 				x1 -= xx - boundx;
       
   318 				xx = boundx;
       
   319 			}
       
   320 
       
   321 			if(yy < 0) {
       
   322 				y1 -= yy;
       
   323 				yy = 0;
       
   324 			} else  if (yy > boundy) {
       
   325 				y1 -= yy - boundy;
       
   326 				yy = boundy;
       
   327 			}
       
   328 
       
   329 			return last = makeObj(flipCoords(x1,y1,xx,yy));
       
   330 		};
       
   331 		/*}}}*/
       
   332 		function rebound(p)/*{{{*/
       
   333 		{
       
   334 			if (p[0] < 0) p[0] = 0;
       
   335 			if (p[1] < 0) p[1] = 0;
       
   336 
       
   337 			if (p[0] > boundx) p[0] = boundx;
       
   338 			if (p[1] > boundy) p[1] = boundy;
       
   339 
       
   340 			return [ p[0], p[1] ];
       
   341 		};
       
   342 		/*}}}*/
       
   343 		function flipCoords(x1,y1,x2,y2)/*{{{*/
       
   344 		{
       
   345 			var xa = x1, xb = x2, ya = y1, yb = y2;
       
   346 			if (x2 < x1)
       
   347 			{
       
   348 				xa = x2;
       
   349 				xb = x1;
       
   350 			}
       
   351 			if (y2 < y1)
       
   352 			{
       
   353 				ya = y2;
       
   354 				yb = y1;
       
   355 			}
       
   356 			return [ Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb) ];
       
   357 		};
       
   358 		/*}}}*/
       
   359 		function getRect()/*{{{*/
       
   360 		{
       
   361 			var xsize = x2 - x1;
       
   362 			var ysize = y2 - y1;
       
   363 
       
   364 			if (xlimit && (Math.abs(xsize) > xlimit))
       
   365 				x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
       
   366 			if (ylimit && (Math.abs(ysize) > ylimit))
       
   367 				y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
       
   368 
       
   369 			if (ymin && (Math.abs(ysize) < ymin))
       
   370 				y2 = (ysize > 0) ? (y1 + ymin) : (y1 - ymin);
       
   371 			if (xmin && (Math.abs(xsize) < xmin))
       
   372 				x2 = (xsize > 0) ? (x1 + xmin) : (x1 - xmin);
       
   373 
       
   374 			if (x1 < 0) { x2 -= x1; x1 -= x1; }
       
   375 			if (y1 < 0) { y2 -= y1; y1 -= y1; }
       
   376 			if (x2 < 0) { x1 -= x2; x2 -= x2; }
       
   377 			if (y2 < 0) { y1 -= y2; y2 -= y2; }
       
   378 			if (x2 > boundx) { var delta = x2 - boundx; x1 -= delta; x2 -= delta; }
       
   379 			if (y2 > boundy) { var delta = y2 - boundy; y1 -= delta; y2 -= delta; }
       
   380 			if (x1 > boundx) { var delta = x1 - boundy; y2 -= delta; y1 -= delta; }
       
   381 			if (y1 > boundy) { var delta = y1 - boundy; y2 -= delta; y1 -= delta; }
       
   382 
       
   383 			return makeObj(flipCoords(x1,y1,x2,y2));
       
   384 		};
       
   385 		/*}}}*/
       
   386 		function makeObj(a)/*{{{*/
       
   387 		{
       
   388 			return { x: a[0], y: a[1], x2: a[2], y2: a[3],
       
   389 				w: a[2] - a[0], h: a[3] - a[1] };
       
   390 		};
       
   391 		/*}}}*/
       
   392 
       
   393 		return {
       
   394 			flipCoords: flipCoords,
       
   395 			setPressed: setPressed,
       
   396 			setCurrent: setCurrent,
       
   397 			getOffset: getOffset,
       
   398 			moveOffset: moveOffset,
       
   399 			getCorner: getCorner,
       
   400 			getFixed: getFixed
       
   401 		};
       
   402 	}();
       
   403 
       
   404 	/*}}}*/
       
   405 	var Selection = function()/*{{{*/
       
   406 	{
       
   407 		var start, end, dragmode, awake, hdep = 370;
       
   408 		var borders = { };
       
   409 		var handle = { };
       
   410 		var seehandles = false;
       
   411 		var hhs = options.handleOffset;
       
   412 
       
   413 		/* Insert draggable elements {{{*/
       
   414 
       
   415 		// Insert border divs for outline
       
   416 		if (options.drawBorders) {
       
   417 			borders = {
       
   418 					top: insertBorder('hline')
       
   419 						.css('top',$.browser.msie?px(-1):px(0)),
       
   420 					bottom: insertBorder('hline'),
       
   421 					left: insertBorder('vline'),
       
   422 					right: insertBorder('vline')
       
   423 			};
       
   424 		}
       
   425 
       
   426 		// Insert handles on edges
       
   427 		if (options.dragEdges) {
       
   428 			handle.t = insertDragbar('n');
       
   429 			handle.b = insertDragbar('s');
       
   430 			handle.r = insertDragbar('e');
       
   431 			handle.l = insertDragbar('w');
       
   432 		}
       
   433 
       
   434 		// Insert side handles
       
   435 		options.sideHandles &&
       
   436 			createHandles(['n','s','e','w']);
       
   437 
       
   438 		// Insert corner handles
       
   439 		options.cornerHandles &&
       
   440 			createHandles(['sw','nw','ne','se']);
       
   441 
       
   442 		/*}}}*/
       
   443 		// Private Methods
       
   444 		function insertBorder(type)/*{{{*/
       
   445 		{
       
   446 			var jq = $('<div />')
       
   447 				.css({position: 'absolute', opacity: options.borderOpacity })
       
   448 				.addClass(cssClass(type));
       
   449 			$img_holder.append(jq);
       
   450 			return jq;
       
   451 		};
       
   452 		/*}}}*/
       
   453 		function dragDiv(ord,zi)/*{{{*/
       
   454 		{
       
   455 			var jq = $('<div />')
       
   456 				.mousedown(createDragger(ord))
       
   457 				.css({
       
   458 					cursor: ord+'-resize',
       
   459 					position: 'absolute',
       
   460 					zIndex: zi 
       
   461 				})
       
   462 			;
       
   463 			$hdl_holder.append(jq);
       
   464 			return jq;
       
   465 		};
       
   466 		/*}}}*/
       
   467 		function insertHandle(ord)/*{{{*/
       
   468 		{
       
   469 			return dragDiv(ord,hdep++)
       
   470 				.css({ top: px(-hhs+1), left: px(-hhs+1), opacity: options.handleOpacity })
       
   471 				.addClass(cssClass('handle'));
       
   472 		};
       
   473 		/*}}}*/
       
   474 		function insertDragbar(ord)/*{{{*/
       
   475 		{
       
   476 			var s = options.handleSize,
       
   477 				o = hhs,
       
   478 				h = s, w = s,
       
   479 				t = o, l = o;
       
   480 
       
   481 			switch(ord)
       
   482 			{
       
   483 				case 'n': case 's': w = pct(100); break;
       
   484 				case 'e': case 'w': h = pct(100); break;
       
   485 			}
       
   486 
       
   487 			return dragDiv(ord,hdep++).width(w).height(h)
       
   488 				.css({ top: px(-t+1), left: px(-l+1)});
       
   489 		};
       
   490 		/*}}}*/
       
   491 		function createHandles(li)/*{{{*/
       
   492 		{
       
   493 			for(i in li) handle[li[i]] = insertHandle(li[i]);
       
   494 		};
       
   495 		/*}}}*/
       
   496 		function moveHandles(c)/*{{{*/
       
   497 		{
       
   498 			var midvert  = Math.round((c.h / 2) - hhs),
       
   499 				midhoriz = Math.round((c.w / 2) - hhs),
       
   500 				north = west = -hhs+1,
       
   501 				east = c.w - hhs,
       
   502 				south = c.h - hhs,
       
   503 				x, y;
       
   504 
       
   505 			'e' in handle &&
       
   506 				handle.e.css({ top: px(midvert), left: px(east) }) &&
       
   507 				handle.w.css({ top: px(midvert) }) &&
       
   508 				handle.s.css({ top: px(south), left: px(midhoriz) }) &&
       
   509 				handle.n.css({ left: px(midhoriz) });
       
   510 
       
   511 			'ne' in handle &&
       
   512 				handle.ne.css({ left: px(east) }) &&
       
   513 				handle.se.css({ top: px(south), left: px(east) }) &&
       
   514 				handle.sw.css({ top: px(south) });
       
   515 
       
   516 			'b' in handle &&
       
   517 				handle.b.css({ top: px(south) }) &&
       
   518 				handle.r.css({ left: px(east) });
       
   519 		};
       
   520 		/*}}}*/
       
   521 		function moveto(x,y)/*{{{*/
       
   522 		{
       
   523 			$img2.css({ top: px(-y), left: px(-x) });
       
   524 			$sel.css({ top: px(y), left: px(x) });
       
   525 		};
       
   526 		/*}}}*/
       
   527 		function resize(w,h)/*{{{*/
       
   528 		{
       
   529 			$sel.width(w).height(h);
       
   530 		};
       
   531 		/*}}}*/
       
   532 		function refresh()/*{{{*/
       
   533 		{
       
   534 			var c = Coords.getFixed();
       
   535 
       
   536 			Coords.setPressed([c.x,c.y]);
       
   537 			Coords.setCurrent([c.x2,c.y2]);
       
   538 
       
   539 			updateVisible();
       
   540 		};
       
   541 		/*}}}*/
       
   542 
       
   543 		// Internal Methods
       
   544 		function updateVisible()/*{{{*/
       
   545 			{ if (awake) return update(); };
       
   546 		/*}}}*/
       
   547 		function update()/*{{{*/
       
   548 		{
       
   549 			var c = Coords.getFixed();
       
   550 
       
   551 			resize(c.w,c.h);
       
   552 			moveto(c.x,c.y);
       
   553 
       
   554 			options.drawBorders &&
       
   555 				borders['right'].css({ left: px(c.w-1) }) &&
       
   556 					borders['bottom'].css({ top: px(c.h-1) });
       
   557 
       
   558 			seehandles && moveHandles(c);
       
   559 			awake || show();
       
   560 
       
   561 			options.onChange(unscale(c));
       
   562 		};
       
   563 		/*}}}*/
       
   564 		function show()/*{{{*/
       
   565 		{
       
   566 			$sel.show();
       
   567 			$img.css('opacity',options.bgOpacity);
       
   568 			awake = true;
       
   569 		};
       
   570 		/*}}}*/
       
   571 		function release()/*{{{*/
       
   572 		{
       
   573 			disableHandles();
       
   574 			$sel.hide();
       
   575 			$img.css('opacity',1);
       
   576 			awake = false;
       
   577 		};
       
   578 		/*}}}*/
       
   579 		function showHandles()//{{{
       
   580 		{
       
   581 			if (seehandles)
       
   582 			{
       
   583 				moveHandles(Coords.getFixed());
       
   584 				$hdl_holder.show();
       
   585 			}
       
   586 		};
       
   587 		//}}}
       
   588 		function enableHandles()/*{{{*/
       
   589 		{ 
       
   590 			seehandles = true;
       
   591 			if (options.allowResize)
       
   592 			{
       
   593 				moveHandles(Coords.getFixed());
       
   594 				$hdl_holder.show();
       
   595 				return true;
       
   596 			}
       
   597 		};
       
   598 		/*}}}*/
       
   599 		function disableHandles()/*{{{*/
       
   600 		{
       
   601 			seehandles = false;
       
   602 			$hdl_holder.hide();
       
   603 		};
       
   604 		/*}}}*/
       
   605 		function animMode(v)/*{{{*/
       
   606 		{
       
   607 			(animating = v) ? disableHandles(): enableHandles();
       
   608 		};
       
   609 		/*}}}*/
       
   610 		function done()/*{{{*/
       
   611 		{
       
   612 			animMode(false);
       
   613 			refresh();
       
   614 		};
       
   615 		/*}}}*/
       
   616 
       
   617 		var $track = newTracker().mousedown(createDragger('move'))
       
   618 				.css({ cursor: 'move', position: 'absolute', zIndex: 360 })
       
   619 
       
   620 		$img_holder.append($track);
       
   621 		disableHandles();
       
   622 
       
   623 		return {
       
   624 			updateVisible: updateVisible,
       
   625 			update: update,
       
   626 			release: release,
       
   627 			refresh: refresh,
       
   628 			setCursor: function (cursor) { $track.css('cursor',cursor); },
       
   629 			enableHandles: enableHandles,
       
   630 			enableOnly: function() { seehandles = true; },
       
   631 			showHandles: showHandles,
       
   632 			disableHandles: disableHandles,
       
   633 			animMode: animMode,
       
   634 			done: done
       
   635 		};
       
   636 	}();
       
   637 	/*}}}*/
       
   638 	var Tracker = function()/*{{{*/
       
   639 	{
       
   640 		var onMove		= function() { },
       
   641 			onDone		= function() { },
       
   642 			trackDoc	= options.trackDocument;
       
   643 
       
   644 		if (!trackDoc)
       
   645 		{
       
   646 			$trk
       
   647 				.mousemove(trackMove)
       
   648 				.mouseup(trackUp)
       
   649 				.mouseout(trackUp)
       
   650 			;
       
   651 		}
       
   652 
       
   653 		function toFront()/*{{{*/
       
   654 		{
       
   655 			$trk.css({zIndex:450});
       
   656 			if (trackDoc)
       
   657 			{
       
   658 				$(document)
       
   659 					.mousemove(trackMove)
       
   660 					.mouseup(trackUp)
       
   661 				;
       
   662 			}
       
   663 		}
       
   664 		/*}}}*/
       
   665 		function toBack()/*{{{*/
       
   666 		{
       
   667 			$trk.css({zIndex:290});
       
   668 			if (trackDoc)
       
   669 			{
       
   670 				$(document)
       
   671 					.unbind('mousemove',trackMove)
       
   672 					.unbind('mouseup',trackUp)
       
   673 				;
       
   674 			}
       
   675 		}
       
   676 		/*}}}*/
       
   677 		function trackMove(e)/*{{{*/
       
   678 		{
       
   679 			onMove(mouseAbs(e));
       
   680 		};
       
   681 		/*}}}*/
       
   682 		function trackUp(e)/*{{{*/
       
   683 		{
       
   684 			e.preventDefault();
       
   685 			e.stopPropagation();
       
   686 
       
   687 			if (btndown)
       
   688 			{
       
   689 				btndown = false;
       
   690 
       
   691 				onDone(mouseAbs(e));
       
   692 				options.onSelect(unscale(Coords.getFixed()));
       
   693 				toBack();
       
   694 				onMove = function() { };
       
   695 				onDone = function() { };
       
   696 			}
       
   697 
       
   698 			return false;
       
   699 		};
       
   700 		/*}}}*/
       
   701 
       
   702 		function activateHandlers(move,done)/* {{{ */
       
   703 		{
       
   704 			btndown = true;
       
   705 			onMove = move;
       
   706 			onDone = done;
       
   707 			toFront();
       
   708 			return false;
       
   709 		};
       
   710 		/* }}} */
       
   711 
       
   712 		function setCursor(t) { $trk.css('cursor',t); };
       
   713 
       
   714 		$img.before($trk);
       
   715 		return {
       
   716 			activateHandlers: activateHandlers,
       
   717 			setCursor: setCursor
       
   718 		};
       
   719 	}();
       
   720 	/*}}}*/
       
   721 	var KeyManager = function()/*{{{*/
       
   722 	{
       
   723 		var $keymgr = $('<input type="radio" />')
       
   724 				.css({ position: 'absolute', left: '-30px' })
       
   725 				.keypress(parseKey)
       
   726 				.blur(onBlur),
       
   727 
       
   728 			$keywrap = $('<div />')
       
   729 				.css({
       
   730 					position: 'absolute',
       
   731 					overflow: 'hidden'
       
   732 				})
       
   733 				.append($keymgr)
       
   734 		;
       
   735 
       
   736 		function watchKeys()/*{{{*/
       
   737 		{
       
   738 			if (options.keySupport)
       
   739 			{
       
   740 				$keymgr.show();
       
   741 				$keymgr.focus();
       
   742 			}
       
   743 		};
       
   744 		/*}}}*/
       
   745 		function onBlur(e)/*{{{*/
       
   746 		{
       
   747 			$keymgr.hide();
       
   748 		};
       
   749 		/*}}}*/
       
   750 		function doNudge(e,x,y)/*{{{*/
       
   751 		{
       
   752 			if (options.allowMove) {
       
   753 				Coords.moveOffset([x,y]);
       
   754 				Selection.updateVisible();
       
   755 			};
       
   756 			e.preventDefault();
       
   757 			e.stopPropagation();
       
   758 		};
       
   759 		/*}}}*/
       
   760 		function parseKey(e)/*{{{*/
       
   761 		{
       
   762 			if (e.ctrlKey) return true;
       
   763 			shift_down = e.shiftKey ? true : false;
       
   764 			var nudge = shift_down ? 10 : 1;
       
   765 			switch(e.keyCode)
       
   766 			{
       
   767 				case 37: doNudge(e,-nudge,0); break;
       
   768 				case 39: doNudge(e,nudge,0); break;
       
   769 				case 38: doNudge(e,0,-nudge); break;
       
   770 				case 40: doNudge(e,0,nudge); break;
       
   771 
       
   772 				case 27: Selection.release(); break;
       
   773 
       
   774 				case 9: return true;
       
   775 			}
       
   776 
       
   777 			return nothing(e);
       
   778 		};
       
   779 		/*}}}*/
       
   780 		
       
   781 		if (options.keySupport) $keywrap.insertBefore($img);
       
   782 		return {
       
   783 			watchKeys: watchKeys
       
   784 		};
       
   785 	}();
       
   786 	/*}}}*/
       
   787 
       
   788 	// }}}
       
   789 	// Internal Methods {{{
       
   790 
       
   791 	function px(n) { return '' + parseInt(n) + 'px'; };
       
   792 	function pct(n) { return '' + parseInt(n) + '%'; };
       
   793 	function cssClass(cl) { return options.baseClass + '-' + cl; };
       
   794 	function getPos(obj)/*{{{*/
       
   795 	{
       
   796 		// Updated in v0.9.4 to use built-in dimensions plugin
       
   797 		var pos = $(obj).offset();
       
   798 		return [ pos.left, pos.top ];
       
   799 	};
       
   800 	/*}}}*/
       
   801 	function mouseAbs(e)/*{{{*/
       
   802 	{
       
   803 		return [ (e.pageX - docOffset[0]), (e.pageY - docOffset[1]) ];
       
   804 	};
       
   805 	/*}}}*/
       
   806 	function myCursor(type)/*{{{*/
       
   807 	{
       
   808 		if (type != lastcurs)
       
   809 		{
       
   810 			Tracker.setCursor(type);
       
   811 			//Handles.xsetCursor(type);
       
   812 			lastcurs = type;
       
   813 		}
       
   814 	};
       
   815 	/*}}}*/
       
   816 	function startDragMode(mode,pos)/*{{{*/
       
   817 	{
       
   818 		docOffset = getPos($img);
       
   819 		Tracker.setCursor(mode=='move'?mode:mode+'-resize');
       
   820 
       
   821 		if (mode == 'move')
       
   822 			return Tracker.activateHandlers(createMover(pos), doneSelect);
       
   823 
       
   824 		var fc = Coords.getFixed();
       
   825 		var opp = oppLockCorner(mode);
       
   826 		var opc = Coords.getCorner(oppLockCorner(opp));
       
   827 
       
   828 		Coords.setPressed(Coords.getCorner(opp));
       
   829 		Coords.setCurrent(opc);
       
   830 
       
   831 		Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);
       
   832 	};
       
   833 	/*}}}*/
       
   834 	function dragmodeHandler(mode,f)/*{{{*/
       
   835 	{
       
   836 		return function(pos) {
       
   837 			if (!options.aspectRatio) switch(mode)
       
   838 			{
       
   839 				case 'e': pos[1] = f.y2; break;
       
   840 				case 'w': pos[1] = f.y2; break;
       
   841 				case 'n': pos[0] = f.x2; break;
       
   842 				case 's': pos[0] = f.x2; break;
       
   843 			}
       
   844 			else switch(mode)
       
   845 			{
       
   846 				case 'e': pos[1] = f.y+1; break;
       
   847 				case 'w': pos[1] = f.y+1; break;
       
   848 				case 'n': pos[0] = f.x+1; break;
       
   849 				case 's': pos[0] = f.x+1; break;
       
   850 			}
       
   851 			Coords.setCurrent(pos);
       
   852 			Selection.update();
       
   853 		};
       
   854 	};
       
   855 	/*}}}*/
       
   856 	function createMover(pos)/*{{{*/
       
   857 	{
       
   858 		var lloc = pos;
       
   859 		KeyManager.watchKeys();
       
   860 
       
   861 		return function(pos)
       
   862 		{
       
   863 			Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
       
   864 			lloc = pos;
       
   865 			
       
   866 			Selection.update();
       
   867 		};
       
   868 	};
       
   869 	/*}}}*/
       
   870 	function oppLockCorner(ord)/*{{{*/
       
   871 	{
       
   872 		switch(ord)
       
   873 		{
       
   874 			case 'n': return 'sw';
       
   875 			case 's': return 'nw';
       
   876 			case 'e': return 'nw';
       
   877 			case 'w': return 'ne';
       
   878 			case 'ne': return 'sw';
       
   879 			case 'nw': return 'se';
       
   880 			case 'se': return 'nw';
       
   881 			case 'sw': return 'ne';
       
   882 		};
       
   883 	};
       
   884 	/*}}}*/
       
   885 	function createDragger(ord)/*{{{*/
       
   886 	{
       
   887 		return function(e) {
       
   888 			if (options.disabled) return false;
       
   889 			if ((ord == 'move') && !options.allowMove) return false;
       
   890 			btndown = true;
       
   891 			startDragMode(ord,mouseAbs(e));
       
   892 			e.stopPropagation();
       
   893 			e.preventDefault();
       
   894 			return false;
       
   895 		};
       
   896 	};
       
   897 	/*}}}*/
       
   898 	function presize($obj,w,h)/*{{{*/
       
   899 	{
       
   900 		var nw = $obj.width(), nh = $obj.height();
       
   901 		if ((nw > w) && w > 0)
       
   902 		{
       
   903 			nw = w;
       
   904 			nh = (w/$obj.width()) * $obj.height();
       
   905 		}
       
   906 		if ((nh > h) && h > 0)
       
   907 		{
       
   908 			nh = h;
       
   909 			nw = (h/$obj.height()) * $obj.width();
       
   910 		}
       
   911 		xscale = $obj.width() / nw;
       
   912 		yscale = $obj.height() / nh;
       
   913 		$obj.width(nw).height(nh);
       
   914 	};
       
   915 	/*}}}*/
       
   916 	function unscale(c)/*{{{*/
       
   917 	{
       
   918 		return {
       
   919 			x: parseInt(c.x * xscale), y: parseInt(c.y * yscale), 
       
   920 			x2: parseInt(c.x2 * xscale), y2: parseInt(c.y2 * yscale), 
       
   921 			w: parseInt(c.w * xscale), h: parseInt(c.h * yscale)
       
   922 		};
       
   923 	};
       
   924 	/*}}}*/
       
   925 	function doneSelect(pos)/*{{{*/
       
   926 	{
       
   927 		var c = Coords.getFixed();
       
   928 		if (c.w > options.minSelect[0] && c.h > options.minSelect[1])
       
   929 		{
       
   930 			Selection.enableHandles();
       
   931 			Selection.done();
       
   932 		}
       
   933 		else
       
   934 		{
       
   935 			Selection.release();
       
   936 		}
       
   937 		Tracker.setCursor( options.allowSelect?'crosshair':'default' );
       
   938 	};
       
   939 	/*}}}*/
       
   940 	function newSelection(e)/*{{{*/
       
   941 	{
       
   942 		if (options.disabled) return false;
       
   943 		if (!options.allowSelect) return false;
       
   944 		btndown = true;
       
   945 		docOffset = getPos($img);
       
   946 		Selection.disableHandles();
       
   947 		myCursor('crosshair');
       
   948 		var pos = mouseAbs(e);
       
   949 		Coords.setPressed(pos);
       
   950 		Tracker.activateHandlers(selectDrag,doneSelect);
       
   951 		KeyManager.watchKeys();
       
   952 		Selection.update();
       
   953 
       
   954 		e.stopPropagation();
       
   955 		e.preventDefault();
       
   956 		return false;
       
   957 	};
       
   958 	/*}}}*/
       
   959 	function selectDrag(pos)/*{{{*/
       
   960 	{
       
   961 		Coords.setCurrent(pos);
       
   962 		Selection.update();
       
   963 	};
       
   964 	/*}}}*/
       
   965 	function newTracker()
       
   966 	{
       
   967 		var trk = $('<div></div>').addClass(cssClass('tracker'));
       
   968 		$.browser.msie && trk.css({ opacity: 0, backgroundColor: 'white' });
       
   969 		return trk;
       
   970 	};
       
   971 
       
   972 	// }}}
       
   973 	// API methods {{{
       
   974 		
       
   975 	function animateTo(a)/*{{{*/
       
   976 	{
       
   977 		var x1 = a[0] / xscale,
       
   978 			y1 = a[1] / yscale,
       
   979 			x2 = a[2] / xscale,
       
   980 			y2 = a[3] / yscale;
       
   981 
       
   982 		if (animating) return;
       
   983 
       
   984 		var animto = Coords.flipCoords(x1,y1,x2,y2);
       
   985 		var c = Coords.getFixed();
       
   986 		var animat = initcr = [ c.x, c.y, c.x2, c.y2 ];
       
   987 		var interv = options.animationDelay;
       
   988 
       
   989 		var x = animat[0];
       
   990 		var y = animat[1];
       
   991 		var x2 = animat[2];
       
   992 		var y2 = animat[3];
       
   993 		var ix1 = animto[0] - initcr[0];
       
   994 		var iy1 = animto[1] - initcr[1];
       
   995 		var ix2 = animto[2] - initcr[2];
       
   996 		var iy2 = animto[3] - initcr[3];
       
   997 		var pcent = 0;
       
   998 		var velocity = options.swingSpeed;
       
   999 
       
  1000 		Selection.animMode(true);
       
  1001 
       
  1002 		var animator = function()
       
  1003 		{
       
  1004 			return function()
       
  1005 			{
       
  1006 				pcent += (100 - pcent) / velocity;
       
  1007 
       
  1008 				animat[0] = x + ((pcent / 100) * ix1);
       
  1009 				animat[1] = y + ((pcent / 100) * iy1);
       
  1010 				animat[2] = x2 + ((pcent / 100) * ix2);
       
  1011 				animat[3] = y2 + ((pcent / 100) * iy2);
       
  1012 
       
  1013 				if (pcent < 100) animateStart();
       
  1014 					else Selection.done();
       
  1015 
       
  1016 				if (pcent >= 99.8) pcent = 100;
       
  1017 
       
  1018 				setSelectRaw(animat);
       
  1019 			};
       
  1020 		}();
       
  1021 
       
  1022 		function animateStart()
       
  1023 			{ window.setTimeout(animator,interv); };
       
  1024 
       
  1025 		animateStart();
       
  1026 	};
       
  1027 	/*}}}*/
       
  1028 	function setSelect(rect)//{{{
       
  1029 	{
       
  1030 		setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);
       
  1031 	};
       
  1032 	//}}}
       
  1033 	function setSelectRaw(l) /*{{{*/
       
  1034 	{
       
  1035 		Coords.setPressed([l[0],l[1]]);
       
  1036 		Coords.setCurrent([l[2],l[3]]);
       
  1037 		Selection.update();
       
  1038 	};
       
  1039 	/*}}}*/
       
  1040 	function setOptions(opt)/*{{{*/
       
  1041 	{
       
  1042 		if (typeof(opt) != 'object') opt = { };
       
  1043 		options = $.extend(options,opt);
       
  1044 
       
  1045 		if (typeof(options.onChange)!=='function')
       
  1046 			options.onChange = function() { };
       
  1047 
       
  1048 		if (typeof(options.onSelect)!=='function')
       
  1049 			options.onSelect = function() { };
       
  1050 
       
  1051 	};
       
  1052 	/*}}}*/
       
  1053 	function tellSelect()/*{{{*/
       
  1054 	{
       
  1055 		return unscale(Coords.getFixed());
       
  1056 	};
       
  1057 	/*}}}*/
       
  1058 	function tellScaled()/*{{{*/
       
  1059 	{
       
  1060 		return Coords.getFixed();
       
  1061 	};
       
  1062 	/*}}}*/
       
  1063 	function setOptionsNew(opt)/*{{{*/
       
  1064 	{
       
  1065 		setOptions(opt);
       
  1066 		interfaceUpdate();
       
  1067 	};
       
  1068 	/*}}}*/
       
  1069 	function disableCrop()//{{{
       
  1070 	{
       
  1071 		options.disabled = true;
       
  1072 		Selection.disableHandles();
       
  1073 		Selection.setCursor('default');
       
  1074 		Tracker.setCursor('default');
       
  1075 	};
       
  1076 	//}}}
       
  1077 	function enableCrop()//{{{
       
  1078 	{
       
  1079 		options.disabled = false;
       
  1080 		interfaceUpdate();
       
  1081 	};
       
  1082 	//}}}
       
  1083 	function cancelCrop()//{{{
       
  1084 	{
       
  1085 		Selection.done();
       
  1086 		Tracker.activateHandlers(null,null);
       
  1087 	};
       
  1088 	//}}}
       
  1089 	function destroy()//{{{
       
  1090 	{
       
  1091 		$div.remove();
       
  1092 		$origimg.show();
       
  1093 	};
       
  1094 	//}}}
       
  1095 
       
  1096 	function interfaceUpdate(alt)//{{{
       
  1097 	// This method tweaks the interface based on options object.
       
  1098 	// Called when options are changed and at end of initialization.
       
  1099 	{
       
  1100 		options.allowResize ?
       
  1101 			alt?Selection.enableOnly():Selection.enableHandles():
       
  1102 			Selection.disableHandles();
       
  1103 
       
  1104 		Tracker.setCursor( options.allowSelect? 'crosshair': 'default' );
       
  1105 		Selection.setCursor( options.allowMove? 'move': 'default' );
       
  1106 
       
  1107 		$div.css('backgroundColor',options.bgColor);
       
  1108 
       
  1109 		if ('setSelect' in options) {
       
  1110 			setSelect(opt.setSelect);
       
  1111 			Selection.done();
       
  1112 			delete(options.setSelect);
       
  1113 		}
       
  1114 
       
  1115 		if ('trueSize' in options) {
       
  1116 			xscale = options.trueSize[0] / boundx;
       
  1117 			yscale = options.trueSize[1] / boundy;
       
  1118 		}
       
  1119 
       
  1120 		xlimit = options.maxSize[0] || 0;
       
  1121 		ylimit = options.maxSize[1] || 0;
       
  1122 		xmin = options.minSize[0] || 0;
       
  1123 		ymin = options.minSize[1] || 0;
       
  1124 
       
  1125 		if ('outerImage' in options)
       
  1126 		{
       
  1127 			$img.attr('src',options.outerImage);
       
  1128 			delete(options.outerImage);
       
  1129 		}
       
  1130 
       
  1131 		Selection.refresh();
       
  1132 	};
       
  1133 	//}}}
       
  1134 
       
  1135 	// }}}
       
  1136 
       
  1137 	$hdl_holder.hide();
       
  1138 	interfaceUpdate(true);
       
  1139 	
       
  1140 	var api = {
       
  1141 		animateTo: animateTo,
       
  1142 		setSelect: setSelect,
       
  1143 		setOptions: setOptionsNew,
       
  1144 		tellSelect: tellSelect,
       
  1145 		tellScaled: tellScaled,
       
  1146 
       
  1147 		disable: disableCrop,
       
  1148 		enable: enableCrop,
       
  1149 		cancel: cancelCrop,
       
  1150 
       
  1151 		focus: KeyManager.watchKeys,
       
  1152 
       
  1153 		getBounds: function() { return [ boundx * xscale, boundy * yscale ]; },
       
  1154 		getWidgetSize: function() { return [ boundx, boundy ]; },
       
  1155 
       
  1156 		release: Selection.release,
       
  1157 		destroy: destroy
       
  1158 
       
  1159 	};
       
  1160 
       
  1161 	$origimg.data('Jcrop',api);
       
  1162 	return api;
       
  1163 };
       
  1164 
       
  1165 $.fn.Jcrop = function(options)/*{{{*/
       
  1166 {
       
  1167 	function attachWhenDone(from)/*{{{*/
       
  1168 	{
       
  1169 		var loadsrc = options.useImg || from.src;
       
  1170 		var img = new Image();
       
  1171 		img.onload = function() { $.Jcrop(from,options); };
       
  1172 		img.src = loadsrc;
       
  1173 	};
       
  1174 	/*}}}*/
       
  1175 	if (typeof(options) !== 'object') options = { };
       
  1176 
       
  1177 	// Iterate over each object, attach Jcrop
       
  1178 	this.each(function()
       
  1179 	{
       
  1180 		// If we've already attached to this object
       
  1181 		if ($(this).data('Jcrop'))
       
  1182 		{
       
  1183 			// The API can be requested this way (undocumented)
       
  1184 			if (options == 'api') return $(this).data('Jcrop');
       
  1185 			// Otherwise, we just reset the options...
       
  1186 			else $(this).data('Jcrop').setOptions(options);
       
  1187 		}
       
  1188 		// If we haven't been attached, preload and attach
       
  1189 		else attachWhenDone(this);
       
  1190 	});
       
  1191 
       
  1192 	// Return "this" so we're chainable a la jQuery plugin-style!
       
  1193 	return this;
       
  1194 };
       
  1195 /*}}}*/
       
  1196 
       
  1197 })(jQuery);