Manual Image Crop - Version 1.01

Version Description

-Fixed Chrome stretched image issue -Improved compatibility with other plugins using 'thickbox'

Download this release

Release Info

Developer tomasz.sita
Plugin Icon 128x128 Manual Image Crop
Version 1.01
Comparing to
See all releases

Version 1.01

assets/css/Jcrop.gif ADDED
Binary file
assets/css/jquery.Jcrop.min.css ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* jquery.Jcrop.min.css v0.9.12 (build:20130126) */
2
+ .jcrop-holder{direction:ltr;text-align:left;}
3
+ .jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;}
4
+ .jcrop-vline{height:100%;width:1px!important;}
5
+ .jcrop-vline.right{right:0;}
6
+ .jcrop-hline{height:1px!important;width:100%;}
7
+ .jcrop-hline.bottom{bottom:0;}
8
+ .jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;}
9
+ .jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;}
10
+ .jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
11
+ .jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
12
+ .jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
13
+ .jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
14
+ .jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
15
+ .jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
16
+ .jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
17
+ .jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
18
+ .jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
19
+ .jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
20
+ .jcrop-dragbar.ord-n{margin-top:-4px;}
21
+ .jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
22
+ .jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
23
+ .jcrop-dragbar.ord-w{margin-left:-4px;}
24
+ .jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;}
25
+ .jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;}
26
+ .jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;}
27
+ .jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;}
28
+ .solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;}
29
+ .jcrop-holder img,img.jcrop-preview{max-width:none;}
assets/css/mic-admin.css ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #TB_window {
2
+ z-index: 260001 !important;
3
+ }
4
+ #TB_overlay {
5
+ z-index: 260000 !important;
6
+ }
7
+
8
+ .mic-editor-wrapper {
9
+ width: 940px;
10
+ }
11
+
12
+ .mic-left-col {
13
+ float: left;
14
+ width: 500px;
15
+ margin-right: 20px;
16
+ }
17
+ .mic-right-col {
18
+ float: left;
19
+ width: 400px;
20
+ }
21
+
22
+ .mic-48-col {
23
+ width: 48%;
24
+ float: right;
25
+ margin: 20px 0px;
26
+ }
27
+
28
+ .mic-52-col {
29
+ width: 48%;
30
+ float: left;
31
+ margin: 20px 0px;
32
+ }
33
+
34
+ .mic-centred {
35
+ text-align: center;
36
+ }
37
+
38
+ #micCropImage {
39
+ margin: auto !important;
40
+ display: block !important;
41
+ border-radius: 0;
42
+ }
43
+
44
+ #micLoading {
45
+ display: none;
46
+ }
47
+
48
+ .mic-editor-wrapper h2 .nav-tab {
49
+ font-size: 16px;
50
+ padding: 4px;
51
+ }
52
+
53
+ #micSuccessMessage, #micFailureMessage {
54
+ display: none;
55
+ }
assets/js/jquery.Jcrop.min.js ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * jquery.Jcrop.min.js v0.9.12 (build:20130202)
3
+ * jQuery Image Cropping Plugin - released under MIT License
4
+ * Copyright (c) 2008-2013 Tapmodo Interactive LLC
5
+ * https://github.com/tapmodo/Jcrop
6
+ */
7
+ (function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function o(a,b,c){e=l(D),bc.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys
8
+ (),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1)}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(a){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,a.type.substring
9
+ (0,5)==="touch"),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("<div></div>").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(X)return;var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),q<100?(bh(k),t()):(bb.done(),bb.animMode(!1),typeof b=="function"&&b.call(bs))}}();t()}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2],
10
+ a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+L*2).height(F+L*2),G.width(E).height(F),ba.resize(E,F),bm(),typeof b=="function"&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb
11
+ .setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if(b.tagName=="IMG"){if(A[0].width!=0&&A[0].height!=0)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id").
12
+ css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,d.shade===null&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("<div />").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a("<div />"),I=a("<div />").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("<div />").width("100%").height("100%").css("zIndex",320),K=a("<div />").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("<img />").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var L=d.boundary,M=y().width(E+L*2).height(F+L*2).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity,P,Q,R,S,T,U,V=!0,W,X,Y;e=l(D);var Z=function(){function a(){var a={},b=["touchstart"
13
+ ,"touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;d<b.length;d++){var e=b[d];e="on"+e;var f=e in c;f||(c.setAttribute(e,"return;"),f=typeof c[e]=="function"),a[b[d]]=f}return a.touchstart&&a.touchend&&a.touchmove}catch(g){return!1}}function b(){return d.touchSupport===!0||d.touchSupport===!1?d.touchSupport:a()}return{createDragger:function(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(Z.cfilter(b)),!0),b.stopPropagation(),b.preventDefault(),!1)}},newSelection:function(a){return w(Z.cfilter(a))},cfilter:function(a){return a.pageX=a.originalEvent.changedTouches[0].pageX,a.pageY=a.originalEvent.changedTouches[0].pageY,a},isSupported:a,support:b()}}(),_=function(){function h(d){d=n(d),c=a=d[0],e=b=d[1]}function i(a){a=n(a),f=a[0]-c,g=a[1]-e,c=a[0],e=a[1]}function j(){return[f,g]}function k(d){var f=d[0],g=d[1];0>a+f&&(f-=f+a),0>b+g&&(g-=g+b),F<e+g&&(g+=F-(e+g)),E<c+f&&(f+=E-(c+f)),a+=f,c+=f,b+=g,e+=g}function l(a){var b=m();switch(a){case"ne":return[
14
+ b.x2,b.y];case"nw":return[b.x,b.y];case"se":return[b.x2,b.y2];case"sw":return[b.x,b.y2]}}function m(){if(!d.aspectRatio)return p();var f=d.aspectRatio,g=d.minSize[0]/T,h=d.maxSize[0]/T,i=d.maxSize[1]/U,j=c-a,k=e-b,l=Math.abs(j),m=Math.abs(k),n=l/m,r,s,t,u;return h===0&&(h=E*10),i===0&&(i=F*10),n<f?(s=e,t=m*f,r=j<0?a-t:t+a,r<0?(r=0,u=Math.abs((r-a)/f),s=k<0?b-u:u+b):r>E&&(r=E,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-a<g?r=a+g:r-a>h&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):r<a&&(a-r<g?r=a-g:a-r>h&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>E&&(a-=r-E,r=E),s<0?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return c<a&&(e=c,f=a),d<b&&(g=d,h=b),[e,g,f,h]}function p(){var d=c-a,f=e-b,g;return P&&Math.abs(d)>P&&(c=d>0?a+P:a-P),Q&&Math.abs
15
+ (f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)<S/U&&(e=f>0?b+S/U:b-S/U),R/T&&Math.abs(d)<R/T&&(c=d>0?a+R/T:a-R/T),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&(a-=c,c-=c),e<0&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("<div />").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb.
16
+ isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("<div />").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("<div />").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("<div />").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++
17
+ ).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b<a.length;b++)g[a[b]]=n(a[b])}function p(a){var b,c;for(c=0;c<a.length;c++){switch(a[c]){case"n":b="hline";break;case"s":b="hline bottom";break;case"e":b="vline right";break;case"w":b="vline"}e[a[c]]=k(b)}}function q(a){var b;for(b=0;b<a.length;b++)f[a[b]]=m(a[b])}function r(a,b){d.shade||H.css({top:i(-b),left:i(-a)}),K.css({top:i(b),left:i(a)})}function t(a,b){K.width(Math.round(a)).height(Math.round(b))}function v(){var a=_.getFixed();_.setPressed([a.x,a.y]),_.setCurrent([a.x2,a.y2]),w()}function w(a){if(b)return x(a)}function x(a){var c=_.getFixed();t(c.w,c.h),r(c.x,c.y),d.shade&&ba.updateRaw(c),b||A(),a?d.onSelect.call(bs,u(c)):d.onChange.call(bs,u(c))}function z(a,c,e){if(!b&&!c)return;d.bgFade&&!e?D.animate({opacity:a},{queue:!1,duration:d.fadeTime}):D.css("opacity",a)}function A(){K.show(),d.shade?ba.opacity(O):z(O,!0),b=!0}function B
18
+ (){F(),K.hide(),d.shade?ba.opacity(1):z(1),b=!1,d.onRelease.call(bs)}function C(){h&&J.show()}function E(){h=!0;if(d.allowResize)return J.show(),!0}function F(){h=!1,J.hide()}function G(a){a?(X=!0,F()):(X=!1,E())}function L(){G(!1),v()}var b,c=370,e={},f={},g={},h=!1;d.dragEdges&&a.isArray(d.createDragbars)&&o(d.createDragbars),a.isArray(d.createHandles)&&q(d.createHandles),d.drawBorders&&a.isArray(d.createBorders)&&p(d.createBorders),a(document).bind("touchstart.jcrop-ios",function(b){a(b.currentTarget).hasClass("jcrop-tracker")&&b.stopPropagation()});var M=y().mousedown(s("move")).css({cursor:"move",position:"absolute",zIndex:360});return Z.support&&M.bind("touchstart.jcrop",Z.createDragger("move")),I.append(M),F(),{updateVisible:w,update:x,release:B,refresh:v,isAwake:function(){return b},setCursor:function(a){M.css("cursor",a)},enableHandles:E,enableOnly:function(){h=!0},showHandles:C,disableHandles:F,animMode:G,setBgOpacity:z,done:L}}(),bc=function(){function f(b){M.css({zIndex:450}),b?a(document).bind("touchmove.jcrop"
19
+ ,k).bind("touchend.jcrop",l):e&&a(document).bind("mousemove.jcrop",h).bind("mouseup.jcrop",i)}function g(){M.css({zIndex:290}),a(document).unbind(".jcrop")}function h(a){return b(m(a)),!1}function i(a){return a.preventDefault(),a.stopPropagation(),W&&(W=!1,c(m(a)),bb.isAwake()&&d.onSelect.call(bs,u(_.getFixed())),g(),b=function(){},c=function(){}),!1}function j(a,d,e){return W=!0,b=a,c=d,f(e),!1}function k(a){return b(m(Z.cfilter(a))),!1}function l(a){return i(Z.cfilter(a))}function n(a){M.css("cursor",a)}var b=function(){},c=function(){},e=d.trackDocument;return e||M.mousemove(h).mouseup(i).mouseout(i),D.before(M),{activateHandlers:j,setCursor:n}}(),bd=function(){function e(){d.keySupport&&(b.show(),b.focus())}function f(a){b.hide()}function g(a,b,c){d.allowMove&&(_.moveOffset([b,c]),bb.updateVisible(!0)),a.preventDefault(),a.stopPropagation()}function i(a){if(a.ctrlKey||a.metaKey)return!0;Y=a.shiftKey?!0:!1;var b=Y?10:1;switch(a.keyCode){case 37:g(a,-b,0);break;case 39:g(a,b,0);break;case 38:g(a,0,-b);break;
20
+ case 40:g(a,0,b);break;case 27:d.allowSelect&&bb.release();break;case 9:return!0}return!1}var b=a('<input type="radio" />').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("<div />").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if(
21
+ b==="api")return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges
22
+ :!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery);
assets/js/jquery.color.js ADDED
@@ -0,0 +1,661 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery Color Animations v2.0pre
3
+ * http://jquery.org/
4
+ *
5
+ * Copyright 2011 John Resig
6
+ * Dual licensed under the MIT or GPL Version 2 licenses.
7
+ * http://jquery.org/license
8
+ */
9
+
10
+ (function( jQuery, undefined ){
11
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color outlineColor".split(" "),
12
+
13
+ // plusequals test for += 100 -= 100
14
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
15
+ // a set of RE's that can match strings and generate color tuples.
16
+ stringParsers = [{
17
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
18
+ parse: function( execResult ) {
19
+ return [
20
+ execResult[ 1 ],
21
+ execResult[ 2 ],
22
+ execResult[ 3 ],
23
+ execResult[ 4 ]
24
+ ];
25
+ }
26
+ }, {
27
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
28
+ parse: function( execResult ) {
29
+ return [
30
+ 2.55 * execResult[1],
31
+ 2.55 * execResult[2],
32
+ 2.55 * execResult[3],
33
+ execResult[ 4 ]
34
+ ];
35
+ }
36
+ }, {
37
+ re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,
38
+ parse: function( execResult ) {
39
+ return [
40
+ parseInt( execResult[ 1 ], 16 ),
41
+ parseInt( execResult[ 2 ], 16 ),
42
+ parseInt( execResult[ 3 ], 16 )
43
+ ];
44
+ }
45
+ }, {
46
+ re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,
47
+ parse: function( execResult ) {
48
+ return [
49
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
50
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
51
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
52
+ ];
53
+ }
54
+ }, {
55
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
56
+ space: "hsla",
57
+ parse: function( execResult ) {
58
+ return [
59
+ execResult[1],
60
+ execResult[2] / 100,
61
+ execResult[3] / 100,
62
+ execResult[4]
63
+ ];
64
+ }
65
+ }],
66
+
67
+ // jQuery.Color( )
68
+ color = jQuery.Color = function( color, green, blue, alpha ) {
69
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
70
+ },
71
+ spaces = {
72
+ rgba: {
73
+ cache: "_rgba",
74
+ props: {
75
+ red: {
76
+ idx: 0,
77
+ type: "byte",
78
+ empty: true
79
+ },
80
+ green: {
81
+ idx: 1,
82
+ type: "byte",
83
+ empty: true
84
+ },
85
+ blue: {
86
+ idx: 2,
87
+ type: "byte",
88
+ empty: true
89
+ },
90
+ alpha: {
91
+ idx: 3,
92
+ type: "percent",
93
+ def: 1
94
+ }
95
+ }
96
+ },
97
+ hsla: {
98
+ cache: "_hsla",
99
+ props: {
100
+ hue: {
101
+ idx: 0,
102
+ type: "degrees",
103
+ empty: true
104
+ },
105
+ saturation: {
106
+ idx: 1,
107
+ type: "percent",
108
+ empty: true
109
+ },
110
+ lightness: {
111
+ idx: 2,
112
+ type: "percent",
113
+ empty: true
114
+ }
115
+ }
116
+ }
117
+ },
118
+ propTypes = {
119
+ "byte": {
120
+ floor: true,
121
+ min: 0,
122
+ max: 255
123
+ },
124
+ "percent": {
125
+ min: 0,
126
+ max: 1
127
+ },
128
+ "degrees": {
129
+ mod: 360,
130
+ floor: true
131
+ }
132
+ },
133
+ rgbaspace = spaces.rgba.props,
134
+ support = color.support = {},
135
+
136
+ // colors = jQuery.Color.names
137
+ colors,
138
+
139
+ // local aliases of functions called often
140
+ each = jQuery.each;
141
+
142
+ spaces.hsla.props.alpha = rgbaspace.alpha;
143
+
144
+ function clamp( value, prop, alwaysAllowEmpty ) {
145
+ var type = propTypes[ prop.type ] || {},
146
+ allowEmpty = prop.empty || alwaysAllowEmpty;
147
+
148
+ if ( allowEmpty && value == null ) {
149
+ return null;
150
+ }
151
+ if ( prop.def && value == null ) {
152
+ return prop.def;
153
+ }
154
+ if ( type.floor ) {
155
+ value = ~~value;
156
+ } else {
157
+ value = parseFloat( value );
158
+ }
159
+ if ( value == null || isNaN( value ) ) {
160
+ return prop.def;
161
+ }
162
+ if ( type.mod ) {
163
+ value = value % type.mod;
164
+ // -10 -> 350
165
+ return value < 0 ? type.mod + value : value;
166
+ }
167
+
168
+ // for now all property types without mod have min and max
169
+ return type.min > value ? type.min : type.max < value ? type.max : value;
170
+ }
171
+
172
+ function stringParse( string ) {
173
+ var inst = color(),
174
+ rgba = inst._rgba = [];
175
+
176
+ string = string.toLowerCase();
177
+
178
+ each( stringParsers, function( i, parser ) {
179
+ var match = parser.re.exec( string ),
180
+ values = match && parser.parse( match ),
181
+ parsed,
182
+ spaceName = parser.space || "rgba",
183
+ cache = spaces[ spaceName ].cache;
184
+
185
+
186
+ if ( values ) {
187
+ parsed = inst[ spaceName ]( values );
188
+
189
+ // if this was an rgba parse the assignment might happen twice
190
+ // oh well....
191
+ inst[ cache ] = parsed[ cache ];
192
+ rgba = inst._rgba = parsed._rgba;
193
+
194
+ // exit each( stringParsers ) here because we matched
195
+ return false;
196
+ }
197
+ });
198
+
199
+ // Found a stringParser that handled it
200
+ if ( rgba.length !== 0 ) {
201
+
202
+ // if this came from a parsed string, force "transparent" when alpha is 0
203
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
204
+ if ( Math.max.apply( Math, rgba ) === 0 ) {
205
+ jQuery.extend( rgba, colors.transparent );
206
+ }
207
+ return inst;
208
+ }
209
+
210
+ // named colors / default - filter back through parse function
211
+ if ( string = colors[ string ] ) {
212
+ return string;
213
+ }
214
+ }
215
+
216
+ color.fn = color.prototype = {
217
+ constructor: color,
218
+ parse: function( red, green, blue, alpha ) {
219
+ if ( red === undefined ) {
220
+ this._rgba = [ null, null, null, null ];
221
+ return this;
222
+ }
223
+ if ( red instanceof jQuery || red.nodeType ) {
224
+ red = red instanceof jQuery ? red.css( green ) : jQuery( red ).css( green );
225
+ green = undefined;
226
+ }
227
+
228
+ var inst = this,
229
+ type = jQuery.type( red ),
230
+ rgba = this._rgba = [],
231
+ source;
232
+
233
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
234
+ if ( green !== undefined ) {
235
+ red = [ red, green, blue, alpha ];
236
+ type = "array";
237
+ }
238
+
239
+ if ( type === "string" ) {
240
+ return this.parse( stringParse( red ) || colors._default );
241
+ }
242
+
243
+ if ( type === "array" ) {
244
+ each( rgbaspace, function( key, prop ) {
245
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
246
+ });
247
+ return this;
248
+ }
249
+
250
+ if ( type === "object" ) {
251
+ if ( red instanceof color ) {
252
+ each( spaces, function( spaceName, space ) {
253
+ if ( red[ space.cache ] ) {
254
+ inst[ space.cache ] = red[ space.cache ].slice();
255
+ }
256
+ });
257
+ } else {
258
+ each( spaces, function( spaceName, space ) {
259
+ each( space.props, function( key, prop ) {
260
+ var cache = space.cache;
261
+
262
+ // if the cache doesn't exist, and we know how to convert
263
+ if ( !inst[ cache ] && space.to ) {
264
+
265
+ // if the value was null, we don't need to copy it
266
+ // if the key was alpha, we don't need to copy it either
267
+ if ( red[ key ] == null || key === "alpha") {
268
+ return;
269
+ }
270
+ inst[ cache ] = space.to( inst._rgba );
271
+ }
272
+
273
+ // this is the only case where we allow nulls for ALL properties.
274
+ // call clamp with alwaysAllowEmpty
275
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
276
+ });
277
+ });
278
+ }
279
+ return this;
280
+ }
281
+ },
282
+ is: function( compare ) {
283
+ var is = color( compare ),
284
+ same = true,
285
+ myself = this;
286
+
287
+ each( spaces, function( _, space ) {
288
+ var isCache = is[ space.cache ],
289
+ localCache;
290
+ if (isCache) {
291
+ localCache = myself[ space.cache ] || space.to && space.to( myself._rgba ) || [];
292
+ each( space.props, function( _, prop ) {
293
+ if ( isCache[ prop.idx ] != null ) {
294
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
295
+ return same;
296
+ }
297
+ });
298
+ }
299
+ return same;
300
+ });
301
+ return same;
302
+ },
303
+ _space: function() {
304
+ var used = [],
305
+ inst = this;
306
+ each( spaces, function( spaceName, space ) {
307
+ if ( inst[ space.cache ] ) {
308
+ used.push( spaceName );
309
+ }
310
+ });
311
+ return used.pop();
312
+ },
313
+ transition: function( other, distance ) {
314
+ var end = color( other ),
315
+ spaceName = end._space(),
316
+ space = spaces[ spaceName ],
317
+ start = this[ space.cache ] || space.to( this._rgba ),
318
+ result = start.slice();
319
+
320
+ end = end[ space.cache ];
321
+ each( space.props, function( key, prop ) {
322
+ var index = prop.idx,
323
+ startValue = start[ index ],
324
+ endValue = end[ index ],
325
+ type = propTypes[ prop.type ] || {};
326
+
327
+ // if null, don't override start value
328
+ if ( endValue === null ) {
329
+ return;
330
+ }
331
+ // if null - use end
332
+ if ( startValue === null ) {
333
+ result[ index ] = endValue;
334
+ } else {
335
+ if ( type.mod ) {
336
+ if ( endValue - startValue > type.mod / 2 ) {
337
+ startValue += type.mod;
338
+ } else if ( startValue - endValue > type.mod / 2 ) {
339
+ startValue -= type.mod;
340
+ }
341
+ }
342
+ result[ prop.idx ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
343
+ }
344
+ });
345
+ return this[ spaceName ]( result );
346
+ },
347
+ blend: function( opaque ) {
348
+ // if we are already opaque - return ourself
349
+ if ( this._rgba[ 3 ] === 1 ) {
350
+ return this;
351
+ }
352
+
353
+ var rgb = this._rgba.slice(),
354
+ a = rgb.pop(),
355
+ blend = color( opaque )._rgba;
356
+
357
+ return color( jQuery.map( rgb, function( v, i ) {
358
+ return ( 1 - a ) * blend[ i ] + a * v;
359
+ }));
360
+ },
361
+ toRgbaString: function() {
362
+ var prefix = "rgba(",
363
+ rgba = jQuery.map( this._rgba, function( v, i ) {
364
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
365
+ });
366
+
367
+ if ( rgba[ 3 ] === 1 ) {
368
+ rgba.pop();
369
+ prefix = "rgb(";
370
+ }
371
+
372
+ return prefix + rgba.join(",") + ")";
373
+ },
374
+ toHslaString: function() {
375
+ var prefix = "hsla(",
376
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
377
+ if ( v == null ) {
378
+ v = i > 2 ? 1 : 0;
379
+ }
380
+
381
+ // catch 1 and 2
382
+ if ( i && i < 3 ) {
383
+ v = Math.round( v * 100 ) + "%";
384
+ }
385
+ return v;
386
+ });
387
+
388
+ if ( hsla[ 3 ] === 1 ) {
389
+ hsla.pop();
390
+ prefix = "hsl(";
391
+ }
392
+ return prefix + hsla.join(",") + ")";
393
+ },
394
+ toHexString: function( includeAlpha ) {
395
+ var rgba = this._rgba.slice(),
396
+ alpha = rgba.pop();
397
+
398
+ if ( includeAlpha ) {
399
+ rgba.push( ~~( alpha * 255 ) );
400
+ }
401
+
402
+ return "#" + jQuery.map( rgba, function( v, i ) {
403
+
404
+ // default to 0 when nulls exist
405
+ v = ( v || 0 ).toString( 16 );
406
+ return v.length === 1 ? "0" + v : v;
407
+ }).join("");
408
+ },
409
+ toString: function() {
410
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
411
+ }
412
+ };
413
+ color.fn.parse.prototype = color.fn;
414
+
415
+ // hsla conversions adapted from:
416
+ // http://www.google.com/codesearch/p#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/inspector/front-end/Color.js&d=7&l=193
417
+
418
+ function hue2rgb( p, q, h ) {
419
+ h = ( h + 1 ) % 1;
420
+ if ( h * 6 < 1 ) {
421
+ return p + (q - p) * 6 * h;
422
+ }
423
+ if ( h * 2 < 1) {
424
+ return q;
425
+ }
426
+ if ( h * 3 < 2 ) {
427
+ return p + (q - p) * ((2/3) - h) * 6;
428
+ }
429
+ return p;
430
+ }
431
+
432
+ spaces.hsla.to = function ( rgba ) {
433
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
434
+ return [ null, null, null, rgba[ 3 ] ];
435
+ }
436
+ var r = rgba[ 0 ] / 255,
437
+ g = rgba[ 1 ] / 255,
438
+ b = rgba[ 2 ] / 255,
439
+ a = rgba[ 3 ],
440
+ max = Math.max( r, g, b ),
441
+ min = Math.min( r, g, b ),
442
+ diff = max - min,
443
+ add = max + min,
444
+ l = add * 0.5,
445
+ h, s;
446
+
447
+ if ( min === max ) {
448
+ h = 0;
449
+ } else if ( r === max ) {
450
+ h = ( 60 * ( g - b ) / diff ) + 360;
451
+ } else if ( g === max ) {
452
+ h = ( 60 * ( b - r ) / diff ) + 120;
453
+ } else {
454
+ h = ( 60 * ( r - g ) / diff ) + 240;
455
+ }
456
+
457
+ if ( l === 0 || l === 1 ) {
458
+ s = l;
459
+ } else if ( l <= 0.5 ) {
460
+ s = diff / add;
461
+ } else {
462
+ s = diff / ( 2 - add );
463
+ }
464
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
465
+ };
466
+
467
+ spaces.hsla.from = function ( hsla ) {
468
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
469
+ return [ null, null, null, hsla[ 3 ] ];
470
+ }
471
+ var h = hsla[ 0 ] / 360,
472
+ s = hsla[ 1 ],
473
+ l = hsla[ 2 ],
474
+ a = hsla[ 3 ],
475
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
476
+ p = 2 * l - q,
477
+ r, g, b;
478
+
479
+ return [
480
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
481
+ Math.round( hue2rgb( p, q, h ) * 255 ),
482
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
483
+ a
484
+ ];
485
+ };
486
+
487
+
488
+ each( spaces, function( spaceName, space ) {
489
+ var props = space.props,
490
+ cache = space.cache,
491
+ to = space.to,
492
+ from = space.from;
493
+
494
+ // makes rgba() and hsla()
495
+ color.fn[ spaceName ] = function( value ) {
496
+
497
+ // generate a cache for this space if it doesn't exist
498
+ if ( to && !this[ cache ] ) {
499
+ this[ cache ] = to( this._rgba );
500
+ }
501
+ if ( value === undefined ) {
502
+ return this[ cache ].slice();
503
+ }
504
+
505
+ var type = jQuery.type( value ),
506
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
507
+ local = this[ cache ].slice(),
508
+ ret;
509
+
510
+ each( props, function( key, prop ) {
511
+ var val = arr[ type === "object" ? key : prop.idx ];
512
+ if ( val == null ) {
513
+ val = local[ prop.idx ];
514
+ }
515
+ local[ prop.idx ] = clamp( val, prop );
516
+ });
517
+
518
+ if ( from ) {
519
+ ret = color( from( local ) );
520
+ ret[ cache ] = local;
521
+ return ret;
522
+ } else {
523
+ return color( local );
524
+ }
525
+ };
526
+
527
+ // makes red() green() blue() alpha() hue() saturation() lightness()
528
+ each( props, function( key, prop ) {
529
+ // alpha is included in more than one space
530
+ if ( color.fn[ key ] ) {
531
+ return;
532
+ }
533
+ color.fn[ key ] = function( value ) {
534
+ var vtype = jQuery.type( value ),
535
+ fn = ( key === 'alpha' ? ( this._hsla ? 'hsla' : 'rgba' ) : spaceName ),
536
+ local = this[ fn ](),
537
+ cur = local[ prop.idx ],
538
+ match;
539
+
540
+ if ( vtype === "undefined" ) {
541
+ return cur;
542
+ }
543
+
544
+ if ( vtype === "function" ) {
545
+ value = value.call( this, cur );
546
+ vtype = jQuery.type( value );
547
+ }
548
+ if ( value == null && prop.empty ) {
549
+ return this;
550
+ }
551
+ if ( vtype === "string" ) {
552
+ match = rplusequals.exec( value );
553
+ if ( match ) {
554
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
555
+ }
556
+ }
557
+ local[ prop.idx ] = value;
558
+ return this[ fn ]( local );
559
+ };
560
+ });
561
+ });
562
+
563
+ // add .fx.step functions
564
+ each( stepHooks, function( i, hook ) {
565
+ jQuery.cssHooks[ hook ] = {
566
+ set: function( elem, value ) {
567
+ var parsed, backgroundColor, curElem;
568
+
569
+ if ( jQuery.type( value ) !== 'string' || ( parsed = stringParse( value ) ) )
570
+ {
571
+ value = color( parsed || value );
572
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
573
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
574
+ do {
575
+ backgroundColor = jQuery.curCSS( curElem, "backgroundColor" );
576
+ } while (
577
+ ( backgroundColor === "" || backgroundColor === "transparent" ) &&
578
+ ( curElem = curElem.parentNode ) &&
579
+ curElem.style
580
+ );
581
+
582
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
583
+ backgroundColor :
584
+ "_default" );
585
+ }
586
+
587
+ value = value.toRgbaString();
588
+ }
589
+ elem.style[ hook ] = value;
590
+ }
591
+ };
592
+ jQuery.fx.step[ hook ] = function( fx ) {
593
+ if ( !fx.colorInit ) {
594
+ fx.start = color( fx.elem, hook );
595
+ fx.end = color( fx.end );
596
+ fx.colorInit = true;
597
+ }
598
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
599
+ };
600
+ });
601
+
602
+ // detect rgba support
603
+ jQuery(function() {
604
+ var div = document.createElement( "div" ),
605
+ div_style = div.style;
606
+
607
+ div_style.cssText = "background-color:rgba(1,1,1,.5)";
608
+ support.rgba = div_style.backgroundColor.indexOf( "rgba" ) > -1;
609
+ });
610
+
611
+ // Some named colors to work with
612
+ // From Interface by Stefan Petre
613
+ // http://interface.eyecon.ro/
614
+ colors = jQuery.Color.names = {
615
+ aqua: "#00ffff",
616
+ azure: "#f0ffff",
617
+ beige: "#f5f5dc",
618
+ black: "#000000",
619
+ blue: "#0000ff",
620
+ brown: "#a52a2a",
621
+ cyan: "#00ffff",
622
+ darkblue: "#00008b",
623
+ darkcyan: "#008b8b",
624
+ darkgrey: "#a9a9a9",
625
+ darkgreen: "#006400",
626
+ darkkhaki: "#bdb76b",
627
+ darkmagenta: "#8b008b",
628
+ darkolivegreen: "#556b2f",
629
+ darkorange: "#ff8c00",
630
+ darkorchid: "#9932cc",
631
+ darkred: "#8b0000",
632
+ darksalmon: "#e9967a",
633
+ darkviolet: "#9400d3",
634
+ fuchsia: "#ff00ff",
635
+ gold: "#ffd700",
636
+ green: "#008000",
637
+ indigo: "#4b0082",
638
+ khaki: "#f0e68c",
639
+ lightblue: "#add8e6",
640
+ lightcyan: "#e0ffff",
641
+ lightgreen: "#90ee90",
642
+ lightgrey: "#d3d3d3",
643
+ lightpink: "#ffb6c1",
644
+ lightyellow: "#ffffe0",
645
+ lime: "#00ff00",
646
+ magenta: "#ff00ff",
647
+ maroon: "#800000",
648
+ navy: "#000080",
649
+ olive: "#808000",
650
+ orange: "#ffa500",
651
+ pink: "#ffc0cb",
652
+ purple: "#800080",
653
+ violet: "#800080",
654
+ red: "#ff0000",
655
+ silver: "#c0c0c0",
656
+ white: "#ffffff",
657
+ yellow: "#ffff00",
658
+ transparent: [ null, null, null, 0 ],
659
+ _default: "#ffffff"
660
+ };
661
+ })( jQuery );
assets/js/microp.js ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var jcrop_api, mic_attachment_id, mic_edited_size, mic_preview_scale;
2
+
3
+ jQuery(document).ready(function($) {
4
+ //image sizes tabs
5
+ $(document).on('click', '.rm-crop-size-tab', function(e) {
6
+ e.preventDefault();
7
+ $(this).addClass('nav-tab-active');
8
+ $.get($(this).attr('href'), function(data) {
9
+ $('#TB_ajaxContent').html(data);
10
+ });
11
+ });
12
+
13
+ $( document ).on('click', '#micCropImage', function() {
14
+ $('#micCropImage').hide();
15
+ $('#micLoading').show();
16
+ $.post(ajaxurl + '?action=mic_crop_image', { select: jcrop_api.tellSelect(), scaled: jcrop_api.tellScaled(), attachmentId: mic_attachment_id, editedSize: mic_edited_size, previewScale: mic_preview_scale } , function(response) {
17
+ if (response.status == 'ok') {
18
+ var newImage = new Image();
19
+ newImage.src = response.file;
20
+ var count = 0;
21
+ function updateImage() {
22
+ if(newImage.complete) {
23
+ $('#micPreviousImage').attr('src', newImage.src);
24
+ $('#micCropImage').show();
25
+ $('#micSuccessMessage').show().delay(5000).fadeOut();
26
+ $('#micLoading').hide();
27
+ }else {
28
+ setTimeout(updateImage, 200);
29
+ }
30
+ }
31
+ updateImage();
32
+ }else {
33
+ $('#micFailureMessage').show().delay(5000).fadeOut();
34
+ $('#micCropImage').show();
35
+ $('#micLoading').hide();
36
+ }
37
+ }, 'json');
38
+ });
39
+
40
+ $('.mic-link').click( function() {
41
+ tb_position();
42
+ });
43
+
44
+ function adjustMicWindowSize() {
45
+ if( ! $('#TB_ajaxContent .mic-editor-wrapper').length) {
46
+ return;
47
+ }
48
+ var tbWindow = $('#TB_window'), width = $(window).width(), H = 560, W = ( 980 < width ) ? 980 : width, adminbar_height = 0;
49
+
50
+ if ( $('body.admin-bar').length )
51
+ adminbar_height = 28;
52
+
53
+ if ( tbWindow.size() ) {
54
+ tbWindow.width( W ).height( H - 45 - adminbar_height );
55
+ $('#TB_iframeContent, #TB_ajaxContent').width( W).height( H - 75 - adminbar_height );
56
+ tbWindow.css({'margin-left': '-' + parseInt((( W) / 2),10) + 'px'});
57
+ if ( typeof document.body.style.maxWidth != 'undefined' )
58
+ tbWindow.css({'top': 20 + adminbar_height + 'px','margin-top':'0'});
59
+ };
60
+ }
61
+
62
+ setInterval(adjustMicWindowSize, 200);
63
+
64
+ });
lib/ManualImageCrop.php ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class ManualImageCrop {
3
+
4
+ private static $instance;
5
+
6
+ /**
7
+ * Returns the instance of the class [Singleton]
8
+ * @return ManualImageCrop
9
+ */
10
+ public static function getInstance() {
11
+ if (self::$instance === null) {
12
+ self::$instance = new ManualImageCrop();
13
+ }
14
+ return self::$instance;
15
+ }
16
+
17
+ private function __construct() {
18
+
19
+ }
20
+
21
+ /**
22
+ * Enqueues all necessary CSS and Scripts
23
+ */
24
+ public function enqueueAssets() {
25
+ wp_register_style( 'rct-admin', plugins_url('assets/css/mic-admin.css', dirname( __FILE__ ) ) );
26
+ wp_enqueue_style( 'rct-admin' );
27
+
28
+ wp_register_style( 'jquery-jcrop', plugins_url('assets/css/jquery.Jcrop.min.css', dirname( __FILE__ ) ) );
29
+ wp_enqueue_style( 'jquery-jcrop' );
30
+
31
+ wp_enqueue_script( 'jquery-color', plugins_url('assets/js/jquery.color.js', dirname( __FILE__ )), array( 'jquery') );
32
+ wp_enqueue_script( 'jquery-jcrop', plugins_url('assets/js/jquery.Jcrop.min.js', dirname( __FILE__ )), array( 'jquery') );
33
+ wp_enqueue_script( 'miccrop', plugins_url('assets/js/microp.js', dirname( __FILE__ )), array( 'jquery') );
34
+ }
35
+
36
+ /**
37
+ * Hooks Editor Links into proper places
38
+ */
39
+ public function addEditorLinks() {
40
+ add_thickbox();
41
+ add_action( 'media_row_actions', array($this, 'addMediaEditorLinks'), 10, 2 );
42
+ add_action( 'admin_post_thumbnail_html', array($this, 'addCropFeatureImageEditorLink'), 10, 2 );
43
+ add_action( 'print_media_templates', array($this, 'addAttachementEditLink') );
44
+ add_action( 'pre-upload-ui', array($this, 'addAfterUploadAttachementEditLink') );
45
+ }
46
+
47
+ /**
48
+ * Adds links in media library list
49
+ */
50
+ public function addMediaEditorLinks($links, $post) {
51
+ if (preg_match('/image/', $post->post_mime_type)) {
52
+ $links['crop'] = '<a class="thickbox mic-link" rel="crop" title="Crop" href="' . admin_url( 'admin-ajax.php' ) . '?action=mic_editor_window&postId=' . $post->ID . '">Crop</a>';
53
+ }
54
+ return $links;
55
+ }
56
+
57
+ /**
58
+ * Adds link below "Remoce feature image" in post editing form
59
+ */
60
+ public function addCropFeatureImageEditorLink($content, $post) {
61
+ $content .= '<a id="micCropFeatureImage" class="thickbox mic-link" rel="crop" title="Crop" href="' . admin_url( 'admin-ajax.php' ) . '?action=mic_editor_window&postId=' . get_post_thumbnail_id($post) . '">Crop featured image</a>
62
+ <script>
63
+ setInterval(function() {
64
+ if (jQuery(\'#remove-post-thumbnail\').is(\':visible\')) {
65
+ jQuery(\'#micCropFeatureImage\').show();
66
+ }else {
67
+ jQuery(\'#micCropFeatureImage\').hide();
68
+ }
69
+ }, 200);
70
+ </script>';
71
+ return $content;
72
+ }
73
+
74
+ /**
75
+ * Ads link in the ligthbox media library
76
+ */
77
+
78
+ public function addAttachementEditLink() {
79
+ ?>
80
+ <script>
81
+ var micEditAttachemtnLinkAdded = false;
82
+ var micEditAttachemtnLinkAddedInterval = 0;
83
+ jQuery(document).ready(function() {
84
+ micEditAttachemtnLinkAddedInterval = setInterval(function() {
85
+ if (jQuery('.details .edit-attachment').length) {
86
+ try {
87
+ var mRegexp = /\?post=([0-9]+)/;
88
+ var match = mRegexp.exec(jQuery('.details .edit-attachment').attr('href'));
89
+ jQuery('.edit-attachment.crop-image').remove();
90
+ jQuery('.details .edit-attachment').after( '<a class="thickbox mic-link edit-attachment crop-image" rel="crop" title="Crop" href="' + ajaxurl + '?action=mic_editor_window&postId=' + match[1] + '">Crop Image</a>' );
91
+ } catch (e) {
92
+ console.log(e);
93
+ }
94
+ }
95
+ }, 500);
96
+ });
97
+ </script>
98
+ <?php
99
+ }
100
+
101
+ /**
102
+ * Ads link in the ligthbox media library
103
+ */
104
+ public function addAfterUploadAttachementEditLink() {
105
+ ?>
106
+ <script>
107
+ var micEditAttachemtnLinkAdded = false;
108
+ var micEditAttachemtnLinkAddedInterval = 0;
109
+ jQuery(document).ready(function() {
110
+ micEditAttachemtnLinkAddedInterval = setInterval(function() {
111
+ if (jQuery('#media-items .edit-attachment').length) {
112
+ jQuery('#media-items .edit-attachment').each(function(i, k) {
113
+ try {
114
+ var mRegexp = /\?post=([0-9]+)/;
115
+ var match = mRegexp.exec(jQuery(this).attr('href'));
116
+ if (!jQuery(this).parent().find('.edit-attachment.crop-image').length && jQuery(this).parent().find('.pinkynail').attr('src').match(/upload/g)) {
117
+ jQuery(this).after( '<a class="thickbox mic-link edit-attachment crop-image" rel="crop" title="Crop" href="' + ajaxurl + '?action=mic_editor_window&postId=' + match[1] + '">Crop Image</a>' );
118
+ }
119
+ } catch (e) {
120
+ console.log(e);
121
+ }
122
+ });
123
+ }
124
+ }, 500);
125
+ });
126
+ </script>
127
+ <?php
128
+ }
129
+
130
+ /**
131
+ * Crops the image based on $_POST array
132
+ */
133
+ public function cropImage() {
134
+ global $_wp_additional_image_sizes;
135
+
136
+ $src_file_url = wp_get_attachment_image_src($_POST['attachmentId'], 'full');
137
+ if (!$src_file_url) {
138
+ echo json_encode (array('status' => 'error', 'message' => 'wrong attachement' ) );
139
+ exit;
140
+ }
141
+ $src_file = ABSPATH . str_replace(get_bloginfo('url'), '', $src_file_url[0]);
142
+
143
+ $dst_file_url = wp_get_attachment_image_src($_POST['attachmentId'], $_POST['editedSize']);
144
+ if (!$dst_file_url) {
145
+ echo json_encode (array('status' => 'error', 'message' => 'wrong size' ) );
146
+ exit;
147
+ }
148
+ $dst_file = ABSPATH . str_replace(get_bloginfo('url'), '', $dst_file_url[0]);
149
+
150
+ if (isset($_wp_additional_image_sizes[$_POST['editedSize']])) {
151
+ $dst_w = min(intval($_wp_additional_image_sizes[$_POST['editedSize']]['width']), $_POST['select']['w'] * $_POST['previewScale']);;
152
+ $dst_h = min(intval($_wp_additional_image_sizes[$_POST['editedSize']]['height']), $_POST['select']['h'] * $_POST['previewScale']);
153
+ } else {
154
+ $dst_w = min(get_option($_POST['editedSize'].'_size_w'), $_POST['select']['w'] * $_POST['previewScale']);
155
+ $dst_h = min(get_option($_POST['editedSize'].'_size_h'), $_POST['select']['h'] * $_POST['previewScale']);
156
+ }
157
+
158
+ if (!$dst_w || !$dst_h) {
159
+ echo json_encode (array('status' => 'error', 'message' => 'wrong dimensions' ) );
160
+ exit;
161
+ }
162
+
163
+ $dst_x = 0;
164
+ $dst_y = 0;
165
+
166
+ $src_x = max(0, $_POST['select']['x']) * $_POST['previewScale'];
167
+ $src_y = max(0, $_POST['select']['y']) * $_POST['previewScale'];
168
+ $src_w = max(0, $_POST['select']['w']) * $_POST['previewScale'];
169
+ $src_h = max(0, $_POST['select']['h']) * $_POST['previewScale'];
170
+
171
+ $ext = pathinfo($src_file, PATHINFO_EXTENSION);
172
+
173
+ if ($ext == "gif"){
174
+ $src_img = imagecreatefromgif($src_file);
175
+ } else if($ext =="png"){
176
+ $src_img = imagecreatefrompng($src_file);
177
+ } else {
178
+ $src_img = imagecreatefromjpeg($src_file);
179
+ }
180
+ $dst_img = imagecreatetruecolor($dst_w, $dst_h);
181
+ imagecopyresampled($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
182
+
183
+ if ($ext == "gif"){
184
+ imagegif($dst_img, $dst_file);
185
+ } else if($ext =="png"){
186
+ imagepng($dst_img, $dst_file);
187
+ } else {
188
+ imagejpeg($dst_img, $dst_file, 80);
189
+ }
190
+
191
+ echo json_encode (array('status' => 'ok', 'file' => $dst_file_url[0] . '?' . time() ) );
192
+ exit;
193
+ }
194
+ }
lib/ManualImageCropEditorWindow.php ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class ManualImageCropEditorWindow {
3
+
4
+ private static $instance;
5
+
6
+ /**
7
+ * Returns the instance of the class [Singleton]
8
+ * @return ManualImageCropEditorWindow
9
+ */
10
+ public static function getInstance() {
11
+ if (self::$instance === null) {
12
+ self::$instance = new ManualImageCropEditorWindow();
13
+ }
14
+ return self::$instance;
15
+ }
16
+
17
+ private function __construct() {
18
+
19
+ }
20
+
21
+ public function renderWindow() {
22
+ ?>
23
+ <div class="mic-editor-wrapper">
24
+ <h2 class="nav-tab-wrapper">
25
+ Pick the image size: <?php
26
+ global $_wp_additional_image_sizes;
27
+
28
+ $imageSizes = get_intermediate_image_sizes();
29
+
30
+ $editedSize = isset( $_GET['size'] ) ? $_GET['size'] : $imageSizes[0];
31
+
32
+ foreach ($imageSizes as $s) {
33
+ if (isset($_wp_additional_image_sizes[$s])) {
34
+ $cropMethod = $_wp_additional_image_sizes[$s]['crop'];
35
+ } else {
36
+ $cropMethod = get_option($s.'_crop');
37
+ }
38
+ if ($cropMethod == 0) {
39
+ continue;
40
+ }
41
+ echo '<a href="' . admin_url( 'admin-ajax.php' ) . '?action=mic_editor_window&size=' . $s . '&postId=' . $_GET['postId'] . '&width=940" class="rm-crop-size-tab nav-tab ' . ( ($s == $editedSize) ? 'nav-tab-active' : '' ) . '">' . $s . '</a>';
42
+ }
43
+ ?>
44
+ </h2>
45
+ <div class="mic-left-col">
46
+ <?php
47
+ if (isset($_wp_additional_image_sizes[$editedSize])) {
48
+ $width = intval($_wp_additional_image_sizes[$editedSize]['width']);
49
+ $height = intval($_wp_additional_image_sizes[$editedSize]['height']);
50
+ $cropMethod = $_wp_additional_image_sizes[$editedSize]['crop'];
51
+ } else {
52
+ $width = get_option($editedSize.'_size_w');
53
+ $height = get_option($editedSize.'_size_h');
54
+ $cropMethod = get_option($editedSize.'_crop');
55
+ }
56
+
57
+ $sizes = getimagesize(wp_get_attachment_url($_GET['postId'], 'full'));
58
+
59
+ $previewWidth = min($sizes[0], 500);
60
+ $previewHeight = min($sizes[1], 350);
61
+ $previewRatio = 1;
62
+
63
+ if ($sizes[1] / 350 < $sizes[0] / 500) {
64
+ $previewHeight = $sizes[1] * $previewWidth / $sizes[0] ;
65
+ $previewRatio = $sizes[1] / $previewHeight;
66
+ }else {
67
+ $previewWidth = $sizes[0] * $previewHeight / $sizes[1];
68
+ $previewRatio = $sizes[0] / $previewWidth;
69
+ }
70
+
71
+ $minWidth = min($width / $previewRatio, $previewWidth);
72
+ $minHeight = min($height / $previewRatio, $previewHeight);
73
+
74
+ if ($cropMethod == 1) {
75
+ $aspectRatio = ($width / $height);
76
+ if ($aspectRatio * $minWidth > $sizes[0]) {
77
+ $aspectRatio = ($previewWidth / $minHeight);
78
+ }else if (1 / $aspectRatio * $minHeight > $sizes[1]) {
79
+ $aspectRatio = ($minWidth / $previewHeight);
80
+ }
81
+
82
+ if ($minWidth / $aspectRatio > $previewHeight) {
83
+ $aspectRatio = $minWidth / $previewHeight;
84
+ }
85
+ }else {
86
+ $aspectRatio = $sizes[0] / $sizes[1];
87
+ }
88
+
89
+
90
+ $smallPreviewWidth = min($width, 180);
91
+ $smallPreviewHeight = min($height, 180);
92
+
93
+ if ($width > $height) {
94
+ $smallPreviewHeight = $smallPreviewWidth * 1/ $aspectRatio;
95
+ }else {
96
+ $smallPreviewWidth = $smallPreviewHeight * $aspectRatio;
97
+ }
98
+ ?>
99
+ <div style="margin: auto; width: <?php echo $previewWidth; ?>px;"><img style="width: <?php echo $previewWidth; ?>px; height: <?php echo $previewHeight; ?>px;" id="jcrop_target" src="<?php echo wp_get_attachment_url($_GET['postId']); ?>"></div>
100
+ </div>
101
+ <div class="mic-right-col">
102
+ <div>
103
+ Original picture dimensions: <strong><?php echo $sizes[0]; ?> x <?php echo $sizes[1]; ?> px</strong><br />
104
+ Target picture dimensions: <strong><?php echo $width; ?>px x <?php echo $height; ?>px</strong> (<?php if ($cropMethod == 0) { echo 'Soft proportional crop mode'; }else { echo 'Hard crop mode'; } ?>)
105
+ </div>
106
+
107
+ <div class="mic-52-col">
108
+ New image:<br />
109
+ <div style="width: <?php echo $smallPreviewWidth; ?>px; height: <?php echo $smallPreviewHeight; ?>px; overflow: hidden; margin-left: 5px; float: right;">
110
+ <img id="preview" src="<?php echo wp_get_attachment_url($_GET['postId']); ?>">
111
+ </div>
112
+ </div>
113
+
114
+ <div class="mic-48-col">
115
+ Previous image:
116
+ <?php
117
+ $editedImage = wp_get_attachment_image_src($_GET['postId'], $editedSize);
118
+ ?>
119
+ <div style="width: <?php echo $smallPreviewWidth; ?>px; height: <?php echo $smallPreviewHeight; ?>px; overflow: hidden; margin-left: 5px;">
120
+ <img id="micPreviousImage" style="max-width: <?php echo $smallPreviewWidth; ?>px; max-height: <?php echo $smallPreviewHeight; ?>px;" src="<?php echo $editedImage[0] . '?' . time(); ?>">
121
+ </div>
122
+ </div>
123
+
124
+ <input id="micCropImage" class="button-primary button-large" type="button" value="Crop it!" />
125
+ <img src="<?php echo includes_url(); ?>js/thickbox/loadingAnimation.gif" id="micLoading" />
126
+ <div id="micSuccessMessage" class="updated below-h2">The image has been cropped successfully</div>
127
+ <div id="micFailureMessage" class="error below-h2">An Error has occured. Please try again or contact plugin's author.</div>
128
+
129
+ </div>
130
+ </div>
131
+ <script>
132
+ jQuery(document).ready(function($) {
133
+ mic_attachment_id = <?php echo $_GET['postId']; ?>;
134
+ mic_edited_size = '<?php echo $editedSize; ?>';
135
+ mic_preview_scale = <?php echo $previewRatio; ?>;
136
+
137
+ setTimeout(function() {
138
+ $('#jcrop_target').Jcrop({
139
+ onChange: showPreview,
140
+ onSelect: showPreview,
141
+ minSize: [<?php echo $minWidth; ?>, <?php echo $minHeight; ?>],
142
+ maxSize: [<?php echo $previewWidth; ?>, <?php echo $previewHeight; ?>],
143
+ aspectRatio: <?php echo $aspectRatio; ?>,
144
+ setSelect: [<?php echo max(0, ($previewWidth - ($previewHeight * $aspectRatio)) / 2) ?>, <?php echo max(0, ($previewHeight - ($previewWidth / $aspectRatio)) / 2) ?>, <?php echo $previewWidth * $aspectRatio; ?>, <?php echo $previewHeight; ?>]
145
+ }, function() {
146
+ jcrop_api = this;
147
+ });
148
+ }, 300);
149
+
150
+ function showPreview(coords) {
151
+ var rx = <?php echo $smallPreviewWidth; ?> / coords.w;
152
+ var ry = <?php echo $smallPreviewHeight; ?> / coords.h;
153
+
154
+ $('#preview').css({
155
+ width: Math.round(rx * <?php echo $previewWidth; ?>)+ 'px',
156
+ height: Math.round(ry * <?php echo $previewHeight; ?>) + 'px',
157
+ marginLeft: '-' + Math.round(rx * coords.x) + 'px',
158
+ marginTop: '-' + Math.round(ry * coords.y) + 'px'
159
+ });
160
+ }
161
+ });
162
+ </script>
163
+ <?php
164
+ die;
165
+ }
166
+ }
manual-image-crop.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Manual Image Crop
4
+ Plugin URI: http://www.rocketmill.co.uk/wordpress-plugin-manual-image-crop
5
+ Description: Plugin allows you to manually crop all the image sizes registered in your WordPress theme (in particular featured image). Simply click on the "Crop" link next to any image in your media library and select the area of the image you want to crop.
6
+ Version: 1.01
7
+ Author: Tomasz Sita
8
+ Author URI: http://www.rocketmill.co.uk/author/tomasz
9
+ License: GPL2
10
+ */
11
+
12
+ define('mic_VERSION', '1.01');
13
+
14
+ include_once(dirname(__FILE__) . '/lib/ManualImageCrop.php');
15
+ include_once(dirname(__FILE__) . '/lib/ManualImageCropEditorWindow.php');
16
+
17
+ //mic - stands for Manual Image Crop
18
+
19
+ function mic_init_plugin() {
20
+ if (! is_admin()) {
21
+ //we are gonna use our plugin in the admin area only, so ends here if it's a frontend
22
+ return;
23
+ }
24
+
25
+ $ManualImageCrop = ManualImageCrop::getInstance();
26
+ add_action( 'admin_head', array($ManualImageCrop, 'enqueueAssets') );
27
+ $ManualImageCrop->addEditorLinks();
28
+
29
+ //attach admin actions
30
+ add_action('wp_ajax_mic_editor_window', 'mic_ajax_editor_window');
31
+ add_action('wp_ajax_mic_crop_image', 'mic_ajax_crop_image');
32
+ }
33
+
34
+ function mic_ajax_editor_window() {
35
+ $ManualImageCropEditorWindow = ManualImageCropEditorWindow::getInstance();
36
+ add_action( 'admin_head', array(ManualImageCropEditorWindow, 'enqueueAssets') );
37
+ $ManualImageCropEditorWindow->renderWindow();
38
+ exit;
39
+ }
40
+
41
+ function mic_ajax_crop_image() {
42
+ $ManualImageCrop = ManualImageCrop::getInstance();
43
+ $ManualImageCrop->cropImage();
44
+ exit;
45
+ }
46
+
47
+ add_action('plugins_loaded', 'mic_init_plugin');
readme.txt ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Manual Image Crop ===
2
+ Contributors: tomasz.sita
3
+ Tags: crop, cropping, thumbnail, featured image, gallery, images, picture, image, image area
4
+ Requires at least: 3.0.1
5
+ Tested up to: 3.6
6
+ License: GPLv2 or later
7
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
8
+ Stable tag: 1.01
9
+
10
+ Plugin allows you to manually crop all the image sizes registered in your WordPress theme (in particular featured image).
11
+
12
+
13
+ == Description ==
14
+
15
+ Plugin allows you to manually crop all the image sizes registered in your WordPress theme (in particular featured image).
16
+ Simply click on the "Crop" link next to any image in your media library.
17
+ The "lightbox" style interface will be brought up and you are ready to go.
18
+ Whole cropping process is really intuitive and simple.
19
+
20
+ Apart from media library list, the plugin adds links in few more places:
21
+ -below featured image box ("Crop featured image")
22
+ -In the media insert modal window (once you select an image)
23
+
24
+
25
+ == Installation ==
26
+ Manually:
27
+ 1. Upload `manual-image-crop` to the `/wp-content/plugins/` directory
28
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
29
+
30
+ Automatically:
31
+ 1. Navigate to the 'Plugins' menu inside of the wordpress wp-admin dashboard, and select AD NEW
32
+ 2. Search for 'Manual Imag Crop', and click install
33
+ 3. When the plugin has been installed, Click 'Activate'
34
+
35
+
36
+ == Changelog ==
37
+
38
+ = 1.0 =
39
+ Initial version
40
+
41
+ = 1.01 =
42
+ -Fixed Chrome stretched image issue
43
+ -Improved compatibility with other plugins using 'thickbox'