a whole BUNCH of stuff

This commit is contained in:
Espen Antonsen 2009-06-02 00:08:57 +02:00
parent ab500a4cf1
commit f2599d9f46
71 changed files with 6632 additions and 346 deletions

251
README
View file

@ -1,243 +1,16 @@
== Welcome to Rails
== Welcome to Gallery!
Rails is a web-application framework that includes everything needed to create
database-backed web applications according to the Model-View-Control pattern.
Made by Espen Antonsen
This pattern splits the view (also called the presentation) into "dumb" templates
that are primarily responsible for inserting pre-built data in between HTML tags.
The model contains the "smart" domain objects (such as Account, Product, Person,
Post) that holds all the business logic and knows how to persist themselves to
a database. The controller handles the incoming requests (such as Save New Account,
Update Product, Show Post) by manipulating the model and directing data to the view.
== Requirements
In Rails, the model is handled by what's called an object-relational mapping
layer entitled Active Record. This layer allows you to present the data from
database rows as objects and embellish these data objects with business logic
methods. You can read more about Active Record in
link:files/vendor/rails/activerecord/README.html.
Software
- FreeIamge (required for Image Science)
- ExifTool (required for Mini_EfixTool)
The controller and view are handled by the Action Pack, which handles both
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
Rails. You can read more about Action Pack in
link:files/vendor/rails/actionpack/README.html.
== Getting Started
1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
and your application name. Ex: rails myapp
2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
4. Follow the guidelines to start developing your application
== Web Servers
By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
with a variety of other web servers.
Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
More info at: http://mongrel.rubyforge.org
Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
== Apache .htaccess example for FCGI/CGI
# General Apache options
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
# RewriteCond %{REQUEST_URI} ^/notrails.*
# RewriteRule .* - [L]
# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On
# If your Rails application is accessed via an Alias directive,
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
# Alias /myrailsapp /path/to/myrailsapp/public
# RewriteBase /myrailsapp
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
# ErrorDocument 500 /500.html
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
== Debugging Rails
Sometimes your application goes wrong. Fortunately there are a lot of tools that
will help you debug it and get it back on the rails.
First area to check is the application log files. Have "tail -f" commands running
on the server.log and development.log. Rails will automatically display debugging
and runtime information to these files. Debugging info will also be shown in the
browser on requests from 127.0.0.1.
You can also log your own messages directly into the log file from your code using
the Ruby logger class from inside your controllers. Example:
class WeblogController < ActionController::Base
def destroy
@weblog = Weblog.find(params[:id])
@weblog.destroy
logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
end
end
The result will be a message in your log file along the lines of:
Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
More information on how to use the logger is at http://www.ruby-doc.org/core/
Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
These two online (and free) books will bring you up to speed on the Ruby language
and also on programming in general.
== Debugger
Debugger support is available through the debugger command when you start your Mongrel or
Webrick server with --debugger. This means that you can break out of execution at any point
in the code, investigate and change the model, AND then resume execution!
You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
Example:
class WeblogController < ActionController::Base
def index
@posts = Post.find(:all)
debugger
end
end
So the controller will accept the action, run the first line, then present you
with a IRB prompt in the server window. Here you can do things like:
>> @posts.inspect
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
>> @posts.first.title = "hello from a debugger"
=> "hello from a debugger"
...and even better is that you can examine how your runtime objects actually work:
>> f = @posts.first
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you enter "cont"
== Console
You can interact with the domain model by starting the console through <tt>script/console</tt>.
Here you'll have all parts of the application configured, just like it is when the
application is running. You can inspect domain models, change values, and save to the
database. Starting the script without arguments will launch it in the development environment.
Passing an argument will specify a different environment, like <tt>script/console production</tt>.
To reload your controllers and models after launching the console run <tt>reload!</tt>
== dbconsole
You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
You would be connected to the database with the credentials defined in database.yml.
Starting the script without arguments will connect you to the development database. Passing an
argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
Currently works for mysql, postgresql and sqlite.
== Description of Contents
app
Holds all the code that's specific to this particular application.
app/controllers
Holds controllers that should be named like weblogs_controller.rb for
automated URL mapping. All controllers should descend from ApplicationController
which itself descends from ActionController::Base.
app/models
Holds models that should be named like post.rb.
Most models will descend from ActiveRecord::Base.
app/views
Holds the template files for the view that should be named like
weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
syntax.
app/views/layouts
Holds the template files for layouts to be used with views. This models the common
header/footer method of wrapping views. In your views, define a layout using the
<tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
call <% yield %> to render the view using this layout.
app/helpers
Holds view helpers that should be named like weblogs_helper.rb. These are generated
for you automatically when using script/generate for controllers. Helpers can be used to
wrap functionality for your views into methods.
config
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
db
Contains the database schema in schema.rb. db/migrate contains all
the sequence of Migrations for your schema.
doc
This directory is where your application documentation will be stored when generated
using <tt>rake doc:app</tt>
lib
Application specific libraries. Basically, any kind of custom code that doesn't
belong under controllers, models, or helpers. This directory is in the load path.
public
The directory available for the web server. Contains subdirectories for images, stylesheets,
and javascripts. Also contains the dispatchers and the default HTML files. This should be
set as the DOCUMENT_ROOT of your web server.
script
Helper scripts for automation and generation.
test
Unit and functional tests along with fixtures. When using the script/generate scripts, template
test files will be generated for you and placed in this directory.
vendor
External libraries that the application depends on. Also includes the plugins subdirectory.
If the app has frozen rails, those gems also go here, under vendor/rails/.
This directory is in the load path.
Ruby Gems
- AuthLogic
- Mime-Types
- Image_Science
- RubyInline (required for Image_Science)
- Mini_ExifTool

View file

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

View file

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

View file

@ -1,5 +1,5 @@
class AlbumsController < ApplicationController
before_filter :require_user, :only => [:new, :create, :edit, :update, :delete, :destroy]
before_filter :require_user, :only => [:new, :create, :edit, :update, :delete, :destroy, :upload]
def index
@albums = Album.find(:all)
@ -26,9 +26,8 @@ class AlbumsController < ApplicationController
def create
@album = Album.new(params[:album])
@album.path = @album.title
if @album.save
Dir.mkdir( APP_CONFIG[:photos_path] + @album.title )
Dir.mkdir( APP_CONFIG[:thumbs_path] + @album.title )
flash[:notice] = "Album created!"
redirect_to @album
else
@ -50,13 +49,18 @@ class AlbumsController < ApplicationController
end
end
def destory
def destroy
@album = Album.find( params[:id])
if @album.destory
redirect_to album_path
if @album.destroy
redirect_to albums_path
else
redirect_to @album
end
end
def upload
@user = current_user_session
@album = Album.find( params[:id])
end
end

View file

@ -2,7 +2,22 @@ class PhotosController < ApplicationController
before_filter :require_user, :only => [:new, :create, :edit, :update, :destroy]
def index
@photos = Tag.find_by_title( params[:tag_id] ).photos
if params[:tag_id]
@photos = Tag.find_by_title( params[:tag_id] ).photos
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 )
else
@photos = Photo.find(:all, :limit => 20)
end
respond_to do |format|
format.html
format.json { render :json => @photos }
format.xml { render :xml => @photos }
end
end
def untouched
@photos = Photo.untouched()
respond_to do |format|
format.html
format.json { render :json => @photos }
@ -24,13 +39,26 @@ class PhotosController < ApplicationController
end
def create
@photo = Photo.new(params[:photo])
if @photo.save
# upload
flash[:notice] = "Photo created!"
redirect_to @photo
else
render :action => :new
respond_to do |format|
@photo = Photo.new(params[:photo])
if params[:Filedata]
@photo.swf_uploaded_data = params[:Filedata]
@photo.save!
format.html { render :text => "FILEID:" + @photo.public_path_modified("album") }
format.xml { render :nothing => true }
else
if @photo.save
flash[:notice] = 'Created'
format.html { redirect_to(@photo) }
format.xml { render :xml => @photo }
else
format.html { render :action => "new" }
format.xml { render :xml => @photo.errors }
end
end
end
end
@ -48,10 +76,11 @@ class PhotosController < ApplicationController
end
end
def destory
def destroy
@photo = Photo.find( params[:id])
if @photo.destory
redirect_to photo_path
@album = @photo.album
if @photo.destroy
redirect_to @album
else
redirect_to @photo
end

View file

@ -19,6 +19,6 @@ class UserSessionsController < ApplicationController
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
redirect_back_or_default new_user_session_url
redirect_to root_path
end
end

View file

@ -1,6 +1,6 @@
class UsersController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => [:show, :edit, :update]
before_filter :require_user, :only => [:show, :edit, :update, :destroy]
def new
@user = User.new
@ -33,4 +33,13 @@ class UsersController < ApplicationController
render :action => :edit
end
end
def destroy
@user = @current_user
if @user.destroy
redirect_to users_path
else
redirect_to @user
end
end
end

View file

@ -1,2 +1,10 @@
module AlbumsHelper
def new_upload_path_with_session_information
session_key = ActionController::Base.session_options[:key]
photos_path(session_key => cookies[session_key], request_forgery_protection_token => form_authenticity_token)
end
def get_session_key
ActionController::Base.session_options[:key]
end
end

View file

@ -0,0 +1,16 @@
require 'rack/utils'
class FlashSessionCookieMiddleware
def initialize(app, session_key = '_session_id')
@app = app
@session_key = session_key
end
def call(env)
if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
env['HTTP_COOKIE'] = [ @session_key, params[@session_key] ].join('=').freeze unless params[@session_key].nil?
end
@app.call(env)
end
end

View file

@ -1,12 +1,60 @@
class Album < ActiveRecord::Base
has_many :photos, :dependent => :destroy
validates_uniqueness_of :path, :message => "Album already exsists on disc"
before_validation :ensure_path
after_create :create_folders
before_destroy :destroy_directory
attr_accessor :tag_list
attr_protected :path
protected
def ensure_path
self.path = self.title if !self.path
end
def tag_list
tags = Array.new
self.photos.map{ |photo|
if photo.tags.empty?
return
else
photo.tags
end }.each_with_index{ |tag,i|
puts tag.inspect
tag.each { |t|
puts t.title
puts i
if i == 0
tags.push(t.title)
elsif !tags.include?(t.title)
tags.delete(t.title)
end
}
}
return tags.join(" ")
end
def tag_list=(tags)
return if tags == self.tag_list
#TODO HERE!
ts = Array.new
tags.split(" ").each do |tag|
ts.push( Tag.find_or_create_by_title( :title => tag) )
end
self.tags = ts
end
private
def create_folders
Dir.mkdir( APP_CONFIG[:photos_path] + self.path )
Dir.mkdir( APP_CONFIG[:thumbs_path] + self.path )
end
def destroy_directory
#puts "DELETE DIRECTORY " + APP_CONFIG[:photos_path] + self.path
#Dir.delete( APP_CONFIG[:photos_path] + self.path + "/" ) if File.exists?( APP_CONFIG[:photos_path] + self.path )

View file

@ -1,16 +1,41 @@
require "image_science"
require 'mini_exiftool'
class Photo < ActiveRecord::Base
belongs_to :album
has_many :photo_tags, :dependent => :destroy
has_many :tags, :through => :photo_tags
#accepts_nested_attributes_for :photo_tags, :allow_destroy => true
validates_uniqueness_of :path, :message => "Photo already exsists on disc"
validates_presence_of :title
before_create :create_thumbnails, :read_exif
before_destroy :destroy_file
attr_accessor :tag_list
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
def path_original
return APP_CONFIG[:photos_path] + self.path
end
def path_original_public
return APP_CONFIG[:photos_path_public] + self.path
end
def path_modified(size)
return APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_" + size + ".jpg"
end
def path_modified_public(size)
return APP_CONFIG[:thumbs_path_public] + self.album.path + "/" + self.id.to_s + "_" + size + ".jpg"
end
def tag_list
return self.tags.find(:all, :order => 'title').collect{ |t| t.title }.join(" ")
@ -24,13 +49,67 @@ class Photo < ActiveRecord::Base
self.tags = ts
end
def create_thumbnails
ImageScience.with_image(APP_CONFIG[:photos_path] + self.path) do |img|
#puts " thumbing it..thumbing it.."
ext = File.extname( APP_CONFIG[:photos_path] + self.path )
img.thumbnail(85) do |thumb|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_thumb" + ext
end
img.thumbnail(150) do |thumb|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_album" + ext
end
img.thumbnail(800) do |thumb|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_large" + ext
end
end
end
def read_exif
photo = MiniExiftool.new(self.path_original)
self.longitude = photo.GPSLongitude
self.latitude = photo.GPSLatitude
self.title = photo.DocumentName
self.description = photo.ImageDescription
end
def write_exif
photo = MiniExiftool.new(self.path_original)
photo.GPSLongitude = self.longitude
photo.GPSLatitude = self.latitude
photo.DocumentName = self.title
photo.ImageDescription = self.description
photo.save
end
def exif_info
photo = MiniExiftool.new(self.path_original)
photo.tags.sort.each do |tag|
puts tag.ljust(28) + photo[tag].to_s
end
end
# Map file extensions to mime types.
# Thanks to bug in Flash 8 the content type is always set to application/octet-stream.
# From: http://blog.airbladesoftware.com/2007/8/8/uploading-files-with-swfupload
def swf_uploaded_data=(data)
data.content_type = MIME::Types.type_for(data.original_filename)
self.title = data.original_filename
self.path = self.album.path + "/" + data.original_filename
File.open(APP_CONFIG[:photos_path] + self.path, "wb") { |f| f.write(data.read) }
end
private
def destroy_file
puts "DELETE FILE " + APP_CONFIG[:photos_path] + self.path
File.delete( APP_CONFIG[:photos_path] + self.path ) if File.exists?( APP_CONFIG[:photos_path] + self.path )
File.delete( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_small" + File.extname( APP_CONFIG[:photos_path] + self.path ) ) if File.exists?( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_small" + File.extname( APP_CONFIG[:photos_path] + self.path ) )
#puts "DELETE THUMBS OF " + APP_CONFIG[:photos_path] + self.path
#File.delete( APP_CONFIG[:photos_path] + self.path ) if File.exists?( APP_CONFIG[:photos_path] + self.path )
File.delete( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_thumb" + File.extname( APP_CONFIG[:photos_path] + self.path ) ) if File.exists?( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_small" + File.extname( APP_CONFIG[:photos_path] + self.path ) )
File.delete( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_album" + File.extname( APP_CONFIG[:photos_path] + self.path ) ) if File.exists?( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_small" + File.extname( APP_CONFIG[:photos_path] + self.path ) )
File.delete( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_large" + File.extname( APP_CONFIG[:photos_path] + self.path ) ) if File.exists?( APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_large" + File.extname( APP_CONFIG[:photos_path] + self.path ) )
end
end

View file

@ -3,6 +3,10 @@ class Tag < ActiveRecord::Base
has_many :photos, :through => :photo_tags
validates_uniqueness_of :title
def self.tag_list
return self.find(:all).map { |tag| tag.title }.join('\',\'')
end
def to_param
#{ }"#{id}-#{name.gsub(/[^a-z0-9]+/i, '-')}"

View file

@ -0,0 +1,11 @@
<%= form.label :name, 'Display name' %><br />
<%= form.text_field :name %><br />
<br />
<%= form.label :email %><br />
<%= form.text_field :email %><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

@ -0,0 +1,13 @@
<h1>Edit Account</h1>
<% form_for [:admin, @user] do |f| %>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<%= f.submit "Update" %>
<% end %>
<br /><%= link_to("Delete user", { :action => "destroy", :id => @user },
:confirm => "Are you sure you want to delete this user?",
:method => :delete) %>
<br /><%= link_to "All users", admin_users_path %>

View file

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

View file

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

View file

@ -0,0 +1,44 @@
<p>
<b>Name:</b>
<%=h @user.name %>
</p>
<p>
<b>Email:</b>
<%=h @user.email %>
</p>
<p>
<b>Login count:</b>
<%=h @user.login_count %>
</p>
<p>
<b>Last request at:</b>
<%=h @user.last_request_at %>
</p>
<p>
<b>Last login at:</b>
<%=h @user.last_login_at %>
</p>
<p>
<b>Current login at:</b>
<%=h @user.current_login_at %>
</p>
<p>
<b>Last login ip:</b>
<%=h @user.last_login_ip %>
</p>
<p>
<b>Current login ip:</b>
<%=h @user.current_login_ip %>
</p>
<%= link_to 'Edit', edit_admin_user_path(@user) %><br/>
<br /><%= link_to "All users", admin_users_path %>

View file

@ -1,7 +1,19 @@
<%= form.label :title %><br />
<%= form.text_field :title %><br />
<%= form.label :title, :Title, {:class => 'big'} %><br />
<%= form.text_field :title, {:class => 'big'} %><br />
<%= form.label :description %><br />
<%= form.text_area :description %><br />
<%= form.label :address %><br />
<%= form.text_area :address, { :rows => 3} %><br />
<%= form.label :note %><br />
<%= form.text_area :note %><br />
<%= form.label :tag_list %><br />
<%= form.text_field :tag_list, { :autocomplete => "off"} %><br />
<br />
<% if @album.path? %>
Location on disk: <i><%= APP_CONFIG[:photos_path] + @album.path %></i><br/>
Contains: <%= @album.photos.count %> photos<br/>
Contains: <%= @album.photos.count %> photos<br/>
<% end %>

View file

@ -6,4 +6,8 @@
<%= f.submit "Update" %>
<% end %>
<br /><%= link_to("Delete album", { :action => "destroy", :id => @album },
:confirm => "Are you sure you want to delete this album?",
:method => :delete) %>
<br /><%= link_to "All albums", albums_path %>

View file

@ -1,30 +1,6 @@
<% content_for :head do %>
<link rel="stylesheet" href="/javascripts/galleria/galleria.css" type="text/css" media="screen" charset="utf-8">
<% for photo in @album.photos %>
<%= link_to image_tag( photo.public_path_modified("album") ), photo %>
<% end %>
<% content_for :javascript do %>
<script type="text/javascript" src="/javascripts/galleria/jquery.galleria.js"></script>
<script type="text/javascript" src="/javascripts/scrollable/jquery.scrollable-1.0.2.js"></script>
<script type="text/javascript" src="/javascripts/jquery.mousewheel.3.0.2/jquery.mousewheel.js"></script>
<% end %>
<h1><%= @album.title %></h1>
<% if current_user %>
<%= link_to "Edit album", edit_album_path( @album )%>
<% end %>
<%= link_to "Generate PDF", album_path( @album, :pdf) %>
<div id="photo">
<div id="photo_metadata"></div>
<div id="photo_large">
</div>
</div>
<div id="thumbstrip">
<ul id="thumbs" class="gallery">
<%= render :partial => @album.photos.find(:all) %>
</ul>
</div>
<p><%= @album.description %></p>
<br /><%= link_to "Update album", edit_album_path(@album) %>
<br /><%= link_to "All albums", albums_path %>

View file

@ -0,0 +1,30 @@
<% content_for :head do %>
<link rel="stylesheet" href="/javascripts/galleria/galleria.css" type="text/css" media="screen" charset="utf-8">
<% end %>
<% content_for :javascript do %>
<script type="text/javascript" src="/javascripts/galleria/jquery.galleria.js"></script>
<script type="text/javascript" src="/javascripts/scrollable/jquery.scrollable-1.0.2.js"></script>
<script type="text/javascript" src="/javascripts/jquery.mousewheel.3.0.2/jquery.mousewheel.js"></script>
<% end %>
<h1><%= @album.title %></h1>
<% if current_user %>
<%= link_to "Edit album", edit_album_path( @album )%>
<% end %>
<%= link_to "Generate PDF", album_path( @album, :pdf) %>
<div id="photo">
<div id="photo_metadata"></div>
<div id="photo_large">
</div>
</div>
<div id="thumbstrip">
<ul id="thumbs" class="gallery">
<%= render :partial => @album.photos.find(:all) %>
</ul>
</div>
<p><%= @album.description %></p>

View file

@ -0,0 +1,697 @@
<% 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

@ -0,0 +1,35 @@
<% content_for :javascript do %>
<script type="text/javascript" src="/javascripts/jquery.uploadify-v1.6.2.mit/jquery.uploadify.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#photo').fileUpload({
uploader:'/javascripts/jquery.uploadify-v1.6.2.mit/uploader.swf',
script:'<%= photos_path %>',
scriptData: {
'<%= get_session_key %>' : '<%= cookies[get_session_key] %>',
'method' : '_put',
'authenticity_token' : '<%= u form_authenticity_token %>',
'photo[album_id]' : "<%= @album.id %>"
},
cancelImg:'/javascripts/jquery.uploadify-v1.6.2.mit/cancel.png',
multi:true,
auto:true,
onComplete : function (e,queueId,fileObj,res,data) {
if (res.substring(0, 7) === "FILEID:") {
var image = $('<img>').appendTo('#thumbs')
image.css('display','none')
image.attr('src', res.substring(7) )
image.fadeIn('slow')
}
}
})
})
</script>
<% end %>
<form>
<input type="file" id="photo" name="photo" />
<br />
<div id="thumbs"></div>
</form>

View file

@ -1,4 +1,4 @@
<li>
<a href="<%= APP_CONFIG[:thumbs_path_public] + photo.album.path + "/" + photo.id.to_s + "_large.jpg" %>" title="<%= photo.title %>">
<%= image_tag APP_CONFIG[:thumbs_path_public] + photo.album.path + "/" + photo.id.to_s + "_small.jpg", { :id => 'thumb_' + photo.id.to_s } %></a>
<a href="<%= photo.public_path_modified("large") %>" title="<%= photo.title %>">
<%= image_tag photo.public_path_modified("album"), { :id => 'thumb_' + photo.id.to_s } %></a>
</li>

View file

@ -1 +1 @@
<%= image_tag APP_CONFIG[:photos_path_public] + photo.path %><br/>
<%= image_tag photo.public_path_original %><br/>

View file

@ -1 +1 @@
<%= image_tag APP_CONFIG[:thumbs_path_public] + photo.id.to_s + ".jpg" %>
<%= image_tag photo.public_path_modified("thumb") %>

View file

@ -6,5 +6,8 @@
<%= f.submit "Update" %>
<% end %>
<%= image_tag APP_CONFIG[:thumbs_path_public] + @photo.album.path + "/" + @photo.id.to_s + "_large.jpg" %>
<%= image_tag @photo.public_path_modified("large") %>
<br /><%= link_to("Delete photo", { :action => "destroy", :id => @photo },
:confirm => "Are you sure you want to delete this photo?",
:method => :delete) %>
<br /><%= link_to "All albums", albums_path %>

View file

@ -1,16 +1 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>index.html</title>
</head>
<body>
</body>
</html>
<ul><%= render :partial => @photos %></ul>

View file

@ -1,7 +1,8 @@
<h1><%= @photo.title%></h1>
<%= image_tag APP_CONFIG[:thumbs_path_public] + @photo.album.path + "/" + @photo.id.to_s + "_large.jpg" %>
<%= image_tag @photo.public_path_modified("large") %>
<br/>
Tagged with: <%= @photo.tag_list %>
<p><%= @photo.description %></p>
<br /><%= link_to "Update photo details", edit_photo_path(@photo) %>
<br /><%= link_to "All albums", albums_path %>

View file

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

View file

@ -1,4 +1,4 @@
<h1>Tags</h1>
<% for tag in @tags %>
<%= tag.title %>
<p><%= link_to tag.title, tag_photos_path(tag) %></p>
<% end %>

View file

@ -1,3 +1,6 @@
<%= form.label :name, 'Display name' %><br />
<%= form.text_field :name %><br />
<br />
<%= form.label :email %><br />
<%= form.text_field :email %><br />
<br />

View file

@ -1,3 +1,14 @@
<p>
<b>Name:</b>
<%=h @user.name %>
</p>
<p>
<b>Email:</b>
<%=h @user.email %>
</p>
<p>
<b>Login count:</b>
<%=h @user.login_count %>

View file

@ -10,14 +10,17 @@ require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
config.gem "authlogic"
config.gem 'mime-types', :lib => 'mime/types'
#config.gem "image_science"
config.load_paths += %W( #{RAILS_ROOT}/app/middleware )
config.time_zone = 'Copenhagen'
config.i18n.default_locale = 'no-NB'
config.action_controller.session = {
:session_key => '_app_session',
:session_key => '_gallery_session',
:secret => '060feafeop90cuepaiam324eoimxeaioa2b4220c445486dace48f53fc0a0d4ec4e8de033e1db323628d66b6cx990loibjustintime99'
}

View file

@ -13,3 +13,5 @@ ActionController::Base.session = {
# which shouldn't be used to store highly confidential information
# (create the session table with "rake db:sessions:create")
# ActionController::Base.session_store = :active_record_store
ActionController::Dispatcher.middleware.use FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]

View file

@ -1,16 +1,19 @@
ActionController::Routing::Routes.draw do |map|
map.resources :users
#map.resources :users
map.resource :user_session
map.resource :account, :controller => "users"
map.signup "signup", :controller => "users", :action => "new"
map.login "login", :controller => "user_sessions", :action => "new"
map.logout "logout", :controller => "user_sessions", :action => "destroy"
map.resources :photos
map.resources :albums
map.resources :photos, :collection => { :untouched => :get }
map.resources :albums, :has_many => [ :photos ], :collection => { :untouched => :get }, :member => { :upload => :get}
map.resources :tags, :has_many => [ :photos ]
#map.connect ':controller/:action/:id'
#map.connect ':controller/:action/:id.:format'
map.root :controller => "user_sessions", :action => "new" # optional, this just sets the root route
map.namespace :admin do |admin|
admin.resources :users
end
map.root :controller => "albums"
end

View file

@ -0,0 +1,13 @@
class AddLocationToAlbum < ActiveRecord::Migration
def self.up
add_column :albums, :address, :string
add_column :albums, :longitude, :float
add_column :albums, :latitude, :float
end
def self.down
remove_column :albums, :latitude
remove_column :albums, :longitude
remove_column :albums, :address
end
end

View file

@ -0,0 +1,9 @@
class AddNameToUser < ActiveRecord::Migration
def self.up
add_column :users, :name, :string
end
def self.down
remove_column :users, :name
end
end

View file

@ -0,0 +1,9 @@
class AddNoteToAlbum < ActiveRecord::Migration
def self.up
add_column :albums, :note, :text
end
def self.down
remove_column :albums, :note
end
end

View file

@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20090522190622) do
ActiveRecord::Schema.define(:version => 20090529155414) do
create_table "albums", :force => true do |t|
t.string "title", :null => false
@ -17,6 +17,10 @@ ActiveRecord::Schema.define(:version => 20090522190622) do
t.datetime "created_at"
t.datetime "updated_at"
t.text "path"
t.string "address"
t.float "longitude"
t.float "latitude"
t.text "note"
end
create_table "photo_tags", :force => true do |t|
@ -57,6 +61,7 @@ ActiveRecord::Schema.define(:version => 20090522190622) do
t.string "last_login_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
end

View file

@ -2,38 +2,30 @@ module ScanFiles
# protected
require "find"
#require 'RMagick'
require "image_science"
supported_files = ["jpeg", "jpg", "gif", "png"]
def self.FullScan
prevalbum = ""
Find.find( APP_CONFIG[:photos_path] ) { |path|
if File.file?(path) && [".jpeg", ".jpg", ".gif", ".png"].include?( File.extname(path) )
relpath = File.dirname( path ).sub(APP_CONFIG[:photos_path], '')
relfile = path.sub(APP_CONFIG[:photos_path], '')
puts relpath
album = Album.find_by_path( relpath )
if prevalbum != relpath
puts relpath
prevalbum = relpath
end
if album.nil?
puts "New album : " + File.basename( relpath )
album = Album.create( :path => relpath, :title => File.basename( File.dirname(path) ) )
Dir.mkdir( APP_CONFIG[:thumbs_path] + album.path )
end
if Photo.find_by_path( relpath ).nil?
puts "New photo added"
photo = Photo.find_by_path( relfile )
if photo.nil?
puts " New photo added " + relfile
photo = Photo.create( :album => album, :title => File.basename(path).sub( File.extname(path), '' ) , :path => relfile )
#image = Magick::Image.read(APP_CONFIG[:photos_path] + photo.path)
ImageScience.with_image(APP_CONFIG[:photos_path] + relfile) do |img|
puts "thumbing.."
img.thumbnail(75) do |thumb|
thumb.save APP_CONFIG[:thumbs_path] + photo.album.path + "/" + photo.id.to_s + "_small" + File.extname( APP_CONFIG[:photos_path] + photo.path )
end
img.thumbnail(600) do |thumb|
thumb.save APP_CONFIG[:thumbs_path] + photo.album.path + "/" + photo.id.to_s + "_large" + File.extname( APP_CONFIG[:photos_path] + photo.path )
end
end
#self.CreateThumbnail( photo, image, "small", 150, 150 )
#self.CreateThumbnail( photo, image, "large", 600, 500 )
else
puts " Found photo " + relfile
end
end
}

View file

@ -19,7 +19,6 @@ jQuery(function($) {
})
}
if ( $('#thumbstrip').length ) {
$('#thumbstrip').scrollable( {
items : '#thumbs',
@ -36,6 +35,9 @@ jQuery(function($) {
tags: $('#all_tags').val().split('\'')
})
}
if ( $('FORM #upload').length ) {
}
//$('div.scrollable').scrollable().click( $('#gallery ul').children().index( $('#gallery li.active') ) )
});

View file

@ -0,0 +1,19 @@
Copyright (c) 2009 Ronnie Garcia, Travis Nickels
Permission is hereby granted, free of charge, to any person obtaining a copy
of Uploadify 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.
UPLOADIFY 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

View file

@ -0,0 +1,35 @@
<?php
/*
Copyright (c) 2009 Ronnie Garcia, Travis Nickels
This file is part of Uploadify v1.6.2
Permission is hereby granted, free of charge, to any person obtaining a copy
of Uploadify 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.
UPLOADIFY 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.
*/
$fileArray = array();
foreach ($_POST as $key => $value) {
if ($key != 'folder') {
if (file_exists($_SERVER['DOCUMENT_ROOT'] . $_POST['folder'] . '/' . $value)) {
$fileArray[$key] = $value;
}
}
}
echo json_encode($fileArray);
?>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,251 @@
/*
Copyright (c) 2009 Ronnie Garcia, Travis Nickels
This file is part of Uploadify v1.6.2
Permission is hereby granted, free of charge, to any person obtaining a copy
of Uploadify 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.
UPLOADIFY 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.
*/
var flashVer = -1;
if (navigator.plugins != null && navigator.plugins.length > 0) {
if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
var descArray = flashDescription.split(" ");
var tempArrayMajor = descArray[2].split(".");
var versionMajor = tempArrayMajor[0];
var versionMinor = tempArrayMajor[1];
var versionRevision = descArray[3];
if (versionRevision == "") {
versionRevision = descArray[4];
}
if (versionRevision[0] == "d") {
versionRevision = versionRevision.substring(1);
} else if (versionRevision[0] == "r") {
ersionRevision = versionRevision.substring(1);
if (versionRevision.indexOf("d") > 0) {
versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
}
}
var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
}
} else if ( $.browser.msie ) {
var version;
var axo;
var e;
try {
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
version = axo.GetVariable("$version");
} catch (e) {
}
flashVer = version.replace("WIN ","").replace(",",".");
}
flashVer = flashVer.split(".")[0];
if(jQuery)(
function($){
$.extend($.fn,{
fileUpload:function(options) {
if (flashVer >= 9) {
$(this).each(function(){
settings = $.extend({
uploader: 'uploader.swf',
script: 'uploader.php',
folder: '',
height: 30,
width: 110,
cancelImg: 'cancel.png',
wmode: 'opaque',
scriptAccess: 'sameDomain',
fileDataName: 'Filedata',
displayData: 'percentage',
onInit: function() {},
onSelect: function() {},
onCheck: function() {},
onCancel: function() {},
onError: function() {},
onProgress: function() {},
onComplete: function() {}
}, options);
var pagePath = location.pathname;
pagePath = pagePath.split('/');
pagePath.pop();
pagePath = pagePath.join('/') + '/';
var data = '&pagepath=' + pagePath;
if (settings.buttonImg) data += '&buttonImg=' + escape(settings.buttonImg);
if (settings.buttonText) data += '&buttonText=' + escape(settings.buttonText);
if (settings.rollover) data += '&rollover=true';
data += '&script=' + settings.script;
data += '&folder=' + escape(settings.folder);
if (settings.scriptData) {
var scriptDataString = '';
for (var name in settings.scriptData) {
scriptDataString += '&' + name + '=' + settings.scriptData[name];
}
data += '&scriptData=' + escape(scriptDataString);
}
data += '&btnWidth=' + settings.width;
data += '&btnHeight=' + settings.height;
data += '&wmode=' + settings.wmode;
if (settings.hideButton) data += '&hideButton=true';
if (settings.fileDesc) data += '&fileDesc=' + settings.fileDesc + '&fileExt=' + settings.fileExt;
if (settings.multi) data += '&multi=true';
if (settings.auto) data += '&auto=true';
if (settings.sizeLimit) data += '&sizeLimit=' + settings.sizeLimit;
if (settings.simUploadLimit) data += '&simUploadLimit=' + settings.simUploadLimit;
if (settings.checkScript) data += '&checkScript=' + settings.checkScript;
if (settings.fileDataName) data += '&fileDataName=' + settings.fileDataName;
if ($.browser.msie) {
flashElement = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + settings.width + '" height="' + settings.height + '" id="' + $(this).attr("id") + 'Uploader" class="fileUploaderBtn">\
<param name="movie" value="' + settings.uploader + '?fileUploadID=' + $(this).attr("id") + data + '" />\
<param name="quality" value="high" />\
<param name="wmode" value="' + settings.wmode + '" />\
<param name="allowScriptAccess" value="' + settings.scriptAccess + '">\
<param name="swfversion" value="9.0.0.0" />\
</object>';
} else {
flashElement = '<embed src="' + settings.uploader + '?fileUploadID=' + $(this).attr("id") + data + '" quality="high" width="' + settings.width + '" height="' + settings.height + '" id="' + $(this).attr("id") + 'Uploader" class="fileUploaderBtn" name="' + $(this).attr("id") + 'Uploader" allowScriptAccess="' + settings.scriptAccess + '" wmode="' + settings.wmode + '" type="application/x-shockwave-flash" />';
}
if (settings.onInit() !== false) {
$(this).css('display','none');
if ($.browser.msie) {
$(this).after('<div id="' + $(this).attr("id") + 'Uploader"></div>');
document.getElementById($(this).attr("id") + 'Uploader').outerHTML = flashElement;
} else {
$(this).after(flashElement);
}
$("#" + $(this).attr('id') + "Uploader").after('<div id="' + $(this).attr('id') + 'Queue" class="fileUploadQueue"></div>');
}
$(this).bind("rfuSelect", {'action': settings.onSelect}, function(event, queueID, fileObj) {
if (event.data.action(event, queueID, fileObj) !== false) {
var byteSize = Math.round(fileObj.size / 1024 * 100) * .01;
var suffix = 'KB';
if (byteSize > 1000) {
byteSize = Math.round(byteSize *.001 * 100) * .01;
suffix = 'MB';
}
var sizeParts = byteSize.toString().split('.');
if (sizeParts.length > 1) {
byteSize = sizeParts[0] + '.' + sizeParts[1].substr(0,2);
} else {
byteSize = sizeParts[0];
}
if (fileObj.name.length > 20) {
fileName = fileObj.name.substr(0,20) + '...';
} else {
fileName = fileObj.name;
}
$('#' + $(this).attr('id') + 'Queue').append('<div id="' + $(this).attr('id') + queueID + '" class="fileUploadQueueItem">\
<div class="cancel">\
<a href="javascript:$(\'#' + $(this).attr('id') + '\').fileUploadCancel(\'' + queueID + '\')"><img src="' + settings.cancelImg + '" border="0" /></a>\
</div>\
<span class="fileName">' + fileName + ' (' + byteSize + suffix + ')</span><span class="percentage">&nbsp;</span>\
<div class="fileUploadProgress" style="width: 100%;">\
<div id="' + $(this).attr('id') + queueID + 'ProgressBar" class="fileUploadProgressBar" style="width: 1px; height: 3px;"></div>\
</div>\
</div>');
}
});
if (typeof(settings.onSelectOnce) == 'function') {
$(this).bind("rfuSelectOnce", settings.onSelectOnce);
}
$(this).bind("rfuCheckExist", {'action': settings.onCheck}, function(event, checkScript, fileQueue, folder, single) {
var postData = new Object();
postData.folder = pagePath + folder;
for (var queueID in fileQueue) {
postData[queueID] = fileQueue[queueID];
if (single) {
var singleFileID = queueID;
}
}
$.post(checkScript, postData, function(data) {
for(var key in data) {
if (event.data.action(event, checkScript, fileQueue, folder, single) !== false) {
var replaceFile = confirm('Do you want to replace the file \'' + data[key] + '\'?');
if (!replaceFile) {
document.getElementById($(event.target).attr('id') + 'Uploader').cancelFileUpload(key);
}
}
}
if (single) {
document.getElementById($(event.target).attr('id') + 'Uploader').startFileUpload(singleFileID, true);
} else {
document.getElementById($(event.target).attr('id') + 'Uploader').startFileUpload(null, true);
}
}, "json");
});
$(this).bind("rfuCancel", {'action': settings.onCancel}, function(event, queueID, fileObj, data) {
if (event.data.action(event, queueID, fileObj, data) !== false) {
$("#" + $(this).attr('id') + queueID).fadeOut(250, function() { $("#" + $(this).attr('id') + queueID).remove()});
}
});
$(this).bind("rfuClearQueue", {'action': settings.onClearQueue}, function() {
if (event.data.action() !== false) {
$('#' + $(this).attr('id') + 'Queue').contents().fadeOut(250, function() {$('#' + $(this).attr('id') + 'Queue').empty()});
}
});
$(this).bind("rfuError", {'action': settings.onError}, function(event, queueID, fileObj, errorObj) {
if (event.data.action(event, queueID, fileObj, errorObj) !== false) {
$("#" + $(this).attr('id') + queueID + " .fileName").text(errorObj.type + " Error - " + fileObj.name);
$("#" + $(this).attr('id') + queueID).css({'border': '3px solid #FBCBBC', 'background-color': '#FDE5DD'});
}
});
$(this).bind("rfuProgress", {'action': settings.onProgress, 'toDisplay': settings.displayData}, function(event, queueID, fileObj, data) {
if (event.data.action(event, queueID, fileObj, data) !== false) {
$("#" + $(this).attr('id') + queueID + "ProgressBar").css('width', data.percentage + '%');
if (event.data.toDisplay == 'percentage') displayData = ' - ' + data.percentage + '%';
if (event.data.toDisplay == 'speed') displayData = ' - ' + data.speed + 'KB/s';
if (event.data.toDisplay == null) displayData = ' ';
$("#" + $(this).attr('id') + queueID + " .percentage").text(displayData);
}
});
$(this).bind("rfuComplete", {'action': settings.onComplete}, function(event, queueID, fileObj, response, data) {
if (event.data.action(event, queueID, fileObj, unescape(response), data) !== false) {
$("#" + $(this).attr('id') + queueID).fadeOut(250, function() { $("#" + $(this).attr('id') + queueID).remove()});
$("#" + $(this).attr('id') + queueID + " .percentage").text(' - Completed');
}
});
if (typeof(settings.onAllComplete) == 'function') {
$(this).bind("rfuAllComplete", settings.onAllComplete);
}
});
}
},
fileUploadSettings:function(settingName, settingValue) {
$(this).each(function() {
document.getElementById($(this).attr('id') + 'Uploader').updateSettings(settingName,settingValue);
});
},
fileUploadStart:function(queueID) {
$(this).each(function() {
document.getElementById($(this).attr('id') + 'Uploader').startFileUpload(queueID, false);
});
},
fileUploadCancel:function(queueID) {
$(this).each(function() {
document.getElementById($(this).attr('id') + 'Uploader').cancelFileUpload(queueID);
});
},
fileUploadClearQueue:function() {
$(this).each(function() {
document.getElementById($(this).attr('id') + 'Uploader').clearFileUploadQueue();
});
}
})
})(jQuery);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,37 @@
<?php
/*
Copyright (c) 2009 Ronnie Garcia, Travis Nickels
This file is part of Uploadify v1.6.2
Permission is hereby granted, free of charge, to any person obtaining a copy
of Uploadify 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.
UPLOADIFY 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.
*/
if (!empty($_FILES)) {
$tempFile = $_FILES['Filedata']['tmp_name'];
$targetPath = $_SERVER['DOCUMENT_ROOT'] . $_GET['folder'] . '/';
$targetFile = str_replace('//','/',$targetPath) . $_FILES['Filedata']['name'];
// Uncomment the following line if you want to make the directory if it doesn't exist
// mkdir(str_replace('//','/',$targetPath), 0755, true);
move_uploaded_file($tempFile,$targetFile);
}
echo "1";
?>

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,47 @@
/*
Copyright (c) 2009 Ronnie Garcia, Travis Nickels
This file is part of Uploadify v1.6.2
Permission is hereby granted, free of charge, to any person obtaining a copy
of Uploadify 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.
UPLOADIFY 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.
*/
.fileUploadQueueItem {
font: 11px Verdana, Geneva, sans-serif;
background-color: #F5F5F5;
border: 3px solid #E5E5E5;
margin-top: 5px;
padding: 10px;
width: 300px;
}
.fileUploadQueueItem .cancel {
float: right;
}
.fileUploadProgress {
background-color: #FFFFFF;
border-top: 1px solid #808080;
border-left: 1px solid #808080;
border-right: 1px solid #C5C5C5;
border-bottom: 1px solid #C5C5C5;
margin-top: 10px;
width: 100%;
}
.fileUploadProgressBar {
background-color: #0099FF;
}

View file

@ -0,0 +1,283 @@
* SWFUpload Core, January 2009, www.swfupload.org, swfupload.googlecode.com
* --------- Version 2.2.0.1-----------
* - Removed requeueUpload due to bugs/poor testing
* = Fixed namespace conflict that broke stopUpload
* --------- Version 2.2.0-----------
* + Added button_placeholder setting that accepts a DOM element.
* + Added ability to requeue any file (including some improvement to internal queue state tracking)
* + UploadErrors caused by a missing upload_url now causes the file to be requeued automatically
* + Added preserve_relative_urls setting
* + SWFUpload now converts relative URLs to absolute URLs to avoid issues with Flash Player interpreting it differently on some clients
* + Added assume_success_timeout setting which allows uploadSuccess to be called after a timeout if, for some reason Flash ignores the server's response
* An additional parameter has been added to the uploadSuccess event to indicate whether a response was received or success was assumed.
* --------- Version 2.2.0 Beta 2 ~ 5-----------
* = Fixed a Queue Limit bug
* + Improved internal event handling code so uploadSuccess fires even when not content is returned from the server (*woot*, except for Macs)
* = Fixed issues in Destroy
* = Fixed issues with Queue Plugin
* + Added periodic checks of the ExternalInterface
* + Improved IE memory leak prevention code
* + Added Speed Plugin
* = Updated Queue Plugin for better multi-plugin compatibility
* --------- Version 2.2.0 Beta 1-----------
* + Added Flash Player 10 Support
* = Added setting for defining a button image
* = Added setting for defining button text
* = Added setting for defining button width, height and padding
* = Added setting for defining what element the Flash Movie should replace
* = Added setting for defining flash wmode
* = Added setting for defining the mouse cursor
* + Added prevent_swf_caching setting as a work-around for issues in Avant Browser (and other IE based browser)
* + Added setting for accepting HTTP Status codes other than 200 as successful
* + Added parameter to cancelUpload that allows the uploadError event for cancelled uploads to be supressed
* + Added pro-active memory leak fix for IE and fixed problems with the destroy function (credits to steffen for patches and testing)
* + Replaced callFlash with CallFunction (using the internal function that Flash uses). Based on code from MooTools.
* = Fixed bug in the Queue plugin that breaks startUpload when passing a file id.
* + Updated Queue plugin to stop the queue if false is returned from the uploadStart handler.
* = Fixed small issues in SWFObject plugin
* = Fixed issue with ExternalInterface string escaping
* - Dropped Graceful Degradation Plugin
* - Dropped v1.0.2 Plugin
* - Dropped Flash Player 8 support
* --------- Version 2.1.0 -----------
* = Fixed GET values so they are escaped properly
* + Added destroy function
* = Added exception handling around browse() calls
* = Minor code cleanup
* + Split Core and Demos
* --------- Version 2.1.0 Beta 2-----------
* = Fixed bug in XHTML fix where it wasn't split correctly by Flash
* = Fixed file params "undefined" in debug output
* + Added requeue_on_error settings so HTTP/IO/Security errors requeue the file instead of discarding it.
This will affect the queue plugin (if an error is occurring the file will be reuploaded and reuploaded).
* = Fixed HTTP/IO error behavior. We'll see how this goes Flash 9 is supposed to call HTTPError followed by an IO error but I suspect they come out of orde sometimes.
* = Fixed invalid characters in file param names. Worked around flash bug by escaping the names. Should be transparent to devs.
* = Fixed missing upload URL logic so it fires consistently
* = Fixed file params not being sent when useQueryString is true
* + Added SWFObject plugin and demo.
* + Added CookieBug demo to demonstrate what they bug really is all about.
* + Added VB.Net version of the Application Demo
* --------- Version 2.1.0 Beta 1-----------
* + Added allowScriptAccess="always" to the embed/object elements so the SWF can be served from different domains.
* = Fixed a type-o in the debug output that prevented the instance id (movieName) from displaying. - Thx Joel
* + Rewrote SWFUpload.js for better code reuse based on sample code from batiste.bieler (thanks!!!)
* + Added queueComplete event to the Queue Plugin
* + Added Simple Upload demo
* = JSLinted all the JavaScript code
* + Added use_query_string setting (and setUseQueryString function) that forces post_param and file_param values to be sent on the query_string instead of the post (for Flash 9 version)
* = Fixed file.type and date properties so a default value is provided (rather than null) when no value is provided by flash.
* = Fixed misc bugs in the demos
* = Fixed ExternalInterface calls being made available for Flash 9 versions <9.0.28 which aren't supported
* + Fixed use of & producing invalid XHTML in the <object> and <embed> tags.
* - Removed the use of the embed tag (using the <object> sample from the Flash Satay method)
* = Updated plugins to work with code rewrite changes.
* = Extracted FileProgress object in to its own file.
* + Added addPostParam and removePostParam functions
* --------- Version 2.0.2 -----------
* = Fixed a bug where post params could not be added to the current file (because it is removed from the queue when it becomes current)
* = Fixed a conversion error when converting kilobytes to bytes in the file size check
* = Fixed a problem in the documentation that said the file_size_limit was bytes when it is actually kilobytes
* + Added formatting to the documentation, a table of contents, and details for each setting .
* + Added units for file_size_limit setting. The setting understands B, KB, MB, GB. Default is KB.
* + Added a check for the ExternalInterface functions in flashReady so SWFUpload will not fire the loaded event if those are not available.
* --------- Version 2.0.1 -----------
* = Fixed a bug where zero-byte files would stop file the queuing process.
* = Finished updating Features Demo
* + Added GetFileByIndex(i) that gets a JavaScript File Object. The index never changes. Finished files continue to be available.
* The JavaScript GetFile function will accept a file_id or an index.
* + Added CheckFileSize constants to replace the magic numbers
* + Added some code in an attempt to fix "Script is running slowly" error messages
* = Better cleanup of FileReference objects
* --------- Version 2.0 -----------
* + Re-created SWFUpload in Actionscript v2 for Flash 8 compatibility. Flash 8 loses POST and Server Data features. The two versions are otherwise fully compatible.
* Flash 8 uses URL to pass post_params/file_params.
* = Changed uploadStart event so it's part of the setTimeout/eventQueue workaround. This allows Flash functions to be called from uploadStart.
* = Renamed uploadComplete to uploadSuccess and fileComplete to uploadComplete. All started uploads call uploadComplete (even if cancelled or stopped).
* = Changed startUpload validation failure behavior. Rather than cancelling the upload the file is now requeued. Devs can cancel
* or do whatever the need to in uploadError to handle the problem.
* = Fixed fileQueueLimit/fileUploadLimit logic so it works correctly.
* = Moved the upload request building to a later point so that the post params and file params can be updated in uploadStart.
* - Removed the last of the UI stuff (ui_container, degraded_container).
* + Started development on Plug-ins. Graceful Degradation, v1.0.2, Cookies, Queue Handling
* = Fixed missing file_status field in FileItem.
* + Added modificationDate to FileItem (file object)
* + Added setStats function that lets you change the file upload count, etc. This will give more power over the queue limits. Not well tested.
* = Renamed compeleted_uploads to successful_uploads in getStats object
* + Added in_progress to getStats object
* --------- Revision 7.0 beta 3 -----------
* + Added an "event queue". Events are added to an array and executeEvent is called on a setTimeout. This prevents out of order issues that occur
* in the Safari browser.
* + Added a check for the UPLOAD_COMPLETE_DATA event constant which only became available in Flash Player 9.0.28. This
* fixes the Flash Version detection (Flash Object Detection) which was accepting Flash Player 9 versions before 9.0.28.
* - Removed old code block that was missed when moving from a Flash Timer to the JavaScript timeout (caused certain cancel events to be called twice)
* = Change ShowUI to the swfUploadLoaded event which will hopefully make it more clear that this is an overrideable event
* = Changed flashReady to behave like the other events (uses setTimeout and the Event Queue).
* --------- Revision 7.0 beta 2 -----------
* = Changed ERROR_CODE_FILE_NOT_FOUND to ERROR_CODE_FILE_ID_NOT_FOUND
* + Grouped the error code constants in objects for queue errors and upload errors.
* + Added an UPLOAD_STOPPED error code.
* = Changed Event calling method (using Timer) in Flash. Timer is no longer called
* instead setTimeout is called in JavaScript. This includes a change to the
* JavaSCript design so the Event methods are not directly overridden but stored
* internally and called if defined (with a setTimeout). This is an effort
* be more compatible with the current Flash Player on Linux
* = Changed the parameter order for the fileQueueError and uploadError events so the fileObj is first, like other events.
* + Added an empty JavaScript object (customSettings) where users can store settings associated with the instance.
* + Worked around an escaping bug in the ExternalInterface library by escaping all backslashes in out-going strings.
* = Updated all the demos.
* --------- Revision 7.0 beta 1 -----------
* = Redesigned the Event Chain
* - Removed much of the queue concepts
* - Removed the fileValidation events. This can be done in the new uploadStart event
* - Removed beginUploadOnQueue feature. This can be done in the new dialogComplete event.
* - Removed use_server_data. This is now always on.
* + Added functions for retrieving queue stats (number of files uploaded, queued, errors, etc)
* + Added a file status property to the FileObject. This indicates, uploaded, error, waiting.
* + Added a single file browser (user cannot select multiple files)
* + Fixed bug (hopefully) caused if Flash call to JavaScript and in the callback JavaSCript calls to Flash
* This only place this does not apply is to uploadStart. If you call in to Flash from uploadStart use a setTimeout to do it.
* --------- Revision 6.2 -----------
* + Added API calls for changing all the changeable settings dynamically
* = Fixed a bug in FileComplete event handler (in the SWF) that caused an error in Debug Players
* and prevent the event from being called
* + Added a setting (use_server_data_event) to indicate whether FileComplete or ServerData should be called.
* The SWFUpload architecture requires that only one file upload success event can be called.
* = Updated all the Demos, especially the Features Demo and the Forms Demo
* --------- Revision 6 -----------
* - Removed the call to setUploadSettings in flashReady. This was a left over call that is unnecessary.
* + Finished the parsing of post params during the init stage. This ommision was hidden by the call to setUploadSettings.
* - Removed the flash_target_id setting. The Flash file should only ever be added to the body tag.
* + Fixed (hopefully for good) another SWF race condition. IE executes the SWF very very early. The this.movieElement value should never be referenced.
* The movie Element should always be retrieved using this.getMovieElement().
* --------- Revision 6 -----------
* + Ported to ActionScript 3. Revision 6 requires Flash Player 9.
* = Fixed bug caused when cancelling single files. Would break any function that searched for a file_id.
* - Removed the automatic cookie sending setting. Devs should just pass the value they want to send in the post_params
* - Removed the query params settings (global and file specific). All params should be sent in the post_params
* + Added post_params which adds post values to the file upload post.
* + Added validate_files setting flag which causes the fileValidation event to be called before each file is uploaded.
* + Added fileValidation event. Return false if validation fails and true if validation is successful.
* + Added server_data parameter to the fileComplete event which returns any text that the upload script returns.
* = Updated all demos to work with Revision 6
* + Added in-code file extension validation. Before a file is queued the extension is checked against the valid extensions.
* Files the have invalid extensions cause the error event to be raised.
* + Added 'file_post_name' setting that allows the post variable name containing the file data to be named something other than 'Filedata'
* = Fixed a race condition in loadFlash where a cached flash movie would execute before this.movieElement could be assigned and loading would fail.
* --------- Revision 5.2 -----------
* = A little more code cleaning and variable renaming
* + Changed from an array queue to a FIFO queue. This eliminates the "current_index" and
* should reduce some memory usage.
* + Added out of order file uploading. Call StartUpload(/file_id/).
* + Added custom query_string parameters in addition to the cookies
* + Added the ability to modify the URL, cookies, params and send to flash
* + Added per file query_string params
* + Added files queued limit. Sometimes you may want the user to only queue one file at a time (or something)
* + Fixed limits so a zero(0) value means unlimited.
* --------- Revision 5 -------------
* = More code cleaning. Ported SWF to FlashDevelop. (Since my Flash Studio trial expired)
* The port to FlashDevelop is a big deal. It significantly changes the code structure
* and could introduce bugs. Also there have been reported issues with the FlashDevelop
* version from swfupload.mammon.se: Doesn't start when reloading in IE. Doesn't start
* in Firefox if the SWF file is visible because of a page scroll.
* + I fixed the Firefox issue by removing the wmode attribute from the embed object.
* + I cannot reproduce the IE issue on my local machine (although I can reproduce it at swfupload.mammon.se)
* + Event Handlers are now attached to the SWFUpload javascript object. The SWF file
* now calls the handlers in the context of the SWFUpload object which means the "this"
* object inside the handler refers to the proper SWFUpload instance.
* + Tested and Fixed upload target cookie attachment
* = Cleaned up / renamed everything for clarity and consistancy
* + File queuing is now subject to the upload limit. If the user attempts to queue more files
* than allowed an error is returned and the files are not queued.
* + Fixed misc bugs and text encodings.
* + Added more debug info for the SWF file.
* + SWF file now obeys the debug setting.
* + Added SetUploadTargetURL function that allows you to "dynamically" change the upload target
* + Added error code for zero byte file uploads which always return an IO error. The files are now rejected
* instead of being uploaded.
* --------- Revision 4 -------------
* = Cleaned up code. Added comments. Reorganized. Added more try..catches. Removed old unused methods.
* - Removed the 'create_ui' setting. The UI is now completely up to the developer.
* + Added upload_backend_cookies setting. Can set a string, or array of cookie names. These values will be
* passed as part of the upload_backend url
*
* = Changed QueueComplete event to only fire if at least one file has been successfully uploaded.
* + Added "Stop Upload" feature.
* = Revised the FLA file to clean things up, better handle errors, etc.
* = Fixed a bug where cancelling the first upload would cause the remaining uploads to fire before calling
* "startUpload". This change is in the FLA.
*
* + Fixed a bug in the upload.swf that prevented further file processing after an error is returned.
* + Added uploadLimit variable. Only complete uploads are counted. Once the limit is reached the flash
* movie will not upload any more files. (The ability to select or queue many files is not affected
* by the upload limit)
* + Added cancelQueue and cancelUpload methods.
* + Added ID property to the FileObj in the upload.swf
* + Added Upload and Queue settings
* + Added methods for generating the flash HTML and inserting it into the DOM.
* - Removed SWFObject
* + Updated the upload.swf and added the "flashReady" event. This will only call back
* for Flash 8 and above. With this we don't need a flash version detect script.
* The script initializes the Flash then waits for the Callback to init the UI.
* + Added seperate ui_target, degraded_target, create_ui settings. This allows fine control
* over what parts of the GUI the script displays and hides
*
* + Changed from a Static Class to an Instance (changed code/class structure)
* + Added "flash_version" setting. When set to zero the version check is skipped
* + Added Debug Console. The Instance class can't do document.write.
* = De-obfuscated SWFObject a bit
* - Removed standalone mode.
* + Added "ui_target" setting. When non-blank the link is added.
* + Added "flash_target" setting. When blank the flash is appended to the <body> tag
* = This fixes ASP.Net not allowing the flash to be added to the Form
* + Added error checking to the callSWF method
*
* -------- -------- -------- -------- -------- -------- -------- --------
* SWFUpload 0.7: Flash upload dialog - http://profandesign.se/swfupload/
* SWFUpload is (c) 2006 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
* -------- -------- -------- -------- -------- -------- -------- --------
* SWFUpload 0.7: Flash upload dialog - http://profandesign.se/swfupload/
*
* VERSION HISTORY
* 0.5 - First release
*
* 0.6 - 2006-11-24
* - Got rid of flash overlay
* - SWF size reduced to 840b
* - CSS-only styling of button
* - Add upload to links etc.
*
* 0.7 - 2006-11-27
* - Added filesize param and check in SWF
*
* 0.7.1 - 2006-12-01
* - Added link_mode param for standalone links
* if set to "standalone", createElement("a") won't run.
* - Added link_text param if css isn't needed.
* - Renamed cssClass to css_class for consistency
*
*/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,121 @@
package {
import flash.external.ExternalInterface;
internal class ExternalCall
{
/*public function ExternalCall()
{
}
*/
public static function Simple(callback:String):void {
ExternalInterface.call(callback);
}
public static function FileQueued(callback:String, file_object:Object):void {
ExternalInterface.call(callback, EscapeMessage(file_object));
}
public static function FileQueueError(callback:String, error_code:Number, file_object:Object, message:String):void {
ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(error_code), EscapeMessage(message));
}
public static function FileDialogComplete(callback:String, num_files_selected:Number, num_files_queued:Number, total_num_files_queued:Number):void {
ExternalInterface.call(callback, EscapeMessage(num_files_selected), EscapeMessage(num_files_queued), EscapeMessage(total_num_files_queued));
}
public static function UploadStart(callback:String, file_object:Object):void {
ExternalInterface.call(callback, EscapeMessage(file_object));
}
public static function UploadProgress(callback:String, file_object:Object, bytes_loaded:uint, bytes_total:uint):void {
ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(bytes_loaded), EscapeMessage(bytes_total));
}
public static function UploadSuccess(callback:String, file_object:Object, server_data:String, responseReceived:Boolean):void {
ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(server_data), EscapeMessage(responseReceived));
}
public static function UploadError(callback:String, error_code:Number, file_object:Object, message:String):void {
ExternalInterface.call(callback, EscapeMessage(file_object), EscapeMessage(error_code), EscapeMessage(message));
}
public static function UploadComplete(callback:String, file_object:Object):void {
ExternalInterface.call(callback, EscapeMessage(file_object));
}
public static function Debug(callback:String, message:String):void {
ExternalInterface.call(callback, EscapeMessage(message));
}
public static function Bool(callback:String):Boolean {
return ExternalInterface.call(callback);
}
/* Escapes all the backslashes which are not translated correctly in the Flash -> JavaScript Interface
*
* These functions had to be developed because the ExternalInterface has a bug that simply places the
* value a string in quotes (except for a " which is escaped) in a JavaScript string literal which
* is executed by the browser. These often results in improperly escaped string literals if your
* input string has any backslash characters. For example the string:
* "c:\Program Files\uploadtools\"
* is placed in a string literal (with quotes escaped) and becomes:
* var __flash__temp = "\"c:\Program Files\uploadtools\\"";
* This statement will cause errors when executed by the JavaScript interpreter:
* 1) The first \" is succesfully transformed to a "
* 2) \P is translated to P and the \ is lost
* 3) \u is interpreted as a unicode character and causes an error in IE
* 4) \\ is translated to \
* 5) leaving an unescaped " which causes an error
*
* I fixed this by escaping \ characters in all outgoing strings. The above escaped string becomes:
* var __flash__temp = "\"c:\\Program Files\\uploadtools\\\"";
* which contains the correct string literal.
*
* Note: The "var __flash__temp = " portion of the example is part of the ExternalInterface not part of
* my escaping routine.
*/
private static function EscapeMessage(message:*):* {
if (message is String) {
message = EscapeString(message);
}
else if (message is Array) {
message = EscapeArray(message);
}
else if (message is Object) {
message = EscapeObject(message);
}
return message;
}
private static function EscapeString(message:String):String {
var replacePattern:RegExp = /\\/g; //new RegExp("/\\/", "g");
return message.replace(replacePattern, "\\\\");
}
private static function EscapeArray(message_array:Array):Array {
var length:uint = message_array.length;
var i:uint = 0;
for (i; i < length; i++) {
message_array[i] = EscapeMessage(message_array[i]);
}
return message_array;
}
private static function EscapeObject(message_obj:Object):Object {
for (var name:String in message_obj) {
message_obj[name] = EscapeMessage(message_obj[name]);
}
return message_obj;
}
}
}

View file

@ -0,0 +1,112 @@
package {
import flash.net.FileReference;
internal class FileItem
{
private static var file_id_sequence:Number = 0; // tracks the file id sequence
private var postObject:Object;
public var file_reference:FileReference;
public var id:String;
public var index:Number = -1;
public var file_status:int = 0;
private var js_object:Object;
public static var FILE_STATUS_QUEUED:int = -1;
public static var FILE_STATUS_IN_PROGRESS:int = -2;
public static var FILE_STATUS_ERROR:int = -3;
public static var FILE_STATUS_SUCCESS:int = -4;
public static var FILE_STATUS_CANCELLED:int = -5;
public static var FILE_STATUS_NEW:int = -6; // This file status should never be sent to JavaScript
public function FileItem(file_reference:FileReference, control_id:String, index:Number)
{
this.postObject = {};
this.file_reference = file_reference;
this.id = control_id + "_" + (FileItem.file_id_sequence++);
this.file_status = FileItem.FILE_STATUS_NEW;
this.index = index;
this.js_object = {
id: this.id,
index: this.index,
post: this.GetPostObject()
};
// Cleanly attempt to retrieve the FileReference info
// this can fail and so is wrapped in try..catch
try {
this.js_object.name = this.file_reference.name;
this.js_object.size = this.file_reference.size;
this.js_object.type = this.file_reference.type || "";
this.js_object.creationdate = this.file_reference.creationDate || new Date(0);
this.js_object.modificationdate = this.file_reference.modificationDate || new Date(0);
} catch (ex:Error) {
this.file_status = FileItem.FILE_STATUS_ERROR;
}
this.js_object.filestatus = this.file_status;
}
public function AddParam(name:String, value:String):void {
this.postObject[name] = value;
}
public function RemoveParam(name:String):void {
delete this.postObject[name];
}
public function GetPostObject(escape:Boolean = false):Object {
if (escape) {
var escapedPostObject:Object = { };
for (var k:String in this.postObject) {
if (this.postObject.hasOwnProperty(k)) {
var escapedName:String = FileItem.EscapeParamName(k);
escapedPostObject[escapedName] = this.postObject[k];
}
}
return escapedPostObject;
} else {
return this.postObject;
}
}
// Create the simply file object that is passed to the browser
public function ToJavaScriptObject():Object {
this.js_object.filestatus = this.file_status;
this.js_object.post = this.GetPostObject(true);
return this.js_object;
}
public function toString():String {
return "FileItem - ID: " + this.id;
}
/*
// The purpose of this function is to escape the property names so when Flash
// passes them back to javascript they can be interpretted correctly.
// ***They have to be unescaped again by JavaScript.**
//
// This works around a bug where Flash sends objects this way:
// object.parametername = "value";
// instead of
// object["parametername"] = "value";
// This can be a problem if the parameter name has characters that are not
// allowed in JavaScript identifiers:
// object.parameter.name! = "value";
// does not work but,
// object["parameter.name!"] = "value";
// would have worked.
*/
public static function EscapeParamName(name:String):String {
name = name.replace(/[^a-z0-9_]/gi, FileItem.EscapeCharacter);
name = name.replace(/^[0-9]/, FileItem.EscapeCharacter);
return name;
}
public static function EscapeCharacter():String {
return "$" + ("0000" + arguments[0].charCodeAt(0).toString(16)).substr(-4, 4);
}
}
}

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<!-- Output SWF options -->
<output>
<movie disabled="False" />
<movie input="" />
<movie path="swfupload.swf" />
<movie fps="15" />
<movie width="300" />
<movie height="300" />
<movie version="9" />
<movie background="#FFFFFF" />
</output>
<!-- Other classes to be compiled into your SWF -->
<classpaths>
<class path="." />
</classpaths>
<!-- Build options -->
<build>
<option accessible="False" />
<option allowSourcePathOverlap="False" />
<option benchmark="False" />
<option es="False" />
<option loadConfig="" />
<option optimize="True" />
<option showActionScriptWarnings="True" />
<option showBindingWarnings="True" />
<option showDeprecationWarnings="True" />
<option showUnusedTypeSelectorWarnings="True" />
<option strict="True" />
<option useNetwork="True" />
<option useResourceBundleMetadata="True" />
<option warnings="True" />
<option verboseStackTraces="False" />
<option additional="" />
<option customSDK="" />
</build>
<!-- SWC Include Libraries -->
<includeLibraries>
<!-- example: <element path="..." /> -->
</includeLibraries>
<!-- SWC Libraries -->
<libraryPaths>
<!-- example: <element path="..." /> -->
</libraryPaths>
<!-- External Libraries -->
<externalLibraryPaths>
<!-- example: <element path="..." /> -->
</externalLibraryPaths>
<!-- Runtime Shared Libraries -->
<rslPaths>
<!-- example: <element path="..." /> -->
</rslPaths>
<!-- Intrinsic Libraries -->
<intrinsics>
<!-- example: <element path="..." /> -->
</intrinsics>
<!-- Assets to embed into the output SWF -->
<library>
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
</library>
<!-- Class files to compile (other referenced classes will automatically be included) -->
<compileTargets>
<compile path="SWFUpload.as" />
</compileTargets>
<!-- Paths to exclude from the Project Explorer tree -->
<hiddenPaths>
<!-- example: <hidden path="..." /> -->
</hiddenPaths>
<!-- Executed before build -->
<preBuildCommand />
<!-- Executed after build -->
<postBuildCommand alwaysRun="True">deploy.bat</postBuildCommand>
<!-- Other project options -->
<options>
<option showHiddenPaths="False" />
<option testMovie="NewWindow" />
</options>
</project>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
@echo off
copy ..\swfupload.js ..\..\samples\demos\swfupload
copy swfupload.swf ..\..\samples\demos\swfupload

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Flex compiler config for project SWFUpload-v2 generated by FDBuild-->
<!--============-->
<!--This file was generated by a tool.-->
<!--Any modifications you make may be lost.-->
<flex-config>
<compiler>
<source-path append="true">
<path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash</path-element>
<path-element>C:\Program Files (x86)\FlashDevelop\Library\AS3\classes</path-element>
</source-path>
</compiler>
<file-specs>
<path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash\SWFUpload.as</path-element>
</file-specs>
<default-background-color>#FFFFFF</default-background-color>
<default-frame-rate>15</default-frame-rate>
<default-size>
<width>300</width>
<height>300</height>
</default-size>
</flex-config>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Flex compiler config for project SWFUpload-v2 generated by FDBuild-->
<!--============-->
<!--This file was generated by a tool.-->
<!--Any modifications you make may be lost.-->
<flex-config>
<compiler>
<source-path append="true">
<path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash</path-element>
<path-element>C:\Program Files (x86)\FlashDevelop\Library\AS3\classes</path-element>
</source-path>
</compiler>
<file-specs>
<path-element>C:\inetpub\wwwroot\other\swfupload\core\Flash\SWFUpload.as</path-element>
</file-specs>
<default-background-color>#FFFFFF</default-background-color>
<default-frame-rate>15</default-frame-rate>
<default-size>
<width>300</width>
<height>300</height>
</default-size>
</flex-config>

Binary file not shown.

View file

@ -0,0 +1,4 @@
/* SWFObject v2.0 rc4 <http://code.google.com/p/swfobject/>
Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/

View file

@ -0,0 +1,53 @@
/*
Cookie Plug-in
This plug in automatically gets all the cookies for this site and adds them to the post_params.
Cookies are loaded only on initialization. The refreshCookies function can be called to update the post_params.
The cookies will override any other post params with the same name.
*/
var SWFUpload;
if (typeof(SWFUpload) === "function") {
SWFUpload.prototype.initSettings = function (oldInitSettings) {
return function () {
if (typeof(oldInitSettings) === "function") {
oldInitSettings.call(this);
}
this.refreshCookies(false); // The false parameter must be sent since SWFUpload has not initialzed at this point
};
}(SWFUpload.prototype.initSettings);
// refreshes the post_params and updates SWFUpload. The sendToFlash parameters is optional and defaults to True
SWFUpload.prototype.refreshCookies = function (sendToFlash) {
if (sendToFlash === undefined) {
sendToFlash = true;
}
sendToFlash = !!sendToFlash;
// Get the post_params object
var postParams = this.settings.post_params;
// Get the cookies
var i, cookieArray = document.cookie.split(';'), caLength = cookieArray.length, c, eqIndex, name, value;
for (i = 0; i < caLength; i++) {
c = cookieArray[i];
// Left Trim spaces
while (c.charAt(0) === " ") {
c = c.substring(1, c.length);
}
eqIndex = c.indexOf("=");
if (eqIndex > 0) {
name = c.substring(0, eqIndex);
value = c.substring(eqIndex + 1);
postParams[name] = value;
}
}
if (sendToFlash) {
this.setPostParams(postParams);
}
};
}

View file

@ -0,0 +1,98 @@
/*
Queue Plug-in
Features:
*Adds a cancelQueue() method for cancelling the entire queue.
*All queued files are uploaded when startUpload() is called.
*If false is returned from uploadComplete then the queue upload is stopped.
If false is not returned (strict comparison) then the queue upload is continued.
*Adds a QueueComplete event that is fired when all the queued files have finished uploading.
Set the event handler with the queue_complete_handler setting.
*/
var SWFUpload;
if (typeof(SWFUpload) === "function") {
SWFUpload.queue = {};
SWFUpload.prototype.initSettings = (function (oldInitSettings) {
return function () {
if (typeof(oldInitSettings) === "function") {
oldInitSettings.call(this);
}
this.queueSettings = {};
this.queueSettings.queue_cancelled_flag = false;
this.queueSettings.queue_upload_count = 0;
this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler;
this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler;
this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler;
this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler;
this.settings.queue_complete_handler = this.settings.queue_complete_handler || null;
};
})(SWFUpload.prototype.initSettings);
SWFUpload.prototype.startUpload = function (fileID) {
this.queueSettings.queue_cancelled_flag = false;
this.callFlash("StartUpload", [fileID]);
};
SWFUpload.prototype.cancelQueue = function () {
this.queueSettings.queue_cancelled_flag = true;
this.stopUpload();
var stats = this.getStats();
while (stats.files_queued > 0) {
this.cancelUpload();
stats = this.getStats();
}
};
SWFUpload.queue.uploadStartHandler = function (file) {
var returnValue;
if (typeof(this.queueSettings.user_upload_start_handler) === "function") {
returnValue = this.queueSettings.user_upload_start_handler.call(this, file);
}
// To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value.
returnValue = (returnValue === false) ? false : true;
this.queueSettings.queue_cancelled_flag = !returnValue;
return returnValue;
};
SWFUpload.queue.uploadCompleteHandler = function (file) {
var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler;
var continueUpload;
if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) {
this.queueSettings.queue_upload_count++;
}
if (typeof(user_upload_complete_handler) === "function") {
continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true;
} else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) {
// If the file was stopped and re-queued don't restart the upload
continueUpload = false;
} else {
continueUpload = true;
}
if (continueUpload) {
var stats = this.getStats();
if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) {
this.startUpload();
} else if (this.queueSettings.queue_cancelled_flag === false) {
this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]);
this.queueSettings.queue_upload_count = 0;
} else {
this.queueSettings.queue_cancelled_flag = false;
this.queueSettings.queue_upload_count = 0;
}
}
};
}

View file

@ -0,0 +1,342 @@
/*
Speed Plug-in
Features:
*Adds several properties to the 'file' object indicated upload speed, time left, upload time, etc.
- currentSpeed -- String indicating the upload speed, bytes per second
- averageSpeed -- Overall average upload speed, bytes per second
- movingAverageSpeed -- Speed over averaged over the last several measurements, bytes per second
- timeRemaining -- Estimated remaining upload time in seconds
- timeElapsed -- Number of seconds passed for this upload
- percentUploaded -- Percentage of the file uploaded (0 to 100)
- sizeUploaded -- Formatted size uploaded so far, bytes
*Adds setting 'moving_average_history_size' for defining the window size used to calculate the moving average speed.
*Adds several Formatting functions for formatting that values provided on the file object.
- SWFUpload.speed.formatBPS(bps) -- outputs string formatted in the best units (Gbps, Mbps, Kbps, bps)
- SWFUpload.speed.formatTime(seconds) -- outputs string formatted in the best units (x Hr y M z S)
- SWFUpload.speed.formatSize(bytes) -- outputs string formatted in the best units (w GB x MB y KB z B )
- SWFUpload.speed.formatPercent(percent) -- outputs string formatted with a percent sign (x.xx %)
- SWFUpload.speed.formatUnits(baseNumber, divisionArray, unitLabelArray, fractionalBoolean)
- Formats a number using the division array to determine how to apply the labels in the Label Array
- factionalBoolean indicates whether the number should be returned as a single fractional number with a unit (speed)
or as several numbers labeled with units (time)
*/
var SWFUpload;
if (typeof(SWFUpload) === "function") {
SWFUpload.speed = {};
SWFUpload.prototype.initSettings = (function (oldInitSettings) {
return function () {
if (typeof(oldInitSettings) === "function") {
oldInitSettings.call(this);
}
this.ensureDefault = function (settingName, defaultValue) {
this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
};
// List used to keep the speed stats for the files we are tracking
this.fileSpeedStats = {};
this.speedSettings = {};
this.ensureDefault("moving_average_history_size", "10");
this.speedSettings.user_file_queued_handler = this.settings.file_queued_handler;
this.speedSettings.user_file_queue_error_handler = this.settings.file_queue_error_handler;
this.speedSettings.user_upload_start_handler = this.settings.upload_start_handler;
this.speedSettings.user_upload_error_handler = this.settings.upload_error_handler;
this.speedSettings.user_upload_progress_handler = this.settings.upload_progress_handler;
this.speedSettings.user_upload_success_handler = this.settings.upload_success_handler;
this.speedSettings.user_upload_complete_handler = this.settings.upload_complete_handler;
this.settings.file_queued_handler = SWFUpload.speed.fileQueuedHandler;
this.settings.file_queue_error_handler = SWFUpload.speed.fileQueueErrorHandler;
this.settings.upload_start_handler = SWFUpload.speed.uploadStartHandler;
this.settings.upload_error_handler = SWFUpload.speed.uploadErrorHandler;
this.settings.upload_progress_handler = SWFUpload.speed.uploadProgressHandler;
this.settings.upload_success_handler = SWFUpload.speed.uploadSuccessHandler;
this.settings.upload_complete_handler = SWFUpload.speed.uploadCompleteHandler;
delete this.ensureDefault;
};
})(SWFUpload.prototype.initSettings);
SWFUpload.speed.fileQueuedHandler = function (file) {
if (typeof this.speedSettings.user_file_queued_handler === "function") {
file = SWFUpload.speed.extendFile(file);
return this.speedSettings.user_file_queued_handler.call(this, file);
}
};
SWFUpload.speed.fileQueueErrorHandler = function (file, errorCode, message) {
if (typeof this.speedSettings.user_file_queue_error_handler === "function") {
file = SWFUpload.speed.extendFile(file);
return this.speedSettings.user_file_queue_error_handler.call(this, file, errorCode, message);
}
};
SWFUpload.speed.uploadStartHandler = function (file) {
if (typeof this.speedSettings.user_upload_start_handler === "function") {
file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
return this.speedSettings.user_upload_start_handler.call(this, file);
}
};
SWFUpload.speed.uploadErrorHandler = function (file, errorCode, message) {
file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
SWFUpload.speed.removeTracking(file, this.fileSpeedStats);
if (typeof this.speedSettings.user_upload_error_handler === "function") {
return this.speedSettings.user_upload_error_handler.call(this, file, errorCode, message);
}
};
SWFUpload.speed.uploadProgressHandler = function (file, bytesComplete, bytesTotal) {
this.updateTracking(file, bytesComplete);
file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
if (typeof this.speedSettings.user_upload_progress_handler === "function") {
return this.speedSettings.user_upload_progress_handler.call(this, file, bytesComplete, bytesTotal);
}
};
SWFUpload.speed.uploadSuccessHandler = function (file, serverData) {
if (typeof this.speedSettings.user_upload_success_handler === "function") {
file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
return this.speedSettings.user_upload_success_handler.call(this, file, serverData);
}
};
SWFUpload.speed.uploadCompleteHandler = function (file) {
file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
SWFUpload.speed.removeTracking(file, this.fileSpeedStats);
if (typeof this.speedSettings.user_upload_complete_handler === "function") {
return this.speedSettings.user_upload_complete_handler.call(this, file);
}
};
// Private: extends the file object with the speed plugin values
SWFUpload.speed.extendFile = function (file, trackingList) {
var tracking;
if (trackingList) {
tracking = trackingList[file.id];
}
if (tracking) {
file.currentSpeed = tracking.currentSpeed;
file.averageSpeed = tracking.averageSpeed;
file.movingAverageSpeed = tracking.movingAverageSpeed;
file.timeRemaining = tracking.timeRemaining;
file.timeElapsed = tracking.timeElapsed;
file.percentUploaded = tracking.percentUploaded;
file.sizeUploaded = tracking.bytesUploaded;
} else {
file.currentSpeed = 0;
file.averageSpeed = 0;
file.movingAverageSpeed = 0;
file.timeRemaining = 0;
file.timeElapsed = 0;
file.percentUploaded = 0;
file.sizeUploaded = 0;
}
return file;
};
// Private: Updates the speed tracking object, or creates it if necessary
SWFUpload.prototype.updateTracking = function (file, bytesUploaded) {
var tracking = this.fileSpeedStats[file.id];
if (!tracking) {
this.fileSpeedStats[file.id] = tracking = {};
}
// Sanity check inputs
bytesUploaded = bytesUploaded || tracking.bytesUploaded || 0;
if (bytesUploaded < 0) {
bytesUploaded = 0;
}
if (bytesUploaded > file.size) {
bytesUploaded = file.size;
}
var tickTime = (new Date()).getTime();
if (!tracking.startTime) {
tracking.startTime = (new Date()).getTime();
tracking.lastTime = tracking.startTime;
tracking.currentSpeed = 0;
tracking.averageSpeed = 0;
tracking.movingAverageSpeed = 0;
tracking.movingAverageHistory = [];
tracking.timeRemaining = 0;
tracking.timeElapsed = 0;
tracking.percentUploaded = bytesUploaded / file.size;
tracking.bytesUploaded = bytesUploaded;
} else if (tracking.startTime > tickTime) {
this.debug("When backwards in time");
} else {
// Get time and deltas
var now = (new Date()).getTime();
var lastTime = tracking.lastTime;
var deltaTime = now - lastTime;
var deltaBytes = bytesUploaded - tracking.bytesUploaded;
if (deltaBytes === 0 || deltaTime === 0) {
return tracking;
}
// Update tracking object
tracking.lastTime = now;
tracking.bytesUploaded = bytesUploaded;
// Calculate speeds
tracking.currentSpeed = (deltaBytes * 8 ) / (deltaTime / 1000);
tracking.averageSpeed = (tracking.bytesUploaded * 8) / ((now - tracking.startTime) / 1000);
// Calculate moving average
tracking.movingAverageHistory.push(tracking.currentSpeed);
if (tracking.movingAverageHistory.length > this.settings.moving_average_history_size) {
tracking.movingAverageHistory.shift();
}
tracking.movingAverageSpeed = SWFUpload.speed.calculateMovingAverage(tracking.movingAverageHistory);
// Update times
tracking.timeRemaining = (file.size - tracking.bytesUploaded) * 8 / tracking.movingAverageSpeed;
tracking.timeElapsed = (now - tracking.startTime) / 1000;
// Update percent
tracking.percentUploaded = (tracking.bytesUploaded / file.size * 100);
}
return tracking;
};
SWFUpload.speed.removeTracking = function (file, trackingList) {
try {
trackingList[file.id] = null;
delete trackingList[file.id];
} catch (ex) {
}
};
SWFUpload.speed.formatUnits = function (baseNumber, unitDivisors, unitLabels, singleFractional) {
var i, unit, unitDivisor, unitLabel;
if (baseNumber === 0) {
return "0 " + unitLabels[unitLabels.length - 1];
}
if (singleFractional) {
unit = baseNumber;
unitLabel = unitLabels.length >= unitDivisors.length ? unitLabels[unitDivisors.length - 1] : "";
for (i = 0; i < unitDivisors.length; i++) {
if (baseNumber >= unitDivisors[i]) {
unit = (baseNumber / unitDivisors[i]).toFixed(2);
unitLabel = unitLabels.length >= i ? " " + unitLabels[i] : "";
break;
}
}
return unit + unitLabel;
} else {
var formattedStrings = [];
var remainder = baseNumber;
for (i = 0; i < unitDivisors.length; i++) {
unitDivisor = unitDivisors[i];
unitLabel = unitLabels.length > i ? " " + unitLabels[i] : "";
unit = remainder / unitDivisor;
if (i < unitDivisors.length -1) {
unit = Math.floor(unit);
} else {
unit = unit.toFixed(2);
}
if (unit > 0) {
remainder = remainder % unitDivisor;
formattedStrings.push(unit + unitLabel);
}
}
return formattedStrings.join(" ");
}
};
SWFUpload.speed.formatBPS = function (baseNumber) {
var bpsUnits = [1073741824, 1048576, 1024, 1], bpsUnitLabels = ["Gbps", "Mbps", "Kbps", "bps"];
return SWFUpload.speed.formatUnits(baseNumber, bpsUnits, bpsUnitLabels, true);
};
SWFUpload.speed.formatTime = function (baseNumber) {
var timeUnits = [86400, 3600, 60, 1], timeUnitLabels = ["d", "h", "m", "s"];
return SWFUpload.speed.formatUnits(baseNumber, timeUnits, timeUnitLabels, false);
};
SWFUpload.speed.formatBytes = function (baseNumber) {
var sizeUnits = [1073741824, 1048576, 1024, 1], sizeUnitLabels = ["GB", "MB", "KB", "bytes"];
return SWFUpload.speed.formatUnits(baseNumber, sizeUnits, sizeUnitLabels, true);
};
SWFUpload.speed.formatPercent = function (baseNumber) {
return baseNumber.toFixed(2) + " %";
};
SWFUpload.speed.calculateMovingAverage = function (history) {
var vals = [], size, sum = 0.0, mean = 0.0, varianceTemp = 0.0, variance = 0.0, standardDev = 0.0;
var i;
var mSum = 0, mCount = 0;
size = history.length;
// Check for sufficient data
if (size >= 8) {
// Clone the array and Calculate sum of the values
for (i = 0; i < size; i++) {
vals[i] = history[i];
sum += vals[i];
}
mean = sum / size;
// Calculate variance for the set
for (i = 0; i < size; i++) {
varianceTemp += Math.pow((vals[i] - mean), 2);
}
variance = varianceTemp / size;
standardDev = Math.sqrt(variance);
//Standardize the Data
for (i = 0; i < size; i++) {
vals[i] = (vals[i] - mean) / standardDev;
}
// Calculate the average excluding outliers
var deviationRange = 2.0;
for (i = 0; i < size; i++) {
if (vals[i] <= deviationRange && vals[i] >= -deviationRange) {
mCount++;
mSum += history[i];
}
}
} else {
// Calculate the average (not enough data points to remove outliers)
mCount = size;
for (i = 0; i < size; i++) {
mSum += history[i];
}
}
return mSum / mCount;
};
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
/**
* SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
*
* mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
*
* SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
*/

View file

@ -0,0 +1,980 @@
/**
* SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
*
* mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
*
* SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
*/
/* ******************* */
/* Constructor & Init */
/* ******************* */
var SWFUpload;
if (SWFUpload == undefined) {
SWFUpload = function (settings) {
this.initSWFUpload(settings);
};
}
SWFUpload.prototype.initSWFUpload = function (settings) {
try {
this.customSettings = {}; // A container where developers can place their own settings associated with this instance.
this.settings = settings;
this.eventQueue = [];
this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
this.movieElement = null;
// Setup global control tracking
SWFUpload.instances[this.movieName] = this;
// Load the settings. Load the Flash movie.
this.initSettings();
this.loadFlash();
this.displayDebugInfo();
} catch (ex) {
delete SWFUpload.instances[this.movieName];
throw ex;
}
};
/* *************** */
/* Static Members */
/* *************** */
SWFUpload.instances = {};
SWFUpload.movieCount = 0;
SWFUpload.version = "2.2.0 2009-03-25";
SWFUpload.QUEUE_ERROR = {
QUEUE_LIMIT_EXCEEDED : -100,
FILE_EXCEEDS_SIZE_LIMIT : -110,
ZERO_BYTE_FILE : -120,
INVALID_FILETYPE : -130
};
SWFUpload.UPLOAD_ERROR = {
HTTP_ERROR : -200,
MISSING_UPLOAD_URL : -210,
IO_ERROR : -220,
SECURITY_ERROR : -230,
UPLOAD_LIMIT_EXCEEDED : -240,
UPLOAD_FAILED : -250,
SPECIFIED_FILE_ID_NOT_FOUND : -260,
FILE_VALIDATION_FAILED : -270,
FILE_CANCELLED : -280,
UPLOAD_STOPPED : -290
};
SWFUpload.FILE_STATUS = {
QUEUED : -1,
IN_PROGRESS : -2,
ERROR : -3,
COMPLETE : -4,
CANCELLED : -5
};
SWFUpload.BUTTON_ACTION = {
SELECT_FILE : -100,
SELECT_FILES : -110,
START_UPLOAD : -120
};
SWFUpload.CURSOR = {
ARROW : -1,
HAND : -2
};
SWFUpload.WINDOW_MODE = {
WINDOW : "window",
TRANSPARENT : "transparent",
OPAQUE : "opaque"
};
// Private: takes a URL, determines if it is relative and converts to an absolute URL
// using the current site. Only processes the URL if it can, otherwise returns the URL untouched
SWFUpload.completeURL = function(url) {
if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) {
return url;
}
var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
var indexSlash = window.location.pathname.lastIndexOf("/");
if (indexSlash <= 0) {
path = "/";
} else {
path = window.location.pathname.substr(0, indexSlash) + "/";
}
return /*currentURL +*/ path + url;
};
/* ******************** */
/* Instance Members */
/* ******************** */
// Private: initSettings ensures that all the
// settings are set, getting a default value if one was not assigned.
SWFUpload.prototype.initSettings = function () {
this.ensureDefault = function (settingName, defaultValue) {
this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
};
// Upload backend settings
this.ensureDefault("upload_url", "");
this.ensureDefault("preserve_relative_urls", false);
this.ensureDefault("file_post_name", "Filedata");
this.ensureDefault("post_params", {});
this.ensureDefault("use_query_string", false);
this.ensureDefault("requeue_on_error", false);
this.ensureDefault("http_success", []);
this.ensureDefault("assume_success_timeout", 0);
// File Settings
this.ensureDefault("file_types", "*.*");
this.ensureDefault("file_types_description", "All Files");
this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited"
this.ensureDefault("file_upload_limit", 0);
this.ensureDefault("file_queue_limit", 0);
// Flash Settings
this.ensureDefault("flash_url", "swfupload.swf");
this.ensureDefault("prevent_swf_caching", true);
// Button Settings
this.ensureDefault("button_image_url", "");
this.ensureDefault("button_width", 1);
this.ensureDefault("button_height", 1);
this.ensureDefault("button_text", "");
this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;");
this.ensureDefault("button_text_top_padding", 0);
this.ensureDefault("button_text_left_padding", 0);
this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
this.ensureDefault("button_disabled", false);
this.ensureDefault("button_placeholder_id", "");
this.ensureDefault("button_placeholder", null);
this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
// Debug Settings
this.ensureDefault("debug", false);
this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
// Event Handlers
this.settings.return_upload_start_handler = this.returnUploadStart;
this.ensureDefault("swfupload_loaded_handler", null);
this.ensureDefault("file_dialog_start_handler", null);
this.ensureDefault("file_queued_handler", null);
this.ensureDefault("file_queue_error_handler", null);
this.ensureDefault("file_dialog_complete_handler", null);
this.ensureDefault("upload_start_handler", null);
this.ensureDefault("upload_progress_handler", null);
this.ensureDefault("upload_error_handler", null);
this.ensureDefault("upload_success_handler", null);
this.ensureDefault("upload_complete_handler", null);
this.ensureDefault("debug_handler", this.debugMessage);
this.ensureDefault("custom_settings", {});
// Other settings
this.customSettings = this.settings.custom_settings;
// Update the flash url if needed
if (!!this.settings.prevent_swf_caching) {
this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime();
}
if (!this.settings.preserve_relative_urls) {
//this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it
this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url);
this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
}
delete this.ensureDefault;
};
// Private: loadFlash replaces the button_placeholder element with the flash movie.
SWFUpload.prototype.loadFlash = function () {
var targetElement, tempParent;
// Make sure an element with the ID we are going to use doesn't already exist
if (document.getElementById(this.movieName) !== null) {
throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
}
// Get the element where we will be placing the flash movie
targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
if (targetElement == undefined) {
throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
}
// Append the container and load the flash
tempParent = document.createElement("div");
tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
// Fix IE Flash/Form bug
if (window[this.movieName] == undefined) {
window[this.movieName] = this.getMovieElement();
}
};
// Private: getFlashHTML generates the object tag needed to embed the flash in to the document
SWFUpload.prototype.getFlashHTML = function () {
// Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
return ['<object id="', this.movieName, '" type="application/x-shockwave-flash" data="', this.settings.flash_url, '" width="', this.settings.button_width, '" height="', this.settings.button_height, '" class="swfupload">',
'<param name="wmode" value="', this.settings.button_window_mode, '" />',
'<param name="movie" value="', this.settings.flash_url, '" />',
'<param name="quality" value="high" />',
'<param name="menu" value="false" />',
'<param name="allowScriptAccess" value="always" />',
'<param name="flashvars" value="' + this.getFlashVars() + '" />',
'</object>'].join("");
};
// Private: getFlashVars builds the parameter string that will be passed
// to flash in the flashvars param.
SWFUpload.prototype.getFlashVars = function () {
// Build a string from the post param object
var paramString = this.buildParamString();
var httpSuccessString = this.settings.http_success.join(",");
// Build the parameter string
return ["movieName=", encodeURIComponent(this.movieName),
"&amp;uploadURL=", encodeURIComponent(this.settings.upload_url),
"&amp;useQueryString=", encodeURIComponent(this.settings.use_query_string),
"&amp;requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
"&amp;httpSuccess=", encodeURIComponent(httpSuccessString),
"&amp;assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
"&amp;params=", encodeURIComponent(paramString),
"&amp;filePostName=", encodeURIComponent(this.settings.file_post_name),
"&amp;fileTypes=", encodeURIComponent(this.settings.file_types),
"&amp;fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
"&amp;fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
"&amp;fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
"&amp;fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
"&amp;debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
"&amp;buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
"&amp;buttonWidth=", encodeURIComponent(this.settings.button_width),
"&amp;buttonHeight=", encodeURIComponent(this.settings.button_height),
"&amp;buttonText=", encodeURIComponent(this.settings.button_text),
"&amp;buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
"&amp;buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
"&amp;buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
"&amp;buttonAction=", encodeURIComponent(this.settings.button_action),
"&amp;buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
"&amp;buttonCursor=", encodeURIComponent(this.settings.button_cursor)
].join("");
};
// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
// The element is cached after the first lookup
SWFUpload.prototype.getMovieElement = function () {
if (this.movieElement == undefined) {
this.movieElement = document.getElementById(this.movieName);
}
if (this.movieElement === null) {
throw "Could not find Flash element";
}
return this.movieElement;
};
// Private: buildParamString takes the name/value pairs in the post_params setting object
// and joins them up in to a string formatted "name=value&amp;name=value"
SWFUpload.prototype.buildParamString = function () {
var postParams = this.settings.post_params;
var paramStringPairs = [];
if (typeof(postParams) === "object") {
for (var name in postParams) {
if (postParams.hasOwnProperty(name)) {
paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
}
}
}
return paramStringPairs.join("&amp;");
};
// Public: Used to remove a SWFUpload instance from the page. This method strives to remove
// all references to the SWF, and other objects so memory is properly freed.
// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
// Credits: Major improvements provided by steffen
SWFUpload.prototype.destroy = function () {
try {
// Make sure Flash is done before we try to remove it
this.cancelUpload(null, false);
// Remove the SWFUpload DOM nodes
var movieElement = null;
movieElement = this.getMovieElement();
if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
// Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround)
for (var i in movieElement) {
try {
if (typeof(movieElement[i]) === "function") {
movieElement[i] = null;
}
} catch (ex1) {}
}
// Remove the Movie Element from the page
try {
movieElement.parentNode.removeChild(movieElement);
} catch (ex) {}
}
// Remove IE form fix reference
window[this.movieName] = null;
// Destroy other references
SWFUpload.instances[this.movieName] = null;
delete SWFUpload.instances[this.movieName];
this.movieElement = null;
this.settings = null;
this.customSettings = null;
this.eventQueue = null;
this.movieName = null;
return true;
} catch (ex2) {
return false;
}
};
// Public: displayDebugInfo prints out settings and configuration
// information about this SWFUpload instance.
// This function (and any references to it) can be deleted when placing
// SWFUpload in production.
SWFUpload.prototype.displayDebugInfo = function () {
this.debug(
[
"---SWFUpload Instance Info---\n",
"Version: ", SWFUpload.version, "\n",
"Movie Name: ", this.movieName, "\n",
"Settings:\n",
"\t", "upload_url: ", this.settings.upload_url, "\n",
"\t", "flash_url: ", this.settings.flash_url, "\n",
"\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
"\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n",
"\t", "http_success: ", this.settings.http_success.join(", "), "\n",
"\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n",
"\t", "file_post_name: ", this.settings.file_post_name, "\n",
"\t", "post_params: ", this.settings.post_params.toString(), "\n",
"\t", "file_types: ", this.settings.file_types, "\n",
"\t", "file_types_description: ", this.settings.file_types_description, "\n",
"\t", "file_size_limit: ", this.settings.file_size_limit, "\n",
"\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n",
"\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n",
"\t", "debug: ", this.settings.debug.toString(), "\n",
"\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
"\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n",
"\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n",
"\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n",
"\t", "button_width: ", this.settings.button_width.toString(), "\n",
"\t", "button_height: ", this.settings.button_height.toString(), "\n",
"\t", "button_text: ", this.settings.button_text.toString(), "\n",
"\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n",
"\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n",
"\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n",
"\t", "button_action: ", this.settings.button_action.toString(), "\n",
"\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n",
"\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n",
"Event Handlers:\n",
"\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n",
"\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n",
"\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n",
"\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n",
"\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n",
"\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n",
"\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n",
"\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n",
"\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n",
"\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n"
].join("")
);
};
/* Note: addSetting and getSetting are no longer used by SWFUpload but are included
the maintain v2 API compatibility
*/
// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
SWFUpload.prototype.addSetting = function (name, value, default_value) {
if (value == undefined) {
return (this.settings[name] = default_value);
} else {
return (this.settings[name] = value);
}
};
// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
SWFUpload.prototype.getSetting = function (name) {
if (this.settings[name] != undefined) {
return this.settings[name];
}
return "";
};
// Private: callFlash handles function calls made to the Flash element.
// Calls are made with a setTimeout for some functions to work around
// bugs in the ExternalInterface library.
SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
argumentArray = argumentArray || [];
var movieElement = this.getMovieElement();
var returnValue, returnString;
// Flash's method if calling ExternalInterface methods (code adapted from MooTools).
try {
returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
returnValue = eval(returnString);
} catch (ex) {
throw "Call to " + functionName + " failed";
}
// Unescape file post param values
if (returnValue != undefined && typeof returnValue.post === "object") {
returnValue = this.unescapeFilePostParams(returnValue);
}
return returnValue;
};
/* *****************************
-- Flash control methods --
Your UI should use these
to operate SWFUpload
***************************** */
// WARNING: this function does not work in Flash Player 10
// Public: selectFile causes a File Selection Dialog window to appear. This
// dialog only allows 1 file to be selected.
SWFUpload.prototype.selectFile = function () {
this.callFlash("SelectFile");
};
// WARNING: this function does not work in Flash Player 10
// Public: selectFiles causes a File Selection Dialog window to appear/ This
// dialog allows the user to select any number of files
// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
// for this bug.
SWFUpload.prototype.selectFiles = function () {
this.callFlash("SelectFiles");
};
// Public: startUpload starts uploading the first file in the queue unless
// the optional parameter 'fileID' specifies the ID
SWFUpload.prototype.startUpload = function (fileID) {
this.callFlash("StartUpload", [fileID]);
};
// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index.
// If you do not specify a fileID the current uploading file or first file in the queue is cancelled.
// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter.
SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) {
if (triggerErrorEvent !== false) {
triggerErrorEvent = true;
}
this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
};
// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
// If nothing is currently uploading then nothing happens.
SWFUpload.prototype.stopUpload = function () {
this.callFlash("StopUpload");
};
/* ************************
* Settings methods
* These methods change the SWFUpload settings.
* SWFUpload settings should not be changed directly on the settings object
* since many of the settings need to be passed to Flash in order to take
* effect.
* *********************** */
// Public: getStats gets the file statistics object.
SWFUpload.prototype.getStats = function () {
return this.callFlash("GetStats");
};
// Public: setStats changes the SWFUpload statistics. You shouldn't need to
// change the statistics but you can. Changing the statistics does not
// affect SWFUpload accept for the successful_uploads count which is used
// by the upload_limit setting to determine how many files the user may upload.
SWFUpload.prototype.setStats = function (statsObject) {
this.callFlash("SetStats", [statsObject]);
};
// Public: getFile retrieves a File object by ID or Index. If the file is
// not found then 'null' is returned.
SWFUpload.prototype.getFile = function (fileID) {
if (typeof(fileID) === "number") {
return this.callFlash("GetFileByIndex", [fileID]);
} else {
return this.callFlash("GetFile", [fileID]);
}
};
// Public: addFileParam sets a name/value pair that will be posted with the
// file specified by the Files ID. If the name already exists then the
// exiting value will be overwritten.
SWFUpload.prototype.addFileParam = function (fileID, name, value) {
return this.callFlash("AddFileParam", [fileID, name, value]);
};
// Public: removeFileParam removes a previously set (by addFileParam) name/value
// pair from the specified file.
SWFUpload.prototype.removeFileParam = function (fileID, name) {
this.callFlash("RemoveFileParam", [fileID, name]);
};
// Public: setUploadUrl changes the upload_url setting.
SWFUpload.prototype.setUploadURL = function (url) {
this.settings.upload_url = url.toString();
this.callFlash("SetUploadURL", [url]);
};
// Public: setPostParams changes the post_params setting
SWFUpload.prototype.setPostParams = function (paramsObject) {
this.settings.post_params = paramsObject;
this.callFlash("SetPostParams", [paramsObject]);
};
// Public: addPostParam adds post name/value pair. Each name can have only one value.
SWFUpload.prototype.addPostParam = function (name, value) {
this.settings.post_params[name] = value;
this.callFlash("SetPostParams", [this.settings.post_params]);
};
// Public: removePostParam deletes post name/value pair.
SWFUpload.prototype.removePostParam = function (name) {
delete this.settings.post_params[name];
this.callFlash("SetPostParams", [this.settings.post_params]);
};
// Public: setFileTypes changes the file_types setting and the file_types_description setting
SWFUpload.prototype.setFileTypes = function (types, description) {
this.settings.file_types = types;
this.settings.file_types_description = description;
this.callFlash("SetFileTypes", [types, description]);
};
// Public: setFileSizeLimit changes the file_size_limit setting
SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) {
this.settings.file_size_limit = fileSizeLimit;
this.callFlash("SetFileSizeLimit", [fileSizeLimit]);
};
// Public: setFileUploadLimit changes the file_upload_limit setting
SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) {
this.settings.file_upload_limit = fileUploadLimit;
this.callFlash("SetFileUploadLimit", [fileUploadLimit]);
};
// Public: setFileQueueLimit changes the file_queue_limit setting
SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) {
this.settings.file_queue_limit = fileQueueLimit;
this.callFlash("SetFileQueueLimit", [fileQueueLimit]);
};
// Public: setFilePostName changes the file_post_name setting
SWFUpload.prototype.setFilePostName = function (filePostName) {
this.settings.file_post_name = filePostName;
this.callFlash("SetFilePostName", [filePostName]);
};
// Public: setUseQueryString changes the use_query_string setting
SWFUpload.prototype.setUseQueryString = function (useQueryString) {
this.settings.use_query_string = useQueryString;
this.callFlash("SetUseQueryString", [useQueryString]);
};
// Public: setRequeueOnError changes the requeue_on_error setting
SWFUpload.prototype.setRequeueOnError = function (requeueOnError) {
this.settings.requeue_on_error = requeueOnError;
this.callFlash("SetRequeueOnError", [requeueOnError]);
};
// Public: setHTTPSuccess changes the http_success setting
SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) {
if (typeof http_status_codes === "string") {
http_status_codes = http_status_codes.replace(" ", "").split(",");
}
this.settings.http_success = http_status_codes;
this.callFlash("SetHTTPSuccess", [http_status_codes]);
};
// Public: setHTTPSuccess changes the http_success setting
SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) {
this.settings.assume_success_timeout = timeout_seconds;
this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]);
};
// Public: setDebugEnabled changes the debug_enabled setting
SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
this.settings.debug_enabled = debugEnabled;
this.callFlash("SetDebugEnabled", [debugEnabled]);
};
// Public: setButtonImageURL loads a button image sprite
SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
if (buttonImageURL == undefined) {
buttonImageURL = "";
}
this.settings.button_image_url = buttonImageURL;
this.callFlash("SetButtonImageURL", [buttonImageURL]);
};
// Public: setButtonDimensions resizes the Flash Movie and button
SWFUpload.prototype.setButtonDimensions = function (width, height) {
this.settings.button_width = width;
this.settings.button_height = height;
var movie = this.getMovieElement();
if (movie != undefined) {
movie.style.width = width + "px";
movie.style.height = height + "px";
}
this.callFlash("SetButtonDimensions", [width, height]);
};
// Public: setButtonText Changes the text overlaid on the button
SWFUpload.prototype.setButtonText = function (html) {
this.settings.button_text = html;
this.callFlash("SetButtonText", [html]);
};
// Public: setButtonTextPadding changes the top and left padding of the text overlay
SWFUpload.prototype.setButtonTextPadding = function (left, top) {
this.settings.button_text_top_padding = top;
this.settings.button_text_left_padding = left;
this.callFlash("SetButtonTextPadding", [left, top]);
};
// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button
SWFUpload.prototype.setButtonTextStyle = function (css) {
this.settings.button_text_style = css;
this.callFlash("SetButtonTextStyle", [css]);
};
// Public: setButtonDisabled disables/enables the button
SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
this.settings.button_disabled = isDisabled;
this.callFlash("SetButtonDisabled", [isDisabled]);
};
// Public: setButtonAction sets the action that occurs when the button is clicked
SWFUpload.prototype.setButtonAction = function (buttonAction) {
this.settings.button_action = buttonAction;
this.callFlash("SetButtonAction", [buttonAction]);
};
// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button
SWFUpload.prototype.setButtonCursor = function (cursor) {
this.settings.button_cursor = cursor;
this.callFlash("SetButtonCursor", [cursor]);
};
/* *******************************
Flash Event Interfaces
These functions are used by Flash to trigger the various
events.
All these functions a Private.
Because the ExternalInterface library is buggy the event calls
are added to a queue and the queue then executed by a setTimeout.
This ensures that events are executed in a determinate order and that
the ExternalInterface bugs are avoided.
******************************* */
SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
// Warning: Don't call this.debug inside here or you'll create an infinite loop
if (argumentArray == undefined) {
argumentArray = [];
} else if (!(argumentArray instanceof Array)) {
argumentArray = [argumentArray];
}
var self = this;
if (typeof this.settings[handlerName] === "function") {
// Queue the event
this.eventQueue.push(function () {
this.settings[handlerName].apply(this, argumentArray);
});
// Execute the next queued event
setTimeout(function () {
self.executeNextEvent();
}, 0);
} else if (this.settings[handlerName] !== null) {
throw "Event handler " + handlerName + " is unknown or is not a function";
}
};
// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout
// we must queue them in order to garentee that they are executed in order.
SWFUpload.prototype.executeNextEvent = function () {
// Warning: Don't call this.debug inside here or you'll create an infinite loop
var f = this.eventQueue ? this.eventQueue.shift() : null;
if (typeof(f) === "function") {
f.apply(this);
}
};
// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have
// properties that contain characters that are not valid for JavaScript identifiers. To work around this
// the Flash Component escapes the parameter names and we must unescape again before passing them along.
SWFUpload.prototype.unescapeFilePostParams = function (file) {
var reg = /[$]([0-9a-f]{4})/i;
var unescapedPost = {};
var uk;
if (file != undefined) {
for (var k in file.post) {
if (file.post.hasOwnProperty(k)) {
uk = k;
var match;
while ((match = reg.exec(uk)) !== null) {
uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
}
unescapedPost[uk] = file.post[k];
}
}
file.post = unescapedPost;
}
return file;
};
// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working)
SWFUpload.prototype.testExternalInterface = function () {
try {
return this.callFlash("TestExternalInterface");
} catch (ex) {
return false;
}
};
// Private: This event is called by Flash when it has finished loading. Don't modify this.
// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded.
SWFUpload.prototype.flashReady = function () {
// Check that the movie element is loaded correctly with its ExternalInterface methods defined
var movieElement = this.getMovieElement();
if (!movieElement) {
this.debug("Flash called back ready but the flash movie can't be found.");
return;
}
this.cleanUp(movieElement);
this.queueEvent("swfupload_loaded_handler");
};
// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE.
// This function is called by Flash each time the ExternalInterface functions are created.
SWFUpload.prototype.cleanUp = function (movieElement) {
// Pro-actively unhook all the Flash functions
try {
if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");
for (var key in movieElement) {
try {
if (typeof(movieElement[key]) === "function") {
movieElement[key] = null;
}
} catch (ex) {
}
}
}
} catch (ex1) {
}
// Fix Flashes own cleanup code so if the SWFMovie was removed from the page
// it doesn't display errors.
window["__flash__removeCallback"] = function (instance, name) {
try {
if (instance) {
instance[name] = null;
}
} catch (flashEx) {
}
};
};
/* This is a chance to do something before the browse window opens */
SWFUpload.prototype.fileDialogStart = function () {
this.queueEvent("file_dialog_start_handler");
};
/* Called when a file is successfully added to the queue. */
SWFUpload.prototype.fileQueued = function (file) {
file = this.unescapeFilePostParams(file);
this.queueEvent("file_queued_handler", file);
};
/* Handle errors that occur when an attempt to queue a file fails. */
SWFUpload.prototype.fileQueueError = function (file, errorCode, message) {
file = this.unescapeFilePostParams(file);
this.queueEvent("file_queue_error_handler", [file, errorCode, message]);
};
/* Called after the file dialog has closed and the selected files have been queued.
You could call startUpload here if you want the queued files to begin uploading immediately. */
SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) {
this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]);
};
SWFUpload.prototype.uploadStart = function (file) {
file = this.unescapeFilePostParams(file);
this.queueEvent("return_upload_start_handler", file);
};
SWFUpload.prototype.returnUploadStart = function (file) {
var returnValue;
if (typeof this.settings.upload_start_handler === "function") {
file = this.unescapeFilePostParams(file);
returnValue = this.settings.upload_start_handler.call(this, file);
} else if (this.settings.upload_start_handler != undefined) {
throw "upload_start_handler must be a function";
}
// Convert undefined to true so if nothing is returned from the upload_start_handler it is
// interpretted as 'true'.
if (returnValue === undefined) {
returnValue = true;
}
returnValue = !!returnValue;
this.callFlash("ReturnUploadStart", [returnValue]);
};
SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
file = this.unescapeFilePostParams(file);
this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
};
SWFUpload.prototype.uploadError = function (file, errorCode, message) {
file = this.unescapeFilePostParams(file);
this.queueEvent("upload_error_handler", [file, errorCode, message]);
};
SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
file = this.unescapeFilePostParams(file);
this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
};
SWFUpload.prototype.uploadComplete = function (file) {
file = this.unescapeFilePostParams(file);
this.queueEvent("upload_complete_handler", file);
};
/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the
internal debug console. You can override this event and have messages written where you want. */
SWFUpload.prototype.debug = function (message) {
this.queueEvent("debug_handler", message);
};
/* **********************************
Debug Console
The debug console is a self contained, in page location
for debug message to be sent. The Debug Console adds
itself to the body if necessary.
The console is automatically scrolled as messages appear.
If you are using your own debug handler or when you deploy to production and
have debug disabled you can remove these functions to reduce the file size
and complexity.
********************************** */
// Private: debugMessage is the default debug_handler. If you want to print debug messages
// call the debug() function. When overriding the function your own function should
// check to see if the debug setting is true before outputting debug information.
SWFUpload.prototype.debugMessage = function (message) {
if (this.settings.debug) {
var exceptionMessage, exceptionValues = [];
// Check for an exception object and print it nicely
if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") {
for (var key in message) {
if (message.hasOwnProperty(key)) {
exceptionValues.push(key + ": " + message[key]);
}
}
exceptionMessage = exceptionValues.join("\n") || "";
exceptionValues = exceptionMessage.split("\n");
exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
SWFUpload.Console.writeLine(exceptionMessage);
} else {
SWFUpload.Console.writeLine(message);
}
}
};
SWFUpload.Console = {};
SWFUpload.Console.writeLine = function (message) {
var console, documentForm;
try {
console = document.getElementById("SWFUpload_Console");
if (!console) {
documentForm = document.createElement("form");
document.getElementsByTagName("body")[0].appendChild(documentForm);
console = document.createElement("textarea");
console.id = "SWFUpload_Console";
console.style.fontFamily = "monospace";
console.setAttribute("wrap", "off");
console.wrap = "off";
console.style.overflow = "auto";
console.style.width = "700px";
console.style.height = "350px";
console.style.margin = "5px";
documentForm.appendChild(console);
}
console.value += message + "\n";
console.scrollTop = console.scrollHeight - console.clientHeight;
} catch (ex) {
alert("Exception: " + ex.name + " Message: " + ex.message);
}
};

View file

@ -29,6 +29,15 @@
typically this element is the one that *you* will style
the most.
*/
LABEL.big {
font-weight: bold;
}
INPUT.big {
font-size: 22px;
}
#thumbstrip ul li {
float:left;
background: black;