META-INF.resources.primefaces.imagecropper.0-jcrop.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of primefaces Show documentation
Show all versions of primefaces Show documentation
PrimeFaces is one of the most popular UI libraries in Java EE Ecosystem and widely used by software companies, world renowned brands, banks, financial institutions, insurance companies, universities and more.
/*! Jcrop.js v2.0.4 - build: 20151117
* @copyright 2008-2015 Tapmodo Interactive LLC
* @license Free software under MIT License
* @website http://jcrop.org/
**/
(function($){
'use strict';
// Jcrop constructor
var Jcrop = function(element,opt){
var _ua = navigator.userAgent.toLowerCase();
this.opt = $.extend({},Jcrop.defaults,opt || {});
this.container = $(element);
this.opt.is_msie = /msie/.test(_ua);
this.opt.is_ie_lt9 = /msie [1-8]\./.test(_ua);
this.container.addClass(this.opt.css_container);
this.ui = {};
this.state = null;
this.ui.multi = [];
this.ui.selection = null;
this.filter = {};
this.init();
this.setOptions(opt);
this.applySizeConstraints();
this.container.trigger('cropinit',this);
// IE<9 doesn't work if mouse events are attached to window
if (this.opt.is_ie_lt9)
this.opt.dragEventTarget = document.body;
};
// Jcrop static functions
$.extend(Jcrop,{
component: { },
filter: { },
stage: { },
registerComponent: function(name,component){
Jcrop.component[name] = component;
},
registerFilter: function(name,filter){
Jcrop.filter[name] = filter;
},
registerStageType: function(name,stage){
Jcrop.stage[name] = stage;
},
// attach: function(element,opt){{{
attach: function(element,opt){
var obj = new $.Jcrop(element,opt);
return obj;
},
// }}}
// imgCopy: function(imgel){{{
imgCopy: function(imgel){
var img = new Image;
img.src = imgel.src;
return img;
},
// }}}
// imageClone: function(imgel){{{
imageClone: function(imgel){
return $.Jcrop.supportsCanvas?
Jcrop.canvasClone(imgel):
Jcrop.imgCopy(imgel);
},
// }}}
// canvasClone: function(imgel){{{
canvasClone: function(imgel){
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
$(canvas).width(imgel.width).height(imgel.height),
canvas.width = imgel.naturalWidth;
canvas.height = imgel.naturalHeight;
ctx.drawImage(imgel,0,0,imgel.naturalWidth,imgel.naturalHeight);
return canvas;
},
// }}}
// propagate: function(plist,config,obj){{{
propagate: function(plist,config,obj){
for(var i=0,l=plist.length;i ratio)
return [ h * ratio, h ];
else return [ w, w / ratio ];
},
// }}}
// stageConstructor: function(el,options,callback){{{
stageConstructor: function(el,options,callback){
// Get a priority-ordered list of available stages
var stages = [];
$.each(Jcrop.stage,function(i,e){
stages.push(e);
});
stages.sort(function(a,b){ return a.priority - b.priority; });
// Find the first one that supports this element
for(var i=0,l=stages.length;i ').parent();
obj.element.width(w).height(h);
obj.imgsrc = el;
if (typeof callback == 'function')
callback.call(this,obj,options);
});
}
});
Jcrop.registerStageType('Image',ImageStage);
var CanvasStage = function(){
this.angle = 0;
this.scale = 1;
this.scaleMin = 0.2;
this.scaleMax = 1.25;
this.offset = [0,0];
};
CanvasStage.prototype = new ImageStage();
$.extend(CanvasStage,{
isSupported: function(el,o){
if ($.Jcrop.supportsCanvas && (el.tagName == 'IMG')) return true;
},
priority: 60,
create: function(el,options,callback){
var $el = $(el);
var opt = $.extend({},options);
$.Jcrop.component.ImageLoader.attach(el,function(w,h){
var obj = new CanvasStage;
$el.hide();
obj.createCanvas(el,w,h);
$el.before(obj.element);
obj.imgsrc = el;
opt.imgsrc = el;
if (typeof callback == 'function'){
callback(obj,opt);
obj.redraw();
}
});
}
});
$.extend(CanvasStage.prototype,{
init: function(core){
this.core = core;
},
// setOffset: function(x,y) {{{
setOffset: function(x,y) {
this.offset = [x,y];
return this;
},
// }}}
// setAngle: function(v) {{{
setAngle: function(v) {
this.angle = v;
return this;
},
// }}}
// setScale: function(v) {{{
setScale: function(v) {
this.scale = this.boundScale(v);
return this;
},
// }}}
boundScale: function(v){
if (vthis.scaleMax) v = this.scaleMax;
return v;
},
createCanvas: function(img,w,h){
this.width = w;
this.height = h;
this.canvas = document.createElement('canvas');
this.canvas.width = w;
this.canvas.height = h;
this.$canvas = $(this.canvas).width('100%').height('100%');
this.context = this.canvas.getContext('2d');
this.fillstyle = "rgb(0,0,0)";
this.element = this.$canvas.wrap('').parent().width(w).height(h);
},
triggerEvent: function(ev){
this.$canvas.trigger(ev);
return this;
},
// clear: function() {{{
clear: function() {
this.context.fillStyle = this.fillstyle;
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
return this;
},
// }}}
// redraw: function() {{{
redraw: function() {
// Save the current context
this.context.save();
this.clear();
// Translate to the center point of our image
this.context.translate(parseInt(this.width * 0.5), parseInt(this.height * 0.5));
// Perform the rotation and scaling
this.context.translate(this.offset[0]/this.core.opt.xscale,this.offset[1]/this.core.opt.yscale);
this.context.rotate(this.angle * (Math.PI/180));
this.context.scale(this.scale,this.scale);
// Translate back to the top left of our image
this.context.translate(-parseInt(this.width * 0.5), -parseInt(this.height * 0.5));
// Finally we draw the image
this.context.drawImage(this.imgsrc,0,0,this.width,this.height);
// And restore the updated context
this.context.restore();
this.$canvas.trigger('cropredraw');
return this;
},
// }}}
// setFillStyle: function(v) {{{
setFillStyle: function(v) {
this.fillstyle = v;
return this;
}
// }}}
});
Jcrop.registerStageType('Canvas',CanvasStage);
/**
* BackoffFilter
* move out-of-bounds selection into allowed position at same size
*/
var BackoffFilter = function(){
this.minw = 40;
this.minh = 40;
this.maxw = 0;
this.maxh = 0;
this.core = null;
};
$.extend(BackoffFilter.prototype,{
tag: 'backoff',
priority: 22,
filter: function(b){
var r = this.bound;
if (b.x < r.minx) { b.x = r.minx; b.x2 = b.w + b.x; }
if (b.y < r.miny) { b.y = r.miny; b.y2 = b.h + b.y; }
if (b.x2 > r.maxx) { b.x2 = r.maxx; b.x = b.x2 - b.w; }
if (b.y2 > r.maxy) { b.y2 = r.maxy; b.y = b.y2 - b.h; }
return b;
},
refresh: function(sel){
this.elw = sel.core.container.width();
this.elh = sel.core.container.height();
this.bound = {
minx: 0 + sel.edge.w,
miny: 0 + sel.edge.n,
maxx: this.elw + sel.edge.e,
maxy: this.elh + sel.edge.s
};
}
});
Jcrop.registerFilter('backoff',BackoffFilter);
/**
* ConstrainFilter
* a filter to constrain crop selection to bounding element
*/
var ConstrainFilter = function(){
this.core = null;
};
$.extend(ConstrainFilter.prototype,{
tag: 'constrain',
priority: 5,
filter: function(b,ord){
if (ord == 'move') {
if (b.x < this.minx) { b.x = this.minx; b.x2 = b.w + b.x; }
if (b.y < this.miny) { b.y = this.miny; b.y2 = b.h + b.y; }
if (b.x2 > this.maxx) { b.x2 = this.maxx; b.x = b.x2 - b.w; }
if (b.y2 > this.maxy) { b.y2 = this.maxy; b.y = b.y2 - b.h; }
} else {
if (b.x < this.minx) { b.x = this.minx; }
if (b.y < this.miny) { b.y = this.miny; }
if (b.x2 > this.maxx) { b.x2 = this.maxx; }
if (b.y2 > this.maxy) { b.y2 = this.maxy; }
}
b.w = b.x2 - b.x;
b.h = b.y2 - b.y;
return b;
},
refresh: function(sel){
this.elw = sel.core.container.width();
this.elh = sel.core.container.height();
this.minx = 0 + sel.edge.w;
this.miny = 0 + sel.edge.n;
this.maxx = this.elw + sel.edge.e;
this.maxy = this.elh + sel.edge.s;
}
});
Jcrop.registerFilter('constrain',ConstrainFilter);
/**
* ExtentFilter
* a filter to implement minimum or maximum size
*/
var ExtentFilter = function(){
this.core = null;
};
$.extend(ExtentFilter.prototype,{
tag: 'extent',
priority: 12,
offsetFromCorner: function(corner,box,b){
var w = box[0], h = box[1];
switch(corner){
case 'bl': return [ b.x2 - w, b.y, w, h ];
case 'tl': return [ b.x2 - w , b.y2 - h, w, h ];
case 'br': return [ b.x, b.y, w, h ];
case 'tr': return [ b.x, b.y2 - h, w, h ];
}
},
getQuadrant: function(s){
var relx = s.opposite[0]-s.offsetx
var rely = s.opposite[1]-s.offsety;
if ((relx < 0) && (rely < 0)) return 'br';
else if ((relx >= 0) && (rely >= 0)) return 'tl';
else if ((relx < 0) && (rely >= 0)) return 'tr';
return 'bl';
},
filter: function(b,ord,sel){
if (ord == 'move') return b;
var w = b.w, h = b.h, st = sel.state, r = this.limits;
var quad = st? this.getQuadrant(st): 'br';
if (r.minw && (w < r.minw)) w = r.minw;
if (r.minh && (h < r.minh)) h = r.minh;
if (r.maxw && (w > r.maxw)) w = r.maxw;
if (r.maxh && (h > r.maxh)) h = r.maxh;
if ((w == b.w) && (h == b.h)) return b;
return Jcrop.wrapFromXywh(this.offsetFromCorner(quad,[w,h],b));
},
refresh: function(sel){
this.elw = sel.core.container.width();
this.elh = sel.core.container.height();
this.limits = {
minw: sel.minSize[0],
minh: sel.minSize[1],
maxw: sel.maxSize[0],
maxh: sel.maxSize[1]
};
}
});
Jcrop.registerFilter('extent',ExtentFilter);
/**
* GridFilter
* a rudimentary grid effect
*/
var GridFilter = function(){
this.stepx = 1;
this.stepy = 1;
this.core = null;
};
$.extend(GridFilter.prototype,{
tag: 'grid',
priority: 19,
filter: function(b){
var n = {
x: Math.round(b.x / this.stepx) * this.stepx,
y: Math.round(b.y / this.stepy) * this.stepy,
x2: Math.round(b.x2 / this.stepx) * this.stepx,
y2: Math.round(b.y2 / this.stepy) * this.stepy
};
n.w = n.x2 - n.x;
n.h = n.y2 - n.y;
return n;
}
});
Jcrop.registerFilter('grid',GridFilter);
/**
* RatioFilter
* implements aspectRatio locking
*/
var RatioFilter = function(){
this.ratio = 0;
this.core = null;
};
$.extend(RatioFilter.prototype,{
tag: 'ratio',
priority: 15,
offsetFromCorner: function(corner,box,b){
var w = box[0], h = box[1];
switch(corner){
case 'bl': return [ b.x2 - w, b.y, w, h ];
case 'tl': return [ b.x2 - w , b.y2 - h, w, h ];
case 'br': return [ b.x, b.y, w, h ];
case 'tr': return [ b.x, b.y2 - h, w, h ];
}
},
getBoundRatio: function(b,quad){
var box = Jcrop.getLargestBox(this.ratio,b.w,b.h);
return Jcrop.wrapFromXywh(this.offsetFromCorner(quad,box,b));
},
getQuadrant: function(s){
var relx = s.opposite[0]-s.offsetx
var rely = s.opposite[1]-s.offsety;
if ((relx < 0) && (rely < 0)) return 'br';
else if ((relx >= 0) && (rely >= 0)) return 'tl';
else if ((relx < 0) && (rely >= 0)) return 'tr';
return 'bl';
},
filter: function(b,ord,sel){
if (!this.ratio) return b;
var rt = b.w / b.h;
var st = sel.state;
var quad = st? this.getQuadrant(st): 'br';
ord = ord || 'se';
if (ord == 'move') return b;
switch(ord) {
case 'n':
b.x2 = this.elw;
b.w = b.x2 - b.x;
quad = 'tr';
break;
case 's':
b.x2 = this.elw;
b.w = b.x2 - b.x;
quad = 'br';
break;
case 'e':
b.y2 = this.elh;
b.h = b.y2 - b.y;
quad = 'br';
break;
case 'w':
b.y2 = this.elh;
b.h = b.y2 - b.y;
quad = 'bl';
break;
}
return this.getBoundRatio(b,quad);
},
refresh: function(sel){
this.ratio = sel.aspectRatio;
this.elw = sel.core.container.width();
this.elh = sel.core.container.height();
}
});
Jcrop.registerFilter('ratio',RatioFilter);
/**
* RoundFilter
* rounds coordinate values to integers
*/
var RoundFilter = function(){
this.core = null;
};
$.extend(RoundFilter.prototype,{
tag: 'round',
priority: 90,
filter: function(b){
var n = {
x: Math.round(b.x),
y: Math.round(b.y),
x2: Math.round(b.x2),
y2: Math.round(b.y2)
};
n.w = n.x2 - n.x;
n.h = n.y2 - n.y;
return n;
}
});
Jcrop.registerFilter('round',RoundFilter);
/**
* ShadeFilter
* A filter that implements div-based shading on any element
*
* The shading you see is actually four semi-opaque divs
* positioned inside the container, around the selection
*/
var ShadeFilter = function(opacity,color){
this.color = color || 'black';
this.opacity = opacity || 0.5;
this.core = null;
this.shades = {};
};
$.extend(ShadeFilter.prototype,{
tag: 'shader',
fade: true,
fadeEasing: 'swing',
fadeSpeed: 320,
priority: 95,
init: function(){
var t = this;
if (!t.attached) {
t.visible = false;
t.container = $('').addClass(t.core.opt.css_shades)
.prependTo(this.core.container).hide();
t.elh = this.core.container.height();
t.elw = this.core.container.width();
t.shades = {
top: t.createShade(),
right: t.createShade(),
left: t.createShade(),
bottom: t.createShade()
};
t.attached = true;
}
},
destroy: function(){
this.container.remove();
},
setColor: function(color,instant){
var t = this;
if (color == t.color) return t;
this.color = color;
var colorfade = Jcrop.supportsColorFade();
$.each(t.shades,function(u,i){
if (!t.fade || instant || !colorfade) i.css('backgroundColor',color);
else i.animate({backgroundColor:color},{queue:false,duration:t.fadeSpeed,easing:t.fadeEasing});
});
return t;
},
setOpacity: function(opacity,instant){
var t = this;
if (opacity == t.opacity) return t;
t.opacity = opacity;
$.each(t.shades,function(u,i){
if (!t.fade || instant) i.css({opacity:opacity});
else i.animate({opacity:opacity},{queue:false,duration:t.fadeSpeed,easing:t.fadeEasing});
});
return t;
},
createShade: function(){
return $('').css({
position: 'absolute',
backgroundColor: this.color,
opacity: this.opacity
}).appendTo(this.container);
},
refresh: function(sel){
var m = this.core, s = this.shades;
this.setColor(sel.bgColor?sel.bgColor:this.core.opt.bgColor);
this.setOpacity(sel.bgOpacity?sel.bgOpacity:this.core.opt.bgOpacity);
this.elh = m.container.height();
this.elw = m.container.width();
s.right.css('height',this.elh+'px');
s.left.css('height',this.elh+'px');
},
filter: function(b,ord,sel){
if (!sel.active) return b;
var t = this,
s = t.shades;
s.top.css({
left: Math.round(b.x)+'px',
width: Math.round(b.w)+'px',
height: Math.round(b.y)+'px'
});
s.bottom.css({
top: Math.round(b.y2)+'px',
left: Math.round(b.x)+'px',
width: Math.round(b.w)+'px',
height: (t.elh-Math.round(b.y2))+'px'
});
s.right.css({
left: Math.round(b.x2)+'px',
width: (t.elw-Math.round(b.x2))+'px'
});
s.left.css({
width: Math.round(b.x)+'px'
});
if (!t.visible) {
t.container.show();
t.visible = true;
}
return b;
}
});
Jcrop.registerFilter('shader',ShadeFilter);
/**
* CanvasAnimator
* manages smooth cropping animation
*
* This object is called internally to manage animation.
* An in-memory div is animated and a progress callback
* is used to update the selection coordinates of the
* visible selection in realtime.
*/
var CanvasAnimator = function(stage){
this.stage = stage;
this.core = stage.core;
this.cloneStagePosition();
};
CanvasAnimator.prototype = {
cloneStagePosition: function(){
var s = this.stage;
this.angle = s.angle;
this.scale = s.scale;
this.offset = s.offset;
},
getElement: function(){
var s = this.stage;
return $('')
.css({
position: 'absolute',
top: s.offset[0]+'px',
left: s.offset[1]+'px',
width: s.angle+'px',
height: s.scale+'px'
});
},
animate: function(cb){
var t = this;
this.scale = this.stage.boundScale(this.scale);
t.stage.triggerEvent('croprotstart');
t.getElement().animate({
top: t.offset[0]+'px',
left: t.offset[1]+'px',
width: t.angle+'px',
height: t.scale+'px'
},{
easing: t.core.opt.animEasing,
duration: t.core.opt.animDuration,
complete: function(){
t.stage.triggerEvent('croprotend');
(typeof cb == 'function') && cb.call(this);
},
progress: function(anim){
var props = {}, i, tw = anim.tweens;
for(i=0;i ')
.css({
position: 'absolute',
top: b.y+'px',
left: b.x+'px',
width: b.w+'px',
height: b.h+'px'
});
},
animate: function(x,y,w,h,cb){
var t = this;
t.selection.allowResize(false);
t.getElement().animate({
top: y+'px',
left: x+'px',
width: w+'px',
height: h+'px'
},{
easing: t.core.opt.animEasing,
duration: t.core.opt.animDuration,
complete: function(){
t.selection.allowResize(true);
cb && cb.call(this);
},
progress: function(anim){
var props = {}, i, tw = anim.tweens;
for(i=0;i 0 || window.DocumentTouch && document instanceof DocumentTouch)
return true;
},
// }}}
prototype: {
// init: function(){{{
init: function(){
var t = this,
p = $.Jcrop.component.DragState.prototype;
// A bit of an ugly hack to make sure we modify prototype
// only once, store a key on the prototype
if (!p.touch) {
t.initEvents();
t.shimDragState();
t.shimStageDrag();
p.touch = true;
}
},
// }}}
// shimDragState: function(){{{
shimDragState: function(){
var t = this;
$.Jcrop.component.DragState.prototype.initEvents = function(e){
// Attach subsequent drag event handlers based on initial
// event type - avoids collecting "pseudo-mouse" events
// generated by some mobile browsers in some circumstances
if (e.type.substr(0,5) == 'touch') {
$(this.eventTarget)
.on('touchmove.jcrop.jcrop-touch',t.dragWrap(this.createDragHandler()))
.on('touchend.jcrop.jcrop-touch',this.createStopHandler());
}
// For other events, use the mouse handlers that
// the default DragState.initEvents() method sets...
else {
$(this.eventTarget)
.on('mousemove.jcrop',this.createDragHandler())
.on('mouseup.jcrop',this.createStopHandler());
}
};
},
// }}}
// shimStageDrag: function(){{{
shimStageDrag: function(){
this.core.container
.addClass('jcrop-touch')
.on('touchstart.jcrop.jcrop-stage',this.dragWrap(this.core.ui.manager.startDragHandler()));
},
// }}}
// dragWrap: function(cb){{{
dragWrap: function(cb){
return function(e){
e.preventDefault();
e.stopPropagation();
if (e.type.substr(0,5) == 'touch') {
e.pageX = e.originalEvent.changedTouches[0].pageX;
e.pageY = e.originalEvent.changedTouches[0].pageY;
return cb(e);
}
return false;
};
},
// }}}
// initEvents: function(){{{
initEvents: function(){
var t = this, c = t.core;
c.container.on(
'touchstart.jcrop.jcrop-touch',
'.'+c.opt.css_drag,
t.dragWrap(c.startDrag())
);
}
// }}}
}
});
Jcrop.registerComponent('Touch',JcropTouch);
/**
* KeyWatcher
* provides keyboard support
*/
// var KeyWatcher = function(core){{{
var KeyWatcher = function(core){
this.core = core;
this.init();
};
// }}}
$.extend(KeyWatcher,{
// defaults: {{{
defaults: {
eventName: 'keydown.jcrop',
passthru: [ 9 ],
debug: false
},
// }}}
prototype: {
// init: function(){{{
init: function(){
$.extend(this,KeyWatcher.defaults);
this.enable();
},
// }}}
// disable: function(){{{
disable: function(){
this.core.container.off(this.eventName);
},
// }}}
// enable: function(){{{
enable: function(){
var t = this, m = t.core;
m.container.on(t.eventName,function(e){
var nudge = e.shiftKey? 16: 2;
if ($.inArray(e.keyCode,t.passthru) >= 0)
return true;
switch(e.keyCode){
case 37: m.nudge(-nudge,0); break;
case 38: m.nudge(0,-nudge); break;
case 39: m.nudge(nudge,0); break;
case 40: m.nudge(0,nudge); break;
case 46:
case 8:
m.requestDelete();
return false;
break;
default:
if (t.debug) console.log('keycode: ' + e.keyCode);
break;
}
if (!e.metaKey && !e.ctrlKey)
e.preventDefault();
});
}
// }}}
}
});
Jcrop.registerComponent('Keyboard',KeyWatcher);
/**
* Selection
* Built-in selection object
*/
var Selection = function(){};
$.extend(Selection,{
// defaults: {{{
defaults: {
minSize: [ 8, 8 ],
maxSize: [ 0, 0 ],
aspectRatio: 0,
edge: { n: 0, s: 0, e: 0, w: 0 },
bgColor: null,
bgOpacity: null,
last: null,
state: null,
active: true,
linked: true,
canDelete: true,
canDrag: true,
canResize: true,
canSelect: true
},
// }}}
prototype: {
// init: function(core){{{
init: function(core){
this.core = core;
this.startup();
this.linked = this.core.opt.linked;
this.attach();
this.setOptions(this.core.opt);
core.container.trigger('cropcreate',[this]);
},
// }}}
// attach: function(){{{
attach: function(){
// For extending init() sequence
},
// }}}
// startup: function(){{{
startup: function(){
var t = this, o = t.core.opt;
$.extend(t,Selection.defaults);
t.filter = t.core.getDefaultFilters();
t.element = $('').addClass(o.css_selection).data({ selection: t });
t.frame = $('').addClass(o.css_button).data('ord','move').attr('type','button');
t.element.append(t.frame).appendTo(t.core.container);
// IE background/draggable hack
if (t.core.opt.is_msie) t.frame.css({
opacity: 0,
backgroundColor: 'white'
});
t.insertElements();
// Bind focus and blur events for this selection
t.frame.on('focus.jcrop',function(e){
t.core.setSelection(t);
t.element.trigger('cropfocus',t);
t.element.addClass('jcrop-focus');
}).on('blur.jcrop',function(e){
t.element.removeClass('jcrop-focus');
t.element.trigger('cropblur',t);
});
},
// }}}
// propagate: [{{{
propagate: [
'canDelete', 'canDrag', 'canResize', 'canSelect',
'minSize', 'maxSize', 'aspectRatio', 'edge'
],
// }}}
// setOptions: function(opt){{{
setOptions: function(opt){
Jcrop.propagate(this.propagate,opt,this);
this.refresh();
return this;
},
// }}}
// refresh: function(){{{
refresh: function(){
this.allowResize();
this.allowDrag();
this.allowSelect();
this.callFilterFunction('refresh');
this.updateRaw(this.get(),'se');
},
// }}}
// callFilterFunction: function(f,args){{{
callFilterFunction: function(f,args){
for(var i=0;i ').addClass(type+' ord-'+ord).data('ord',ord);
},
//}}}
//moveTo: function(x,y){{{
moveTo: function(x,y){
this.element.css({top: y+'px', left: x+'px'});
},
//}}}
// blur: function(){{{
blur: function(){
this.element.blur();
return this;
},
// }}}
// focus: function(){{{
focus: function(){
this.core.setSelection(this);
this.frame.focus();
return this;
},
// }}}
//resize: function(w,h){{{
resize: function(w,h){
this.element.css({width: w+'px', height: h+'px'});
},
//}}}
//get: function(){{{
get: function(){
var b = this.element,
o = b.position(),
w = b.width(),
h = b.height(),
rv = { x: o.left, y: o.top };
rv.x2 = rv.x + w;
rv.y2 = rv.y + h;
rv.w = w;
rv.h = h;
return rv;
},
//}}}
//insertElements: function(){{{
insertElements: function(){
var t = this, i,
m = t.core,
fr = t.element,
o = t.core.opt,
b = o.borders,
h = o.handles,
d = o.dragbars;
for(i=0; i= c.opt.multiMax)) return false;
// calculate a few variables for this drag operation
var o = $(e.currentTarget).offset();
var origx = e.pageX - o.left + this.offset[0];
var origy = e.pageY - o.top + this.offset[1];
var m = c.ui.multi;
// Determine newly dragged crop behavior if multi disabled
if (!c.opt.multi) {
// For multiCleaanup true, remove all existing selections
if (c.opt.multiCleanup){
for(var i=0;i ').addClass('jcrop-thumb')
.width(this.width).height(this.height)
.append(this.preview)
.appendTo(this.core.container);
},
resize: function(w,h){
this.width = w;
this.height = h;
this.element.width(w).height(h);
this.renderCoords(this.last);
},
refresh: function(){
this.cw = (this.core.opt.xscale * this.core.container.width());
this.ch = (this.core.opt.yscale * this.core.container.height());
if (this.last) {
this.renderCoords(this.last);
}
},
renderCoords: function(c){
var rx = this.width / c.w;
var ry = this.height / c.h;
this.preview.css({
width: Math.round(rx * this.cw) + 'px',
height: Math.round(ry * this.ch) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
});
this.last = c;
return this;
},
renderSelection: function(s){
return this.renderCoords(s.core.unscale(s.get()));
},
selectionStart: function(s){
this.renderSelection(s);
},
show: function(){
if (this._hiding) clearTimeout(this._hiding);
if (!this.fading) this.element.stop().css({ opacity: 1 });
else this.element.stop().animate({ opacity: 1 },{ duration: 80, queue: false });
},
hide: function(){
var t = this;
if (!t.fading) t.element.hide();
else t._hiding = setTimeout(function(){
t._hiding = null;
t.element.stop().animate({ opacity: 0 },{ duration: t.fadeDuration, queue: false });
},t.fadeDelay);
},
initEvents: function(){
var t = this;
t.core.container.on('croprotstart croprotend cropimage cropstart cropmove cropend',function(e,s,c){
if (t.selectionTarget && (t.selectionTarget !== e.target)) return false;
switch(e.type){
case 'cropimage':
t.updateImage(c);
break;
case 'cropstart':
t.selectionStart(s);
case 'croprotstart':
t.show();
break;
case 'cropend':
t.renderCoords(c);
case 'croprotend':
if (t.autoHide) t.hide();
break;
case 'cropmove':
t.renderCoords(c);
break;
}
});
}
}
});
Jcrop.registerComponent('Thumbnailer',Thumbnailer);
/**
* DialDrag component
* This is a little hacky, it was adapted from some previous/old code
* Plan to update this API in the future
*/
var DialDrag = function() { };
DialDrag.prototype = {
init: function(core,actuator,callback){
var that = this;
if (!actuator) actuator = core.container;
this.$btn = $(actuator);
this.$targ = $(actuator);
this.core = core;
this.$btn
.addClass('dialdrag')
.on('mousedown.dialdrag',this.mousedown())
.data('dialdrag',this);
if (!$.isFunction(callback)) callback = function(){ };
this.callback = callback;
this.ondone = callback;
},
remove: function(){
this.$btn
.removeClass('dialdrag')
.off('.dialdrag')
.data('dialdrag',null);
return this;
},
setTarget: function(obj){
this.$targ = $(obj);
return this;
},
getOffset: function(){
var targ = this.$targ, pos = targ.offset();
return [
pos.left + (targ.width()/2),
pos.top + (targ.height()/2)
];
},
relMouse: function(e){
var x = e.pageX - this.offset[0],
y = e.pageY - this.offset[1],
ang = Math.atan2(y,x) * (180 / Math.PI),
vec = Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
return [ x, y, ang, vec ];
},
mousedown: function(){
var that = this;
function mouseUp(e){
$(window).off('.dialdrag');
that.ondone.call(that,that.relMouse(e));
that.core.container.trigger('croprotend');
}
function mouseMove(e){
that.callback.call(that,that.relMouse(e));
}
return function(e) {
that.offset = that.getOffset();
var rel = that.relMouse(e);
that.angleOffset = -that.core.ui.stage.angle+rel[2];
that.distOffset = rel[3];
that.dragOffset = [rel[0],rel[1]];
that.core.container.trigger('croprotstart');
$(window)
.on('mousemove.dialdrag',mouseMove)
.on('mouseup.dialdrag',mouseUp);
that.callback.call(that,that.relMouse(e));
return false;
};
}
};
Jcrop.registerComponent('DialDrag',DialDrag);
/////////////////////////////////
// DEFAULT SETTINGS
Jcrop.defaults = {
// Selection Behavior
edge: { n: 0, s: 0, e: 0, w: 0 },
setSelect: null,
linked: true,
linkCurrent: true,
canDelete: true,
canSelect: true,
canDrag: true,
canResize: true,
// Component constructors
eventManagerComponent: Jcrop.component.EventManager,
keyboardComponent: Jcrop.component.Keyboard,
dragstateComponent: Jcrop.component.DragState,
stagemanagerComponent: Jcrop.component.StageManager,
animatorComponent: Jcrop.component.Animator,
selectionComponent: Jcrop.component.Selection,
// This is a function that is called, which returns a stage object
stageConstructor: Jcrop.stageConstructor,
// Stage Behavior
allowSelect: true,
multi: false,
multiMax: false,
multiCleanup: true,
animation: true,
animEasing: 'swing',
animDuration: 400,
fading: true,
fadeDuration: 300,
fadeEasing: 'swing',
bgColor: 'black',
bgOpacity: .5,
// Startup options
applyFilters: [ 'constrain', 'extent', 'backoff', 'ratio', 'shader', 'round' ],
borders: [ 'e', 'w', 's', 'n' ],
handles: [ 'n', 's', 'e', 'w', 'sw', 'ne', 'nw', 'se' ],
dragbars: [ 'n', 'e', 'w', 's' ],
dragEventTarget: window,
xscale: 1,
yscale: 1,
boxWidth: null,
boxHeight: null,
// CSS Classes
// @todo: These need to be moved to top-level object keys
// for better customization. Currently if you try to extend one
// via an options object to Jcrop, it will wipe out all
// the others you don't specify. Be careful for now!
css_nodrag: 'jcrop-nodrag',
css_drag: 'jcrop-drag',
css_container: 'jcrop-active',
css_shades: 'jcrop-shades',
css_selection: 'jcrop-selection',
css_borders: 'jcrop-border',
css_handles: 'jcrop-handle jcrop-drag',
css_button: 'jcrop-box jcrop-drag',
css_noresize: 'jcrop-noresize',
css_dragbars: 'jcrop-dragbar jcrop-drag',
legacyHandlers: {
onChange: 'cropmove',
onSelect: 'cropend'
}
};
// Jcrop API methods
$.extend(Jcrop.prototype,{
//init: function(){{{
init: function(){
this.event = new this.opt.eventManagerComponent(this);
this.ui.keyboard = new this.opt.keyboardComponent(this);
this.ui.manager = new this.opt.stagemanagerComponent(this);
this.applyFilters();
if ($.Jcrop.supportsTouch)
new $.Jcrop.component.Touch(this);
this.initEvents();
},
//}}}
// applySizeConstraints: function(){{{
applySizeConstraints: function(){
var o = this.opt,
img = this.opt.imgsrc;
if (img){
var iw = img.naturalWidth || img.width,
ih = img.naturalHeight || img.height,
bw = o.boxWidth || iw,
bh = o.boxHeight || ih;
if (img && ((iw > bw) || (ih > bh))){
var bx = Jcrop.getLargestBox(iw/ih,bw,bh);
$(img).width(bx[0]).height(bx[1]);
this.resizeContainer(bx[0],bx[1]);
this.opt.xscale = iw / bx[0];
this.opt.yscale = ih / bx[1];
}
}
if (this.opt.trueSize){
var dw = this.opt.trueSize[0];
var dh = this.opt.trueSize[1];
var cs = this.getContainerSize();
this.opt.xscale = dw / cs[0];
this.opt.yscale = dh / cs[1];
}
},
// }}}
initComponent: function(name){
if (Jcrop.component[name]) {
var args = Array.prototype.slice.call(arguments);
var obj = new Jcrop.component[name];
args.shift();
args.unshift(this);
obj.init.apply(obj,args);
return obj;
}
},
// setOptions: function(opt){{{
setOptions: function(opt,proptype){
if (!$.isPlainObject(opt)) opt = {};
$.extend(this.opt,opt);
// Handle a setSelect value
if (this.opt.setSelect) {
// If there is no current selection
// passing setSelect will create one
if (!this.ui.multi.length)
this.newSelection();
// Use these values to update the current selection
this.setSelect(this.opt.setSelect);
// Set to null so it doesn't get called again
this.opt.setSelect = null;
}
this.event.trigger('configupdate');
return this;
},
// }}}
//destroy: function(){{{
destroy: function(){
if (this.opt.imgsrc) {
this.container.before(this.opt.imgsrc);
this.container.remove();
$(this.opt.imgsrc).removeData('Jcrop').show();
} else {
// @todo: more elegant destroy() process for non-image containers
this.container.remove();
}
},
// }}}
// applyFilters: function(){{{
applyFilters: function(){
var obj;
for(var i=0,f=this.opt.applyFilters,l=f.length; i this.elw) { b.x2 = this.elw; b.x = b.x2 - b.w; }
if (b.y < 0) { b.y2 = b.h; b.y = 0; }
else if (b.y2 > this.elh) { b.y2 = this.elh; b.y = b.y2 - b.h; }
s.element.trigger('cropstart',[s,this.unscale(b)]);
s.updateRaw(b,'move');
s.element.trigger('cropend',[s,this.unscale(b)]);
},
// }}}
// refresh: function(){{{
refresh: function(){
for(var i=0,s=this.ui.multi,l=s.length;i 1) && (this.ui.selection.canDelete))
return this.deleteSelection();
},
// }}}
// deleteSelection: function(){{{
deleteSelection: function(){
if (this.ui.selection) {
this.removeSelection(this.ui.selection);
if (this.ui.multi.length) this.ui.multi[0].focus();
this.ui.selection.refresh();
}
},
// }}}
// animateTo: function(box){{{
animateTo: function(box){
if (this.ui.selection)
this.ui.selection.animateTo(box);
return this;
},
// }}}
// setselect: function(box){{{
setSelect: function(box){
if (this.ui.selection)
this.ui.selection.update(Jcrop.wrapFromXywh(box));
return this;
},
// }}}
//startDrag: function(){{{
startDrag: function(){
var t = this;
return function(e){
var $targ = $(e.target);
var selection = $targ.closest('.'+t.opt.css_selection).data('selection');
var ord = $targ.data('ord');
t.container.trigger('cropstart',[selection,t.unscale(selection.get())]);
selection.startDrag(e,ord);
return false;
};
},
//}}}
// getContainerSize: function(){{{
getContainerSize: function(){
return [ this.container.width(), this.container.height() ];
},
// }}}
// resizeContainer: function(w,h){{{
resizeContainer: function(w,h){
this.container.width(w).height(h);
this.refresh();
},
// }}}
// setImage: function(src,cb){{{
setImage: function(src,cb){
var t = this, targ = t.opt.imgsrc;
if (!targ) return false;
new $.Jcrop.component.ImageLoader(src,null,function(w,h){
t.resizeContainer(w,h);
targ.src = src;
$(targ).width(w).height(h);
t.applySizeConstraints();
t.refresh();
t.container.trigger('cropimage',[t,targ]);
if (typeof cb == 'function')
cb.call(t,w,h);
});
},
// }}}
// update: function(b){{{
update: function(b){
if (this.ui.selection)
this.ui.selection.update(b);
}
// }}}
});
// Jcrop jQuery plugin function
$.fn.Jcrop = function(options,callback){
options = options || {};
var first = this.eq(0).data('Jcrop');
var args = Array.prototype.slice.call(arguments);
// Return API if requested
if (options == 'api') { return first; }
// Allow calling API methods (with arguments)
else if (first && (typeof options == 'string')) {
// Call method if it exists
if (first[options]) {
args.shift();
first[options].apply(first,args);
return first;
}
// Unknown input/method does not exist
return false;
}
// Otherwise, loop over selected elements
this.each(function(){
var t = this, $t = $(this);
var exists = $t.data('Jcrop');
var obj;
// If Jcrop already exists on this element only setOptions()
if (exists)
exists.setOptions(options);
else {
if (!options.stageConstructor)
options.stageConstructor = $.Jcrop.stageConstructor;
options.stageConstructor(this,options,function(stage,options){
var selection = options.setSelect;
if (selection) delete(options.setSelect);
var obj = $.Jcrop.attach(stage.element,options);
if (typeof stage.attach == 'function')
stage.attach(obj);
$t.data('Jcrop',obj);
if (selection) {
obj.newSelection();
obj.setSelect(selection);
}
if (typeof callback == 'function')
callback.call(obj);
});
}
return this;
});
};
/* Modernizr 2.7.1 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-csstransforms-canvas-canvastext-draganddrop-inlinesvg-svg-svgclippaths-touch-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-url_data_uri
*/
;
var Modernizr = (function( window, document, undefined ) {
var version = '2.7.1',
Modernizr = {},
docElement = document.documentElement,
mod = 'modernizr',
modElem = document.createElement(mod),
mStyle = modElem.style,
inputElem ,
toString = {}.toString,
prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
omPrefixes = 'Webkit Moz O ms',
cssomPrefixes = omPrefixes.split(' '),
domPrefixes = omPrefixes.toLowerCase().split(' '),
ns = {'svg': 'http://www.w3.org/2000/svg'},
tests = {},
inputs = {},
attrs = {},
classes = [],
slice = classes.slice,
featureName,
injectElementWithStyles = function( rule, callback, nodes, testnames ) {
var style, ret, node, docOverflow,
div = document.createElement('div'),
body = document.body,
fakeBody = body || document.createElement('body');
if ( parseInt(nodes, 10) ) {
while ( nodes-- ) {
node = document.createElement('div');
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
div.appendChild(node);
}
}
style = ['',''].join('');
div.id = mod;
(body ? div : fakeBody).innerHTML += style;
fakeBody.appendChild(div);
if ( !body ) {
fakeBody.style.background = '';
fakeBody.style.overflow = 'hidden';
docOverflow = docElement.style.overflow;
docElement.style.overflow = 'hidden';
docElement.appendChild(fakeBody);
}
ret = callback(div, rule);
if ( !body ) {
fakeBody.parentNode.removeChild(fakeBody);
docElement.style.overflow = docOverflow;
} else {
div.parentNode.removeChild(div);
}
return !!ret;
},
isEventSupported = (function() {
var TAGNAMES = {
'select': 'input', 'change': 'input',
'submit': 'form', 'reset': 'form',
'error': 'img', 'load': 'img', 'abort': 'img'
};
function isEventSupported( eventName, element ) {
element = element || document.createElement(TAGNAMES[eventName] || 'div');
eventName = 'on' + eventName;
var isSupported = eventName in element;
if ( !isSupported ) {
if ( !element.setAttribute ) {
element = document.createElement('div');
}
if ( element.setAttribute && element.removeAttribute ) {
element.setAttribute(eventName, '');
isSupported = is(element[eventName], 'function');
if ( !is(element[eventName], 'undefined') ) {
element[eventName] = undefined;
}
element.removeAttribute(eventName);
}
}
element = null;
return isSupported;
}
return isEventSupported;
})(),
_hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
hasOwnProp = function (object, property) {
return _hasOwnProperty.call(object, property);
};
}
else {
hasOwnProp = function (object, property) {
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
};
}
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != "function") {
throw new TypeError();
}
var args = slice.call(arguments, 1),
bound = function () {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F();
var result = target.apply(
self,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return self;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
return bound;
};
}
function setCss( str ) {
mStyle.cssText = str;
}
function setCssAll( str1, str2 ) {
return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
}
function is( obj, type ) {
return typeof obj === type;
}
function contains( str, substr ) {
return !!~('' + str).indexOf(substr);
}
function testProps( props, prefixed ) {
for ( var i in props ) {
var prop = props[i];
if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
return prefixed == 'pfx' ? prop : true;
}
}
return false;
}
function testDOMProps( props, obj, elem ) {
for ( var i in props ) {
var item = obj[props[i]];
if ( item !== undefined) {
if (elem === false) return props[i];
if (is(item, 'function')){
return item.bind(elem || obj);
}
return item;
}
}
return false;
}
function testPropsAll( prop, prefixed, elem ) {
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
if(is(prefixed, "string") || is(prefixed, "undefined")) {
return testProps(props, prefixed);
} else {
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
return testDOMProps(props, prefixed, elem);
}
}
tests['canvas'] = function() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
tests['canvastext'] = function() {
return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
};
tests['touch'] = function() {
var bool;
if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
bool = true;
} else {
injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
bool = node.offsetTop === 9;
});
}
return bool;
};
tests['draganddrop'] = function() {
var div = document.createElement('div');
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
};
tests['csstransforms'] = function() {
return !!testPropsAll('transform');
};
tests['svg'] = function() {
return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
};
tests['inlinesvg'] = function() {
var div = document.createElement('div');
div.innerHTML = '';
return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
};
tests['svgclippaths'] = function() {
return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
};
for ( var feature in tests ) {
if ( hasOwnProp(tests, feature) ) {
featureName = feature.toLowerCase();
Modernizr[featureName] = tests[feature]();
classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
}
}
Modernizr.addTest = function ( feature, test ) {
if ( typeof feature == 'object' ) {
for ( var key in feature ) {
if ( hasOwnProp( feature, key ) ) {
Modernizr.addTest( key, feature[ key ] );
}
}
} else {
feature = feature.toLowerCase();
if ( Modernizr[feature] !== undefined ) {
return Modernizr;
}
test = typeof test == 'function' ? test() : test;
if (typeof enableClasses !== "undefined" && enableClasses) {
docElement.className += ' ' + (test ? '' : 'no-') + feature;
}
Modernizr[feature] = test;
}
return Modernizr;
};
setCss('');
modElem = inputElem = null;
Modernizr._version = version;
Modernizr._prefixes = prefixes;
Modernizr._domPrefixes = domPrefixes;
Modernizr._cssomPrefixes = cssomPrefixes;
Modernizr.hasEvent = isEventSupported;
Modernizr.testProp = function(prop){
return testProps([prop]);
};
Modernizr.testAllProps = testPropsAll;
Modernizr.testStyles = injectElementWithStyles;
return Modernizr;
})(window, window.document);
// data uri test.
// https://github.com/Modernizr/Modernizr/issues/14
// This test is asynchronous. Watch out.
// in IE7 in HTTPS this can cause a Mixed Content security popup.
// github.com/Modernizr/Modernizr/issues/362
// To avoid that you can create a new iframe and inject this.. perhaps..
(function(){
var datauri = new Image();
datauri.onerror = function() {
Modernizr.addTest('datauri', function () { return false; });
};
datauri.onload = function() {
Modernizr.addTest('datauri', function () { return (datauri.width == 1 && datauri.height == 1); });
};
datauri.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
})();
;
// Attach to jQuery object
$.Jcrop = Jcrop;
$.Jcrop.supportsCanvas = Modernizr.canvas;
$.Jcrop.supportsCanvasText = Modernizr.canvastext;
$.Jcrop.supportsDragAndDrop = Modernizr.draganddrop;
$.Jcrop.supportsDataURI = Modernizr.datauri;
$.Jcrop.supportsSVG = Modernizr.svg;
$.Jcrop.supportsInlineSVG = Modernizr.inlinesvg;
$.Jcrop.supportsSVGClipPaths = Modernizr.svgclippaths;
$.Jcrop.supportsCSSTransforms = Modernizr.csstransforms;
$.Jcrop.supportsTouch = Modernizr.touch;
})(jQuery);