cropper 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rvmrc +48 -0
- data/Gemfile +7 -0
- data/README.md +17 -0
- data/Rakefile +31 -0
- data/app/assets/images/cropper/progress_stripes.png +0 -0
- data/app/assets/images/cropper/scale.png +0 -0
- data/app/assets/images/cropper/scale_large.png +0 -0
- data/app/assets/images/cropper/scale_small.png +0 -0
- data/app/assets/images/cropper/upload_spinner.gif +0 -0
- data/app/assets/javascripts/cropper.js.coffee +9 -0
- data/app/assets/javascripts/cropper/filedrop.js.coffee +255 -0
- data/app/assets/javascripts/cropper/upload_crop_scale.js.coffee +360 -0
- data/app/assets/javascripts/lib/es5-shim.js +1105 -0
- data/app/assets/javascripts/lib/modernizr.js +4 -0
- data/app/assets/stylesheets/cropper/uploads.css.sass +203 -0
- data/app/controllers/cropper/application_controller.rb +4 -0
- data/app/controllers/cropper/uploads_controller.rb +74 -0
- data/app/helpers/cropper/application_helper.rb +4 -0
- data/app/models/cropper/upload.rb +231 -0
- data/app/views/cropper/uploads/_crop.html.haml +34 -0
- data/app/views/cropper/uploads/_error.html.haml +1 -0
- data/app/views/cropper/uploads/_pick.html.haml +42 -0
- data/app/views/cropper/uploads/edit.html.haml +6 -0
- data/app/views/cropper/uploads/new.html.haml +5 -0
- data/app/views/cropper/uploads/show.html.haml +1 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +3 -0
- data/cropper.gemspec +32 -0
- data/db/migrate/20120510103921_uploads.rb +11 -0
- data/db/migrate/20130226190434_uploads_hold_crop_data.rb +8 -0
- data/db/migrate/20130402074802_upload_holder.rb +20 -0
- data/init.rb +4 -0
- data/lib/cropper.rb +159 -0
- data/lib/cropper/engine.rb +8 -0
- data/lib/cropper/glue.rb +20 -0
- data/lib/cropper/routing.rb +23 -0
- data/lib/cropper/schema.rb +63 -0
- data/lib/cropper/version.rb +3 -0
- data/lib/paperclip/geometry_transformation.rb +80 -0
- data/lib/paperclip/validators/attachment_height_validator.rb +89 -0
- data/lib/paperclip/validators/attachment_width_validator.rb +89 -0
- data/lib/paperclip_processors/offset_thumbnail.rb +93 -0
- data/lib/tasks/cropper_tasks.rake +4 -0
- data/script/rails +8 -0
- data/spec/acceptance/acceptance_helper.rb +2 -0
- data/spec/controllers/uploads_controller_spec.rb +5 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/thing.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +56 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/db/migrate/20120510104910_things.rb +8 -0
- data/spec/dummy/db/schema.rb +51 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/fixtures/images/icon.png +0 -0
- data/spec/fixtures/images/test.jpg +0 -0
- data/spec/models/thing_spec.rb +6 -0
- data/spec/models/upload_spec.rb +7 -0
- data/spec/spec_helper.rb +18 -0
- metadata +326 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/* Modernizr 2.0.6 | MIT & BSD
|
|
2
|
+
* Contains: All core tests, html5shiv, yepnope, respond.js. Get your own custom build at www.modernizr.com/download/
|
|
3
|
+
*/
|
|
4
|
+
;window.Modernizr=function(a,b,c){function I(){e.input=function(a){for(var b=0,c=a.length;b<c;b++)t[a[b]]=a[b]in l;return t}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,f,h,i=a.length;d<i;d++)l.setAttribute("type",f=a[d]),e=l.type!=="text",e&&(l.value=m,l.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(f)&&l.style.WebkitAppearance!==c?(g.appendChild(l),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(l,null).WebkitAppearance!=="textfield"&&l.offsetHeight!==0,g.removeChild(l)):/^(search|tel)$/.test(f)||(/^(url|email)$/.test(f)?e=l.checkValidity&&l.checkValidity()===!1:/^color$/.test(f)?(g.appendChild(l),g.offsetWidth,e=l.value!=m,g.removeChild(l)):e=l.value!=m)),s[a[d]]=!!e;return s}("search tel url email datetime date month week time datetime-local number range color".split(" "))}function G(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1),d=(a+" "+p.join(c+" ")+c).split(" ");return F(d,b)}function F(a,b){for(var d in a)if(k[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1}function E(a,b){return!!~(""+a).indexOf(b)}function D(a,b){return typeof a===b}function C(a,b){return B(o.join(a+";")+(b||""))}function B(a){k.cssText=a}var d="2.0.6",e={},f=!0,g=b.documentElement,h=b.head||b.getElementsByTagName("head")[0],i="modernizr",j=b.createElement(i),k=j.style,l=b.createElement("input"),m=":)",n=Object.prototype.toString,o=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),p="Webkit Moz O ms Khtml".split(" "),q={svg:"http://www.w3.org/2000/svg"},r={},s={},t={},u=[],v=function(a,c,d,e){var f,h,j,k=b.createElement("div");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:i+(d+1),k.appendChild(j);f=["­","<style>",a,"</style>"].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},w=function(b){if(a.matchMedia)return matchMedia(b).matches;var c;v("@media "+b+" { #"+i+" { position: absolute; } }",function(b){c=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).position=="absolute"});return c},x=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=D(e[d],"function"),D(e[d],c)||(e[d]=c),e.removeAttribute(d))),e=null;return f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),y,z={}.hasOwnProperty,A;!D(z,c)&&!D(z.call,c)?A=function(a,b){return z.call(a,b)}:A=function(a,b){return b in a&&D(a.constructor.prototype[b],c)};var H=function(c,d){var f=c.join(""),g=d.length;v(f,function(c,d){var f=b.styleSheets[b.styleSheets.length-1],h=f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"",i=c.childNodes,j={};while(g--)j[i[g].id]=i[g];e.touch="ontouchstart"in a||j.touch.offsetTop===9,e.csstransforms3d=j.csstransforms3d.offsetLeft===9,e.generatedcontent=j.generatedcontent.offsetHeight>=1,e.fontface=/src/i.test(h)&&h.indexOf(d.split(" ")[0])===0},g,d)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",o.join("touch-enabled),("),i,")","{#touch{top:9px;position:absolute}}"].join(""),["@media (",o.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join(""),['#generatedcontent:after{content:"',m,'";visibility:hidden}'].join("")],["fontface","touch","csstransforms3d","generatedcontent"]);r.flexbox=function(){function c(a,b,c,d){a.style.cssText=o.join(b+":"+c+";")+(d||"")}function a(a,b,c,d){b+=":",a.style.cssText=(b+o.join(c+";"+b)).slice(0,-b.length)+(d||"")}var d=b.createElement("div"),e=b.createElement("div");a(d,"display","box","width:42px;padding:0;"),c(e,"box-flex","1","width:10px;"),d.appendChild(e),g.appendChild(d);var f=e.offsetWidth===42;d.removeChild(e),g.removeChild(d);return f},r.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},r.canvastext=function(){return!!e.canvas&&!!D(b.createElement("canvas").getContext("2d").fillText,"function")},r.webgl=function(){return!!a.WebGLRenderingContext},r.touch=function(){return e.touch},r.geolocation=function(){return!!navigator.geolocation},r.postmessage=function(){return!!a.postMessage},r.websqldatabase=function(){var b=!!a.openDatabase;return b},r.indexedDB=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b].toLowerCase()+"IndexedDB"])return!0;return!!a.indexedDB},r.hashchange=function(){return x("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},r.history=function(){return!!a.history&&!!history.pushState},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){for(var b=-1,c=p.length;++b<c;)if(a[p[b]+"WebSocket"])return!0;return"WebSocket"in a},r.rgba=function(){B("background-color:rgba(150,255,150,.5)");return E(k.backgroundColor,"rgba")},r.hsla=function(){B("background-color:hsla(120,40%,100%,.5)");return E(k.backgroundColor,"rgba")||E(k.backgroundColor,"hsla")},r.multiplebgs=function(){B("background:url(https://),url(https://),red url(https://)");return/(url\s*\(.*?){3}/.test(k.background)},r.backgroundsize=function(){return G("backgroundSize")},r.borderimage=function(){return G("borderImage")},r.borderradius=function(){return G("borderRadius")},r.boxshadow=function(){return G("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){C("opacity:.55");return/^0.55$/.test(k.opacity)},r.cssanimations=function(){return G("animationName")},r.csscolumns=function(){return G("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";B((a+o.join(b+a)+o.join(c+a)).slice(0,-a.length));return E(k.backgroundImage,"gradient")},r.cssreflections=function(){return G("boxReflect")},r.csstransforms=function(){return!!F(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])},r.csstransforms3d=function(){var a=!!F(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=e.csstransforms3d);return a},r.csstransitions=function(){return G("transitionProperty")},r.fontface=function(){return e.fontface},r.generatedcontent=function(){return e.generatedcontent},r.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType){c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"');var d='video/mp4; codecs="avc1.42E01E';c.h264=a.canPlayType(d+'"')||a.canPlayType(d+', mp4a.40.2"'),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}}catch(e){}return c},r.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"'),c.mp3=a.canPlayType("audio/mpeg;"),c.wav=a.canPlayType('audio/wav; codecs="1"'),c.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}catch(d){}return c},r.localstorage=function(){try{return!!localStorage.getItem}catch(a){return!1}},r.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return!1}},r.webworkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");a.innerHTML="<svg/>";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var J in r)A(r,J)&&(y=J.toLowerCase(),e[y]=r[J](),u.push((e[y]?"":"no-")+y));e.input||I(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)A(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return;b=typeof b=="boolean"?b:!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b}return e},B(""),j=l=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="<elem></elem>";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b<g)a.createElement(f[b])}a.iepp=a.iepp||{};var d=a.iepp,e=d.html5elements||"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",f=e.split("|"),g=f.length,h=new RegExp("(^|\\s)("+e+")","gi"),i=new RegExp("<(/*)("+e+")","gi"),j=/^\s*[\{\}]\s*$/,k=new RegExp("(^|[^\\n]*?\\s)("+e+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),l=b.createDocumentFragment(),m=b.documentElement,n=m.firstChild,o=b.createElement("body"),p=b.createElement("style"),q=/print|all/,r;d.getCSS=function(a,b){if(a+""===c)return"";var e=-1,f=a.length,g,h=[];while(++e<f){g=a[e];if(g.disabled)continue;b=g.media||b,q.test(b)&&h.push(d.getCSS(g.imports,b),g.cssText),b="all"}return h.join("")},d.parseCSS=function(a){var b=[],c;while((c=k.exec(a))!=null)b.push(((j.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(h,"$1.iepp_$2")+c[4]);return b.join("\n")},d.writeHTML=function(){var a=-1;r=r||b.body;while(++a<g){var c=b.getElementsByTagName(f[a]),d=c.length,e=-1;while(++e<d)c[e].className.indexOf("iepp_")<0&&(c[e].className+=" iepp_"+f[a])}l.appendChild(r),m.appendChild(o),o.className=r.className,o.id=r.id,o.innerHTML=r.innerHTML.replace(i,"<$1font")},d._beforePrint=function(){p.styleSheet.cssText=d.parseCSS(d.getCSS(b.styleSheets,"all")),d.writeHTML()},d.restoreHTML=function(){o.innerHTML="",m.removeChild(o),m.appendChild(r)},d._afterPrint=function(){d.restoreHTML(),p.styleSheet.cssText=""},s(b),s(l);d.disablePP||(n.insertBefore(p,n.firstChild),p.media="print",p.className="iepp-printshim",a.attachEvent("onbeforeprint",d._beforePrint),a.attachEvent("onafterprint",d._afterPrint))}(a,b),e._version=d,e._prefixes=o,e._domPrefixes=p,e.mq=w,e.hasEvent=x,e.testProp=function(a){return F([a])},e.testAllProps=G,e.testStyles=v,e.prefixed=function(a){return G(a,"pfx")},g.className=g.className.replace(/\bno-js\b/,"")+(f?" js "+u.join(" "):"");return e}(this,this.document),function(a,b){function u(){r(!0)}a.respond={},respond.update=function(){},respond.mediaQueriesSupported=b;if(!b){var c=a.document,d=c.documentElement,e=[],f=[],g=[],h={},i=30,j=c.getElementsByTagName("head")[0]||d,k=j.getElementsByTagName("link"),l=[],m=function(){var b=k,c=b.length,d=0,e,f,g,i;for(;d<c;d++)e=b[d],f=e.href,g=e.media,i=e.rel&&e.rel.toLowerCase()==="stylesheet",!!f&&i&&!h[f]&&(!/^([a-zA-Z]+?:(\/\/)?(www\.)?)/.test(f)||f.replace(RegExp.$1,"").split("/")[0]===a.location.host?l.push({href:f,media:g}):h[f]=!0);n()},n=function(){if(l.length){var a=l.shift();s(a.href,function(b){o(b,a.href,a.media),h[a.href]=!0,n()})}},o=function(a,b,c){var d=a.match(/@media[^\{]+\{([^\{\}]+\{[^\}\{]+\})+/gi),g=d&&d.length||0,b=b.substring(0,b.lastIndexOf("/")),h=function(a){return a.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+b+"$2$3")},i=!g&&c,j=0,k,l,m,n,o;b.length&&(b+="/"),i&&(g=1);for(;j<g;j++){k=0,i?(l=c,f.push(h(a))):(l=d[j].match(/@media ([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1,f.push(RegExp.$2&&h(RegExp.$2))),n=l.split(","),o=n.length;for(;k<o;k++)m=n[k],e.push({media:m.match(/(only\s+)?([a-zA-Z]+)(\sand)?/)&&RegExp.$2,rules:f.length-1,minw:m.match(/\(min\-width:[\s]*([\s]*[0-9]+)px[\s]*\)/)&&parseFloat(RegExp.$1),maxw:m.match(/\(max\-width:[\s]*([\s]*[0-9]+)px[\s]*\)/)&&parseFloat(RegExp.$1)})}r()},p,q,r=function(a){var b="clientWidth",h=d[b],l=c.compatMode==="CSS1Compat"&&h||c.body[b]||h,m={},n=c.createDocumentFragment(),o=k[k.length-1],s=(new Date).getTime();if(a&&p&&s-p<i)clearTimeout(q),q=setTimeout(r,i);else{p=s;for(var t in e){var u=e[t];if(!u.minw&&!u.maxw||(!u.minw||u.minw&&l>=u.minw)&&(!u.maxw||u.maxw&&l<=u.maxw))m[u.media]||(m[u.media]=[]),m[u.media].push(f[u.rules])}for(var t in g)g[t]&&g[t].parentNode===j&&j.removeChild(g[t]);for(var t in m){var v=c.createElement("style"),w=m[t].join("\n");v.type="text/css",v.media=t,v.styleSheet?v.styleSheet.cssText=w:v.appendChild(c.createTextNode(w)),n.appendChild(v),g.push(v)}j.insertBefore(n,o.nextSibling)}},s=function(a,b){var c=t();if(!!c){c.open("GET",a,!0),c.onreadystatechange=function(){c.readyState==4&&(c.status==200||c.status==304)&&b(c.responseText)};if(c.readyState==4)return;c.send()}},t=function(){var a=!1,b=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new XMLHttpRequest}],c=b.length;while(c--){try{a=b[c]()}catch(d){continue}break}return function(){return a}}();m(),respond.update=m,a.addEventListener?a.addEventListener("resize",u,!1):a.attachEvent&&a.attachEvent("onresize",u)}}(this,Modernizr.mq("only all")),function(a,b,c){function k(a){return!a||a=="loaded"||a=="complete"}function j(){var a=1,b=-1;while(p.length- ++b)if(p[b].s&&!(a=p[b].r))break;a&&g()}function i(a){var c=b.createElement("script"),d;c.src=a.s,c.onreadystatechange=c.onload=function(){!d&&k(c.readyState)&&(d=1,j(),c.onload=c.onreadystatechange=null)},m(function(){d||(d=1,j())},H.errorTimeout),a.e?c.onload():n.parentNode.insertBefore(c,n)}function h(a){var c=b.createElement("link"),d;c.href=a.s,c.rel="stylesheet",c.type="text/css";if(!a.e&&(w||r)){var e=function(a){m(function(){if(!d)try{a.sheet.cssRules.length?(d=1,j()):e(a)}catch(b){b.code==1e3||b.message=="security"||b.message=="denied"?(d=1,m(function(){j()},0)):e(a)}},0)};e(c)}else c.onload=function(){d||(d=1,m(function(){j()},0))},a.e&&c.onload();m(function(){d||(d=1,j())},H.errorTimeout),!a.e&&n.parentNode.insertBefore(c,n)}function g(){var a=p.shift();q=1,a?a.t?m(function(){a.t=="c"?h(a):i(a)},0):(a(),j()):q=0}function f(a,c,d,e,f,h){function i(){!o&&k(l.readyState)&&(r.r=o=1,!q&&j(),l.onload=l.onreadystatechange=null,m(function(){u.removeChild(l)},0))}var l=b.createElement(a),o=0,r={t:d,s:c,e:h};l.src=l.data=c,!s&&(l.style.display="none"),l.width=l.height="0",a!="object"&&(l.type=d),l.onload=l.onreadystatechange=i,a=="img"?l.onerror=i:a=="script"&&(l.onerror=function(){r.e=r.r=1,g()}),p.splice(e,0,r),u.insertBefore(l,s?null:n),m(function(){o||(u.removeChild(l),r.r=r.e=o=1,j())},H.errorTimeout)}function e(a,b,c){var d=b=="c"?z:y;q=0,b=b||"j",C(a)?f(d,a,b,this.i++,l,c):(p.splice(this.i++,0,a),p.length==1&&g());return this}function d(){var a=H;a.loader={load:e,i:0};return a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=r&&!s,u=s?l:n.parentNode,v=a.opera&&o.call(a.opera)=="[object Opera]",w="webkitAppearance"in l.style,x=w&&"async"in b.createElement("script"),y=r?"object":v||x?"img":"script",z=w?"img":y,A=Array.isArray||function(a){return o.call(a)=="[object Array]"},B=function(a){return Object(a)===a},C=function(a){return typeof a=="string"},D=function(a){return o.call(a)=="[object Function]"},E=[],F={},G,H;H=function(a){function f(a){var b=a.split("!"),c=E.length,d=b.pop(),e=b.length,f={url:d,origUrl:d,prefixes:b},g,h;for(h=0;h<e;h++)g=F[b[h]],g&&(f=g(f));for(h=0;h<c;h++)f=E[h](f);return f}function e(a,b,e,g,h){var i=f(a),j=i.autoCallback;if(!i.bypass){b&&(b=D(b)?b:b[a]||b[g]||b[a.split("/").pop().split("?")[0]]);if(i.instead)return i.instead(a,b,e,g,h);e.load(i.url,i.forceCSS||!i.forceJS&&/css$/.test(i.url)?"c":c,i.noexec),(D(b)||D(j))&&e.load(function(){d(),b&&b(i.origUrl,h,g),j&&j(i.origUrl,h,g)})}}function b(a,b){function c(a){if(C(a))e(a,h,b,0,d);else if(B(a))for(i in a)a.hasOwnProperty(i)&&e(a[i],h,b,i,d)}var d=!!a.test,f=d?a.yep:a.nope,g=a.load||a.both,h=a.callback,i;c(f),c(g),a.complete&&b.load(a.complete)}var g,h,i=this.yepnope.loader;if(C(a))e(a,0,i,0);else if(A(a))for(g=0;g<a.length;g++)h=a[g],C(h)?e(h,0,i,0):A(h)?H(h):B(h)&&b(h,i);else B(a)&&b(a,i)},H.addPrefix=function(a,b){F[a]=b},H.addFilter=function(a){E.push(a)},H.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",G=function(){b.removeEventListener("DOMContentLoaded",G,0),b.readyState="complete"},0)),a.yepnope=d()}(this,this.document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
@import compass/css3
|
|
2
|
+
|
|
3
|
+
$coolgrey0: #f2f0ed
|
|
4
|
+
$coolgrey1: #e2e1dd
|
|
5
|
+
$coolgrey2: #d6d6d4
|
|
6
|
+
$coolgrey3: #cacac8
|
|
7
|
+
$coolgrey4: #bdbdbd
|
|
8
|
+
$coolgrey5: #b3b3b3
|
|
9
|
+
$coolgrey6: #afafaf
|
|
10
|
+
$coolgrey7: #9a9b9d
|
|
11
|
+
$coolgrey8: #8c8d8e
|
|
12
|
+
$coolgrey9: #747679
|
|
13
|
+
$coolgrey10: #616265
|
|
14
|
+
$coolgrey11: #4d4e53
|
|
15
|
+
$rubine: #d1005d
|
|
16
|
+
|
|
17
|
+
$text: #4d4e53
|
|
18
|
+
$link: #ED1C24
|
|
19
|
+
$hover: #9a9b9d
|
|
20
|
+
$active: #d1005d
|
|
21
|
+
$visited: #d3181f
|
|
22
|
+
$pale: #d6d6d4
|
|
23
|
+
$blue: #549dc4
|
|
24
|
+
$green: #74b87a
|
|
25
|
+
$input: #616265
|
|
26
|
+
$error: $rubine
|
|
27
|
+
$help: #e59811
|
|
28
|
+
|
|
29
|
+
$dark: #616265
|
|
30
|
+
$mid: #b3b3b3
|
|
31
|
+
$verypale: #ebeae8
|
|
32
|
+
$palest: #f5f5f5
|
|
33
|
+
|
|
34
|
+
.uploadbox
|
|
35
|
+
position: relative
|
|
36
|
+
width: 640px
|
|
37
|
+
height: 480px
|
|
38
|
+
overflow: hidden
|
|
39
|
+
background:
|
|
40
|
+
color: transparent
|
|
41
|
+
position: center center
|
|
42
|
+
repeat: no-repeat
|
|
43
|
+
&.hover
|
|
44
|
+
background-position: 0 - 150px
|
|
45
|
+
input
|
|
46
|
+
position: absolute
|
|
47
|
+
top: 300px
|
|
48
|
+
left: 0
|
|
49
|
+
.img
|
|
50
|
+
background:
|
|
51
|
+
color: $coolgrey0
|
|
52
|
+
repeat: no-repeat
|
|
53
|
+
position: top left
|
|
54
|
+
border: 1px solid $coolgrey1
|
|
55
|
+
a.detach
|
|
56
|
+
position: absolute
|
|
57
|
+
top: 10px
|
|
58
|
+
right: 10px
|
|
59
|
+
width: 32px
|
|
60
|
+
height: 32px
|
|
61
|
+
text-indent: 50px
|
|
62
|
+
overflow: hidden
|
|
63
|
+
background:
|
|
64
|
+
repeat: no-repeat
|
|
65
|
+
position: 0 -860px
|
|
66
|
+
image: image-url('cropper/symbols.png')
|
|
67
|
+
&:hover
|
|
68
|
+
background-color: $rubine
|
|
69
|
+
.prompt
|
|
70
|
+
text-align: center
|
|
71
|
+
padding: 55px 25px
|
|
72
|
+
a
|
|
73
|
+
color: $link
|
|
74
|
+
.note
|
|
75
|
+
color: $mid
|
|
76
|
+
&:hover, &.hover
|
|
77
|
+
.prompt
|
|
78
|
+
a
|
|
79
|
+
color: $hover
|
|
80
|
+
&.hover
|
|
81
|
+
.img
|
|
82
|
+
.prompt
|
|
83
|
+
a
|
|
84
|
+
color: $hover
|
|
85
|
+
|
|
86
|
+
.progress_holder
|
|
87
|
+
position: absolute
|
|
88
|
+
overflow: hidden
|
|
89
|
+
top: 10%
|
|
90
|
+
left: 10%
|
|
91
|
+
width: 75%
|
|
92
|
+
height: 32px
|
|
93
|
+
border: 1px solid $mid
|
|
94
|
+
background-color: white
|
|
95
|
+
z-index: 900
|
|
96
|
+
+border-radius
|
|
97
|
+
.progress
|
|
98
|
+
position: relative
|
|
99
|
+
width: 0%
|
|
100
|
+
height: 100%
|
|
101
|
+
background-color: $active
|
|
102
|
+
background: transparent image-url('cropper/progress_stripes.png') repeat-x top left scroll
|
|
103
|
+
.commentary
|
|
104
|
+
position: absolute
|
|
105
|
+
top: 0
|
|
106
|
+
left: 0
|
|
107
|
+
width: 100%
|
|
108
|
+
font-size: 1em
|
|
109
|
+
line-height: 1
|
|
110
|
+
padding: 1em
|
|
111
|
+
text-align: cetner
|
|
112
|
+
.waiter
|
|
113
|
+
position: absolute
|
|
114
|
+
overflow: hidden
|
|
115
|
+
top: 150px
|
|
116
|
+
left: 410px
|
|
117
|
+
width: 32px
|
|
118
|
+
height: 32px
|
|
119
|
+
background: transparent image-url('cropper/upload_spinner.gif') no-repeat center center scroll
|
|
120
|
+
display: none
|
|
121
|
+
.preview
|
|
122
|
+
position: absolute
|
|
123
|
+
top: 0
|
|
124
|
+
left: 0
|
|
125
|
+
cursor: move
|
|
126
|
+
img
|
|
127
|
+
width: 100%
|
|
128
|
+
height: 100%
|
|
129
|
+
.report
|
|
130
|
+
position: absolute
|
|
131
|
+
top: 20px
|
|
132
|
+
left: 20px
|
|
133
|
+
z-index: 500
|
|
134
|
+
.scaler
|
|
135
|
+
position: absolute
|
|
136
|
+
top: 100px
|
|
137
|
+
left: 55px
|
|
138
|
+
width: 240px
|
|
139
|
+
height: 40px
|
|
140
|
+
color: white
|
|
141
|
+
+text-shadow(1px, 2px, 3px, #333)
|
|
142
|
+
p.range
|
|
143
|
+
position: relative
|
|
144
|
+
margin: 0 auto
|
|
145
|
+
overflow: hidden
|
|
146
|
+
span.small, span.large
|
|
147
|
+
display: inline-block
|
|
148
|
+
width: 32px
|
|
149
|
+
height: 50px
|
|
150
|
+
background-repeat: no-repeat
|
|
151
|
+
span.small
|
|
152
|
+
background:
|
|
153
|
+
image: image-url('cropper/scale_small.png')
|
|
154
|
+
position: right center
|
|
155
|
+
span.large
|
|
156
|
+
background:
|
|
157
|
+
image: image-url('cropper/scale_large.png')
|
|
158
|
+
position: left center
|
|
159
|
+
|
|
160
|
+
.stop
|
|
161
|
+
display: block
|
|
162
|
+
position: relative
|
|
163
|
+
border: 2px solid white
|
|
164
|
+
+box-shadow
|
|
165
|
+
float: left
|
|
166
|
+
&.min
|
|
167
|
+
width: 9px
|
|
168
|
+
height: 12px
|
|
169
|
+
margin-top: 14px
|
|
170
|
+
margin-right: 4px
|
|
171
|
+
&.max
|
|
172
|
+
width: 18px
|
|
173
|
+
height: 24px
|
|
174
|
+
margin-top: 6px
|
|
175
|
+
margin-left: 5px
|
|
176
|
+
.slider
|
|
177
|
+
display: block
|
|
178
|
+
position: relative
|
|
179
|
+
display: inline-block
|
|
180
|
+
width: 150px
|
|
181
|
+
height: 40px
|
|
182
|
+
background: transparent image-url('cropper/scale.png') no-repeat 0 20px
|
|
183
|
+
.marker
|
|
184
|
+
display: block
|
|
185
|
+
position: absolute
|
|
186
|
+
background-color: white
|
|
187
|
+
+box-shadow
|
|
188
|
+
top: 9px
|
|
189
|
+
left: 50px
|
|
190
|
+
width: 12px
|
|
191
|
+
height: 24px
|
|
192
|
+
cursor: move
|
|
193
|
+
z-index: 1000
|
|
194
|
+
|
|
195
|
+
.overflow
|
|
196
|
+
position: absolute
|
|
197
|
+
overflow: hidden
|
|
198
|
+
top: 0
|
|
199
|
+
left: 0
|
|
200
|
+
+opacity(0.3)
|
|
201
|
+
img
|
|
202
|
+
width: 100%
|
|
203
|
+
height: 100%
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Cropper
|
|
2
|
+
class UploadsController < ::ApplicationController
|
|
3
|
+
respond_to :js
|
|
4
|
+
before_filter :get_holder, :only => [:new, :create]
|
|
5
|
+
before_filter :find_upload, :only => [:show, :edit, :destroy]
|
|
6
|
+
before_filter :build_upload, :only => [:new, :create]
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
respond_with(@uploads)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def show
|
|
13
|
+
respond_with(@upload)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def new
|
|
17
|
+
respond_with @upload do |format|
|
|
18
|
+
format.js { render :partial => 'pick' }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create
|
|
23
|
+
@upload.holder ||= @holder
|
|
24
|
+
@upload.update_attributes(params[:upload])
|
|
25
|
+
respond_with(@upload) do |format|
|
|
26
|
+
format.js { render :partial => 'crop' }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def edit
|
|
31
|
+
respond_with(@upload) do |format|
|
|
32
|
+
format.js { render :partial => 'crop' }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update
|
|
37
|
+
@upload.update_attributes(params[:upload])
|
|
38
|
+
redirect_to @holder
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def destroy
|
|
42
|
+
@upload.destroy
|
|
43
|
+
head :ok
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def get_holder
|
|
49
|
+
klass = params[:holder_type]
|
|
50
|
+
if id = params[:holder_id]
|
|
51
|
+
@holder = klass.classify.constantize.find(id)
|
|
52
|
+
else
|
|
53
|
+
# The difficult case is when an upload is created during the creation of a new holder
|
|
54
|
+
# this at least gives us access the necessary geometry methods.
|
|
55
|
+
@holder = klass.classify.constantize.new
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def build_upload
|
|
60
|
+
@column = params[:holder_column] || :image
|
|
61
|
+
@upload = @holder.send(:"build_#{@column}_upload")
|
|
62
|
+
@holder.send(:"#{@column}_upload=", @upload)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def find_upload
|
|
66
|
+
if params[:uuid]
|
|
67
|
+
@upload = Cropper::Upload.find_by_uuid(params[:uuid])
|
|
68
|
+
else
|
|
69
|
+
@upload = Cropper::Upload.find(params[:id])
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# This is a standard upload class that should be useable for most purposes.
|
|
2
|
+
# We assume that even when the final destination is an S3 bucket, the initial upload
|
|
3
|
+
# will be held locally.
|
|
4
|
+
#
|
|
5
|
+
require 'open-uri'
|
|
6
|
+
|
|
7
|
+
module Cropper
|
|
8
|
+
class Upload < ActiveRecord::Base
|
|
9
|
+
belongs_to :holder, :polymorphic => true
|
|
10
|
+
attr_accessible :file, :scale_width, :scale_height, :offset_top, :offset_left, :holder_type, :holder_id, :holder, :holder_column, :multiplier
|
|
11
|
+
attr_accessor :reprocessed, :multiplier
|
|
12
|
+
# Unlike previous versions, the main resizing and cropping step is now carried out within the upload object.
|
|
13
|
+
# Usually this happens in a second step: first we upload, then we update with crop parameters, but it is
|
|
14
|
+
# also possible to present the cropping in javascript and upload the file with all the necessary values.
|
|
15
|
+
|
|
16
|
+
has_attached_file :file,
|
|
17
|
+
:processors => [:thumbnail],
|
|
18
|
+
:styles => lambda { |attachment| attachment.instance.paperclip_styles }
|
|
19
|
+
|
|
20
|
+
validates :file, :attachment_presence => true
|
|
21
|
+
validates :holder_column, :presence => true
|
|
22
|
+
|
|
23
|
+
before_update :reprocess_if_crop_changed
|
|
24
|
+
before_save :apply_multiplier
|
|
25
|
+
|
|
26
|
+
scope :destined_for, lambda { |col|
|
|
27
|
+
where(:holder_column => col).order('updated_at DESC, created_at DESC')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def paperclip_styles
|
|
31
|
+
styles = {}
|
|
32
|
+
styles[:precrop] = {
|
|
33
|
+
:geometry => precrop_geometry,
|
|
34
|
+
:processors => [:thumbnail]
|
|
35
|
+
}
|
|
36
|
+
if croppable?
|
|
37
|
+
styles[:cropped] = {
|
|
38
|
+
:geometry => crop_geometry,
|
|
39
|
+
:processors => [:offset_thumbnail],
|
|
40
|
+
:scale => "#{scale_width}x",
|
|
41
|
+
:crop_and_offset => "%dx%d%+d%+d" % [crop_width, crop_height, -offset_left, -offset_top]
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
styles
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def styled_file(style=:cropped)
|
|
48
|
+
settings = Rails.application.config.paperclip_defaults
|
|
49
|
+
if bucket = Fog::Storage.new(settings[:fog_credentials]).directories.get(settings[:fog_directory])
|
|
50
|
+
bucket.files.get(file.path(style))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# crop_changed? returns true if any property has changed that should cause a recrop. That shuold include the file attachment itself.
|
|
55
|
+
#
|
|
56
|
+
def crop_changed?
|
|
57
|
+
!self.reprocessed && !![:scale_width, :scale_height, :offset_top, :offset_left, :holder_type, :holder_id, :holder_column].detect { |col| self.send :"#{col}_changed?" }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def reprocess_if_crop_changed
|
|
61
|
+
self.file.assign(file) if crop_changed?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
## Image dimensions
|
|
65
|
+
#
|
|
66
|
+
# We need to know dimensions of the precrop image in order to set up the cropping interface,
|
|
67
|
+
# so we examine the uploaded file before it is flushed.
|
|
68
|
+
#
|
|
69
|
+
after_post_process :read_dimensions
|
|
70
|
+
after_save :update_holder
|
|
71
|
+
|
|
72
|
+
# ## Crop boundaries
|
|
73
|
+
#
|
|
74
|
+
# Precrop geometry is unpredictable and has to be calculated.
|
|
75
|
+
#
|
|
76
|
+
def precrop_geometry
|
|
77
|
+
@precrop_geometry ||= Cropper.precrop_geometry(holder_type, holder_column)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def precrop_width
|
|
81
|
+
@precrop_width ||= width(:precrop)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def precrop_height
|
|
85
|
+
@precrop_height ||= height(:precrop)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Cropped geometry is always to a fixed size, so we can just return parts of the definition
|
|
89
|
+
# knowing that they match the eventual dimensions. Useful, because we need this information to
|
|
90
|
+
# build the cropping interface.
|
|
91
|
+
#
|
|
92
|
+
def crop_geometry
|
|
93
|
+
@crop_geometry ||= Cropper.crop_geometry(holder_type, holder_column)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def crop_width
|
|
97
|
+
@cropped_width ||= crop_geometry.split('x').first.to_i
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def crop_height
|
|
101
|
+
@cropped_height ||= crop_geometry.split('x').last.to_i
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# *original_geometry* returns the discovered dimensions of the uploaded file as a paperclip geometry object.
|
|
105
|
+
#
|
|
106
|
+
def original_geometry
|
|
107
|
+
@original_geometry ||= Paperclip::Geometry.new(original_width, original_height)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# *geometry*, given a style name, returns the dimensions of the file if that style were applied. For
|
|
111
|
+
# speed we calculate this rather than reading the file, which might be in S3 or some other distant place.
|
|
112
|
+
#
|
|
113
|
+
# The logic is in [lib/paperclip/geometry_tranformation.rb](/lib/paperclip/geometry_tranformation.html),
|
|
114
|
+
# which is a ruby library that mimics the action of imagemagick's convert command.
|
|
115
|
+
#
|
|
116
|
+
def geometry(style_name='original')
|
|
117
|
+
@geometry ||= {}
|
|
118
|
+
begin
|
|
119
|
+
@geometry[style_name] ||= if style_name.to_s == 'original'
|
|
120
|
+
# If no style name is given, or it is 'original', we return the original discovered dimensions.
|
|
121
|
+
original_geometry
|
|
122
|
+
else
|
|
123
|
+
# Otherwise, we apply a mock transformation to see what dimensions would result.
|
|
124
|
+
style = self.file.styles[style_name.to_sym]
|
|
125
|
+
original_geometry.transformed_by(style.geometry)
|
|
126
|
+
end
|
|
127
|
+
rescue Paperclip::TransformationError => e
|
|
128
|
+
# In case of explosion, we always return the original dimensions so that action can continue.
|
|
129
|
+
original_geometry
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# *width* returns the width of this image in a given style.
|
|
134
|
+
#
|
|
135
|
+
def width(style_name='original')
|
|
136
|
+
geometry(style_name).width.to_i
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# *height* returns the height of this image in a given style.
|
|
140
|
+
#
|
|
141
|
+
def height(style_name='original')
|
|
142
|
+
geometry(style_name).height.to_i
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# *square?* returns true if width and height are the same.
|
|
146
|
+
#
|
|
147
|
+
def square?(style_name='original')
|
|
148
|
+
geometry(style_name).square?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# *vertical?* returns true if the image, in the given style, is taller than it is wide.
|
|
152
|
+
#
|
|
153
|
+
def vertical?(style_name='original')
|
|
154
|
+
geometry(style_name).vertical?
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# *horizontal?* returns true if the image, in the given style, is wider than it is tall.
|
|
158
|
+
#
|
|
159
|
+
def horizontal?(style_name='original')
|
|
160
|
+
geometry(style_name).horizontal?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# *dimensions_known?* returns true we have managed to discover the dimensions of the original file.
|
|
164
|
+
#
|
|
165
|
+
def dimensions_known?
|
|
166
|
+
original_width? && original_height?
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
##
|
|
170
|
+
|
|
171
|
+
def url(style=:cropped)
|
|
172
|
+
file.url(:style)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
private
|
|
176
|
+
|
|
177
|
+
# sometimes the interface will work in miniature and send through a multiplier by which to scale everything up.
|
|
178
|
+
def apply_multiplier
|
|
179
|
+
if multiplier = self.multiplier.to_i
|
|
180
|
+
Rails.logger.warn "multiplying upload params by #{multiplier}."
|
|
181
|
+
if multiplier != 1
|
|
182
|
+
%w{offset_left offset_top scale_width scale_height}.each do |col|
|
|
183
|
+
if param = self.send(col.to_sym)
|
|
184
|
+
self.send(:"#{col}=", param * self.multiplier.to_i)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
self.multiplier = 1
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# *read_dimensions* is called after post processing to record in the database the original width, height
|
|
193
|
+
# and extension of the uploaded file. At this point the file queue will not have been flushed but the upload
|
|
194
|
+
# should be in place. We grab dimensions from the temp file and calculate thumbnail dimensions later, on demand.
|
|
195
|
+
#
|
|
196
|
+
def read_dimensions
|
|
197
|
+
if uploaded_file = self.file.queued_for_write[:original]
|
|
198
|
+
file = uploaded_file.send :destination
|
|
199
|
+
Rails.logger.warn "+++ getting geometry from queued file #{file.inspect}."
|
|
200
|
+
Rails.logger.warn "--- File exist? #{File.exist?(file).inspect}"
|
|
201
|
+
geometry = Paperclip::Geometry.from_file(file)
|
|
202
|
+
Rails.logger.warn "=== Geometry: #{geometry.inspect}"
|
|
203
|
+
self.original_width = geometry.width
|
|
204
|
+
self.original_height = geometry.height
|
|
205
|
+
self.original_extension = File.extname(file.path)
|
|
206
|
+
Rails.logger.warn "??? validity: #{self.valid?.inspect}. errors: #{self.errors.inspect}"
|
|
207
|
+
end
|
|
208
|
+
true
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def croppable?
|
|
212
|
+
!!scale_width && !!offset_left && !!offset_top
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def update_holder
|
|
216
|
+
if holder
|
|
217
|
+
holder.send :"#{holder_column}_upload=", self
|
|
218
|
+
if croppable? && holder.persisted?
|
|
219
|
+
if source = file.url(:cropped, false)
|
|
220
|
+
source = (Rails.root + "public/#{source}") unless source =~ /^http/
|
|
221
|
+
Rails.logger.warn "--- update_holder: #{source}"
|
|
222
|
+
Rails.logger.warn "--- File exist? #{File.exist?(source).inspect}"
|
|
223
|
+
holder.send :"#{holder_column}=", open(source)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
holder.save
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
end
|
|
231
|
+
end
|