更新前端文件
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
## Javascript source files
|
||||
|
||||
The files in this path are Javascript fragments that are compiled together
|
||||
to create the Jcrop.js source file. Also includes LESS CSS source files.
|
||||
|
||||
##### Building with Grunt
|
||||
|
||||
$ npm install
|
||||
$ grunt
|
||||
|
||||
##### Grunt watch
|
||||
|
||||
The Grunt configuration also includes a watch task using grunt-watch.
|
||||
Using `watch` (in a different terminal) will allow you to modify files
|
||||
and have them automatically recompile when changes are detected.
|
||||
|
||||
$ grunt watch
|
||||
|
||||
Read the [grunt documentation](http://gruntjs.com) for more info.
|
||||
@@ -0,0 +1,352 @@
|
||||
// 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<l; i++){
|
||||
if ($.Jcrop.filter[f[i]])
|
||||
obj = new $.Jcrop.filter[f[i]];
|
||||
obj.core = this;
|
||||
if (obj.init) obj.init();
|
||||
this.filter[f[i]] = obj;
|
||||
}
|
||||
},
|
||||
// }}}
|
||||
// getDefaultFilters: function(){{{
|
||||
getDefaultFilters: function(){
|
||||
var rv = [];
|
||||
|
||||
for(var i=0,f=this.opt.applyFilters,l=f.length; i<l; i++)
|
||||
if(this.filter.hasOwnProperty(f[i]))
|
||||
rv.push(this.filter[f[i]]);
|
||||
|
||||
rv.sort(function(x,y){ return x.priority - y.priority; });
|
||||
return rv;
|
||||
},
|
||||
// }}}
|
||||
// setSelection: function(sel){{{
|
||||
setSelection: function(sel){
|
||||
var m = this.ui.multi;
|
||||
var n = [];
|
||||
for(var i=0;i<m.length;i++) {
|
||||
if (m[i] !== sel) n.push(m[i]);
|
||||
m[i].toBack();
|
||||
}
|
||||
n.unshift(sel);
|
||||
this.ui.multi = n;
|
||||
this.ui.selection = sel;
|
||||
sel.toFront();
|
||||
return sel;
|
||||
},
|
||||
// }}}
|
||||
// getSelection: function(raw){{{
|
||||
getSelection: function(raw){
|
||||
var b = this.ui.selection.get();
|
||||
return b;
|
||||
},
|
||||
// }}}
|
||||
// newSelection: function(){{{
|
||||
newSelection: function(sel){
|
||||
if (!sel)
|
||||
sel = new this.opt.selectionComponent();
|
||||
|
||||
sel.init(this);
|
||||
this.setSelection(sel);
|
||||
|
||||
return sel;
|
||||
},
|
||||
// }}}
|
||||
// hasSelection: function(sel){{{
|
||||
hasSelection: function(sel){
|
||||
for(var i=0;i<this.ui.multi;i++)
|
||||
if (sel === this.ui.multi[i]) return true;
|
||||
},
|
||||
// }}}
|
||||
// removeSelection: function(sel){{{
|
||||
removeSelection: function(sel){
|
||||
var i, n = [], m = this.ui.multi;
|
||||
for(var i=0;i<m.length;i++){
|
||||
if (sel !== m[i])
|
||||
n.push(m[i]);
|
||||
else m[i].remove();
|
||||
}
|
||||
return this.ui.multi = n;
|
||||
},
|
||||
// }}}
|
||||
//addFilter: function(filter){{{
|
||||
addFilter: function(filter){
|
||||
for(var i=0,m=this.ui.multi,l=m.length; i<l; i++)
|
||||
m[i].addFilter(filter);
|
||||
|
||||
return this;
|
||||
},
|
||||
//}}}
|
||||
// removeFiltersByTag: function(tag){{{
|
||||
removeFilter: function(filter){
|
||||
for(var i=0,m=this.ui.multi,l=m.length; i<l; i++)
|
||||
m[i].removeFilter(filter);
|
||||
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// blur: function(){{{
|
||||
blur: function(){
|
||||
this.ui.selection.blur();
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// focus: function(){{{
|
||||
focus: function(){
|
||||
this.ui.selection.focus();
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
//initEvents: function(){{{
|
||||
initEvents: function(){
|
||||
var t = this;
|
||||
t.container.on('selectstart',function(e){ return false; })
|
||||
.on('mousedown','.'+t.opt.css_drag,t.startDrag());
|
||||
},
|
||||
//}}}
|
||||
// maxSelect: function(){{{
|
||||
maxSelect: function(){
|
||||
this.setSelect([0,0,this.elw,this.elh]);
|
||||
},
|
||||
// }}}
|
||||
// nudge: function(x,y){{{
|
||||
nudge: function(x,y){
|
||||
var s = this.ui.selection, b = s.get();
|
||||
|
||||
b.x += x;
|
||||
b.x2 += x;
|
||||
b.y += y;
|
||||
b.y2 += y;
|
||||
|
||||
if (b.x < 0) { b.x2 = b.w; b.x = 0; }
|
||||
else if (b.x2 > 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<l;i++)
|
||||
s[i].refresh();
|
||||
},
|
||||
// }}}
|
||||
// blurAll: function(){{{
|
||||
blurAll: function(){
|
||||
var m = this.ui.multi;
|
||||
for(var i=0;i<m.length;i++) {
|
||||
if (m[i] !== sel) n.push(m[i]);
|
||||
m[i].toBack();
|
||||
}
|
||||
},
|
||||
// }}}
|
||||
// scale: function(b){{{
|
||||
scale: function(b){
|
||||
var xs = this.opt.xscale,
|
||||
ys = this.opt.yscale;
|
||||
|
||||
return {
|
||||
x: b.x / xs,
|
||||
y: b.y / ys,
|
||||
x2: b.x2 / xs,
|
||||
y2: b.y2 / ys,
|
||||
w: b.w / xs,
|
||||
h: b.h / ys
|
||||
};
|
||||
},
|
||||
// }}}
|
||||
// unscale: function(b){{{
|
||||
unscale: function(b){
|
||||
var xs = this.opt.xscale,
|
||||
ys = this.opt.yscale;
|
||||
|
||||
return {
|
||||
x: b.x * xs,
|
||||
y: b.y * ys,
|
||||
x2: b.x2 * xs,
|
||||
y2: b.y2 * ys,
|
||||
w: b.w * xs,
|
||||
h: b.h * ys
|
||||
};
|
||||
},
|
||||
// }}}
|
||||
// requestDelete: function(){{{
|
||||
requestDelete: function(){
|
||||
if ((this.ui.multi.length > 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);
|
||||
}
|
||||
// }}}
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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 $('<div />')
|
||||
.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<tw.length;i++){
|
||||
props[tw[i].prop] = tw[i].now; }
|
||||
|
||||
t.stage.setAngle(props.width)
|
||||
.setScale(props.height)
|
||||
.setOffset(props.top,props.left)
|
||||
.redraw();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
Jcrop.stage.Canvas.prototype.getAnimator = function(){
|
||||
return new CanvasAnimator(this);
|
||||
};
|
||||
Jcrop.registerComponent('CanvasAnimator',CanvasAnimator);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* CropAnimator
|
||||
* 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 CropAnimator = function(selection){{{
|
||||
var CropAnimator = function(selection){
|
||||
this.selection = selection;
|
||||
this.core = selection.core;
|
||||
};
|
||||
// }}}
|
||||
|
||||
CropAnimator.prototype = {
|
||||
|
||||
getElement: function(){
|
||||
var b = this.selection.get();
|
||||
|
||||
return $('<div />')
|
||||
.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<tw.length;i++){
|
||||
props[tw[i].prop] = tw[i].now; }
|
||||
|
||||
var b = {
|
||||
x: parseInt(props.left),
|
||||
y: parseInt(props.top),
|
||||
w: parseInt(props.width),
|
||||
h: parseInt(props.height)
|
||||
};
|
||||
|
||||
b.x2 = b.x + b.w;
|
||||
b.y2 = b.y + b.h;
|
||||
|
||||
t.selection.updateRaw(b,'se');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
Jcrop.registerComponent('Animator',CropAnimator);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* DragState
|
||||
* an object that handles dragging events
|
||||
*
|
||||
* This object is used by the built-in selection object to
|
||||
* track a dragging operation on a selection
|
||||
*/
|
||||
// var DragState = function(e,selection,ord){{{
|
||||
var DragState = function(e,selection,ord){
|
||||
var t = this;
|
||||
|
||||
t.x = e.pageX;
|
||||
t.y = e.pageY;
|
||||
|
||||
t.selection = selection;
|
||||
t.eventTarget = selection.core.opt.dragEventTarget;
|
||||
t.orig = selection.get();
|
||||
|
||||
selection.callFilterFunction('refresh');
|
||||
|
||||
var p = selection.core.container.position();
|
||||
t.elx = p.left;
|
||||
t.ely = p.top;
|
||||
|
||||
t.offsetx = 0;
|
||||
t.offsety = 0;
|
||||
t.ord = ord;
|
||||
t.opposite = t.getOppositeCornerOffset();
|
||||
|
||||
t.initEvents(e);
|
||||
|
||||
};
|
||||
// }}}
|
||||
|
||||
DragState.prototype = {
|
||||
// getOppositeCornerOffset: function(){{{
|
||||
// Calculate relative offset of locked corner
|
||||
getOppositeCornerOffset: function(){
|
||||
|
||||
var o = this.orig;
|
||||
var relx = this.x - this.elx - o.x;
|
||||
var rely = this.y - this.ely - o.y;
|
||||
|
||||
switch(this.ord){
|
||||
case 'nw':
|
||||
case 'w':
|
||||
return [ o.w - relx, o.h - rely ];
|
||||
return [ o.x + o.w, o.y + o.h ];
|
||||
|
||||
case 'sw':
|
||||
return [ o.w - relx, -rely ];
|
||||
return [ o.x + o.w, o.y ];
|
||||
|
||||
case 'se':
|
||||
case 's':
|
||||
case 'e':
|
||||
return [ -relx, -rely ];
|
||||
return [ o.x, o.y ];
|
||||
|
||||
case 'ne':
|
||||
case 'n':
|
||||
return [ -relx, o.h - rely ];
|
||||
return [ o.w, o.y + o.h ];
|
||||
}
|
||||
|
||||
return [ null, null ];
|
||||
},
|
||||
// }}}
|
||||
// initEvents: function(e){{{
|
||||
initEvents: function(e){
|
||||
$(this.eventTarget)
|
||||
.on('mousemove.jcrop',this.createDragHandler())
|
||||
.on('mouseup.jcrop',this.createStopHandler());
|
||||
},
|
||||
// }}}
|
||||
// dragEvent: function(e){{{
|
||||
dragEvent: function(e){
|
||||
this.offsetx = e.pageX - this.x;
|
||||
this.offsety = e.pageY - this.y;
|
||||
this.selection.updateRaw(this.getBox(),this.ord);
|
||||
},
|
||||
// }}}
|
||||
// endDragEvent: function(e){{{
|
||||
endDragEvent: function(e){
|
||||
var sel = this.selection;
|
||||
sel.core.container.removeClass('jcrop-dragging');
|
||||
sel.element.trigger('cropend',[sel,sel.core.unscale(sel.get())]);
|
||||
sel.focus();
|
||||
},
|
||||
// }}}
|
||||
// createStopHandler: function(){{{
|
||||
createStopHandler: function(){
|
||||
var t = this;
|
||||
return function(e){
|
||||
$(t.eventTarget).off('.jcrop');
|
||||
t.endDragEvent(e);
|
||||
return false;
|
||||
};
|
||||
},
|
||||
// }}}
|
||||
// createDragHandler: function(){{{
|
||||
createDragHandler: function(){
|
||||
var t = this;
|
||||
return function(e){
|
||||
t.dragEvent(e);
|
||||
return false;
|
||||
};
|
||||
},
|
||||
// }}}
|
||||
//update: function(x,y){{{
|
||||
update: function(x,y){
|
||||
var t = this;
|
||||
t.offsetx = x - t.x;
|
||||
t.offsety = y - t.y;
|
||||
},
|
||||
//}}}
|
||||
//resultWrap: function(d){{{
|
||||
resultWrap: function(d){
|
||||
var b = {
|
||||
x: Math.min(d[0],d[2]),
|
||||
y: Math.min(d[1],d[3]),
|
||||
x2: Math.max(d[0],d[2]),
|
||||
y2: Math.max(d[1],d[3])
|
||||
};
|
||||
|
||||
b.w = b.x2 - b.x;
|
||||
b.h = b.y2 - b.y;
|
||||
|
||||
return b;
|
||||
},
|
||||
//}}}
|
||||
//getBox: function(){{{
|
||||
getBox: function(){
|
||||
var t = this;
|
||||
var o = t.orig;
|
||||
var _c = { x2: o.x + o.w, y2: o.y + o.h };
|
||||
switch(t.ord){
|
||||
case 'n': return t.resultWrap([ o.x, t.offsety + o.y, _c.x2, _c.y2 ]);
|
||||
case 's': return t.resultWrap([ o.x, o.y, _c.x2, t.offsety + _c.y2 ]);
|
||||
case 'e': return t.resultWrap([ o.x, o.y, t.offsetx + _c.x2, _c.y2 ]);
|
||||
case 'w': return t.resultWrap([ o.x + t.offsetx, o.y, _c.x2, _c.y2 ]);
|
||||
case 'sw': return t.resultWrap([ t.offsetx + o.x, o.y, _c.x2, t.offsety + _c.y2 ]);
|
||||
case 'se': return t.resultWrap([ o.x, o.y, t.offsetx + _c.x2, t.offsety + _c.y2 ]);
|
||||
case 'ne': return t.resultWrap([ o.x, t.offsety + o.y, t.offsetx + _c.x2, _c.y2 ]);
|
||||
case 'nw': return t.resultWrap([ t.offsetx + o.x, t.offsety + o.y, _c.x2, _c.y2 ]);
|
||||
case 'move':
|
||||
_c.nx = o.x + t.offsetx;
|
||||
_c.ny = o.y + t.offsety;
|
||||
return t.resultWrap([ _c.nx, _c.ny, _c.nx + o.w, _c.ny + o.h ]);
|
||||
}
|
||||
}
|
||||
//}}}
|
||||
};
|
||||
Jcrop.registerComponent('DragState',DragState);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* EventManager
|
||||
* provides internal event support
|
||||
*/
|
||||
var EventManager = function(core){
|
||||
this.core = core;
|
||||
};
|
||||
EventManager.prototype = {
|
||||
on: function(n,cb){ $(this).on(n,cb); },
|
||||
off: function(n){ $(this).off(n); },
|
||||
trigger: function(n){ $(this).trigger(n); }
|
||||
};
|
||||
Jcrop.registerComponent('EventManager',EventManager);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Image Loader
|
||||
* Reliably pre-loads images
|
||||
*/
|
||||
// var ImageLoader = function(src,element,cb){{{
|
||||
var ImageLoader = function(src,element,cb){
|
||||
this.src = src;
|
||||
if (!element) element = new Image;
|
||||
this.element = element;
|
||||
this.callback = cb;
|
||||
this.load();
|
||||
};
|
||||
// }}}
|
||||
|
||||
$.extend(ImageLoader,{
|
||||
// attach: function(el,cb){{{
|
||||
attach: function(el,cb){
|
||||
return new ImageLoader(el.src,el,cb);
|
||||
},
|
||||
// }}}
|
||||
// prototype: {{{
|
||||
prototype: {
|
||||
getDimensions: function(){
|
||||
var el = this.element;
|
||||
|
||||
if (el.naturalWidth)
|
||||
return [ el.naturalWidth, el. naturalHeight ];
|
||||
|
||||
if (el.width)
|
||||
return [ el.width, el.height ];
|
||||
|
||||
return null;
|
||||
},
|
||||
fireCallback: function(){
|
||||
this.element.onload = null;
|
||||
if (typeof this.callback == 'function')
|
||||
this.callback.apply(this,this.getDimensions());
|
||||
},
|
||||
isLoaded: function(){
|
||||
return this.element.complete;
|
||||
},
|
||||
load: function(){
|
||||
var t = this;
|
||||
var el = t.element;
|
||||
|
||||
el.src = t.src;
|
||||
|
||||
if (t.isLoaded()) t.fireCallback();
|
||||
else t.element.onload = function(e){
|
||||
t.fireCallback();
|
||||
};
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
});
|
||||
Jcrop.registerComponent('ImageLoader',ImageLoader);
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* JcropTouch
|
||||
* Detects and enables mobile touch support
|
||||
*/
|
||||
// var JcropTouch = function(core){{{
|
||||
var JcropTouch = function(core){
|
||||
this.core = core;
|
||||
this.init();
|
||||
};
|
||||
// }}}
|
||||
|
||||
$.extend(JcropTouch,{
|
||||
// support: function(){{{
|
||||
support: function(){
|
||||
if(('ontouchstart' in window) || 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);
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* 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 = $('<div />').addClass(o.css_selection).data({ selection: t });
|
||||
t.frame = $('<button />').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<this.filter.length;i++)
|
||||
if (this.filter[i][f]) this.filter[i][f](this);
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
//addFilter: function(filter){{{
|
||||
addFilter: function(filter){
|
||||
filter.core = this.core;
|
||||
if (!this.hasFilter(filter)) {
|
||||
this.filter.push(filter);
|
||||
this.sortFilters();
|
||||
if (filter.init) filter.init();
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
//}}}
|
||||
// hasFilter: function(filter){{{
|
||||
hasFilter: function(filter){
|
||||
var i, f = this.filter, n = [];
|
||||
for(i=0;i<f.length;i++) if (f[i] === filter) return true;
|
||||
},
|
||||
// }}}
|
||||
// sortFilters: function(){{{
|
||||
sortFilters: function(){
|
||||
this.filter.sort(
|
||||
function(x,y){ return x.priority - y.priority; }
|
||||
);
|
||||
},
|
||||
// }}}
|
||||
//clearFilters: function(){{{
|
||||
clearFilters: function(){
|
||||
var i, f = this.filter;
|
||||
|
||||
for(var i=0;i<f.length;i++)
|
||||
if (f[i].destroy) f[i].destroy();
|
||||
|
||||
this.filter = [];
|
||||
},
|
||||
//}}}
|
||||
// removeFiltersByTag: function(tag){{{
|
||||
removeFilter: function(tag){
|
||||
var i, f = this.filter, n = [];
|
||||
|
||||
for(var i=0;i<f.length;i++)
|
||||
if ((f[i].tag && (f[i].tag == tag)) || (tag === f[i])){
|
||||
if (f[i].destroy) f[i].destroy();
|
||||
}
|
||||
else n.push(f[i]);
|
||||
|
||||
this.filter = n;
|
||||
},
|
||||
// }}}
|
||||
// runFilters: function(b,ord){{{
|
||||
runFilters: function(b,ord){
|
||||
for(var i=0;i<this.filter.length;i++)
|
||||
b = this.filter[i].filter(b,ord,this);
|
||||
return b;
|
||||
},
|
||||
// }}}
|
||||
//endDrag: function(){{{
|
||||
endDrag: function(){
|
||||
if (this.state) {
|
||||
$(document.body).off('.jcrop');
|
||||
this.focus();
|
||||
this.state = null;
|
||||
}
|
||||
},
|
||||
//}}}
|
||||
// startDrag: function(e,ord){{{
|
||||
startDrag: function(e,ord){
|
||||
var t = this;
|
||||
var m = t.core;
|
||||
|
||||
ord = ord || $(e.target).data('ord');
|
||||
|
||||
this.focus();
|
||||
|
||||
if ((ord == 'move') && t.element.hasClass(t.core.opt.css_nodrag))
|
||||
return false;
|
||||
|
||||
this.state = new Jcrop.component.DragState(e,this,ord);
|
||||
return false;
|
||||
},
|
||||
// }}}
|
||||
// allowSelect: function(v){{{
|
||||
allowSelect: function(v){
|
||||
if (v === undefined) v = this.canSelect;
|
||||
|
||||
if (v && this.canSelect) this.frame.attr('disabled',false);
|
||||
else this.frame.attr('disabled','disabled');
|
||||
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// allowDrag: function(v){{{
|
||||
allowDrag: function(v){
|
||||
var t = this, o = t.core.opt;
|
||||
if (v == undefined) v = t.canDrag;
|
||||
|
||||
if (v && t.canDrag) t.element.removeClass(o.css_nodrag);
|
||||
else t.element.addClass(o.css_nodrag);
|
||||
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// allowResize: function(v){{{
|
||||
allowResize: function(v){
|
||||
var t = this, o = t.core.opt;
|
||||
if (v == undefined) v = t.canResize;
|
||||
|
||||
if (v && t.canResize) t.element.removeClass(o.css_noresize);
|
||||
else t.element.addClass(o.css_noresize);
|
||||
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// remove: function(){{{
|
||||
remove: function(){
|
||||
this.element.trigger('cropremove',this);
|
||||
this.element.remove();
|
||||
},
|
||||
// }}}
|
||||
// toBack: function(){{{
|
||||
toBack: function(){
|
||||
this.active = false;
|
||||
this.element.removeClass('jcrop-current jcrop-focus');
|
||||
},
|
||||
// }}}
|
||||
// toFront: function(){{{
|
||||
toFront: function(){
|
||||
this.active = true;
|
||||
this.element.addClass('jcrop-current');
|
||||
this.callFilterFunction('refresh');
|
||||
this.refresh();
|
||||
},
|
||||
// }}}
|
||||
// redraw: function(b){{{
|
||||
redraw: function(b){
|
||||
this.moveTo(b.x,b.y);
|
||||
this.resize(b.w,b.h);
|
||||
this.last = b;
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// update: function(b,ord){{{
|
||||
update: function(b,ord){
|
||||
return this.updateRaw(this.core.scale(b),ord);
|
||||
},
|
||||
// }}}
|
||||
// update: function(b,ord){{{
|
||||
updateRaw: function(b,ord){
|
||||
b = this.runFilters(b,ord);
|
||||
this.redraw(b);
|
||||
this.element.trigger('cropmove',[this,this.core.unscale(b)]);
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
// animateTo: function(box,cb){{{
|
||||
animateTo: function(box,cb){
|
||||
var ca = new Jcrop.component.Animator(this),
|
||||
b = this.core.scale(Jcrop.wrapFromXywh(box));
|
||||
|
||||
ca.animate(b.x,b.y,b.w,b.h,cb);
|
||||
},
|
||||
// }}}
|
||||
// center: function(instant){{{
|
||||
center: function(instant){
|
||||
var b = this.get(), m = this.core;
|
||||
var elw = m.container.width(), elh = m.container.height();
|
||||
var box = [ (elw-b.w)/2, (elh-b.h)/2, b.w, b.h ];
|
||||
return this[instant?'setSelect':'animateTo'](box);
|
||||
},
|
||||
// }}}
|
||||
//createElement: function(type,ord){{{
|
||||
createElement: function(type,ord){
|
||||
return $('<div />').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<d.length; i++)
|
||||
fr.append(t.createElement(o.css_dragbars,d[i]));
|
||||
|
||||
for(i=0; i<h.length; i++)
|
||||
fr.append(t.createElement(o.css_handles,h[i]));
|
||||
|
||||
for(i=0; i<b.length; i++)
|
||||
fr.append(t.createElement(o.css_borders,b[i]));
|
||||
}
|
||||
//}}}
|
||||
}
|
||||
});
|
||||
Jcrop.registerComponent('Selection',Selection);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* StageDrag
|
||||
* Facilitates dragging
|
||||
*/
|
||||
// var StageDrag = function(manager,opt){{{
|
||||
var StageDrag = function(manager,opt){
|
||||
$.extend(this,StageDrag.defaults,opt || {});
|
||||
this.manager = manager;
|
||||
this.core = manager.core;
|
||||
};
|
||||
// }}}
|
||||
// StageDrag.defaults = {{{
|
||||
StageDrag.defaults = {
|
||||
offset: [ -8, -8 ],
|
||||
active: true,
|
||||
minsize: [ 20, 20 ]
|
||||
};
|
||||
// }}}
|
||||
|
||||
$.extend(StageDrag.prototype,{
|
||||
// start: function(e){{{
|
||||
start: function(e){
|
||||
var c = this.core;
|
||||
|
||||
// Do nothing if allowSelect is off
|
||||
if (!c.opt.allowSelect) return;
|
||||
|
||||
// Also do nothing if we can't draw any more selections
|
||||
if (c.opt.multi && c.opt.multiMax && (c.ui.multi.length >= 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<m.length;i++) m[i].remove();
|
||||
c.ui.multi = [];
|
||||
}
|
||||
// If not, only remove the currently active selection
|
||||
else {
|
||||
c.removeSelection(c.ui.selection);
|
||||
}
|
||||
}
|
||||
|
||||
c.container.addClass('jcrop-dragging');
|
||||
|
||||
// Create the new selection
|
||||
var sel = c.newSelection()
|
||||
// and position it
|
||||
.updateRaw(Jcrop.wrapFromXywh([origx,origy,1,1]));
|
||||
|
||||
sel.element.trigger('cropstart',[sel,this.core.unscale(sel.get())]);
|
||||
|
||||
return sel.startDrag(e,'se');
|
||||
},
|
||||
// }}}
|
||||
// end: function(x,y){{{
|
||||
end: function(x,y){
|
||||
this.drag(x,y);
|
||||
var b = this.sel.get();
|
||||
|
||||
this.core.container.removeClass('jcrop-dragging');
|
||||
|
||||
if ((b.w < this.minsize[0]) || (b.h < this.minsize[1]))
|
||||
this.core.requestDelete();
|
||||
|
||||
else this.sel.focus();
|
||||
}
|
||||
// }}}
|
||||
});
|
||||
Jcrop.registerComponent('StageDrag',StageDrag);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* StageManager
|
||||
* Provides basic stage-specific functionality
|
||||
*/
|
||||
// var StageManager = function(core){{{
|
||||
var StageManager = function(core){
|
||||
this.core = core;
|
||||
this.ui = core.ui;
|
||||
this.init();
|
||||
};
|
||||
// }}}
|
||||
|
||||
$.extend(StageManager.prototype,{
|
||||
// init: function(){{{
|
||||
init: function(){
|
||||
this.setupEvents();
|
||||
this.dragger = new StageDrag(this);
|
||||
},
|
||||
// }}}
|
||||
// tellConfigUpdate: function(options){{{
|
||||
tellConfigUpdate: function(options){
|
||||
for(var i=0,m=this.ui.multi,l=m.length;i<l;i++)
|
||||
if (m[i].setOptions && (m[i].linked || (this.core.opt.linkCurrent && m[i] == this.ui.selection)))
|
||||
m[i].setOptions(options);
|
||||
},
|
||||
// }}}
|
||||
// startDragHandler: function(){{{
|
||||
startDragHandler: function(){
|
||||
var t = this;
|
||||
return function(e){
|
||||
if (!e.button || t.core.opt.is_ie_lt9) return t.dragger.start(e);
|
||||
};
|
||||
},
|
||||
// }}}
|
||||
// removeEvents: function(){{{
|
||||
removeEvents: function(){
|
||||
this.core.event.off('.jcrop-stage');
|
||||
this.core.container.off('.jcrop-stage');
|
||||
},
|
||||
// }}}
|
||||
// shimLegacyHandlers: function(options){{{
|
||||
// This method uses the legacyHandlers configuration object to
|
||||
// gracefully wrap old-style Jcrop events with new ones
|
||||
shimLegacyHandlers: function(options){
|
||||
var _x = {}, core = this.core, tmp;
|
||||
|
||||
$.each(core.opt.legacyHandlers,function(k,i){
|
||||
if (k in options) {
|
||||
tmp = options[k];
|
||||
core.container.off('.jcrop-'+k)
|
||||
.on(i+'.jcrop.jcrop-'+k,function(e,s,c){
|
||||
tmp.call(core,c);
|
||||
});
|
||||
delete options[k];
|
||||
}
|
||||
});
|
||||
},
|
||||
// }}}
|
||||
// setupEvents: function(){{{
|
||||
setupEvents: function(){
|
||||
var t = this, c = t.core;
|
||||
|
||||
c.event.on('configupdate.jcrop-stage',function(e){
|
||||
t.shimLegacyHandlers(c.opt);
|
||||
t.tellConfigUpdate(c.opt)
|
||||
c.container.trigger('cropconfig',[c,c.opt]);
|
||||
});
|
||||
|
||||
this.core.container
|
||||
.on('mousedown.jcrop.jcrop-stage',this.startDragHandler());
|
||||
}
|
||||
// }}}
|
||||
});
|
||||
Jcrop.registerComponent('StageManager',StageManager);
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
var Thumbnailer = function(){
|
||||
};
|
||||
|
||||
$.extend(Thumbnailer,{
|
||||
defaults: {
|
||||
// Set to a specific Selection object
|
||||
// If this value is set, the preview will only track that Selection
|
||||
selection: null,
|
||||
|
||||
fading: true,
|
||||
fadeDelay: 1000,
|
||||
fadeDuration: 1000,
|
||||
autoHide: false,
|
||||
width: 80,
|
||||
height: 80,
|
||||
_hiding: null
|
||||
},
|
||||
|
||||
prototype: {
|
||||
recopyCanvas: function(){
|
||||
var s = this.core.ui.stage, cxt = s.context;
|
||||
this.context.putImageData(cxt.getImageData(0,0,s.canvas.width,s.canvas.height),0,0);
|
||||
},
|
||||
init: function(core,options){
|
||||
var t = this;
|
||||
this.core = core;
|
||||
$.extend(this,Thumbnailer.defaults,options);
|
||||
t.initEvents();
|
||||
t.refresh();
|
||||
t.insertElements();
|
||||
if (t.selection) {
|
||||
t.renderSelection(t.selection);
|
||||
t.selectionTarget = t.selection.element[0];
|
||||
} else if (t.core.ui.selection) {
|
||||
t.renderSelection(t.core.ui.selection);
|
||||
}
|
||||
|
||||
if (t.core.ui.stage.canvas) {
|
||||
t.context = t.preview[0].getContext('2d');
|
||||
t.core.container.on('cropredraw',function(e){
|
||||
t.recopyCanvas();
|
||||
t.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
updateImage: function(imgel){
|
||||
this.preview.remove();
|
||||
this.preview = $($.Jcrop.imageClone(imgel));
|
||||
this.element.append(this.preview);
|
||||
this.refresh();
|
||||
return this;
|
||||
},
|
||||
insertElements: function(){
|
||||
this.preview = $($.Jcrop.imageClone(this.core.ui.stage.imgsrc));
|
||||
|
||||
this.element = $('<div />').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);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
|
||||
@white: white;
|
||||
@black: black;
|
||||
|
||||
@selectionBorderWidth: 1px;
|
||||
@selectionBackgroundImage: "Jcrop.gif";
|
||||
@selectionBackgroundColor: @white;
|
||||
@selectionBackground: @selectionBackgroundColor url(@selectionBackgroundImage);
|
||||
|
||||
// Setting some variables to
|
||||
// Used to set handle and dragbar size/width
|
||||
// To center on a 1px selection line, use an odd number
|
||||
@grabSize: 9px;
|
||||
|
||||
// Used to offset handles and dragbar
|
||||
// Default value will center on 1px selection line
|
||||
@grabOffset: (floor(@grabSize/2)+1) * -1;
|
||||
|
||||
@handleSize: @grabSize;
|
||||
@handleOffset: @grabOffset;
|
||||
@handleBorderWidth: 1px;
|
||||
@handleBorderColor: #eee;
|
||||
@handleBorderStyle: solid;
|
||||
@handleBackgroundColor: rgba(49,28,28,0.58);
|
||||
@handleOpacity: 0.8;
|
||||
|
||||
@dragbarWidth: @grabSize;
|
||||
@dragbarOffset: @grabOffset;
|
||||
|
||||
/*
|
||||
The outer-most container in a typical Jcrop instance
|
||||
If you are having difficulty with formatting related to styles
|
||||
on a parent element, place any fixes here or in a like selector
|
||||
|
||||
You can also style this element if you want to add a border, etc
|
||||
A better method for styling can be seen below with .jcrop-light
|
||||
(Add a class to the holder and style elements for that extended class)
|
||||
*/
|
||||
.jcrop-active {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
|
||||
/* IE10 touch compatibility */ -ms-touch-action: none;
|
||||
}
|
||||
|
||||
.jcrop-dragging {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.jcrop-selection {
|
||||
z-index: 2;
|
||||
&.jcrop-current { z-index: 4; }
|
||||
}
|
||||
|
||||
/* Selection Borders */
|
||||
.jcrop-border {
|
||||
background: @selectionBackground;
|
||||
line-height: 1px !important;
|
||||
font-size: 0 !important;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
filter: Alpha(opacity=50) !important;
|
||||
opacity: 0.5 !important;
|
||||
&.ord-w, &.ord-e, &.ord-n { top: 0px; }
|
||||
&.ord-n, &.ord-s { width: 100%; height: @selectionBorderWidth !important; }
|
||||
&.ord-w, &.ord-e { height: 100%; width: @selectionBorderWidth !important; }
|
||||
&.ord-e { right: -@selectionBorderWidth; }
|
||||
&.ord-n { top: -@selectionBorderWidth; }
|
||||
&.ord-w { left: -@selectionBorderWidth; }
|
||||
&.ord-s { bottom: -@selectionBorderWidth; }
|
||||
}
|
||||
|
||||
.jcrop-selection {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jcrop-box {
|
||||
z-index: 2;
|
||||
display: block;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0;
|
||||
&:hover { background: none; }
|
||||
&:active { background: none; }
|
||||
&:focus { outline: 1px rgba(128,128,128,.65) dotted; }
|
||||
}
|
||||
|
||||
.jcrop-active, .jcrop-box { position: relative; }
|
||||
.jcrop-box { width: 100%; height: 100%; cursor: move; }
|
||||
|
||||
.handles (@handleSize;@handleOffset;@bgColor;@bgOpacity;@borderWidth;@borderColor;@borderStyle) {
|
||||
|
||||
z-index: 4;
|
||||
@ieopacity: @bgOpacity * 100;
|
||||
font-size: 0;
|
||||
background-color: @bgColor;
|
||||
border: @borderWidth @borderColor @borderStyle;
|
||||
width: @handleSize;
|
||||
height: @handleSize;
|
||||
font-size: 0;
|
||||
position: absolute;
|
||||
filter: Alpha(opacity=@ieopacity) !important;
|
||||
opacity: @bgOpacity !important;
|
||||
|
||||
&.ord-n {left:50%;margin-left:@handleOffset;margin-top:@handleOffset;top:0;cursor:n-resize;}
|
||||
&.ord-s {bottom:0;left:50%;margin-bottom:@handleOffset;margin-left:@handleOffset;cursor:s-resize;}
|
||||
&.ord-e {margin-right:@handleOffset;margin-top:@handleOffset;right:0;top:50%;cursor:e-resize;}
|
||||
&.ord-w {left:0;margin-left:@handleOffset;margin-top:@handleOffset;top:50%;cursor:w-resize;}
|
||||
&.ord-nw {left:0;margin-left:@handleOffset;margin-top:@handleOffset;top:0;cursor:nw-resize;}
|
||||
&.ord-ne {margin-right:@handleOffset;margin-top:@handleOffset;right:0;top:0;cursor:ne-resize;}
|
||||
&.ord-se {bottom:0;margin-bottom:@handleOffset;margin-right:@handleOffset;right:0;cursor:se-resize;}
|
||||
&.ord-sw {bottom:0;left:0;margin-bottom:@handleOffset;margin-left:@handleOffset;cursor:sw-resize;}
|
||||
|
||||
}
|
||||
|
||||
.standard-handles (@handleSize;@bgColor;@bgOpacity;@borderColor) {
|
||||
@handleOffset: (floor(@handleSize/2)+1) * -1;
|
||||
.handles(@handleSize;@handleOffset;@bgColor;@bgOpacity;@handleBorderWidth;@borderColor;@handleBorderStyle);
|
||||
}
|
||||
|
||||
/* Selection Handles */
|
||||
|
||||
.jcrop-handle {
|
||||
.standard-handles(@handleSize;@handleBackgroundColor;@handleOpacity;@handleBorderColor);
|
||||
}
|
||||
|
||||
/* Larger Selection Handles for Touch */
|
||||
|
||||
.jcrop-touch .jcrop-handle {
|
||||
.standard-handles(@handleSize * 2;@handleBackgroundColor;@handleOpacity;@handleBorderColor);
|
||||
}
|
||||
|
||||
/* Selection Dragbars */
|
||||
|
||||
.jcrop-dragbar {
|
||||
|
||||
font-size: 0;
|
||||
position: absolute;
|
||||
|
||||
&.ord-n, &.ord-s {height:@dragbarWidth !important;width:100%;}
|
||||
&.ord-e, &.ord-w { top:0px; height:100%;width:@dragbarWidth !important;}
|
||||
&.ord-n {margin-top:@dragbarOffset;cursor:n-resize; top:0px; }
|
||||
&.ord-s {bottom:0;margin-bottom:@dragbarOffset;cursor:s-resize;}
|
||||
&.ord-e {margin-right:@dragbarOffset;right:0;cursor:e-resize;}
|
||||
&.ord-w {margin-left:@dragbarOffset;cursor:w-resize;}
|
||||
|
||||
}
|
||||
|
||||
/* Shading panels */
|
||||
|
||||
.jcrop-shades {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
div { cursor: crosshair; }
|
||||
}
|
||||
|
||||
/* Various special states */
|
||||
|
||||
.jcrop-noresize {
|
||||
.jcrop-dragbar,
|
||||
.jcrop-handle
|
||||
{ display: none; }
|
||||
}
|
||||
|
||||
.jcrop-selection.jcrop-nodrag .jcrop-box,
|
||||
.jcrop-nodrag .jcrop-shades div
|
||||
{ cursor: default; }
|
||||
|
||||
/* The "jcrop-light" class/extension */
|
||||
|
||||
.jcrop-light {
|
||||
.jcrop-border {
|
||||
background: @white;
|
||||
filter:Alpha(opacity=70)!important;
|
||||
opacity:.70!important;
|
||||
}
|
||||
.jcrop-handle {
|
||||
background-color: @black;
|
||||
border-color: @white;
|
||||
}
|
||||
}
|
||||
|
||||
/* The "jcrop-dark" class/extension */
|
||||
|
||||
.jcrop-dark {
|
||||
.jcrop-border {
|
||||
background: @black;
|
||||
filter: Alpha(opacity=70) !important;
|
||||
opacity: 0.7 !important;
|
||||
}
|
||||
.jcrop-handle {
|
||||
background-color: @white;
|
||||
border-color: @black;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple macro to turn off the antlines */
|
||||
|
||||
.solid-line {
|
||||
.jcrop-border {
|
||||
background: @selectionBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
.jcrop-thumb {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Fix for twitter bootstrap et al. */
|
||||
|
||||
.jcrop-active img,
|
||||
.jcrop-thumb img,
|
||||
.jcrop-thumb canvas {
|
||||
min-width: none;
|
||||
min-height: none;
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
/* Improved multiple selection styles - in progress */
|
||||
|
||||
.jcrop-hl-active {
|
||||
.jcrop-border {
|
||||
filter:Alpha(opacity=20)!important;
|
||||
opacity:.20!important;
|
||||
}
|
||||
.jcrop-handle {
|
||||
filter:Alpha(opacity=10)!important;
|
||||
opacity:.10!important;
|
||||
}
|
||||
.jcrop-selection:hover {
|
||||
.jcrop-border {
|
||||
background-color: #ccc;
|
||||
filter:Alpha(opacity=50)!important;
|
||||
opacity:.50!important;
|
||||
}
|
||||
/*
|
||||
.jcrop-handle {
|
||||
filter:Alpha(opacity=35)!important;
|
||||
opacity:.35!important;
|
||||
}
|
||||
*/
|
||||
}
|
||||
.jcrop-selection.jcrop-current {
|
||||
.jcrop-border {
|
||||
background: gray url('Jcrop.gif');
|
||||
opacity:.35!important;
|
||||
filter:Alpha(opacity=35)!important;
|
||||
}
|
||||
.jcrop-handle {
|
||||
filter:Alpha(opacity=30)!important;
|
||||
opacity:.30!important;
|
||||
}
|
||||
}
|
||||
.jcrop-selection.jcrop-focus {
|
||||
.jcrop-border {
|
||||
background: url('Jcrop.gif');
|
||||
opacity:.65!important;
|
||||
filter:Alpha(opacity=65)!important;
|
||||
}
|
||||
.jcrop-handle {
|
||||
filter:Alpha(opacity=60)!important;
|
||||
opacity:.60!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent background on button element */
|
||||
button.jcrop-box { background: none; }
|
||||
@@ -0,0 +1,8 @@
|
||||
## LESScss source files
|
||||
|
||||
Files in this folder are used to compile the Jcrop.css file from .less definitions.
|
||||
|
||||
##### Compiling with Grunt
|
||||
|
||||
$ npm install
|
||||
$ grunt css
|
||||
@@ -0,0 +1,64 @@
|
||||
/*!
|
||||
* Bootstrap v2.2.1
|
||||
*
|
||||
* Copyright 2012 Twitter, Inc
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
||||
*/
|
||||
|
||||
// CSS Reset
|
||||
@import "_reset.less";
|
||||
|
||||
// Core variables and mixins
|
||||
@import "_variables.less"; // Modify this for custom colors, font-sizes, etc
|
||||
@import "bs/less/mixins.less";
|
||||
|
||||
// Grid system and page structure
|
||||
@import "bs/less/scaffolding.less";
|
||||
@import "bs/less/grid.less";
|
||||
@import "bs/less/layouts.less";
|
||||
|
||||
// Base CSS
|
||||
@import "bs/less/type.less";
|
||||
@import "bs/less/code.less";
|
||||
@import "bs/less/forms.less";
|
||||
@import "bs/less/tables.less";
|
||||
|
||||
// Components: common
|
||||
@import "bs/less/sprites.less";
|
||||
@import "bs/less/dropdowns.less";
|
||||
@import "bs/less/wells.less";
|
||||
@import "bs/less/component-animations.less";
|
||||
@import "bs/less/close.less";
|
||||
|
||||
// Components: Buttons & Alerts
|
||||
@import "bs/less/buttons.less";
|
||||
@import "bs/less/button-groups.less";
|
||||
@import "bs/less/alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less
|
||||
|
||||
// Components: Nav
|
||||
@import "bs/less/navs.less";
|
||||
@import "bs/less/navbar.less";
|
||||
@import "bs/less/breadcrumbs.less";
|
||||
@import "bs/less/pagination.less";
|
||||
@import "bs/less/pager.less";
|
||||
|
||||
// Components: Popovers
|
||||
@import "bs/less/modals.less";
|
||||
@import "bs/less/tooltip.less";
|
||||
@import "bs/less/popovers.less";
|
||||
|
||||
// Components: Misc
|
||||
//@import "bs/less/thumbnails.less";
|
||||
@import "bs/less/media.less";
|
||||
@import "bs/less/labels-badges.less";
|
||||
@import "bs/less/progress-bars.less";
|
||||
@import "bs/less/accordion.less";
|
||||
@import "bs/less/carousel.less";
|
||||
@import "bs/less/hero-unit.less";
|
||||
|
||||
// Utility classes
|
||||
@import "bs/less/utilities.less"; // Has to be last to override when necessary
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// Modals
|
||||
// Adapted from http://github.com/necolas/normalize.css
|
||||
// --------------------------------------------------
|
||||
|
||||
|
||||
// Display in IE6-9 and FF3
|
||||
// -------------------------
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Display block in IE6-9 and FF3
|
||||
// -------------------------
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
video {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
// Prevents modern browsers from displaying 'audio' without controls
|
||||
// -------------------------
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Base settings
|
||||
// -------------------------
|
||||
|
||||
html {
|
||||
font-size: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
// Focus states
|
||||
a:focus {
|
||||
.tab-focus();
|
||||
}
|
||||
// Hover & Active
|
||||
a:hover,
|
||||
a:active {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
// Prevents sub and sup affecting line-height in all browsers
|
||||
// -------------------------
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
// Forms
|
||||
// -------------------------
|
||||
|
||||
// Font size in all browsers, margin changes, misc consistency
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
button,
|
||||
input {
|
||||
*overflow: visible; // Inner spacing ie IE6/7
|
||||
line-height: normal; // FF3/4 have !important on line-height in UA stylesheet
|
||||
}
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
button,
|
||||
html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls.
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS.
|
||||
cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others.
|
||||
}
|
||||
input[type="search"] { // Appearance in Safari/Chrome
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
input[type="search"]::-webkit-search-decoration,
|
||||
input[type="search"]::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
|
||||
}
|
||||
textarea {
|
||||
overflow: auto; // Remove vertical scrollbar in IE6-9
|
||||
vertical-align: top; // Readability and alignment cross-browser
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
.tapmodo-logo
|
||||
{
|
||||
display: block;
|
||||
width: 103px;
|
||||
height: 21px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGcAAAAVCAYAAABbq/AzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABUNJREFUeNrsWX9oU1cUvn0pkUDlSaDSEcgoRAqFN1IqhY79IRuFDUFRFEHp6LBYMhRBURREQSYbW5UOpaIoSkVpURDEYZlMWhiWDQNloigWgsFCoFCQBQphj3nu+C4cD/e+NCOTsnjgI+/d3nvfuef3uW0aHh5WjLJAHO8zhMdq+dRGCAhJwoR6T+OEDJ5vEb6rZXEzfjsIo4RPLXMWCPcJhwnzEXvlsIem1++V8w/1EtJ4fl7rYg+a/cOhGE2thJ2YE0Ts5bPnsIEV0kKI1WMjD5udg7VHURJKsjFzgbCFjcUxNmph9HPCdcIjhm9gBFLZ5u85zHlJ+BuGkrPw0o/vXkA02Eu4hz3GEHa1Ed7E2G+Y4zrvt4QpzL1LOERIRHjJE8KfhL8Iv2CPKOoknAUfj8BXv/ljE+Uc/bElCGcMwrOFtTOEvOUDaQjNRWuY4i8RdjvmFQhdbG61fTVdJAyx9+sOA1Is3PqW8a8J59l7N4TrO/j8DL9cMVMsV9voBmEXe9/jMF4FeX/hQdvaChf1ABjVRcBRCGstNtXMjBA2WQ6cF/mogrEZKF6JuKvnXiXcYX9rj1Cc+c5lwu/igN1VFFixhN6KmLNJeP2YUExZ8Dkq1h9higkRia5ZvmMoA1nGxPkM9REOeHD1UbhVAAv6CJXFLDxJh4lXhP2W8KM3XQ+GDJUw9rFgUM/5inASBy4B/OAuOkYYhNUuijBpI20UHxA2i/EfCKtEFZoSXtDJlKjPsFp4aJ9QHs/XWm77CF+Ks8nwm2Ce+CF45TLsb2aTslDQSXwghFd1RiT+WimHOO5y/6hEGjIrniP0sJzn8piSsHrFwpErx6bE3Bk8X4ORGj5T2CMmeMgvs+UwNE0osnLb5MC0J5iMI/H2Whg1tPgvFaOVfJopZh4HWVjm+iQzjgwbn69ztfVaCLGFhSJlCXWhMIC2Gr/R4XgueyKxmY/Ngimbl/xaxbKNUrUFXGHekBXzdyHElJfpOdpoXhCeMUVp77hdZ+XMMJ70+R/CY+6J3Flk75Ps+TjOPs56HEmTIoz+DFmN8DkeXElWZ2WLpSg0lnOODxaFkHWJOMAsLy8UOIUDtIsEH5V3Mswyl5CD6u05OjKcYO8B+EoxIxwSa06x3NqGs++I+MYDUQz1QVYJpoNTHqx3VihHWbQ+bWGK00+Ep5akXGHWNijCYgmCmINBbLV4sqEfkQsv4raiC3nAFXIX2W/oGFeO/HMGletji1DXQxactPw2iPPrCLMdZbGyhO+tKBxklXsVBVmhCXdr2rq/RxWhD7IOVdAY3PwyFlXr/GNI1AEEnnck3jSEUxbNbDmif5K9yLukTETEsN2UVEQLUY0SCNVvRYEmcfG5kighYrDscf731LyCeVuqEkZrpawI30pUqXFL2V0PSrIQGqgabvm9BjLEoujTOkTFtEO9fbGbEq2Ebynpux0hMMWKgxzmJcBDzNKb+eLqKN5oyjE3CVoJGyEs16XnNibk3Wz9TlZR9eF3AD1cDIrw8W6rOj9hPPDeJoAiB5DX9XVST7NqPGpFxWe8w0eFGCLkpDCnAAWZCkwXOgdFExrDmk6su2EpgAri1iBEldqG314UW3tRfCWByUZUTrWYz3PPhCiXFbP8aXZ3llHufyW42o4BKOMpK6MVqsIHjRbWbDcZvN/qgPUXWF7IsKusUPSCxltMKJpECAzgZWnWXqQtyishvJoK9D7WhRhvWcml9H9VNfks9PjwkhDPrayfCSDYWUvVZd7bEbJaWJjLQnlFppwA+/gi7LWK5tTcG2rFzb8RYADOuFkIlIcpJwAAAABJRU5ErkJggg==);
|
||||
overflow: hidden;
|
||||
text-indent: -99em;
|
||||
}
|
||||
|
||||
.tapmodo-footer {
|
||||
font-size: 10px;
|
||||
color: #aaa;
|
||||
line-height: 1.1;
|
||||
border-top: 1px #eee solid;
|
||||
padding: 22px 0 16px;
|
||||
margin-top: 3.5em;
|
||||
.segment {
|
||||
float: left;
|
||||
margin-right: 1.5em;
|
||||
|
||||
a {
|
||||
color: #999;
|
||||
text-decoration: underline;
|
||||
&:hover { color: #888; text-decoration: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/////////////////////////////////
|
||||
// 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'
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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);
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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);
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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 = $('<div />').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 $('<div />').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);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
(function($){
|
||||
'use strict';
|
||||
@@ -0,0 +1,378 @@
|
||||
/* 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 = ['­','<style id="s', mod, '">', rule, '</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 = '<svg/>';
|
||||
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==";
|
||||
|
||||
})();
|
||||
;
|
||||
@@ -0,0 +1,14 @@
|
||||
// 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);
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
var AbstractStage = function(){
|
||||
};
|
||||
|
||||
$.extend(AbstractStage,{
|
||||
isSupported: function(el,o){
|
||||
// @todo: should actually check if it's an HTML element
|
||||
return true;
|
||||
},
|
||||
// A higher priority means less desirable
|
||||
// AbstractStage is the last one we want to use
|
||||
priority: 100,
|
||||
create: function(el,options,callback){
|
||||
var obj = new AbstractStage;
|
||||
obj.element = el;
|
||||
callback.call(this,obj,options);
|
||||
},
|
||||
prototype: {
|
||||
attach: function(core){
|
||||
this.init(core);
|
||||
core.ui.stage = this;
|
||||
},
|
||||
triggerEvent: function(ev){
|
||||
$(this.element).trigger(ev);
|
||||
return this;
|
||||
},
|
||||
getElement: function(){
|
||||
return this.element;
|
||||
}
|
||||
}
|
||||
});
|
||||
Jcrop.registerStageType('Block',AbstractStage);
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
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 (v<this.scaleMin) v = this.scaleMin;
|
||||
else if (v>this.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('<div />').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);
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
var TransformStage = function(){
|
||||
this.angle = 0;
|
||||
this.scale = 1;
|
||||
this.scaleMin = 0.2;
|
||||
this.scaleMax = 1.25;
|
||||
this.offset = [0,0];
|
||||
};
|
||||
|
||||
TransformStage.prototype = new ImageStage();
|
||||
|
||||
$.extend(TransformStage,{
|
||||
isSupported: function(el,o){
|
||||
if ($.Jcrop.supportsCSSTransforms && (el.tagName == 'IMG')) return true;
|
||||
},
|
||||
priority: 101,
|
||||
create: function(el,options,callback){
|
||||
$.Jcrop.component.ImageLoader.attach(el,function(w,h){
|
||||
var obj = new TransformStage;
|
||||
obj.$img = $(el);
|
||||
obj.element = obj.$img.wrap('<div />').parent();
|
||||
obj.element.width(w).height(h);
|
||||
obj.imgsrc = el;
|
||||
|
||||
if (typeof callback == 'function')
|
||||
callback.call(this,obj,options);
|
||||
});
|
||||
}
|
||||
});
|
||||
$.extend(TransformStage.prototype,{
|
||||
init: function(core){
|
||||
this.core = core;
|
||||
},
|
||||
boundScale: function(v){
|
||||
if (v<this.scaleMin) v = this.scaleMin;
|
||||
else if (v>this.scaleMax) v = this.scaleMax;
|
||||
return v;
|
||||
},
|
||||
// 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;
|
||||
},
|
||||
// }}}
|
||||
// clear: function() {{{
|
||||
clear: function() {
|
||||
},
|
||||
// }}}
|
||||
triggerEvent: function(ev){
|
||||
this.$img.trigger(ev);
|
||||
return this;
|
||||
},
|
||||
// redraw: function() {{{
|
||||
redraw: function() {
|
||||
|
||||
this.$img.css({
|
||||
transform:
|
||||
'translate('+(-this.offset[0])+'px,'+(-this.offset[1])+'px) '+
|
||||
'rotate('+this.angle+'deg) '+
|
||||
'scale('+this.scale+','+this.scale+')'
|
||||
});
|
||||
|
||||
this.$img.trigger('cropredraw');
|
||||
return this;
|
||||
},
|
||||
// }}}
|
||||
});
|
||||
Jcrop.registerStageType('Transform',TransformStage);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
var ImageStage = function(){
|
||||
};
|
||||
|
||||
ImageStage.prototype = new AbstractStage();
|
||||
|
||||
$.extend(ImageStage,{
|
||||
isSupported: function(el,o){
|
||||
if (el.tagName == 'IMG') return true;
|
||||
},
|
||||
priority: 90,
|
||||
create: function(el,options,callback){
|
||||
$.Jcrop.component.ImageLoader.attach(el,function(w,h){
|
||||
var obj = new ImageStage;
|
||||
obj.element = $(el).wrap('<div />').parent();
|
||||
|
||||
obj.element.width(w).height(h);
|
||||
obj.imgsrc = el;
|
||||
|
||||
if (typeof callback == 'function')
|
||||
callback.call(this,obj,options);
|
||||
});
|
||||
}
|
||||
});
|
||||
Jcrop.registerStageType('Image',ImageStage);
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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<l;i++)
|
||||
if (config.hasOwnProperty(plist[i]))
|
||||
obj[plist[i]] = config[plist[i]];
|
||||
},
|
||||
// }}}
|
||||
// getLargestBox: function(ratio,w,h){{{
|
||||
getLargestBox: function(ratio,w,h){
|
||||
if ((w/h) > 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<l;i++){
|
||||
if (stages[i].isSupported(el,options)){
|
||||
stages[i].create(el,options,function(obj,opt){
|
||||
if (typeof callback == 'function') callback(obj,opt);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
// }}}
|
||||
// supportsColorFade: function(){{{
|
||||
supportsColorFade: function(){
|
||||
return $.fx.step.hasOwnProperty('backgroundColor');
|
||||
},
|
||||
// }}}
|
||||
// wrapFromXywh: function(xywh){{{
|
||||
wrapFromXywh: function(xywh){
|
||||
var b = { x: xywh[0], y: xywh[1], w: xywh[2], h: xywh[3] };
|
||||
b.x2 = b.x + b.w;
|
||||
b.y2 = b.y + b.h;
|
||||
return b;
|
||||
}
|
||||
// }}}
|
||||
});
|
||||
Reference in New Issue
Block a user