diff --git a/.gitignore b/.gitignore index eb3489a..90ec8a8 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ # Ignore all logfiles and tempfiles. /log/*.log /tmp +/public diff --git a/.rvmrc b/.rvmrc new file mode 100644 index 0000000..81983d7 --- /dev/null +++ b/.rvmrc @@ -0,0 +1 @@ +rvm --create use "ruby-2.0.0@dropzone" diff --git a/Gemfile b/Gemfile index 860f485..d1b2b5d 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ group :assets do gem 'coffee-rails', '~> 3.2.1' # See https://github.com/sstephenson/execjs#readme for more supported runtimes - # gem 'therubyracer', :platforms => :ruby + gem 'therubyracer', :platforms => :ruby gem 'uglifier', '>= 1.0.3' end @@ -41,4 +41,7 @@ gem "haml-rails" gem "jquery-rails" gem "bson_ext" gem "mongoid", ">= 2.0.0.beta.19" -gem "rspec-rails", ">= 2.0.1", :group => [:development, :test] \ No newline at end of file +gem "rspec-rails", ">= 2.0.1", :group => [:development, :test] +gem "cloudinary" +gem 'carrierwave-mongoid' +gem 'bootstrap-sass' diff --git a/Gemfile.lock b/Gemfile.lock index f5dd6fb..92210d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -29,10 +29,24 @@ GEM i18n (~> 0.6) multi_json (~> 1.0) arel (3.0.2) + aws_cf_signer (0.1.1) + bootstrap-sass (2.3.2.1) + sass (~> 3.2) bson (1.9.1) bson_ext (1.9.1) bson (~> 1.9.1) builder (3.0.4) + carrierwave (0.9.0) + activemodel (>= 3.2.0) + activesupport (>= 3.2.0) + json (>= 1.7) + carrierwave-mongoid (0.6.1) + carrierwave (>= 0.8.0, < 0.10.0) + mongoid (>= 3.0, < 5.0) + mongoid-grid_fs (~> 1.3) + cloudinary (1.0.62) + aws_cf_signer + rest-client coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) @@ -58,6 +72,7 @@ GEM railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.0) + libv8 (3.11.8.17) mail (2.4.4) i18n (>= 0.4.0) mime-types (~> 1.16) @@ -68,6 +83,9 @@ GEM moped (~> 1.4) origin (~> 1.0) tzinfo (~> 0.3.22) + mongoid-grid_fs (1.8.0) + mime-types (~> 1.19) + mongoid (~> 3.0) moped (1.5.0) multi_json (1.7.7) origin (1.1.0) @@ -97,6 +115,9 @@ GEM rake (10.1.0) rdoc (3.12.2) json (~> 1.4) + ref (1.0.5) + rest-client (1.6.7) + mime-types (>= 1.16) rspec-core (2.14.4) rspec-expectations (2.14.0) diff-lcs (>= 1.1.3, < 2.0) @@ -118,6 +139,9 @@ GEM multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) + therubyracer (0.11.4) + libv8 (~> 3.11.8.12) + ref thor (0.18.1) tilt (1.4.1) treetop (1.4.14) @@ -132,7 +156,10 @@ PLATFORMS ruby DEPENDENCIES + bootstrap-sass bson_ext + carrierwave-mongoid + cloudinary coffee-rails (~> 3.2.1) haml (>= 3.0.0) haml-rails @@ -141,4 +168,5 @@ DEPENDENCIES rails (= 3.2.11) rspec-rails (>= 2.0.1) sass-rails (~> 3.2.3) + therubyracer uglifier (>= 1.0.3) diff --git a/app/assets/images/spritemap.png b/app/assets/images/spritemap.png new file mode 100644 index 0000000..9f21314 Binary files /dev/null and b/app/assets/images/spritemap.png differ diff --git a/app/assets/images/spritemap@2x.png b/app/assets/images/spritemap@2x.png new file mode 100644 index 0000000..e877eea Binary files /dev/null and b/app/assets/images/spritemap@2x.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 15ebed9..f96d98c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,4 +10,6 @@ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. // +//= require jquery.min +//= require jquery_ujs //= require_tree . diff --git a/app/assets/javascripts/dropzone.min.js b/app/assets/javascripts/dropzone.min.js new file mode 100644 index 0000000..06333ea --- /dev/null +++ b/app/assets/javascripts/dropzone.min.js @@ -0,0 +1,26 @@ +!function(){function e(t,i,n){var r=e.resolve(t);if(null==r){n=n||t,i=i||"root";var s=new Error('Failed to require "'+n+'" from "'+i+'"');throw s.path=n,s.parent=i,s.require=!0,s}var o=e.modules[r];return o.exports||(o.exports={},o.client=o.component=!0,o.call(this,o.exports,e.relative(r),o)),o.exports}e.modules={},e.aliases={},e.resolve=function(t){"/"===t.charAt(0)&&(t=t.slice(1));for(var i=[t,t+".js",t+".json",t+"/index.js",t+"/index.json"],n=0;nn;++n)i[n].apply(this,t)}return this},n.prototype.listeners=function(e){return this._callbacks=this._callbacks||{},this._callbacks[e]||[]},n.prototype.hasListeners=function(e){return!!this.listeners(e).length}}),e.register("dropzone/index.js",function(e,t,i){i.exports=t("./lib/dropzone.js")}),e.register("dropzone/lib/dropzone.js",function(e,t,i){/* +# +# More info at [www.dropzonejs.com](http://www.dropzonejs.com) +# +# Copyright (c) 2012, Matias Meno +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +*/ +!function(){var e,n,r,s,o,l,a={}.hasOwnProperty,p=function(e,t){function i(){this.constructor=e}for(var n in t)a.call(t,n)&&(e[n]=t[n]);return i.prototype=t.prototype,e.prototype=new i,e.__super__=t.prototype,e},u=[].slice;n="undefined"!=typeof Emitter&&null!==Emitter?Emitter:t("emitter"),o=function(){},e=function(e){function t(e,n){var r,s,o;if(this.element=e,this.version=t.version,this.defaultOptions.previewTemplate=this.defaultOptions.previewTemplate.replace(/\n*/g,""),this.clickableElements=[],this.listeners=[],this.files=[],"string"==typeof this.element&&(this.element=document.querySelector(this.element)),!this.element||null==this.element.nodeType)throw new Error("Invalid dropzone element.");if(this.element.dropzone)throw new Error("Dropzone already attached.");if(t.instances.push(this),e.dropzone=this,r=null!=(o=t.optionsForElement(this.element))?o:{},this.options=i({},this.defaultOptions,r,null!=n?n:{}),null==this.options.url&&(this.options.url=this.element.action),!this.options.url)throw new Error("No URL provided.");if(this.options.acceptedFiles&&this.options.acceptedMimeTypes)throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");return this.options.acceptedMimeTypes&&(this.options.acceptedFiles=this.options.acceptedMimeTypes,delete this.options.acceptedMimeTypes),this.options.method=this.options.method.toUpperCase(),this.options.forceFallback||!t.isBrowserSupported()?this.options.fallback.call(this):((s=this.getExistingFallback())&&s.parentNode&&s.parentNode.removeChild(s),this.previewsContainer=this.options.previewsContainer?t.getElement(this.options.previewsContainer,"previewsContainer"):this.element,this.options.clickable&&(this.clickableElements=this.options.clickable===!0?[this.element]:t.getElements(this.options.clickable,"clickable")),this.init(),void 0)}var i;return p(t,e),t.prototype.events=["drop","dragstart","dragend","dragenter","dragover","dragleave","selectedfiles","addedfile","removedfile","thumbnail","error","processing","processingmultiple","uploadprogress","totaluploadprogress","sending","sendingmultiple","success","successmultiple","canceled","canceledmultiple","complete","completemultiple","reset"],t.prototype.defaultOptions={url:null,method:"post",withCredentials:!1,parallelUploads:2,uploadMultiple:!1,maxFilesize:256,paramName:"file",createImageThumbnails:!0,maxThumbnailFilesize:10,thumbnailWidth:100,thumbnailHeight:100,params:{},clickable:!0,ignoreHiddenFiles:!0,acceptedFiles:null,acceptedMimeTypes:null,autoProcessQueue:!0,addRemoveLinks:!1,previewsContainer:null,dictDefaultMessage:"Drop files here to upload",dictFallbackMessage:"Your browser does not support drag'n'drop file uploads.",dictFallbackText:"Please use the fallback form below to upload your files like in the olden days.",dictFileTooBig:"File is too big ({{filesize}}MB). Max filesize: {{maxFilesize}}MB.",dictInvalidFileType:"You can't upload files of this type.",dictResponseError:"Server responded with {{statusCode}} code.",dictCancelUpload:"Cancel upload",dictCancelUploadConfirmation:"Are you sure you want to cancel this upload?",dictRemoveFile:"Remove file",accept:function(e,t){return t()},init:function(){return o},forceFallback:!1,fallback:function(){var e,i,n,r,s,o;for(this.element.className=""+this.element.className+" dz-browser-not-supported",o=this.element.getElementsByTagName("div"),r=0,s=o.length;s>r;r++)e=o[r],/(^| )dz-message($| )/.test(e.className)&&(i=e,e.className="dz-message");return i||(i=t.createElement('
'),this.element.appendChild(i)),n=i.getElementsByTagName("span")[0],n&&(n.textContent=this.options.dictFallbackMessage),this.element.appendChild(this.getFallbackForm())},resize:function(e){var t,i,n;return t={srcX:0,srcY:0,srcWidth:e.width,srcHeight:e.height},i=e.width/e.height,n=this.options.thumbnailWidth/this.options.thumbnailHeight,e.heightn?(t.srcHeight=e.height,t.srcWidth=t.srcHeight*n):(t.srcWidth=e.width,t.srcHeight=t.srcWidth/n),t.srcX=(e.width-t.srcWidth)/2,t.srcY=(e.height-t.srcHeight)/2,t},drop:function(){return this.element.classList.remove("dz-drag-hover")},dragstart:o,dragend:function(){return this.element.classList.remove("dz-drag-hover")},dragenter:function(){return this.element.classList.add("dz-drag-hover")},dragover:function(){return this.element.classList.add("dz-drag-hover")},dragleave:function(){return this.element.classList.remove("dz-drag-hover")},selectedfiles:function(){return this.element===this.previewsContainer?this.element.classList.add("dz-started"):void 0},reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(e){var i=this;return e.previewElement=t.createElement(this.options.previewTemplate),e.previewTemplate=e.previewElement,this.previewsContainer.appendChild(e.previewElement),e.previewElement.querySelector("[data-dz-name]").textContent=e.name,e.previewElement.querySelector("[data-dz-size]").innerHTML=this.filesize(e.size),e.remote_url&&(e.previewElement.querySelector("[data-dz-thumbnail]").src=e.remote_url,e.previewElement.classList.remove("dz-file-preview"),e.previewElement.classList.add("dz-image-preview"),e.previewElement.classList.add("dz-success")),this.options.addRemoveLinks?(e._removeLink=t.createElement(''+this.options.dictRemoveFile+""),e._removeLink.addEventListener("click",function(n){return n.preventDefault(),n.stopPropagation(),e.status!==t.UPLOADING?i.removeFile(e):window.confirm(i.options.dictCancelUploadConfirmation)?i.removeFile(e):void 0}),e.previewElement.appendChild(e._removeLink)):void 0},removedfile:function(e){var t;return null!=(t=e.previewElement)?t.parentNode.removeChild(e.previewElement):void 0},thumbnail:function(e,t){var i;return e.previewElement.classList.remove("dz-file-preview"),e.previewElement.classList.add("dz-image-preview"),i=e.previewElement.querySelector("[data-dz-thumbnail]"),i.alt=e.name,i.src=t},error:function(e,t){return e.previewElement.classList.add("dz-error"),e.previewElement.querySelector("[data-dz-errormessage]").textContent=t},processing:function(e){return e.previewElement.classList.add("dz-processing"),e._removeLink?e._removeLink.textContent=this.options.dictCancelUpload:void 0},processingmultiple:o,uploadprogress:function(e,t){return e.previewElement.querySelector("[data-dz-uploadprogress]").style.width=""+t+"%"},totaluploadprogress:o,sending:o,sendingmultiple:o,success:function(e){return e.previewElement.classList.add("dz-success")},successmultiple:o,canceled:function(e){return this.emit("error",e,"Upload canceled.")},canceledmultiple:o,complete:function(e){return e._removeLink?e._removeLink.textContent=this.options.dictRemoveFile:void 0},completemultiple:o,previewTemplate:'
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
'},i=function(){var e,t,i,n,r,s,o;for(n=arguments[0],i=2<=arguments.length?u.call(arguments,1):[],s=0,o=i.length;o>s;s++){t=i[s];for(e in t)r=t[e],n[e]=r}return n},t.prototype.getAcceptedFiles=function(){var e,t,i,n,r;for(n=this.files,r=[],t=0,i=n.length;i>t;t++)e=n[t],e.accepted&&r.push(e);return r},t.prototype.getRejectedFiles=function(){var e,t,i,n,r;for(n=this.files,r=[],t=0,i=n.length;i>t;t++)e=n[t],e.accepted||r.push(e);return r},t.prototype.getQueuedFiles=function(){var e,i,n,r,s;for(r=this.files,s=[],i=0,n=r.length;n>i;i++)e=r[i],e.status===t.QUEUED&&s.push(e);return s},t.prototype.getUploadingFiles=function(){var e,i,n,r,s;for(r=this.files,s=[],i=0,n=r.length;n>i;i++)e=r[i],e.status===t.UPLOADING&&s.push(e);return s},t.prototype.init=function(){var e,i,n,r,s,o,l,a=this;for("form"===this.element.tagName&&this.element.setAttribute("enctype","multipart/form-data"),this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")&&this.element.appendChild(t.createElement('
'+this.options.dictDefaultMessage+"
")),this.clickableElements.length&&(n=function(){return a.hiddenFileInput&&document.body.removeChild(a.hiddenFileInput),a.hiddenFileInput=document.createElement("input"),a.hiddenFileInput.setAttribute("type","file"),a.options.uploadMultiple&&a.hiddenFileInput.setAttribute("multiple","multiple"),null!=a.options.acceptedFiles&&a.hiddenFileInput.setAttribute("accept",a.options.acceptedFiles),a.hiddenFileInput.style.visibility="hidden",a.hiddenFileInput.style.position="absolute",a.hiddenFileInput.style.top="0",a.hiddenFileInput.style.left="0",a.hiddenFileInput.style.height="0",a.hiddenFileInput.style.width="0",document.body.appendChild(a.hiddenFileInput),a.hiddenFileInput.addEventListener("change",function(){var e;return e=a.hiddenFileInput.files,e.length&&(a.emit("selectedfiles",e),a.handleFiles(e)),n()})},n()),this.URL=null!=(o=window.URL)?o:window.webkitURL,l=this.events,r=0,s=l.length;s>r;r++)e=l[r],this.on(e,this.options[e]);return this.on("uploadprogress",function(){return a.updateTotalUploadProgress()}),this.on("removedfile",function(){return a.updateTotalUploadProgress()}),this.on("canceled",function(e){return a.emit("complete",e)}),i=function(e){return e.stopPropagation(),e.preventDefault?e.preventDefault():e.returnValue=!1},this.listeners=[{element:this.element,events:{dragstart:function(e){return a.emit("dragstart",e)},dragenter:function(e){return i(e),a.emit("dragenter",e)},dragover:function(e){return i(e),a.emit("dragover",e)},dragleave:function(e){return a.emit("dragleave",e)},drop:function(e){return i(e),a.drop(e),a.emit("drop",e)},dragend:function(e){return a.emit("dragend",e)}}}],this.clickableElements.forEach(function(e){return a.listeners.push({element:e,events:{click:function(i){return e!==a.element||i.target===a.element||t.elementInside(i.target,a.element.querySelector(".dz-message"))?a.hiddenFileInput.click():void 0}}})}),this.enable(),this.options.init.call(this)},t.prototype.destroy=function(){var e;return this.disable(),this.removeAllFiles(!0),(null!=(e=this.hiddenFileInput)?e.parentNode:void 0)&&(this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput),this.hiddenFileInput=null),delete this.element.dropzone},t.prototype.updateTotalUploadProgress=function(){var e,t,i,n,r,s,o,l;if(n=0,i=0,e=this.getAcceptedFiles(),e.length){for(l=this.getAcceptedFiles(),s=0,o=l.length;o>s;s++)t=l[s],n+=t.upload.bytesSent,i+=t.upload.total;r=100*n/i}else r=100;return this.emit("totaluploadprogress",r,i,n)},t.prototype.getFallbackForm=function(){var e,i,n,r;return(e=this.getExistingFallback())?e:(n='
',this.options.dictFallbackText&&(n+="

"+this.options.dictFallbackText+"

"),n+='
',i=t.createElement(n),"FORM"!==this.element.tagName?(r=t.createElement('
'),r.appendChild(i)):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=r?r:i)},t.prototype.getExistingFallback=function(){var e,t,i,n,r,s;for(t=function(e){var t,i,n;for(i=0,n=e.length;n>i;i++)if(t=e[i],/(^| )fallback($| )/.test(t.className))return t},s=["div","form"],n=0,r=s.length;r>n;n++)if(i=s[n],e=t(this.element.getElementsByTagName(i)))return e},t.prototype.setupEventListeners=function(){var e,t,i,n,r,s,o;for(s=this.listeners,o=[],n=0,r=s.length;r>n;n++)e=s[n],o.push(function(){var n,r;n=e.events,r=[];for(t in n)i=n[t],r.push(e.element.addEventListener(t,i,!1));return r}());return o},t.prototype.removeEventListeners=function(){var e,t,i,n,r,s,o;for(s=this.listeners,o=[],n=0,r=s.length;r>n;n++)e=s[n],o.push(function(){var n,r;n=e.events,r=[];for(t in n)i=n[t],r.push(e.element.removeEventListener(t,i,!1));return r}());return o},t.prototype.disable=function(){var e,t,i,n,r;for(this.clickableElements.forEach(function(e){return e.classList.remove("dz-clickable")}),this.removeEventListeners(),n=this.files,r=[],t=0,i=n.length;i>t;t++)e=n[t],r.push(this.cancelUpload(e));return r},t.prototype.enable=function(){return this.clickableElements.forEach(function(e){return e.classList.add("dz-clickable")}),this.setupEventListeners()},t.prototype.filesize=function(e){var t;return e>=1e11?(e/=1e11,t="TB"):e>=1e8?(e/=1e8,t="GB"):e>=1e5?(e/=1e5,t="MB"):e>=100?(e/=100,t="KB"):(e=10*e,t="b"),""+Math.round(e)/10+" "+t},t.prototype.drop=function(e){var t,i;e.dataTransfer&&(t=e.dataTransfer.files,this.emit("selectedfiles",t),t.length&&(i=e.dataTransfer.items,i&&i.length&&(null!=i[0].webkitGetAsEntry||null!=i[0].getAsEntry)?this.handleItems(i):this.handleFiles(t)))},t.prototype.handleFiles=function(e){var t,i,n,r;for(r=[],i=0,n=e.length;n>i;i++)t=e[i],r.push(this.addFile(t));return r},t.prototype.handleItems=function(e){var t,i,n,r;for(n=0,r=e.length;r>n;n++)i=e[n],null!=i.webkitGetAsEntry?(t=i.webkitGetAsEntry(),t.isFile?this.addFile(i.getAsFile()):t.isDirectory&&this.addDirectory(t,t.name)):this.addFile(i.getAsFile())},t.prototype.accept=function(e,i){return e.size>1024*1024*this.options.maxFilesize?i(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(e.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):t.isValidFile(e,this.options.acceptedFiles)?this.options.accept.call(this,e,i):i(this.options.dictInvalidFileType)},t.prototype.addExistingFile=function(e){e.upload={progress:0,total:e.size,bytesSent:0},this.files.push(e),e.status=t.ADDED,this.emit("addedfile",e),e.previewElement.id=e._id},t.prototype.addFile=function(e){var i=this;return e.upload={progress:0,total:e.size,bytesSent:0},this.files.push(e),e.status=t.ADDED,this.emit("addedfile",e),this.options.createImageThumbnails&&e.type.match(/image.*/)&&e.size<=1024*1024*this.options.maxThumbnailFilesize&&this.createThumbnail(e),this.accept(e,function(t){return t?(e.accepted=!1,i._errorProcessing([e],t)):(e.accepted=!0,i.enqueueFile(e))})},t.prototype.enqueueFiles=function(e){var t,i,n;for(i=0,n=e.length;n>i;i++)t=e[i],this.enqueueFile(t);return null},t.prototype.enqueueFile=function(e){var i=this;if(e.status!==t.ADDED)throw new Error("This file can't be queued because it has already been processed or was rejected.");return e.status=t.QUEUED,this.options.autoProcessQueue?setTimeout(function(){return i.processQueue()},1):void 0},t.prototype.addDirectory=function(e,t){var i,n,r=this;return i=e.createReader(),n=function(i){var n,s;for(n=0,s=i.length;s>n;n++)e=i[n],e.isFile?e.file(function(e){return r.options.ignoreHiddenFiles&&"."===e.name.substring(0,1)?void 0:(e.fullPath=""+t+"/"+e.name,r.addFile(e))}):e.isDirectory&&r.addDirectory(e,""+t+"/"+e.name)},i.readEntries(n,function(e){return"undefined"!=typeof console&&null!==console?"function"==typeof console.log?console.log(e):void 0:void 0})},t.prototype.removeFile=function(e){return e.status===t.UPLOADING&&this.cancelUpload(e),this.files=l(this.files,e),this.emit("removedfile",e),0===this.files.length?this.emit("reset"):void 0},t.prototype.removeAllFiles=function(e){var i,n,r,s;for(null==e&&(e=!1),s=this.files.slice(),n=0,r=s.length;r>n;n++)i=s[n],(i.status!==t.UPLOADING||e)&&this.removeFile(i);return null},t.prototype.createThumbnail=function(e){var t,i=this;return t=new FileReader,t.onload=function(){var n;return n=new Image,n.onload=function(){var t,r,s,o,l,a,p,u;return e.width=n.width,e.height=n.height,s=i.options.resize.call(i,e),null==s.trgWidth&&(s.trgWidth=i.options.thumbnailWidth),null==s.trgHeight&&(s.trgHeight=i.options.thumbnailHeight),t=document.createElement("canvas"),r=t.getContext("2d"),t.width=s.trgWidth,t.height=s.trgHeight,r.drawImage(n,null!=(l=s.srcX)?l:0,null!=(a=s.srcY)?a:0,s.srcWidth,s.srcHeight,null!=(p=s.trgX)?p:0,null!=(u=s.trgY)?u:0,s.trgWidth,s.trgHeight),o=t.toDataURL("image/png"),i.emit("thumbnail",e,o)},n.src=t.result},t.readAsDataURL(e)},t.prototype.processQueue=function(){var e,t,i,n;if(t=this.options.parallelUploads,i=this.getUploadingFiles().length,e=i,n=this.getQueuedFiles(),n.length>0){if(this.options.uploadMultiple)return this.processFiles(n.slice(0,t));for(;t>e;){if(!n.length)return;this.processFile(n.shift()),e++}}},t.prototype.processFile=function(e){return this.processFiles([e])},t.prototype.processFiles=function(e){var i,n,r;for(n=0,r=e.length;r>n;n++)i=e[n],i.processing=!0,i.status=t.UPLOADING,this.emit("processing",i);return this.options.uploadMultiple&&this.emit("processingmultiple",e),this.uploadFiles(e)},t.prototype._getFilesWithXhr=function(e){var t,i;return i=function(){var i,n,r,s;for(r=this.files,s=[],i=0,n=r.length;n>i;i++)t=r[i],t.xhr===e&&s.push(t);return s}.call(this)},t.prototype.cancelUpload=function(e){var i,n,r,s,o,l,a;if(e.status===t.UPLOADING){for(n=this._getFilesWithXhr(e.xhr),r=0,o=n.length;o>r;r++)i=n[r],i.status=t.CANCELED;for(e.xhr.abort(),s=0,l=n.length;l>s;s++)i=n[s],this.emit("canceled",i);this.options.uploadMultiple&&this.emit("canceledmultiple",n)}else((a=e.status)===t.ADDED||a===t.QUEUED)&&(e.status=t.CANCELED,this.emit("canceled",e),this.options.uploadMultiple&&this.emit("canceledmultiple",[e]));return this.options.autoProcessQueue?this.processQueue():void 0},t.prototype.uploadFile=function(e){return this.uploadFiles([e])},t.prototype.uploadFiles=function(e){var n,r,s,o,l,a,p,u,d,c,h,m,f,v,g,y,E,b,w,F,z,L,k,C,D,A,x,T=this;for(g=new XMLHttpRequest,y=0,F=e.length;F>y;y++)n=e[y],n.xhr=g;g.open(this.options.method,this.options.url,!0),g.withCredentials=!!this.options.withCredentials,m=null,s=function(){var t,i,r;for(r=[],t=0,i=e.length;i>t;t++)n=e[t],r.push(T._errorProcessing(e,m||T.options.dictResponseError.replace("{{statusCode}}",g.status),g));return r},f=function(t){var i,r,s,o,l,a,p,u,d;if(null!=t)for(r=100*t.loaded/t.total,s=0,a=e.length;a>s;s++)n=e[s],n.upload={progress:r,total:t.total,bytesSent:t.loaded};else{for(i=!0,r=100,o=0,p=e.length;p>o;o++)n=e[o],(100!==n.upload.progress||n.upload.bytesSent!==n.upload.total)&&(i=!1),n.upload.progress=r,n.upload.bytesSent=n.upload.total;if(i)return}for(d=[],l=0,u=e.length;u>l;l++)n=e[l],d.push(T.emit("uploadprogress",n,r,n.upload.bytesSent));return d},g.onload=function(i){var n;if(e[0].status!==t.CANCELED&&4===g.readyState){if(m=g.responseText,g.getResponseHeader("content-type")&&~g.getResponseHeader("content-type").indexOf("application/json"))try{m=JSON.parse(m)}catch(r){i=r,m="Invalid JSON response from server."}return f(),200<=(n=g.status)&&300>n?T._finished(e,m,i):s()}},g.onerror=function(){return e[0].status!==t.CANCELED?s():void 0},h=null!=(C=g.upload)?C:g,h.onprogress=f,l={Accept:"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"},this.options.headers&&i(l,this.options.headers);for(o in l)c=l[o],g.setRequestHeader(o,c);if(r=new FormData,this.options.params){D=this.options.params;for(d in D)v=D[d],r.append(d,v)}for(E=0,z=e.length;z>E;E++)n=e[E],this.emit("sending",n,g,r);if(this.options.uploadMultiple&&this.emit("sendingmultiple",e,g,r),"FORM"===this.element.tagName)for(A=this.element.querySelectorAll("input, textarea, select, button"),b=0,L=A.length;L>b;b++)a=A[b],p=a.getAttribute("name"),u=a.getAttribute("type"),(!u||"checkbox"!==(x=u.toLowerCase())&&"radio"!==x||a.checked)&&r.append(p,a.value);for(w=0,k=e.length;k>w;w++)n=e[w],r.append(""+this.options.paramName+(this.options.uploadMultiple?"[]":""),n,n.name);return g.send(r)},t.prototype._finished=function(e,i,n){var r,s,o;for(s=0,o=e.length;o>s;s++)r=e[s],r.status=t.SUCCESS,this.emit("success",r,i,n),this.emit("complete",r);return this.options.uploadMultiple&&(this.emit("successmultiple",e,i,n),this.emit("completemultiple",e)),this.options.autoProcessQueue?this.processQueue():void 0},t.prototype._errorProcessing=function(e,i,n){var r,s,o;for(s=0,o=e.length;o>s;s++)r=e[s],r.status=t.ERROR,this.emit("error",r,i,n),this.emit("complete",r);return this.options.uploadMultiple&&(this.emit("errormultiple",e,i,n),this.emit("completemultiple",e)),this.options.autoProcessQueue?this.processQueue():void 0},t}(n),e.version="3.6.1",e.options={},e.optionsForElement=function(t){return t.id?e.options[r(t.id)]:void 0},e.instances=[],e.forElement=function(e){if("string"==typeof e&&(e=document.querySelector(e)),null==(null!=e?e.dropzone:void 0))throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");return e.dropzone},e.autoDiscover=!0,e.discover=function(){var t,i,n,r,s,o;if(e.autoDiscover){for(document.querySelectorAll?n=document.querySelectorAll(".dropzone"):(n=[],t=function(e){var t,i,r,s;for(s=[],i=0,r=e.length;r>i;i++)t=e[i],/(^| )dropzone($| )/.test(t.className)?s.push(n.push(t)):s.push(void 0);return s},t(document.getElementsByTagName("div")),t(document.getElementsByTagName("form"))),o=[],r=0,s=n.length;s>r;r++)i=n[r],e.optionsForElement(i)!==!1?o.push(new e(i)):o.push(void 0);return o}},e.blacklistedBrowsers=[/opera.*Macintosh.*version\/12/i],e.isBrowserSupported=function(){var t,i,n,r,s;if(t=!0,window.File&&window.FileReader&&window.FileList&&window.Blob&&window.FormData&&document.querySelector)if("classList"in document.createElement("a"))for(s=e.blacklistedBrowsers,n=0,r=s.length;r>n;n++)i=s[n],i.test(navigator.userAgent)&&(t=!1);else t=!1;else t=!1;return t},l=function(e,t){var i,n,r,s;for(s=[],n=0,r=e.length;r>n;n++)i=e[n],i!==t&&s.push(i);return s},r=function(e){return e.replace(/[\-_](\w)/g,function(e){return e[1].toUpperCase()})},e.createElement=function(e){var t;return t=document.createElement("div"),t.innerHTML=e,t.childNodes[0]},e.elementInside=function(e,t){if(e===t)return!0;for(;e=e.parentNode;)if(e===t)return!0;return!1},e.getElement=function(e,t){var i;if("string"==typeof e?i=document.querySelector(e):null!=e.nodeType&&(i=e),null==i)throw new Error("Invalid `"+t+"` option provided. Please provide a CSS selector or a plain HTML element.");return i},e.getElements=function(e,t){var i,n,r,s,o,l,a,p;if(e instanceof Array){r=[];try{for(s=0,l=e.length;l>s;s++)n=e[s],r.push(this.getElement(n,t))}catch(u){i=u,r=null}}else if("string"==typeof e)for(r=[],p=document.querySelectorAll(e),o=0,a=p.length;a>o;o++)n=p[o],r.push(n);else null!=e.nodeType&&(r=[e]);if(null==r||!r.length)throw new Error("Invalid `"+t+"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");return r},e.isValidFile=function(e,t){var i,n,r,s,o;if(!t)return!0;for(t=t.split(","),n=e.type,i=n.replace(/\/.*$/,""),s=0,o=t.length;o>s;s++)if(r=t[s],r=r.trim(),"."===r.charAt(0)){if(-1!==e.name.indexOf(r,e.name.length-r.length))return!0}else if(/\/\*$/.test(r)){if(i===r.replace(/\/.*$/,""))return!0}else if(n===r)return!0;return!1},"undefined"!=typeof jQuery&&null!==jQuery&&(jQuery.fn.dropzone=function(t){return this.each(function(){return new e(this,t)})}),"undefined"!=typeof i&&null!==i?i.exports=e:window.Dropzone=e,e.ADDED="added",e.QUEUED="queued",e.ACCEPTED=e.QUEUED,e.UPLOADING="uploading",e.PROCESSING=e.UPLOADING,e.CANCELED="canceled",e.ERROR="error",e.SUCCESS="success",s=function(e,t){var i,n,r,s,o,l,a,p,u;if(r=!1,u=!0,n=e.document,p=n.documentElement,i=n.addEventListener?"addEventListener":"attachEvent",a=n.addEventListener?"removeEventListener":"detachEvent",l=n.addEventListener?"":"on",s=function(i){return"readystatechange"!==i.type||"complete"===n.readyState?(("load"===i.type?e:n)[a](l+i.type,s,!1),!r&&(r=!0)?t.call(e,i.type||i):void 0):void 0},o=function(){var e;try{p.doScroll("left")}catch(t){return e=t,setTimeout(o,50),void 0}return s("poll")},"complete"!==n.readyState){if(n.createEventObject&&p.doScroll){try{u=!e.frameElement}catch(d){}u&&o()}return n[i](l+"DOMContentLoaded",s,!1),n[i](l+"readystatechange",s,!1),e[i](l+"load",s,!1)}},s(window,e.discover)}.call(this)}),e.alias("component-emitter/index.js","dropzone/deps/emitter/index.js"),e.alias("component-emitter/index.js","emitter/index.js"),"object"==typeof exports?module.exports=e("dropzone"):"function"==typeof define&&define.amd?define(function(){return e("dropzone")}):this.Dropzone=e("dropzone")}(); \ No newline at end of file diff --git a/app/assets/javascripts/home.js.coffee b/app/assets/javascripts/home.js.coffee new file mode 100644 index 0000000..64c5fbe --- /dev/null +++ b/app/assets/javascripts/home.js.coffee @@ -0,0 +1,45 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ + +$(document).ready -> + + org_success = Dropzone.prototype.defaultOptions.success + org_removed = Dropzone.prototype.defaultOptions.removedfile + + Dropzone.options.assetsDropzone = { + addRemoveLinks: true, + paramName: 'image', + previewTemplate: '
Set Primary
', + removedfile: (file) -> + $.ajax({ + url: "/#{file._id}/remove_image", + method: 'post' + }) + org_removed(file) + , + success: (file, data) -> + index = $('#assets-dropzone').get(0).dropzone.files.indexOf(file) + $('#assets-dropzone').get(0).dropzone.files[index]["_id"] = data["asset_id"] + $('#assets-dropzone').get(0).dropzone.files[index].previewElement.id = data["asset_id"] + org_success(file) + } + Dropzone.autoDiscover = false + + $('#assets-dropzone').on 'click', '.dz-set-primary', -> + $.ajax({ + url: "/#{$(this).parent().attr('id')}/set_primary", + method: 'post' + }) + + if images? + $('#assets-dropzone').dropzone() + + $.each images, (i, image) -> + $('#assets-dropzone').get(0).dropzone.addExistingFile(image) + + primary_asset = images.filter((x) -> + x if x.is_primary is true + )[0] + + $('#'+primary_asset._id).addClass('dz-primary') if primary_asset? diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css.scss similarity index 77% rename from app/assets/stylesheets/application.css rename to app/assets/stylesheets/application.css.scss index 3192ec8..74c0488 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css.scss @@ -11,3 +11,12 @@ *= require_self *= require_tree . */ + +@import "bootstrap"; + +#assets-dropzone { + border-radius: 3px 3px 3px 3px; + box-shadow: 0 0 50px rgba(0, 0, 0, 0.13); + margin: 30px 0; + padding: 4px; +} diff --git a/app/assets/stylesheets/dropzone.css b/app/assets/stylesheets/dropzone.css new file mode 100644 index 0000000..4db9e11 --- /dev/null +++ b/app/assets/stylesheets/dropzone.css @@ -0,0 +1,457 @@ +/* The MIT License */ +.dropzone, +.dropzone *, +.dropzone-previews, +.dropzone-previews * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dropzone { + position: relative; + border: 1px solid rgba(0,0,0,0.08); + background: rgba(0,0,0,0.02); + padding: 1em; +} +.dropzone.dz-clickable { + cursor: pointer; +} +.dropzone.dz-clickable .dz-message, +.dropzone.dz-clickable .dz-message span { + cursor: pointer; +} +.dropzone.dz-clickable * { + cursor: default; +} +.dropzone .dz-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone.dz-drag-hover { + border-color: rgba(0,0,0,0.15); + background: rgba(0,0,0,0.04); +} +.dropzone.dz-started .dz-message { + display: none; +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + background: rgba(255,255,255,0.8); + position: relative; + display: inline-block; + margin: 17px; + vertical-align: top; + border: 1px solid #acacac; + padding: 6px 6px 6px 6px; +} +.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail], +.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] { + display: none; +} +.dropzone .dz-preview .dz-details, +.dropzone-previews .dz-preview .dz-details { + width: 100px; + height: 100px; + position: relative; + background: #ebebeb; + padding: 5px; + margin-bottom: 22px; +} +.dropzone .dz-preview .dz-details .dz-filename, +.dropzone-previews .dz-preview .dz-details .dz-filename { + overflow: hidden; + height: 100%; +} +.dropzone .dz-preview .dz-details img, +.dropzone-previews .dz-preview .dz-details img { + position: absolute; + top: 0; + left: 0; + width: 100px; + height: 100px; +} +.dropzone .dz-preview .dz-details .dz-size, +.dropzone-previews .dz-preview .dz-details .dz-size { + position: absolute; + bottom: -28px; + left: 3px; + height: 28px; + line-height: 28px; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + display: block; +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + display: block; +} +.dropzone .dz-preview:hover .dz-details img, +.dropzone-previews .dz-preview:hover .dz-details img { + display: none; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark, +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + display: none; + position: absolute; + width: 40px; + height: 40px; + font-size: 30px; + text-align: center; + right: -10px; + top: -10px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + color: #8cc657; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + color: #ee162d; +} +.dropzone .dz-preview .dz-progress, +.dropzone-previews .dz-preview .dz-progress { + position: absolute; + top: 100px; + left: 6px; + right: 6px; + height: 6px; + background: #d7d7d7; + display: none; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 0%; + background-color: #8cc657; +} +.dropzone .dz-preview.dz-processing .dz-progress, +.dropzone-previews .dz-preview.dz-processing .dz-progress { + display: block; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: none; + position: absolute; + top: -5px; + left: -20px; + background: rgba(245,245,245,0.8); + padding: 8px 10px; + color: #800; + min-width: 140px; + max-width: 500px; + z-index: 500; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + display: block; +} +.dropzone { + border: 1px solid rgba(0,0,0,0.03); + min-height: 360px; + -webkit-border-radius: 3px; + border-radius: 3px; + background: rgba(0,0,0,0.03); + padding: 23px; +} +.dropzone .dz-default.dz-message { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transition: opacity 0.3s ease-in-out; + -moz-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + -ms-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; + background-image: url("/assets/spritemap.png"); + background-repeat: no-repeat; + background-position: 0 0; + position: absolute; + width: 428px; + height: 123px; + margin-left: -214px; + margin-top: -61.5px; + top: 50%; + left: 50%; +} +@media all and (-webkit-min-device-pixel-ratio: 1.5) { + .dropzone .dz-default.dz-message { + background-image: url("/assets/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-default.dz-message span { + display: none; +} +.dropzone.dz-square .dz-default.dz-message { + background-position: 0 -123px; + width: 268px; + margin-left: -134px; + height: 174px; + margin-top: -87px; +} +.dropzone.dz-drag-hover .dz-message { + opacity: 0.15; + filter: alpha(opacity=15); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=15)"; +} +.dropzone.dz-started .dz-message { + display: block; + opacity: 0; + filter: alpha(opacity=0); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + -webkit-box-shadow: 1px 1px 4px rgba(0,0,0,0.16); + box-shadow: 1px 1px 4px rgba(0,0,0,0.16); + font-size: 14px; +} +.dropzone .dz-preview.dz-image-preview:hover .dz-details img, +.dropzone-previews .dz-preview.dz-image-preview:hover .dz-details img { + display: block; + opacity: 0.1; + filter: alpha(opacity=10); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone .dz-preview.dz-error .dz-progress .dz-upload, +.dropzone-previews .dz-preview.dz-error .dz-progress .dz-upload { + background: #ee1e2d; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark, +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + display: block; + opacity: 0; + filter: alpha(opacity=0); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out; + background-image: url("/assets/spritemap.png"); + background-repeat: no-repeat; +} +@media all and (-webkit-min-device-pixel-ratio: 1.5) { + .dropzone .dz-preview .dz-error-mark, + .dropzone-previews .dz-preview .dz-error-mark, + .dropzone .dz-preview .dz-success-mark, + .dropzone-previews .dz-preview .dz-success-mark { + background-image: url("/assets/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-preview .dz-error-mark span, +.dropzone-previews .dz-preview .dz-error-mark span, +.dropzone .dz-preview .dz-success-mark span, +.dropzone-previews .dz-preview .dz-success-mark span { + display: none; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + background-position: -268px -123px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + background-position: -268px -163px; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + -webkit-animation: loading 0.4s linear infinite; + -moz-animation: loading 0.4s linear infinite; + -o-animation: loading 0.4s linear infinite; + -ms-animation: loading 0.4s linear infinite; + animation: loading 0.4s linear infinite; + -webkit-transition: width 0.3s ease-in-out; + -moz-transition: width 0.3s ease-in-out; + -o-transition: width 0.3s ease-in-out; + -ms-transition: width 0.3s ease-in-out; + transition: width 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px; + position: absolute; + top: 0; + left: 0; + width: 0%; + height: 100%; + background-image: url("/assets/spritemap.png"); + background-repeat: repeat-x; + background-position: 0px -400px; +} +@media all and (-webkit-min-device-pixel-ratio: 1.5) { + .dropzone .dz-preview .dz-progress .dz-upload, + .dropzone-previews .dz-preview .dz-progress .dz-upload { + background-image: url("/assets/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-preview.dz-success .dz-progress, +.dropzone-previews .dz-preview.dz-success .dz-progress { + display: block; + opacity: 0; + filter: alpha(opacity=0); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: block; + opacity: 0; + filter: alpha(opacity=0); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + -webkit-transition: opacity 0.3s ease-in-out; + -moz-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + -ms-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone a.dz-remove, +.dropzone-previews a.dz-remove { + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fafafa), color-stop(1, #eee)); + background-image: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%); + background-image: -moz-linear-gradient(top, #fafafa 0%, #eee 100%); + background-image: -o-linear-gradient(top, #fafafa 0%, #eee 100%); + background-image: -ms-linear-gradient(top, #fafafa 0%, #eee 100%); + background-image: linear-gradient(top, #fafafa 0%, #eee 100%); + -webkit-border-radius: 2px; + border-radius: 2px; + border: 1px solid #eee; + text-decoration: none; + display: block; + padding: 4px 5px; + text-align: center; + color: #aaa; + margin-top: 26px; +} +.dropzone a.dz-remove:hover, +.dropzone-previews a.dz-remove:hover { + color: #666; +} +@-moz-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-webkit-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-o-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-ms-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} + +.dropzone .dz-preview, .dropzone-previews .dz-preview { + z-index: 1; +} + +.dz-primary .dz-primary-mark { + display: block; +} + +.dz-primary .dz-primary-mark:after { + background-color: #F41D3D; + border: 1px solid #F41D3D; + border-radius: 4px 0 4px 0; + color: white; + content: "Primary"; + font-size: 12px; + font-weight: bold; + left: -1px; + padding: 4px; + position: absolute; + top: -1px; +} + +.dz-primary-mark { + display: none; +} + +.dz-set-primary { + background-image: -moz-linear-gradient(center top , #FAFAFA 0%, #EEEEEE 100%); + border: 1px solid #EEEEEE; + border-radius: 2px 2px 2px 2px; + color: #AAAAAA; + display: block; + margin-top: 26px; + padding: 4px 5px; + text-align: center; + text-decoration: none; +} + +.dz-set-primary:hover { + text-decoration: none; + color: #666; +} + +a.dz-remove { + margin-top: 5px !important; +} diff --git a/app/assets/stylesheets/home.css.scss b/app/assets/stylesheets/home.css.scss new file mode 100644 index 0000000..f0ddc68 --- /dev/null +++ b/app/assets/stylesheets/home.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the home controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 0000000..592e958 --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,25 @@ +class HomeController < ApplicationController + skip_before_filter :protect_from_forgery, only: :upload + + def index + @assets = Asset.all + end + + def upload + asset = Asset.new(image: params[:image], file_name: params[:image].original_filename) + asset.save! + render json: {asset_id: asset.id} + end + + def remove_image + Asset.find(params[:asset_id]).destroy + render nothing: true + end + + def set_primary + Asset.primary.update_all(is_primary: false) + + asset = Asset.find(params[:asset_id]) + asset.update_attributes(is_primary: true) + end +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 0000000..23de56a --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/app/models/asset.rb b/app/models/asset.rb new file mode 100644 index 0000000..9aa46e0 --- /dev/null +++ b/app/models/asset.rb @@ -0,0 +1,40 @@ +class Asset + include Mongoid::Document + + mount_uploader :image, AssetUploader + + field :file_name + field :file_size + field :is_primary, type: Boolean, default: false + + scope :primary, where(is_primary: true) + + def name + self.file_name + end + + def size + self.file_size + end + + def remote_url + self.image.url + end + + def type + "image/png" + end + + def as_json(options= {}) + options.merge!(only: [:_id, :is_primary], methods: [:name, :size, :remote_url, :type]) + super + end + + private + + def update_asset_attributes + if image.present? && image_changed? + self.file_size = image.file.size + end + end +end diff --git a/app/uploaders/asset_uploader.rb b/app/uploaders/asset_uploader.rb new file mode 100644 index 0000000..4c44f7a --- /dev/null +++ b/app/uploaders/asset_uploader.rb @@ -0,0 +1,56 @@ +# encoding: utf-8 + +class AssetUploader < CarrierWave::Uploader::Base + include Cloudinary::CarrierWave + + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + # include CarrierWave::MiniMagick + + # Choose what kind of storage to use for this uploader: + #storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + #def store_dir + # "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + #end + + def public_id + "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # # For Rails 3.1+ asset pipeline compatibility: + # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) + # + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + # version :thumb do + # process :scale => [50, 50] + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w(jpg jpeg gif png) + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml new file mode 100644 index 0000000..0c92bcd --- /dev/null +++ b/app/views/home/index.html.haml @@ -0,0 +1,8 @@ +.span12 + #images + #my-zone + %h3 My Images + %form{action: upload_path, class: "dropzone#{' dz-started' if @assets.count > 0}", id: 'assets-dropzone'} + +:coffeescript + @images = #{@assets.to_json} diff --git a/app/views/home/set_primary.js.haml b/app/views/home/set_primary.js.haml new file mode 100644 index 0000000..64fbd54 --- /dev/null +++ b/app/views/home/set_primary.js.haml @@ -0,0 +1,2 @@ +$('#assets-dropzone').find('.dz-primary').removeClass('dz-primary') +$('#'+"#{params[:asset_id]}").addClass('dz-primary') diff --git a/config/cloudinary.yml b/config/cloudinary.yml new file mode 100644 index 0000000..8a59ff8 --- /dev/null +++ b/config/cloudinary.yml @@ -0,0 +1,19 @@ +--- +development: + cloud_name: dt8tllzzd + api_key: '992573219328542' + api_secret: vweQ0Z_yIT5DHbrbkx8fMFIKusk + enhance_image_tag: true + static_image_support: false +production: + cloud_name: dt8tllzzd + api_key: '992573219328542' + api_secret: vweQ0Z_yIT5DHbrbkx8fMFIKusk + enhance_image_tag: true + static_image_support: true +test: + cloud_name: dt8tllzzd + api_key: '992573219328542' + api_secret: vweQ0Z_yIT5DHbrbkx8fMFIKusk + enhance_image_tag: true + static_image_support: false diff --git a/config/routes.rb b/config/routes.rb index 3e77e84..578815c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,8 @@ DropzoneRails::Application.routes.draw do + + match 'upload' => "home#upload", as: :upload + match '/:asset_id/set_primary' => "home#set_primary", as: :set_primary + match '/:asset_id/remove_image' => "home#remove_image", as: :remove_image # The priority is based upon order of creation: # first created -> highest priority. @@ -48,7 +52,7 @@ # You can have the root of your site routed with "root" # just remember to delete public/index.html. - # root :to => 'welcome#index' + root :to => 'home#index' # See how all your routes lay out with "rake routes" diff --git a/public/index.html b/public/index.html deleted file mode 100644 index a1d5099..0000000 --- a/public/index.html +++ /dev/null @@ -1,241 +0,0 @@ - - - - Ruby on Rails: Welcome aboard - - - - -
- - -
- - - - -
-

Getting started

-

Here’s how to get rolling:

- -
    -
  1. -

    Use rails generate to create your models and controllers

    -

    To see all available options, run it without parameters.

    -
  2. - -
  3. -

    Set up a default route and remove public/index.html

    -

    Routes are set up in config/routes.rb.

    -
  4. - -
  5. -

    Create your database

    -

    Run rake db:create to create your database. If you're not using SQLite (the default), edit config/database.yml with your username and password.

    -
  6. -
-
-
- - -
- - diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb new file mode 100644 index 0000000..9d48b6a --- /dev/null +++ b/spec/controllers/home_controller_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe HomeController do + +end diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb new file mode 100644 index 0000000..f529425 --- /dev/null +++ b/spec/helpers/home_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the HomeHelper. For example: +# +# describe HomeHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +describe HomeHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/asset_spec.rb b/spec/models/asset_spec.rb new file mode 100644 index 0000000..fd1e183 --- /dev/null +++ b/spec/models/asset_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Asset do + pending "add some examples to (or delete) #{__FILE__}" +end