== Getting started
-1. Run the WEBrick servlet: <tt>ruby script/server</tt> (run with --help for options)
- ...or if you have lighttpd installed: <tt>ruby script/lighttpd</tt> (it's faster)
-2. Go to http://localhost:3000/ and get "Congratulations, you've put Ruby on Rails!"
-3. Follow the guidelines on the "Congratulations, you've put Ruby on Rails!" screen
+1. Start the web server: <tt>ruby script/server</tt> (run with --help for options)
+2. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!"
+3. Follow the guidelines to start developing your application
+== Web servers
+
+Rails uses the built-in web server in Ruby called WEBrick by default, so you don't
+have to install or configure anything to play around.
+
+If you have lighttpd installed, though, it'll be used instead when running script/server.
+It's considerably faster than WEBrick and suited for production use, but requires additional
+installation and currently only works well on OS X/Unix (Windows users are encouraged
+to start with WEBrick). We recommend version 1.4.11 and higher. You can download it from
+http://www.lighttpd.net.
+
+If you want something that's halfway between WEBrick and lighttpd, we heartily recommend
+Mongrel. It's a Ruby-based web server with a C-component (so it requires compilation) that
+also works very well with Windows. See more at http://mongrel.rubyforge.org/.
+
+But of course its also possible to run Rails with the premiere open source web server Apache.
+To get decent performance, though, you'll need to install FastCGI. For Apache 1.3, you want
+to use mod_fastcgi. For Apache 2.0+, you want to use mod_fcgid.
+
+See http://wiki.rubyonrails.com/rails/pages/FastCGI for more information on FastCGI.
+
== Example for Apache conf
<VirtualHost *:80>
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>console production</tt>.
+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>
+
== Description of contents
app/helpers
Holds view helpers that should be named like weblog_helper.rb.
+app/apis
+ Holds API classes for web services.
+
config
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
components
Self-contained mini-applications that can bundle together controllers, models, and views.
+db
+ Contains the database schema in schema.rb. db/migrate contains all
+ the sequence of Migrations for your schema.
+
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.
# Add your own tasks in files placed in lib/tasks ending in .rake,
-# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake.
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require(File.join(File.dirname(__FILE__), 'config', 'boot'))
require 'rake/testtask'
require 'rake/rdoctask'
-require 'tasks/rails'
\ No newline at end of file
+require 'tasks/rails'
+# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb
+
unless defined?(RAILS_ROOT)
root_path = File.join(File.dirname(__FILE__), '..')
+
unless RUBY_PLATFORM =~ /mswin32/
require 'pathname'
root_path = Pathname.new(root_path).cleanpath(true).to_s
end
+
RAILS_ROOT = root_path
end
-if File.directory?("#{RAILS_ROOT}/vendor/rails")
- require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
-else
- require 'rubygems'
- require 'initializer'
-end
+unless defined?(Rails::Initializer)
+ if File.directory?("#{RAILS_ROOT}/vendor/rails")
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
+ else
+ require 'rubygems'
+
+ environment_without_comments = IO.readlines(File.dirname(__FILE__) + '/environment.rb').reject { |l| l =~ /^#/ }.join
+ environment_without_comments =~ /[^#]RAILS_GEM_VERSION = '([\d.]+)'/
+ rails_gem_version = $1
+
+ if version = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : rails_gem_version
+ rails_gem = Gem.cache.search('rails', "=#{version}").first
+
+ if rails_gem
+ require_gem "rails", "=#{version}"
+ require rails_gem.full_gem_path + '/lib/initializer'
+ else
+ STDERR.puts %(Cannot find gem for Rails =#{version}:
+ Install the missing gem with 'gem install -v=#{version} rails', or
+ change environment.rb to define RAILS_GEM_VERSION with your desired version.
+ )
+ exit 1
+ end
+ else
+ require_gem "rails"
+ require 'initializer'
+ end
+ end
-Rails::Initializer.run(:set_load_path)
+ Rails::Initializer.run(:set_load_path)
+end
\ No newline at end of file
# Be sure to restart your web server when you modify this file.
-# Uncomment below to force Rails into production mode
-# (Use only when you can't set environment variables through your web/app server)
+# Uncomment below to force Rails into production mode when
+# you don't control web/app server and can't set it the proper way
# ENV['RAILS_ENV'] ||= 'production'
+# Specifies gem version of Rails to use when vendor/rails is not present
+RAILS_GEM_VERSION = '1.1.6'
+
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
- # Skip frameworks you're not going to use
+ # Settings in config/environments/* take precedence those specified here
+
+ # Skip frameworks you're not going to use (only works if using vendor/rails)
# config.frameworks -= [ :action_web_service, :action_mailer ]
# Add additional load paths for your own custom dirs
# config.log_level = :debug
# Use the database for sessions instead of the file system
- # (create the session table with 'rake create_sessions_table')
+ # (create the session table with 'rake db:sessions:create')
# config.action_controller.session_store = :active_record_store
- # Enable page/fragment caching by setting a file-based store
- # (remember to create the caching directory and make it readable to the application)
- # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache"
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
- # Use Active Record's schema dumper instead of SQL when creating the test database
- # (enables use of different database adapters for development and test environments)
- # config.active_record.schema_format = :ruby
-
# See Rails::Configuration for more options
end
# end
# Include your application configuration below
-
-require 'uniq_token'
-require 'randarray'
+require 'uniq_token'
+require 'randarray'
require 'rubyvote'
+
+# Settings specified here will take precedence over those in config/environment.rb
+
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
-config.cache_classes = false
+config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
-config.whiny_nils = true
+config.whiny_nils = true
# Enable the breakpoint server that script/breakpointer connects to
config.breakpoint_server = true
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
+config.action_view.cache_template_extensions = false
+config.action_view.debug_rjs = true
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
+# Settings specified here will take precedence over those in config/environment.rb
+
# The production environment is meant for finished, "live" apps.
# Code is not reloaded between requests
config.cache_classes = true
# Use a different logger for distributed setups
-# config.logger = SyslogLogger.new
-
+# config.logger = SyslogLogger.new
# Full error reports are disabled and caching is turned on
config.action_controller.consider_all_requests_local = false
+# Settings specified here will take precedence over those in config/environment.rb
+
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
config.cache_classes = true
# Log error messages when you accidentally call methods on nil.
-config.whiny_nils = true
+config.whiny_nils = true
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
ActionController::Routing::Routes.draw do |map|
- # Add your own custom routes here.
# The priority is based upon order of creation: first created -> highest priority.
- # Here's a sample route:
+ # Sample of regular route:
# map.connect 'products/:id', :controller => 'catalog', :action => 'view'
# Keep in mind you can assign values other than :controller and :action
+ # Sample of named route:
+ # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
+ # This route can be invoked with purchase_url(:id => product.id)
+
# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
map.connect '', :controller => "site"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
- <h1>Application error (Apache)</h1>
+ <h1>Application error</h1>
<p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p>
</body>
</html>
\ No newline at end of file
--- /dev/null
+// Place your application-specific JavaScript functions and classes here
+// This file is automatically included by javascript_include_tag :defaults
show: function() {
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
- if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && (Element.getStyle(this.update, 'position')=='absolute')) {
+ if(!this.iefix &&
+ (navigator.appVersion.indexOf('MSIE')>0) &&
+ (navigator.userAgent.indexOf('Opera')<0) &&
+ (Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
return;
}
else
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
- return;
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
this.changed = true;
this.hasFocus = true;
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
},
+ activate: function() {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
onHover: function(event) {
var element = Event.findElement(event, 'LI');
if(this.index != element.autocompleteIndex)
this.options.updateElement(selectedElement);
return;
}
-
- var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+ var value = '';
+ if (this.options.select) {
+ var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
+ if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+ } else
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
var lastTokenPos = this.findLastToken();
if (lastTokenPos != -1) {
var newValue = this.element.value.substr(0, lastTokenPos + 1);
Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
initialize: function(element, update, url, options) {
- this.baseInitialize(element, update, options);
+ this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.element = $(element);
this.options = Object.extend({
+ okButton: true,
okText: "ok",
+ cancelLink: true,
cancelText: "cancel",
savingText: "Saving...",
clickToEditText: "Click to edit",
formClassName: 'inplaceeditor-form',
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
highlightendcolor: "#FFFFFF",
- externalControl: null,
- ajaxOptions: {}
+ externalControl: null,
+ submitOnBlur: false,
+ ajaxOptions: {},
+ evalScripts: false
}, options || {});
if(!this.options.formId && this.element.id) {
this.form.appendChild(br);
}
- okButton = document.createElement("input");
- okButton.type = "submit";
- okButton.value = this.options.okText;
- this.form.appendChild(okButton);
+ if (this.options.okButton) {
+ okButton = document.createElement("input");
+ okButton.type = "submit";
+ okButton.value = this.options.okText;
+ okButton.className = 'editor_ok_button';
+ this.form.appendChild(okButton);
+ }
- cancelLink = document.createElement("a");
- cancelLink.href = "#";
- cancelLink.appendChild(document.createTextNode(this.options.cancelText));
- cancelLink.onclick = this.onclickCancel.bind(this);
- this.form.appendChild(cancelLink);
+ if (this.options.cancelLink) {
+ cancelLink = document.createElement("a");
+ cancelLink.href = "#";
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
+ cancelLink.onclick = this.onclickCancel.bind(this);
+ cancelLink.className = 'editor_cancel';
+ this.form.appendChild(cancelLink);
+ }
},
hasHTMLLineBreaks: function(string) {
if (!this.options.handleLineBreaks) return false;
} else {
text = this.getText();
}
+
+ var obj = this;
if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
this.options.textarea = false;
var textField = document.createElement("input");
+ textField.obj = this;
textField.type = "text";
textField.name = "value";
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
+ textField.className = 'editor_field';
var size = this.options.size || this.options.cols || 0;
if (size != 0) textField.size = size;
+ if (this.options.submitOnBlur)
+ textField.onblur = this.onSubmit.bind(this);
this.editField = textField;
} else {
this.options.textarea = true;
var textArea = document.createElement("textarea");
+ textArea.obj = this;
textArea.name = "value";
textArea.value = this.convertHTMLLineBreaks(text);
textArea.rows = this.options.rows;
textArea.cols = this.options.cols || 40;
+ textArea.className = 'editor_field';
+ if (this.options.submitOnBlur)
+ textArea.onblur = this.onSubmit.bind(this);
this.editField = textArea;
}
// to be displayed indefinitely
this.onLoading();
- new Ajax.Updater(
- {
- success: this.element,
- // don't update on failure (this could be an option)
- failure: null
- },
- this.url,
- Object.extend({
- parameters: this.options.callback(form, value),
- onComplete: this.onComplete.bind(this),
- onFailure: this.onFailure.bind(this)
- }, this.options.ajaxOptions)
- );
+ if (this.options.evalScripts) {
+ new Ajax.Request(
+ this.url, Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this),
+ asynchronous:true,
+ evalScripts:true
+ }, this.options.ajaxOptions));
+ } else {
+ new Ajax.Updater(
+ { success: this.element,
+ // don't update on failure (this could be an option)
+ failure: null },
+ this.url, Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this)
+ }, this.options.ajaxOptions));
+ }
// stop the event to avoid a page refresh in Safari
if (arguments.length > 1) {
Event.stop(arguments[0]);
Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
}
-};
\ No newline at end of file
+};
+
+Ajax.InPlaceCollectionEditor = Class.create();
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
+ createEditField: function() {
+ if (!this.cached_selectTag) {
+ var selectTag = document.createElement("select");
+ var collection = this.options.collection || [];
+ var optionTag;
+ collection.each(function(e,i) {
+ optionTag = document.createElement("option");
+ optionTag.value = (e instanceof Array) ? e[0] : e;
+ if(this.options.value==optionTag.value) optionTag.selected = true;
+ optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
+ selectTag.appendChild(optionTag);
+ }.bind(this));
+ this.cached_selectTag = selectTag;
+ }
+
+ this.editField = this.cached_selectTag;
+ if(this.options.loadTextURL) this.loadExternalText();
+ this.form.appendChild(this.editField);
+ this.options.callback = function(form, value) {
+ return "value=" + encodeURIComponent(value);
+ }
+ }
+});
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create();
+Form.Element.DelayedObserver.prototype = {
+ initialize: function(element, delay, callback) {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function(event) {
+ if(this.lastValue == $F(this.element)) return;
+ if(this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function() {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+};
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-//
-// Element.Class part Copyright (c) 2005 by Rick Olson
+// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// See scriptaculous.js for full license.
drops: [],
remove: function(element) {
- this.drops = this.drops.reject(function(d) { return d.element==element });
+ this.drops = this.drops.reject(function(d) { return d.element==$(element) });
},
add: function(element) {
element = $(element);
var options = Object.extend({
greedy: true,
- hoverclass: null
+ hoverclass: null,
+ tree: false
}, arguments[1] || {});
// cache containers
options._containers.push($(containment));
}
}
+
+ if(options.accept) options.accept = [options.accept].flatten();
Element.makePositioned(element); // fix IE
options.element = element;
this.drops.push(options);
},
+
+ findDeepestChild: function(drops) {
+ deepest = drops[0];
+
+ for (i = 1; i < drops.length; ++i)
+ if (Element.isParent(drops[i].element, deepest.element))
+ deepest = drops[i];
+
+ return deepest;
+ },
isContained: function(element, drop) {
- var parentNode = element.parentNode;
- return drop._containers.detect(function(c) { return parentNode == c });
+ var containmentNode;
+ if(drop.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function(c) { return containmentNode == c });
},
-
- isAffected: function(pX, pY, element, drop) {
+
+ isAffected: function(point, element, drop) {
return (
(drop.element!=element) &&
((!drop._containers) ||
this.isContained(element, drop)) &&
((!drop.accept) ||
- (Element.Class.has_any(element, drop.accept))) &&
- Position.within(drop.element, pX, pY) );
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) &&
+ Position.within(drop.element, point[0], point[1]) );
},
deactivate: function(drop) {
if(drop.hoverclass)
- Element.Class.remove(drop.element, drop.hoverclass);
+ Element.removeClassName(drop.element, drop.hoverclass);
this.last_active = null;
},
activate: function(drop) {
- if(this.last_active) this.deactivate(this.last_active);
if(drop.hoverclass)
- Element.Class.add(drop.element, drop.hoverclass);
+ Element.addClassName(drop.element, drop.hoverclass);
this.last_active = drop;
},
- show: function(event, element) {
+ show: function(point, element) {
if(!this.drops.length) return;
- var pX = Event.pointerX(event);
- var pY = Event.pointerY(event);
- Position.prepare();
-
- var i = this.drops.length-1; do {
- var drop = this.drops[i];
- if(this.isAffected(pX, pY, element, drop)) {
- if(drop.onHover)
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
- if(drop.greedy) {
- this.activate(drop);
- return;
- }
- }
- } while (i--);
+ var affected = [];
if(this.last_active) this.deactivate(this.last_active);
+ this.drops.each( function(drop) {
+ if(Droppables.isAffected(point, element, drop))
+ affected.push(drop);
+ });
+
+ if(affected.length>0) {
+ drop = Droppables.findDeepestChild(affected);
+ Position.within(drop.element, point[0], point[1]);
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ Droppables.activate(drop);
+ }
},
fire: function(event, element) {
if(!this.last_active) return;
Position.prepare();
- if (this.isAffected(Event.pointerX(event), Event.pointerY(event), element, this.last_active))
+ if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
if (this.last_active.onDrop)
this.last_active.onDrop(element, this.last_active.element, event);
},
}
var Draggables = {
+ drags: [],
observers: [],
+
+ register: function(draggable) {
+ if(this.drags.length == 0) {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function(draggable) {
+ this.drags = this.drags.reject(function(d) { return d==draggable });
+ if(this.drags.length == 0) {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function(draggable) {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ },
+
+ deactivate: function() {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function(event) {
+ if(!this.activeDraggable) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+ this._lastPointer = pointer;
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function(event) {
+ if(!this.activeDraggable) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function(event) {
+ if(this.activeDraggable)
+ this.activeDraggable.keyPress(event);
+ },
+
addObserver: function(observer) {
- this.observers.push(observer);
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
},
- removeObserver: function(element) { // element instead of obsever fixes mem leaks
+
+ removeObserver: function(element) { // element instead of observer fixes mem leaks
this.observers = this.observers.reject( function(o) { return o.element==element });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
+ if(this[eventName+'Count'] > 0)
+ this.observers.each( function(o) {
+ if(o[eventName]) o[eventName](eventName, draggable, event);
+ });
},
- notify: function(eventName, draggable) { // 'onStart', 'onEnd'
- this.observers.invoke(eventName, draggable);
+
+ _cacheObserverCallbacks: function() {
+ ['onStart','onEnd','onDrag'].each( function(eventName) {
+ Draggables[eventName+'Count'] = Draggables.observers.select(
+ function(o) { return o[eventName]; }
+ ).length;
+ });
}
}
},
reverteffect: function(element, top_offset, left_offset) {
var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
- new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
+ element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
},
endeffect: function(element) {
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
},
zindex: 1000,
- revert: false
+ revert: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
}, arguments[1] || {});
- this.element = $(element);
- if(options.handle && (typeof options.handle == 'string'))
- this.handle = Element.Class.childrenWith(this.element, options.handle)[0];
-
+ this.element = $(element);
+
+ if(options.handle && (typeof options.handle == 'string')) {
+ var h = Element.childrenWithClassName(this.element, options.handle, true);
+ if(h.length>0) this.handle = h[0];
+ }
if(!this.handle) this.handle = $(options.handle);
if(!this.handle) this.handle = this.element;
+
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)
+ options.scroll = $(options.scroll);
Element.makePositioned(this.element); // fix IE
- this.offsetX = 0;
- this.offsetY = 0;
- this.originalLeft = this.currentLeft();
- this.originalTop = this.currentTop();
- this.originalX = this.element.offsetLeft;
- this.originalY = this.element.offsetTop;
-
- this.options = options;
-
- this.active = false;
- this.dragging = false;
+ this.delta = this.currentDelta();
+ this.options = options;
+ this.dragging = false;
- this.eventMouseDown = this.startDrag.bindAsEventListener(this);
- this.eventMouseUp = this.endDrag.bindAsEventListener(this);
- this.eventMouseMove = this.update.bindAsEventListener(this);
- this.eventKeypress = this.keyPress.bindAsEventListener(this);
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
- this.registerEvents();
+ Draggables.register(this);
},
+
destroy: function() {
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
- this.unregisterEvents();
- },
- registerEvents: function() {
- Event.observe(document, "mouseup", this.eventMouseUp);
- Event.observe(document, "mousemove", this.eventMouseMove);
- Event.observe(document, "keypress", this.eventKeypress);
- Event.observe(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
},
- unregisterEvents: function() {
- //if(!this.active) return;
- //Event.stopObserving(document, "mouseup", this.eventMouseUp);
- //Event.stopObserving(document, "mousemove", this.eventMouseMove);
- //Event.stopObserving(document, "keypress", this.eventKeypress);
+
+ currentDelta: function() {
+ return([
+ parseInt(Element.getStyle(this.element,'left') || '0'),
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
},
- currentLeft: function() {
- return parseInt(this.element.style.left || '0');
- },
- currentTop: function() {
- return parseInt(this.element.style.top || '0')
- },
- startDrag: function(event) {
- if(Event.isLeftClick(event)) {
-
+
+ initDrag: function(event) {
+ if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if(src.tagName && (
src.tagName=='INPUT' ||
src.tagName=='SELECT' ||
+ src.tagName=='OPTION' ||
src.tagName=='BUTTON' ||
src.tagName=='TEXTAREA')) return;
+
+ if(this.element._revert) {
+ this.element._revert.cancel();
+ this.element._revert = null;
+ }
- // this.registerEvents();
- this.active = true;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
- var offsets = Position.cumulativeOffset(this.element);
- this.offsetX = (pointer[0] - offsets[0]);
- this.offsetY = (pointer[1] - offsets[1]);
+ var pos = Position.cumulativeOffset(this.element);
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
Event.stop(event);
}
},
+
+ startDrag: function(event) {
+ this.dragging = true;
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function(event, pointer) {
+ if(!this.dragging) this.startDrag(event);
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ Draggables.notify('onDrag', this, event);
+ this.draw(pointer);
+ if(this.options.change) this.options.change(this);
+
+ if(this.options.scroll) {
+ this.stopScrolling();
+
+ var p;
+ if (this.options.scroll == window) {
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+ } else {
+ p = Position.page(this.options.scroll);
+ p[0] += this.options.scroll.scrollLeft;
+ p[1] += this.options.scroll.scrollTop;
+ p.push(p[0]+this.options.scroll.offsetWidth);
+ p.push(p[1]+this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+
+ Event.stop(event);
+ },
+
finishDrag: function(event, success) {
- // this.unregisterEvents();
-
- this.active = false;
this.dragging = false;
if(this.options.ghosting) {
}
if(success) Droppables.fire(event, this.element);
- Draggables.notify('onEnd', this);
+ Draggables.notify('onEnd', this, event);
var revert = this.options.revert;
if(revert && typeof revert == 'function') revert = revert(this.element);
-
+
+ var d = this.currentDelta();
if(revert && this.options.reverteffect) {
this.options.reverteffect(this.element,
- this.currentTop()-this.originalTop,
- this.currentLeft()-this.originalLeft);
+ d[1]-this.delta[1], d[0]-this.delta[0]);
} else {
- this.originalLeft = this.currentLeft();
- this.originalTop = this.currentTop();
+ this.delta = d;
}
if(this.options.zindex)
if(this.options.endeffect)
this.options.endeffect(this.element);
-
+ Draggables.deactivate(this);
Droppables.reset();
},
+
keyPress: function(event) {
- if(this.active) {
- if(event.keyCode==Event.KEY_ESC) {
- this.finishDrag(event, false);
- Event.stop(event);
- }
- }
+ if(event.keyCode!=Event.KEY_ESC) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
},
+
endDrag: function(event) {
- if(this.active && this.dragging) {
- this.finishDrag(event, true);
- Event.stop(event);
- }
- this.active = false;
- this.dragging = false;
+ if(!this.dragging) return;
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ Event.stop(event);
},
- draw: function(event) {
- var pointer = [Event.pointerX(event), Event.pointerY(event)];
- var offsets = Position.cumulativeOffset(this.element);
- offsets[0] -= this.currentLeft();
- offsets[1] -= this.currentTop();
+
+ draw: function(point) {
+ var pos = Position.cumulativeOffset(this.element);
+ var d = this.currentDelta();
+ pos[0] -= d[0]; pos[1] -= d[1];
+
+ if(this.options.scroll && (this.options.scroll != window)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ if(this.options.snap) {
+ if(typeof this.options.snap == 'function') {
+ p = this.options.snap(p[0],p[1]);
+ } else {
+ if(this.options.snap instanceof Array) {
+ p = p.map( function(v, i) {
+ return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+ } else {
+ p = p.map( function(v) {
+ return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+ }
+ }}
+
var style = this.element.style;
if((!this.options.constraint) || (this.options.constraint=='horizontal'))
- style.left = (pointer[0] - offsets[0] - this.offsetX) + "px";
+ style.left = p[0] + "px";
if((!this.options.constraint) || (this.options.constraint=='vertical'))
- style.top = (pointer[1] - offsets[1] - this.offsetY) + "px";
+ style.top = p[1] + "px";
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
},
- update: function(event) {
- if(this.active) {
- if(!this.dragging) {
- var style = this.element.style;
- this.dragging = true;
-
- if(Element.getStyle(this.element,'position')=='')
- style.position = "relative";
-
- if(this.options.zindex) {
- this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
- style.zIndex = this.options.zindex;
- }
-
- if(this.options.ghosting) {
- this._clone = this.element.cloneNode(true);
- Position.absolutize(this.element);
- this.element.parentNode.insertBefore(this._clone, this.element);
+
+ stopScrolling: function() {
+ if(this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function(speed) {
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function() {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if(this.options.scroll == window) {
+ with (this._getWindowScroll(this.options.scroll)) {
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
}
-
- Draggables.notify('onStart', this);
- if(this.options.starteffect) this.options.starteffect(this.element);
}
-
- Droppables.show(event, this.element);
- this.draw(event);
- if(this.options.change) this.options.change(this);
-
- // fix AppleWebKit rendering
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-
- Event.stop(event);
- }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if (Draggables._lastScrollPointer[0] < 0)
+ Draggables._lastScrollPointer[0] = 0;
+ if (Draggables._lastScrollPointer[1] < 0)
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+
+ if(this.options.change) this.options.change(this);
+ },
+
+ _getWindowScroll: function(w) {
+ var T, L, W, H;
+ with (w.document) {
+ if (w.document.documentElement && documentElement.scrollTop) {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ } else if (w.document.body) {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if (w.innerWidth) {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ } else if (w.document.documentElement && documentElement.clientWidth) {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ } else {
+ W = body.offsetWidth;
+ H = body.offsetHeight
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
}
}
this.observer = observer;
this.lastValue = Sortable.serialize(this.element);
},
+
onStart: function() {
this.lastValue = Sortable.serialize(this.element);
},
+
onEnd: function() {
Sortable.unmark();
if(this.lastValue != Sortable.serialize(this.element))
}
var Sortable = {
- sortables: new Array(),
- options: function(element){
- element = $(element);
- return this.sortables.detect(function(s) { return s.element == element });
+ sortables: {},
+
+ _findRootElement: function(element) {
+ while (element.tagName != "BODY") {
+ if(element.id && Sortable.sortables[element.id]) return element;
+ element = element.parentNode;
+ }
},
+
+ options: function(element) {
+ element = Sortable._findRootElement($(element));
+ if(!element) return;
+ return Sortable.sortables[element.id];
+ },
+
destroy: function(element){
- element = $(element);
- this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
+ var s = Sortable.options(element);
+
+ if(s) {
Draggables.removeObserver(s.element);
s.droppables.each(function(d){ Droppables.remove(d) });
s.draggables.invoke('destroy');
- });
- this.sortables = this.sortables.reject(function(s) { return s.element == element });
+
+ delete Sortable.sortables[s.element.id];
+ }
},
+
create: function(element) {
element = $(element);
var options = Object.extend({
element: element,
tag: 'li', // assumes li children, override with tag: 'tagname'
dropOnEmpty: false,
- tree: false, // fixme: unimplemented
+ tree: false,
+ treeTag: 'ul',
overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false
containment: element, // also takes array of elements (or id's); or false
only: false,
hoverclass: null,
ghosting: false,
- format: null,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: /^[^_]*_(.*)$/,
onChange: Prototype.emptyFunction,
onUpdate: Prototype.emptyFunction
}, arguments[1] || {});
// build options for the draggables
var options_for_draggable = {
revert: true,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
ghosting: options.ghosting,
constraint: options.constraint,
handle: options.handle };
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
+ tree: options.tree,
hoverclass: options.hoverclass,
- onHover: Sortable.onHover,
- greedy: !options.dropOnEmpty
+ onHover: Sortable.onHover
+ //greedy: !options.dropOnEmpty
+ }
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
}
// fix for gecko engine
options.draggables = [];
options.droppables = [];
- // make it so
-
// drop on empty handling
- if(options.dropOnEmpty) {
- Droppables.add(element,
- {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
+ if(options.dropOnEmpty || options.tree) {
+ Droppables.add(element, options_for_tree);
options.droppables.push(element);
}
(this.findElements(element, options) || []).each( function(e) {
// handles are per-draggable
var handle = options.handle ?
- Element.Class.childrenWith(e, options.handle)[0] : e;
+ Element.childrenWithClassName(e, options.handle)[0] : e;
options.draggables.push(
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
Droppables.add(e, options_for_droppable);
+ if(options.tree) e.treeNode = element;
options.droppables.push(e);
});
+
+ if(options.tree) {
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
// keep reference
- this.sortables.push(options);
+ this.sortables[element.id] = options;
// for onupdate
Draggables.addObserver(new SortableObserver(element, options.onUpdate));
// return all suitable-for-sortable elements in a guaranteed order
findElements: function(element, options) {
- if(!element.hasChildNodes()) return null;
- var elements = [];
- $A(element.childNodes).each( function(e) {
- if(e.tagName && e.tagName==options.tag.toUpperCase() &&
- (!options.only || (Element.Class.has(e, options.only))))
- elements.push(e);
- if(options.tree) {
- var grandchildren = this.findElements(e, options);
- if(grandchildren) elements.push(grandchildren);
- }
- });
-
- return (elements.length>0 ? elements.flatten() : null);
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
},
onHover: function(element, dropon, overlap) {
- if(overlap>0.5) {
+ if(Element.isParent(dropon, element)) return;
+
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+ return;
+ } else if(overlap>0.5) {
Sortable.mark(dropon, 'before');
if(dropon.previousSibling != element) {
var oldParentNode = element.parentNode;
}
}
},
-
- onEmptyHover: function(element, dropon) {
- if(element.parentNode!=dropon) {
- var oldParentNode = element.parentNode;
- dropon.appendChild(element);
+
+ onEmptyHover: function(element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if(!Element.isParent(dropon, element)) {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
+ var child = null;
+
+ if(children) {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
Sortable.options(oldParentNode).onChange(element);
- Sortable.options(dropon).onChange(element);
+ droponOptions.onChange(element);
}
},
if(!Sortable._marker) {
Sortable._marker = $('dropmarker') || document.createElement('DIV');
Element.hide(Sortable._marker);
- Element.Class.add(Sortable._marker, 'dropmarker');
+ Element.addClassName(Sortable._marker, 'dropmarker');
Sortable._marker.style.position = 'absolute';
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
}
var offsets = Position.cumulativeOffset(dropon);
- Sortable._marker.style.top = offsets[1] + 'px';
- if(position=='after') Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
Sortable._marker.style.left = offsets[0] + 'px';
+ Sortable._marker.style.top = offsets[1] + 'px';
+
+ if(position=='after')
+ if(sortable.overlap == 'horizontal')
+ Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
+ else
+ Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
+
Element.show(Sortable._marker);
},
+
+ _tree: function(element, options, parent) {
+ var children = Sortable.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
+
+ if (!match) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: new Array,
+ position: parent.children.length,
+ container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
+ }
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container)
+ this._tree(child.container, options, child)
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
- serialize: function(element) {
+ /* Finds the first element of the given tag type within a parent element.
+ Used for finding the first LI[ST] within a L[IST]I[TEM].*/
+ _findChildrenElement: function (element, containerTag) {
+ if (element && element.hasChildNodes)
+ for (var i = 0; i < element.childNodes.length; ++i)
+ if (element.childNodes[i].tagName == containerTag)
+ return element.childNodes[i];
+
+ return null;
+ },
+
+ tree: function(element) {
element = $(element);
var sortableOptions = this.options(element);
var options = Object.extend({
- tag: sortableOptions.tag,
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
- format: sortableOptions.format || /^[^_]*_(.*)$/
+ format: sortableOptions.format
}, arguments[1] || {});
- return $(this.findElements(element, options) || []).collect( function(item) {
- return (encodeURIComponent(options.name) + "[]=" +
- encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
- }).join("&");
+
+ var root = {
+ id: null,
+ parent: null,
+ children: new Array,
+ container: element,
+ position: 0
+ }
+
+ return Sortable._tree (element, options, root);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function(node) {
+ var index = '';
+ do {
+ if (node.id) index = '[' + node.position + ']' + index;
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ sequence: function(element) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || {});
+
+ return $(this.findElements(element, options) || []).map( function(item) {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function(element, new_sequence) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || {});
+
+ var nodeMap = {};
+ this.findElements(element, options).each( function(n) {
+ if (n.id.match(options.format))
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function(ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || {});
+ var name = encodeURIComponent(
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if (options.tree) {
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
+ return [name + Sortable._constructIndex(item) + "=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ } else {
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
}
+}
+
+/* Returns true if child is contained within element */
+Element.isParent = function(child, element) {
+ if (!child.parentNode || child == element) return false;
+
+ if (child.parentNode == element) return true;
+
+ return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function(element, only, recursive, tagName) {
+ if(!element.hasChildNodes()) return null;
+ tagName = tagName.toUpperCase();
+ if(only) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+ elements.push(e);
+ if(recursive) {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function (element, type) {
+ if (type == 'vertical' || type == 'height')
+ return element.offsetHeight;
+ else
+ return element.offsetWidth;
}
\ No newline at end of file
//
// See scriptaculous.js for full license.
-/* ------------- element ext -------------- */
-
// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
String.prototype.parseColor = function() {
- color = "#";
- if(this.slice(0,4) == "rgb(") {
+ var color = '#';
+ if(this.slice(0,4) == 'rgb(') {
var cols = this.slice(4,this.length-1).split(',');
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
} else {
}
}
return(color.length==7 ? color : (arguments[0] || this));
-}
+}
-Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
- var children = $(element).childNodes;
- var text = "";
- var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i");
-
- for (var i = 0; i < children.length; i++) {
- if(children[i].nodeType==3) {
- text+=children[i].nodeValue;
- } else {
- if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
- text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
- }
- }
-
- return text;
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+}
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
}
-Element.setContentZoom = function(element, percent) {
+Element.setContentZoom = function(element, percent) {
element = $(element);
- element.style.fontSize = (percent/100) + "em";
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+ Element.setStyle(element, {fontSize: (percent/100) + 'em'});
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
}
Element.getOpacity = function(element){
- var opacity;
- if (opacity = Element.getStyle(element, "opacity"))
+ var opacity;
+ if (opacity = Element.getStyle(element, 'opacity'))
return parseFloat(opacity);
- if (opacity = (Element.getStyle(element, "filter") || '').match(/alpha\(opacity=(.*)\)/))
+ if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
if(opacity[1]) return parseFloat(opacity[1]) / 100;
return 1.0;
}
Element.setOpacity = function(element, value){
element= $(element);
- var els = element.style;
- if (value == 1){
- els.opacity = '0.999999';
+ if (value == 1){
+ Element.setStyle(element, { opacity:
+ (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
+ 0.999999 : null });
if(/MSIE/.test(navigator.userAgent))
- els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'');
+ Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
} else {
if(value < 0.00001) value = 0;
- els.opacity = value;
+ Element.setStyle(element, {opacity: value});
if(/MSIE/.test(navigator.userAgent))
- els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
- "alpha(opacity="+value*100+")";
- }
+ Element.setStyle(element,
+ { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
+ 'alpha(opacity='+value*100+')' });
+ }
}
Element.getInlineOpacity = function(element){
- element= $(element);
- var op;
- op = element.style.opacity;
- if (typeof op != "undefined" && op != "") return op;
- return "";
-}
-
-Element.setInlineOpacity = function(element, value){
- element= $(element);
- var els = element.style;
- els.opacity = value;
-}
-
-/*--------------------------------------------------------------------------*/
-
-Element.Class = {
- // Element.toggleClass(element, className) toggles the class being on/off
- // Element.toggleClass(element, className1, className2) toggles between both classes,
- // defaulting to className1 if neither exist
- toggle: function(element, className) {
- if(Element.Class.has(element, className)) {
- Element.Class.remove(element, className);
- if(arguments.length == 3) Element.Class.add(element, arguments[2]);
- } else {
- Element.Class.add(element, className);
- if(arguments.length == 3) Element.Class.remove(element, arguments[2]);
- }
- },
-
- // gets space-delimited classnames of an element as an array
- get: function(element) {
- return $(element).className.split(' ');
- },
-
- // functions adapted from original functions by Gavin Kistner
- remove: function(element) {
- element = $(element);
- var removeClasses = arguments;
- $R(1,arguments.length-1).each( function(index) {
- element.className =
- element.className.split(' ').reject(
- function(klass) { return (klass == removeClasses[index]) } ).join(' ');
- });
- },
-
- add: function(element) {
- element = $(element);
- for(var i = 1; i < arguments.length; i++) {
- Element.Class.remove(element, arguments[i]);
- element.className += (element.className.length > 0 ? ' ' : '') + arguments[i];
- }
- },
-
- // returns true if all given classes exist in said element
- has: function(element) {
- element = $(element);
- if(!element || !element.className) return false;
- var regEx;
- for(var i = 1; i < arguments.length; i++) {
- if((typeof arguments[i] == 'object') &&
- (arguments[i].constructor == Array)) {
- for(var j = 0; j < arguments[i].length; j++) {
- regEx = new RegExp("(^|\\s)" + arguments[i][j] + "(\\s|$)");
- if(!regEx.test(element.className)) return false;
- }
- } else {
- regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)");
- if(!regEx.test(element.className)) return false;
- }
- }
- return true;
- },
-
- // expects arrays of strings and/or strings as optional paramters
- // Element.Class.has_any(element, ['classA','classB','classC'], 'classD')
- has_any: function(element) {
- element = $(element);
- if(!element || !element.className) return false;
- var regEx;
- for(var i = 1; i < arguments.length; i++) {
- if((typeof arguments[i] == 'object') &&
- (arguments[i].constructor == Array)) {
- for(var j = 0; j < arguments[i].length; j++) {
- regEx = new RegExp("(^|\\s)" + arguments[i][j] + "(\\s|$)");
- if(regEx.test(element.className)) return true;
- }
- } else {
- regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)");
- if(regEx.test(element.className)) return true;
- }
- }
- return false;
- },
-
- childrenWith: function(element, className) {
- var children = $(element).getElementsByTagName('*');
- var elements = new Array();
-
- for (var i = 0; i < children.length; i++)
- if (Element.Class.has(children[i], className))
- elements.push(children[i]);
-
- return elements;
- }
+ return $(element).style.opacity || '';
}
-
+
+Element.childrenWithClassName = function(element, className, findFirst) {
+ var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
+ var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) {
+ return (c.className && c.className.match(classNameRegExp));
+ });
+ if(!results) results = [];
+ return results;
+}
+
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Array.prototype.call = function() {
+ var args = arguments;
+ this.each(function(f){ f.apply(this, args) });
+}
+
/*--------------------------------------------------------------------------*/
var Effect = {
tagifyText: function(element) {
- var tagifyStyle = "position:relative";
- if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ";zoom:1";
+ var tagifyStyle = 'position:relative';
+ if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
element = $(element);
$A(element.childNodes).each( function(child) {
if(child.nodeType==3) {
child.nodeValue.toArray().each( function(character) {
element.insertBefore(
Builder.node('span',{style: tagifyStyle},
- character == " " ? String.fromCharCode(160) : character),
+ character == ' ' ? String.fromCharCode(160) : character),
child);
});
Element.remove(child);
speed: 0.1,
delay: 0.0
}, arguments[2] || {});
- var speed = options.speed;
- var delay = options.delay;
+ var masterDelay = options.delay;
$A(elements).each( function(element, index) {
- new effect(element, Object.extend(options, { delay: delay + index * speed }));
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
});
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function(element, effect) {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+ var options = Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, arguments[2] || {});
+ Effect[element.visible() ?
+ Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
}
};
/* ------------- core effects ------------- */
-Effect.Queue = {
- effects: [],
+Effect.ScopedQueue = Class.create();
+Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
+ initialize: function() {
+ this.effects = [];
+ this.interval = null;
+ },
_each: function(iterator) {
this.effects._each(iterator);
},
- interval: null,
add: function(effect) {
var timestamp = new Date().getTime();
- switch(effect.options.queue) {
+ var position = (typeof effect.options.queue == 'string') ?
+ effect.options.queue : effect.options.queue.position;
+
+ switch(position) {
case 'front':
// move unstarted effects after this effect
this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
effect.startOn += timestamp;
effect.finishOn += timestamp;
- this.effects.push(effect);
+
+ if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
if(!this.interval)
this.interval = setInterval(this.loop.bind(this), 40);
},
var timePos = new Date().getTime();
this.effects.invoke('loop', timePos);
}
+});
+
+Effect.Queues = {
+ instances: $H(),
+ get: function(queueName) {
+ if(typeof queueName != 'string') return queueName;
+
+ if(!this.instances[queueName])
+ this.instances[queueName] = new Effect.ScopedQueue();
+
+ return this.instances[queueName];
+ }
+}
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.DefaultOptions = {
+ transition: Effect.Transitions.sinoidal,
+ duration: 1.0, // seconds
+ fps: 25.0, // max. 25fps due to Effect.Queue implementation
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
}
-Object.extend(Effect.Queue, Enumerable);
Effect.Base = function() {};
Effect.Base.prototype = {
position: null,
- setOptions: function(options) {
- this.options = Object.extend({
- transition: Effect.Transitions.sinoidal,
- duration: 1.0, // seconds
- fps: 25.0, // max. 25fps due to Effect.Queue implementation
- sync: false, // true for combining
- from: 0.0,
- to: 1.0,
- delay: 0.0,
- queue: 'parallel'
- }, options || {});
- },
start: function(options) {
- this.setOptions(options || {});
+ this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
this.currentFrame = 0;
this.state = 'idle';
this.startOn = this.options.delay*1000;
this.finishOn = this.startOn + (this.options.duration*1000);
this.event('beforeStart');
- if(!this.options.sync) Effect.Queue.add(this);
+ if(!this.options.sync)
+ Effect.Queues.get(typeof this.options.queue == 'string' ?
+ 'global' : this.options.queue.scope).add(this);
},
loop: function(timePos) {
if(timePos >= this.startOn) {
if(this.setup) this.setup();
this.event('afterSetup');
}
- if(this.options.transition) pos = this.options.transition(pos);
- pos *= (this.options.to-this.options.from);
- pos += this.options.from;
- this.position = pos;
- this.event('beforeUpdate');
- if(this.update) this.update(pos);
- this.event('afterUpdate');
+ if(this.state == 'running') {
+ if(this.options.transition) pos = this.options.transition(pos);
+ pos *= (this.options.to-this.options.from);
+ pos += this.options.from;
+ this.position = pos;
+ this.event('beforeUpdate');
+ if(this.update) this.update(pos);
+ this.event('afterUpdate');
+ }
},
cancel: function() {
- if(!this.options.sync) Effect.Queue.remove(this);
+ if(!this.options.sync)
+ Effect.Queues.get(typeof this.options.queue == 'string' ?
+ 'global' : this.options.queue.scope).remove(this);
this.state = 'finished';
},
event: function(eventName) {
if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
if(this.options[eventName]) this.options[eventName](this);
+ },
+ inspect: function() {
+ return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
}
}
this.element = $(element);
// make this work on IE on elements without 'layout'
if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
- this.element.style.zoom = 1;
+ this.element.setStyle({zoom: 1});
var options = Object.extend({
- from: Element.getOpacity(this.element) || 0.0,
+ from: this.element.getOpacity() || 0.0,
to: 1.0
}, arguments[1] || {});
this.start(options);
},
update: function(position) {
- Element.setOpacity(this.element, position);
+ this.element.setOpacity(position);
}
});
-Effect.MoveBy = Class.create();
-Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
- initialize: function(element, toTop, toLeft) {
- this.element = $(element);
- this.toTop = toTop;
- this.toLeft = toLeft;
- this.start(arguments[3]);
+Effect.Move = Class.create();
+Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
+ initialize: function(element) {
+ this.element = $(element);
+ var options = Object.extend({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, arguments[1] || {});
+ this.start(options);
},
setup: function() {
// Bug in Opera: Opera returns the "real" position of a static element or
// relative element that does not have top/left explicitly set.
// ==> Always set top and left for position relative elements in your stylesheets
- // (to 0 if you do not need them)
-
- Element.makePositioned(this.element);
- this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
- this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
+ // (to 0 if you do not need them)
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if(this.options.mode == 'absolute') {
+ // absolute movement, so we need to calc deltaX and deltaY
+ this.options.x = this.options.x - this.originalLeft;
+ this.options.y = this.options.y - this.originalTop;
+ }
},
update: function(position) {
- var topd = this.toTop * position + this.originalTop;
- var leftd = this.toLeft * position + this.originalLeft;
- this.setPosition(topd, leftd);
- },
- setPosition: function(topd, leftd) {
- this.element.style.top = topd + "px";
- this.element.style.left = leftd + "px";
+ this.element.setStyle({
+ left: this.options.x * position + this.originalLeft + 'px',
+ top: this.options.y * position + this.originalTop + 'px'
+ });
}
});
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+ return new Effect.Move(element,
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
+};
+
Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
initialize: function(element, percent) {
this.start(options);
},
setup: function() {
- var effect = this;
-
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
- this.elementPositioning = Element.getStyle(this.element,'position');
+ this.elementPositioning = this.element.getStyle('position');
- effect.originalStyle = {};
+ this.originalStyle = {};
['top','left','width','height','fontSize'].each( function(k) {
- effect.originalStyle[k] = effect.element.style[k];
- });
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
this.originalTop = this.element.offsetTop;
this.originalLeft = this.element.offsetLeft;
- var fontSize = Element.getStyle(this.element,'font-size') || "100%";
+ var fontSize = this.element.getStyle('font-size') || '100%';
['em','px','%'].each( function(fontSizeType) {
if(fontSize.indexOf(fontSizeType)>0) {
- effect.fontSize = parseFloat(fontSize);
- effect.fontSizeType = fontSizeType;
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
}
- });
+ }.bind(this));
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
this.dims = null;
if(this.options.scaleMode=='box')
- this.dims = [this.element.clientHeight, this.element.clientWidth];
- if(this.options.scaleMode=='content')
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if(/^content/.test(this.options.scaleMode))
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
if(!this.dims)
this.dims = [this.options.scaleMode.originalHeight,
update: function(position) {
var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
if(this.options.scaleContent && this.fontSize)
- this.element.style.fontSize = this.fontSize*currentScale + this.fontSizeType;
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
},
finish: function(position) {
- if (this.restoreAfterFinish) {
- var effect = this;
- ['top','left','width','height','fontSize'].each( function(k) {
- effect.element.style[k] = effect.originalStyle[k];
- });
- }
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
},
setDimensions: function(height, width) {
- var els = this.element.style;
- if(this.options.scaleX) els.width = width + 'px';
- if(this.options.scaleY) els.height = height + 'px';
+ var d = {};
+ if(this.options.scaleX) d.width = width + 'px';
+ if(this.options.scaleY) d.height = height + 'px';
if(this.options.scaleFromCenter) {
var topd = (height - this.dims[0])/2;
var leftd = (width - this.dims[1])/2;
if(this.elementPositioning == 'absolute') {
- if(this.options.scaleY) els.top = this.originalTop-topd + "px";
- if(this.options.scaleX) els.left = this.originalLeft-leftd + "px";
+ if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
} else {
- if(this.options.scaleY) els.top = -topd + "px";
- if(this.options.scaleX) els.left = -leftd + "px";
+ if(this.options.scaleY) d.top = -topd + 'px';
+ if(this.options.scaleX) d.left = -leftd + 'px';
}
}
+ this.element.setStyle(d);
}
});
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
- var options = Object.extend({
- startcolor: "#ffff99"
- }, arguments[1] || {});
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
this.start(options);
},
setup: function() {
// Prevent executing on elements not in the layout flow
- if(this.element.style.display=='none') { this.cancel(); return; }
+ if(this.element.getStyle('display')=='none') { this.cancel(); return; }
// Disable background image during the effect
- this.oldBgImage = this.element.style.backgroundImage;
- this.element.style.backgroundImage = "none";
+ this.oldStyle = {
+ backgroundImage: this.element.getStyle('background-image') };
+ this.element.setStyle({backgroundImage: 'none'});
if(!this.options.endcolor)
- this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
- if (typeof this.options.restorecolor == "undefined")
- this.options.restorecolor = this.element.style.backgroundColor;
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if(!this.options.restorecolor)
+ this.options.restorecolor = this.element.getStyle('background-color');
// init color calculations
- this.colors_base = [
- parseInt(this.options.startcolor.slice(1,3),16),
- parseInt(this.options.startcolor.slice(3,5),16),
- parseInt(this.options.startcolor.slice(5),16) ];
- this.colors_delta = [
- parseInt(this.options.endcolor.slice(1,3),16)-this.colors_base[0],
- parseInt(this.options.endcolor.slice(3,5),16)-this.colors_base[1],
- parseInt(this.options.endcolor.slice(5),16)-this.colors_base[2]];
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
},
update: function(position) {
- var effect = this; var colors = $R(0,2).map( function(i){
- return Math.round(effect.colors_base[i]+(effect.colors_delta[i]*position))
- });
- this.element.style.backgroundColor = "#" +
- colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart();
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
},
finish: function() {
- this.element.style.backgroundColor = this.options.restorecolor;
- this.element.style.backgroundImage = this.oldBgImage;
+ this.element.setStyle(Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
}
});
setup: function() {
Position.prepare();
var offsets = Position.cumulativeOffset(this.element);
+ if(this.options.offset) offsets[1] += this.options.offset;
var max = window.innerHeight ?
window.height - window.innerHeight :
document.body.scrollHeight -
/* ------------- combination effects ------------- */
Effect.Fade = function(element) {
- var oldOpacity = Element.getInlineOpacity(element);
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
var options = Object.extend({
- from: Element.getOpacity(element) || 1.0,
+ from: element.getOpacity() || 1.0,
to: 0.0,
- afterFinishInternal: function(effect)
- { if (effect.options.to == 0) {
- Element.hide(effect.element);
- Element.setInlineOpacity(effect.element, oldOpacity);
- }
- }
- }, arguments[1] || {});
+ afterFinishInternal: function(effect) {
+ if(effect.options.to!=0) return;
+ effect.element.hide();
+ effect.element.setStyle({opacity: oldOpacity});
+ }}, arguments[1] || {});
return new Effect.Opacity(element,options);
}
Effect.Appear = function(element) {
+ element = $(element);
var options = Object.extend({
- from: (Element.getStyle(element, "display") == "none" ? 0.0 : Element.getOpacity(element) || 0.0),
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
to: 1.0,
- beforeSetup: function(effect)
- { Element.setOpacity(effect.element, effect.options.from);
- Element.show(effect.element); }
- }, arguments[1] || {});
+ // force Safari to render floated elements properly
+ afterFinishInternal: function(effect) {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function(effect) {
+ effect.element.setOpacity(effect.options.from);
+ effect.element.show();
+ }}, arguments[1] || {});
return new Effect.Opacity(element,options);
}
Effect.Puff = function(element) {
element = $(element);
- var oldOpacity = Element.getInlineOpacity(element);
- var oldPosition = element.style.position;
+ var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') };
return new Effect.Parallel(
[ new Effect.Scale(element, 200,
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
Object.extend({ duration: 1.0,
- beforeSetupInternal: function(effect)
- { effect.effects[0].element.style.position = 'absolute'; },
- afterFinishInternal: function(effect)
- { Element.hide(effect.effects[0].element);
- effect.effects[0].element.style.position = oldPosition;
- Element.setInlineOpacity(effect.effects[0].element, oldOpacity); }
+ beforeSetupInternal: function(effect) {
+ effect.effects[0].element.setStyle({position: 'absolute'}); },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide();
+ effect.effects[0].element.setStyle(oldStyle); }
}, arguments[1] || {})
);
}
Effect.BlindUp = function(element) {
element = $(element);
- Element.makeClipping(element);
+ element.makeClipping();
return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
scaleX: false,
restoreAfterFinish: true,
- afterFinishInternal: function(effect)
- {
- Element.hide(effect.element);
- Element.undoClipping(effect.element);
- }
+ afterFinishInternal: function(effect) {
+ effect.element.hide();
+ effect.element.undoClipping();
+ }
}, arguments[1] || {})
);
}
Effect.BlindDown = function(element) {
element = $(element);
- var oldHeight = element.style.height;
- var elementDimensions = Element.getDimensions(element);
+ var elementDimensions = element.getDimensions();
return new Effect.Scale(element, 100,
Object.extend({ scaleContent: false,
scaleX: false,
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
afterSetup: function(effect) {
- Element.makeClipping(effect.element);
- effect.element.style.height = "0px";
- Element.show(effect.element);
+ effect.element.makeClipping();
+ effect.element.setStyle({height: '0px'});
+ effect.element.show();
},
afterFinishInternal: function(effect) {
- Element.undoClipping(effect.element);
- effect.element.style.height = oldHeight;
+ effect.element.undoClipping();
}
}, arguments[1] || {})
);
Effect.SwitchOff = function(element) {
element = $(element);
- var oldOpacity = Element.getInlineOpacity(element);
+ var oldOpacity = element.getInlineOpacity();
return new Effect.Appear(element, {
duration: 0.4,
from: 0,
duration: 0.3, scaleFromCenter: true,
scaleX: false, scaleContent: false, restoreAfterFinish: true,
beforeSetup: function(effect) {
- Element.makePositioned(effect.element);
- Element.makeClipping(effect.element);
+ effect.element.makePositioned();
+ effect.element.makeClipping();
},
- afterFinishInternal: function(effect) {
- Element.hide(effect.element);
- Element.undoClipping(effect.element);
- Element.undoPositioned(effect.element);
- Element.setInlineOpacity(effect.element, oldOpacity);
+ afterFinishInternal: function(effect) {
+ effect.element.hide();
+ effect.element.undoClipping();
+ effect.element.undoPositioned();
+ effect.element.setStyle({opacity: oldOpacity});
}
})
}
Effect.DropOut = function(element) {
element = $(element);
- var oldTop = element.style.top;
- var oldLeft = element.style.left;
- var oldOpacity = Element.getInlineOpacity(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
return new Effect.Parallel(
- [ new Effect.MoveBy(element, 100, 0, { sync: true }),
+ [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
Object.extend(
{ duration: 0.5,
- beforeSetup: function(effect) {
- Element.makePositioned(effect.effects[0].element); },
- afterFinishInternal: function(effect) {
- Element.hide(effect.effects[0].element);
- Element.undoPositioned(effect.effects[0].element);
- effect.effects[0].element.style.left = oldLeft;
- effect.effects[0].element.style.top = oldTop;
- Element.setInlineOpacity(effect.effects[0].element, oldOpacity); }
+ beforeSetup: function(effect) {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide();
+ effect.effects[0].element.undoPositioned();
+ effect.effects[0].element.setStyle(oldStyle);
+ }
}, arguments[1] || {}));
}
Effect.Shake = function(element) {
element = $(element);
- var oldTop = element.style.top;
- var oldLeft = element.style.left;
- return new Effect.MoveBy(element, 0, 20,
- { duration: 0.05, afterFinishInternal: function(effect) {
- new Effect.MoveBy(effect.element, 0, -40,
- { duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.MoveBy(effect.element, 0, 40,
- { duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.MoveBy(effect.element, 0, -40,
- { duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.MoveBy(effect.element, 0, 40,
- { duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.MoveBy(effect.element, 0, -20,
- { duration: 0.05, afterFinishInternal: function(effect) {
- Element.undoPositioned(effect.element);
- effect.element.style.left = oldLeft;
- effect.element.style.top = oldTop;
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element,
+ { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
+ effect.element.undoPositioned();
+ effect.element.setStyle(oldStyle);
}}) }}) }}) }}) }}) }});
}
Effect.SlideDown = function(element) {
element = $(element);
- Element.cleanWhitespace(element);
+ element.cleanWhitespace();
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
- var oldInnerBottom = element.firstChild.style.bottom;
- var elementDimensions = Element.getDimensions(element);
- return new Effect.Scale(element, 100,
- Object.extend({ scaleContent: false,
+ var oldInnerBottom = $(element.firstChild).getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
scaleX: false,
scaleFrom: 0,
- scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
afterSetup: function(effect) {
- Element.makePositioned(effect.element.firstChild);
- if (window.opera) effect.element.firstChild.style.top = "";
- Element.makeClipping(effect.element);
- element.style.height = '0';
- Element.show(element);
- },
- afterUpdateInternal: function(effect) {
- effect.element.firstChild.style.bottom =
- (effect.dims[0] - effect.element.clientHeight) + 'px'; },
- afterFinishInternal: function(effect) {
- Element.undoClipping(effect.element);
- Element.undoPositioned(effect.element.firstChild);
- effect.element.firstChild.style.bottom = oldInnerBottom; }
+ effect.element.makePositioned();
+ effect.element.firstChild.makePositioned();
+ if(window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping();
+ effect.element.setStyle({height: '0px'});
+ effect.element.show(); },
+ afterUpdateInternal: function(effect) {
+ effect.element.firstChild.setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping();
+ // IE will crash if child is undoPositioned first
+ if(/MSIE/.test(navigator.userAgent)){
+ effect.element.undoPositioned();
+ effect.element.firstChild.undoPositioned();
+ }else{
+ effect.element.firstChild.undoPositioned();
+ effect.element.undoPositioned();
+ }
+ effect.element.firstChild.setStyle({bottom: oldInnerBottom}); }
}, arguments[1] || {})
);
}
Effect.SlideUp = function(element) {
element = $(element);
- Element.cleanWhitespace(element);
- var oldInnerBottom = element.firstChild.style.bottom;
+ element.cleanWhitespace();
+ var oldInnerBottom = $(element.firstChild).getStyle('bottom');
return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
scaleX: false,
scaleMode: 'box',
scaleFrom: 100,
restoreAfterFinish: true,
- beforeStartInternal: function(effect) {
- Element.makePositioned(effect.element.firstChild);
- if (window.opera) effect.element.firstChild.style.top = "";
- Element.makeClipping(effect.element);
- Element.show(element);
- },
- afterUpdateInternal: function(effect) {
- effect.element.firstChild.style.bottom =
- (effect.dims[0] - effect.element.clientHeight) + 'px'; },
- afterFinishInternal: function(effect) {
- Element.hide(effect.element);
- Element.undoClipping(effect.element);
- Element.undoPositioned(effect.element.firstChild);
- effect.element.firstChild.style.bottom = oldInnerBottom; }
+ beforeStartInternal: function(effect) {
+ effect.element.makePositioned();
+ effect.element.firstChild.makePositioned();
+ if(window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping();
+ effect.element.show(); },
+ afterUpdateInternal: function(effect) {
+ effect.element.firstChild.setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' }); },
+ afterFinishInternal: function(effect) {
+ effect.element.hide();
+ effect.element.undoClipping();
+ effect.element.firstChild.undoPositioned();
+ effect.element.undoPositioned();
+ effect.element.setStyle({bottom: oldInnerBottom}); }
}, arguments[1] || {})
);
}
+// Bug in opera makes the TD containing this element expand for a instance after finish
Effect.Squish = function(element) {
- // Bug in opera makes the TD containing this element expand for a instance after finish
return new Effect.Scale(element, window.opera ? 1 : 0,
{ restoreAfterFinish: true,
- beforeSetup: function(effect) {
- Element.makeClipping(effect.element); },
- afterFinishInternal: function(effect) {
- Element.hide(effect.element);
- Element.undoClipping(effect.element); }
+ beforeSetup: function(effect) {
+ effect.element.makeClipping(effect.element); },
+ afterFinishInternal: function(effect) {
+ effect.element.hide(effect.element);
+ effect.element.undoClipping(effect.element); }
});
}
Effect.Grow = function(element) {
element = $(element);
- var options = arguments[1] || {};
-
- var elementDimensions = Element.getDimensions(element);
- var originalWidth = elementDimensions.width;
- var originalHeight = elementDimensions.height;
- var oldTop = element.style.top;
- var oldLeft = element.style.left;
- var oldHeight = element.style.height;
- var oldWidth = element.style.width;
- var oldOpacity = Element.getInlineOpacity(element);
-
- var direction = options.direction || 'center';
- var moveTransition = options.moveTransition || Effect.Transitions.sinoidal;
- var scaleTransition = options.scaleTransition || Effect.Transitions.sinoidal;
- var opacityTransition = options.opacityTransition || Effect.Transitions.full;
-
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || {});
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
var initialMoveX, initialMoveY;
var moveX, moveY;
- switch (direction) {
+ switch (options.direction) {
case 'top-left':
initialMoveX = initialMoveY = moveX = moveY = 0;
break;
case 'top-right':
- initialMoveX = originalWidth;
+ initialMoveX = dims.width;
initialMoveY = moveY = 0;
- moveX = -originalWidth;
+ moveX = -dims.width;
break;
case 'bottom-left':
initialMoveX = moveX = 0;
- initialMoveY = originalHeight;
- moveY = -originalHeight;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
break;
case 'bottom-right':
- initialMoveX = originalWidth;
- initialMoveY = originalHeight;
- moveX = -originalWidth;
- moveY = -originalHeight;
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
break;
case 'center':
- initialMoveX = originalWidth / 2;
- initialMoveY = originalHeight / 2;
- moveX = -originalWidth / 2;
- moveY = -originalHeight / 2;
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
break;
}
- return new Effect.MoveBy(element, initialMoveY, initialMoveX, {
+ return new Effect.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
duration: 0.01,
- beforeSetup: function(effect) {
- Element.hide(effect.element);
- Element.makeClipping(effect.element);
- Element.makePositioned(effect.element);
+ beforeSetup: function(effect) {
+ effect.element.hide();
+ effect.element.makeClipping();
+ effect.element.makePositioned();
},
afterFinishInternal: function(effect) {
new Effect.Parallel(
- [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: opacityTransition }),
- new Effect.MoveBy(effect.element, moveY, moveX, { sync: true, transition: moveTransition }),
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
new Effect.Scale(effect.element, 100, {
- scaleMode: { originalHeight: originalHeight, originalWidth: originalWidth },
- sync: true, scaleFrom: window.opera ? 1 : 0, transition: scaleTransition, restoreAfterFinish: true})
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
], Object.extend({
beforeSetup: function(effect) {
- effect.effects[0].element.style.height = 0;
- Element.show(effect.effects[0].element);
- },
+ effect.effects[0].element.setStyle({height: '0px'});
+ effect.effects[0].element.show();
+ },
afterFinishInternal: function(effect) {
- var el = effect.effects[0].element;
- var els = el.style;
- Element.undoClipping(el);
- Element.undoPositioned(el);
- els.top = oldTop;
- els.left = oldLeft;
- els.height = oldHeight;
- els.width = originalWidth + 'px';
- Element.setInlineOpacity(el, oldOpacity);
+ effect.effects[0].element.undoClipping();
+ effect.effects[0].element.undoPositioned();
+ effect.effects[0].element.setStyle(oldStyle);
}
}, options)
)
Effect.Shrink = function(element) {
element = $(element);
- var options = arguments[1] || {};
-
- var originalWidth = element.clientWidth;
- var originalHeight = element.clientHeight;
- var oldTop = element.style.top;
- var oldLeft = element.style.left;
- var oldHeight = element.style.height;
- var oldWidth = element.style.width;
- var oldOpacity = Element.getInlineOpacity(element);
-
- var direction = options.direction || 'center';
- var moveTransition = options.moveTransition || Effect.Transitions.sinoidal;
- var scaleTransition = options.scaleTransition || Effect.Transitions.sinoidal;
- var opacityTransition = options.opacityTransition || Effect.Transitions.none;
-
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || {});
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
var moveX, moveY;
- switch (direction) {
+ switch (options.direction) {
case 'top-left':
moveX = moveY = 0;
break;
case 'top-right':
- moveX = originalWidth;
+ moveX = dims.width;
moveY = 0;
break;
case 'bottom-left':
moveX = 0;
- moveY = originalHeight;
+ moveY = dims.height;
break;
case 'bottom-right':
- moveX = originalWidth;
- moveY = originalHeight;
+ moveX = dims.width;
+ moveY = dims.height;
break;
case 'center':
- moveX = originalWidth / 2;
- moveY = originalHeight / 2;
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
break;
}
return new Effect.Parallel(
- [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: opacityTransition }),
- new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: scaleTransition, restoreAfterFinish: true}),
- new Effect.MoveBy(element, moveY, moveX, { sync: true, transition: moveTransition })
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
], Object.extend({
- beforeStartInternal: function(effect) {
- Element.makePositioned(effect.effects[0].element);
- Element.makeClipping(effect.effects[0].element);
- },
+ beforeStartInternal: function(effect) {
+ effect.effects[0].element.makePositioned();
+ effect.effects[0].element.makeClipping(); },
afterFinishInternal: function(effect) {
- var el = effect.effects[0].element;
- var els = el.style;
- Element.hide(el);
- Element.undoClipping(el);
- Element.undoPositioned(el);
- els.top = oldTop;
- els.left = oldLeft;
- els.height = oldHeight;
- els.width = oldWidth;
- Element.setInlineOpacity(el, oldOpacity);
- }
+ effect.effects[0].element.hide();
+ effect.effects[0].element.undoClipping();
+ effect.effects[0].element.undoPositioned();
+ effect.effects[0].element.setStyle(oldStyle); }
}, options)
);
}
Effect.Pulsate = function(element) {
element = $(element);
var options = arguments[1] || {};
- var oldOpacity = Element.getInlineOpacity(element);
+ var oldOpacity = element.getInlineOpacity();
var transition = options.transition || Effect.Transitions.sinoidal;
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
reverser.bind(transition);
return new Effect.Opacity(element,
Object.extend(Object.extend({ duration: 3.0, from: 0,
- afterFinishInternal: function(effect) { Element.setInlineOpacity(effect.element, oldOpacity); }
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
}, options), {transition: reverser}));
}
Effect.Fold = function(element) {
element = $(element);
- var originalTop = element.style.top;
- var originalLeft = element.style.left;
- var originalWidth = element.style.width;
- var originalHeight = element.style.height;
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
Element.makeClipping(element);
return new Effect.Scale(element, 5, Object.extend({
scaleContent: false,
new Effect.Scale(element, 1, {
scaleContent: false,
scaleY: false,
- afterFinishInternal: function(effect) {
- Element.hide(effect.element);
- Element.undoClipping(effect.element);
- effect.element.style.top = originalTop;
- effect.element.style.left = originalLeft;
- effect.element.style.width = originalWidth;
- effect.element.style.height = originalHeight;
+ afterFinishInternal: function(effect) {
+ effect.element.hide();
+ effect.element.undoClipping();
+ effect.element.setStyle(oldStyle);
} });
}}, arguments[1] || {}));
-}
+};
+
+['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
+ 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each(
+ function(f) { Element.Methods[f] = Element[f]; }
+);
+
+Element.Methods.visualEffect = function(element, effect, options) {
+ s = effect.gsub(/_/, '-').camelize();
+ effect_class = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[effect_class](element, options);
+ return $(element);
+};
+
+Element.addMethods();
\ No newline at end of file
-/* Prototype JavaScript framework, version 1.4.0_rc2
+/* Prototype JavaScript framework, version 1.5.0_rc0
* (c) 2005 Sam Stephenson <sam@conio.net>
*
- * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
- * against the source tree, available from the Prototype darcs repository.
- *
* Prototype is freely distributable under the terms of an MIT-style license.
- *
* For details, see the Prototype web site: http://prototype.conio.net/
*
/*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.4.0_rc2',
+ Version: '1.5.0_rc0',
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
emptyFunction: function() {},
K: function(x) {return x}
var Abstract = new Object();
Object.extend = function(destination, source) {
- for (property in source) {
+ for (var property in source) {
destination[property] = source[property];
}
return destination;
}
}
-Function.prototype.bind = function(object) {
- var __method = this;
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
return function() {
- return __method.apply(object, arguments);
+ return __method.apply(object, args.concat($A(arguments)));
}
}
}
}
}
+Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += (replacement(match) || '').toString();
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
-/*--------------------------------------------------------------------------*/
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = count === undefined ? 1 : count;
-function $() {
- var elements = new Array();
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
- for (var i = 0; i < arguments.length; i++) {
- var element = arguments[i];
- if (typeof element == 'string')
- element = document.getElementById(element);
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return this;
+ },
- if (arguments.length == 1)
- return element;
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = truncation === undefined ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : this;
+ },
- elements.push(element);
- }
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
- return elements;
-}
-Object.extend(String.prototype, {
stripTags: function() {
return this.replace(/<\/?[^>]+>/gi, '');
},
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
escapeHTML: function() {
var div = document.createElement('div');
var text = document.createTextNode(this);
},
inspect: function() {
- return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
+ return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'";
}
});
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (typeof replacement == 'function') return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+}
+
String.prototype.parseQuery = String.prototype.toQueryParams;
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ return this.template.gsub(this.pattern, function(match) {
+ var before = match[1];
+ if (before == '\\') return match[2];
+ return before + (object[match[3]] || '').toString();
+ });
+ }
+}
+
var $break = new Object();
var $continue = new Object();
all: function(iterator) {
var result = true;
this.each(function(value, index) {
- if (!(result &= (iterator || Prototype.K)(value, index)))
- throw $break;
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
});
return result;
},
any: function(iterator) {
var result = true;
this.each(function(value, index) {
- if (result &= (iterator || Prototype.K)(value, index))
+ if (result = !!(iterator || Prototype.K)(value, index))
throw $break;
});
return result;
var result;
this.each(function(value, index) {
value = (iterator || Prototype.K)(value, index);
- if (value >= (result || value))
+ if (result == undefined || value >= result)
result = value;
});
return result;
var result;
this.each(function(value, index) {
value = (iterator || Prototype.K)(value, index);
- if (value <= (result || value))
+ if (result == undefined || value < result)
result = value;
});
return result;
var collections = [this].concat(args).map($A);
return this.map(function(value, index) {
- iterator(value = collections.pluck(index));
- return value;
+ return iterator(collections.pluck(index));
});
},
entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
if (iterable.toArray) {
return iterable.toArray();
} else {
Object.extend(Array.prototype, Enumerable);
+if (!Array.prototype._reverse)
+ Array.prototype._reverse = Array.prototype.reverse;
+
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0; i < this.length; i++)
iterator(this[i]);
},
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
first: function() {
return this[0];
},
flatten: function() {
return this.inject([], function(array, value) {
- return array.concat(value.constructor == Array ?
+ return array.concat(value && value.constructor == Array ?
value.flatten() : [value]);
});
},
indexOf: function(object) {
for (var i = 0; i < this.length; i++)
if (this[i] == object) return i;
- return false;
+ return -1;
},
- reverse: function() {
- var result = [];
- for (var i = this.length; i > 0; i--)
- result.push(this[i-1]);
- return result;
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
},
inspect: function() {
});
var Hash = {
_each: function(iterator) {
- for (key in this) {
+ for (var key in this) {
var value = this[key];
if (typeof value == 'function') continue;
Object.extend(hash, Hash);
return hash;
}
-var Range = Class.create();
-Object.extend(Range.prototype, Enumerable);
-Object.extend(Range.prototype, {
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
initialize: function(start, end, exclusive) {
this.start = start;
this.end = end;
});
var $R = function(start, end, exclusive) {
- return new Range(start, end, exclusive);
+ return new ObjectRange(start, end, exclusive);
}
var Ajax = {
getTransport: function() {
return Try.these(
+ function() {return new XMLHttpRequest()},
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
- function() {return new ActiveXObject('Microsoft.XMLHTTP')},
- function() {return new XMLHttpRequest()}
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
) || false;
},
if (responder[callback] && typeof responder[callback] == 'function') {
try {
responder[callback].apply(responder, [request, transport, json]);
- } catch (e) {
- }
+ } catch (e) {}
}
});
}
this.options = {
method: 'post',
asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
parameters: ''
}
Object.extend(this.options, options || {});
this.transport.send(this.options.method == 'post' ? body : null);
} catch (e) {
- (this.options.onException || Prototype.emptyFunction)(this, e);
- Ajax.Responders.dispatch('onException', this, e);
+ this.dispatchException(e);
}
},
setRequestHeaders: function() {
var requestHeaders =
['X-Requested-With', 'XMLHttpRequest',
- 'X-Prototype-Version', Prototype.Version];
+ 'X-Prototype-Version', Prototype.Version,
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
if (this.options.method == 'post') {
- requestHeaders.push('Content-type',
- 'application/x-www-form-urlencoded');
+ requestHeaders.push('Content-type', this.options.contentType);
/* Force "Connection: close" for Mozilla browsers to work around
* a bug where XMLHttpReqeuest sends an incorrect Content-length
this.respondToReadyState(this.transport.readyState);
},
+ header: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {}
+ },
+
evalJSON: function() {
try {
- var json = this.transport.getResponseHeader('X-JSON'), object;
- object = eval(json);
- return object;
+ return eval('(' + this.header('X-JSON') + ')');
+ } catch (e) {}
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
} catch (e) {
+ this.dispatchException(e);
}
},
var event = Ajax.Request.Events[readyState];
var transport = this.transport, json = this.evalJSON();
- if (event == 'Complete')
- (this.options['on' + this.transport.status]
- || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
- || Prototype.emptyFunction)(transport, json);
+ if (event == 'Complete') {
+ try {
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
- (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
- Ajax.Responders.dispatch('on' + event, this, transport, json);
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
if (event == 'Complete')
this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
}
});
Ajax.Updater = Class.create();
-Ajax.Updater.ScriptFragment = '(?:<script.*?>)((\n|.)*?)(?:<\/script>)';
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
initialize: function(container, url, options) {
updateContent: function() {
var receiver = this.responseIsSuccess() ?
this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
- var match = new RegExp(Ajax.Updater.ScriptFragment, 'img');
- var response = this.transport.responseText.replace(match, '');
- var scripts = this.transport.responseText.match(match);
+ if (!this.options.evalScripts)
+ response = response.stripScripts();
if (receiver) {
if (this.options.insertion) {
new this.options.insertion(receiver, response);
} else {
- receiver.innerHTML = response;
+ Element.update(receiver, response);
}
}
if (this.onComplete)
setTimeout(this.onComplete.bind(this), 10);
}
-
- if (this.options.evalScripts && scripts) {
- match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
- setTimeout((function() {
- for (var i = 0; i < scripts.length; i++)
- eval(scripts[i].match(match)[1]);
- }).bind(this), 10);
- }
}
});
this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
});
+function $() {
+ var results = [], element;
+ for (var i = 0; i < arguments.length; i++) {
+ element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ results.push(Element.extend(element));
+ }
+ return results.length < 2 ? results[0] : results;
+}
+
document.getElementsByClassName = function(className, parentElement) {
var children = ($(parentElement) || document.body).getElementsByTagName('*');
return $A(children).inject([], function(elements, child) {
if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
- elements.push(child);
+ elements.push(Element.extend(child));
return elements;
});
}
/*--------------------------------------------------------------------------*/
-if (!window.Element) {
+if (!window.Element)
var Element = new Object();
+
+Element.extend = function(element) {
+ if (!element) return;
+ if (_nativeExtensions) return element;
+
+ if (!element._extended && element.tagName && element != window) {
+ var methods = Element.Methods, cache = Element.extend.cache;
+ for (property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
}
-Object.extend(Element, {
+Element.extend.cache = {
+ findOrStore: function(value) {
+ return this[value] = this[value] || function() {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+}
+
+Element.Methods = {
visible: function(element) {
return $(element).style.display != 'none';
},
element.parentNode.removeChild(element);
},
+ update: function(element, html) {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
+ replace: function(element, html) {
+ element = $(element);
+ if (element.outerHTML) {
+ element.outerHTML = html.stripScripts();
+ } else {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(
+ range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
getHeight: function(element) {
element = $(element);
return element.offsetHeight;
return $(element).innerHTML.match(/^\s*$/);
},
+ childOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+ return false;
+ },
+
scrollTo: function(element) {
element = $(element);
var x = element.x ? element.x : element.offsetLeft,
return value == 'auto' ? null : value;
},
+ setStyle: function(element, style) {
+ element = $(element);
+ for (var name in style)
+ element.style[name.camelize()] = style[name];
+ },
+
getDimensions: function(element) {
element = $(element);
if (Element.getStyle(element, 'display') != 'none')
element.style.overflow = element._overflow;
element._overflow = undefined;
}
-});
+}
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ var HTMLElement = {}
+ HTMLElement.prototype = document.createElement('div').__proto__;
+}
+
+Element.addMethods = function(methods) {
+ Object.extend(Element.Methods, methods || {});
+
+ if(typeof HTMLElement != 'undefined') {
+ var methods = Element.Methods, cache = Element.extend.cache;
+ for (property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ HTMLElement.prototype[property] = cache.findOrStore(value);
+ }
+ _nativeExtensions = true;
+ }
+}
+
+Element.addMethods();
var Toggle = new Object();
Toggle.display = Element.toggle;
Abstract.Insertion.prototype = {
initialize: function(element, content) {
this.element = $(element);
- this.content = content;
+ this.content = content.stripScripts();
if (this.adjacency && this.element.insertAdjacentHTML) {
try {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} catch (e) {
- if (this.element.tagName.toLowerCase() == 'tbody') {
+ var tagName = this.element.tagName.toLowerCase();
+ if (tagName == 'tbody' || tagName == 'tr') {
this.insertContent(this.contentFromAnonymousTable());
} else {
throw e;
if (this.initializeRange) this.initializeRange();
this.insertContent([this.range.createContextualFragment(this.content)]);
}
+
+ setTimeout(function() {content.evalScripts()}, 10);
},
contentFromAnonymousTable: function() {
},
insertContent: function(fragments) {
- fragments.reverse().each((function(fragment) {
+ fragments.reverse(false).each((function(fragment) {
this.element.insertBefore(fragment, this.element.firstChild);
}).bind(this));
}
if (!this.include(classNameToRemove)) return;
this.set(this.select(function(className) {
return className != classNameToRemove;
- }));
+ }).join(' '));
},
toString: function() {
}
Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+ initialize: function(expression) {
+ this.params = {classNames: []};
+ this.expression = expression.toString().strip();
+ this.parseExpression();
+ this.compileMatcher();
+ },
+
+ parseExpression: function() {
+ function abort(message) { throw 'Parse error in selector: ' + message; }
+
+ if (this.expression == '') abort('empty expression');
+
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if (expr == '*') return this.params.wildcard = true;
+
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+ modifier = match[1], clause = match[2], rest = match[3];
+ switch (modifier) {
+ case '#': params.id = clause; break;
+ case '.': params.classNames.push(clause); break;
+ case '':
+ case undefined: params.tagName = clause.toUpperCase(); break;
+ default: abort(expr.inspect());
+ }
+ expr = rest;
+ }
+
+ if (expr.length > 0) abort(expr.inspect());
+ },
+
+ buildMatchExpression: function() {
+ var params = this.params, conditions = [], clause;
+
+ if (params.wildcard)
+ conditions.push('true');
+ if (clause = params.id)
+ conditions.push('element.id == ' + clause.inspect());
+ if (clause = params.tagName)
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+ if ((clause = params.classNames).length > 0)
+ for (var i = 0; i < clause.length; i++)
+ conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
+ if (clause = params.attributes) {
+ clause.each(function(attribute) {
+ var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
+ var splitValueBy = function(delimiter) {
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+ }
+
+ switch (attribute.operator) {
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+ case '|=': conditions.push(
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+ ); break;
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
+ case '':
+ case undefined: conditions.push(value + ' != null'); break;
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ });
+ }
+
+ return conditions.join(' && ');
+ },
+
+ compileMatcher: function() {
+ this.match = new Function('element', 'if (!element.tagName) return false; \
+ return ' + this.buildMatchExpression());
+ },
+
+ findElements: function(scope) {
+ var element;
+
+ if (element = $(this.params.id))
+ if (this.match(element))
+ if (!scope || Element.childOf(element, scope))
+ return [element];
+
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+ var results = [];
+ for (var i = 0; i < scope.length; i++)
+ if (this.match(element = scope[i]))
+ results.push(Element.extend(element));
+
+ return results;
+ },
+
+ toString: function() {
+ return this.expression;
+ }
+}
+
+function $$() {
+ return $A(arguments).map(function(expression) {
+ return expression.strip().split(/\s+/).inject([null], function(results, expr) {
+ var selector = new Selector(expr);
+ return results.map(selector.findElements.bind(selector)).flatten();
+ });
+ }).flatten();
+}
var Field = {
clear: function() {
for (var i = 0; i < arguments.length; i++)
},
activate: function(element) {
- $(element).focus();
- $(element).select();
+ element = $(element);
+ element.focus();
+ if (element.select)
+ element.select();
}
}
form = $(form);
var elements = new Array();
- for (tagName in Form.Element.Serializers) {
+ for (var tagName in Form.Element.Serializers) {
var tagElements = form.getElementsByTagName(tagName);
for (var j = 0; j < tagElements.length; j++)
elements.push(tagElements[j]);
}
},
+ findFirstElement: function(form) {
+ return Form.getElements(form).find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
focusFirstElement: function(form) {
- form = $(form);
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
- if (element.type != 'hidden' && !element.disabled) {
- Field.activate(element);
- break;
- }
- }
+ Field.activate(Form.findFirstElement(form));
},
reset: function(form) {
var method = element.tagName.toLowerCase();
var parameter = Form.Element.Serializers[method](element);
- if (parameter)
- return encodeURIComponent(parameter[0]) + '=' +
- encodeURIComponent(parameter[1]);
+ if (parameter) {
+ var key = encodeURIComponent(parameter[0]);
+ if (key.length == 0) return;
+
+ if (parameter[1].constructor != Array)
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
},
getValue: function(element) {
var value = '', opt, index = element.selectedIndex;
if (index >= 0) {
opt = element.options[index];
- value = opt.value;
- if (!value && !('value' in opt))
- value = opt.text;
+ value = opt.value || opt.text;
}
return [element.name, value];
},
selectMany: function(element) {
- var value = new Array();
+ var value = [];
for (var i = 0; i < element.length; i++) {
var opt = element.options[i];
- if (opt.selected) {
- var optValue = opt.value;
- if (!optValue && !('value' in opt))
- optValue = opt.text;
- value.push(optValue);
- }
+ if (opt.selected)
+ value.push(opt.value || opt.text);
}
return [element.name, value];
}
switch (element.type.toLowerCase()) {
case 'checkbox':
case 'radio':
- element.target = this;
- element.prev_onclick = element.onclick || Prototype.emptyFunction;
- element.onclick = function() {
- this.prev_onclick();
- this.target.onElementEvent();
- }
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
break;
case 'password':
case 'text':
case 'textarea':
case 'select-one':
case 'select-multiple':
- element.target = this;
- element.prev_onchange = element.onchange || Prototype.emptyFunction;
- element.onchange = function() {
- this.prev_onchange();
- this.target.onElementEvent();
- }
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
break;
}
}
});
/* prevent memory leaks in IE */
-Event.observe(window, 'unload', Event.unloadCache, false);
+if (navigator.appVersion.match(/\bMSIE\b/))
+ Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
// set to true if needed, warning: firefox performance problems
// NOT neeeded for page scrolling, only if draggable contained in
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/about'
\ No newline at end of file
-#!/usr/bin/ruby1.8
-
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/breakpointer'
\ No newline at end of file
-#!/usr/bin/ruby1.8
-
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/console'
\ No newline at end of file
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/destroy'
\ No newline at end of file
-#!/usr/bin/ruby1.8
-
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/generate'
\ No newline at end of file
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/performance/benchmarker'
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/performance/profiler'
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/plugin'
\ No newline at end of file
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/process/reaper'
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/process/spawner'
-#!/usr/bin/ruby1.8
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/runner'
\ No newline at end of file
-#!/usr/bin/ruby1.8
-
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/server'
\ No newline at end of file
-/home/mako/votingbooth/vendor
\ No newline at end of file
+.
\ No newline at end of file