mirror of
https://github.com/danbee/danbarberphoto
synced 2025-03-04 08:49:07 +00:00
Removed localised paperclip plugin and added the gem. Added :preview
image size to photo attachment for admin interface.
This commit is contained in:
parent
67e7f0eb12
commit
8621da4d3b
4
Gemfile
4
Gemfile
@ -32,8 +32,10 @@ gem 'sqlite3-ruby', :require => 'sqlite3'
|
||||
gem "exception_notification", :git => "git://github.com/rails/exception_notification", :require => 'exception_notifier'
|
||||
gem 'pg'
|
||||
gem 'meta_where'
|
||||
gem 'typus', :git => 'git://github.com/fesplugas/typus.git'
|
||||
gem 'typus', :git => 'https://github.com/fesplugas/typus.git'
|
||||
gem 'mini_exiftool'
|
||||
gem 'will_paginate', :git => 'http://github.com/mislav/will_paginate.git', :branch => 'rails3'
|
||||
gem 'rdiscount'
|
||||
gem 'paperclip'
|
||||
gem 'acts_as_markup'
|
||||
gem 'jquery-rails', '>= 0.2.6'
|
||||
|
||||
41
Gemfile.lock
41
Gemfile.lock
@ -1,9 +1,3 @@
|
||||
GIT
|
||||
remote: git://github.com/fesplugas/typus.git
|
||||
revision: e0ce90d39989a82662e6d8c6c6c091860b5d9e51
|
||||
specs:
|
||||
typus (1.0.0.pre8)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/rails/exception_notification
|
||||
revision: 192a49a02d63d28b23ed41cebadfedd490929cf1
|
||||
@ -17,6 +11,14 @@ GIT
|
||||
specs:
|
||||
will_paginate (3.0.pre3)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/fesplugas/typus.git
|
||||
revision: d03b28cc20c9b5cb82a34065d14348d491018b27
|
||||
specs:
|
||||
typus (3.0.3)
|
||||
render_inheritable
|
||||
will_paginate (~> 3.0.pre2)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
@ -59,18 +61,25 @@ GEM
|
||||
builder (2.1.2)
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
i18n (0.4.1)
|
||||
mail (2.2.7)
|
||||
i18n (0.4.2)
|
||||
jquery-rails (0.2.6)
|
||||
rails (~> 3.0)
|
||||
thor (~> 0.14.4)
|
||||
mail (2.2.12)
|
||||
activesupport (>= 2.3.6)
|
||||
mime-types
|
||||
treetop (>= 1.4.5)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
meta_where (0.9.6)
|
||||
activerecord (~> 3.0.0)
|
||||
activesupport (~> 3.0.0)
|
||||
arel (~> 1.0.1)
|
||||
mime-types (1.16)
|
||||
mini_exiftool (1.0.1)
|
||||
pg (0.9.0)
|
||||
paperclip (2.3.8)
|
||||
activerecord
|
||||
activesupport
|
||||
pg (0.10.0)
|
||||
polyglot (0.3.1)
|
||||
rack (1.2.1)
|
||||
rack-mount (0.6.13)
|
||||
@ -92,9 +101,11 @@ GEM
|
||||
thor (~> 0.14.0)
|
||||
rake (0.8.7)
|
||||
rdiscount (1.6.5)
|
||||
sqlite3-ruby (1.3.1)
|
||||
thor (0.14.3)
|
||||
treetop (1.4.8)
|
||||
render_inheritable (1.0.0)
|
||||
rails (~> 3.0)
|
||||
sqlite3-ruby (1.3.2)
|
||||
thor (0.14.6)
|
||||
treetop (1.4.9)
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.23)
|
||||
wikitext (2.1.1)
|
||||
@ -105,8 +116,10 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
acts_as_markup
|
||||
exception_notification!
|
||||
jquery-rails (>= 0.2.6)
|
||||
meta_where
|
||||
mini_exiftool
|
||||
paperclip
|
||||
pg
|
||||
rails (= 3.0.0)
|
||||
rdiscount
|
||||
|
||||
@ -3,7 +3,8 @@ require 'mini_exiftool'
|
||||
class Photo < ActiveRecord::Base
|
||||
has_and_belongs_to_many :categories
|
||||
|
||||
has_attached_file :photo, :styles => { :size17 => "476x476#",
|
||||
has_attached_file :photo, :styles => { :preview => "600x600",
|
||||
:size17 => "476x476#",
|
||||
:size11 => "308x308#",
|
||||
:size8 => "224x224#",
|
||||
:size5 => "140x140#",
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
Typus.setup do |config|
|
||||
|
||||
# Application name.
|
||||
config.admin_title = "Dan Barber Photography"
|
||||
config.admin_title = "danbarberphoto"
|
||||
# config.admin_sub_title = ""
|
||||
|
||||
# When mailer_sender is set, password recover is enabled. This email
|
||||
# address will be used in Admin::Mailer.
|
||||
# config.mailer_sender = "admin@example.com"
|
||||
|
||||
# Define file attachment settings.
|
||||
# config.file_preview = :typus_preview
|
||||
# config.file_thumbnail = :typus_thumbnail
|
||||
# Define paperclip attachment styles.
|
||||
# config.file_preview = :medium
|
||||
# config.file_thumbnail = :thumb
|
||||
config.file_preview = :preview
|
||||
config.file_thumbnail = :size2
|
||||
|
||||
# Authentication: +:none+, +:http_basic+
|
||||
# Run `rails g typus:migration` if you need an advanced authentication system.
|
||||
@ -20,7 +22,10 @@ Typus.setup do |config|
|
||||
# config.username = "admin"
|
||||
# config.password = "columbia"
|
||||
|
||||
# Define available languages on the admin interface.
|
||||
# config.available_locales = [:en]
|
||||
# Pagination options:
|
||||
# These options are passed to `will_paginate`. You can see the available
|
||||
# options in the plugin source. (https://github.com/mislav/will_paginate/blob/rails3/lib/will_paginate/view_helpers.rb)
|
||||
# config.pagination = { :previous_label => "← " + Typus::I18n.t("Previous"),
|
||||
# :next_label => Typus::I18n.t("Next") + " →" }
|
||||
|
||||
end
|
||||
|
||||
@ -15,9 +15,6 @@ Typus::Resources.setup do |config|
|
||||
# Defines minute_step.
|
||||
# config.minute_step = 5
|
||||
|
||||
# Defines nil.
|
||||
# config.human_nil = "nil"
|
||||
|
||||
# Defines only_user_items.
|
||||
# config.only_user_items = false
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ common settings.
|
||||
application: Application
|
||||
description: Some text to describe the model
|
||||
options:
|
||||
action_after_save: :index
|
||||
action_after_save: index
|
||||
default_action_on_item: show
|
||||
end_year: 2015
|
||||
form_rows: 25
|
||||
|
||||
@ -14,7 +14,7 @@ Category:
|
||||
|
||||
Photo:
|
||||
fields:
|
||||
default: title, sort, enabled, featured
|
||||
default: photo, title, enabled, featured, views
|
||||
form: photo, title, description, flickr_url, enabled, featured, sort
|
||||
order_by:
|
||||
relationships: categories
|
||||
|
||||
@ -1,6 +1,2 @@
|
||||
// Place your application-specific JavaScript functions and classes for
|
||||
// the admin panel here.
|
||||
|
||||
$(function() {
|
||||
$("#quicksearch").searchField();
|
||||
});
|
||||
|
||||
167
public/admin/javascripts/jquery-1.4.4.min.js
vendored
Normal file
167
public/admin/javascripts/jquery-1.4.4.min.js
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
/*!
|
||||
* jQuery JavaScript Library v1.4.4
|
||||
* http://jquery.com/
|
||||
*
|
||||
* Copyright 2010, John Resig
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* Includes Sizzle.js
|
||||
* http://sizzlejs.com/
|
||||
* Copyright 2010, The Dojo Foundation
|
||||
* Released under the MIT, BSD, and GPL Licenses.
|
||||
*
|
||||
* Date: Thu Nov 11 19:04:53 2010 -0500
|
||||
*/
|
||||
(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
|
||||
h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
|
||||
h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
|
||||
"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
|
||||
e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
|
||||
"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
|
||||
a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
|
||||
C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
|
||||
s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
|
||||
j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
|
||||
toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
|
||||
-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
|
||||
if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
|
||||
if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
|
||||
b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
|
||||
!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
|
||||
l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
|
||||
z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
|
||||
s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
|
||||
s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
|
||||
[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
|
||||
false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
|
||||
k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
|
||||
scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
|
||||
false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
|
||||
1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
|
||||
"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
|
||||
c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
|
||||
else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
|
||||
a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
|
||||
c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
|
||||
a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
|
||||
colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
|
||||
1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
|
||||
l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
|
||||
"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
|
||||
if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
|
||||
a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
|
||||
attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
|
||||
b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
|
||||
c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
|
||||
arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
|
||||
d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
|
||||
c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
|
||||
w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
|
||||
8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
|
||||
"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
|
||||
d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
||||
fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
|
||||
Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
|
||||
c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
|
||||
var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
|
||||
"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
|
||||
xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
|
||||
B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
|
||||
"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
|
||||
0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
|
||||
a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
|
||||
1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
|
||||
"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
|
||||
c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
|
||||
(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
|
||||
[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
|
||||
break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
|
||||
q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
|
||||
l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
|
||||
return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
|
||||
B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
|
||||
POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
|
||||
i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
|
||||
i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
|
||||
"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
|
||||
m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
|
||||
true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
|
||||
g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
|
||||
0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
|
||||
"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
|
||||
i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
|
||||
if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
|
||||
g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
|
||||
for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
|
||||
i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
|
||||
n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
|
||||
function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
|
||||
p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
|
||||
t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
|
||||
function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
|
||||
c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
|
||||
not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
|
||||
h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
|
||||
c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
|
||||
2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
|
||||
b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
|
||||
e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
|
||||
"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
|
||||
else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
|
||||
c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
|
||||
b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
|
||||
this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
|
||||
prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
|
||||
b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
|
||||
1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
|
||||
d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
|
||||
jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
|
||||
zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
|
||||
h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
|
||||
if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
|
||||
d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
|
||||
e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||
ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
|
||||
"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
|
||||
!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
|
||||
getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
|
||||
script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
|
||||
!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
|
||||
false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
|
||||
A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
|
||||
b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
|
||||
c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
|
||||
c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
|
||||
encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
|
||||
[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
|
||||
e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
|
||||
if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
|
||||
3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
|
||||
d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
|
||||
d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
|
||||
"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
|
||||
1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
|
||||
d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
|
||||
Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
|
||||
var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
|
||||
this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
|
||||
this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
|
||||
c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
|
||||
b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
|
||||
h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
|
||||
for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
|
||||
parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
|
||||
height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
|
||||
f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
|
||||
"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
|
||||
e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
|
||||
c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
|
||||
c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
|
||||
b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);
|
||||
16
public/admin/javascripts/jquery.application.js
Normal file
16
public/admin/javascripts/jquery.application.js
Normal file
@ -0,0 +1,16 @@
|
||||
$(document).ready(function() {
|
||||
$("#quicksearch").searchField();
|
||||
$('.resource :input', document.myForm).bind("change", function() { setConfirmUnload(true); });
|
||||
$("a.fancybox").fancybox({
|
||||
'titlePosition': 'over',
|
||||
'type': 'image'
|
||||
});
|
||||
});
|
||||
|
||||
function setConfirmUnload(on) {
|
||||
window.onbeforeunload = (on) ? unloadMessage : null;
|
||||
}
|
||||
|
||||
function unloadMessage() {
|
||||
return "You have entered new data on this page. If you navigate away from this page without first saving your data, the changes will be lost.";
|
||||
}
|
||||
@ -1,3 +1,12 @@
|
||||
/*
|
||||
* jquery-ujs
|
||||
*
|
||||
* http://github.com/rails/jquery-ujs/blob/master/src/rails.js
|
||||
*
|
||||
* This rails.js file supports jQuery 1.4.3 and 1.4.4 .
|
||||
*
|
||||
*/
|
||||
|
||||
jQuery(function ($) {
|
||||
var csrf_token = $('meta[name=csrf-token]').attr('content'),
|
||||
csrf_param = $('meta[name=csrf-param]').attr('content');
|
||||
@ -19,26 +28,34 @@ jQuery(function ($) {
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles execution of remote calls firing overridable events along the way
|
||||
* Handles execution of remote calls. Provides following callbacks:
|
||||
*
|
||||
* - ajax:beforeSend - is executed before firing ajax call
|
||||
* - ajax:success - is executed when status is success
|
||||
* - ajax:complete - is executed when the request finishes, whether in failure or success.
|
||||
* - ajax:error - is execute in case of error
|
||||
*/
|
||||
callRemote: function () {
|
||||
var el = this,
|
||||
method = el.attr('method') || el.attr('data-method') || 'GET',
|
||||
url = el.attr('action') || el.attr('href'),
|
||||
dataType = el.attr('data-type') || 'script';
|
||||
dataType = el.attr('data-type') || ($.ajaxSettings && $.ajaxSettings.dataType);
|
||||
|
||||
if (url === undefined) {
|
||||
throw "No URL specified for remote call (action or href must be present).";
|
||||
throw "No URL specified for remote call (action or href must be present).";
|
||||
} else {
|
||||
if (el.triggerAndReturn('ajax:before')) {
|
||||
var data = el.is('form') ? el.serializeArray() : [];
|
||||
var $this = $(this), data = el.is('form') ? el.serializeArray() : [];
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
data: data,
|
||||
dataType: dataType,
|
||||
type: method.toUpperCase(),
|
||||
beforeSend: function (xhr) {
|
||||
el.trigger('ajax:loading', xhr);
|
||||
xhr.setRequestHeader("Accept", "text/javascript");
|
||||
if ($this.triggerHandler('ajax:beforeSend') === false) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
success: function (data, status, xhr) {
|
||||
el.trigger('ajax:success', [data, status, xhr]);
|
||||
@ -47,12 +64,9 @@ jQuery(function ($) {
|
||||
el.trigger('ajax:complete', xhr);
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
el.trigger('ajax:failure', [xhr, status, error]);
|
||||
el.trigger('ajax:error', [xhr, status, error]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
el.trigger('ajax:after');
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -60,7 +74,8 @@ jQuery(function ($) {
|
||||
/**
|
||||
* confirmation handler
|
||||
*/
|
||||
$('a[data-confirm],input[data-confirm]').live('click', function () {
|
||||
|
||||
$('body').delegate('a[data-confirm], button[data-confirm], input[data-confirm]', 'click.rails', function () {
|
||||
var el = $(this);
|
||||
if (el.triggerAndReturn('confirm')) {
|
||||
if (!confirm(el.attr('data-confirm'))) {
|
||||
@ -70,28 +85,34 @@ jQuery(function ($) {
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* remote handlers
|
||||
*/
|
||||
$('form[data-remote]').live('submit', function (e) {
|
||||
$('form[data-remote]').live('submit.rails', function (e) {
|
||||
$(this).callRemote();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$('a[data-remote],input[data-remote]').live('click', function (e) {
|
||||
$('a[data-remote],input[data-remote]').live('click.rails', function (e) {
|
||||
$(this).callRemote();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$('a[data-method]:not([data-remote])').live('click', function (e){
|
||||
/**
|
||||
* <%= link_to "Delete", user_path(@user), :method => :delete, :confirm => "Are you sure?" %>
|
||||
*
|
||||
* <a href="/users/5" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Delete</a>
|
||||
*/
|
||||
$('a[data-method]:not([data-remote])').live('click.rails', function (e){
|
||||
var link = $(this),
|
||||
href = link.attr('href'),
|
||||
method = link.attr('data-method'),
|
||||
form = $('<form method="post" action="'+href+'"></form>'),
|
||||
metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';
|
||||
|
||||
if (csrf_param != null && csrf_token != null) {
|
||||
metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
|
||||
if (csrf_param !== undefined && csrf_token !== undefined) {
|
||||
metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
|
||||
}
|
||||
|
||||
form.hide()
|
||||
@ -105,9 +126,9 @@ jQuery(function ($) {
|
||||
/**
|
||||
* disable-with handlers
|
||||
*/
|
||||
var disable_with_input_selector = 'input[data-disable-with]';
|
||||
var disable_with_form_remote_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';
|
||||
var disable_with_form_not_remote_selector = 'form:not([data-remote]):has(' + disable_with_input_selector + ')';
|
||||
var disable_with_input_selector = 'input[data-disable-with]',
|
||||
disable_with_form_remote_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')',
|
||||
disable_with_form_not_remote_selector = 'form:not([data-remote]):has(' + disable_with_input_selector + ')';
|
||||
|
||||
var disable_with_input_function = function () {
|
||||
$(this).find(disable_with_input_selector).each(function () {
|
||||
@ -118,10 +139,10 @@ jQuery(function ($) {
|
||||
});
|
||||
};
|
||||
|
||||
$(disable_with_form_remote_selector).live('ajax:before', disable_with_input_function);
|
||||
$(disable_with_form_not_remote_selector).live('submit', disable_with_input_function);
|
||||
$(disable_with_form_remote_selector).live('ajax:before.rails', disable_with_input_function);
|
||||
$(disable_with_form_not_remote_selector).live('submit.rails', disable_with_input_function);
|
||||
|
||||
$(disable_with_form_remote_selector).live('ajax:complete', function () {
|
||||
$(disable_with_form_remote_selector).live('ajax:complete.rails', function () {
|
||||
$(this).find(disable_with_input_selector).each(function () {
|
||||
var input = $(this);
|
||||
input.removeAttr('disabled')
|
||||
@ -129,4 +150,11 @@ jQuery(function ($) {
|
||||
});
|
||||
});
|
||||
|
||||
var jqueryVersion = $().jquery;
|
||||
|
||||
if (!( (jqueryVersion === '1.4.3') || (jqueryVersion === '1.4.4'))){
|
||||
alert('This rails.js does not support the jQuery version you are using. Please read documentation.');
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
@ -24,12 +24,7 @@ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abb
|
||||
|
||||
/* @group Defaults */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
html, body {}
|
||||
|
||||
body {
|
||||
font-family: "Lucida Grande", Sans-serif;
|
||||
@ -61,7 +56,7 @@ li { color: #777; }
|
||||
a,
|
||||
a:visited,
|
||||
a:link { color: #000; font-weight: normal; }
|
||||
a:hover { color: #333; text-decoration: underline; }
|
||||
a:hover { color: #333; text-decoration: underline!important; }
|
||||
|
||||
/* @end */
|
||||
|
||||
@ -109,6 +104,7 @@ a:hover { color: #333; text-decoration: underline; }
|
||||
/* @group Content */
|
||||
|
||||
#content { margin: 0 0 0 20em; }
|
||||
#content.headless { margin: 1em; }
|
||||
|
||||
#content h2 { font-size: 1.5em; margin: 0.5em 0; }
|
||||
#content h2 small { font-size: 0.75em; }
|
||||
@ -159,21 +155,13 @@ a:hover { color: #333; text-decoration: underline; }
|
||||
#sidebar ul li { padding: 0.25em 1em; }
|
||||
|
||||
#sidebar a { text-decoration: none; }
|
||||
#sidebar a:hover { text-decoration: underline; }
|
||||
#sidebar li a:hover { text-decoration: underline; }
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Footer */
|
||||
|
||||
#footer_wrapper {
|
||||
bottom: 0;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: -100;
|
||||
}
|
||||
|
||||
#footer { font-size: 0.9em; padding: 20px; }
|
||||
#footer_wrapper { display: none; }
|
||||
|
||||
/* @end */
|
||||
|
||||
@ -182,7 +170,8 @@ a:hover { color: #333; text-decoration: underline; }
|
||||
fieldset { margin: 0; padding: 0; }
|
||||
fieldset ol { margin: 0!important; }
|
||||
fieldset ol li { list-style: none!important; margin: 1em 0!important; }
|
||||
fieldset small { font-size: 0.9em; font-weight: normal; }
|
||||
fieldset small { font-size: 0.9em; font-weight: normal; margin: 0 0 0 0.25em; }
|
||||
fieldset small a { text-decoration: none; }
|
||||
|
||||
fieldset.inputs { }
|
||||
|
||||
@ -194,7 +183,7 @@ fieldset.inputs { }
|
||||
}
|
||||
|
||||
fieldset.inputs input[type='text']:focus,
|
||||
fieldset.inputs input[type='password']:focus, {
|
||||
fieldset.inputs input[type='password']:focus {
|
||||
background: #FFFCE1;
|
||||
}
|
||||
|
||||
@ -244,12 +233,12 @@ fieldset.buttons { }
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
#account #box h1 { margin: 0.5em 0 0.5em 0; }
|
||||
#account #box h1 { margin: 0.5em 0; }
|
||||
#account #box ul { margin: 1.5em 0 0.5em 0; }
|
||||
#account #box li { margin: 1em 0; }
|
||||
|
||||
#account #box input.text { font-size: 2em; padding: 0.25em; width: 17.25em; }
|
||||
#account #box input.button { margin: 0.5em 0 0 0; }
|
||||
#account #box input.button { margin: 0.5em 1em 0 0; }
|
||||
|
||||
#account #footer { font-size: 0.9em; line-height: 1.8em; text-align: center; }
|
||||
#account #footer a { font-weight: bold; }
|
||||
@ -258,15 +247,23 @@ fieldset.buttons { }
|
||||
|
||||
/* @group Pagination */
|
||||
|
||||
#pagination { margin: 1.5em auto; text-align: center; }
|
||||
.pagination {
|
||||
border-top: 1px solid #D3D3D3;
|
||||
margin: 1.5em auto;
|
||||
padding: 1em 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#pagination a { padding: 3px 5px; text-decoration: none; }
|
||||
#pagination a:hover { background: #000; color: #FFF; }
|
||||
.pagination em { font-style: normal!important; }
|
||||
.pagination em,
|
||||
.pagination a { padding: 3px 5px; text-decoration: none; }
|
||||
.pagination a:hover,
|
||||
.pagination em { background: #000; color: #FFF; }
|
||||
|
||||
#pagination span.disabled { color: #D3D3D3; margin: 2px; padding: 2px 3px; }
|
||||
.pagination span.disabled { color: #D3D3D3; margin: 2px; padding: 2px 3px; }
|
||||
|
||||
#pagination .left { float: left; }
|
||||
#pagination .right { float: right; }
|
||||
.pagination .previous_page { float: left; }
|
||||
.pagination .next_page { float: right; }
|
||||
|
||||
/* @end */
|
||||
|
||||
@ -276,7 +273,7 @@ fieldset.buttons { }
|
||||
.alert,
|
||||
.notice {
|
||||
padding: 0.8em;
|
||||
margin-bottom: 1em;
|
||||
margin: 1em 0;
|
||||
border: 1px solid #ddd;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-border-radius: 8px;
|
||||
@ -327,14 +324,6 @@ fieldset.buttons { }
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Sprite */
|
||||
|
||||
.sprite { background: url(../images/ui-icons.png) no-repeat; text-indent: -10000px; }
|
||||
.trash { background-position: -177px -97px; height: 15px; width: 15px; }
|
||||
.unrelate { background-position: -145px -129px; height: 15px; width: 15px; }
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Filters */
|
||||
|
||||
#content .filters {
|
||||
@ -356,3 +345,25 @@ fieldset.buttons { }
|
||||
#search input { font-size: 1em; padding: 3px; }
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Misc */
|
||||
|
||||
ul.predefined_filters {
|
||||
margin: 1em 0 0.5em 0!important;
|
||||
}
|
||||
|
||||
ul.predefined_filters li {
|
||||
display: inline;
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
.actions {
|
||||
font-size: 0.9em;
|
||||
margin: 0.5em 0;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
tr .hidden { display: none; }
|
||||
tr:hover .hidden { display: block; }
|
||||
|
||||
/* @end */
|
||||
|
||||
BIN
public/admin/vendor/fancybox/fancy_loading.png
vendored
BIN
public/admin/vendor/fancybox/fancy_loading.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -5,33 +5,33 @@
|
||||
* to offer multiple easing options
|
||||
*
|
||||
* TERMS OF USE - jQuery Easing
|
||||
*
|
||||
* Open source under the BSD License.
|
||||
*
|
||||
*
|
||||
* Open source under the BSD License.
|
||||
*
|
||||
* Copyright © 2008 George McGinley Smith
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the author nor the names of contributors may be used to endorse
|
||||
*
|
||||
* Neither the name of the author nor the names of contributors may be used to endorse
|
||||
* or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -41,32 +41,32 @@ eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a
|
||||
/*
|
||||
*
|
||||
* TERMS OF USE - EASING EQUATIONS
|
||||
*
|
||||
* Open source under the BSD License.
|
||||
*
|
||||
*
|
||||
* Open source under the BSD License.
|
||||
*
|
||||
* Copyright © 2001 Robert Penner
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the author nor the names of contributors may be used to endorse
|
||||
*
|
||||
* Neither the name of the author nor the names of contributors may be used to endorse
|
||||
* or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
359
public/admin/vendor/fancybox/jquery.fancybox-1.3.4.css
vendored
Normal file
359
public/admin/vendor/fancybox/jquery.fancybox-1.3.4.css
vendored
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* FancyBox - jQuery Plugin
|
||||
* Simple and fancy lightbox alternative
|
||||
*
|
||||
* Examples and documentation at: http://fancybox.net
|
||||
*
|
||||
* Copyright (c) 2008 - 2010 Janis Skarnelis
|
||||
* That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
|
||||
*
|
||||
* Version: 1.3.4 (11/11/2010)
|
||||
* Requires: jQuery v1.3+
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
#fancybox-loading {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: -20px;
|
||||
margin-left: -20px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
z-index: 1104;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-loading div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 40px;
|
||||
height: 480px;
|
||||
background-image: url('fancybox.png');
|
||||
}
|
||||
|
||||
#fancybox-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 1100;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-tmp {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
overflow: auto;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-wrap {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 20px;
|
||||
z-index: 1101;
|
||||
outline: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-outer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#fancybox-content {
|
||||
width: 0;
|
||||
height: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
z-index: 1102;
|
||||
border: 0px solid #fff;
|
||||
}
|
||||
|
||||
#fancybox-hide-sel-frame {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
z-index: 1101;
|
||||
}
|
||||
|
||||
#fancybox-close {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
right: -15px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: transparent url('fancybox.png') -40px 0px;
|
||||
cursor: pointer;
|
||||
z-index: 1103;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-error {
|
||||
color: #444;
|
||||
font: normal 12px/20px Arial;
|
||||
padding: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#fancybox-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
line-height: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#fancybox-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-left, #fancybox-right {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
height: 100%;
|
||||
width: 35%;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
background: transparent url('blank.gif');
|
||||
z-index: 1102;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-left {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
#fancybox-right {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#fancybox-left-ico, #fancybox-right-ico {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -9999px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: -15px;
|
||||
cursor: pointer;
|
||||
z-index: 1102;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-left-ico {
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -30px;
|
||||
}
|
||||
|
||||
#fancybox-right-ico {
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -60px;
|
||||
}
|
||||
|
||||
#fancybox-left:hover, #fancybox-right:hover {
|
||||
visibility: visible; /* IE6 */
|
||||
}
|
||||
|
||||
#fancybox-left:hover span {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
#fancybox-right:hover span {
|
||||
left: auto;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.fancybox-bg {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
#fancybox-bg-n {
|
||||
top: -20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-image: url('fancybox-x.png');
|
||||
}
|
||||
|
||||
#fancybox-bg-ne {
|
||||
top: -20px;
|
||||
right: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -162px;
|
||||
}
|
||||
|
||||
#fancybox-bg-e {
|
||||
top: 0;
|
||||
right: -20px;
|
||||
height: 100%;
|
||||
background-image: url('fancybox-y.png');
|
||||
background-position: -20px 0px;
|
||||
}
|
||||
|
||||
#fancybox-bg-se {
|
||||
bottom: -20px;
|
||||
right: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -182px;
|
||||
}
|
||||
|
||||
#fancybox-bg-s {
|
||||
bottom: -20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-image: url('fancybox-x.png');
|
||||
background-position: 0px -20px;
|
||||
}
|
||||
|
||||
#fancybox-bg-sw {
|
||||
bottom: -20px;
|
||||
left: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -142px;
|
||||
}
|
||||
|
||||
#fancybox-bg-w {
|
||||
top: 0;
|
||||
left: -20px;
|
||||
height: 100%;
|
||||
background-image: url('fancybox-y.png');
|
||||
}
|
||||
|
||||
#fancybox-bg-nw {
|
||||
top: -20px;
|
||||
left: -20px;
|
||||
background-image: url('fancybox.png');
|
||||
background-position: -40px -122px;
|
||||
}
|
||||
|
||||
#fancybox-title {
|
||||
font-family: Helvetica;
|
||||
font-size: 12px;
|
||||
z-index: 1102;
|
||||
}
|
||||
|
||||
.fancybox-title-inside {
|
||||
padding-bottom: 10px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fancybox-title-outside {
|
||||
padding-top: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.fancybox-title-over {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: #FFF;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#fancybox-title-over {
|
||||
padding: 10px;
|
||||
background-image: url('fancy_title_over.png');
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fancybox-title-float {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -20px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#fancybox-title-float-wrap {
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#fancybox-title-float-wrap td {
|
||||
border: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#fancybox-title-float-left {
|
||||
padding: 0 0 0 15px;
|
||||
background: url('fancybox.png') -40px -90px no-repeat;
|
||||
}
|
||||
|
||||
#fancybox-title-float-main {
|
||||
color: #FFF;
|
||||
line-height: 29px;
|
||||
font-weight: bold;
|
||||
padding: 0 0 3px 0;
|
||||
background: url('fancybox-x.png') 0px -40px;
|
||||
}
|
||||
|
||||
#fancybox-title-float-right {
|
||||
padding: 0 0 0 15px;
|
||||
background: url('fancybox.png') -55px -90px no-repeat;
|
||||
}
|
||||
|
||||
/* IE6 */
|
||||
|
||||
.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
|
||||
.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
|
||||
.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
|
||||
.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
|
||||
.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
|
||||
height: expression(this.parentNode.clientHeight + "px");
|
||||
}
|
||||
|
||||
#fancybox-loading.fancybox-ie6 {
|
||||
position: absolute; margin-top: 0;
|
||||
top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
|
||||
}
|
||||
|
||||
#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
|
||||
|
||||
/* IE6, IE7, IE8 */
|
||||
|
||||
.fancybox-ie .fancybox-bg { background: transparent !important; }
|
||||
|
||||
.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
|
||||
1156
public/admin/vendor/fancybox/jquery.fancybox-1.3.4.js
vendored
Normal file
1156
public/admin/vendor/fancybox/jquery.fancybox-1.3.4.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
46
public/admin/vendor/fancybox/jquery.fancybox-1.3.4.pack.js
vendored
Normal file
46
public/admin/vendor/fancybox/jquery.fancybox-1.3.4.pack.js
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* FancyBox - jQuery Plugin
|
||||
* Simple and fancy lightbox alternative
|
||||
*
|
||||
* Examples and documentation at: http://fancybox.net
|
||||
*
|
||||
* Copyright (c) 2008 - 2010 Janis Skarnelis
|
||||
* That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
|
||||
*
|
||||
* Version: 1.3.4 (11/11/2010)
|
||||
* Requires: jQuery v1.3+
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
|
||||
F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
|
||||
c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
|
||||
false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
|
||||
function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
|
||||
'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
|
||||
"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
|
||||
";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
|
||||
opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
|
||||
d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
|
||||
y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
|
||||
i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
|
||||
f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
|
||||
37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
|
||||
s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
|
||||
f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
|
||||
j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
|
||||
"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
|
||||
10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
|
||||
b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
|
||||
0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
|
||||
1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
|
||||
true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
|
||||
b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
|
||||
d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
|
||||
D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
|
||||
b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
|
||||
b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
|
||||
easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);
|
||||
14
public/admin/vendor/fancybox/jquery.mousewheel-3.0.4.pack.js
vendored
Normal file
14
public/admin/vendor/fancybox/jquery.mousewheel-3.0.4.pack.js
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
|
||||
* Licensed under the MIT License (LICENSE.txt).
|
||||
*
|
||||
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
|
||||
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
|
||||
* Thanks to: Seamus Leahy for adding deltaX and deltaY
|
||||
*
|
||||
* Version: 3.0.4
|
||||
*
|
||||
* Requires: 1.2.2+
|
||||
*/
|
||||
|
||||
(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=
|
||||
f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
|
||||
@ -1,10 +1,8 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Admin::AdminUsersControllerTest < ActionController::TestCase
|
||||
|
||||
# Replace this with your real tests.
|
||||
test "the truth" do
|
||||
assert true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Admin::CategoriesControllerTest < ActionController::TestCase
|
||||
|
||||
# Replace this with your real tests.
|
||||
test "the truth" do
|
||||
assert true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Admin::PagesControllerTest < ActionController::TestCase
|
||||
|
||||
# Replace this with your real tests.
|
||||
test "the truth" do
|
||||
assert true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Admin::PhotosControllerTest < ActionController::TestCase
|
||||
|
||||
# Replace this with your real tests.
|
||||
test "the truth" do
|
||||
assert true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
26
vendor/plugins/paperclip/LICENSE
vendored
26
vendor/plugins/paperclip/LICENSE
vendored
@ -1,26 +0,0 @@
|
||||
|
||||
LICENSE
|
||||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2008 Jon Yurek and thoughtbot, inc.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
182
vendor/plugins/paperclip/README.rdoc
vendored
182
vendor/plugins/paperclip/README.rdoc
vendored
@ -1,182 +0,0 @@
|
||||
=Paperclip
|
||||
|
||||
Paperclip is intended as an easy file attachment library for ActiveRecord. The
|
||||
intent behind it was to keep setup as easy as possible and to treat files as
|
||||
much like other attributes as possible. This means they aren't saved to their
|
||||
final locations on disk, nor are they deleted if set to nil, until
|
||||
ActiveRecord::Base#save is called. It manages validations based on size and
|
||||
presence, if required. It can transform its assigned image into thumbnails if
|
||||
needed, and the prerequisites are as simple as installing ImageMagick (which,
|
||||
for most modern Unix-based systems, is as easy as installing the right
|
||||
packages). Attached files are saved to the filesystem and referenced in the
|
||||
browser by an easily understandable specification, which has sensible and
|
||||
useful defaults.
|
||||
|
||||
See the documentation for +has_attached_file+ in Paperclip::ClassMethods for
|
||||
more detailed options.
|
||||
|
||||
The complete RDoc[http://rdoc.info/projects/thoughtbot/paperclip] is online.
|
||||
|
||||
==Quick Start
|
||||
|
||||
In your model:
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
|
||||
end
|
||||
|
||||
In your migrations:
|
||||
|
||||
class AddAvatarColumnsToUser < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :users, :avatar_file_name, :string
|
||||
add_column :users, :avatar_content_type, :string
|
||||
add_column :users, :avatar_file_size, :integer
|
||||
add_column :users, :avatar_updated_at, :datetime
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :users, :avatar_file_name
|
||||
remove_column :users, :avatar_content_type
|
||||
remove_column :users, :avatar_file_size
|
||||
remove_column :users, :avatar_updated_at
|
||||
end
|
||||
end
|
||||
|
||||
In your edit and new views:
|
||||
|
||||
<% form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %>
|
||||
<%= form.file_field :avatar %>
|
||||
<% end %>
|
||||
|
||||
In your controller:
|
||||
|
||||
def create
|
||||
@user = User.create( params[:user] )
|
||||
end
|
||||
|
||||
In your show view:
|
||||
|
||||
<%= image_tag @user.avatar.url %>
|
||||
<%= image_tag @user.avatar.url(:medium) %>
|
||||
<%= image_tag @user.avatar.url(:thumb) %>
|
||||
|
||||
==Usage
|
||||
|
||||
The basics of paperclip are quite simple: Declare that your model has an
|
||||
attachment with the has_attached_file method, and give it a name. Paperclip
|
||||
will wrap up up to four attributes (all prefixed with that attachment's name,
|
||||
so you can have multiple attachments per model if you wish) and give the a
|
||||
friendly front end. The attributes are <attachment>_file_name,
|
||||
<attachment>_file_size, <attachment>_content_type, and <attachment>_updated_at.
|
||||
Only <attachment>_file_name is required for paperclip to operate. More
|
||||
information about the options to has_attached_file is available in the
|
||||
documentation of Paperclip::ClassMethods.
|
||||
|
||||
Attachments can be validated with Paperclip's validation methods,
|
||||
validates_attachment_presence, validates_attachment_content_type, and
|
||||
validates_attachment_size.
|
||||
|
||||
==Storage
|
||||
|
||||
The files that are assigned as attachments are, by default, placed in the
|
||||
directory specified by the :path option to has_attached_file. By default, this
|
||||
location is ":rails_root/public/system/:attachment/:id/:style/:filename". This
|
||||
location was chosen because on standard Capistrano deployments, the
|
||||
public/system directory is symlinked to the app's shared directory, meaning it
|
||||
will survive between deployments. For example, using that :path, you may have a
|
||||
file at
|
||||
|
||||
/data/myapp/releases/20081229172410/public/system/avatars/13/small/my_pic.png
|
||||
|
||||
NOTE: This is a change from previous versions of Paperclip, but is overall a
|
||||
safer choice for the default file store.
|
||||
|
||||
You may also choose to store your files using Amazon's S3 service. You can find
|
||||
more information about S3 storage at the description for
|
||||
Paperclip::Storage::S3.
|
||||
|
||||
Files on the local filesystem (and in the Rails app's public directory) will be
|
||||
available to the internet at large. If you require access control, it's
|
||||
possible to place your files in a different location. You will need to change
|
||||
both the :path and :url options in order to make sure the files are unavailable
|
||||
to the public. Both :path and :url allow the same set of interpolated
|
||||
variables.
|
||||
|
||||
==Post Processing
|
||||
|
||||
Paperclip supports an extensible selection of post-processors. When you define
|
||||
a set of styles for an attachment, by default it is expected that those
|
||||
"styles" are actually "thumbnails". However, you can do much more than just
|
||||
thumbnail images. By defining a subclass of Paperclip::Processor, you can
|
||||
perform any processing you want on the files that are attached. Any file in
|
||||
your Rails app's lib/paperclip_processors directory is automatically loaded by
|
||||
paperclip, allowing you to easily define custom processors. You can specify a
|
||||
processor with the :processors option to has_attached_file:
|
||||
|
||||
has_attached_file :scan, :styles => { :text => { :quality => :better } },
|
||||
:processors => [:ocr]
|
||||
|
||||
This would load the hypothetical class Paperclip::Ocr, which would have the
|
||||
hash "{ :quality => :better }" passed to it along with the uploaded file. For
|
||||
more information about defining processors, see Paperclip::Processor.
|
||||
|
||||
The default processor is Paperclip::Thumbnail. For backwards compatability
|
||||
reasons, you can pass a single geometry string or an array containing a
|
||||
geometry and a format, which the file will be converted to, like so:
|
||||
|
||||
has_attached_file :avatar, :styles => { :thumb => ["32x32#", :png] }
|
||||
|
||||
This will convert the "thumb" style to a 32x32 square in png format, regardless
|
||||
of what was uploaded. If the format is not specified, it is kept the same (i.e.
|
||||
jpgs will remain jpgs).
|
||||
|
||||
Multiple processors can be specified, and they will be invoked in the order
|
||||
they are defined in the :processors array. Each successive processor will
|
||||
be given the result of the previous processor's execution. All processors will
|
||||
receive the same parameters, which are what you define in the :styles hash.
|
||||
For example, assuming we had this definition:
|
||||
|
||||
has_attached_file :scan, :styles => { :text => { :quality => :better } },
|
||||
:processors => [:rotator, :ocr]
|
||||
|
||||
then both the :rotator processor and the :ocr processor would receive the
|
||||
options "{ :quality => :better }". This parameter may not mean anything to one
|
||||
or more or the processors, and they are expected to ignore it.
|
||||
|
||||
NOTE: Because processors operate by turning the original attachment into the
|
||||
styles, no processors will be run if there are no styles defined.
|
||||
|
||||
==Events
|
||||
|
||||
Before and after the Post Processing step, Paperclip calls back to the model
|
||||
with a few callbacks, allowing the model to change or cancel the processing
|
||||
step. The callbacks are "before_post_process" and "after_post_process" (which
|
||||
are called before and after the processing of each attachment), and the
|
||||
attachment-specific "before_<attachment>_post_process" and
|
||||
"after_<attachment>_post_process". The callbacks are intended to be as close to
|
||||
normal ActiveRecord callbacks as possible, so if you return false (specifically
|
||||
- returning nil is not the same) in a before_ filter, the post processing step
|
||||
will halt. Returning false in an after_ filter will not halt anything, but you
|
||||
can access the model and the attachment if necessary.
|
||||
|
||||
NOTE: Post processing will not even *start* if the attachment is not valid
|
||||
according to the validations. Your callbacks and processors will *only* be
|
||||
called with valid attachments.
|
||||
|
||||
==Testing
|
||||
|
||||
Paperclip provides rspec-compatible matchers for testing attachments. See the
|
||||
documentation on Paperclip::Shoulda::Matchers for more information.
|
||||
|
||||
==Contributing
|
||||
|
||||
If you'd like to contribute a feature or bugfix: Thanks! To make sure your
|
||||
fix/feature has a high chance of being included, please read the following
|
||||
guidelines:
|
||||
|
||||
1. Ask on the mailing list[http://groups.google.com/group/paperclip-plugin], or
|
||||
post a new GitHub Issue[http://github.com/thoughtbot/paperclip/issues].
|
||||
2. Make sure there are tests! We will not accept any patch that is not tested.
|
||||
It's a rare time when explicit tests aren't needed. If you have questions
|
||||
about writing tests for paperclip, please ask the mailing list.
|
||||
76
vendor/plugins/paperclip/Rakefile
vendored
76
vendor/plugins/paperclip/Rakefile
vendored
@ -1,76 +0,0 @@
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
||||
require 'paperclip'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => [:clean, :test]
|
||||
|
||||
desc 'Test the paperclip plugin under all supported Rails versions.'
|
||||
task :all do |t|
|
||||
exec('rake RAILS_VERSION=2.1 && rake RAILS_VERSION=2.3 && rake RAILS_VERSION=3.0')
|
||||
end
|
||||
|
||||
desc 'Test the paperclip plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib' << 'profile'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Start an IRB session with all necessary files required.'
|
||||
task :shell do |t|
|
||||
chdir File.dirname(__FILE__)
|
||||
exec 'irb -I lib/ -I lib/paperclip -r rubygems -r active_record -r tempfile -r init'
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the paperclip plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = 'Paperclip'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README*')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
desc 'Update documentation on website'
|
||||
task :sync_docs => 'rdoc' do
|
||||
`rsync -ave ssh doc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/paperclip`
|
||||
end
|
||||
|
||||
desc 'Clean up files.'
|
||||
task :clean do |t|
|
||||
FileUtils.rm_rf "doc"
|
||||
FileUtils.rm_rf "tmp"
|
||||
FileUtils.rm_rf "pkg"
|
||||
FileUtils.rm_rf "public"
|
||||
FileUtils.rm "test/debug.log" rescue nil
|
||||
FileUtils.rm "test/paperclip.db" rescue nil
|
||||
Dir.glob("paperclip-*.gem").each{|f| FileUtils.rm f }
|
||||
end
|
||||
|
||||
desc 'Build the gemspec.'
|
||||
task :gemspec do |t|
|
||||
exec 'gem build paperclip.gemspec'
|
||||
end
|
||||
|
||||
desc "Print a list of the files to be put into the gem"
|
||||
task :manifest => :clean do
|
||||
spec.files.each do |file|
|
||||
puts file
|
||||
end
|
||||
end
|
||||
|
||||
desc "Generate a gemspec file for GitHub"
|
||||
task :gemspec => :clean do
|
||||
File.open("#{spec.name}.gemspec", 'w') do |f|
|
||||
f.write spec.to_ruby
|
||||
end
|
||||
end
|
||||
|
||||
desc "Build the gem into the current directory"
|
||||
task :gem => :gemspec do
|
||||
`gem build #{spec.name}.gemspec`
|
||||
end
|
||||
@ -1,6 +0,0 @@
|
||||
When /^I attach an? "([^\"]*)" "([^\"]*)" file to an? "([^\"]*)" on S3$/ do |attachment, extension, model|
|
||||
stub_paperclip_s3(model, attachment, extension)
|
||||
attach_file attachment,
|
||||
"features/support/paperclip/#{model.gsub(" ", "_").underscore}/#{attachment}.#{extension}"
|
||||
end
|
||||
|
||||
17
vendor/plugins/paperclip/features/basic.feature
vendored
17
vendor/plugins/paperclip/features/basic.feature
vendored
@ -1,17 +0,0 @@
|
||||
Feature: Running paperclip in a Rails app
|
||||
|
||||
Scenario: Basic utilization
|
||||
Given I have a rails application
|
||||
And I save the following as "app/models/user.rb"
|
||||
"""
|
||||
class User < ActiveRecord::Base
|
||||
has_attached_file :avatar
|
||||
end
|
||||
"""
|
||||
When I visit /users/new
|
||||
And I fill in "user_name" with "something"
|
||||
And I attach the file "test/fixtures/5k.png" to "user_avatar"
|
||||
And I press "Submit"
|
||||
Then I should see "Name: something"
|
||||
And I should see an image with a path of "/system/avatars/1/original/5k.png"
|
||||
And the file at "/system/avatars/1/original/5k.png" is the same as "test/fixtures/5k.png"
|
||||
27
vendor/plugins/paperclip/features/s3.feature
vendored
27
vendor/plugins/paperclip/features/s3.feature
vendored
@ -1,27 +0,0 @@
|
||||
Feature: Running paperclip in a Rails app using basic S3 support
|
||||
|
||||
Scenario: Basic utilization
|
||||
Given I have a rails application
|
||||
And I save the following as "app/models/user.rb"
|
||||
"""
|
||||
class User < ActiveRecord::Base
|
||||
has_attached_file :avatar,
|
||||
:storage => :s3,
|
||||
:path => "/:attachment/:id/:style/:filename",
|
||||
:s3_credentials => Rails.root.join("config/s3.yml")
|
||||
end
|
||||
"""
|
||||
And I validate my S3 credentials
|
||||
And I save the following as "config/s3.yml"
|
||||
"""
|
||||
bucket: <%= ENV['PAPERCLIP_TEST_BUCKET'] || 'paperclip' %>
|
||||
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
|
||||
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
|
||||
"""
|
||||
When I visit /users/new
|
||||
And I fill in "user_name" with "something"
|
||||
And I attach the file "test/fixtures/5k.png" to "user_avatar"
|
||||
And I press "Submit"
|
||||
Then I should see "Name: something"
|
||||
And I should see an image with a path of "http://s3.amazonaws.com/paperclip/avatars/1/original/5k.png"
|
||||
And the file at "http://s3.amazonaws.com/paperclip/avatars/1/original/5k.png" is the same as "test/fixtures/5k.png"
|
||||
@ -1,14 +0,0 @@
|
||||
Then %r{I should see an image with a path of "([^"]*)"} do |path|
|
||||
page.should have_css("img[src^='#{path}']")
|
||||
end
|
||||
|
||||
Then %r{^the file at "([^"]*)" is the same as "([^"]*)"$} do |web_file, path|
|
||||
expected = IO.read(path)
|
||||
actual = if web_file.match %r{^https?://}
|
||||
Net::HTTP.get(URI.parse(web_file))
|
||||
else
|
||||
visit(web_file)
|
||||
page.body
|
||||
end
|
||||
actual.should == expected
|
||||
end
|
||||
@ -1,90 +0,0 @@
|
||||
Given "I have a rails application" do
|
||||
steps %{
|
||||
Given I generate a rails application
|
||||
And this plugin is available
|
||||
And I have a "users" resource with "name:string"
|
||||
And I turn off class caching
|
||||
Given I save the following as "app/models/user.rb"
|
||||
"""
|
||||
class User < ActiveRecord::Base
|
||||
end
|
||||
"""
|
||||
And I save the following as "config/s3.yml"
|
||||
"""
|
||||
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
|
||||
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
|
||||
bucket: paperclip
|
||||
"""
|
||||
And I save the following as "app/views/users/new.html.erb"
|
||||
"""
|
||||
<% form_for @user, :html => { :multipart => true } do |f| %>
|
||||
<%= f.text_field :name %>
|
||||
<%= f.file_field :avatar %>
|
||||
<%= submit_tag "Submit" %>
|
||||
<% end %>
|
||||
"""
|
||||
And I save the following as "app/views/users/show.html.erb"
|
||||
"""
|
||||
<p>Name: <%= @user.name %></p>
|
||||
<p>Avatar: <%= image_tag @user.avatar.url %></p>
|
||||
"""
|
||||
And I run "script/generate paperclip user avatar"
|
||||
And the rails application is prepped and running
|
||||
}
|
||||
end
|
||||
|
||||
Given %r{I generate a rails application} do
|
||||
FileUtils.rm_rf TEMP_ROOT
|
||||
FileUtils.mkdir_p TEMP_ROOT
|
||||
Dir.chdir(TEMP_ROOT) do
|
||||
`rails _2.3.8_ #{APP_NAME}`
|
||||
end
|
||||
end
|
||||
|
||||
When %r{I save the following as "([^"]*)"} do |path, string|
|
||||
FileUtils.mkdir_p(File.join(CUC_RAILS_ROOT, File.dirname(path)))
|
||||
File.open(File.join(CUC_RAILS_ROOT, path), 'w') { |file| file.write(string) }
|
||||
end
|
||||
|
||||
When %r{I turn off class caching} do
|
||||
Dir.chdir(CUC_RAILS_ROOT) do
|
||||
file = "config/environments/test.rb"
|
||||
config = IO.read(file)
|
||||
config.gsub!(%r{^\s*config.cache_classes.*$},
|
||||
"config.cache_classes = false")
|
||||
File.open(file, "w"){|f| f.write(config) }
|
||||
end
|
||||
end
|
||||
|
||||
When %r{the rails application is prepped and running$} do
|
||||
When "I reset the database"
|
||||
When "the rails application is running"
|
||||
end
|
||||
|
||||
When %r{I reset the database} do
|
||||
When %{I run "rake db:drop db:create db:migrate"}
|
||||
end
|
||||
|
||||
When %r{the rails application is running} do
|
||||
Dir.chdir(CUC_RAILS_ROOT) do
|
||||
require "config/environment"
|
||||
require "capybara/rails"
|
||||
end
|
||||
end
|
||||
|
||||
When %r{this plugin is available} do
|
||||
$LOAD_PATH << "#{PROJECT_ROOT}/lib"
|
||||
require 'paperclip'
|
||||
When %{I save the following as "vendor/plugins/paperclip/rails/init.rb"},
|
||||
IO.read("#{PROJECT_ROOT}/rails/init.rb")
|
||||
end
|
||||
|
||||
When %r{I run "([^"]*)"} do |command|
|
||||
Dir.chdir(CUC_RAILS_ROOT) do
|
||||
`#{command}`
|
||||
end
|
||||
end
|
||||
|
||||
When %r{I have a "([^"]*)" resource with "([^"]*)"} do |resource, fields|
|
||||
When %{I run "script/generate scaffold #{resource} #{fields}"}
|
||||
end
|
||||
@ -1,9 +0,0 @@
|
||||
Given /I validate my S3 credentials/ do
|
||||
key = ENV['AWS_ACCESS_KEY_ID']
|
||||
secret = ENV['AWS_SECRET_ACCESS_KEY']
|
||||
|
||||
key.should_not be_nil
|
||||
secret.should_not be_nil
|
||||
|
||||
assert_credentials(key, secret)
|
||||
end
|
||||
@ -1,227 +0,0 @@
|
||||
# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
|
||||
# It is recommended to regenerate this file in the future when you upgrade to a
|
||||
# newer version of cucumber-rails. Consider adding your own code to a new file
|
||||
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
||||
# files.
|
||||
|
||||
|
||||
require 'uri'
|
||||
require 'cgi'
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
|
||||
|
||||
module WithinHelpers
|
||||
def with_scope(locator)
|
||||
locator ? within(locator) { yield } : yield
|
||||
end
|
||||
end
|
||||
World(WithinHelpers)
|
||||
|
||||
Given /^(?:|I )am on (.+)$/ do |page_name|
|
||||
visit path_to(page_name)
|
||||
end
|
||||
|
||||
When /^(?:|I )go to (.+)$/ do |page_name|
|
||||
visit path_to(page_name)
|
||||
end
|
||||
|
||||
When /^(?:|I )visit (\/.+)$/ do |page_path|
|
||||
visit page_path
|
||||
end
|
||||
|
||||
When /^(?:|I )press "([^"]*)"(?: within "([^"]*)")?$/ do |button, selector|
|
||||
with_scope(selector) do
|
||||
click_button(button)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector|
|
||||
with_scope(selector) do
|
||||
click_link(link)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )fill in "([^"]*)" with "([^"]*)"(?: within "([^"]*)")?$/ do |field, value, selector|
|
||||
with_scope(selector) do
|
||||
fill_in(field, :with => value)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )fill in "([^"]*)" for "([^"]*)"(?: within "([^"]*)")?$/ do |value, field, selector|
|
||||
with_scope(selector) do
|
||||
fill_in(field, :with => value)
|
||||
end
|
||||
end
|
||||
|
||||
# Use this to fill in an entire form with data from a table. Example:
|
||||
#
|
||||
# When I fill in the following:
|
||||
# | Account Number | 5002 |
|
||||
# | Expiry date | 2009-11-01 |
|
||||
# | Note | Nice guy |
|
||||
# | Wants Email? | |
|
||||
#
|
||||
# TODO: Add support for checkbox, select og option
|
||||
# based on naming conventions.
|
||||
#
|
||||
When /^(?:|I )fill in the following(?: within "([^"]*)")?:$/ do |selector, fields|
|
||||
with_scope(selector) do
|
||||
fields.rows_hash.each do |name, value|
|
||||
When %{I fill in "#{name}" with "#{value}"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )select "([^"]*)" from "([^"]*)"(?: within "([^"]*)")?$/ do |value, field, selector|
|
||||
with_scope(selector) do
|
||||
select(value, :from => field)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )check "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector|
|
||||
with_scope(selector) do
|
||||
check(field)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )uncheck "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector|
|
||||
with_scope(selector) do
|
||||
uncheck(field)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )choose "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector|
|
||||
with_scope(selector) do
|
||||
choose(field)
|
||||
end
|
||||
end
|
||||
|
||||
When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"(?: within "([^"]*)")?$/ do |path, field, selector|
|
||||
with_scope(selector) do
|
||||
attach_file(field, path)
|
||||
end
|
||||
end
|
||||
|
||||
Then /^(?:|I )should see JSON:$/ do |expected_json|
|
||||
require 'json'
|
||||
expected = JSON.pretty_generate(JSON.parse(expected_json))
|
||||
actual = JSON.pretty_generate(JSON.parse(response.body))
|
||||
expected.should == actual
|
||||
end
|
||||
|
||||
Then /^(?:|I )should see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector|
|
||||
with_scope(selector) do
|
||||
if page.respond_to? :should
|
||||
page.should have_content(text)
|
||||
else
|
||||
assert page.has_content?(text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^(?:|I )should see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector|
|
||||
regexp = Regexp.new(regexp)
|
||||
with_scope(selector) do
|
||||
if page.respond_to? :should
|
||||
page.should have_xpath('//*', :text => regexp)
|
||||
else
|
||||
assert page.has_xpath?('//*', :text => regexp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^(?:|I )should not see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector|
|
||||
with_scope(selector) do
|
||||
if page.respond_to? :should
|
||||
page.should have_no_content(text)
|
||||
else
|
||||
assert page.has_no_content?(text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^(?:|I )should not see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector|
|
||||
regexp = Regexp.new(regexp)
|
||||
with_scope(selector) do
|
||||
if page.respond_to? :should
|
||||
page.should have_no_xpath('//*', :text => regexp)
|
||||
else
|
||||
assert page.has_no_xpath?('//*', :text => regexp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^the "([^"]*)" field(?: within "([^"]*)")? should contain "([^"]*)"$/ do |field, selector, value|
|
||||
with_scope(selector) do
|
||||
field = find_field(field)
|
||||
field_value = (field.tag_name == 'textarea') ? field.text : field.value
|
||||
if field_value.respond_to? :should
|
||||
field_value.should =~ /#{value}/
|
||||
else
|
||||
assert_match(/#{value}/, field_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^the "([^"]*)" field(?: within "([^"]*)")? should not contain "([^"]*)"$/ do |field, selector, value|
|
||||
with_scope(selector) do
|
||||
field = find_field(field)
|
||||
field_value = (field.tag_name == 'textarea') ? field.text : field.value
|
||||
if field_value.respond_to? :should_not
|
||||
field_value.should_not =~ /#{value}/
|
||||
else
|
||||
assert_no_match(/#{value}/, field_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should be checked$/ do |label, selector|
|
||||
with_scope(selector) do
|
||||
field_checked = find_field(label)['checked']
|
||||
if field_checked.respond_to? :should
|
||||
field_checked.should be_true
|
||||
else
|
||||
assert field_checked
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should not be checked$/ do |label, selector|
|
||||
with_scope(selector) do
|
||||
field_checked = find_field(label)['checked']
|
||||
if field_checked.respond_to? :should
|
||||
field_checked.should be_false
|
||||
else
|
||||
assert !field_checked
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Then /^(?:|I )should be on (.+)$/ do |page_name|
|
||||
current_path = URI.parse(current_url).path
|
||||
if current_path.respond_to? :should
|
||||
current_path.should == path_to(page_name)
|
||||
else
|
||||
assert_equal path_to(page_name), current_path
|
||||
end
|
||||
end
|
||||
|
||||
Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
|
||||
query = URI.parse(current_url).query
|
||||
actual_params = query ? CGI.parse(query) : {}
|
||||
expected_params = {}
|
||||
expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
|
||||
|
||||
if actual_params.respond_to? :should
|
||||
actual_params.should == expected_params
|
||||
else
|
||||
assert_equal expected_params, actual_params
|
||||
end
|
||||
end
|
||||
|
||||
Then /^I save and open the page$/ do
|
||||
save_and_open_page
|
||||
end
|
||||
|
||||
Then /^show me the page$/ do
|
||||
save_and_open_page
|
||||
end
|
||||
@ -1,3 +0,0 @@
|
||||
require 'capybara/cucumber'
|
||||
require 'test/unit/assertions'
|
||||
World(Test::Unit::Assertions)
|
||||
@ -1,35 +0,0 @@
|
||||
module NavigationHelpers
|
||||
# Maps a name to a path. Used by the
|
||||
#
|
||||
# When /^I go to (.+)$/ do |page_name|
|
||||
#
|
||||
# step definition in web_steps.rb
|
||||
#
|
||||
def path_to(page_name)
|
||||
case page_name
|
||||
|
||||
when /the new user page/
|
||||
'/users/new'
|
||||
when /the home\s?page/
|
||||
'/'
|
||||
|
||||
# Add more mappings here.
|
||||
# Here is an example that pulls values out of the Regexp:
|
||||
#
|
||||
# when /^(.*)'s profile page$/i
|
||||
# user_profile_path(User.find_by_login($1))
|
||||
|
||||
else
|
||||
begin
|
||||
page_name =~ /the (.*) page/
|
||||
path_components = $1.split(/\s+/)
|
||||
self.send(path_components.push('path').join('_').to_sym)
|
||||
rescue Object => e
|
||||
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
||||
"Now, go and add a mapping in #{__FILE__}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
World(NavigationHelpers)
|
||||
@ -1,5 +0,0 @@
|
||||
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
|
||||
TEMP_ROOT = File.join(PROJECT_ROOT, 'tmp').freeze
|
||||
APP_NAME = 'testapp'.freeze
|
||||
CUC_RAILS_ROOT = File.join(TEMP_ROOT, APP_NAME).freeze
|
||||
ENV['RAILS_ENV'] = 'test'
|
||||
25
vendor/plugins/paperclip/features/support/s3.rb
vendored
25
vendor/plugins/paperclip/features/support/s3.rb
vendored
@ -1,25 +0,0 @@
|
||||
module AWSS3Methods
|
||||
def load_s3
|
||||
begin
|
||||
require 'aws/s3'
|
||||
rescue LoadError => e
|
||||
fail "You do not have aws-s3 installed."
|
||||
end
|
||||
end
|
||||
|
||||
def assert_credentials(key, secret)
|
||||
load_s3
|
||||
begin
|
||||
AWS::S3::Base.establish_connection!(
|
||||
:access_key_id => key,
|
||||
:secret_access_key => secret
|
||||
)
|
||||
AWS::S3::Service.buckets
|
||||
rescue AWS::S3::ResponseError => e
|
||||
fail "Could not connect using AWS credentials in AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. " +
|
||||
"Please make sure these are set in your environment."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
World(AWSS3Methods)
|
||||
@ -1,5 +0,0 @@
|
||||
Usage:
|
||||
|
||||
script/generate paperclip Class attachment1 (attachment2 ...)
|
||||
|
||||
This will create a migration that will add the proper columns to your class's table.
|
||||
@ -1,27 +0,0 @@
|
||||
class PaperclipGenerator < Rails::Generator::NamedBase
|
||||
attr_accessor :attachments, :migration_name
|
||||
|
||||
def initialize(args, options = {})
|
||||
super
|
||||
@class_name, @attachments = args[0], args[1..-1]
|
||||
end
|
||||
|
||||
def manifest
|
||||
file_name = generate_file_name
|
||||
@migration_name = file_name.camelize
|
||||
record do |m|
|
||||
m.migration_template "paperclip_migration.rb.erb",
|
||||
File.join('db', 'migrate'),
|
||||
:migration_file_name => file_name
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_file_name
|
||||
names = attachments.map{|a| a.underscore }
|
||||
names = names[0..-2] + ["and", names[-1]] if names.length > 1
|
||||
"add_attachments_#{names.join("_")}_to_#{@class_name.underscore}"
|
||||
end
|
||||
|
||||
end
|
||||
@ -1,19 +0,0 @@
|
||||
class <%= migration_name %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
<% attachments.each do |attachment| -%>
|
||||
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name, :string
|
||||
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type, :string
|
||||
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size, :integer
|
||||
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at, :datetime
|
||||
<% end -%>
|
||||
end
|
||||
|
||||
def self.down
|
||||
<% attachments.each do |attachment| -%>
|
||||
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name
|
||||
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type
|
||||
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size
|
||||
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
1
vendor/plugins/paperclip/init.rb
vendored
1
vendor/plugins/paperclip/init.rb
vendored
@ -1 +0,0 @@
|
||||
require File.join(File.dirname(__FILE__), "lib", "paperclip")
|
||||
@ -1,8 +0,0 @@
|
||||
Description:
|
||||
Explain the generator
|
||||
|
||||
Example:
|
||||
rails generate paperclip Thing
|
||||
|
||||
This will create:
|
||||
what/will/it/create
|
||||
@ -1,31 +0,0 @@
|
||||
require 'rails/generators/active_record'
|
||||
|
||||
class PaperclipGenerator < ActiveRecord::Generators::Base
|
||||
desc "Create a migration to add paperclip-specific fields to your model."
|
||||
|
||||
argument :attachment_names, :required => true, :type => :array, :desc => "The names of the attachment(s) to add.",
|
||||
:banner => "attachment_one attachment_two attachment_three ..."
|
||||
|
||||
def self.source_root
|
||||
@source_root ||= File.expand_path('../templates', __FILE__)
|
||||
end
|
||||
|
||||
def generate_migration
|
||||
migration_template "paperclip_migration.rb.erb", "db/migrate/#{migration_file_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def migration_name
|
||||
"add_attachment_#{attachment_names.join("_")}_to_#{name.underscore}"
|
||||
end
|
||||
|
||||
def migration_file_name
|
||||
"#{migration_name}.rb"
|
||||
end
|
||||
|
||||
def migration_class_name
|
||||
migration_name.camelize
|
||||
end
|
||||
|
||||
end
|
||||
@ -1,19 +0,0 @@
|
||||
class <%= migration_class_name %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
<% attachment_names.each do |attachment| -%>
|
||||
add_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_file_name, :string
|
||||
add_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_content_type, :string
|
||||
add_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_file_size, :integer
|
||||
add_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at, :datetime
|
||||
<% end -%>
|
||||
end
|
||||
|
||||
def self.down
|
||||
<% attachment_names.each do |attachment| -%>
|
||||
remove_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_file_name
|
||||
remove_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_content_type
|
||||
remove_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_file_size
|
||||
remove_column :<%= name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at
|
||||
<% end -%>
|
||||
end
|
||||
end
|
||||
370
vendor/plugins/paperclip/lib/paperclip.rb
vendored
370
vendor/plugins/paperclip/lib/paperclip.rb
vendored
@ -1,370 +0,0 @@
|
||||
# Paperclip allows file attachments that are stored in the filesystem. All graphical
|
||||
# transformations are done using the Graphics/ImageMagick command line utilities and
|
||||
# are stored in Tempfiles until the record is saved. Paperclip does not require a
|
||||
# separate model for storing the attachment's information, instead adding a few simple
|
||||
# columns to your table.
|
||||
#
|
||||
# Author:: Jon Yurek
|
||||
# Copyright:: Copyright (c) 2008-2009 thoughtbot, inc.
|
||||
# License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
#
|
||||
# Paperclip defines an attachment as any file, though it makes special considerations
|
||||
# for image files. You can declare that a model has an attached file with the
|
||||
# +has_attached_file+ method:
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# has_attached_file :avatar, :styles => { :thumb => "100x100" }
|
||||
# end
|
||||
#
|
||||
# user = User.new
|
||||
# user.avatar = params[:user][:avatar]
|
||||
# user.avatar.url
|
||||
# # => "/users/avatars/4/original_me.jpg"
|
||||
# user.avatar.url(:thumb)
|
||||
# # => "/users/avatars/4/thumb_me.jpg"
|
||||
#
|
||||
# See the +has_attached_file+ documentation for more details.
|
||||
|
||||
require 'erb'
|
||||
require 'digest'
|
||||
require 'tempfile'
|
||||
require 'paperclip/version'
|
||||
require 'paperclip/upfile'
|
||||
require 'paperclip/iostream'
|
||||
require 'paperclip/geometry'
|
||||
require 'paperclip/processor'
|
||||
require 'paperclip/thumbnail'
|
||||
require 'paperclip/interpolations'
|
||||
require 'paperclip/style'
|
||||
require 'paperclip/attachment'
|
||||
require 'paperclip/storage'
|
||||
require 'paperclip/callback_compatability'
|
||||
require 'paperclip/command_line'
|
||||
require 'paperclip/railtie'
|
||||
if defined?(Rails.root) && Rails.root
|
||||
Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor|
|
||||
require processor
|
||||
end
|
||||
end
|
||||
|
||||
# The base module that gets included in ActiveRecord::Base. See the
|
||||
# documentation for Paperclip::ClassMethods for more useful information.
|
||||
module Paperclip
|
||||
|
||||
class << self
|
||||
# Provides configurability to Paperclip. There are a number of options available, such as:
|
||||
# * whiny: Will raise an error if Paperclip cannot process thumbnails of
|
||||
# an uploaded image. Defaults to true.
|
||||
# * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors
|
||||
# log levels, etc. Defaults to true.
|
||||
# * command_path: Defines the path at which to find the command line
|
||||
# programs if they are not visible to Rails the system's search path. Defaults to
|
||||
# nil, which uses the first executable found in the user's search path.
|
||||
# * image_magick_path: Deprecated alias of command_path.
|
||||
def options
|
||||
@options ||= {
|
||||
:whiny => true,
|
||||
:image_magick_path => nil,
|
||||
:command_path => nil,
|
||||
:log => true,
|
||||
:log_command => true,
|
||||
:swallow_stderr => true
|
||||
}
|
||||
end
|
||||
|
||||
def configure
|
||||
yield(self) if block_given?
|
||||
end
|
||||
|
||||
def interpolates key, &block
|
||||
Paperclip::Interpolations[key] = block
|
||||
end
|
||||
|
||||
# The run method takes a command to execute and an array of parameters
|
||||
# that get passed to it. The command is prefixed with the :command_path
|
||||
# option from Paperclip.options. If you have many commands to run and
|
||||
# they are in different paths, the suggested course of action is to
|
||||
# symlink them so they are all in the same directory.
|
||||
#
|
||||
# If the command returns with a result code that is not one of the
|
||||
# expected_outcodes, a PaperclipCommandLineError will be raised. Generally
|
||||
# a code of 0 is expected, but a list of codes may be passed if necessary.
|
||||
# These codes should be passed as a hash as the last argument, like so:
|
||||
#
|
||||
# Paperclip.run("echo", "something", :expected_outcodes => [0,1,2,3])
|
||||
#
|
||||
# This method can log the command being run when
|
||||
# Paperclip.options[:log_command] is set to true (defaults to false). This
|
||||
# will only log if logging in general is set to true as well.
|
||||
def run cmd, *params
|
||||
if options[:image_magick_path]
|
||||
Paperclip.log("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
|
||||
end
|
||||
CommandLine.path = options[:command_path] || options[:image_magick_path]
|
||||
CommandLine.new(cmd, *params).run
|
||||
end
|
||||
|
||||
def processor name #:nodoc:
|
||||
name = name.to_s.camelize
|
||||
processor = Paperclip.const_get(name)
|
||||
unless processor.ancestors.include?(Paperclip::Processor)
|
||||
raise PaperclipError.new("Processor #{name} was not found")
|
||||
end
|
||||
processor
|
||||
end
|
||||
|
||||
# Log a paperclip-specific line. Uses ActiveRecord::Base.logger
|
||||
# by default. Set Paperclip.options[:log] to false to turn off.
|
||||
def log message
|
||||
logger.info("[paperclip] #{message}") if logging?
|
||||
end
|
||||
|
||||
def logger #:nodoc:
|
||||
ActiveRecord::Base.logger
|
||||
end
|
||||
|
||||
def logging? #:nodoc:
|
||||
options[:log]
|
||||
end
|
||||
end
|
||||
|
||||
class PaperclipError < StandardError #:nodoc:
|
||||
end
|
||||
|
||||
class PaperclipCommandLineError < PaperclipError #:nodoc:
|
||||
attr_accessor :output
|
||||
def initialize(msg = nil, output = nil)
|
||||
super(msg)
|
||||
@output = output
|
||||
end
|
||||
end
|
||||
|
||||
class StorageMethodNotFound < PaperclipError
|
||||
end
|
||||
|
||||
class CommandNotFoundError < PaperclipError
|
||||
end
|
||||
|
||||
class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
|
||||
end
|
||||
|
||||
class InfiniteInterpolationError < PaperclipError #:nodoc:
|
||||
end
|
||||
|
||||
module Glue
|
||||
def self.included base #:nodoc:
|
||||
base.extend ClassMethods
|
||||
if base.respond_to?("set_callback")
|
||||
base.send :include, Paperclip::CallbackCompatability::Rails3
|
||||
else
|
||||
base.send :include, Paperclip::CallbackCompatability::Rails21
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# +has_attached_file+ gives the class it is called on an attribute that maps to a file. This
|
||||
# is typically a file stored somewhere on the filesystem and has been uploaded by a user.
|
||||
# The attribute returns a Paperclip::Attachment object which handles the management of
|
||||
# that file. The intent is to make the attachment as much like a normal attribute. The
|
||||
# thumbnails will be created when the new file is assigned, but they will *not* be saved
|
||||
# until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is
|
||||
# called on it, the attachment will *not* be deleted until +save+ is called. See the
|
||||
# Paperclip::Attachment documentation for more specifics. There are a number of options
|
||||
# you can set to change the behavior of a Paperclip attachment:
|
||||
# * +url+: The full URL of where the attachment is publically accessible. This can just
|
||||
# as easily point to a directory served directly through Apache as it can to an action
|
||||
# that can control permissions. You can specify the full domain and path, but usually
|
||||
# just an absolute path is sufficient. The leading slash *must* be included manually for
|
||||
# absolute paths. The default value is
|
||||
# "/system/:attachment/:id/:style/:filename". See
|
||||
# Paperclip::Attachment#interpolate for more information on variable interpolaton.
|
||||
# :url => "/:class/:attachment/:id/:style_:filename"
|
||||
# :url => "http://some.other.host/stuff/:class/:id_:extension"
|
||||
# * +default_url+: The URL that will be returned if there is no attachment assigned.
|
||||
# This field is interpolated just as the url is. The default value is
|
||||
# "/:attachment/:style/missing.png"
|
||||
# has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png"
|
||||
# User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
|
||||
# * +styles+: A hash of thumbnail styles and their geometries. You can find more about
|
||||
# geometry strings at the ImageMagick website
|
||||
# (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip
|
||||
# also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally
|
||||
# inside the dimensions and then crop the rest off (weighted at the center). The
|
||||
# default value is to generate no thumbnails.
|
||||
# * +default_style+: The thumbnail style that will be used by default URLs.
|
||||
# Defaults to +original+.
|
||||
# has_attached_file :avatar, :styles => { :normal => "100x100#" },
|
||||
# :default_style => :normal
|
||||
# user.avatar.url # => "/avatars/23/normal_me.png"
|
||||
# * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due
|
||||
# to a command line error. This will override the global setting for this attachment.
|
||||
# Defaults to true. This option used to be called :whiny_thumbanils, but this is
|
||||
# deprecated.
|
||||
# * +convert_options+: When creating thumbnails, use this free-form options
|
||||
# array to pass in various convert command options. Typical options are "-strip" to
|
||||
# remove all Exif data from the image (save space for thumbnails and avatars) or
|
||||
# "-depth 8" to specify the bit depth of the resulting conversion. See ImageMagick
|
||||
# convert documentation for more options: (http://www.imagemagick.org/script/convert.php)
|
||||
# Note that this option takes a hash of options, each of which correspond to the style
|
||||
# of thumbnail being generated. You can also specify :all as a key, which will apply
|
||||
# to all of the thumbnails being generated. If you specify options for the :original,
|
||||
# it would be best if you did not specify destructive options, as the intent of keeping
|
||||
# the original around is to regenerate all the thumbnails when requirements change.
|
||||
# has_attached_file :avatar, :styles => { :large => "300x300", :negative => "100x100" }
|
||||
# :convert_options => {
|
||||
# :all => "-strip",
|
||||
# :negative => "-negate"
|
||||
# }
|
||||
# NOTE: While not deprecated yet, it is not recommended to specify options this way.
|
||||
# It is recommended that :convert_options option be included in the hash passed to each
|
||||
# :styles for compatability with future versions.
|
||||
# NOTE: Strings supplied to :convert_options are split on space in order to undergo
|
||||
# shell quoting for safety. If your options require a space, please pre-split them
|
||||
# and pass an array to :convert_options instead.
|
||||
# * +storage+: Chooses the storage backend where the files will be stored. The current
|
||||
# choices are :filesystem and :s3. The default is :filesystem. Make sure you read the
|
||||
# documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3
|
||||
# for backend-specific options.
|
||||
def has_attached_file name, options = {}
|
||||
include InstanceMethods
|
||||
|
||||
write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil?
|
||||
attachment_definitions[name] = {:validations => []}.merge(options)
|
||||
|
||||
after_save :save_attached_files
|
||||
before_destroy :destroy_attached_files
|
||||
|
||||
define_paperclip_callbacks :post_process, :"#{name}_post_process"
|
||||
|
||||
define_method name do |*args|
|
||||
a = attachment_for(name)
|
||||
(args.length > 0) ? a.to_s(args.first) : a
|
||||
end
|
||||
|
||||
define_method "#{name}=" do |file|
|
||||
attachment_for(name).assign(file)
|
||||
end
|
||||
|
||||
define_method "#{name}?" do
|
||||
attachment_for(name).file?
|
||||
end
|
||||
|
||||
validates_each(name) do |record, attr, value|
|
||||
attachment = record.attachment_for(name)
|
||||
attachment.send(:flush_errors)
|
||||
end
|
||||
end
|
||||
|
||||
# Places ActiveRecord-style validations on the size of the file assigned. The
|
||||
# possible options are:
|
||||
# * +in+: a Range of bytes (i.e. +1..1.megabyte+),
|
||||
# * +less_than+: equivalent to :in => 0..options[:less_than]
|
||||
# * +greater_than+: equivalent to :in => options[:greater_than]..Infinity
|
||||
# * +message+: error message to display, use :min and :max as replacements
|
||||
# * +if+: A lambda or name of a method on the instance. Validation will only
|
||||
# be run is this lambda or method returns true.
|
||||
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
||||
def validates_attachment_size name, options = {}
|
||||
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
||||
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
||||
range = (min..max)
|
||||
message = options[:message] || "file size must be between :min and :max bytes."
|
||||
message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
|
||||
|
||||
validates_inclusion_of :"#{name}_file_size",
|
||||
:in => range,
|
||||
:message => message,
|
||||
:if => options[:if],
|
||||
:unless => options[:unless],
|
||||
:allow_nil => true
|
||||
end
|
||||
|
||||
# Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
|
||||
def validates_attachment_thumbnails name, options = {}
|
||||
warn('[DEPRECATION] validates_attachment_thumbnail is deprecated. ' +
|
||||
'This validation is on by default and will be removed from future versions. ' +
|
||||
'If you wish to turn it off, supply :whiny => false in your definition.')
|
||||
attachment_definitions[name][:whiny_thumbnails] = true
|
||||
end
|
||||
|
||||
# Places ActiveRecord-style validations on the presence of a file.
|
||||
# Options:
|
||||
# * +if+: A lambda or name of a method on the instance. Validation will only
|
||||
# be run is this lambda or method returns true.
|
||||
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
||||
def validates_attachment_presence name, options = {}
|
||||
message = options[:message] || "must be set."
|
||||
validates_presence_of :"#{name}_file_name",
|
||||
:message => message,
|
||||
:if => options[:if],
|
||||
:unless => options[:unless]
|
||||
end
|
||||
|
||||
# Places ActiveRecord-style validations on the content type of the file
|
||||
# assigned. The possible options are:
|
||||
# * +content_type+: Allowed content types. Can be a single content type
|
||||
# or an array. Each type can be a String or a Regexp. It should be
|
||||
# noted that Internet Explorer upload files with content_types that you
|
||||
# may not expect. For example, JPEG images are given image/pjpeg and
|
||||
# PNGs are image/x-png, so keep that in mind when determining how you
|
||||
# match. Allows all by default.
|
||||
# * +message+: The message to display when the uploaded file has an invalid
|
||||
# content type.
|
||||
# * +if+: A lambda or name of a method on the instance. Validation will only
|
||||
# be run is this lambda or method returns true.
|
||||
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
||||
# NOTE: If you do not specify an [attachment]_content_type field on your
|
||||
# model, content_type validation will work _ONLY upon assignment_ and
|
||||
# re-validation after the instance has been reloaded will always succeed.
|
||||
def validates_attachment_content_type name, options = {}
|
||||
validation_options = options.dup
|
||||
allowed_types = [validation_options[:content_type]].flatten
|
||||
validates_each(:"#{name}_content_type", validation_options) do |record, attr, value|
|
||||
if !allowed_types.any?{|t| t === value } && !(value.nil? || value.blank?)
|
||||
if record.errors.method(:add).arity == -2
|
||||
message = options[:message] || "is not one of #{allowed_types.join(", ")}"
|
||||
record.errors.add(:"#{name}_content_type", message)
|
||||
else
|
||||
record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the attachment definitions defined by each call to
|
||||
# has_attached_file.
|
||||
def attachment_definitions
|
||||
read_inheritable_attribute(:attachment_definitions)
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods #:nodoc:
|
||||
def attachment_for name
|
||||
@_paperclip_attachments ||= {}
|
||||
@_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name])
|
||||
end
|
||||
|
||||
def each_attachment
|
||||
self.class.attachment_definitions.each do |name, definition|
|
||||
yield(name, attachment_for(name))
|
||||
end
|
||||
end
|
||||
|
||||
def save_attached_files
|
||||
Paperclip.log("Saving attachments.")
|
||||
each_attachment do |name, attachment|
|
||||
attachment.send(:save)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_attached_files
|
||||
Paperclip.log("Deleting attachments.")
|
||||
each_attachment do |name, attachment|
|
||||
attachment.send(:queue_existing_for_delete)
|
||||
attachment.send(:flush_deletes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
340
vendor/plugins/paperclip/lib/paperclip/attachment.rb
vendored
340
vendor/plugins/paperclip/lib/paperclip/attachment.rb
vendored
@ -1,340 +0,0 @@
|
||||
# encoding: utf-8
|
||||
module Paperclip
|
||||
# The Attachment class manages the files for a given attachment. It saves
|
||||
# when the model saves, deletes when the model is destroyed, and processes
|
||||
# the file upon assignment.
|
||||
class Attachment
|
||||
|
||||
def self.default_options
|
||||
@default_options ||= {
|
||||
:url => "/system/:attachment/:id/:style/:filename",
|
||||
:path => ":rails_root/public:url",
|
||||
:styles => {},
|
||||
:processors => [:thumbnail],
|
||||
:convert_options => {},
|
||||
:default_url => "/:attachment/:style/missing.png",
|
||||
:default_style => :original,
|
||||
:storage => :filesystem,
|
||||
:use_timestamp => true,
|
||||
:whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
|
||||
}
|
||||
end
|
||||
|
||||
attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny, :options
|
||||
|
||||
# Creates an Attachment object. +name+ is the name of the attachment,
|
||||
# +instance+ is the ActiveRecord object instance it's attached to, and
|
||||
# +options+ is the same as the hash passed to +has_attached_file+.
|
||||
def initialize name, instance, options = {}
|
||||
@name = name
|
||||
@instance = instance
|
||||
|
||||
options = self.class.default_options.merge(options)
|
||||
|
||||
@url = options[:url]
|
||||
@url = @url.call(self) if @url.is_a?(Proc)
|
||||
@path = options[:path]
|
||||
@path = @path.call(self) if @path.is_a?(Proc)
|
||||
@styles = options[:styles]
|
||||
@normalized_styles = nil
|
||||
@default_url = options[:default_url]
|
||||
@default_style = options[:default_style]
|
||||
@storage = options[:storage]
|
||||
@use_timestamp = options[:use_timestamp]
|
||||
@whiny = options[:whiny_thumbnails] || options[:whiny]
|
||||
@convert_options = options[:convert_options]
|
||||
@processors = options[:processors]
|
||||
@options = options
|
||||
@queued_for_delete = []
|
||||
@queued_for_write = {}
|
||||
@errors = {}
|
||||
@dirty = false
|
||||
|
||||
initialize_storage
|
||||
end
|
||||
|
||||
def styles
|
||||
unless @normalized_styles
|
||||
@normalized_styles = {}
|
||||
(@styles.respond_to?(:call) ? @styles.call(self) : @styles).each do |name, args|
|
||||
@normalized_styles[name] = Paperclip::Style.new(name, args.dup, self)
|
||||
end
|
||||
end
|
||||
@normalized_styles
|
||||
end
|
||||
|
||||
def processors
|
||||
@processors.respond_to?(:call) ? @processors.call(instance) : @processors
|
||||
end
|
||||
|
||||
# What gets called when you call instance.attachment = File. It clears
|
||||
# errors, assigns attributes, and processes the file. It
|
||||
# also queues up the previous file for deletion, to be flushed away on
|
||||
# #save of its host. In addition to form uploads, you can also assign
|
||||
# another Paperclip attachment:
|
||||
# new_user.avatar = old_user.avatar
|
||||
def assign uploaded_file
|
||||
ensure_required_accessors!
|
||||
|
||||
if uploaded_file.is_a?(Paperclip::Attachment)
|
||||
uploaded_file = uploaded_file.to_file(:original)
|
||||
close_uploaded_file = uploaded_file.respond_to?(:close)
|
||||
end
|
||||
|
||||
return nil unless valid_assignment?(uploaded_file)
|
||||
|
||||
uploaded_file.binmode if uploaded_file.respond_to? :binmode
|
||||
self.clear
|
||||
|
||||
return nil if uploaded_file.nil?
|
||||
|
||||
@queued_for_write[:original] = uploaded_file.to_tempfile
|
||||
instance_write(:file_name, uploaded_file.original_filename.strip)
|
||||
instance_write(:content_type, uploaded_file.content_type.to_s.strip)
|
||||
instance_write(:file_size, uploaded_file.size.to_i)
|
||||
instance_write(:fingerprint, uploaded_file.fingerprint)
|
||||
instance_write(:updated_at, Time.now)
|
||||
|
||||
@dirty = true
|
||||
|
||||
post_process
|
||||
|
||||
# Reset the file size if the original file was reprocessed.
|
||||
instance_write(:file_size, @queued_for_write[:original].size.to_i)
|
||||
instance_write(:fingerprint, @queued_for_write[:original].fingerprint)
|
||||
ensure
|
||||
uploaded_file.close if close_uploaded_file
|
||||
end
|
||||
|
||||
# Returns the public URL of the attachment, with a given style. Note that
|
||||
# this does not necessarily need to point to a file that your web server
|
||||
# can access and can point to an action in your app, if you need fine
|
||||
# grained security. This is not recommended if you don't need the
|
||||
# security, however, for performance reasons. Set use_timestamp to false
|
||||
# if you want to stop the attachment update time appended to the url
|
||||
def url(style_name = default_style, use_timestamp = @use_timestamp)
|
||||
url = original_filename.nil? ? interpolate(@default_url, style_name) : interpolate(@url, style_name)
|
||||
use_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url
|
||||
end
|
||||
|
||||
# Returns the path of the attachment as defined by the :path option. If the
|
||||
# file is stored in the filesystem the path refers to the path of the file
|
||||
# on disk. If the file is stored in S3, the path is the "key" part of the
|
||||
# URL, and the :bucket option refers to the S3 bucket.
|
||||
def path style_name = default_style
|
||||
original_filename.nil? ? nil : interpolate(@path, style_name)
|
||||
end
|
||||
|
||||
# Alias to +url+
|
||||
def to_s style_name = nil
|
||||
url(style_name)
|
||||
end
|
||||
|
||||
# Returns an array containing the errors on this attachment.
|
||||
def errors
|
||||
@errors
|
||||
end
|
||||
|
||||
# Returns true if there are changes that need to be saved.
|
||||
def dirty?
|
||||
@dirty
|
||||
end
|
||||
|
||||
# Saves the file, if there are no errors. If there are, it flushes them to
|
||||
# the instance's errors and returns false, cancelling the save.
|
||||
def save
|
||||
flush_deletes
|
||||
flush_writes
|
||||
@dirty = false
|
||||
true
|
||||
end
|
||||
|
||||
# Clears out the attachment. Has the same effect as previously assigning
|
||||
# nil to the attachment. Does NOT save. If you wish to clear AND save,
|
||||
# use #destroy.
|
||||
def clear
|
||||
queue_existing_for_delete
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
# Destroys the attachment. Has the same effect as previously assigning
|
||||
# nil to the attachment *and saving*. This is permanent. If you wish to
|
||||
# wipe out the existing attachment but not save, use #clear.
|
||||
def destroy
|
||||
clear
|
||||
save
|
||||
end
|
||||
|
||||
# Returns the name of the file as originally assigned, and lives in the
|
||||
# <attachment>_file_name attribute of the model.
|
||||
def original_filename
|
||||
instance_read(:file_name)
|
||||
end
|
||||
|
||||
# Returns the size of the file as originally assigned, and lives in the
|
||||
# <attachment>_file_size attribute of the model.
|
||||
def size
|
||||
instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size)
|
||||
end
|
||||
|
||||
# Returns the hash of the file as originally assigned, and lives in the
|
||||
# <attachment>_fingerprint attribute of the model.
|
||||
def fingerprint
|
||||
instance_read(:fingerprint) || (@queued_for_write[:original] && @queued_for_write[:original].fingerprint)
|
||||
end
|
||||
|
||||
# Returns the content_type of the file as originally assigned, and lives
|
||||
# in the <attachment>_content_type attribute of the model.
|
||||
def content_type
|
||||
instance_read(:content_type)
|
||||
end
|
||||
|
||||
# Returns the last modified time of the file as originally assigned, and
|
||||
# lives in the <attachment>_updated_at attribute of the model.
|
||||
def updated_at
|
||||
time = instance_read(:updated_at)
|
||||
time && time.to_f.to_i
|
||||
end
|
||||
|
||||
# Paths and URLs can have a number of variables interpolated into them
|
||||
# to vary the storage location based on name, id, style, class, etc.
|
||||
# This method is a deprecated access into supplying and retrieving these
|
||||
# interpolations. Future access should use either Paperclip.interpolates
|
||||
# or extend the Paperclip::Interpolations module directly.
|
||||
def self.interpolations
|
||||
warn('[DEPRECATION] Paperclip::Attachment.interpolations is deprecated ' +
|
||||
'and will be removed from future versions. ' +
|
||||
'Use Paperclip.interpolates instead')
|
||||
Paperclip::Interpolations
|
||||
end
|
||||
|
||||
# This method really shouldn't be called that often. It's expected use is
|
||||
# in the paperclip:refresh rake task and that's it. It will regenerate all
|
||||
# thumbnails forcefully, by reobtaining the original file and going through
|
||||
# the post-process again.
|
||||
def reprocess!
|
||||
new_original = Tempfile.new("paperclip-reprocess")
|
||||
new_original.binmode
|
||||
if old_original = to_file(:original)
|
||||
new_original.write( old_original.respond_to?(:get) ? old_original.get : old_original.read )
|
||||
new_original.rewind
|
||||
|
||||
@queued_for_write = { :original => new_original }
|
||||
post_process
|
||||
|
||||
old_original.close if old_original.respond_to?(:close)
|
||||
|
||||
save
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Returns true if a file has been assigned.
|
||||
def file?
|
||||
!original_filename.blank?
|
||||
end
|
||||
|
||||
# Writes the attachment-specific attribute on the instance. For example,
|
||||
# instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
|
||||
# "avatar_file_name" field (assuming the attachment is called avatar).
|
||||
def instance_write(attr, value)
|
||||
setter = :"#{name}_#{attr}="
|
||||
responds = instance.respond_to?(setter)
|
||||
self.instance_variable_set("@_#{setter.to_s.chop}", value)
|
||||
instance.send(setter, value) if responds || attr.to_s == "file_name"
|
||||
end
|
||||
|
||||
# Reads the attachment-specific attribute on the instance. See instance_write
|
||||
# for more details.
|
||||
def instance_read(attr)
|
||||
getter = :"#{name}_#{attr}"
|
||||
responds = instance.respond_to?(getter)
|
||||
cached = self.instance_variable_get("@_#{getter}")
|
||||
return cached if cached
|
||||
instance.send(getter) if responds || attr.to_s == "file_name"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_required_accessors! #:nodoc:
|
||||
%w(file_name).each do |field|
|
||||
unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=")
|
||||
raise PaperclipError.new("#{@instance.class} model missing required attr_accessor for '#{name}_#{field}'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def log message #:nodoc:
|
||||
Paperclip.log(message)
|
||||
end
|
||||
|
||||
def valid_assignment? file #:nodoc:
|
||||
file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
|
||||
end
|
||||
|
||||
def initialize_storage #:nodoc:
|
||||
storage_class_name = @storage.to_s.capitalize
|
||||
begin
|
||||
@storage_module = Paperclip::Storage.const_get(storage_class_name)
|
||||
rescue NameError
|
||||
raise StorageMethodNotFound, "Cannot load storage module '#{storage_class_name}'"
|
||||
end
|
||||
self.extend(@storage_module)
|
||||
end
|
||||
|
||||
def extra_options_for(style) #:nodoc:
|
||||
all_options = convert_options[:all]
|
||||
all_options = all_options.call(instance) if all_options.respond_to?(:call)
|
||||
style_options = convert_options[style]
|
||||
style_options = style_options.call(instance) if style_options.respond_to?(:call)
|
||||
|
||||
[ style_options, all_options ].compact.join(" ")
|
||||
end
|
||||
|
||||
def post_process #:nodoc:
|
||||
return if @queued_for_write[:original].nil?
|
||||
instance.run_paperclip_callbacks(:post_process) do
|
||||
instance.run_paperclip_callbacks(:"#{name}_post_process") do
|
||||
post_process_styles
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def post_process_styles #:nodoc:
|
||||
styles.each do |name, style|
|
||||
begin
|
||||
raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
|
||||
@queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
|
||||
Paperclip.processor(processor).make(file, style.processor_options, self)
|
||||
end
|
||||
rescue PaperclipError => e
|
||||
log("An error was received while processing: #{e.inspect}")
|
||||
(@errors[:processing] ||= []) << e.message if @whiny
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def interpolate pattern, style_name = default_style #:nodoc:
|
||||
Paperclip::Interpolations.interpolate(pattern, self, style_name)
|
||||
end
|
||||
|
||||
def queue_existing_for_delete #:nodoc:
|
||||
return unless file?
|
||||
@queued_for_delete += [:original, *styles.keys].uniq.map do |style|
|
||||
path(style) if exists?(style)
|
||||
end.compact
|
||||
instance_write(:file_name, nil)
|
||||
instance_write(:content_type, nil)
|
||||
instance_write(:file_size, nil)
|
||||
instance_write(:updated_at, nil)
|
||||
end
|
||||
|
||||
def flush_errors #:nodoc:
|
||||
@errors.each do |error, message|
|
||||
[message].flatten.each {|m| instance.errors.add(name, m) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@ -1,61 +0,0 @@
|
||||
module Paperclip
|
||||
module CallbackCompatability
|
||||
module Rails21
|
||||
def self.included(base)
|
||||
base.extend(Defining)
|
||||
base.send(:include, Running)
|
||||
end
|
||||
|
||||
module Defining
|
||||
def define_paperclip_callbacks(*args)
|
||||
args.each do |callback|
|
||||
define_callbacks("before_#{callback}")
|
||||
define_callbacks("after_#{callback}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Running
|
||||
def run_paperclip_callbacks(callback, opts = nil, &blk)
|
||||
# The overall structure of this isn't ideal since after callbacks run even if
|
||||
# befores return false. But this is how rails 3's callbacks work, unfortunately.
|
||||
if run_callbacks(:"before_#{callback}"){ |result, object| result == false } != false
|
||||
blk.call
|
||||
end
|
||||
run_callbacks(:"after_#{callback}"){ |result, object| result == false }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Rails3
|
||||
def self.included(base)
|
||||
base.extend(Defining)
|
||||
base.send(:include, Running)
|
||||
end
|
||||
|
||||
module Defining
|
||||
def define_paperclip_callbacks(*callbacks)
|
||||
define_callbacks *[callbacks, {:terminator => "result == false"}].flatten
|
||||
callbacks.each do |callback|
|
||||
eval <<-end_callbacks
|
||||
def before_#{callback}(*args, &blk)
|
||||
set_callback(:#{callback}, :before, *args, &blk)
|
||||
end
|
||||
def after_#{callback}(*args, &blk)
|
||||
set_callback(:#{callback}, :after, *args, &blk)
|
||||
end
|
||||
end_callbacks
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Running
|
||||
def run_paperclip_callbacks(callback, opts = nil, &block)
|
||||
run_callbacks(callback, opts, &block)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@ -1,80 +0,0 @@
|
||||
module Paperclip
|
||||
class CommandLine
|
||||
class << self
|
||||
attr_accessor :path
|
||||
end
|
||||
|
||||
def initialize(binary, params = "", options = {})
|
||||
@binary = binary.dup
|
||||
@params = params.dup
|
||||
@options = options.dup
|
||||
@swallow_stderr = @options.has_key?(:swallow_stderr) ? @options.delete(:swallow_stderr) : Paperclip.options[:swallow_stderr]
|
||||
@expected_outcodes = @options.delete(:expected_outcodes)
|
||||
@expected_outcodes ||= [0]
|
||||
end
|
||||
|
||||
def command
|
||||
cmd = []
|
||||
cmd << full_path(@binary)
|
||||
cmd << interpolate(@params, @options)
|
||||
cmd << bit_bucket if @swallow_stderr
|
||||
cmd.join(" ")
|
||||
end
|
||||
|
||||
def run
|
||||
Paperclip.log(command)
|
||||
begin
|
||||
output = self.class.send(:'`', command)
|
||||
rescue Errno::ENOENT
|
||||
raise Paperclip::CommandNotFoundError
|
||||
end
|
||||
if $?.exitstatus == 127
|
||||
raise Paperclip::CommandNotFoundError
|
||||
end
|
||||
unless @expected_outcodes.include?($?.exitstatus)
|
||||
raise Paperclip::PaperclipCommandLineError, "Command '#{command}' returned #{$?.exitstatus}. Expected #{@expected_outcodes.join(", ")}"
|
||||
end
|
||||
output
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def full_path(binary)
|
||||
[self.class.path, binary].compact.join("/")
|
||||
end
|
||||
|
||||
def interpolate(pattern, vars)
|
||||
# interpolates :variables and :{variables}
|
||||
pattern.gsub(%r#:(?:\w+|\{\w+\})#) do |match|
|
||||
key = match[1..-1]
|
||||
key = key[1..-2] if key[0,1] == '{'
|
||||
if invalid_variables.include?(key)
|
||||
raise PaperclipCommandLineError,
|
||||
"Interpolation of #{key} isn't allowed."
|
||||
end
|
||||
shell_quote(vars[key.to_sym])
|
||||
end
|
||||
end
|
||||
|
||||
def invalid_variables
|
||||
%w(expected_outcodes swallow_stderr)
|
||||
end
|
||||
|
||||
def shell_quote(string)
|
||||
return "" if string.nil? or string.blank?
|
||||
if self.class.unix?
|
||||
string.split("'").map{|m| "'#{m}'" }.join("\\'")
|
||||
else
|
||||
%{"#{string}"}
|
||||
end
|
||||
end
|
||||
|
||||
def bit_bucket
|
||||
self.class.unix? ? "2>/dev/null" : "2>NUL"
|
||||
end
|
||||
|
||||
def self.unix?
|
||||
File.exist?("/dev/null")
|
||||
end
|
||||
end
|
||||
end
|
||||
115
vendor/plugins/paperclip/lib/paperclip/geometry.rb
vendored
115
vendor/plugins/paperclip/lib/paperclip/geometry.rb
vendored
@ -1,115 +0,0 @@
|
||||
module Paperclip
|
||||
|
||||
# Defines the geometry of an image.
|
||||
class Geometry
|
||||
attr_accessor :height, :width, :modifier
|
||||
|
||||
# Gives a Geometry representing the given height and width
|
||||
def initialize width = nil, height = nil, modifier = nil
|
||||
@height = height.to_f
|
||||
@width = width.to_f
|
||||
@modifier = modifier
|
||||
end
|
||||
|
||||
# Uses ImageMagick to determing the dimensions of a file, passed in as either a
|
||||
# File or path.
|
||||
def self.from_file file
|
||||
file = file.path if file.respond_to? "path"
|
||||
geometry = begin
|
||||
Paperclip.run("identify", "-format %wx%h :file", :file => "#{file}[0]")
|
||||
rescue PaperclipCommandLineError
|
||||
""
|
||||
end
|
||||
parse(geometry) ||
|
||||
raise(NotIdentifiedByImageMagickError.new("#{file} is not recognized by the 'identify' command."))
|
||||
end
|
||||
|
||||
# Parses a "WxH" formatted string, where W is the width and H is the height.
|
||||
def self.parse string
|
||||
if match = (string && string.match(/\b(\d*)x?(\d*)\b([\>\<\#\@\%^!])?/i))
|
||||
Geometry.new(*match[1,3])
|
||||
end
|
||||
end
|
||||
|
||||
# True if the dimensions represent a square
|
||||
def square?
|
||||
height == width
|
||||
end
|
||||
|
||||
# True if the dimensions represent a horizontal rectangle
|
||||
def horizontal?
|
||||
height < width
|
||||
end
|
||||
|
||||
# True if the dimensions represent a vertical rectangle
|
||||
def vertical?
|
||||
height > width
|
||||
end
|
||||
|
||||
# The aspect ratio of the dimensions.
|
||||
def aspect
|
||||
width / height
|
||||
end
|
||||
|
||||
# Returns the larger of the two dimensions
|
||||
def larger
|
||||
[height, width].max
|
||||
end
|
||||
|
||||
# Returns the smaller of the two dimensions
|
||||
def smaller
|
||||
[height, width].min
|
||||
end
|
||||
|
||||
# Returns the width and height in a format suitable to be passed to Geometry.parse
|
||||
def to_s
|
||||
s = ""
|
||||
s << width.to_i.to_s if width > 0
|
||||
s << "x#{height.to_i}" if height > 0
|
||||
s << modifier.to_s
|
||||
s
|
||||
end
|
||||
|
||||
# Same as to_s
|
||||
def inspect
|
||||
to_s
|
||||
end
|
||||
|
||||
# Returns the scaling and cropping geometries (in string-based ImageMagick format)
|
||||
# neccessary to transform this Geometry into the Geometry given. If crop is true,
|
||||
# then it is assumed the destination Geometry will be the exact final resolution.
|
||||
# In this case, the source Geometry is scaled so that an image containing the
|
||||
# destination Geometry would be completely filled by the source image, and any
|
||||
# overhanging image would be cropped. Useful for square thumbnail images. The cropping
|
||||
# is weighted at the center of the Geometry.
|
||||
def transformation_to dst, crop = false
|
||||
if crop
|
||||
ratio = Geometry.new( dst.width / self.width, dst.height / self.height )
|
||||
scale_geometry, scale = scaling(dst, ratio)
|
||||
crop_geometry = cropping(dst, ratio, scale)
|
||||
else
|
||||
scale_geometry = dst.to_s
|
||||
end
|
||||
|
||||
[ scale_geometry, crop_geometry ]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scaling dst, ratio
|
||||
if ratio.horizontal? || ratio.square?
|
||||
[ "%dx" % dst.width, ratio.width ]
|
||||
else
|
||||
[ "x%d" % dst.height, ratio.height ]
|
||||
end
|
||||
end
|
||||
|
||||
def cropping dst, ratio, scale
|
||||
if ratio.horizontal? || ratio.square?
|
||||
"%dx%d+%d+%d" % [ dst.width, dst.height, 0, (self.height * scale - dst.height) / 2 ]
|
||||
else
|
||||
"%dx%d+%d+%d" % [ dst.width, dst.height, (self.width * scale - dst.width) / 2, 0 ]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,113 +0,0 @@
|
||||
module Paperclip
|
||||
# This module contains all the methods that are available for interpolation
|
||||
# in paths and urls. To add your own (or override an existing one), you
|
||||
# can either open this module and define it, or call the
|
||||
# Paperclip.interpolates method.
|
||||
module Interpolations
|
||||
extend self
|
||||
|
||||
# Hash assignment of interpolations. Included only for compatability,
|
||||
# and is not intended for normal use.
|
||||
def self.[]= name, block
|
||||
define_method(name, &block)
|
||||
end
|
||||
|
||||
# Hash access of interpolations. Included only for compatability,
|
||||
# and is not intended for normal use.
|
||||
def self.[] name
|
||||
method(name)
|
||||
end
|
||||
|
||||
# Returns a sorted list of all interpolations.
|
||||
def self.all
|
||||
self.instance_methods(false).sort
|
||||
end
|
||||
|
||||
# Perform the actual interpolation. Takes the pattern to interpolate
|
||||
# and the arguments to pass, which are the attachment and style name.
|
||||
def self.interpolate pattern, *args
|
||||
all.reverse.inject( pattern.dup ) do |result, tag|
|
||||
result.gsub(/:#{tag}/) do |match|
|
||||
send( tag, *args )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the filename, the same way as ":basename.:extension" would.
|
||||
def filename attachment, style_name
|
||||
"#{basename(attachment, style_name)}.#{extension(attachment, style_name)}"
|
||||
end
|
||||
|
||||
# Returns the interpolated URL. Will raise an error if the url itself
|
||||
# contains ":url" to prevent infinite recursion. This interpolation
|
||||
# is used in the default :path to ease default specifications.
|
||||
def url attachment, style_name
|
||||
raise InfiniteInterpolationError if caller.any?{|b| b.index("#{__FILE__}:#{__LINE__ + 1}") }
|
||||
attachment.url(style_name, false)
|
||||
end
|
||||
|
||||
# Returns the timestamp as defined by the <attachment>_updated_at field
|
||||
def timestamp attachment, style_name
|
||||
attachment.instance_read(:updated_at).to_s
|
||||
end
|
||||
|
||||
# Returns the Rails.root constant.
|
||||
def rails_root attachment, style_name
|
||||
Rails.root
|
||||
end
|
||||
|
||||
# Returns the Rails.env constant.
|
||||
def rails_env attachment, style_name
|
||||
Rails.env
|
||||
end
|
||||
|
||||
# Returns the underscored, pluralized version of the class name.
|
||||
# e.g. "users" for the User class.
|
||||
# NOTE: The arguments need to be optional, because some tools fetch
|
||||
# all class names. Calling #class will return the expected class.
|
||||
def class attachment = nil, style_name = nil
|
||||
return super() if attachment.nil? && style_name.nil?
|
||||
attachment.instance.class.to_s.underscore.pluralize
|
||||
end
|
||||
|
||||
# Returns the basename of the file. e.g. "file" for "file.jpg"
|
||||
def basename attachment, style_name
|
||||
attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "")
|
||||
end
|
||||
|
||||
# Returns the extension of the file. e.g. "jpg" for "file.jpg"
|
||||
# If the style has a format defined, it will return the format instead
|
||||
# of the actual extension.
|
||||
def extension attachment, style_name
|
||||
((style = attachment.styles[style_name]) && style[:format]) ||
|
||||
File.extname(attachment.original_filename).gsub(/^\.+/, "")
|
||||
end
|
||||
|
||||
# Returns the id of the instance.
|
||||
def id attachment, style_name
|
||||
attachment.instance.id
|
||||
end
|
||||
|
||||
# Returns the fingerprint of the instance.
|
||||
def fingerprint attachment, style_name
|
||||
attachment.fingerprint
|
||||
end
|
||||
|
||||
# Returns the id of the instance in a split path form. e.g. returns
|
||||
# 000/001/234 for an id of 1234.
|
||||
def id_partition attachment, style_name
|
||||
("%09d" % attachment.instance.id).scan(/\d{3}/).join("/")
|
||||
end
|
||||
|
||||
# Returns the pluralized form of the attachment name. e.g.
|
||||
# "avatars" for an attachment of :avatar
|
||||
def attachment attachment, style_name
|
||||
attachment.name.to_s.downcase.pluralize
|
||||
end
|
||||
|
||||
# Returns the style, or the default style if nil is supplied.
|
||||
def style attachment, style_name
|
||||
style_name || attachment.default_style
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,59 +0,0 @@
|
||||
# Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying
|
||||
# and Tempfile conversion.
|
||||
module IOStream
|
||||
|
||||
# Returns a Tempfile containing the contents of the readable object.
|
||||
def to_tempfile
|
||||
name = respond_to?(:original_filename) ? original_filename : (respond_to?(:path) ? path : "stream")
|
||||
tempfile = Paperclip::Tempfile.new(["stream", File.extname(name)])
|
||||
tempfile.binmode
|
||||
self.stream_to(tempfile)
|
||||
end
|
||||
|
||||
# Copies one read-able object from one place to another in blocks, obviating the need to load
|
||||
# the whole thing into memory. Defaults to 8k blocks. If this module is included in both
|
||||
# StringIO and Tempfile, then either can have its data copied anywhere else without typing
|
||||
# worries or memory overhead worries. Returns a File if a String is passed in as the destination
|
||||
# and returns the IO or Tempfile as passed in if one is sent as the destination.
|
||||
def stream_to path_or_file, in_blocks_of = 8192
|
||||
dstio = case path_or_file
|
||||
when String then File.new(path_or_file, "wb+")
|
||||
when IO then path_or_file
|
||||
when Tempfile then path_or_file
|
||||
end
|
||||
buffer = ""
|
||||
self.rewind
|
||||
while self.read(in_blocks_of, buffer) do
|
||||
dstio.write(buffer)
|
||||
end
|
||||
dstio.rewind
|
||||
dstio
|
||||
end
|
||||
end
|
||||
|
||||
class IO #:nodoc:
|
||||
include IOStream
|
||||
end
|
||||
|
||||
%w( Tempfile StringIO ).each do |klass|
|
||||
if Object.const_defined? klass
|
||||
Object.const_get(klass).class_eval do
|
||||
include IOStream
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Corrects a bug in Windows when asking for Tempfile size.
|
||||
if defined? Tempfile
|
||||
class Tempfile
|
||||
def size
|
||||
if @tmpfile
|
||||
@tmpfile.fsync
|
||||
@tmpfile.flush
|
||||
@tmpfile.stat.size
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,33 +0,0 @@
|
||||
require 'paperclip/matchers/have_attached_file_matcher'
|
||||
require 'paperclip/matchers/validate_attachment_presence_matcher'
|
||||
require 'paperclip/matchers/validate_attachment_content_type_matcher'
|
||||
require 'paperclip/matchers/validate_attachment_size_matcher'
|
||||
|
||||
module Paperclip
|
||||
module Shoulda
|
||||
# Provides rspec-compatible matchers for testing Paperclip attachments.
|
||||
#
|
||||
# In spec_helper.rb, you'll need to require the matchers:
|
||||
#
|
||||
# require "paperclip/matchers"
|
||||
#
|
||||
# And include the module:
|
||||
#
|
||||
# Spec::Runner.configure do |config|
|
||||
# config.include Paperclip::Shoulda::Matchers
|
||||
# end
|
||||
#
|
||||
# Example:
|
||||
# describe User do
|
||||
# it { should have_attached_file(:avatar) }
|
||||
# it { should validate_attachment_presence(:avatar) }
|
||||
# it { should validate_attachment_content_type(:avatar).
|
||||
# allowing('image/png', 'image/gif').
|
||||
# rejecting('text/plain', 'text/xml') }
|
||||
# it { should validate_attachment_size(:avatar).
|
||||
# less_than(2.megabytes) }
|
||||
# end
|
||||
module Matchers
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,57 +0,0 @@
|
||||
module Paperclip
|
||||
module Shoulda
|
||||
module Matchers
|
||||
# Ensures that the given instance or class has an attachment with the
|
||||
# given name.
|
||||
#
|
||||
# Example:
|
||||
# describe User do
|
||||
# it { should have_attached_file(:avatar) }
|
||||
# end
|
||||
def have_attached_file name
|
||||
HaveAttachedFileMatcher.new(name)
|
||||
end
|
||||
|
||||
class HaveAttachedFileMatcher
|
||||
def initialize attachment_name
|
||||
@attachment_name = attachment_name
|
||||
end
|
||||
|
||||
def matches? subject
|
||||
@subject = subject
|
||||
@subject = @subject.class unless Class === @subject
|
||||
responds? && has_column? && included?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Should have an attachment named #{@attachment_name}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Should not have an attachment named #{@attachment_name}"
|
||||
end
|
||||
|
||||
def description
|
||||
"have an attachment named #{@attachment_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def responds?
|
||||
methods = @subject.instance_methods.map(&:to_s)
|
||||
methods.include?("#{@attachment_name}") &&
|
||||
methods.include?("#{@attachment_name}=") &&
|
||||
methods.include?("#{@attachment_name}?")
|
||||
end
|
||||
|
||||
def has_column?
|
||||
@subject.column_names.include?("#{@attachment_name}_file_name")
|
||||
end
|
||||
|
||||
def included?
|
||||
@subject.ancestors.include?(Paperclip::InstanceMethods)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,75 +0,0 @@
|
||||
module Paperclip
|
||||
module Shoulda
|
||||
module Matchers
|
||||
# Ensures that the given instance or class validates the content type of
|
||||
# the given attachment as specified.
|
||||
#
|
||||
# Example:
|
||||
# describe User do
|
||||
# it { should validate_attachment_content_type(:icon).
|
||||
# allowing('image/png', 'image/gif').
|
||||
# rejecting('text/plain', 'text/xml') }
|
||||
# end
|
||||
def validate_attachment_content_type name
|
||||
ValidateAttachmentContentTypeMatcher.new(name)
|
||||
end
|
||||
|
||||
class ValidateAttachmentContentTypeMatcher
|
||||
def initialize attachment_name
|
||||
@attachment_name = attachment_name
|
||||
end
|
||||
|
||||
def allowing *types
|
||||
@allowed_types = types.flatten
|
||||
self
|
||||
end
|
||||
|
||||
def rejecting *types
|
||||
@rejected_types = types.flatten
|
||||
self
|
||||
end
|
||||
|
||||
def matches? subject
|
||||
@subject = subject
|
||||
@subject = @subject.class unless Class === @subject
|
||||
@allowed_types && @rejected_types &&
|
||||
allowed_types_allowed? && rejected_types_rejected?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Content types #{@allowed_types.join(", ")} should be accepted" +
|
||||
" and #{@rejected_types.join(", ")} rejected by #{@attachment_name}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Content types #{@allowed_types.join(", ")} should be rejected" +
|
||||
" and #{@rejected_types.join(", ")} accepted by #{@attachment_name}"
|
||||
end
|
||||
|
||||
def description
|
||||
"validate the content types allowed on attachment #{@attachment_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def allow_types?(types)
|
||||
types.all? do |type|
|
||||
file = StringIO.new(".")
|
||||
file.content_type = type
|
||||
(subject = @subject.new).attachment_for(@attachment_name).assign(file)
|
||||
subject.valid?
|
||||
subject.errors[:"#{@attachment_name}_content_type"].blank?
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_types_allowed?
|
||||
allow_types?(@allowed_types)
|
||||
end
|
||||
|
||||
def rejected_types_rejected?
|
||||
not allow_types?(@rejected_types)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,54 +0,0 @@
|
||||
module Paperclip
|
||||
module Shoulda
|
||||
module Matchers
|
||||
# Ensures that the given instance or class validates the presence of the
|
||||
# given attachment.
|
||||
#
|
||||
# describe User do
|
||||
# it { should validate_attachment_presence(:avatar) }
|
||||
# end
|
||||
def validate_attachment_presence name
|
||||
ValidateAttachmentPresenceMatcher.new(name)
|
||||
end
|
||||
|
||||
class ValidateAttachmentPresenceMatcher
|
||||
def initialize attachment_name
|
||||
@attachment_name = attachment_name
|
||||
end
|
||||
|
||||
def matches? subject
|
||||
@subject = subject
|
||||
@subject = @subject.class unless Class === @subject
|
||||
error_when_not_valid? && no_error_when_valid?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Attachment #{@attachment_name} should be required"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Attachment #{@attachment_name} should not be required"
|
||||
end
|
||||
|
||||
def description
|
||||
"require presence of attachment #{@attachment_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def error_when_not_valid?
|
||||
(subject = @subject.new).send(@attachment_name).assign(nil)
|
||||
subject.valid?
|
||||
not subject.errors[:"#{@attachment_name}_file_name"].blank?
|
||||
end
|
||||
|
||||
def no_error_when_valid?
|
||||
@file = StringIO.new(".")
|
||||
(subject = @subject.new).send(@attachment_name).assign(@file)
|
||||
subject.valid?
|
||||
subject.errors[:"#{@attachment_name}_file_name"].blank?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,95 +0,0 @@
|
||||
module Paperclip
|
||||
module Shoulda
|
||||
module Matchers
|
||||
# Ensures that the given instance or class validates the size of the
|
||||
# given attachment as specified.
|
||||
#
|
||||
# Examples:
|
||||
# it { should validate_attachment_size(:avatar).
|
||||
# less_than(2.megabytes) }
|
||||
# it { should validate_attachment_size(:icon).
|
||||
# greater_than(1024) }
|
||||
# it { should validate_attachment_size(:icon).
|
||||
# in(0..100) }
|
||||
def validate_attachment_size name
|
||||
ValidateAttachmentSizeMatcher.new(name)
|
||||
end
|
||||
|
||||
class ValidateAttachmentSizeMatcher
|
||||
def initialize attachment_name
|
||||
@attachment_name = attachment_name
|
||||
@low, @high = 0, (1.0/0)
|
||||
end
|
||||
|
||||
def less_than size
|
||||
@high = size
|
||||
self
|
||||
end
|
||||
|
||||
def greater_than size
|
||||
@low = size
|
||||
self
|
||||
end
|
||||
|
||||
def in range
|
||||
@low, @high = range.first, range.last
|
||||
self
|
||||
end
|
||||
|
||||
def matches? subject
|
||||
@subject = subject
|
||||
@subject = @subject.class unless Class === @subject
|
||||
lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes"
|
||||
end
|
||||
|
||||
def description
|
||||
"validate the size of attachment #{@attachment_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def override_method object, method, &replacement
|
||||
(class << object; self; end).class_eval do
|
||||
define_method(method, &replacement)
|
||||
end
|
||||
end
|
||||
|
||||
def passes_validation_with_size(new_size)
|
||||
file = StringIO.new(".")
|
||||
override_method(file, :size){ new_size }
|
||||
override_method(file, :to_tempfile){ file }
|
||||
|
||||
(subject = @subject.new).send(@attachment_name).assign(file)
|
||||
subject.valid?
|
||||
subject.errors[:"#{@attachment_name}_file_size"].blank?
|
||||
end
|
||||
|
||||
def lower_than_low?
|
||||
not passes_validation_with_size(@low - 1)
|
||||
end
|
||||
|
||||
def higher_than_low?
|
||||
passes_validation_with_size(@low + 1)
|
||||
end
|
||||
|
||||
def lower_than_high?
|
||||
return true if @high == (1.0/0)
|
||||
passes_validation_with_size(@high - 1)
|
||||
end
|
||||
|
||||
def higher_than_high?
|
||||
return true if @high == (1.0/0)
|
||||
not passes_validation_with_size(@high + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,58 +0,0 @@
|
||||
module Paperclip
|
||||
# Paperclip processors allow you to modify attached files when they are
|
||||
# attached in any way you are able. Paperclip itself uses command-line
|
||||
# programs for its included Thumbnail processor, but custom processors
|
||||
# are not required to follow suit.
|
||||
#
|
||||
# Processors are required to be defined inside the Paperclip module and
|
||||
# are also required to be a subclass of Paperclip::Processor. There is
|
||||
# only one method you *must* implement to properly be a subclass:
|
||||
# #make, but #initialize may also be of use. Both methods accept 3
|
||||
# arguments: the file that will be operated on (which is an instance of
|
||||
# File), a hash of options that were defined in has_attached_file's
|
||||
# style hash, and the Paperclip::Attachment itself.
|
||||
#
|
||||
# All #make needs to return is an instance of File (Tempfile is
|
||||
# acceptable) which contains the results of the processing.
|
||||
#
|
||||
# See Paperclip.run for more information about using command-line
|
||||
# utilities from within Processors.
|
||||
class Processor
|
||||
attr_accessor :file, :options, :attachment
|
||||
|
||||
def initialize file, options = {}, attachment = nil
|
||||
@file = file
|
||||
@options = options
|
||||
@attachment = attachment
|
||||
end
|
||||
|
||||
def make
|
||||
end
|
||||
|
||||
def self.make file, options = {}, attachment = nil
|
||||
new(file, options, attachment).make
|
||||
end
|
||||
end
|
||||
|
||||
# Due to how ImageMagick handles its image format conversion and how Tempfile
|
||||
# handles its naming scheme, it is necessary to override how Tempfile makes
|
||||
# its names so as to allow for file extensions. Idea taken from the comments
|
||||
# on this blog post:
|
||||
# http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
|
||||
class Tempfile < ::Tempfile
|
||||
# This is Ruby 1.8.7's implementation.
|
||||
if RUBY_VERSION <= "1.8.6"
|
||||
def make_tmpname(basename, n)
|
||||
case basename
|
||||
when Array
|
||||
prefix, suffix = *basename
|
||||
else
|
||||
prefix, suffix = basename, ''
|
||||
end
|
||||
|
||||
t = Time.now.strftime("%y%m%d")
|
||||
path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,24 +0,0 @@
|
||||
require 'paperclip'
|
||||
|
||||
module Paperclip
|
||||
if defined? Rails::Railtie
|
||||
require 'rails'
|
||||
class Railtie < Rails::Railtie
|
||||
initializer 'paperclip.insert_into_active_record' do
|
||||
ActiveSupport.on_load :active_record do
|
||||
Paperclip::Railtie.insert
|
||||
end
|
||||
end
|
||||
rake_tasks do
|
||||
load "tasks/paperclip.rake"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Railtie
|
||||
def self.insert
|
||||
ActiveRecord::Base.send(:include, Paperclip::Glue)
|
||||
File.send(:include, Paperclip::Upfile)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,2 +0,0 @@
|
||||
require "paperclip/storage/filesystem"
|
||||
require "paperclip/storage/s3"
|
||||
@ -1,73 +0,0 @@
|
||||
module Paperclip
|
||||
module Storage
|
||||
# The default place to store attachments is in the filesystem. Files on the local
|
||||
# filesystem can be very easily served by Apache without requiring a hit to your app.
|
||||
# They also can be processed more easily after they've been saved, as they're just
|
||||
# normal files. There is one Filesystem-specific option for has_attached_file.
|
||||
# * +path+: The location of the repository of attachments on disk. This can (and, in
|
||||
# almost all cases, should) be coordinated with the value of the +url+ option to
|
||||
# allow files to be saved into a place where Apache can serve them without
|
||||
# hitting your app. Defaults to
|
||||
# ":rails_root/public/:attachment/:id/:style/:basename.:extension"
|
||||
# By default this places the files in the app's public directory which can be served
|
||||
# directly. If you are using capistrano for deployment, a good idea would be to
|
||||
# make a symlink to the capistrano-created system directory from inside your app's
|
||||
# public directory.
|
||||
# See Paperclip::Attachment#interpolate for more information on variable interpolaton.
|
||||
# :path => "/var/app/attachments/:class/:id/:style/:basename.:extension"
|
||||
module Filesystem
|
||||
def self.extended base
|
||||
end
|
||||
|
||||
def exists?(style_name = default_style)
|
||||
if original_filename
|
||||
File.exist?(path(style_name))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Returns representation of the data of the file assigned to the given
|
||||
# style, in the format most representative of the current storage.
|
||||
def to_file style_name = default_style
|
||||
@queued_for_write[style_name] || (File.new(path(style_name), 'rb') if exists?(style_name))
|
||||
end
|
||||
|
||||
def flush_writes #:nodoc:
|
||||
@queued_for_write.each do |style_name, file|
|
||||
file.close
|
||||
FileUtils.mkdir_p(File.dirname(path(style_name)))
|
||||
log("saving #{path(style_name)}")
|
||||
FileUtils.mv(file.path, path(style_name))
|
||||
FileUtils.chmod(0644, path(style_name))
|
||||
end
|
||||
@queued_for_write = {}
|
||||
end
|
||||
|
||||
def flush_deletes #:nodoc:
|
||||
@queued_for_delete.each do |path|
|
||||
begin
|
||||
log("deleting #{path}")
|
||||
FileUtils.rm(path) if File.exist?(path)
|
||||
rescue Errno::ENOENT => e
|
||||
# ignore file-not-found, let everything else pass
|
||||
end
|
||||
begin
|
||||
while(true)
|
||||
path = File.dirname(path)
|
||||
FileUtils.rmdir(path)
|
||||
break if File.exists?(path) # Ruby 1.9.2 does not raise if the removal failed.
|
||||
end
|
||||
rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR
|
||||
# Stop trying to remove parent directories
|
||||
rescue SystemCallError => e
|
||||
log("There was an unexpected error while deleting directories: #{e.class}")
|
||||
# Ignore it
|
||||
end
|
||||
end
|
||||
@queued_for_delete = []
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
191
vendor/plugins/paperclip/lib/paperclip/storage/s3.rb
vendored
191
vendor/plugins/paperclip/lib/paperclip/storage/s3.rb
vendored
@ -1,191 +0,0 @@
|
||||
module Paperclip
|
||||
module Storage
|
||||
# Amazon's S3 file hosting service is a scalable, easy place to store files for
|
||||
# distribution. You can find out more about it at http://aws.amazon.com/s3
|
||||
# There are a few S3-specific options for has_attached_file:
|
||||
# * +s3_credentials+: Takes a path, a File, or a Hash. The path (or File) must point
|
||||
# to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
|
||||
# gives you. You can 'environment-space' this just like you do to your
|
||||
# database.yml file, so different environments can use different accounts:
|
||||
# development:
|
||||
# access_key_id: 123...
|
||||
# secret_access_key: 123...
|
||||
# test:
|
||||
# access_key_id: abc...
|
||||
# secret_access_key: abc...
|
||||
# production:
|
||||
# access_key_id: 456...
|
||||
# secret_access_key: 456...
|
||||
# This is not required, however, and the file may simply look like this:
|
||||
# access_key_id: 456...
|
||||
# secret_access_key: 456...
|
||||
# In which case, those access keys will be used in all environments. You can also
|
||||
# put your bucket name in this file, instead of adding it to the code directly.
|
||||
# This is useful when you want the same account but a different bucket for
|
||||
# development versus production.
|
||||
# * +s3_permissions+: This is a String that should be one of the "canned" access
|
||||
# policies that S3 provides (more information can be found here:
|
||||
# http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html#RESTCannedAccessPolicies)
|
||||
# The default for Paperclip is :public_read.
|
||||
# * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
|
||||
# 'http' or 'https'. Defaults to 'http' when your :s3_permissions are :public_read (the
|
||||
# default), and 'https' when your :s3_permissions are anything else.
|
||||
# * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate}
|
||||
# * +bucket+: This is the name of the S3 bucket that will store your files. Remember
|
||||
# that the bucket must be unique across all of Amazon S3. If the bucket does not exist
|
||||
# Paperclip will attempt to create it. The bucket name will not be interpolated.
|
||||
# You can define the bucket as a Proc if you want to determine it's name at runtime.
|
||||
# Paperclip will call that Proc with attachment as the only argument.
|
||||
# * +s3_host_alias+: The fully-qualified domain name (FQDN) that is the alias to the
|
||||
# S3 domain of your bucket. Used with the :s3_alias_url url interpolation. See the
|
||||
# link in the +url+ entry for more information about S3 domains and buckets.
|
||||
# * +url+: There are three options for the S3 url. You can choose to have the bucket's name
|
||||
# placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket).
|
||||
# Lastly, you can specify a CNAME (which requires the CNAME to be specified as
|
||||
# :s3_alias_url. You can read more about CNAMEs and S3 at
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/index.html?VirtualHosting.html
|
||||
# Normally, this won't matter in the slightest and you can leave the default (which is
|
||||
# path-style, or :s3_path_url). But in some cases paths don't work and you need to use
|
||||
# the domain-style (:s3_domain_url). Anything else here will be treated like path-style.
|
||||
# NOTE: If you use a CNAME for use with CloudFront, you can NOT specify https as your
|
||||
# :s3_protocol; This is *not supported* by S3/CloudFront. Finally, when using the host
|
||||
# alias, the :bucket parameter is ignored, as the hostname is used as the bucket name
|
||||
# by S3.
|
||||
# * +path+: This is the key under the bucket in which the file will be stored. The
|
||||
# URL will be constructed from the bucket and the path. This is what you will want
|
||||
# to interpolate. Keys should be unique, like filenames, and despite the fact that
|
||||
# S3 (strictly speaking) does not support directories, you can still use a / to
|
||||
# separate parts of your file name.
|
||||
module S3
|
||||
def self.extended base
|
||||
begin
|
||||
require 'aws/s3'
|
||||
rescue LoadError => e
|
||||
e.message << " (You may need to install the aws-s3 gem)"
|
||||
raise e
|
||||
end
|
||||
|
||||
base.instance_eval do
|
||||
@s3_credentials = parse_credentials(@options[:s3_credentials])
|
||||
@bucket = @options[:bucket] || @s3_credentials[:bucket]
|
||||
@bucket = @bucket.call(self) if @bucket.is_a?(Proc)
|
||||
@s3_options = @options[:s3_options] || {}
|
||||
@s3_permissions = @options[:s3_permissions] || :public_read
|
||||
@s3_protocol = @options[:s3_protocol] || (@s3_permissions == :public_read ? 'http' : 'https')
|
||||
@s3_headers = @options[:s3_headers] || {}
|
||||
@s3_host_alias = @options[:s3_host_alias]
|
||||
unless @url.to_s.match(/^:s3.*url$/)
|
||||
@path = @path.gsub(/:url/, @url)
|
||||
@url = ":s3_path_url"
|
||||
end
|
||||
AWS::S3::Base.establish_connection!( @s3_options.merge(
|
||||
:access_key_id => @s3_credentials[:access_key_id],
|
||||
:secret_access_key => @s3_credentials[:secret_access_key]
|
||||
))
|
||||
end
|
||||
Paperclip.interpolates(:s3_alias_url) do |attachment, style|
|
||||
"#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
||||
end
|
||||
Paperclip.interpolates(:s3_path_url) do |attachment, style|
|
||||
"#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
||||
end
|
||||
Paperclip.interpolates(:s3_domain_url) do |attachment, style|
|
||||
"#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
|
||||
end
|
||||
end
|
||||
|
||||
def expiring_url(time = 3600)
|
||||
AWS::S3::S3Object.url_for(path, bucket_name, :expires_in => time )
|
||||
end
|
||||
|
||||
def bucket_name
|
||||
@bucket
|
||||
end
|
||||
|
||||
def s3_host_alias
|
||||
@s3_host_alias
|
||||
end
|
||||
|
||||
def parse_credentials creds
|
||||
creds = find_credentials(creds).stringify_keys
|
||||
(creds[Rails.env] || creds).symbolize_keys
|
||||
end
|
||||
|
||||
def exists?(style = default_style)
|
||||
if original_filename
|
||||
AWS::S3::S3Object.exists?(path(style), bucket_name)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def s3_protocol
|
||||
@s3_protocol
|
||||
end
|
||||
|
||||
# Returns representation of the data of the file assigned to the given
|
||||
# style, in the format most representative of the current storage.
|
||||
def to_file style = default_style
|
||||
return @queued_for_write[style] if @queued_for_write[style]
|
||||
filename = path(style).split(".")
|
||||
extname = File.extname(filename)
|
||||
basename = File.basename(filename, extname)
|
||||
file = Tempfile.new(basename, extname)
|
||||
file.write(AWS::S3::S3Object.value(path(style), bucket_name))
|
||||
file.rewind
|
||||
return file
|
||||
end
|
||||
|
||||
def create_bucket
|
||||
AWS::S3::Bucket.create(bucket_name)
|
||||
end
|
||||
|
||||
def flush_writes #:nodoc:
|
||||
@queued_for_write.each do |style, file|
|
||||
begin
|
||||
log("saving #{path(style)}")
|
||||
AWS::S3::S3Object.store(path(style),
|
||||
file,
|
||||
bucket_name,
|
||||
{:content_type => instance_read(:content_type),
|
||||
:access => @s3_permissions,
|
||||
}.merge(@s3_headers))
|
||||
rescue AWS::S3::NoSuchBucket => e
|
||||
create_bucket
|
||||
retry
|
||||
rescue AWS::S3::ResponseError => e
|
||||
raise
|
||||
end
|
||||
end
|
||||
@queued_for_write = {}
|
||||
end
|
||||
|
||||
def flush_deletes #:nodoc:
|
||||
@queued_for_delete.each do |path|
|
||||
begin
|
||||
log("deleting #{path}")
|
||||
AWS::S3::S3Object.delete(path, bucket_name)
|
||||
rescue AWS::S3::ResponseError
|
||||
# Ignore this.
|
||||
end
|
||||
end
|
||||
@queued_for_delete = []
|
||||
end
|
||||
|
||||
def find_credentials creds
|
||||
case creds
|
||||
when File
|
||||
YAML::load(ERB.new(File.read(creds.path)).result)
|
||||
when String, Pathname
|
||||
YAML::load(ERB.new(File.read(creds)).result)
|
||||
when Hash
|
||||
creds
|
||||
else
|
||||
raise ArgumentError, "Credentials are not a path, file, or hash."
|
||||
end
|
||||
end
|
||||
private :find_credentials
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
90
vendor/plugins/paperclip/lib/paperclip/style.rb
vendored
90
vendor/plugins/paperclip/lib/paperclip/style.rb
vendored
@ -1,90 +0,0 @@
|
||||
# encoding: utf-8
|
||||
module Paperclip
|
||||
# The Style class holds the definition of a thumbnail style, applying
|
||||
# whatever processing is required to normalize the definition and delaying
|
||||
# the evaluation of block parameters until useful context is available.
|
||||
|
||||
class Style
|
||||
|
||||
attr_reader :name, :attachment, :format
|
||||
|
||||
# Creates a Style object. +name+ is the name of the attachment,
|
||||
# +definition+ is the style definition from has_attached_file, which
|
||||
# can be string, array or hash
|
||||
def initialize name, definition, attachment
|
||||
@name = name
|
||||
@attachment = attachment
|
||||
if definition.is_a? Hash
|
||||
@geometry = definition.delete(:geometry)
|
||||
@format = definition.delete(:format)
|
||||
@processors = definition.delete(:processors)
|
||||
@other_args = definition
|
||||
else
|
||||
@geometry, @format = [definition, nil].flatten[0..1]
|
||||
@other_args = {}
|
||||
end
|
||||
@format = nil if @format.blank?
|
||||
end
|
||||
|
||||
# retrieves from the attachment the processors defined in the has_attached_file call
|
||||
# (which method (in the attachment) will call any supplied procs)
|
||||
# There is an important change of interface here: a style rule can set its own processors
|
||||
# by default we behave as before, though.
|
||||
def processors
|
||||
@processors || attachment.processors
|
||||
end
|
||||
|
||||
# retrieves from the attachment the whiny setting
|
||||
def whiny
|
||||
attachment.whiny
|
||||
end
|
||||
|
||||
# returns true if we're inclined to grumble
|
||||
def whiny?
|
||||
!!whiny
|
||||
end
|
||||
|
||||
def convert_options
|
||||
attachment.send(:extra_options_for, name)
|
||||
end
|
||||
|
||||
# returns the geometry string for this style
|
||||
# if a proc has been supplied, we call it here
|
||||
def geometry
|
||||
@geometry.respond_to?(:call) ? @geometry.call(attachment.instance) : @geometry
|
||||
end
|
||||
|
||||
# Supplies the hash of options that processors expect to receive as their second argument
|
||||
# Arguments other than the standard geometry, format etc are just passed through from
|
||||
# initialization and any procs are called here, just before post-processing.
|
||||
def processor_options
|
||||
args = {}
|
||||
@other_args.each do |k,v|
|
||||
args[k] = v.respond_to?(:call) ? v.call(attachment) : v
|
||||
end
|
||||
[:processors, :geometry, :format, :whiny, :convert_options].each do |k|
|
||||
(arg = send(k)) && args[k] = arg
|
||||
end
|
||||
args
|
||||
end
|
||||
|
||||
# Supports getting and setting style properties with hash notation to ensure backwards-compatibility
|
||||
# eg. @attachment.styles[:large][:geometry]@ will still work
|
||||
def [](key)
|
||||
if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
|
||||
send(key)
|
||||
elsif defined? @other_args[key]
|
||||
@other_args[key]
|
||||
end
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
|
||||
send("#{key}=".intern, value)
|
||||
else
|
||||
@other_args[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@ -1,79 +0,0 @@
|
||||
module Paperclip
|
||||
# Handles thumbnailing images that are uploaded.
|
||||
class Thumbnail < Processor
|
||||
|
||||
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options, :source_file_options
|
||||
|
||||
# Creates a Thumbnail object set to work on the +file+ given. It
|
||||
# will attempt to transform the image into one defined by +target_geometry+
|
||||
# which is a "WxH"-style string. +format+ will be inferred from the +file+
|
||||
# unless specified. Thumbnail creation will raise no errors unless
|
||||
# +whiny+ is true (which it is, by default. If +convert_options+ is
|
||||
# set, the options will be appended to the convert command upon image conversion
|
||||
def initialize file, options = {}, attachment = nil
|
||||
super
|
||||
|
||||
geometry = options[:geometry]
|
||||
@file = file
|
||||
@crop = geometry[-1,1] == '#'
|
||||
@target_geometry = Geometry.parse geometry
|
||||
@current_geometry = Geometry.from_file @file
|
||||
@source_file_options = options[:source_file_options]
|
||||
@convert_options = options[:convert_options]
|
||||
@whiny = options[:whiny].nil? ? true : options[:whiny]
|
||||
@format = options[:format]
|
||||
|
||||
@source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
|
||||
@convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
|
||||
|
||||
@current_format = File.extname(@file.path)
|
||||
@basename = File.basename(@file.path, @current_format)
|
||||
|
||||
end
|
||||
|
||||
# Returns true if the +target_geometry+ is meant to crop.
|
||||
def crop?
|
||||
@crop
|
||||
end
|
||||
|
||||
# Returns true if the image is meant to make use of additional convert options.
|
||||
def convert_options?
|
||||
!@convert_options.nil? && !@convert_options.empty?
|
||||
end
|
||||
|
||||
# Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
|
||||
# that contains the new image.
|
||||
def make
|
||||
src = @file
|
||||
dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
|
||||
dst.binmode
|
||||
|
||||
begin
|
||||
parameters = []
|
||||
parameters << source_file_options
|
||||
parameters << ":source"
|
||||
parameters << transformation_command
|
||||
parameters << convert_options
|
||||
parameters << ":dest"
|
||||
|
||||
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
|
||||
|
||||
success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}[0]", :dest => File.expand_path(dst.path))
|
||||
rescue PaperclipCommandLineError => e
|
||||
raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
|
||||
end
|
||||
|
||||
dst
|
||||
end
|
||||
|
||||
# Returns the command ImageMagick's +convert+ needs to transform the image
|
||||
# into the thumbnail.
|
||||
def transformation_command
|
||||
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
|
||||
trans = []
|
||||
trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
|
||||
trans << "-crop" << %["#{crop}"] << "+repage" if crop
|
||||
trans
|
||||
end
|
||||
end
|
||||
end
|
||||
60
vendor/plugins/paperclip/lib/paperclip/upfile.rb
vendored
60
vendor/plugins/paperclip/lib/paperclip/upfile.rb
vendored
@ -1,60 +0,0 @@
|
||||
module Paperclip
|
||||
# The Upfile module is a convenience module for adding uploaded-file-type methods
|
||||
# to the +File+ class. Useful for testing.
|
||||
# user.avatar = File.new("test/test_avatar.jpg")
|
||||
module Upfile
|
||||
|
||||
# Infer the MIME-type of the file from the extension.
|
||||
def content_type
|
||||
type = (self.path.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
|
||||
case type
|
||||
when %r"jp(e|g|eg)" then "image/jpeg"
|
||||
when %r"tiff?" then "image/tiff"
|
||||
when %r"png", "gif", "bmp" then "image/#{type}"
|
||||
when "txt" then "text/plain"
|
||||
when %r"html?" then "text/html"
|
||||
when "js" then "application/js"
|
||||
when "csv", "xml", "css" then "text/#{type}"
|
||||
else
|
||||
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
|
||||
content_type = (Paperclip.run("file", "-b --mime-type :file", :file => self.path).split(':').last.strip rescue "application/x-#{type}")
|
||||
content_type = "application/x-#{type}" if content_type.match(/\(.*?\)/)
|
||||
content_type
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the file's normal name.
|
||||
def original_filename
|
||||
File.basename(self.path)
|
||||
end
|
||||
|
||||
# Returns the size of the file.
|
||||
def size
|
||||
File.size(self)
|
||||
end
|
||||
|
||||
# Returns the hash of the file.
|
||||
def fingerprint
|
||||
Digest::MD5.hexdigest(self.read)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if defined? StringIO
|
||||
class StringIO
|
||||
attr_accessor :original_filename, :content_type, :fingerprint
|
||||
def original_filename
|
||||
@original_filename ||= "stringio.txt"
|
||||
end
|
||||
def content_type
|
||||
@content_type ||= "text/plain"
|
||||
end
|
||||
def fingerprint
|
||||
@fingerprint ||= Digest::MD5.hexdigest(self.string)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class File #:nodoc:
|
||||
include Paperclip::Upfile
|
||||
end
|
||||
@ -1,3 +0,0 @@
|
||||
module Paperclip
|
||||
VERSION = "2.3.4" unless defined? Paperclip::VERSION
|
||||
end
|
||||
@ -1,79 +0,0 @@
|
||||
def obtain_class
|
||||
class_name = ENV['CLASS'] || ENV['class']
|
||||
raise "Must specify CLASS" unless class_name
|
||||
@klass = Object.const_get(class_name)
|
||||
end
|
||||
|
||||
def obtain_attachments
|
||||
name = ENV['ATTACHMENT'] || ENV['attachment']
|
||||
raise "Class #{@klass.name} has no attachments specified" unless @klass.respond_to?(:attachment_definitions)
|
||||
if !name.blank? && @klass.attachment_definitions.keys.include?(name)
|
||||
[ name ]
|
||||
else
|
||||
@klass.attachment_definitions.keys
|
||||
end
|
||||
end
|
||||
|
||||
def for_all_attachments
|
||||
klass = obtain_class
|
||||
names = obtain_attachments
|
||||
ids = klass.connection.select_values(klass.send(:construct_finder_sql, :select => 'id'))
|
||||
|
||||
ids.each do |id|
|
||||
instance = klass.find(id)
|
||||
names.each do |name|
|
||||
result = if instance.send("#{ name }?")
|
||||
yield(instance, name)
|
||||
else
|
||||
true
|
||||
end
|
||||
print result ? "." : "x"; $stdout.flush
|
||||
end
|
||||
end
|
||||
puts " Done."
|
||||
end
|
||||
|
||||
namespace :paperclip do
|
||||
desc "Refreshes both metadata and thumbnails."
|
||||
task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
|
||||
|
||||
namespace :refresh do
|
||||
desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)."
|
||||
task :thumbnails => :environment do
|
||||
errors = []
|
||||
for_all_attachments do |instance, name|
|
||||
result = instance.send(name).reprocess!
|
||||
errors << [instance.id, instance.errors] unless instance.errors.blank?
|
||||
result
|
||||
end
|
||||
errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" }
|
||||
end
|
||||
|
||||
desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
|
||||
task :metadata => :environment do
|
||||
for_all_attachments do |instance, name|
|
||||
if file = instance.send(name).to_file
|
||||
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
|
||||
instance.send("#{name}_content_type=", file.content_type.strip)
|
||||
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
|
||||
instance.save(false)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Cleans out invalid attachments. Useful after you've added new validations."
|
||||
task :clean => :environment do
|
||||
for_all_attachments do |instance, name|
|
||||
instance.send(name).send(:validate)
|
||||
if instance.send(name).valid?
|
||||
true
|
||||
else
|
||||
instance.send("#{name}=", nil)
|
||||
instance.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
34
vendor/plugins/paperclip/paperclip.gemspec
vendored
34
vendor/plugins/paperclip/paperclip.gemspec
vendored
@ -1,34 +0,0 @@
|
||||
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
||||
require 'paperclip/version'
|
||||
|
||||
include_files = ["README*", "LICENSE", "Rakefile", "init.rb", "{lib,tasks,test,rails,generators,shoulda_macros}/**/*"].map do |glob|
|
||||
Dir[glob]
|
||||
end.flatten
|
||||
exclude_files = ["test/s3.yml", "test/debug.log", "test/paperclip.db", "test/doc", "test/doc/*", "test/pkg", "test/pkg/*", "test/tmp", "test/tmp/*"].map do |glob|
|
||||
Dir[glob]
|
||||
end.flatten
|
||||
|
||||
spec = Gem::Specification.new do |s|
|
||||
s.name = "paperclip"
|
||||
s.version = Paperclip::VERSION
|
||||
s.author = "Jon Yurek"
|
||||
s.email = "jyurek@thoughtbot.com"
|
||||
s.homepage = "http://www.thoughtbot.com/projects/paperclip"
|
||||
s.description = "Easy upload management for ActiveRecord"
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.summary = "File attachments as attributes for ActiveRecord"
|
||||
s.files = include_files - exclude_files
|
||||
s.require_path = "lib"
|
||||
s.test_files = Dir["test/**/test_*.rb"]
|
||||
s.rubyforge_project = "paperclip"
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = Dir["README*"]
|
||||
s.rdoc_options << '--line-numbers' << '--inline-source'
|
||||
s.requirements << "ImageMagick"
|
||||
s.add_dependency 'activerecord'
|
||||
s.add_dependency 'activesupport'
|
||||
s.add_development_dependency 'shoulda'
|
||||
s.add_development_dependency 'mocha'
|
||||
s.add_development_dependency 'aws-s3'
|
||||
s.add_development_dependency 'sqlite3-ruby'
|
||||
end
|
||||
2
vendor/plugins/paperclip/rails/init.rb
vendored
2
vendor/plugins/paperclip/rails/init.rb
vendored
@ -1,2 +0,0 @@
|
||||
require 'paperclip/railtie'
|
||||
Paperclip::Railtie.insert
|
||||
118
vendor/plugins/paperclip/shoulda_macros/paperclip.rb
vendored
118
vendor/plugins/paperclip/shoulda_macros/paperclip.rb
vendored
@ -1,118 +0,0 @@
|
||||
require 'paperclip/matchers'
|
||||
|
||||
module Paperclip
|
||||
# =Paperclip Shoulda Macros
|
||||
#
|
||||
# These macros are intended for use with shoulda, and will be included into
|
||||
# your tests automatically. All of the macros use the standard shoulda
|
||||
# assumption that the name of the test is based on the name of the model
|
||||
# you're testing (that is, UserTest is the test for the User model), and
|
||||
# will load that class for testing purposes.
|
||||
module Shoulda
|
||||
include Matchers
|
||||
# This will test whether you have defined your attachment correctly by
|
||||
# checking for all the required fields exist after the definition of the
|
||||
# attachment.
|
||||
def should_have_attached_file name
|
||||
klass = self.name.gsub(/Test$/, '').constantize
|
||||
matcher = have_attached_file name
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Tests for validations on the presence of the attachment.
|
||||
def should_validate_attachment_presence name
|
||||
klass = self.name.gsub(/Test$/, '').constantize
|
||||
matcher = validate_attachment_presence name
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Tests that you have content_type validations specified. There are two
|
||||
# options, :valid and :invalid. Both accept an array of strings. The
|
||||
# strings should be a list of content types which will pass and fail
|
||||
# validation, respectively.
|
||||
def should_validate_attachment_content_type name, options = {}
|
||||
klass = self.name.gsub(/Test$/, '').constantize
|
||||
valid = [options[:valid]].flatten
|
||||
invalid = [options[:invalid]].flatten
|
||||
matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Tests to ensure that you have file size validations turned on. You
|
||||
# can pass the same options to this that you can to
|
||||
# validate_attachment_file_size - :less_than, :greater_than, and :in.
|
||||
# :less_than checks that a file is less than a certain size, :greater_than
|
||||
# checks that a file is more than a certain size, and :in takes a Range or
|
||||
# Array which specifies the lower and upper limits of the file size.
|
||||
def should_validate_attachment_size name, options = {}
|
||||
klass = self.name.gsub(/Test$/, '').constantize
|
||||
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
||||
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
||||
range = (min..max)
|
||||
matcher = validate_attachment_size(name).in(range)
|
||||
should matcher.description do
|
||||
assert_accepts(matcher, klass)
|
||||
end
|
||||
end
|
||||
|
||||
# Stubs the HTTP PUT for an attachment using S3 storage.
|
||||
#
|
||||
# @example
|
||||
# stub_paperclip_s3('user', 'avatar', 'png')
|
||||
def stub_paperclip_s3(model, attachment, extension)
|
||||
definition = model.gsub(" ", "_").classify.constantize.
|
||||
attachment_definitions[attachment.to_sym]
|
||||
|
||||
path = "http://s3.amazonaws.com/:id/#{definition[:path]}"
|
||||
path.gsub!(/:([^\/\.]+)/) do |match|
|
||||
"([^\/\.]+)"
|
||||
end
|
||||
|
||||
begin
|
||||
FakeWeb.register_uri(:put, Regexp.new(path), :body => "OK")
|
||||
rescue NameError
|
||||
raise NameError, "the stub_paperclip_s3 shoulda macro requires the fakeweb gem."
|
||||
end
|
||||
end
|
||||
|
||||
# Stub S3 and return a file for attachment. Best with Factory Girl.
|
||||
# Uses a strict directory convention:
|
||||
#
|
||||
# features/support/paperclip
|
||||
#
|
||||
# This method is used by the Paperclip-provided Cucumber step:
|
||||
#
|
||||
# When I attach a "demo_tape" "mp3" file to a "band" on S3
|
||||
#
|
||||
# @example
|
||||
# Factory.define :band_with_demo_tape, :parent => :band do |band|
|
||||
# band.demo_tape { band.paperclip_fixture("band", "demo_tape", "png") }
|
||||
# end
|
||||
def paperclip_fixture(model, attachment, extension)
|
||||
stub_paperclip_s3(model, attachment, extension)
|
||||
base_path = File.join(File.dirname(__FILE__), "..", "..",
|
||||
"features", "support", "paperclip")
|
||||
File.new(File.join(base_path, model, "#{attachment}.#{extension}"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(ActionController::Integration::Session)
|
||||
class ActionController::Integration::Session #:nodoc:
|
||||
include Paperclip::Shoulda
|
||||
end
|
||||
end
|
||||
|
||||
class Factory
|
||||
include Paperclip::Shoulda #:nodoc:
|
||||
end
|
||||
|
||||
class Test::Unit::TestCase #:nodoc:
|
||||
extend Paperclip::Shoulda
|
||||
end
|
||||
1
vendor/plugins/paperclip/test/.gitignore
vendored
1
vendor/plugins/paperclip/test/.gitignore
vendored
@ -1 +0,0 @@
|
||||
debug.log
|
||||
804
vendor/plugins/paperclip/test/attachment_test.rb
vendored
804
vendor/plugins/paperclip/test/attachment_test.rb
vendored
@ -1,804 +0,0 @@
|
||||
# encoding: utf-8
|
||||
require 'test/helper'
|
||||
|
||||
class Dummy
|
||||
# This is a dummy class
|
||||
end
|
||||
|
||||
class AttachmentTest < Test::Unit::TestCase
|
||||
should "return the path based on the url by default" do
|
||||
@attachment = attachment :url => "/:class/:id/:basename"
|
||||
@model = @attachment.instance
|
||||
@model.id = 1234
|
||||
@model.avatar_file_name = "fake.jpg"
|
||||
assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
|
||||
end
|
||||
|
||||
context "Attachment default_options" do
|
||||
setup do
|
||||
rebuild_model
|
||||
@old_default_options = Paperclip::Attachment.default_options.dup
|
||||
@new_default_options = @old_default_options.merge({
|
||||
:path => "argle/bargle",
|
||||
:url => "fooferon",
|
||||
:default_url => "not here.png"
|
||||
})
|
||||
end
|
||||
|
||||
teardown do
|
||||
Paperclip::Attachment.default_options.merge! @old_default_options
|
||||
end
|
||||
|
||||
should "be overrideable" do
|
||||
Paperclip::Attachment.default_options.merge!(@new_default_options)
|
||||
@new_default_options.keys.each do |key|
|
||||
assert_equal @new_default_options[key],
|
||||
Paperclip::Attachment.default_options[key]
|
||||
end
|
||||
end
|
||||
|
||||
context "without an Attachment" do
|
||||
setup do
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "return false when asked exists?" do
|
||||
assert !@dummy.avatar.exists?
|
||||
end
|
||||
end
|
||||
|
||||
context "on an Attachment" do
|
||||
setup do
|
||||
@dummy = Dummy.new
|
||||
@attachment = @dummy.avatar
|
||||
end
|
||||
|
||||
Paperclip::Attachment.default_options.keys.each do |key|
|
||||
should "be the default_options for #{key}" do
|
||||
assert_equal @old_default_options[key],
|
||||
@attachment.instance_variable_get("@#{key}"),
|
||||
key
|
||||
end
|
||||
end
|
||||
|
||||
context "when redefined" do
|
||||
setup do
|
||||
Paperclip::Attachment.default_options.merge!(@new_default_options)
|
||||
@dummy = Dummy.new
|
||||
@attachment = @dummy.avatar
|
||||
end
|
||||
|
||||
Paperclip::Attachment.default_options.keys.each do |key|
|
||||
should "be the new default_options for #{key}" do
|
||||
assert_equal @new_default_options[key],
|
||||
@attachment.instance_variable_get("@#{key}"),
|
||||
key
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with similarly named interpolations" do
|
||||
setup do
|
||||
rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
|
||||
@dummy = Dummy.new
|
||||
@dummy.stubs(:id).returns(1024)
|
||||
@file = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "make sure that they are interpolated correctly" do
|
||||
assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with a :rails_env interpolation" do
|
||||
setup do
|
||||
@rails_env = "blah"
|
||||
@id = 1024
|
||||
rebuild_model :path => ":rails_env/:id.png"
|
||||
@dummy = Dummy.new
|
||||
@dummy.stubs(:id).returns(@id)
|
||||
@file = StringIO.new(".")
|
||||
@dummy.avatar = @file
|
||||
Rails.stubs(:env).returns(@rails_env)
|
||||
end
|
||||
|
||||
should "return the proper path" do
|
||||
assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with a default style and an extension interpolation" do
|
||||
setup do
|
||||
@attachment = attachment :path => ":basename.:extension",
|
||||
:styles => { :default => ["100x100", :png] },
|
||||
:default_style => :default
|
||||
@file = StringIO.new("...")
|
||||
@file.stubs(:original_filename).returns("file.jpg")
|
||||
end
|
||||
should "return the right extension for the path" do
|
||||
@attachment.assign(@file)
|
||||
assert_equal "file.png", @attachment.path
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with :convert_options" do
|
||||
setup do
|
||||
rebuild_model :styles => {
|
||||
:thumb => "100x100",
|
||||
:large => "400x400"
|
||||
},
|
||||
:convert_options => {
|
||||
:all => "-do_stuff",
|
||||
:thumb => "-thumbnailize"
|
||||
}
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar
|
||||
end
|
||||
|
||||
should "report the correct options when sent #extra_options_for(:thumb)" do
|
||||
assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
|
||||
end
|
||||
|
||||
should "report the correct options when sent #extra_options_for(:large)" do
|
||||
assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with :convert_options that is a proc" do
|
||||
setup do
|
||||
rebuild_model :styles => {
|
||||
:thumb => "100x100",
|
||||
:large => "400x400"
|
||||
},
|
||||
:convert_options => {
|
||||
:all => lambda{|i| i.all },
|
||||
:thumb => lambda{|i| i.thumb }
|
||||
}
|
||||
Dummy.class_eval do
|
||||
def all; "-all"; end
|
||||
def thumb; "-thumb"; end
|
||||
end
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar
|
||||
end
|
||||
|
||||
should "report the correct options when sent #extra_options_for(:thumb)" do
|
||||
assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
|
||||
end
|
||||
|
||||
should "report the correct options when sent #extra_options_for(:large)" do
|
||||
assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with :path that is a proc" do
|
||||
setup do
|
||||
rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
|
||||
|
||||
@file = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
@dummyA = Dummy.new(:other => 'a')
|
||||
@dummyA.avatar = @file
|
||||
@dummyB = Dummy.new(:other => 'b')
|
||||
@dummyB.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "return correct path" do
|
||||
assert_equal "path/a.png", @dummyA.avatar.path
|
||||
assert_equal "path/b.png", @dummyB.avatar.path
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with :styles that is a proc" do
|
||||
setup do
|
||||
rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
|
||||
|
||||
@attachment = Dummy.new.avatar
|
||||
end
|
||||
|
||||
should "have the correct geometry" do
|
||||
assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with :url that is a proc" do
|
||||
setup do
|
||||
rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
|
||||
|
||||
@file = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
@dummyA = Dummy.new(:other => 'a')
|
||||
@dummyA.avatar = @file
|
||||
@dummyB = Dummy.new(:other => 'b')
|
||||
@dummyB.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "return correct url" do
|
||||
assert_equal "path/a.png", @dummyA.avatar.url(:original, false)
|
||||
assert_equal "path/b.png", @dummyB.avatar.url(:original, false)
|
||||
end
|
||||
end
|
||||
|
||||
geometry_specs = [
|
||||
[ lambda{|z| "50x50#" }, :png ],
|
||||
lambda{|z| "50x50#" },
|
||||
{ :geometry => lambda{|z| "50x50#" } }
|
||||
]
|
||||
geometry_specs.each do |geometry_spec|
|
||||
context "An attachment geometry like #{geometry_spec}" do
|
||||
setup do
|
||||
rebuild_model :styles => { :normal => geometry_spec }
|
||||
@attachment = Dummy.new.avatar
|
||||
end
|
||||
|
||||
context "when assigned" do
|
||||
setup do
|
||||
@file = StringIO.new(".")
|
||||
@attachment.assign(@file)
|
||||
end
|
||||
|
||||
should "have the correct geometry" do
|
||||
assert_equal "50x50#", @attachment.styles[:normal][:geometry]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with both 'normal' and hash-style styles" do
|
||||
setup do
|
||||
rebuild_model :styles => {
|
||||
:normal => ["50x50#", :png],
|
||||
:hash => { :geometry => "50x50#", :format => :png }
|
||||
}
|
||||
@dummy = Dummy.new
|
||||
@attachment = @dummy.avatar
|
||||
end
|
||||
|
||||
[:processors, :whiny, :convert_options, :geometry, :format].each do |field|
|
||||
should "have the same #{field} field" do
|
||||
assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with :processors that is a proc" do
|
||||
setup do
|
||||
rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] }
|
||||
@attachment = Dummy.new.avatar
|
||||
end
|
||||
|
||||
context "when assigned" do
|
||||
setup do
|
||||
@attachment.assign(StringIO.new("."))
|
||||
end
|
||||
|
||||
should "have the correct processors" do
|
||||
assert_equal [ :test ], @attachment.styles[:normal][:processors]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with erroring processor" do
|
||||
setup do
|
||||
rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true
|
||||
@dummy = Dummy.new
|
||||
Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.")
|
||||
@file = StringIO.new("...")
|
||||
@file.stubs(:to_tempfile).returns(@file)
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "correctly forward processing error message to the instance" do
|
||||
@dummy.valid?
|
||||
assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with multiple processors" do
|
||||
setup do
|
||||
class Paperclip::Test < Paperclip::Processor; end
|
||||
@style_params = { :once => {:one => 1, :two => 2} }
|
||||
rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
|
||||
@dummy = Dummy.new
|
||||
@file = StringIO.new("...")
|
||||
@file.stubs(:to_tempfile).returns(@file)
|
||||
Paperclip::Test.stubs(:make).returns(@file)
|
||||
Paperclip::Thumbnail.stubs(:make).returns(@file)
|
||||
end
|
||||
|
||||
context "when assigned" do
|
||||
setup { @dummy.avatar = @file }
|
||||
|
||||
before_should "call #make on all specified processors" do
|
||||
Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
|
||||
Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
|
||||
end
|
||||
|
||||
before_should "call #make with the right parameters passed as second argument" do
|
||||
expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
|
||||
Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
|
||||
end
|
||||
|
||||
before_should "call #make with attachment passed as third argument" do
|
||||
Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "include the filesystem module when loading the filesystem storage" do
|
||||
rebuild_model :storage => :filesystem
|
||||
@dummy = Dummy.new
|
||||
assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
|
||||
end
|
||||
|
||||
should "include the filesystem module even if capitalization is wrong" do
|
||||
rebuild_model :storage => :FileSystem
|
||||
@dummy = Dummy.new
|
||||
assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
|
||||
end
|
||||
|
||||
should "raise an error if you try to include a storage module that doesn't exist" do
|
||||
rebuild_model :storage => :not_here
|
||||
@dummy = Dummy.new
|
||||
assert_raises(Paperclip::StorageMethodNotFound) do
|
||||
@dummy.avatar
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with styles but no processors defined" do
|
||||
setup do
|
||||
rebuild_model :processors => [], :styles => {:something => '1'}
|
||||
@dummy = Dummy.new
|
||||
@file = StringIO.new("...")
|
||||
end
|
||||
should "raise when assigned to" do
|
||||
assert_raises(RuntimeError){ @dummy.avatar = @file }
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment without styles and with no processors defined" do
|
||||
setup do
|
||||
rebuild_model :processors => [], :styles => {}
|
||||
@dummy = Dummy.new
|
||||
@file = StringIO.new("...")
|
||||
end
|
||||
should "not raise when assigned to" do
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
end
|
||||
|
||||
context "Assigning an attachment with post_process hooks" do
|
||||
setup do
|
||||
rebuild_class :styles => { :something => "100x100#" }
|
||||
Dummy.class_eval do
|
||||
before_avatar_post_process :do_before_avatar
|
||||
after_avatar_post_process :do_after_avatar
|
||||
before_post_process :do_before_all
|
||||
after_post_process :do_after_all
|
||||
def do_before_avatar; end
|
||||
def do_after_avatar; end
|
||||
def do_before_all; end
|
||||
def do_after_all; end
|
||||
end
|
||||
@file = StringIO.new(".")
|
||||
@file.stubs(:to_tempfile).returns(@file)
|
||||
@dummy = Dummy.new
|
||||
Paperclip::Thumbnail.stubs(:make).returns(@file)
|
||||
@attachment = @dummy.avatar
|
||||
end
|
||||
|
||||
should "call the defined callbacks when assigned" do
|
||||
@dummy.expects(:do_before_avatar).with()
|
||||
@dummy.expects(:do_after_avatar).with()
|
||||
@dummy.expects(:do_before_all).with()
|
||||
@dummy.expects(:do_after_all).with()
|
||||
Paperclip::Thumbnail.expects(:make).returns(@file)
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "not cancel the processing if a before_post_process returns nil" do
|
||||
@dummy.expects(:do_before_avatar).with().returns(nil)
|
||||
@dummy.expects(:do_after_avatar).with()
|
||||
@dummy.expects(:do_before_all).with().returns(nil)
|
||||
@dummy.expects(:do_after_all).with()
|
||||
Paperclip::Thumbnail.expects(:make).returns(@file)
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "cancel the processing if a before_post_process returns false" do
|
||||
@dummy.expects(:do_before_avatar).never
|
||||
@dummy.expects(:do_after_avatar).never
|
||||
@dummy.expects(:do_before_all).with().returns(false)
|
||||
@dummy.expects(:do_after_all)
|
||||
Paperclip::Thumbnail.expects(:make).never
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "cancel the processing if a before_avatar_post_process returns false" do
|
||||
@dummy.expects(:do_before_avatar).with().returns(false)
|
||||
@dummy.expects(:do_after_avatar)
|
||||
@dummy.expects(:do_before_all).with().returns(true)
|
||||
@dummy.expects(:do_after_all)
|
||||
Paperclip::Thumbnail.expects(:make).never
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
end
|
||||
|
||||
context "Assigning an attachment" do
|
||||
setup do
|
||||
rebuild_model :styles => { :something => "100x100#" }
|
||||
@file = StringIO.new(".")
|
||||
@file.stubs(:original_filename).returns("5k.png\n\n")
|
||||
@file.stubs(:content_type).returns("image/png\n\n")
|
||||
@file.stubs(:to_tempfile).returns(@file)
|
||||
@dummy = Dummy.new
|
||||
Paperclip::Thumbnail.expects(:make).returns(@file)
|
||||
@attachment = @dummy.avatar
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "strip whitespace from original_filename field" do
|
||||
assert_equal "5k.png", @dummy.avatar.original_filename
|
||||
end
|
||||
|
||||
should "strip whitespace from content_type field" do
|
||||
assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
|
||||
end
|
||||
end
|
||||
|
||||
context "Attachment with strange letters" do
|
||||
setup do
|
||||
rebuild_model
|
||||
|
||||
@not_file = mock
|
||||
@tempfile = mock
|
||||
@not_file.stubs(:nil?).returns(false)
|
||||
@not_file.stubs(:fingerprint).returns('bd94545193321376b70136f8b223abf8')
|
||||
@tempfile.stubs(:fingerprint).returns('bd94545193321376b70136f8b223abf8')
|
||||
@not_file.expects(:size).returns(10)
|
||||
@tempfile.expects(:size).returns(10)
|
||||
@not_file.expects(:to_tempfile).returns(@tempfile)
|
||||
@not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
|
||||
@not_file.expects(:content_type).returns("image/png\r\n")
|
||||
|
||||
@dummy = Dummy.new
|
||||
@attachment = @dummy.avatar
|
||||
@attachment.expects(:valid_assignment?).with(@not_file).returns(true)
|
||||
@attachment.expects(:queue_existing_for_delete)
|
||||
@attachment.expects(:post_process)
|
||||
@dummy.avatar = @not_file
|
||||
end
|
||||
|
||||
should "not remove strange letters" do
|
||||
assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment" do
|
||||
setup do
|
||||
@old_defaults = Paperclip::Attachment.default_options.dup
|
||||
Paperclip::Attachment.default_options.merge!({
|
||||
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
||||
})
|
||||
FileUtils.rm_rf("tmp")
|
||||
rebuild_model
|
||||
@instance = Dummy.new
|
||||
@instance.stubs(:id).returns 123
|
||||
@attachment = Paperclip::Attachment.new(:avatar, @instance)
|
||||
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
||||
end
|
||||
|
||||
teardown do
|
||||
@file.close
|
||||
Paperclip::Attachment.default_options.merge!(@old_defaults)
|
||||
end
|
||||
|
||||
should "raise if there are not the correct columns when you try to assign" do
|
||||
@other_attachment = Paperclip::Attachment.new(:not_here, @instance)
|
||||
assert_raises(Paperclip::PaperclipError) do
|
||||
@other_attachment.assign(@file)
|
||||
end
|
||||
end
|
||||
|
||||
should "return its default_url when no file assigned" do
|
||||
assert @attachment.to_file.nil?
|
||||
assert_equal "/avatars/original/missing.png", @attachment.url
|
||||
assert_equal "/avatars/blah/missing.png", @attachment.url(:blah)
|
||||
end
|
||||
|
||||
should "return nil as path when no file assigned" do
|
||||
assert @attachment.to_file.nil?
|
||||
assert_equal nil, @attachment.path
|
||||
assert_equal nil, @attachment.path(:blah)
|
||||
end
|
||||
|
||||
context "with a file assigned in the database" do
|
||||
setup do
|
||||
@attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
|
||||
@attachment.stubs(:instance_read).with(:content_type).returns("image/png")
|
||||
@attachment.stubs(:instance_read).with(:file_size).returns(12345)
|
||||
dtnow = DateTime.now
|
||||
@now = Time.now
|
||||
Time.stubs(:now).returns(@now)
|
||||
@attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
|
||||
end
|
||||
|
||||
should "return a correct url even if the file does not exist" do
|
||||
assert_nil @attachment.to_file
|
||||
assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
|
||||
end
|
||||
|
||||
should "make sure the updated_at mtime is in the url if it is defined" do
|
||||
assert_match %r{#{@now.to_i}$}, @attachment.url(:blah)
|
||||
end
|
||||
|
||||
should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do
|
||||
assert_no_match %r{#{@now.to_i}$}, @attachment.url(:blah, false)
|
||||
end
|
||||
|
||||
context "with the updated_at field removed" do
|
||||
setup do
|
||||
@attachment.stubs(:instance_read).with(:updated_at).returns(nil)
|
||||
end
|
||||
|
||||
should "only return the url without the updated_at when sent #url" do
|
||||
assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah)
|
||||
end
|
||||
end
|
||||
|
||||
should "return the proper path when filename has a single .'s" do
|
||||
assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
|
||||
end
|
||||
|
||||
should "return the proper path when filename has multiple .'s" do
|
||||
@attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
|
||||
assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
|
||||
end
|
||||
|
||||
context "when expecting three styles" do
|
||||
setup do
|
||||
styles = {:styles => { :large => ["400x400", :png],
|
||||
:medium => ["100x100", :gif],
|
||||
:small => ["32x32#", :jpg]}}
|
||||
@attachment = Paperclip::Attachment.new(:avatar,
|
||||
@instance,
|
||||
styles)
|
||||
end
|
||||
|
||||
context "and assigned a file" do
|
||||
setup do
|
||||
now = Time.now
|
||||
Time.stubs(:now).returns(now)
|
||||
@attachment.assign(@file)
|
||||
end
|
||||
|
||||
should "be dirty" do
|
||||
assert @attachment.dirty?
|
||||
end
|
||||
|
||||
context "and saved" do
|
||||
setup do
|
||||
@attachment.save
|
||||
end
|
||||
|
||||
should "return the real url" do
|
||||
file = @attachment.to_file
|
||||
assert file
|
||||
assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
|
||||
assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
|
||||
file.close
|
||||
end
|
||||
|
||||
should "commit the files to disk" do
|
||||
[:large, :medium, :small].each do |style|
|
||||
io = @attachment.to_file(style)
|
||||
# p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
|
||||
assert File.exists?(io)
|
||||
assert ! io.is_a?(::Tempfile)
|
||||
io.close
|
||||
end
|
||||
end
|
||||
|
||||
should "save the files as the right formats and sizes" do
|
||||
[[:large, 400, 61, "PNG"],
|
||||
[:medium, 100, 15, "GIF"],
|
||||
[:small, 32, 32, "JPEG"]].each do |style|
|
||||
cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
|
||||
out = `#{cmd}`
|
||||
width, height, size, format = out.split(" ")
|
||||
assert_equal style[1].to_s, width.to_s
|
||||
assert_equal style[2].to_s, height.to_s
|
||||
assert_equal style[3].to_s, format.to_s
|
||||
end
|
||||
end
|
||||
|
||||
should "still have its #file attribute not be nil" do
|
||||
assert ! (file = @attachment.to_file).nil?
|
||||
file.close
|
||||
end
|
||||
|
||||
context "and trying to delete" do
|
||||
setup do
|
||||
@existing_names = @attachment.styles.keys.collect do |style|
|
||||
@attachment.path(style)
|
||||
end
|
||||
end
|
||||
|
||||
should "delete the files after assigning nil" do
|
||||
@attachment.expects(:instance_write).with(:file_name, nil)
|
||||
@attachment.expects(:instance_write).with(:content_type, nil)
|
||||
@attachment.expects(:instance_write).with(:file_size, nil)
|
||||
@attachment.expects(:instance_write).with(:updated_at, nil)
|
||||
@attachment.assign nil
|
||||
@attachment.save
|
||||
@existing_names.each{|f| assert ! File.exists?(f) }
|
||||
end
|
||||
|
||||
should "delete the files when you call #clear and #save" do
|
||||
@attachment.expects(:instance_write).with(:file_name, nil)
|
||||
@attachment.expects(:instance_write).with(:content_type, nil)
|
||||
@attachment.expects(:instance_write).with(:file_size, nil)
|
||||
@attachment.expects(:instance_write).with(:updated_at, nil)
|
||||
@attachment.clear
|
||||
@attachment.save
|
||||
@existing_names.each{|f| assert ! File.exists?(f) }
|
||||
end
|
||||
|
||||
should "delete the files when you call #delete" do
|
||||
@attachment.expects(:instance_write).with(:file_name, nil)
|
||||
@attachment.expects(:instance_write).with(:content_type, nil)
|
||||
@attachment.expects(:instance_write).with(:file_size, nil)
|
||||
@attachment.expects(:instance_write).with(:updated_at, nil)
|
||||
@attachment.destroy
|
||||
@existing_names.each{|f| assert ! File.exists?(f) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "when trying a nonexistant storage type" do
|
||||
setup do
|
||||
rebuild_model :storage => :not_here
|
||||
end
|
||||
|
||||
should "not be able to find the module" do
|
||||
assert_raise(Paperclip::StorageMethodNotFound){ Dummy.new.avatar }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with only a avatar_file_name column" do
|
||||
setup do
|
||||
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
||||
table.column :avatar_file_name, :string
|
||||
end
|
||||
rebuild_class
|
||||
@dummy = Dummy.new
|
||||
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "not error when assigned an attachment" do
|
||||
assert_nothing_raised { @dummy.avatar = @file }
|
||||
end
|
||||
|
||||
should "return the time when sent #avatar_updated_at" do
|
||||
now = Time.now
|
||||
Time.stubs(:now).returns(now)
|
||||
@dummy.avatar = @file
|
||||
assert now, @dummy.avatar.updated_at
|
||||
end
|
||||
|
||||
should "return nil when reloaded and sent #avatar_updated_at" do
|
||||
@dummy.save
|
||||
@dummy.reload
|
||||
assert_nil @dummy.avatar.updated_at
|
||||
end
|
||||
|
||||
should "return the right value when sent #avatar_file_size" do
|
||||
@dummy.avatar = @file
|
||||
assert_equal @file.size, @dummy.avatar.size
|
||||
end
|
||||
|
||||
context "and avatar_updated_at column" do
|
||||
setup do
|
||||
ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
|
||||
rebuild_class
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "not error when assigned an attachment" do
|
||||
assert_nothing_raised { @dummy.avatar = @file }
|
||||
end
|
||||
|
||||
should "return the right value when sent #avatar_updated_at" do
|
||||
now = Time.now
|
||||
Time.stubs(:now).returns(now)
|
||||
@dummy.avatar = @file
|
||||
assert_equal now.to_i, @dummy.avatar.updated_at
|
||||
end
|
||||
end
|
||||
|
||||
context "and avatar_content_type column" do
|
||||
setup do
|
||||
ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
|
||||
rebuild_class
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "not error when assigned an attachment" do
|
||||
assert_nothing_raised { @dummy.avatar = @file }
|
||||
end
|
||||
|
||||
should "return the right value when sent #avatar_content_type" do
|
||||
@dummy.avatar = @file
|
||||
assert_equal "image/png", @dummy.avatar.content_type
|
||||
end
|
||||
end
|
||||
|
||||
context "and avatar_file_size column" do
|
||||
setup do
|
||||
ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
|
||||
rebuild_class
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "not error when assigned an attachment" do
|
||||
assert_nothing_raised { @dummy.avatar = @file }
|
||||
end
|
||||
|
||||
should "return the right value when sent #avatar_file_size" do
|
||||
@dummy.avatar = @file
|
||||
assert_equal @file.size, @dummy.avatar.size
|
||||
end
|
||||
|
||||
should "return the right value when saved, reloaded, and sent #avatar_file_size" do
|
||||
@dummy.avatar = @file
|
||||
@dummy.save
|
||||
@dummy = Dummy.find(@dummy.id)
|
||||
assert_equal @file.size, @dummy.avatar.size
|
||||
end
|
||||
end
|
||||
|
||||
context "and avatar_fingerprint column" do
|
||||
setup do
|
||||
ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
|
||||
rebuild_class
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "not error when assigned an attachment" do
|
||||
assert_nothing_raised { @dummy.avatar = @file }
|
||||
end
|
||||
|
||||
should "return the right value when sent #avatar_fingerprint" do
|
||||
@dummy.avatar = @file
|
||||
assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
|
||||
end
|
||||
|
||||
should "return the right value when saved, reloaded, and sent #avatar_fingerprint" do
|
||||
@dummy.avatar = @file
|
||||
@dummy.save
|
||||
@dummy = Dummy.find(@dummy.id)
|
||||
assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
133
vendor/plugins/paperclip/test/command_line_test.rb
vendored
133
vendor/plugins/paperclip/test/command_line_test.rb
vendored
@ -1,133 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class CommandLineTest < Test::Unit::TestCase
|
||||
def setup
|
||||
Paperclip::CommandLine.path = nil
|
||||
File.stubs(:exist?).with("/dev/null").returns(true)
|
||||
end
|
||||
|
||||
should "take a command and parameters and produce a shell command for bash" do
|
||||
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
|
||||
assert_equal "convert a.jpg b.png", cmd.command
|
||||
end
|
||||
|
||||
should "be able to set a path and produce commands with that path" do
|
||||
Paperclip::CommandLine.path = "/opt/bin"
|
||||
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
|
||||
assert_equal "/opt/bin/convert a.jpg b.png", cmd.command
|
||||
end
|
||||
|
||||
should "be able to interpolate quoted variables into the parameters" do
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
":one :{two}",
|
||||
:one => "a.jpg",
|
||||
:two => "b.png",
|
||||
:swallow_stderr => false)
|
||||
assert_equal "convert 'a.jpg' 'b.png'", cmd.command
|
||||
end
|
||||
|
||||
should "quote command line options differently if we're on windows" do
|
||||
File.stubs(:exist?).with("/dev/null").returns(false)
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
":one :{two}",
|
||||
:one => "a.jpg",
|
||||
:two => "b.png",
|
||||
:swallow_stderr => false)
|
||||
assert_equal 'convert "a.jpg" "b.png"', cmd.command
|
||||
end
|
||||
|
||||
should "be able to quote and interpolate dangerous variables" do
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
":one :two",
|
||||
:one => "`rm -rf`.jpg",
|
||||
:two => "ha'ha.png",
|
||||
:swallow_stderr => false)
|
||||
assert_equal "convert '`rm -rf`.jpg' 'ha'\\''ha.png'", cmd.command
|
||||
end
|
||||
|
||||
should "be able to quote and interpolate dangerous variables even on windows" do
|
||||
File.stubs(:exist?).with("/dev/null").returns(false)
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
":one :two",
|
||||
:one => "`rm -rf`.jpg",
|
||||
:two => "ha'ha.png",
|
||||
:swallow_stderr => false)
|
||||
assert_equal %{convert "`rm -rf`.jpg" "ha'ha.png"}, cmd.command
|
||||
end
|
||||
|
||||
should "add redirection to get rid of stderr in bash" do
|
||||
File.stubs(:exist?).with("/dev/null").returns(true)
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
"a.jpg b.png",
|
||||
:swallow_stderr => true)
|
||||
|
||||
assert_equal "convert a.jpg b.png 2>/dev/null", cmd.command
|
||||
end
|
||||
|
||||
should "add redirection to get rid of stderr in cmd.exe" do
|
||||
File.stubs(:exist?).with("/dev/null").returns(false)
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
"a.jpg b.png",
|
||||
:swallow_stderr => true)
|
||||
|
||||
assert_equal "convert a.jpg b.png 2>NUL", cmd.command
|
||||
end
|
||||
|
||||
should "raise if trying to interpolate :swallow_stderr or :expected_outcodes" do
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
":swallow_stderr :expected_outcodes",
|
||||
:swallow_stderr => false,
|
||||
:expected_outcodes => [0, 1])
|
||||
assert_raise(Paperclip::PaperclipCommandLineError) do
|
||||
cmd.command
|
||||
end
|
||||
end
|
||||
|
||||
should "run the #command it's given and return the output" do
|
||||
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
|
||||
cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
|
||||
with_exitstatus_returning(0) do
|
||||
assert_equal :correct_value, cmd.run
|
||||
end
|
||||
end
|
||||
|
||||
should "raise a PaperclipCommandLineError if the result code isn't expected" do
|
||||
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
|
||||
cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
|
||||
with_exitstatus_returning(1) do
|
||||
assert_raises(Paperclip::PaperclipCommandLineError) do
|
||||
cmd.run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "not raise a PaperclipCommandLineError if the result code is expected" do
|
||||
cmd = Paperclip::CommandLine.new("convert",
|
||||
"a.jpg b.png",
|
||||
:expected_outcodes => [0, 1],
|
||||
:swallow_stderr => false)
|
||||
cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
|
||||
with_exitstatus_returning(1) do
|
||||
assert_nothing_raised do
|
||||
cmd.run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "log the command" do
|
||||
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
|
||||
cmd.class.stubs(:'`')
|
||||
Paperclip.expects(:log).with("convert a.jpg b.png")
|
||||
cmd.run
|
||||
end
|
||||
|
||||
should "detect that the system is unix or windows based on presence of /dev/null" do
|
||||
File.stubs(:exist?).returns(true)
|
||||
assert Paperclip::CommandLine.unix?
|
||||
end
|
||||
|
||||
should "detect that the system is not unix or windows based on absence of /dev/null" do
|
||||
File.stubs(:exist?).returns(false)
|
||||
assert ! Paperclip::CommandLine.unix?
|
||||
end
|
||||
end
|
||||
4
vendor/plugins/paperclip/test/database.yml
vendored
4
vendor/plugins/paperclip/test/database.yml
vendored
@ -1,4 +0,0 @@
|
||||
test:
|
||||
adapter: sqlite3
|
||||
database: ":memory:"
|
||||
|
||||
BIN
vendor/plugins/paperclip/test/fixtures/12k.png
vendored
BIN
vendor/plugins/paperclip/test/fixtures/12k.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
BIN
vendor/plugins/paperclip/test/fixtures/50x50.png
vendored
BIN
vendor/plugins/paperclip/test/fixtures/50x50.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
BIN
vendor/plugins/paperclip/test/fixtures/5k.png
vendored
BIN
vendor/plugins/paperclip/test/fixtures/5k.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 4.4 KiB |
@ -1 +0,0 @@
|
||||
This is not an image.
|
||||
@ -1,8 +0,0 @@
|
||||
development:
|
||||
key: 54321
|
||||
production:
|
||||
key: 12345
|
||||
test:
|
||||
bucket: <%= ENV['S3_BUCKET'] %>
|
||||
access_key_id: <%= ENV['S3_KEY'] %>
|
||||
secret_access_key: <%= ENV['S3_SECRET'] %>
|
||||
BIN
vendor/plugins/paperclip/test/fixtures/twopage.pdf
vendored
BIN
vendor/plugins/paperclip/test/fixtures/twopage.pdf
vendored
Binary file not shown.
177
vendor/plugins/paperclip/test/geometry_test.rb
vendored
177
vendor/plugins/paperclip/test/geometry_test.rb
vendored
@ -1,177 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class GeometryTest < Test::Unit::TestCase
|
||||
context "Paperclip::Geometry" do
|
||||
should "correctly report its given dimensions" do
|
||||
assert @geo = Paperclip::Geometry.new(1024, 768)
|
||||
assert_equal 1024, @geo.width
|
||||
assert_equal 768, @geo.height
|
||||
end
|
||||
|
||||
should "set height to 0 if height dimension is missing" do
|
||||
assert @geo = Paperclip::Geometry.new(1024)
|
||||
assert_equal 1024, @geo.width
|
||||
assert_equal 0, @geo.height
|
||||
end
|
||||
|
||||
should "set width to 0 if width dimension is missing" do
|
||||
assert @geo = Paperclip::Geometry.new(nil, 768)
|
||||
assert_equal 0, @geo.width
|
||||
assert_equal 768, @geo.height
|
||||
end
|
||||
|
||||
should "be generated from a WxH-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("800x600")
|
||||
assert_equal 800, @geo.width
|
||||
assert_equal 600, @geo.height
|
||||
end
|
||||
|
||||
should "be generated from a xH-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("x600")
|
||||
assert_equal 0, @geo.width
|
||||
assert_equal 600, @geo.height
|
||||
end
|
||||
|
||||
should "be generated from a Wx-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("800x")
|
||||
assert_equal 800, @geo.width
|
||||
assert_equal 0, @geo.height
|
||||
end
|
||||
|
||||
should "be generated from a W-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("800")
|
||||
assert_equal 800, @geo.width
|
||||
assert_equal 0, @geo.height
|
||||
end
|
||||
|
||||
should "ensure the modifier is nil if not present" do
|
||||
assert @geo = Paperclip::Geometry.parse("123x456")
|
||||
assert_nil @geo.modifier
|
||||
end
|
||||
|
||||
should "treat x and X the same in geometries" do
|
||||
@lower = Paperclip::Geometry.parse("123x456")
|
||||
@upper = Paperclip::Geometry.parse("123X456")
|
||||
assert_equal 123, @lower.width
|
||||
assert_equal 123, @upper.width
|
||||
assert_equal 456, @lower.height
|
||||
assert_equal 456, @upper.height
|
||||
end
|
||||
|
||||
['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
|
||||
should "ensure the modifier #{mod.inspect} is preserved" do
|
||||
assert @geo = Paperclip::Geometry.parse("123x456#{mod}")
|
||||
assert_equal mod, @geo.modifier
|
||||
assert_equal "123x456#{mod}", @geo.to_s
|
||||
end
|
||||
end
|
||||
|
||||
['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
|
||||
should "ensure the modifier #{mod.inspect} is preserved with no height" do
|
||||
assert @geo = Paperclip::Geometry.parse("123x#{mod}")
|
||||
assert_equal mod, @geo.modifier
|
||||
assert_equal "123#{mod}", @geo.to_s
|
||||
end
|
||||
end
|
||||
|
||||
should "make sure the modifier gets passed during transformation_to" do
|
||||
assert @src = Paperclip::Geometry.parse("123x456")
|
||||
assert @dst = Paperclip::Geometry.parse("123x456>")
|
||||
assert_equal ["123x456>", nil], @src.transformation_to(@dst)
|
||||
end
|
||||
|
||||
should "generate correct ImageMagick formatting string for W-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("800")
|
||||
assert_equal "800", @geo.to_s
|
||||
end
|
||||
|
||||
should "generate correct ImageMagick formatting string for Wx-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("800x")
|
||||
assert_equal "800", @geo.to_s
|
||||
end
|
||||
|
||||
should "generate correct ImageMagick formatting string for xH-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("x600")
|
||||
assert_equal "x600", @geo.to_s
|
||||
end
|
||||
|
||||
should "generate correct ImageMagick formatting string for WxH-formatted string" do
|
||||
assert @geo = Paperclip::Geometry.parse("800x600")
|
||||
assert_equal "800x600", @geo.to_s
|
||||
end
|
||||
|
||||
should "be generated from a file" do
|
||||
file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
|
||||
file = File.new(file, 'rb')
|
||||
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
|
||||
assert @geo.height > 0
|
||||
assert @geo.width > 0
|
||||
end
|
||||
|
||||
should "be generated from a file path" do
|
||||
file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
|
||||
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
|
||||
assert @geo.height > 0
|
||||
assert @geo.width > 0
|
||||
end
|
||||
|
||||
should "not generate from a bad file" do
|
||||
file = "/home/This File Does Not Exist.omg"
|
||||
assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
|
||||
end
|
||||
|
||||
[['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
|
||||
['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
|
||||
['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
|
||||
context "performing calculations on a #{args[0]} viewport" do
|
||||
setup do
|
||||
@geo = Paperclip::Geometry.new(args[1], args[2])
|
||||
end
|
||||
|
||||
should "#{args[3] ? "" : "not"} be vertical" do
|
||||
assert_equal args[3], @geo.vertical?
|
||||
end
|
||||
|
||||
should "#{args[4] ? "" : "not"} be horizontal" do
|
||||
assert_equal args[4], @geo.horizontal?
|
||||
end
|
||||
|
||||
should "#{args[5] ? "" : "not"} be square" do
|
||||
assert_equal args[5], @geo.square?
|
||||
end
|
||||
|
||||
should "report that #{args[6]} is the larger dimension" do
|
||||
assert_equal args[6], @geo.larger
|
||||
end
|
||||
|
||||
should "report that #{args[7]} is the smaller dimension" do
|
||||
assert_equal args[7], @geo.smaller
|
||||
end
|
||||
|
||||
should "have an aspect ratio of #{args[8]}" do
|
||||
assert_in_delta args[8], @geo.aspect, 0.0001
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[[ [1000, 100], [64, 64], "x64", "64x64+288+0" ],
|
||||
[ [100, 1000], [50, 950], "x950", "50x950+22+0" ],
|
||||
[ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args|
|
||||
context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do
|
||||
setup do
|
||||
@geo = Paperclip::Geometry.new(*args[0])
|
||||
@dst = Paperclip::Geometry.new(*args[1])
|
||||
@scale, @crop = @geo.transformation_to @dst, true
|
||||
end
|
||||
|
||||
should "be able to return the correct scaling transformation geometry #{args[2]}" do
|
||||
assert_equal args[2], @scale
|
||||
end
|
||||
|
||||
should "be able to return the correct crop transformation geometry #{args[3]}" do
|
||||
assert_equal args[3], @crop
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
158
vendor/plugins/paperclip/test/helper.rb
vendored
158
vendor/plugins/paperclip/test/helper.rb
vendored
@ -1,158 +0,0 @@
|
||||
require 'rubygems'
|
||||
require 'tempfile'
|
||||
require 'test/unit'
|
||||
|
||||
require 'shoulda'
|
||||
require 'mocha'
|
||||
|
||||
case ENV['RAILS_VERSION']
|
||||
when '2.1' then
|
||||
gem 'activerecord', '~>2.1.0'
|
||||
gem 'activesupport', '~>2.1.0'
|
||||
when '3.0' then
|
||||
gem 'activerecord', '~>3.0.0'
|
||||
gem 'activesupport', '~>3.0.0'
|
||||
else
|
||||
gem 'activerecord', '~>2.3.0'
|
||||
gem 'activesupport', '~>2.3.0'
|
||||
end
|
||||
|
||||
require 'active_record'
|
||||
require 'active_record/version'
|
||||
require 'active_support'
|
||||
|
||||
puts "Testing against version #{ActiveRecord::VERSION::STRING}"
|
||||
|
||||
`ruby -e 'exit 0'` # Prime $? with a value.
|
||||
|
||||
begin
|
||||
require 'ruby-debug'
|
||||
rescue LoadError => e
|
||||
puts "debugger disabled"
|
||||
end
|
||||
|
||||
ROOT = File.join(File.dirname(__FILE__), '..')
|
||||
|
||||
def silence_warnings
|
||||
old_verbose, $VERBOSE = $VERBOSE, nil
|
||||
yield
|
||||
ensure
|
||||
$VERBOSE = old_verbose
|
||||
end
|
||||
|
||||
class Test::Unit::TestCase
|
||||
def setup
|
||||
silence_warnings do
|
||||
Object.const_set(:Rails, stub('Rails', :root => ROOT, :env => 'test'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
$LOAD_PATH << File.join(ROOT, 'lib')
|
||||
$LOAD_PATH << File.join(ROOT, 'lib', 'paperclip')
|
||||
|
||||
require File.join(ROOT, 'lib', 'paperclip.rb')
|
||||
|
||||
require 'shoulda_macros/paperclip'
|
||||
|
||||
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
||||
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
||||
ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
|
||||
ActiveRecord::Base.establish_connection(config['test'])
|
||||
|
||||
def reset_class class_name
|
||||
ActiveRecord::Base.send(:include, Paperclip::Glue)
|
||||
Object.send(:remove_const, class_name) rescue nil
|
||||
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
||||
klass.class_eval{ include Paperclip::Glue }
|
||||
klass
|
||||
end
|
||||
|
||||
def reset_table table_name, &block
|
||||
block ||= lambda { |table| true }
|
||||
ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block
|
||||
end
|
||||
|
||||
def modify_table table_name, &block
|
||||
ActiveRecord::Base.connection.change_table :dummies, &block
|
||||
end
|
||||
|
||||
def rebuild_model options = {}
|
||||
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
||||
table.column :other, :string
|
||||
table.column :avatar_file_name, :string
|
||||
table.column :avatar_content_type, :string
|
||||
table.column :avatar_file_size, :integer
|
||||
table.column :avatar_updated_at, :datetime
|
||||
table.column :avatar_fingerprint, :string
|
||||
end
|
||||
rebuild_class options
|
||||
end
|
||||
|
||||
def rebuild_class options = {}
|
||||
ActiveRecord::Base.send(:include, Paperclip::Glue)
|
||||
Object.send(:remove_const, "Dummy") rescue nil
|
||||
Object.const_set("Dummy", Class.new(ActiveRecord::Base))
|
||||
Dummy.class_eval do
|
||||
include Paperclip::Glue
|
||||
has_attached_file :avatar, options
|
||||
end
|
||||
end
|
||||
|
||||
class FakeModel
|
||||
attr_accessor :avatar_file_name,
|
||||
:avatar_file_size,
|
||||
:avatar_last_updated,
|
||||
:avatar_content_type,
|
||||
:avatar_fingerprint,
|
||||
:id
|
||||
|
||||
def errors
|
||||
@errors ||= []
|
||||
end
|
||||
|
||||
def run_paperclip_callbacks name, *args
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def attachment options
|
||||
Paperclip::Attachment.new(:avatar, FakeModel.new, options)
|
||||
end
|
||||
|
||||
def silence_warnings
|
||||
old_verbose, $VERBOSE = $VERBOSE, nil
|
||||
yield
|
||||
ensure
|
||||
$VERBOSE = old_verbose
|
||||
end
|
||||
|
||||
def should_accept_dummy_class
|
||||
should "accept the class" do
|
||||
assert_accepts @matcher, @dummy_class
|
||||
end
|
||||
|
||||
should "accept an instance of that class" do
|
||||
assert_accepts @matcher, @dummy_class.new
|
||||
end
|
||||
end
|
||||
|
||||
def should_reject_dummy_class
|
||||
should "reject the class" do
|
||||
assert_rejects @matcher, @dummy_class
|
||||
end
|
||||
|
||||
should "reject an instance of that class" do
|
||||
assert_rejects @matcher, @dummy_class.new
|
||||
end
|
||||
end
|
||||
|
||||
def with_exitstatus_returning(code)
|
||||
saved_exitstatus = $?.nil? ? 0 : $?.exitstatus
|
||||
begin
|
||||
`ruby -e 'exit #{code.to_i}'`
|
||||
yield
|
||||
ensure
|
||||
`ruby -e 'exit #{saved_exitstatus.to_i}'`
|
||||
end
|
||||
end
|
||||
482
vendor/plugins/paperclip/test/integration_test.rb
vendored
482
vendor/plugins/paperclip/test/integration_test.rb
vendored
@ -1,482 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class IntegrationTest < Test::Unit::TestCase
|
||||
context "Many models at once" do
|
||||
setup do
|
||||
rebuild_model
|
||||
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
||||
300.times do |i|
|
||||
Dummy.create! :avatar => @file
|
||||
end
|
||||
end
|
||||
|
||||
should "not exceed the open file limit" do
|
||||
assert_nothing_raised do
|
||||
dummies = Dummy.find(:all)
|
||||
dummies.each { |dummy| dummy.avatar }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment" do
|
||||
setup do
|
||||
rebuild_model :styles => { :thumb => "50x50#" }
|
||||
@dummy = Dummy.new
|
||||
@file = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
@dummy.avatar = @file
|
||||
assert @dummy.save
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "create its thumbnails properly" do
|
||||
assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
|
||||
end
|
||||
|
||||
context "redefining its attachment styles" do
|
||||
setup do
|
||||
Dummy.class_eval do
|
||||
has_attached_file :avatar, :styles => { :thumb => "150x25#" }
|
||||
has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
|
||||
end
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
@d2.avatar.reprocess!
|
||||
@d2.save
|
||||
end
|
||||
|
||||
should "create its thumbnails properly" do
|
||||
assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
|
||||
assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A model that modifies its original" do
|
||||
setup do
|
||||
rebuild_model :styles => { :original => "2x2#" }
|
||||
@dummy = Dummy.new
|
||||
@file = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "report the file size of the processed file and not the original" do
|
||||
assert_not_equal @file.size, @dummy.avatar.size
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
end
|
||||
|
||||
context "A model with attachments scoped under an id" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "100x100",
|
||||
:medium => "50x50" },
|
||||
:path => ":rails_root/tmp/:id/:attachments/:style.:extension"
|
||||
@dummy = Dummy.new
|
||||
@file = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
context "when saved" do
|
||||
setup do
|
||||
@dummy.save
|
||||
@saved_path = @dummy.avatar.path(:large)
|
||||
end
|
||||
|
||||
should "have a large file in the right place" do
|
||||
assert File.exists?(@dummy.avatar.path(:large))
|
||||
end
|
||||
|
||||
context "and deleted" do
|
||||
setup do
|
||||
@dummy.avatar.clear
|
||||
@dummy.save
|
||||
end
|
||||
|
||||
should "not have a large file in the right place anymore" do
|
||||
assert ! File.exists?(@saved_path)
|
||||
end
|
||||
|
||||
should "not have its next two parent directories" do
|
||||
assert ! File.exists?(File.dirname(@saved_path))
|
||||
assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
|
||||
end
|
||||
|
||||
before_should "not die if an unexpected SystemCallError happens" do
|
||||
FileUtils.stubs(:rmdir).raises(Errno::EPIPE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A model with no attachment validation" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "300x300>",
|
||||
:medium => "100x100",
|
||||
:thumb => ["32x32#", :gif] },
|
||||
:default_style => :medium,
|
||||
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
||||
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "have its definition return false when asked about whiny_thumbnails" do
|
||||
assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
|
||||
end
|
||||
|
||||
context "when validates_attachment_thumbnails is called" do
|
||||
setup do
|
||||
Dummy.validates_attachment_thumbnails :avatar
|
||||
end
|
||||
|
||||
should "have its definition return true when asked about whiny_thumbnails" do
|
||||
assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
|
||||
end
|
||||
end
|
||||
|
||||
context "redefined to have attachment validations" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "300x300>",
|
||||
:medium => "100x100",
|
||||
:thumb => ["32x32#", :gif] },
|
||||
:whiny_thumbnails => true,
|
||||
:default_style => :medium,
|
||||
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
||||
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
||||
end
|
||||
|
||||
should "have its definition return true when asked about whiny_thumbnails" do
|
||||
assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A model with no convert_options setting" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "300x300>",
|
||||
:medium => "100x100",
|
||||
:thumb => ["32x32#", :gif] },
|
||||
:default_style => :medium,
|
||||
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
||||
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "have its definition return nil when asked about convert_options" do
|
||||
assert ! Dummy.attachment_definitions[:avatar][:convert_options]
|
||||
end
|
||||
|
||||
context "redefined to have convert_options setting" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "300x300>",
|
||||
:medium => "100x100",
|
||||
:thumb => ["32x32#", :gif] },
|
||||
:convert_options => "-strip -depth 8",
|
||||
:default_style => :medium,
|
||||
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
||||
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
||||
end
|
||||
|
||||
should "have its definition return convert_options value when asked about convert_options" do
|
||||
assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A model with a filesystem attachment" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "300x300>",
|
||||
:medium => "100x100",
|
||||
:thumb => ["32x32#", :gif] },
|
||||
:whiny_thumbnails => true,
|
||||
:default_style => :medium,
|
||||
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
||||
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
||||
@dummy = Dummy.new
|
||||
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
||||
@bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
|
||||
|
||||
assert @dummy.avatar = @file
|
||||
assert @dummy.valid?, @dummy.errors.full_messages.join(", ")
|
||||
assert @dummy.save
|
||||
end
|
||||
|
||||
should "write and delete its files" do
|
||||
[["434x66", :original],
|
||||
["300x46", :large],
|
||||
["100x15", :medium],
|
||||
["32x32", :thumb]].each do |geo, style|
|
||||
cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"]
|
||||
assert_equal geo, `#{cmd}`.chomp, cmd
|
||||
end
|
||||
|
||||
saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
|
||||
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp
|
||||
assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp
|
||||
assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp
|
||||
assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
|
||||
assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
|
||||
|
||||
@dummy.avatar = "not a valid file but not nil"
|
||||
assert_equal File.basename(@file.path), @dummy.avatar_file_name
|
||||
assert @dummy.valid?
|
||||
assert @dummy.save
|
||||
|
||||
saved_paths.each do |p|
|
||||
assert File.exists?(p)
|
||||
end
|
||||
|
||||
@dummy.avatar.clear
|
||||
assert_nil @dummy.avatar_file_name
|
||||
assert @dummy.valid?
|
||||
assert @dummy.save
|
||||
|
||||
saved_paths.each do |p|
|
||||
assert ! File.exists?(p)
|
||||
end
|
||||
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
assert_nil @d2.avatar_file_name
|
||||
end
|
||||
|
||||
should "work exactly the same when new as when reloaded" do
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
|
||||
assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
|
||||
[:thumb, :medium, :large, :original].each do |style|
|
||||
assert_equal @dummy.avatar.path(style), @d2.avatar.path(style)
|
||||
end
|
||||
|
||||
saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
|
||||
|
||||
@d2.avatar.clear
|
||||
assert @d2.save
|
||||
|
||||
saved_paths.each do |p|
|
||||
assert ! File.exists?(p)
|
||||
end
|
||||
end
|
||||
|
||||
should "know the difference between good files, bad files, and not files" do
|
||||
expected = @dummy.avatar.to_file
|
||||
@dummy.avatar = "not a file"
|
||||
assert @dummy.valid?
|
||||
assert_equal expected.path, @dummy.avatar.path
|
||||
expected.close
|
||||
|
||||
@dummy.avatar = @bad_file
|
||||
assert ! @dummy.valid?
|
||||
end
|
||||
|
||||
should "know the difference between good files, bad files, and not files when validating" do
|
||||
Dummy.validates_attachment_presence :avatar
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
@d2.avatar = @file
|
||||
assert @d2.valid?, @d2.errors.full_messages.inspect
|
||||
@d2.avatar = @bad_file
|
||||
assert ! @d2.valid?
|
||||
end
|
||||
|
||||
should "be able to reload without saving and not have the file disappear" do
|
||||
@dummy.avatar = @file
|
||||
assert @dummy.save
|
||||
@dummy.avatar.clear
|
||||
assert_nil @dummy.avatar_file_name
|
||||
@dummy.reload
|
||||
assert_equal "5k.png", @dummy.avatar_file_name
|
||||
end
|
||||
|
||||
context "that is assigned its file from another Paperclip attachment" do
|
||||
setup do
|
||||
@dummy2 = Dummy.new
|
||||
@file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb')
|
||||
assert @dummy2.avatar = @file2
|
||||
@dummy2.save
|
||||
end
|
||||
|
||||
should "work when assigned a file" do
|
||||
assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
|
||||
`identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
|
||||
|
||||
assert @dummy.avatar = @dummy2.avatar
|
||||
@dummy.save
|
||||
assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
|
||||
`identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "A model with an attachments association and a Paperclip attachment" do
|
||||
setup do
|
||||
Dummy.class_eval do
|
||||
has_many :attachments, :class_name => 'Dummy'
|
||||
end
|
||||
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = File.new(File.join(File.dirname(__FILE__),
|
||||
"fixtures",
|
||||
"5k.png"), 'rb')
|
||||
end
|
||||
|
||||
should "should not error when saving" do
|
||||
assert_nothing_raised do
|
||||
@dummy.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ENV['S3_TEST_BUCKET']
|
||||
def s3_files_for attachment
|
||||
[:thumb, :medium, :large, :original].inject({}) do |files, style|
|
||||
data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp
|
||||
t = Tempfile.new("paperclip-test")
|
||||
t.binmode
|
||||
t.write(data)
|
||||
t.rewind
|
||||
files[style] = t
|
||||
files
|
||||
end
|
||||
end
|
||||
|
||||
def s3_headers_for attachment, style
|
||||
`curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head|
|
||||
split_head = head.chomp.split(/\s*:\s*/, 2)
|
||||
h[split_head.first.downcase] = split_head.last unless split_head.empty?
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
context "A model with an S3 attachment" do
|
||||
setup do
|
||||
rebuild_model :styles => { :large => "300x300>",
|
||||
:medium => "100x100",
|
||||
:thumb => ["32x32#", :gif] },
|
||||
:storage => :s3,
|
||||
:whiny_thumbnails => true,
|
||||
:s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")),
|
||||
:default_style => :medium,
|
||||
:bucket => ENV['S3_TEST_BUCKET'],
|
||||
:path => ":class/:attachment/:id/:style/:basename.:extension"
|
||||
@dummy = Dummy.new
|
||||
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
||||
@bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
|
||||
|
||||
assert @dummy.avatar = @file
|
||||
assert @dummy.valid?
|
||||
assert @dummy.save
|
||||
|
||||
@files_on_s3 = s3_files_for @dummy.avatar
|
||||
end
|
||||
|
||||
should "have the same contents as the original" do
|
||||
@file.rewind
|
||||
assert_equal @file.read, @files_on_s3[:original].read
|
||||
end
|
||||
|
||||
should "write and delete its files" do
|
||||
[["434x66", :original],
|
||||
["300x46", :large],
|
||||
["100x15", :medium],
|
||||
["32x32", :thumb]].each do |geo, style|
|
||||
cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"]
|
||||
assert_equal geo, `#{cmd}`.chomp, cmd
|
||||
end
|
||||
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
@d2_files = s3_files_for @d2.avatar
|
||||
[["434x66", :original],
|
||||
["300x46", :large],
|
||||
["100x15", :medium],
|
||||
["32x32", :thumb]].each do |geo, style|
|
||||
cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"]
|
||||
assert_equal geo, `#{cmd}`.chomp, cmd
|
||||
end
|
||||
|
||||
@dummy.avatar = "not a valid file but not nil"
|
||||
assert_equal File.basename(@file.path), @dummy.avatar_file_name
|
||||
assert @dummy.valid?
|
||||
assert @dummy.save
|
||||
|
||||
[:thumb, :medium, :large, :original].each do |style|
|
||||
assert @dummy.avatar.exists?(style)
|
||||
end
|
||||
|
||||
@dummy.avatar.clear
|
||||
assert_nil @dummy.avatar_file_name
|
||||
assert @dummy.valid?
|
||||
assert @dummy.save
|
||||
|
||||
[:thumb, :medium, :large, :original].each do |style|
|
||||
assert ! @dummy.avatar.exists?(style)
|
||||
end
|
||||
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
assert_nil @d2.avatar_file_name
|
||||
end
|
||||
|
||||
should "work exactly the same when new as when reloaded" do
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
|
||||
assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
|
||||
[:thumb, :medium, :large, :original].each do |style|
|
||||
assert_equal @dummy.avatar.to_file(style).read, @d2.avatar.to_file(style).read
|
||||
end
|
||||
|
||||
saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
|
||||
|
||||
@d2.avatar.clear
|
||||
assert @d2.save
|
||||
|
||||
[:thumb, :medium, :large, :original].each do |style|
|
||||
assert ! @dummy.avatar.exists?(style)
|
||||
end
|
||||
end
|
||||
|
||||
should "know the difference between good files, bad files, not files, and nil" do
|
||||
expected = @dummy.avatar.to_file
|
||||
@dummy.avatar = "not a file"
|
||||
assert @dummy.valid?
|
||||
assert_equal expected.read, @dummy.avatar.to_file.read
|
||||
|
||||
@dummy.avatar = @bad_file
|
||||
assert ! @dummy.valid?
|
||||
@dummy.avatar = nil
|
||||
assert @dummy.valid?
|
||||
|
||||
Dummy.validates_attachment_presence :avatar
|
||||
@d2 = Dummy.find(@dummy.id)
|
||||
@d2.avatar = @file
|
||||
assert @d2.valid?
|
||||
@d2.avatar = @bad_file
|
||||
assert ! @d2.valid?
|
||||
@d2.avatar = nil
|
||||
assert ! @d2.valid?
|
||||
end
|
||||
|
||||
should "be able to reload without saving and not have the file disappear" do
|
||||
@dummy.avatar = @file
|
||||
assert @dummy.save
|
||||
@dummy.avatar = nil
|
||||
assert_nil @dummy.avatar_file_name
|
||||
@dummy.reload
|
||||
assert_equal "5k.png", @dummy.avatar_file_name
|
||||
end
|
||||
|
||||
should "have the right content type" do
|
||||
headers = s3_headers_for(@dummy.avatar, :original)
|
||||
assert_equal 'image/png', headers['content-type']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
127
vendor/plugins/paperclip/test/interpolations_test.rb
vendored
127
vendor/plugins/paperclip/test/interpolations_test.rb
vendored
@ -1,127 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class InterpolationsTest < Test::Unit::TestCase
|
||||
should "return all methods but the infrastructure when sent #all" do
|
||||
methods = Paperclip::Interpolations.all
|
||||
assert ! methods.include?(:[])
|
||||
assert ! methods.include?(:[]=)
|
||||
assert ! methods.include?(:all)
|
||||
methods.each do |m|
|
||||
assert Paperclip::Interpolations.respond_to?(m)
|
||||
end
|
||||
end
|
||||
|
||||
should "return the Rails.root" do
|
||||
assert_equal Rails.root, Paperclip::Interpolations.rails_root(:attachment, :style)
|
||||
end
|
||||
|
||||
should "return the Rails.env" do
|
||||
assert_equal Rails.env, Paperclip::Interpolations.rails_env(:attachment, :style)
|
||||
end
|
||||
|
||||
should "return the class of the Interpolations module when called with no params" do
|
||||
assert_equal Module, Paperclip::Interpolations.class
|
||||
end
|
||||
|
||||
should "return the class of the instance" do
|
||||
attachment = mock
|
||||
attachment.expects(:instance).returns(attachment)
|
||||
attachment.expects(:class).returns("Thing")
|
||||
assert_equal "things", Paperclip::Interpolations.class(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the basename of the file" do
|
||||
attachment = mock
|
||||
attachment.expects(:original_filename).returns("one.jpg").times(2)
|
||||
assert_equal "one", Paperclip::Interpolations.basename(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the extension of the file" do
|
||||
attachment = mock
|
||||
attachment.expects(:original_filename).returns("one.jpg")
|
||||
attachment.expects(:styles).returns({})
|
||||
assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the extension of the file as the format if defined in the style" do
|
||||
attachment = mock
|
||||
attachment.expects(:original_filename).never
|
||||
attachment.expects(:styles).returns({:style => {:format => "png"}})
|
||||
assert_equal "png", Paperclip::Interpolations.extension(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the id of the attachment" do
|
||||
attachment = mock
|
||||
attachment.expects(:id).returns(23)
|
||||
attachment.expects(:instance).returns(attachment)
|
||||
assert_equal 23, Paperclip::Interpolations.id(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the partitioned id of the attachment" do
|
||||
attachment = mock
|
||||
attachment.expects(:id).returns(23)
|
||||
attachment.expects(:instance).returns(attachment)
|
||||
assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the name of the attachment" do
|
||||
attachment = mock
|
||||
attachment.expects(:name).returns("file")
|
||||
assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the style" do
|
||||
assert_equal :style, Paperclip::Interpolations.style(:attachment, :style)
|
||||
end
|
||||
|
||||
should "return the default style" do
|
||||
attachment = mock
|
||||
attachment.expects(:default_style).returns(:default_style)
|
||||
assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil)
|
||||
end
|
||||
|
||||
should "reinterpolate :url" do
|
||||
attachment = mock
|
||||
attachment.expects(:url).with(:style, false).returns("1234")
|
||||
assert_equal "1234", Paperclip::Interpolations.url(attachment, :style)
|
||||
end
|
||||
|
||||
should "raise if infinite loop detcted reinterpolating :url" do
|
||||
attachment = Object.new
|
||||
class << attachment
|
||||
def url(*args)
|
||||
Paperclip::Interpolations.url(self, :style)
|
||||
end
|
||||
end
|
||||
assert_raises(Paperclip::InfiniteInterpolationError){ Paperclip::Interpolations.url(attachment, :style) }
|
||||
end
|
||||
|
||||
should "return the filename as basename.extension" do
|
||||
attachment = mock
|
||||
attachment.expects(:styles).returns({})
|
||||
attachment.expects(:original_filename).returns("one.jpg").times(3)
|
||||
assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the filename as basename.extension when format supplied" do
|
||||
attachment = mock
|
||||
attachment.expects(:styles).returns({:style => {:format => :png}})
|
||||
attachment.expects(:original_filename).returns("one.jpg").times(2)
|
||||
assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
|
||||
end
|
||||
|
||||
should "return the timestamp" do
|
||||
now = Time.now
|
||||
attachment = mock
|
||||
attachment.expects(:instance_read).with(:updated_at).returns(now)
|
||||
assert_equal now.to_s, Paperclip::Interpolations.timestamp(attachment, :style)
|
||||
end
|
||||
|
||||
should "call all expected interpolations with the given arguments" do
|
||||
Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234)
|
||||
Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments")
|
||||
Paperclip::Interpolations.expects(:notreal).never
|
||||
value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style)
|
||||
assert_equal ":notreal/1234/attachments", value
|
||||
end
|
||||
end
|
||||
78
vendor/plugins/paperclip/test/iostream_test.rb
vendored
78
vendor/plugins/paperclip/test/iostream_test.rb
vendored
@ -1,78 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class IOStreamTest < Test::Unit::TestCase
|
||||
context "IOStream" do
|
||||
should "be included in IO, File, Tempfile, and StringIO" do
|
||||
[IO, File, Tempfile, StringIO].each do |klass|
|
||||
assert klass.included_modules.include?(IOStream), "Not in #{klass}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A file" do
|
||||
setup do
|
||||
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
context "that is sent #stream_to" do
|
||||
|
||||
context "and given a String" do
|
||||
setup do
|
||||
FileUtils.mkdir_p(File.join(ROOT, 'tmp'))
|
||||
assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test'))
|
||||
end
|
||||
|
||||
should "return a File" do
|
||||
assert @result.is_a?(File)
|
||||
end
|
||||
|
||||
should "contain the same data as the original file" do
|
||||
@file.rewind; @result.rewind
|
||||
assert_equal @file.read, @result.read
|
||||
end
|
||||
end
|
||||
|
||||
context "and given a Tempfile" do
|
||||
setup do
|
||||
tempfile = Tempfile.new('iostream.test')
|
||||
tempfile.binmode
|
||||
assert @result = @file.stream_to(tempfile)
|
||||
end
|
||||
|
||||
should "return a Tempfile" do
|
||||
assert @result.is_a?(Tempfile)
|
||||
end
|
||||
|
||||
should "contain the same data as the original file" do
|
||||
@file.rewind; @result.rewind
|
||||
assert_equal @file.read, @result.read
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "that is sent #to_tempfile" do
|
||||
setup do
|
||||
assert @tempfile = @file.to_tempfile
|
||||
end
|
||||
|
||||
should "convert it to a Paperclip Tempfile" do
|
||||
assert @tempfile.is_a?(Paperclip::Tempfile)
|
||||
end
|
||||
|
||||
should "have the name be based on the original_filename" do
|
||||
name = File.basename(@file.path)
|
||||
extension = File.extname(name)
|
||||
basename = File.basename(name, extension)
|
||||
assert_match %r[^stream.*?#{Regexp.quote(extension)}], File.basename(@tempfile.path)
|
||||
end
|
||||
|
||||
should "have the Tempfile contain the same data as the file" do
|
||||
@file.rewind; @tempfile.rewind
|
||||
assert_equal @file.read, @tempfile.read
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,24 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class HaveAttachedFileMatcherTest < Test::Unit::TestCase
|
||||
context "have_attached_file" do
|
||||
setup do
|
||||
@dummy_class = reset_class "Dummy"
|
||||
reset_table "dummies"
|
||||
@matcher = self.class.have_attached_file(:avatar)
|
||||
end
|
||||
|
||||
context "given a class with no attachment" do
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with an attachment" do
|
||||
setup do
|
||||
modify_table("dummies"){|d| d.string :avatar_file_name }
|
||||
@dummy_class.has_attached_file :avatar
|
||||
end
|
||||
|
||||
should_accept_dummy_class
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,47 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
|
||||
context "validate_attachment_content_type" do
|
||||
setup do
|
||||
reset_table("dummies") do |d|
|
||||
d.string :title
|
||||
d.string :avatar_file_name
|
||||
d.string :avatar_content_type
|
||||
end
|
||||
@dummy_class = reset_class "Dummy"
|
||||
@dummy_class.has_attached_file :avatar
|
||||
@matcher = self.class.validate_attachment_content_type(:avatar).
|
||||
allowing(%w(image/png image/jpeg)).
|
||||
rejecting(%w(audio/mp3 application/octet-stream))
|
||||
end
|
||||
|
||||
context "given a class with no validation" do
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with a validation that doesn't match" do
|
||||
setup do
|
||||
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
|
||||
end
|
||||
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with a matching validation" do
|
||||
setup do
|
||||
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
||||
end
|
||||
|
||||
should_accept_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with other validations but matching types" do
|
||||
setup do
|
||||
@dummy_class.validates_presence_of :title
|
||||
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
||||
end
|
||||
|
||||
should_accept_dummy_class
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,26 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
|
||||
context "validate_attachment_presence" do
|
||||
setup do
|
||||
reset_table("dummies") do |d|
|
||||
d.string :avatar_file_name
|
||||
end
|
||||
@dummy_class = reset_class "Dummy"
|
||||
@dummy_class.has_attached_file :avatar
|
||||
@matcher = self.class.validate_attachment_presence(:avatar)
|
||||
end
|
||||
|
||||
context "given a class with no validation" do
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with a matching validation" do
|
||||
setup do
|
||||
@dummy_class.validates_attachment_presence :avatar
|
||||
end
|
||||
|
||||
should_accept_dummy_class
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,51 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
|
||||
context "validate_attachment_size" do
|
||||
setup do
|
||||
reset_table("dummies") do |d|
|
||||
d.string :avatar_file_name
|
||||
d.integer :avatar_file_size
|
||||
end
|
||||
@dummy_class = reset_class "Dummy"
|
||||
@dummy_class.has_attached_file :avatar
|
||||
end
|
||||
|
||||
context "of limited size" do
|
||||
setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) }
|
||||
|
||||
context "given a class with no validation" do
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with a validation that's too high" do
|
||||
setup { @dummy_class.validates_attachment_size :avatar, :in => 256..2048 }
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with a validation that's too low" do
|
||||
setup { @dummy_class.validates_attachment_size :avatar, :in => 0..1024 }
|
||||
should_reject_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with a validation that matches" do
|
||||
setup { @dummy_class.validates_attachment_size :avatar, :in => 256..1024 }
|
||||
should_accept_dummy_class
|
||||
end
|
||||
end
|
||||
|
||||
context "validates_attachment_size with infinite range" do
|
||||
setup{ @matcher = self.class.validate_attachment_size(:avatar) }
|
||||
|
||||
context "given a class with an upper limit" do
|
||||
setup { @dummy_class.validates_attachment_size :avatar, :less_than => 1 }
|
||||
should_accept_dummy_class
|
||||
end
|
||||
|
||||
context "given a class with no upper limit" do
|
||||
setup { @dummy_class.validates_attachment_size :avatar, :greater_than => 1 }
|
||||
should_accept_dummy_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
254
vendor/plugins/paperclip/test/paperclip_test.rb
vendored
254
vendor/plugins/paperclip/test/paperclip_test.rb
vendored
@ -1,254 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class PaperclipTest < Test::Unit::TestCase
|
||||
context "Calling Paperclip.run" do
|
||||
setup do
|
||||
Paperclip.options[:image_magick_path] = nil
|
||||
Paperclip.options[:command_path] = nil
|
||||
Paperclip::CommandLine.stubs(:'`')
|
||||
end
|
||||
|
||||
should "execute the right command with :image_magick_path" do
|
||||
Paperclip.options[:image_magick_path] = "/usr/bin"
|
||||
Paperclip.expects(:log).with(includes('[DEPRECATION]'))
|
||||
Paperclip.expects(:log).with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
||||
Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
||||
Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
|
||||
end
|
||||
|
||||
should "execute the right command with :command_path" do
|
||||
Paperclip.options[:command_path] = "/usr/bin"
|
||||
Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
||||
Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
|
||||
end
|
||||
|
||||
should "execute the right command with no path" do
|
||||
Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
||||
Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
|
||||
end
|
||||
|
||||
should "tell you the command isn't there if the shell returns 127" do
|
||||
with_exitstatus_returning(127) do
|
||||
assert_raises(Paperclip::CommandNotFoundError) do
|
||||
Paperclip.run("command")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "tell you the command isn't there if an ENOENT is raised" do
|
||||
assert_raises(Paperclip::CommandNotFoundError) do
|
||||
Paperclip::CommandLine.stubs(:"`").raises(Errno::ENOENT)
|
||||
Paperclip.run("command")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
|
||||
assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
|
||||
end
|
||||
|
||||
should "raise when sent #processor and the name of a class that doesn't exist" do
|
||||
assert_raises(NameError){ Paperclip.processor(:boogey_man) }
|
||||
end
|
||||
|
||||
should "return a class when sent #processor and the name of a class under Paperclip" do
|
||||
assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
|
||||
end
|
||||
|
||||
context "An ActiveRecord model with an 'avatar' attachment" do
|
||||
setup do
|
||||
rebuild_model :path => "tmp/:class/omg/:style.:extension"
|
||||
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "not error when trying to also create a 'blah' attachment" do
|
||||
assert_nothing_raised do
|
||||
Dummy.class_eval do
|
||||
has_attached_file :blah
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "that is attr_protected" do
|
||||
setup do
|
||||
Dummy.class_eval do
|
||||
attr_protected :avatar
|
||||
end
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "not assign the avatar on mass-set" do
|
||||
@dummy.attributes = { :other => "I'm set!",
|
||||
:avatar => @file }
|
||||
|
||||
assert_equal "I'm set!", @dummy.other
|
||||
assert ! @dummy.avatar?
|
||||
end
|
||||
|
||||
should "still allow assigment on normal set" do
|
||||
@dummy.other = "I'm set!"
|
||||
@dummy.avatar = @file
|
||||
|
||||
assert_equal "I'm set!", @dummy.other
|
||||
assert @dummy.avatar?
|
||||
end
|
||||
end
|
||||
|
||||
context "with a subclass" do
|
||||
setup do
|
||||
class ::SubDummy < Dummy; end
|
||||
end
|
||||
|
||||
should "be able to use the attachment from the subclass" do
|
||||
assert_nothing_raised do
|
||||
@subdummy = SubDummy.create(:avatar => @file)
|
||||
end
|
||||
end
|
||||
|
||||
should "be able to see the attachment definition from the subclass's class" do
|
||||
assert_equal "tmp/:class/omg/:style.:extension",
|
||||
SubDummy.attachment_definitions[:avatar][:path]
|
||||
end
|
||||
|
||||
teardown do
|
||||
Object.send(:remove_const, "SubDummy") rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
should "have an #avatar method" do
|
||||
assert Dummy.new.respond_to?(:avatar)
|
||||
end
|
||||
|
||||
should "have an #avatar= method" do
|
||||
assert Dummy.new.respond_to?(:avatar=)
|
||||
end
|
||||
|
||||
context "that is valid" do
|
||||
setup do
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
should "be valid" do
|
||||
assert @dummy.valid?
|
||||
end
|
||||
end
|
||||
|
||||
context "a validation with an if guard clause" do
|
||||
setup do
|
||||
Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo })
|
||||
@dummy = Dummy.new
|
||||
@dummy.stubs(:avatar_file_name).returns(nil)
|
||||
end
|
||||
|
||||
should "attempt validation if the guard returns true" do
|
||||
@dummy.expects(:foo).returns(true)
|
||||
assert ! @dummy.valid?
|
||||
end
|
||||
|
||||
should "not attempt validation if the guard returns false" do
|
||||
@dummy.expects(:foo).returns(false)
|
||||
assert @dummy.valid?
|
||||
end
|
||||
end
|
||||
|
||||
context "a validation with an unless guard clause" do
|
||||
setup do
|
||||
Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
|
||||
@dummy = Dummy.new
|
||||
@dummy.stubs(:avatar_file_name).returns(nil)
|
||||
end
|
||||
|
||||
should "attempt validation if the guard returns true" do
|
||||
@dummy.expects(:foo).returns(false)
|
||||
assert ! @dummy.valid?
|
||||
end
|
||||
|
||||
should "not attempt validation if the guard returns false" do
|
||||
@dummy.expects(:foo).returns(true)
|
||||
assert @dummy.valid?
|
||||
end
|
||||
end
|
||||
|
||||
should "not have Attachment in the ActiveRecord::Base namespace" do
|
||||
assert_raises(NameError) do
|
||||
ActiveRecord::Base::Attachment
|
||||
end
|
||||
end
|
||||
|
||||
def self.should_validate validation, options, valid_file, invalid_file
|
||||
context "with #{validation} validation and #{options.inspect} options" do
|
||||
setup do
|
||||
rebuild_class
|
||||
Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
context "and assigning nil" do
|
||||
setup do
|
||||
@dummy.avatar = nil
|
||||
@dummy.valid?
|
||||
end
|
||||
if validation == :presence
|
||||
should "have an error on the attachment" do
|
||||
assert @dummy.errors[:avatar_file_name]
|
||||
end
|
||||
else
|
||||
should "not have an error on the attachment" do
|
||||
assert @dummy.errors.blank?, @dummy.errors.full_messages.join(", ")
|
||||
end
|
||||
end
|
||||
end
|
||||
context "and assigned a valid file" do
|
||||
setup do
|
||||
@dummy.avatar = valid_file
|
||||
@dummy.valid?
|
||||
end
|
||||
should "not have an error when assigned a valid file" do
|
||||
assert_equal 0, @dummy.errors.length, @dummy.errors.full_messages.join(", ")
|
||||
end
|
||||
end
|
||||
context "and assigned an invalid file" do
|
||||
setup do
|
||||
@dummy.avatar = invalid_file
|
||||
@dummy.valid?
|
||||
end
|
||||
should "have an error when assigned a valid file" do
|
||||
assert @dummy.errors.length > 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[[:presence, {}, "5k.png", nil],
|
||||
[:size, {:in => 1..10240}, "5k.png", "12k.png"],
|
||||
[:size, {:less_than => 10240}, "5k.png", "12k.png"],
|
||||
[:size, {:greater_than => 8096}, "12k.png", "5k.png"],
|
||||
[:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
|
||||
[:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
|
||||
[:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
|
||||
validation, options, valid_file, invalid_file = args
|
||||
valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
|
||||
invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
|
||||
|
||||
should_validate validation, options, valid_file, invalid_file
|
||||
end
|
||||
|
||||
context "with size validation and less_than 10240 option" do
|
||||
context "and assigned an invalid file" do
|
||||
setup do
|
||||
Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240)
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
|
||||
@dummy.valid?
|
||||
end
|
||||
|
||||
should "have a file size min/max error message" do
|
||||
assert [@dummy.errors[:avatar_file_size]].flatten.any?{|error| error =~ %r/between 0 and 10240 bytes/ }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
10
vendor/plugins/paperclip/test/processor_test.rb
vendored
10
vendor/plugins/paperclip/test/processor_test.rb
vendored
@ -1,10 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class ProcessorTest < Test::Unit::TestCase
|
||||
should "instantiate and call #make when sent #make to the class" do
|
||||
processor = mock
|
||||
processor.expects(:make).with()
|
||||
Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor)
|
||||
Paperclip::Processor.make(:one, :two, :three)
|
||||
end
|
||||
end
|
||||
358
vendor/plugins/paperclip/test/storage_test.rb
vendored
358
vendor/plugins/paperclip/test/storage_test.rb
vendored
@ -1,358 +0,0 @@
|
||||
require 'test/helper'
|
||||
require 'aws/s3'
|
||||
|
||||
class StorageTest < Test::Unit::TestCase
|
||||
def rails_env(env)
|
||||
silence_warnings do
|
||||
Object.const_set(:Rails, stub('Rails', :env => env))
|
||||
end
|
||||
end
|
||||
|
||||
context "Parsing S3 credentials" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:bucket => "testing",
|
||||
:s3_credentials => {:not => :important}
|
||||
|
||||
@dummy = Dummy.new
|
||||
@avatar = @dummy.avatar
|
||||
end
|
||||
|
||||
should "get the correct credentials when RAILS_ENV is production" do
|
||||
rails_env("production")
|
||||
assert_equal({:key => "12345"},
|
||||
@avatar.parse_credentials('production' => {:key => '12345'},
|
||||
:development => {:key => "54321"}))
|
||||
end
|
||||
|
||||
should "get the correct credentials when RAILS_ENV is development" do
|
||||
rails_env("development")
|
||||
assert_equal({:key => "54321"},
|
||||
@avatar.parse_credentials('production' => {:key => '12345'},
|
||||
:development => {:key => "54321"}))
|
||||
end
|
||||
|
||||
should "return the argument if the key does not exist" do
|
||||
rails_env("not really an env")
|
||||
assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
|
||||
end
|
||||
end
|
||||
|
||||
context "" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => {},
|
||||
:bucket => "bucket",
|
||||
:path => ":attachment/:basename.:extension",
|
||||
:url => ":s3_path_url"
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = StringIO.new(".")
|
||||
end
|
||||
|
||||
should "return a url based on an S3 path" do
|
||||
assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
|
||||
end
|
||||
end
|
||||
context "" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => {},
|
||||
:bucket => "bucket",
|
||||
:path => ":attachment/:basename.:extension",
|
||||
:url => ":s3_domain_url"
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = StringIO.new(".")
|
||||
end
|
||||
|
||||
should "return a url based on an S3 subdomain" do
|
||||
assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
|
||||
end
|
||||
end
|
||||
context "" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => {
|
||||
:production => { :bucket => "prod_bucket" },
|
||||
:development => { :bucket => "dev_bucket" }
|
||||
},
|
||||
:s3_host_alias => "something.something.com",
|
||||
:path => ":attachment/:basename.:extension",
|
||||
:url => ":s3_alias_url"
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = StringIO.new(".")
|
||||
end
|
||||
|
||||
should "return a url based on the host_alias" do
|
||||
assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
|
||||
end
|
||||
end
|
||||
|
||||
context "Generating a url with an expiration" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => {
|
||||
:production => { :bucket => "prod_bucket" },
|
||||
:development => { :bucket => "dev_bucket" }
|
||||
},
|
||||
:s3_host_alias => "something.something.com",
|
||||
:path => ":attachment/:basename.:extension",
|
||||
:url => ":s3_alias_url"
|
||||
|
||||
rails_env("production")
|
||||
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = StringIO.new(".")
|
||||
|
||||
AWS::S3::S3Object.expects(:url_for).with("avatars/stringio.txt", "prod_bucket", { :expires_in => 3600 })
|
||||
|
||||
@dummy.avatar.expiring_url
|
||||
end
|
||||
|
||||
should "should succeed" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
|
||||
context "Parsing S3 credentials with a bucket in them" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => {
|
||||
:production => { :bucket => "prod_bucket" },
|
||||
:development => { :bucket => "dev_bucket" }
|
||||
}
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "get the right bucket in production" do
|
||||
rails_env("production")
|
||||
assert_equal "prod_bucket", @dummy.avatar.bucket_name
|
||||
end
|
||||
|
||||
should "get the right bucket in development" do
|
||||
rails_env("development")
|
||||
assert_equal "dev_bucket", @dummy.avatar.bucket_name
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with S3 storage" do
|
||||
setup do
|
||||
rebuild_model :storage => :s3,
|
||||
:bucket => "testing",
|
||||
:path => ":attachment/:style/:basename.:extension",
|
||||
:s3_credentials => {
|
||||
'access_key_id' => "12345",
|
||||
'secret_access_key' => "54321"
|
||||
}
|
||||
end
|
||||
|
||||
should "be extended by the S3 module" do
|
||||
assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
|
||||
end
|
||||
|
||||
should "not be extended by the Filesystem module" do
|
||||
assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
|
||||
end
|
||||
|
||||
context "when assigned" do
|
||||
setup do
|
||||
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "not get a bucket to get a URL" do
|
||||
@dummy.avatar.expects(:s3).never
|
||||
@dummy.avatar.expects(:s3_bucket).never
|
||||
assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
|
||||
end
|
||||
|
||||
context "and saved" do
|
||||
setup do
|
||||
AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
|
||||
@dummy.save
|
||||
end
|
||||
|
||||
should "succeed" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
|
||||
context "and saved without a bucket" do
|
||||
setup do
|
||||
class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
|
||||
# Force the class to be created as a proper subclass of ResponseError thanks to AWS::S3's autocreation of exceptions
|
||||
end
|
||||
AWS::S3::Bucket.expects(:create).with("testing")
|
||||
AWS::S3::S3Object.stubs(:store).raises(AWS::S3::NoSuchBucket.new(:message, :response)).then.returns(true)
|
||||
@dummy.save
|
||||
end
|
||||
|
||||
should "succeed" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
|
||||
context "and remove" do
|
||||
setup do
|
||||
AWS::S3::S3Object.stubs(:exists?).returns(true)
|
||||
AWS::S3::S3Object.stubs(:delete)
|
||||
@dummy.destroy_attached_files
|
||||
end
|
||||
|
||||
should "succeed" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with S3 storage and bucket defined as a Proc" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
|
||||
:s3_credentials => {:not => :important}
|
||||
end
|
||||
|
||||
should "get the right bucket name" do
|
||||
assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name
|
||||
assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with S3 storage and specific s3 headers set" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
rebuild_model :storage => :s3,
|
||||
:bucket => "testing",
|
||||
:path => ":attachment/:style/:basename.:extension",
|
||||
:s3_credentials => {
|
||||
'access_key_id' => "12345",
|
||||
'secret_access_key' => "54321"
|
||||
},
|
||||
:s3_headers => {'Cache-Control' => 'max-age=31557600'}
|
||||
end
|
||||
|
||||
context "when assigned" do
|
||||
setup do
|
||||
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
||||
@dummy = Dummy.new
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
context "and saved" do
|
||||
setup do
|
||||
AWS::S3::Base.stubs(:establish_connection!)
|
||||
AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path,
|
||||
anything,
|
||||
'testing',
|
||||
:content_type => 'image/png',
|
||||
:access => :public_read,
|
||||
'Cache-Control' => 'max-age=31557600')
|
||||
@dummy.save
|
||||
end
|
||||
|
||||
should "succeed" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with S3 credentials supplied as Pathname" do
|
||||
setup do
|
||||
ENV['S3_KEY'] = 'pathname_key'
|
||||
ENV['S3_BUCKET'] = 'pathname_bucket'
|
||||
ENV['S3_SECRET'] = 'pathname_secret'
|
||||
|
||||
rails_env('test')
|
||||
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => Pathname.new(File.join(File.dirname(__FILE__))).join("fixtures/s3.yml")
|
||||
|
||||
Dummy.delete_all
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "parse the credentials" do
|
||||
assert_equal 'pathname_bucket', @dummy.avatar.bucket_name
|
||||
assert_equal 'pathname_key', AWS::S3::Base.connection.options[:access_key_id]
|
||||
assert_equal 'pathname_secret', AWS::S3::Base.connection.options[:secret_access_key]
|
||||
end
|
||||
end
|
||||
|
||||
context "with S3 credentials in a YAML file" do
|
||||
setup do
|
||||
ENV['S3_KEY'] = 'env_key'
|
||||
ENV['S3_BUCKET'] = 'env_bucket'
|
||||
ENV['S3_SECRET'] = 'env_secret'
|
||||
|
||||
rails_env('test')
|
||||
|
||||
rebuild_model :storage => :s3,
|
||||
:s3_credentials => File.new(File.join(File.dirname(__FILE__), "fixtures/s3.yml"))
|
||||
|
||||
Dummy.delete_all
|
||||
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "run it the file through ERB" do
|
||||
assert_equal 'env_bucket', @dummy.avatar.bucket_name
|
||||
assert_equal 'env_key', AWS::S3::Base.connection.options[:access_key_id]
|
||||
assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
|
||||
end
|
||||
end
|
||||
|
||||
unless ENV["S3_TEST_BUCKET"].blank?
|
||||
context "Using S3 for real, an attachment with S3 storage" do
|
||||
setup do
|
||||
rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
|
||||
:storage => :s3,
|
||||
:bucket => ENV["S3_TEST_BUCKET"],
|
||||
:path => ":class/:attachment/:id/:style.:extension",
|
||||
:s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml"))
|
||||
|
||||
Dummy.delete_all
|
||||
@dummy = Dummy.new
|
||||
end
|
||||
|
||||
should "be extended by the S3 module" do
|
||||
assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
|
||||
end
|
||||
|
||||
context "when assigned" do
|
||||
setup do
|
||||
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
||||
@dummy.avatar = @file
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "still return a Tempfile when sent #to_file" do
|
||||
assert_equal Paperclip::Tempfile, @dummy.avatar.to_file.class
|
||||
end
|
||||
|
||||
context "and saved" do
|
||||
setup do
|
||||
@dummy.save
|
||||
end
|
||||
|
||||
should "be on S3" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
141
vendor/plugins/paperclip/test/style_test.rb
vendored
141
vendor/plugins/paperclip/test/style_test.rb
vendored
@ -1,141 +0,0 @@
|
||||
# encoding: utf-8
|
||||
require 'test/helper'
|
||||
|
||||
class StyleTest < Test::Unit::TestCase
|
||||
|
||||
context "A style rule" do
|
||||
setup do
|
||||
@attachment = attachment :path => ":basename.:extension",
|
||||
:styles => { :foo => {:geometry => "100x100#", :format => :png} }
|
||||
@style = @attachment.styles[:foo]
|
||||
end
|
||||
|
||||
should "be held as a Style object" do
|
||||
assert_kind_of Paperclip::Style, @style
|
||||
end
|
||||
|
||||
should "get processors from the attachment definition" do
|
||||
assert_equal [:thumbnail], @style.processors
|
||||
end
|
||||
|
||||
should "have the right geometry" do
|
||||
assert_equal "100x100#", @style.geometry
|
||||
end
|
||||
|
||||
should "be whiny if the attachment is" do
|
||||
@attachment.expects(:whiny).returns(true)
|
||||
assert @style.whiny?
|
||||
end
|
||||
|
||||
should "respond to hash notation" do
|
||||
assert_equal [:thumbnail], @style[:processors]
|
||||
assert_equal "100x100#", @style[:geometry]
|
||||
end
|
||||
end
|
||||
|
||||
context "A style rule with properties supplied as procs" do
|
||||
setup do
|
||||
@attachment = attachment :path => ":basename.:extension",
|
||||
:whiny_thumbnails => true,
|
||||
:processors => lambda {|a| [:test]},
|
||||
:styles => {
|
||||
:foo => lambda{|a| "300x300#"},
|
||||
:bar => {
|
||||
:geometry => lambda{|a| "300x300#"}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
should "defer processing of procs until they are needed" do
|
||||
assert_kind_of Proc, @attachment.styles[:foo].instance_variable_get("@geometry")
|
||||
assert_kind_of Proc, @attachment.styles[:bar].instance_variable_get("@geometry")
|
||||
assert_kind_of Proc, @attachment.instance_variable_get("@processors")
|
||||
end
|
||||
|
||||
should "call procs when they are needed" do
|
||||
assert_equal "300x300#", @attachment.styles[:foo].geometry
|
||||
assert_equal "300x300#", @attachment.styles[:bar].geometry
|
||||
assert_equal [:test], @attachment.styles[:foo].processors
|
||||
assert_equal [:test], @attachment.styles[:bar].processors
|
||||
end
|
||||
end
|
||||
|
||||
context "An attachment with style rules in various forms" do
|
||||
setup do
|
||||
@attachment = attachment :path => ":basename.:extension",
|
||||
:styles => {
|
||||
:aslist => ["100x100", :png],
|
||||
:ashash => {:geometry => "100x100", :format => :png},
|
||||
:asstring => "100x100"
|
||||
}
|
||||
end
|
||||
should "have the right number of styles" do
|
||||
assert_kind_of Hash, @attachment.styles
|
||||
assert_equal 3, @attachment.styles.size
|
||||
end
|
||||
|
||||
should "have styles as Style objects" do
|
||||
[:aslist, :ashash, :aslist].each do |s|
|
||||
assert_kind_of Paperclip::Style, @attachment.styles[s]
|
||||
end
|
||||
end
|
||||
|
||||
should "have the right geometries" do
|
||||
[:aslist, :ashash, :aslist].each do |s|
|
||||
assert_equal @attachment.styles[s].geometry, "100x100"
|
||||
end
|
||||
end
|
||||
|
||||
should "have the right formats" do
|
||||
assert_equal @attachment.styles[:aslist].format, :png
|
||||
assert_equal @attachment.styles[:ashash].format, :png
|
||||
assert_nil @attachment.styles[:asstring].format
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "An attachment with :convert_options" do
|
||||
setup do
|
||||
@attachment = attachment :path => ":basename.:extension",
|
||||
:styles => {:thumb => "100x100", :large => "400x400"},
|
||||
:convert_options => {:all => "-do_stuff", :thumb => "-thumbnailize"}
|
||||
@style = @attachment.styles[:thumb]
|
||||
@file = StringIO.new("...")
|
||||
@file.stubs(:original_filename).returns("file.jpg")
|
||||
end
|
||||
|
||||
before_should "not have called extra_options_for(:thumb/:large) on initialization" do
|
||||
@attachment.expects(:extra_options_for).never
|
||||
end
|
||||
|
||||
should "call extra_options_for(:thumb/:large) when convert options are requested" do
|
||||
@attachment.expects(:extra_options_for).with(:thumb)
|
||||
@attachment.styles[:thumb].convert_options
|
||||
end
|
||||
end
|
||||
|
||||
context "A style rule with its own :processors" do
|
||||
setup do
|
||||
@attachment = attachment :path => ":basename.:extension",
|
||||
:styles => {
|
||||
:foo => {
|
||||
:geometry => "100x100#",
|
||||
:format => :png,
|
||||
:processors => [:test]
|
||||
}
|
||||
},
|
||||
:processors => [:thumbnail]
|
||||
@style = @attachment.styles[:foo]
|
||||
end
|
||||
|
||||
should "not get processors from the attachment" do
|
||||
@attachment.expects(:processors).never
|
||||
assert_not_equal [:thumbnail], @style.processors
|
||||
end
|
||||
|
||||
should "report its own processors" do
|
||||
assert_equal [:test], @style.processors
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
228
vendor/plugins/paperclip/test/thumbnail_test.rb
vendored
228
vendor/plugins/paperclip/test/thumbnail_test.rb
vendored
@ -1,228 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class ThumbnailTest < Test::Unit::TestCase
|
||||
|
||||
context "A Paperclip Tempfile" do
|
||||
setup do
|
||||
@tempfile = Paperclip::Tempfile.new(["file", ".jpg"])
|
||||
end
|
||||
|
||||
should "have its path contain a real extension" do
|
||||
p @tempfile.path
|
||||
assert_equal ".jpg", File.extname(@tempfile.path)
|
||||
end
|
||||
|
||||
should "be a real Tempfile" do
|
||||
assert @tempfile.is_a?(::Tempfile)
|
||||
end
|
||||
end
|
||||
|
||||
context "Another Paperclip Tempfile" do
|
||||
setup do
|
||||
@tempfile = Paperclip::Tempfile.new("file")
|
||||
end
|
||||
|
||||
should "not have an extension if not given one" do
|
||||
assert_equal "", File.extname(@tempfile.path)
|
||||
end
|
||||
|
||||
should "still be a real Tempfile" do
|
||||
assert @tempfile.is_a?(::Tempfile)
|
||||
end
|
||||
end
|
||||
|
||||
context "An image" do
|
||||
setup do
|
||||
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
[["600x600>", "434x66"],
|
||||
["400x400>", "400x61"],
|
||||
["32x32<", "434x66"]
|
||||
].each do |args|
|
||||
context "being thumbnailed with a geometry of #{args[0]}" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file, :geometry => args[0])
|
||||
end
|
||||
|
||||
should "start with dimensions of 434x66" do
|
||||
cmd = %Q[identify -format "%wx%h" "#{@file.path}"]
|
||||
assert_equal "434x66", `#{cmd}`.chomp
|
||||
end
|
||||
|
||||
should "report the correct target geometry" do
|
||||
assert_equal args[0], @thumb.target_geometry.to_s
|
||||
end
|
||||
|
||||
context "when made" do
|
||||
setup do
|
||||
@thumb_result = @thumb.make
|
||||
end
|
||||
|
||||
should "be the size we expect it to be" do
|
||||
cmd = %Q[identify -format "%wx%h" "#{@thumb_result.path}"]
|
||||
assert_equal args[1], `#{cmd}`.chomp
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "being thumbnailed at 100x50 with cropping" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#")
|
||||
end
|
||||
|
||||
should "report its correct current and target geometries" do
|
||||
assert_equal "100x50#", @thumb.target_geometry.to_s
|
||||
assert_equal "434x66", @thumb.current_geometry.to_s
|
||||
end
|
||||
|
||||
should "report its correct format" do
|
||||
assert_nil @thumb.format
|
||||
end
|
||||
|
||||
should "have whiny turned on by default" do
|
||||
assert @thumb.whiny
|
||||
end
|
||||
|
||||
should "have convert_options set to nil by default" do
|
||||
assert_equal nil, @thumb.convert_options
|
||||
end
|
||||
|
||||
should "send the right command to convert when sent #make" do
|
||||
Paperclip::CommandLine.expects(:"`").with do |arg|
|
||||
arg.match %r{convert ["']#{File.expand_path(@thumb.file.path)}\[0\]["'] -resize ["']x50["'] -crop ["']100x50\+114\+0["'] \+repage ["'].*?["']}
|
||||
end
|
||||
@thumb.make
|
||||
end
|
||||
|
||||
should "create the thumbnail when sent #make" do
|
||||
dst = @thumb.make
|
||||
assert_match /100x50/, `identify "#{dst.path}"`
|
||||
end
|
||||
end
|
||||
|
||||
context "being thumbnailed with source file options set" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file,
|
||||
:geometry => "100x50#",
|
||||
:source_file_options => "-strip")
|
||||
end
|
||||
|
||||
should "have source_file_options value set" do
|
||||
assert_equal ["-strip"], @thumb.source_file_options
|
||||
end
|
||||
|
||||
should "send the right command to convert when sent #make" do
|
||||
Paperclip::CommandLine.expects(:"`").with do |arg|
|
||||
arg.match %r{convert -strip ["']#{File.expand_path(@thumb.file.path)}\[0\]["'] -resize ["']x50["'] -crop ["']100x50\+114\+0["'] \+repage ["'].*?["']}
|
||||
end
|
||||
@thumb.make
|
||||
end
|
||||
|
||||
should "create the thumbnail when sent #make" do
|
||||
dst = @thumb.make
|
||||
assert_match /100x50/, `identify "#{dst.path}"`
|
||||
end
|
||||
|
||||
context "redefined to have bad source_file_options setting" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file,
|
||||
:geometry => "100x50#",
|
||||
:source_file_options => "-this-aint-no-option")
|
||||
end
|
||||
|
||||
should "error when trying to create the thumbnail" do
|
||||
assert_raises(Paperclip::PaperclipError) do
|
||||
@thumb.make
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "being thumbnailed with convert options set" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file,
|
||||
:geometry => "100x50#",
|
||||
:convert_options => "-strip -depth 8")
|
||||
end
|
||||
|
||||
should "have convert_options value set" do
|
||||
assert_equal %w"-strip -depth 8", @thumb.convert_options
|
||||
end
|
||||
|
||||
should "send the right command to convert when sent #make" do
|
||||
Paperclip::CommandLine.expects(:"`").with do |arg|
|
||||
arg.match %r{convert ["']#{File.expand_path(@thumb.file.path)}\[0\]["'] -resize ["']x50["'] -crop ["']100x50\+114\+0["'] \+repage -strip -depth 8 ["'].*?["']}
|
||||
end
|
||||
@thumb.make
|
||||
end
|
||||
|
||||
should "create the thumbnail when sent #make" do
|
||||
dst = @thumb.make
|
||||
assert_match /100x50/, `identify "#{dst.path}"`
|
||||
end
|
||||
|
||||
context "redefined to have bad convert_options setting" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file,
|
||||
:geometry => "100x50#",
|
||||
:convert_options => "-this-aint-no-option")
|
||||
end
|
||||
|
||||
should "error when trying to create the thumbnail" do
|
||||
assert_raises(Paperclip::PaperclipError) do
|
||||
@thumb.make
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "being thumbnailed with a blank geometry string" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file,
|
||||
:geometry => "",
|
||||
:convert_options => "-gravity center -crop \"300x300+0-0\"")
|
||||
end
|
||||
|
||||
should "not get resized by default" do
|
||||
assert !@thumb.transformation_command.include?("-resize")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "A multipage PDF" do
|
||||
setup do
|
||||
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "twopage.pdf"), 'rb')
|
||||
end
|
||||
|
||||
teardown { @file.close }
|
||||
|
||||
should "start with two pages with dimensions 612x792" do
|
||||
cmd = %Q[identify -format "%wx%h" "#{@file.path}"]
|
||||
assert_equal "612x792"*2, `#{cmd}`.chomp
|
||||
end
|
||||
|
||||
context "being thumbnailed at 100x100 with cropping" do
|
||||
setup do
|
||||
@thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x100#", :format => :png)
|
||||
end
|
||||
|
||||
should "report its correct current and target geometries" do
|
||||
assert_equal "100x100#", @thumb.target_geometry.to_s
|
||||
assert_equal "612x792", @thumb.current_geometry.to_s
|
||||
end
|
||||
|
||||
should "report its correct format" do
|
||||
assert_equal :png, @thumb.format
|
||||
end
|
||||
|
||||
should "create the thumbnail when sent #make" do
|
||||
dst = @thumb.make
|
||||
assert_match /100x100/, `identify "#{dst.path}"`
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
36
vendor/plugins/paperclip/test/upfile_test.rb
vendored
36
vendor/plugins/paperclip/test/upfile_test.rb
vendored
@ -1,36 +0,0 @@
|
||||
require 'test/helper'
|
||||
|
||||
class UpfileTest < Test::Unit::TestCase
|
||||
{ %w(jpg jpe jpeg) => 'image/jpeg',
|
||||
%w(tif tiff) => 'image/tiff',
|
||||
%w(png) => 'image/png',
|
||||
%w(gif) => 'image/gif',
|
||||
%w(bmp) => 'image/bmp',
|
||||
%w(txt) => 'text/plain',
|
||||
%w(htm html) => 'text/html',
|
||||
%w(csv) => 'text/csv',
|
||||
%w(xml) => 'text/xml',
|
||||
%w(css) => 'text/css',
|
||||
%w(js) => 'application/js',
|
||||
%w(foo) => 'application/x-foo'
|
||||
}.each do |extensions, content_type|
|
||||
extensions.each do |extension|
|
||||
should "return a content_type of #{content_type} for a file with extension .#{extension}" do
|
||||
file = stub('file', :path => "basename.#{extension}")
|
||||
class << file
|
||||
include Paperclip::Upfile
|
||||
end
|
||||
|
||||
assert_equal content_type, file.content_type
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "return a content_type of text/plain on a real file whose content_type is determined with the file command" do
|
||||
file = File.new(File.join(File.dirname(__FILE__), "..", "LICENSE"))
|
||||
class << file
|
||||
include Paperclip::Upfile
|
||||
end
|
||||
assert_equal 'text/plain', file.content_type
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user