Merge branch 'master' of git://gitorious.org/gallery-without-a-name/gallery-without-a-name

This commit is contained in:
Arne Fismen 2009-06-09 21:38:41 +02:00
commit fb35671cc4
31 changed files with 942 additions and 806 deletions

32
README
View file

@ -1,7 +1,18 @@
== Welcome to Gallery! == Welcome to the gallery without a name
Made by Espen Antonsen Made by Espen Antonsen
== Features
* Stores photos to disk in folders
* Create various thumbnails
* Read and writes EXIF
* Organize in albums (events in iPhoto)
* Combine albums in collections (albums in iPhoto)
* Upload multiple photos (using uploadify)
* Tag photos. Can also tag albums (actually all photos in album is tagged)
* User management with roles and permissions.
== Requirements == Requirements
Tested with Ruby 1.8.6 and Rails 2.3 Tested with Ruby 1.8.6 and Rails 2.3
@ -16,3 +27,22 @@ Ruby Gems
- Image_Science - Image_Science
- RubyInline (required for Image_Science) - RubyInline (required for Image_Science)
- Mini_ExifTool - Mini_ExifTool
== Installation
Put photos in containing folders(albums) in the specified gallery folder. This format is recommended:
./ski weekend in hemsedal/snow.jpg
./ski weekend in hemsedal/afterski.jpg
./trip to iran/beautiful girls in tehran.jpg
./trip to iran/mosque in yazd.jpg
./trip to iran/powder snow in dizin.jpg
Every time you manually add photos to disk you must run:
require "scan"
ScanFiles.FullScan
In future releases this will be automated.
Uploads will be written to the database and thus no need to manually scan the folders.

View file

@ -1,11 +1,5 @@
class Admin::ApplicationController < ApplicationController class Admin::ApplicationController < ApplicationController
before_filter :require_user, :require_role_admin before_filter :require_role_admin
protected
def require_role_admin
redirect_to(login_path) unless @current_user
end
end end

View file

@ -1,7 +1,7 @@
class Admin::UsersController < Admin::ApplicationController class Admin::UsersController < Admin::ApplicationController
def index def index
@users = User.find(:all) @users = User.find(:all, :order => "Name, email")
end end
def show def show
@ -16,7 +16,7 @@ class Admin::UsersController < Admin::ApplicationController
@user = User.new(params[:user]) @user = User.new(params[:user])
if @user.save if @user.save
flash[:notice] = "Account registered!" flash[:notice] = "Account registered!"
redirect_to [:admin, @user] redirect_to @user
else else
render :action => :new render :action => :new
end end
@ -30,7 +30,7 @@ class Admin::UsersController < Admin::ApplicationController
@user = User.find(params[:id]) @user = User.find(params[:id])
if @user.update_attributes(params[:user]) if @user.update_attributes(params[:user])
flash[:notice] = "Account updated!" flash[:notice] = "Account updated!"
redirect_to [:admin, @user] redirect_to @user
else else
render :action => :edit render :action => :edit
end end
@ -39,7 +39,7 @@ class Admin::UsersController < Admin::ApplicationController
def destroy def destroy
@user = User.find(params[:id]) @user = User.find(params[:id])
if @user.destroy if @user.destroy
redirect_to admin_users_path redirect_to users_path
else else
redirect_to @user redirect_to @user
end end

View file

@ -1,8 +1,15 @@
class AlbumsController < ApplicationController class AlbumsController < ApplicationController
before_filter :require_user, :only => [:new, :create, :edit, :update, :delete, :destroy, :upload]
before_filter :require_role_admin, :only => [:untouched, :new, :create, :edit, :update, :destroy]
def index def index
if params[:tag_id]
@albums = Album.find(:all, :conditions => [ "Id IN ( SELECT DISTINCT Photos.ALbum_id FROM Photos WHERE Photos.Id IN ( SELECT Photo_Id FROM Photo_Tags WHERE Photo_Tags.Tag_Id = :q) )", { :q => Tag.find_by_title( params[:tag_id] ).id } ])
elsif params[:q]
@albums = Album.find(:all, :conditions => [ "Id IN ( SELECT DISTINCT Photos.Album_Id FROM Photos WHERE Photos.description LIKE :q OR Photos.title LIKE :q OR Photos.Id IN ( SELECT Photo_Id FROM Photo_Tags LEFT OUTER JOIN Tags ON Photo_Tags.Tag_Id = Tags.Id WHERE Tags.Title LIKE :q) )", { :q => '%' + params[:q] + '%' } ])
else
@albums = Album.find(:all) @albums = Album.find(:all)
end
respond_to do |format| respond_to do |format|
format.html format.html
format.json { render :json => @albums } format.json { render :json => @albums }
@ -51,7 +58,7 @@ class AlbumsController < ApplicationController
def update def update
@album = Album.find( params[:id]) @album = Album.find( params[:id])
if @album.update_attributes(params[:album]) if @album.update_attributes(params[:album])
flash[:notice] = "Account updated!" flash[:notice] = "Album updated!"
redirect_to @album redirect_to @album
else else
render :action => :edit render :action => :edit
@ -67,9 +74,4 @@ class AlbumsController < ApplicationController
end end
end end
def upload
@user = current_user_session
@album = Album.find( params[:id])
end
end end

View file

@ -8,7 +8,10 @@ class ApplicationController < ActionController::Base
filter_parameter_logging :password, :password_confirmation filter_parameter_logging :password, :password_confirmation
helper_method :current_user, :current_user_session helper_method :current_user, :current_user_session
private private
def current_user_session def current_user_session
return @current_user_session if defined?(@current_user_session) return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find @current_user_session = UserSession.find
@ -19,22 +22,50 @@ class ApplicationController < ActionController::Base
@current_user = current_user_session && current_user_session.user @current_user = current_user_session && current_user_session.user
end end
def require_role(roles = [])
unless current_user && current_user.in_role?(*roles)
store_location
flash[:notice] = "You must have permission to access this page"
redirect_to account_path
return false
end
return true
end
def require_role_admin
return false if !require_user
return require_role("admin")
end
def require_permission(permissions = [])
return false if !require_user
unless current_user && current_user.has_permission?(*permissions)
store_location
flash[:notice] = "You must have permission to access this page"
redirect_to account_path
return false
end
return true
end
def require_user def require_user
unless current_user unless current_user
store_location store_location
flash[:notice] = "You must be logged in to access this page" flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url redirect_to login_path
return false return false
end end
return true
end end
def require_no_user def require_no_user
if current_user if current_user
store_location store_location
flash[:notice] = "You must be logged out to access this page" flash[:notice] = "Already logged in. Please logout"
redirect_to account_url redirect_to account_path
return false return false
end end
return true
end end
def store_location def store_location

View file

@ -1,6 +1,6 @@
class CollectionsController < ApplicationController class CollectionsController < ApplicationController
before_filter :require_user, :only => [:new, :create, :edit, :update, :delete, :destroy]
before_filter :require_role_admin, :only => [:new, :create, :edit, :update, :destroy]
def index def index
@collections = Collection.find(:all) @collections = Collection.find(:all)
respond_to do |format| respond_to do |format|
@ -41,7 +41,7 @@ class CollectionsController < ApplicationController
def update def update
@collection = Collection.find( params[:id]) @collection = Collection.find( params[:id])
if @collection.update_attributes(params[:collection]) if @collection.update_attributes(params[:collection])
flash[:notice] = "collection updated!" flash[:notice] = "Collection updated!"
redirect_to @collection redirect_to @collection
else else
render :action => :edit render :action => :edit

View file

@ -1,13 +1,16 @@
class PhotosController < ApplicationController class PhotosController < ApplicationController
before_filter :require_user, :only => [:new, :create, :edit, :update, :destroy]
before_filter :require_role_admin, :only => [:untouched, :upload, :new, :create, :edit, :update, :destroy]
def index def index
if params[:tag_id] if params[:tag_id]
@photos = Tag.find_by_title( params[:tag_id] ).photos @photos = Tag.find_by_title( params[:tag_id] ).photos
elsif params[:album_id]
@photos = Album.find( params[:album_id]).photos.find(:all)
elsif params[:q] elsif params[:q]
@photos = Photo.find(:all, :limit => 20, :conditions => [ "Photos.description LIKE :q OR Photos.title LIKE :q OR Photos.Id IN ( SELECT Photo_Id FROM Photo_Tags LEFT OUTER JOIN Tags ON Photo_Tags.Tag_Id = Tags.Id WHERE Tags.Title LIKE :q) ", { :q => '%' + params[:q] + '%' } ], :include => :album ) @photos = Photo.find(:all, :limit => 20, :conditions => [ "Photos.description LIKE :q OR Photos.title LIKE :q OR Photos.Id IN ( SELECT Photo_Id FROM Photo_Tags LEFT OUTER JOIN Tags ON Photo_Tags.Tag_Id = Tags.Id WHERE Tags.Title LIKE :q) ", { :q => '%' + params[:q] + '%' } ], :include => :album )
else else
@photos = Photo.find(:all, :limit => 20) @photos = Photo.find(:all)
end end
respond_to do |format| respond_to do |format|
format.html format.html
@ -17,7 +20,12 @@ class PhotosController < ApplicationController
end end
def untouched def untouched
if params[:album_id]
@album = Album.find( params[:album_id])
@photos = @album.photos.untouched
else
@photos = Photo.untouched() @photos = Photo.untouched()
end
respond_to do |format| respond_to do |format|
format.html format.html
format.json { render :json => @photos } format.json { render :json => @photos }
@ -38,9 +46,11 @@ class PhotosController < ApplicationController
@photo = Photo.new @photo = Photo.new
end end
def upload
@album = Album.find( params[:album_id])
end
def create def create
respond_to do |format| respond_to do |format|
@photo = Photo.new(params[:photo]) @photo = Photo.new(params[:photo])
if params[:Filedata] if params[:Filedata]
@ -69,16 +79,33 @@ class PhotosController < ApplicationController
@photo = Photo.find( params[:id]) @photo = Photo.find( params[:id])
end end
def edit_multiple
if params[:album_id]
@photos = Album.find( params[:album_id] ).photos
else
@photos = Photo.find( params[:photo_ids] )
end
end
def update def update
@photo = Photo.find( params[:id]) @photo = Photo.find( params[:id])
if @photo.update_attributes(params[:photo]) if @photo.update_attributes(params[:photo])
flash[:notice] = "Account updated!" flash[:notice] = "Photo updated!"
redirect_to @photo redirect_to @photo
else else
render :action => :edit render :action => :edit
end end
end end
def update_multiple
@photos = Photo.find(params[:photo_ids])
@photos.each do |photo|
photo.update_attributes!(params[:photo].reject { |k,v| v.blank? })
end
flash[:notice] = "Updated photos!"
redirect_to photos_path
end
def destroy def destroy
@photo = Photo.find( params[:id]) @photo = Photo.find( params[:id])
@album = @photo.album @album = @photo.album

View file

@ -10,9 +10,9 @@ class UserSessionsController < ApplicationController
@user_session = UserSession.new(params[:user_session]) @user_session = UserSession.new(params[:user_session])
if @user_session.save if @user_session.save
flash[:notice] = "Login successful!" flash[:notice] = "Login successful!"
redirect_back_or_default account_url redirect_back_or_default account_path
else else
render :action => :new render :new
end end
end end

View file

@ -10,7 +10,7 @@ class UsersController < ApplicationController
@user = User.new(params[:user]) @user = User.new(params[:user])
if @user.save if @user.save
flash[:notice] = "Account registered!" flash[:notice] = "Account registered!"
redirect_back_or_default account_url redirect_back_or_default account_path
else else
render :action => :new render :action => :new
end end
@ -28,7 +28,7 @@ class UsersController < ApplicationController
@user = @current_user # makes our views "cleaner" and more consistent @user = @current_user # makes our views "cleaner" and more consistent
if @user.update_attributes(params[:user]) if @user.update_attributes(params[:user])
flash[:notice] = "Account updated!" flash[:notice] = "Account updated!"
redirect_to account_url redirect_to account_path
else else
render :action => :edit render :action => :edit
end end

View file

@ -1,3 +1,4 @@
# Methods added to this helper will be available to all templates in the application. # Methods added to this helper will be available to all templates in the application.
module ApplicationHelper module ApplicationHelper
end end

View file

@ -1,2 +1,9 @@
module UsersHelper module UsersHelper
def has_permission?(permissions = [])
return current_user && current_user.has_permission?(permissions)
end
def has_role?(roles = [])
return current_user && current_user.in_role?(roles)
end
end end

View file

@ -12,12 +12,9 @@ class Album < ActiveRecord::Base
attr_accessor :tag_list attr_accessor :tag_list
attr_protected :path attr_protected :path
named_scope :untouched, :conditions => "Albums.Id IN ( SELECT DISTINCT Photos.Album_Id FROM Photos WHERE Photos.description IS NULL AND Photos.Id NOT IN ( SELECT Photo_ID FROM Photo_Tags) )"
def self.untouched
self.find(:all, :conditions => "Albums.Id IN ( SELECT DISTINCT Photos.Album_Id FROM Photos WHERE Photos.description IS NULL AND Photos.Id NOT IN ( SELECT Photo_ID FROM Photo_Tags) )" )
end
def ensure_path def ensure_path
self.path = self.title if !self.path self.path = self.title if !self.path

View file

@ -15,13 +15,9 @@ class Photo < ActiveRecord::Base
before_destroy :destroy_file before_destroy :destroy_file
attr_accessor :tag_list attr_accessor :tag_list
attr_protected :path #attr_protected :path
def self.untouched
self.find(:all, :conditions => "Photos.description IS NULL AND Photos.Id NOT IN ( SELECT Photo_ID FROM Photo_Tags)", :include => :album )
end
named_scope :untouched, :conditions => "Photos.description IS NULL AND Photos.Id NOT IN ( SELECT Photo_ID FROM Photo_Tags)", :include => :album
def path_original_public def path_original_public
return APP_CONFIG[:photos_path_public] + self.path return APP_CONFIG[:photos_path_public] + self.path
@ -113,12 +109,15 @@ class Photo < ActiveRecord::Base
end end
def exif_read def exif_read
puts "exif"
puts self.path
puts self.path_original
photo = MiniExiftool.new(self.path_original) photo = MiniExiftool.new(self.path_original)
self.longitude = photo.GPSLongitude if self.longitude.nil? self.longitude = photo.GPSLongitude if self.longitude.nil?
self.latitude = photo.GPSLatitude if self.latitude.nil? self.latitude = photo.GPSLatitude if self.latitude.nil?
self.title = photo.DocumentName if self.title.nil? self.title = photo.DocumentName if self.title.nil?
self.description = photo.ImageDescription if self.description.nil? self.description = photo.ImageDescription if self.description.nil?
self.tag_list = (self.tags.empty? ? "" : self.album.tag_list) + " " + (photo.Keywords.map { |tag| tag.gsub(" ", "_") }.join(" ") if !photo.Keywords.nil?) self.tag_list = (self.tags.empty? ? "" : self.album.tag_list) + " " + (photo.Keywords.nil? ? "" : photo.Keywords.map { |tag| tag.gsub(" ", "_") }.join(" "))
end end
def exif_write def exif_write

View file

@ -4,8 +4,3 @@
<%= form.label :email %><br /> <%= form.label :email %><br />
<%= form.text_field :email %><br /> <%= form.text_field :email %><br />
<br/> <br/>
<%= form.label :password, form.object.new_record? ? nil : "Change password" %><br />
<%= form.password_field :password %><br />
<br />
<%= form.label :password_confirmation %><br />
<%= form.password_field :password_confirmation %><br />

View file

@ -1,6 +1,6 @@
<h1>Edit Account</h1> <h1>Edit Account</h1>
<% form_for [:admin, @user] do |f| %> <% form_for @user do |f| %>
<%= f.error_messages %> <%= f.error_messages %>
<%= render :partial => "form", :object => f %> <%= render :partial => "form", :object => f %>
<%= f.submit "Update" %> <%= f.submit "Update" %>
@ -10,4 +10,4 @@
:confirm => "Are you sure you want to delete this user?", :confirm => "Are you sure you want to delete this user?",
:method => :delete) %> :method => :delete) %>
<br /><%= link_to "All users", admin_users_path %> <br /><%= link_to "All users", users_path %>

View file

@ -1,3 +1,5 @@
<% for user in @users %> <% for user in @users %>
<h2><%= link_to user.name || user.email , [:admin, user] %></h2> <h2><%= link_to user.name || user.email , user %></h2>
<% end %> <% end %>
<br /><%= link_to "New user", new_user_path %>

View file

@ -1,7 +1,9 @@
<h1>Register</h1> <h1>Register</h1>
<% form_for [:admin, @user] do |f| %> <% form_for @user do |f| %>
<%= f.error_messages %> <%= f.error_messages %>
<%= render :partial => "form", :object => f %> <%= render :partial => "form", :object => f %>
<%= f.submit "Register" %> <%= f.submit "Register" %>
<% end %> <% end %>
<br /><%= link_to "All users", users_path %>

View file

@ -40,5 +40,5 @@
</p> </p>
<%= link_to 'Edit', edit_admin_user_path(@user) %><br/> <%= link_to 'Edit', edit_user_path(@user) %><br/>
<br /><%= link_to "All users", admin_users_path %> <br /><%= link_to "All users", users_path %>

View file

@ -2,4 +2,3 @@
<%= render :partial => @albums %> <%= render :partial => @albums %>
<br /><%= link_to "New Album", new_album_path %> <br /><%= link_to "New Album", new_album_path %>
<br /><%= link_to "All albums", albums_path %>

View file

@ -3,10 +3,13 @@
<%= link_to image_tag( photo.path_modified_public("album") ), photo %> <%= link_to image_tag( photo.path_modified_public("album") ), photo %>
<% end %> <% end %>
<p><%= @album.description %></p> <p><%= @album.description %></p>
<% if current_user && current_user.has_permission?("see_album_note") %> <% if has_permission?("see_album_note") %>
<p><%= @album.note %></p> <p><%= @album.note %></p>
<% end %> <% end %>
<% if has_role?("admin") %>
<br /><%= link_to "Update album", edit_album_path(@album) %> <br /><%= link_to "Update album", edit_album_path(@album) %>
<br /><%= link_to "Upload photos", upload_album_path(@album) %> <br /><%= link_to "Update photos", edit_multiple_album_photos_path(@album) %>
<br /><%= link_to "Upload photos", upload_album_photos_path(@album) %>
<% end %>
<br /><%= link_to "All albums", albums_path %> <br /><%= link_to "All albums", albums_path %>

View file

@ -1,729 +1,36 @@
if ( $('ul.gallery').length ) {
$('ul.gallery').galleria( {
clickNext : true,
insert: "#photo_large",
onImage: function ( image, caption, thumb ) {
image.css('display','none').fadeIn()
thumb.parents('li').siblings().children('img.selected').fadeTo(500,0.3)
thumb.fadeTo('fast',1).addClass('selected')
$( '#photo_metadata' ).html( '<a href=\'/photos/' + thumb.attr('id').replace('thumb_', '') + '/edit\'>Update photo details</a>' )
var scrollable = $("#thumbstrip").scrollable()
scrollable.seekTo( thumb.parents('ul').children().index( thumb.parents('li') ) )
},
onThumb: function ( thumb) {
thumb.css({display:'none',opacity: (thumb.parents('li').is('.active') ? '1' : '0.3') }).fadeIn(1500)
}
})
}
if ( $('#thumbstrip').length ) {
$('#thumbstrip').scrollable( {
items : '#thumbs',
clickable: true,
keyboard : false
})
if ( $('#thumbs li.active').length == 0 ){
//$('div.scrollable').scrollable().click(0)
$('#thumbs li:first').addClass('active')
}
}
<% content_for :javascript do %> <% content_for :javascript do %>
<script type="text/javascript" src="/javascripts/swfupload/swfupload.js"></script> <script type="text/javascript" src="/javascripts/jquery.uploadify-v1.6.2.mit/jquery.uploadify.js"></script>
<% end %>
<style type="text/css">
/* -----------------------------------------------
www.swfupload.org
Description: Common Screen Stylesheet for SWFUpload Demos
Updated on: May 1, 2008
----------------------------------------------- */
/* -----------------------------------------------
GLOBAL RESET
----------------------------------------------- */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
/* remember to define focus styles! */
:focus { outline: 0; }
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: separate;
border-spacing: 0;
}
caption, th, td {
text-align: left;
font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: "";
}
blockquote, q {
quotes: "" "";
}
/* -----------------------------------------------
BASIC ELEMENTS
----------------------------------------------- */
/* -- Text Styles ------------------------------- */
html,
body {
margin: 0;
padding: 0;
width: 100%;
font: 12px/1.4em Helvetica, Arial, sans-serif;
}
a {
color: #385ea2;
text-decoration: none;
}
a:hover { text-decoration: underline; }
strong { font-weight: 700; }
h1 {
font: 28px/1em Arial, Helvetica, sans-serif;
padding: 60px 20px 20px;
margin-bottom: 15px;
color: #333;
text-decoration: none;
}
h1 a{
color: #fff;
text-decoration: none;
}
h2 {
font-size: 22px;
font-weight: 300;
padding-top: 1em;
padding-bottom: .25em;
}
p {
margin-top: .25em;
margin-bottom: .5em;
}
ul { padding: 4px 5px; }
ul li {
padding: 4px 5px;
margin: 0 20px;
list-style:square;
}
code {
display: block;
background:#edffb8 none repeat scroll 0%;
border-color:#b2da3a;
border-style:solid;
border-width:1px 0;
font-size: 1em;
margin: 1em 0pt;
overflow:auto;
padding: 0.3em 0.4em;
white-space:pre;
}
/* -- Layout ------------------------------- */
#header {
background: #313131 url(http://demo.swfupload.org/v220/images/header-bg.jpg) repeat-x top left;
height: 125px;
position: relative;
}
#logo {
padding: 0;
margin: 0;
background: url(http://demo.swfupload.org/v220/images/logo.gif) no-repeat 20px 20px;
height: 106px;
width: 272px;
text-indent: -5000px;
overflow: hidden;
}
/* hide link text */
#logo a {
display: block;
color: #fff;
text-indent: -5000px;
overflow: hidden;
height: 106px;
width: 272px;
}
#version {
color: #fff;
position: absolute;
right: 20px;
top: 85px;
}
#content { width: 680px;}
#content { margin: 20px 90px; }
/* -- Form Styles ------------------------------- */
form {
margin: 0;
padding: 0;
}
div.fieldset {
border: 1px solid #afe14c;
margin: 10px 0;
padding: 20px 10px;
}
div.fieldset span.legend {
position: relative;
background-color: #FFF;
padding: 3px;
top: -30px;
font: 700 14px Arial, Helvetica, sans-serif;
color: #73b304;
}
div.flash {
width: 375px;
margin: 10px 5px;
border-color: #D9E4FF;
-moz-border-radius-topleft : 5px;
-webkit-border-top-left-radius : 5px;
-moz-border-radius-topright : 5px;
-webkit-border-top-right-radius : 5px;
-moz-border-radius-bottomleft : 5px;
-webkit-border-bottom-left-radius : 5px;
-moz-border-radius-bottomright : 5px;
-webkit-border-bottom-right-radius : 5px;
}
button,
input,
select,
textarea {
border-width: 1px;
margin-bottom: 10px;
padding: 2px 3px;
}
input[disabled]{ border: 1px solid #ccc } /* FF 2 Fix */
label {
width: 150px;
text-align: right;
display:block;
margin-right: 5px;
}
#btnSubmit { margin: 0 0 0 155px ; }
/* -- Table Styles ------------------------------- */
td {
font: 10pt Helvetica, Arial, sans-serif;
vertical-align: top;
}
.progressWrapper {
width: 357px;
overflow: hidden;
}
.progressContainer {
margin: 5px;
padding: 4px;
border: solid 1px #E8E8E8;
background-color: #F7F7F7;
overflow: hidden;
}
/* Message */
.message {
margin: 1em 0;
padding: 10px 20px;
border: solid 1px #FFDD99;
background-color: #FFFFCC;
overflow: hidden;
}
/* Error */
.red {
border: solid 1px #B50000;
background-color: #FFEBEB;
}
/* Current */
.green {
border: solid 1px #DDF0DD;
background-color: #EBFFEB;
}
/* Complete */
.blue {
border: solid 1px #CEE2F2;
background-color: #F0F5FF;
}
.progressName {
font-size: 8pt;
font-weight: 700;
color: #555;
width: 323px;
height: 14px;
text-align: left;
white-space: nowrap;
overflow: hidden;
}
.progressBarInProgress,
.progressBarComplete,
.progressBarError {
font-size: 0;
width: 0%;
height: 2px;
background-color: blue;
margin-top: 2px;
}
.progressBarComplete {
width: 100%;
background-color: green;
visibility: hidden;
}
.progressBarError {
width: 100%;
background-color: red;
visibility: hidden;
}
.progressBarStatus {
margin-top: 2px;
width: 337px;
font-size: 7pt;
font-family: Arial;
text-align: left;
white-space: nowrap;
}
a.progressCancel {
font-size: 0;
display: block;
height: 14px;
width: 14px;
background-image: url(http://demo.swfupload.org/v220/images/cancelbutton.gif);
background-repeat: no-repeat;
background-position: -14px 0px;
float: right;
}
a.progressCancel:hover {
background-position: 0px 0px;
}
/* -- SWFUpload Object Styles ------------------------------- */
.swfupload {
vertical-align: top;
}
</style>
<script type="text/javascript"> <script type="text/javascript">
function fileQueueError(file, errorCode, message) { $(document).ready(function() {
try { $('#photo').fileUpload({
var imageName = "error.gif"; uploader:'/javascripts/jquery.uploadify-v1.6.2.mit/uploader.swf',
var errorName = ""; script:'<%= photos_path %>',
if (errorCode === SWFUpload.errorCode_QUEUE_LIMIT_EXCEEDED) { scriptData: {
errorName = "You have attempted to queue too many files."; '<%= get_session_key %>' : encodeURIComponent('<%= u cookies[get_session_key] %>'),
} '<%= request_forgery_protection_token %>' : encodeURIComponent('<%= u form_authenticity_token %>'),
if (errorName !== "") {
alert(errorName);
return;
}
switch (errorCode) {
case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
imageName = "zerobyte.gif";
break;
case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT:
imageName = "toobig.gif";
break;
case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE:
default:
alert(message);
break;
}
addImage("http://demo.swfupload.org/v220/applicationdemo/images/" + imageName);
} catch (ex) {
this.debug(ex);
}
}
function fileDialogComplete(numFilesSelected, numFilesQueued) {
try {
if (numFilesQueued > 0) {
this.startUpload();
}
} catch (ex) {
this.debug(ex);
}
}
function uploadProgress(file, bytesLoaded) {
try {
var percent = Math.ceil((bytesLoaded / file.size) * 100);
var progress = new FileProgress(file, this.customSettings.upload_target);
progress.setProgress(percent);
if (percent === 100) {
progress.setStatus("Creating thumbnail...");
progress.toggleCancel(false, this);
} else {
progress.setStatus("Uploading...");
progress.toggleCancel(true, this);
}
} catch (ex) {
this.debug(ex);
}
}
function uploadSuccess(file, serverData) {
try {
var progress = new FileProgress(file, this.customSettings.upload_target);
if (serverData.substring(0, 7) === "FILEID:") {
addImage(serverData.substring(7));
progress.setStatus("Thumbnail Created.");
progress.toggleCancel(false);
} else {
addImage("http://demo.swfupload.org/v220/applicationdemo/images/error.gif");
progress.setStatus("Error.");
progress.toggleCancel(false);
alert(serverData);
}
} catch (ex) {
this.debug(ex);
}
}
function uploadComplete(file) {
try {
/* I want the next upload to continue automatically so I'll call startUpload here */
if (this.getStats().files_queued > 0) {
this.startUpload();
} else {
var progress = new FileProgress(file, this.customSettings.upload_target);
progress.setComplete();
progress.setStatus("All images received.");
progress.toggleCancel(false);
}
} catch (ex) {
this.debug(ex);
}
}
function uploadError(file, errorCode, message) {
var imageName = "error.gif";
var progress;
try {
switch (errorCode) {
case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
try {
progress = new FileProgress(file, this.customSettings.upload_target);
progress.setCancelled();
progress.setStatus("Cancelled");
progress.toggleCancel(false);
}
catch (ex1) {
this.debug(ex1);
}
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
try {
progress = new FileProgress(file, this.customSettings.upload_target);
progress.setCancelled();
progress.setStatus("Stopped");
progress.toggleCancel(true);
}
catch (ex2) {
this.debug(ex2);
}
case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
imageName = "uploadlimit.gif";
break;
default:
alert(message);
break;
}
addImage("http://demo.swfupload.org/v220/applicationdemo/images/" + imageName);
} catch (ex3) {
this.debug(ex3);
}
}
function addImage(src) {
var newImg = document.createElement("img");
newImg.style.margin = "5px";
document.getElementById("thumbnails").appendChild(newImg);
if (newImg.filters) {
try {
newImg.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 0;
} catch (e) {
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
newImg.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + 0 + ')';
}
} else {
newImg.style.opacity = 0;
}
newImg.onload = function () {
fadeIn(newImg, 0);
};
newImg.src = src;
}
function fadeIn(element, opacity) {
var reduceOpacityBy = 5;
var rate = 30; // 15 fps
if (opacity < 100) {
opacity += reduceOpacityBy;
if (opacity > 100) {
opacity = 100;
}
if (element.filters) {
try {
element.filters.item("DXImageTransform.Microsoft.Alpha").opacity = opacity;
} catch (e) {
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
element.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + opacity + ')';
}
} else {
element.style.opacity = opacity / 100;
}
}
if (opacity < 100) {
setTimeout(function () {
fadeIn(element, opacity);
}, rate);
}
}
/* ******************************************
* FileProgress Object
* Control object for displaying file info
* ****************************************** */
function FileProgress(file, targetID) {
this.fileProgressID = "divFileProgress";
this.fileProgressWrapper = document.getElementById(this.fileProgressID);
if (!this.fileProgressWrapper) {
this.fileProgressWrapper = document.createElement("div");
this.fileProgressWrapper.className = "progressWrapper";
this.fileProgressWrapper.id = this.fileProgressID;
this.fileProgressElement = document.createElement("div");
this.fileProgressElement.className = "progressContainer";
var progressCancel = document.createElement("a");
progressCancel.className = "progressCancel";
progressCancel.href = "#";
progressCancel.style.visibility = "hidden";
progressCancel.appendChild(document.createTextNode(" "));
var progressText = document.createElement("div");
progressText.className = "progressName";
progressText.appendChild(document.createTextNode(file.name));
var progressBar = document.createElement("div");
progressBar.className = "progressBarInProgress";
var progressStatus = document.createElement("div");
progressStatus.className = "progressBarStatus";
progressStatus.innerHTML = "&nbsp;";
this.fileProgressElement.appendChild(progressCancel);
this.fileProgressElement.appendChild(progressText);
this.fileProgressElement.appendChild(progressStatus);
this.fileProgressElement.appendChild(progressBar);
this.fileProgressWrapper.appendChild(this.fileProgressElement);
document.getElementById(targetID).appendChild(this.fileProgressWrapper);
fadeIn(this.fileProgressWrapper, 0);
} else {
this.fileProgressElement = this.fileProgressWrapper.firstChild;
this.fileProgressElement.childNodes[1].firstChild.nodeValue = file.name;
}
this.height = this.fileProgressWrapper.offsetHeight;
}
FileProgress.prototype.setProgress = function (percentage) {
this.fileProgressElement.className = "progressContainer green";
this.fileProgressElement.childNodes[3].className = "progressBarInProgress";
this.fileProgressElement.childNodes[3].style.width = percentage + "%";
};
FileProgress.prototype.setComplete = function () {
this.fileProgressElement.className = "progressContainer blue";
this.fileProgressElement.childNodes[3].className = "progressBarComplete";
this.fileProgressElement.childNodes[3].style.width = "";
};
FileProgress.prototype.setError = function () {
this.fileProgressElement.className = "progressContainer red";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
};
FileProgress.prototype.setCancelled = function () {
this.fileProgressElement.className = "progressContainer";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
};
FileProgress.prototype.setStatus = function (status) {
this.fileProgressElement.childNodes[2].innerHTML = status;
};
FileProgress.prototype.toggleCancel = function (show, swfuploadInstance) {
this.fileProgressElement.childNodes[0].style.visibility = show ? "visible" : "hidden";
if (swfuploadInstance) {
var fileID = this.fileProgressID;
this.fileProgressElement.childNodes[0].onclick = function () {
swfuploadInstance.cancelUpload(fileID);
return false;
};
}
};
var swfu;
window.onload = function () {
swfu = new SWFUpload({
// Backend Settings
upload_url: "<%= new_upload_path_with_session_information %>",
post_params : {
'method' : "_put",
'authenticity_token' : '<%= u form_authenticity_token -%>',
'photo[album_id]' : "<%= @album.id %>" 'photo[album_id]' : "<%= @album.id %>"
}, },
cancelImg:'/javascripts/jquery.uploadify-v1.6.2.mit/cancel.png',
// File Upload Settings multi:true,
file_size_limit : "2 MB", // 2MB auto:true,
file_types : "*.jpg", onComplete : function (e,queueId,fileObj,res,data) {
file_types_description : "JPG Images", if (res.substring(0, 7) === "FILEID:") {
file_upload_limit : "0", var image = $('<img>').appendTo('#thumbs')
image.css('display','none')
// Event Handler Settings - these functions as defined in Handlers.js image.attr('src', res.substring(7) )
// The handlers are not part of SWFUpload but are part of my website and control how image.fadeIn('slow')
// my website reacts to the SWFUpload events. }
file_queue_error_handler : fileQueueError,
file_dialog_complete_handler : fileDialogComplete,
upload_progress_handler : uploadProgress,
upload_error_handler : uploadError,
upload_success_handler : uploadSuccess,
upload_complete_handler : uploadComplete,
// Button Settings
button_image_url : "http://demo.swfupload.org/v220/applicationdemo/images/SmallSpyGlassWithTransperancy_17x18.png",
button_placeholder_id : "spanButtonPlaceholder",
button_width: 180,
button_height: 18,
button_text : '<span class="button">Select Images <span class="buttonSmall">(2 MB Max)</span></span>',
button_text_style : '.button { font-family: Helvetica, Arial, sans-serif; font-size: 12pt; } .buttonSmall { font-size: 10pt; }',
button_text_top_padding: 0,
button_text_left_padding: 18,
button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
button_cursor: SWFUpload.CURSOR.HAND,
// Flash Settings
flash_url : "/javascripts/swfupload/Flash/swfupload.swf",
custom_settings : {
upload_target : "divFileProgressContainer"
}, },
onError : function (e,queueId,fileObj,errorObj,res) {
// Debug Settings }
debug: false })
}); })
};
</script> </script>
<div id="content">
<h2>Application Demo</h2>
<p>This demo shows how SWFUpload can behave like an AJAX application. Images are uploaded by SWFUpload then some JavaScript is used to display the thumbnails without reloading the page.</p>
<% form_for(Photo.new) do |f| %>
<div style="display: inline; border: solid 1px #7FAAFF; background-color: #C5D9FF; padding: 2px;">
<span id="spanButtonPlaceholder"></span>
</div>
<% end %> <% end %>
<div id="divFileProgressContainer" style="height: 75px;"></div> <form>
<div id="thumbnails"></div> <input type="file" id="photo" name="photo" />
</div> <br />
<div id="thumbs"></div>
</form>

View file

@ -0,0 +1,729 @@
if ( $('ul.gallery').length ) {
$('ul.gallery').galleria( {
clickNext : true,
insert: "#photo_large",
onImage: function ( image, caption, thumb ) {
image.css('display','none').fadeIn()
thumb.parents('li').siblings().children('img.selected').fadeTo(500,0.3)
thumb.fadeTo('fast',1).addClass('selected')
$( '#photo_metadata' ).html( '<a href=\'/photos/' + thumb.attr('id').replace('thumb_', '') + '/edit\'>Update photo details</a>' )
var scrollable = $("#thumbstrip").scrollable()
scrollable.seekTo( thumb.parents('ul').children().index( thumb.parents('li') ) )
},
onThumb: function ( thumb) {
thumb.css({display:'none',opacity: (thumb.parents('li').is('.active') ? '1' : '0.3') }).fadeIn(1500)
}
})
}
if ( $('#thumbstrip').length ) {
$('#thumbstrip').scrollable( {
items : '#thumbs',
clickable: true,
keyboard : false
})
if ( $('#thumbs li.active').length == 0 ){
//$('div.scrollable').scrollable().click(0)
$('#thumbs li:first').addClass('active')
}
}
<% content_for :javascript do %>
<script type="text/javascript" src="/javascripts/swfupload/swfupload.js"></script>
<% end %>
<style type="text/css">
/* -----------------------------------------------
www.swfupload.org
Description: Common Screen Stylesheet for SWFUpload Demos
Updated on: May 1, 2008
----------------------------------------------- */
/* -----------------------------------------------
GLOBAL RESET
----------------------------------------------- */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
/* remember to define focus styles! */
:focus { outline: 0; }
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: separate;
border-spacing: 0;
}
caption, th, td {
text-align: left;
font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: "";
}
blockquote, q {
quotes: "" "";
}
/* -----------------------------------------------
BASIC ELEMENTS
----------------------------------------------- */
/* -- Text Styles ------------------------------- */
html,
body {
margin: 0;
padding: 0;
width: 100%;
font: 12px/1.4em Helvetica, Arial, sans-serif;
}
a {
color: #385ea2;
text-decoration: none;
}
a:hover { text-decoration: underline; }
strong { font-weight: 700; }
h1 {
font: 28px/1em Arial, Helvetica, sans-serif;
padding: 60px 20px 20px;
margin-bottom: 15px;
color: #333;
text-decoration: none;
}
h1 a{
color: #fff;
text-decoration: none;
}
h2 {
font-size: 22px;
font-weight: 300;
padding-top: 1em;
padding-bottom: .25em;
}
p {
margin-top: .25em;
margin-bottom: .5em;
}
ul { padding: 4px 5px; }
ul li {
padding: 4px 5px;
margin: 0 20px;
list-style:square;
}
code {
display: block;
background:#edffb8 none repeat scroll 0%;
border-color:#b2da3a;
border-style:solid;
border-width:1px 0;
font-size: 1em;
margin: 1em 0pt;
overflow:auto;
padding: 0.3em 0.4em;
white-space:pre;
}
/* -- Layout ------------------------------- */
#header {
background: #313131 url(http://demo.swfupload.org/v220/images/header-bg.jpg) repeat-x top left;
height: 125px;
position: relative;
}
#logo {
padding: 0;
margin: 0;
background: url(http://demo.swfupload.org/v220/images/logo.gif) no-repeat 20px 20px;
height: 106px;
width: 272px;
text-indent: -5000px;
overflow: hidden;
}
/* hide link text */
#logo a {
display: block;
color: #fff;
text-indent: -5000px;
overflow: hidden;
height: 106px;
width: 272px;
}
#version {
color: #fff;
position: absolute;
right: 20px;
top: 85px;
}
#content { width: 680px;}
#content { margin: 20px 90px; }
/* -- Form Styles ------------------------------- */
form {
margin: 0;
padding: 0;
}
div.fieldset {
border: 1px solid #afe14c;
margin: 10px 0;
padding: 20px 10px;
}
div.fieldset span.legend {
position: relative;
background-color: #FFF;
padding: 3px;
top: -30px;
font: 700 14px Arial, Helvetica, sans-serif;
color: #73b304;
}
div.flash {
width: 375px;
margin: 10px 5px;
border-color: #D9E4FF;
-moz-border-radius-topleft : 5px;
-webkit-border-top-left-radius : 5px;
-moz-border-radius-topright : 5px;
-webkit-border-top-right-radius : 5px;
-moz-border-radius-bottomleft : 5px;
-webkit-border-bottom-left-radius : 5px;
-moz-border-radius-bottomright : 5px;
-webkit-border-bottom-right-radius : 5px;
}
button,
input,
select,
textarea {
border-width: 1px;
margin-bottom: 10px;
padding: 2px 3px;
}
input[disabled]{ border: 1px solid #ccc } /* FF 2 Fix */
label {
width: 150px;
text-align: right;
display:block;
margin-right: 5px;
}
#btnSubmit { margin: 0 0 0 155px ; }
/* -- Table Styles ------------------------------- */
td {
font: 10pt Helvetica, Arial, sans-serif;
vertical-align: top;
}
.progressWrapper {
width: 357px;
overflow: hidden;
}
.progressContainer {
margin: 5px;
padding: 4px;
border: solid 1px #E8E8E8;
background-color: #F7F7F7;
overflow: hidden;
}
/* Message */
.message {
margin: 1em 0;
padding: 10px 20px;
border: solid 1px #FFDD99;
background-color: #FFFFCC;
overflow: hidden;
}
/* Error */
.red {
border: solid 1px #B50000;
background-color: #FFEBEB;
}
/* Current */
.green {
border: solid 1px #DDF0DD;
background-color: #EBFFEB;
}
/* Complete */
.blue {
border: solid 1px #CEE2F2;
background-color: #F0F5FF;
}
.progressName {
font-size: 8pt;
font-weight: 700;
color: #555;
width: 323px;
height: 14px;
text-align: left;
white-space: nowrap;
overflow: hidden;
}
.progressBarInProgress,
.progressBarComplete,
.progressBarError {
font-size: 0;
width: 0%;
height: 2px;
background-color: blue;
margin-top: 2px;
}
.progressBarComplete {
width: 100%;
background-color: green;
visibility: hidden;
}
.progressBarError {
width: 100%;
background-color: red;
visibility: hidden;
}
.progressBarStatus {
margin-top: 2px;
width: 337px;
font-size: 7pt;
font-family: Arial;
text-align: left;
white-space: nowrap;
}
a.progressCancel {
font-size: 0;
display: block;
height: 14px;
width: 14px;
background-image: url(http://demo.swfupload.org/v220/images/cancelbutton.gif);
background-repeat: no-repeat;
background-position: -14px 0px;
float: right;
}
a.progressCancel:hover {
background-position: 0px 0px;
}
/* -- SWFUpload Object Styles ------------------------------- */
.swfupload {
vertical-align: top;
}
</style>
<script type="text/javascript">
function fileQueueError(file, errorCode, message) {
try {
var imageName = "error.gif";
var errorName = "";
if (errorCode === SWFUpload.errorCode_QUEUE_LIMIT_EXCEEDED) {
errorName = "You have attempted to queue too many files.";
}
if (errorName !== "") {
alert(errorName);
return;
}
switch (errorCode) {
case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
imageName = "zerobyte.gif";
break;
case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT:
imageName = "toobig.gif";
break;
case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE:
default:
alert(message);
break;
}
addImage("http://demo.swfupload.org/v220/applicationdemo/images/" + imageName);
} catch (ex) {
this.debug(ex);
}
}
function fileDialogComplete(numFilesSelected, numFilesQueued) {
try {
if (numFilesQueued > 0) {
this.startUpload();
}
} catch (ex) {
this.debug(ex);
}
}
function uploadProgress(file, bytesLoaded) {
try {
var percent = Math.ceil((bytesLoaded / file.size) * 100);
var progress = new FileProgress(file, this.customSettings.upload_target);
progress.setProgress(percent);
if (percent === 100) {
progress.setStatus("Creating thumbnail...");
progress.toggleCancel(false, this);
} else {
progress.setStatus("Uploading...");
progress.toggleCancel(true, this);
}
} catch (ex) {
this.debug(ex);
}
}
function uploadSuccess(file, serverData) {
try {
var progress = new FileProgress(file, this.customSettings.upload_target);
if (serverData.substring(0, 7) === "FILEID:") {
addImage(serverData.substring(7));
progress.setStatus("Thumbnail Created.");
progress.toggleCancel(false);
} else {
addImage("http://demo.swfupload.org/v220/applicationdemo/images/error.gif");
progress.setStatus("Error.");
progress.toggleCancel(false);
alert(serverData);
}
} catch (ex) {
this.debug(ex);
}
}
function uploadComplete(file) {
try {
/* I want the next upload to continue automatically so I'll call startUpload here */
if (this.getStats().files_queued > 0) {
this.startUpload();
} else {
var progress = new FileProgress(file, this.customSettings.upload_target);
progress.setComplete();
progress.setStatus("All images received.");
progress.toggleCancel(false);
}
} catch (ex) {
this.debug(ex);
}
}
function uploadError(file, errorCode, message) {
var imageName = "error.gif";
var progress;
try {
switch (errorCode) {
case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
try {
progress = new FileProgress(file, this.customSettings.upload_target);
progress.setCancelled();
progress.setStatus("Cancelled");
progress.toggleCancel(false);
}
catch (ex1) {
this.debug(ex1);
}
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
try {
progress = new FileProgress(file, this.customSettings.upload_target);
progress.setCancelled();
progress.setStatus("Stopped");
progress.toggleCancel(true);
}
catch (ex2) {
this.debug(ex2);
}
case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
imageName = "uploadlimit.gif";
break;
default:
alert(message);
break;
}
addImage("http://demo.swfupload.org/v220/applicationdemo/images/" + imageName);
} catch (ex3) {
this.debug(ex3);
}
}
function addImage(src) {
var newImg = document.createElement("img");
newImg.style.margin = "5px";
document.getElementById("thumbnails").appendChild(newImg);
if (newImg.filters) {
try {
newImg.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 0;
} catch (e) {
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
newImg.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + 0 + ')';
}
} else {
newImg.style.opacity = 0;
}
newImg.onload = function () {
fadeIn(newImg, 0);
};
newImg.src = src;
}
function fadeIn(element, opacity) {
var reduceOpacityBy = 5;
var rate = 30; // 15 fps
if (opacity < 100) {
opacity += reduceOpacityBy;
if (opacity > 100) {
opacity = 100;
}
if (element.filters) {
try {
element.filters.item("DXImageTransform.Microsoft.Alpha").opacity = opacity;
} catch (e) {
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
element.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + opacity + ')';
}
} else {
element.style.opacity = opacity / 100;
}
}
if (opacity < 100) {
setTimeout(function () {
fadeIn(element, opacity);
}, rate);
}
}
/* ******************************************
* FileProgress Object
* Control object for displaying file info
* ****************************************** */
function FileProgress(file, targetID) {
this.fileProgressID = "divFileProgress";
this.fileProgressWrapper = document.getElementById(this.fileProgressID);
if (!this.fileProgressWrapper) {
this.fileProgressWrapper = document.createElement("div");
this.fileProgressWrapper.className = "progressWrapper";
this.fileProgressWrapper.id = this.fileProgressID;
this.fileProgressElement = document.createElement("div");
this.fileProgressElement.className = "progressContainer";
var progressCancel = document.createElement("a");
progressCancel.className = "progressCancel";
progressCancel.href = "#";
progressCancel.style.visibility = "hidden";
progressCancel.appendChild(document.createTextNode(" "));
var progressText = document.createElement("div");
progressText.className = "progressName";
progressText.appendChild(document.createTextNode(file.name));
var progressBar = document.createElement("div");
progressBar.className = "progressBarInProgress";
var progressStatus = document.createElement("div");
progressStatus.className = "progressBarStatus";
progressStatus.innerHTML = "&nbsp;";
this.fileProgressElement.appendChild(progressCancel);
this.fileProgressElement.appendChild(progressText);
this.fileProgressElement.appendChild(progressStatus);
this.fileProgressElement.appendChild(progressBar);
this.fileProgressWrapper.appendChild(this.fileProgressElement);
document.getElementById(targetID).appendChild(this.fileProgressWrapper);
fadeIn(this.fileProgressWrapper, 0);
} else {
this.fileProgressElement = this.fileProgressWrapper.firstChild;
this.fileProgressElement.childNodes[1].firstChild.nodeValue = file.name;
}
this.height = this.fileProgressWrapper.offsetHeight;
}
FileProgress.prototype.setProgress = function (percentage) {
this.fileProgressElement.className = "progressContainer green";
this.fileProgressElement.childNodes[3].className = "progressBarInProgress";
this.fileProgressElement.childNodes[3].style.width = percentage + "%";
};
FileProgress.prototype.setComplete = function () {
this.fileProgressElement.className = "progressContainer blue";
this.fileProgressElement.childNodes[3].className = "progressBarComplete";
this.fileProgressElement.childNodes[3].style.width = "";
};
FileProgress.prototype.setError = function () {
this.fileProgressElement.className = "progressContainer red";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
};
FileProgress.prototype.setCancelled = function () {
this.fileProgressElement.className = "progressContainer";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
};
FileProgress.prototype.setStatus = function (status) {
this.fileProgressElement.childNodes[2].innerHTML = status;
};
FileProgress.prototype.toggleCancel = function (show, swfuploadInstance) {
this.fileProgressElement.childNodes[0].style.visibility = show ? "visible" : "hidden";
if (swfuploadInstance) {
var fileID = this.fileProgressID;
this.fileProgressElement.childNodes[0].onclick = function () {
swfuploadInstance.cancelUpload(fileID);
return false;
};
}
};
var swfu;
window.onload = function () {
swfu = new SWFUpload({
// Backend Settings
upload_url: "<%= new_upload_path_with_session_information %>",
post_params : {
'method' : "_put",
'authenticity_token' : '<%= u form_authenticity_token -%>',
'photo[album_id]' : "<%= @album.id %>"
},
// File Upload Settings
file_size_limit : "2 MB", // 2MB
file_types : "*.jpg",
file_types_description : "JPG Images",
file_upload_limit : "0",
// Event Handler Settings - these functions as defined in Handlers.js
// The handlers are not part of SWFUpload but are part of my website and control how
// my website reacts to the SWFUpload events.
file_queue_error_handler : fileQueueError,
file_dialog_complete_handler : fileDialogComplete,
upload_progress_handler : uploadProgress,
upload_error_handler : uploadError,
upload_success_handler : uploadSuccess,
upload_complete_handler : uploadComplete,
// Button Settings
button_image_url : "http://demo.swfupload.org/v220/applicationdemo/images/SmallSpyGlassWithTransperancy_17x18.png",
button_placeholder_id : "spanButtonPlaceholder",
button_width: 180,
button_height: 18,
button_text : '<span class="button">Select Images <span class="buttonSmall">(2 MB Max)</span></span>',
button_text_style : '.button { font-family: Helvetica, Arial, sans-serif; font-size: 12pt; } .buttonSmall { font-size: 10pt; }',
button_text_top_padding: 0,
button_text_left_padding: 18,
button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
button_cursor: SWFUpload.CURSOR.HAND,
// Flash Settings
flash_url : "/javascripts/swfupload/Flash/swfupload.swf",
custom_settings : {
upload_target : "divFileProgressContainer"
},
// Debug Settings
debug: false
});
};
</script>
<div id="content">
<h2>Application Demo</h2>
<p>This demo shows how SWFUpload can behave like an AJAX application. Images are uploaded by SWFUpload then some JavaScript is used to display the thumbnails without reloading the page.</p>
<% form_for(Photo.new) do |f| %>
<div style="display: inline; border: solid 1px #7FAAFF; background-color: #C5D9FF; padding: 2px;">
<span id="spanButtonPlaceholder"></span>
</div>
<% end %>
<div id="divFileProgressContainer" style="height: 75px;"></div>
<div id="thumbnails"></div>
</div>

View file

@ -1,2 +1,4 @@
<h1>Albums</h1> <h1>Albums</h1>
<%= render :partial => @albums %> <%= render :partial => @albums %>
<br /><%= link_to "All albums", albums_path %>

View file

@ -2,5 +2,7 @@
<p><%= h @collection.description %></p> <p><%= h @collection.description %></p>
<%= render :partial => @collection.albums %> <%= render :partial => @collection.albums %>
<% if has_role?("admin") %>
<br /><%= link_to "Update collection", edit_collection_path(@collection) %> <br /><%= link_to "Update collection", edit_collection_path(@collection) %>
<% end %>
<br /><%= link_to "All collections", collections_path %> <br /><%= link_to "All collections", collections_path %>

View file

@ -0,0 +1 @@
<ul><%= render :partial => @photos %></ul>

View file

@ -4,6 +4,9 @@
<br/> <br/>
Tagged with: <%= @photo.tag_list %> Tagged with: <%= @photo.tag_list %>
<p><%= @photo.description %></p> <p><%= @photo.description %></p>
<% if has_role?("admin") %>
<br /><%= link_to "Update photo details", edit_photo_path(@photo) %> <br /><%= link_to "Update photo details", edit_photo_path(@photo) %>
<% end %>
<br /><%= link_to "Back to #{@photo.album.title}", @photo.album %> <br /><%= link_to "Back to #{@photo.album.title}", @photo.album %>
<br /><%= link_to "All albums", albums_path %> <br /><%= link_to "All albums", albums_path %>

View file

@ -1 +1,3 @@
<ul><%= render :partial => @photos %></ul> <ul><%= render :partial => @photos %></ul>
<br /><%= link_to "Back to #{@album.title}", @album %>

View file

@ -34,3 +34,4 @@ $(document).ready(function() {
<div id="thumbs"></div> <div id="thumbs"></div>
</form> </form>
<br /><%= link_to "Back to #{@album.title}", @album %>

View file

@ -1,6 +1,6 @@
<h1>Login</h1> <h1>Login</h1>
<% form_for @user_session, :url => user_session_path do |f| %> <% form_for @user_session, :url => authenticate_path do |f| %>
<%= f.error_messages %> <%= f.error_messages %>
<%= f.label :email %><br /> <%= f.label :email %><br />
<%= f.text_field :email %><br /> <%= f.text_field :email %><br />

View file

@ -41,3 +41,4 @@
<%= link_to 'Edit', edit_account_path %> <%= link_to 'Edit', edit_account_path %>
<%= link_to 'Logout', logout_path %>

View file

@ -1,19 +1,18 @@
ActionController::Routing::Routes.draw do |map| ActionController::Routing::Routes.draw do |map|
#map.resources :users
map.resource :user_session
map.resource :account, :controller => "users" map.resource :account, :controller => "users"
map.signup "signup", :controller => "users", :action => "new"
map.login "login", :controller => "user_sessions", :action => "new" map.login "login", :controller => "user_sessions", :action => "new"
map.authenticate "authenticate", :controller => "user_sessions", :action => "create"
map.logout "logout", :controller => "user_sessions", :action => "destroy" map.logout "logout", :controller => "user_sessions", :action => "destroy"
map.resources :photos, :collection => { :untouched => :get } map.resources :photos,
map.resources :albums, :collection => { :untouched => :get }, :member => { :upload => :get}, :has_many => [ :photos ] :collection => { :untouched => :get, :edit_multiple => :post, :update_multiple => :put, :upload => :get }
map.resources :collections map.resources :albums, :collection => { :untouched => :get} do |album|
map.resources :tags, :has_many => [ :photos ] album.resources :photos, :collection => { :untouched => :get, :upload => :get, :edit_multiple => :get }
map.namespace :admin do |admin|
admin.resources :users
end end
map.resources :collections
map.resources :tags, :has_many => [ :photos, :albums ]
map.resources :users, :controller => "admin/users"
map.root :controller => "collections" map.root :controller => "collections"