Merge branch 'jquery' of epall/tracks

This concludes the transition from Prototype to
jQuery throughout Tracks. Closes #944.
This commit is contained in:
Eric Allen 2009-11-04 22:08:13 -05:00
commit 45d9ab60bf
185 changed files with 3856 additions and 14123 deletions

View file

@ -27,6 +27,7 @@ class ApplicationController < ActionController::Base
helper_method :current_user, :prefs
layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
exempt_from_layout /\.js\.erb$/
before_filter :set_session_expiration
before_filter :set_time_zone
@ -129,14 +130,6 @@ class ApplicationController < ActionController::Base
RedCloth.new(text).to_html
end
def build_default_project_context_name_map(projects)
Hash[*projects.reject{ |p| p.default_context.nil? }.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
end
def build_default_project_tags_map(projects)
Hash[*projects.reject{ |p| p.default_tags.nil? }.map{ |p| [p.name, p.default_tags] }.flatten].to_json
end
# Here's the concept behind this "mobile content negotiation" hack: In
# addition to the main, AJAXy Web UI, Tracks has a lightweight low-feature
# 'mobile' version designed to be suitablef or use from a phone or PDA. It

View file

@ -92,7 +92,7 @@ class ContextsController < ApplicationController
if @context.save
if boolean_param('wants_render')
@context_state_changed = (@orgininal_context_hidden != @context.hidden?)
@context_state_changed = (@original_context_hidden != @context.hidden?)
@new_state = (@context.hidden? ? "hidden" : "active") if @context_state_changed
respond_to do |format|
format.js
@ -110,6 +110,13 @@ class ContextsController < ApplicationController
end
end
def edit
@context = Context.find(params[:id])
respond_to do |format|
format.js
end
end
# Fairly self-explanatory; deletes the context If the context contains
# actions, you'll get a warning dialogue. If you choose to go ahead, any
# actions in the context will also be deleted.
@ -124,11 +131,12 @@ class ContextsController < ApplicationController
# Methods for changing the sort order of the contexts in the list
#
def order
list = params["list-contexts-hidden"] || params["list-contexts-active"]
list.each_with_index do |id, position|
current_user.contexts.update(id, :position => position + 1)
end
context_ids = params["container_context"]
@projects = current_user.contexts.update_positions( context_ids )
render :nothing => true
rescue
notify :error, $!
redirect_to :action => 'index'
end
protected
@ -218,8 +226,6 @@ class ContextsController < ApplicationController
@projects = current_user.projects
@count = @not_done_todos.size
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_tags_map = build_default_project_tags_map(@projects).to_json
end
end

View file

@ -53,8 +53,7 @@ class ProjectsController < ApplicationController
@down_count = @count + @deferred.size
@next_project = current_user.projects.next_from(@project)
@previous_project = current_user.projects.previous_from(@project)
@default_project_context_name_map = build_default_project_context_name_map(current_user.projects).to_json
@default_project_tags_map = build_default_project_tags_map(current_user.projects).to_json
@default_tags = @project.default_tags
respond_to do |format|
format.html
format.m &render_project_mobile
@ -127,6 +126,7 @@ class ProjectsController < ApplicationController
@active_projects_count = current_user.projects.active.count
@hidden_projects_count = current_user.projects.hidden.count
@completed_projects_count = current_user.projects.completed.count
init_data_for_sidebar
render :template => 'projects/update.js.rjs'
return
elsif boolean_param('update_status')
@ -173,7 +173,7 @@ class ProjectsController < ApplicationController
end
def order
project_ids = params["list-active-projects"] || params["list-hidden-projects"] || params["list-completed-projects"]
project_ids = params["container_project"]
@projects = current_user.projects.update_positions( project_ids )
render :nothing => true
rescue
@ -186,6 +186,7 @@ class ProjectsController < ApplicationController
@projects = current_user.projects.alphabetize(:state => @state) if @state
@contexts = current_user.contexts
init_not_done_counts(['project'])
init_project_hidden_todo_counts(['project']) if @state == 'hidden'
end
def actionize
@ -193,6 +194,7 @@ class ProjectsController < ApplicationController
@projects = current_user.projects.actionize(current_user.id, :state => @state) if @state
@contexts = current_user.contexts
init_not_done_counts(['project'])
init_project_hidden_todo_counts(['project']) if @state == 'hidden'
end
protected

View file

@ -251,8 +251,6 @@ class RecurringTodosController < ApplicationController
@xth_day = [['first',1],['second',2],['third',3],['fourth',4],['last',5]]
@projects = current_user.projects.find(:all, :include => [:default_context])
@contexts = current_user.contexts.find(:all)
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_tags_map = build_default_project_tags_map(@projects).to_json
end
def get_recurring_todo_from_param
@ -265,4 +263,4 @@ class RecurringTodosController < ApplicationController
recurring_todos.each { |rt| rt.toggle_completion! if rt.todos.not_completed.count == 0}
end
end
end

View file

@ -95,6 +95,7 @@ class TodosController < ApplicationController
@projects = current_user.projects.find(:all) if @new_project_created
@initial_context_name = params['default_context_name']
@initial_project_name = params['default_project_name']
@default_tags = @todo.project.default_tags unless @todo.project.nil?
render :action => 'create'
end
format.xml do
@ -358,8 +359,6 @@ class TodosController < ApplicationController
@not_done_todos = current_user.deferred_todos
@count = @not_done_todos.size
@down_count = @count
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_tags_map = build_default_project_tags_map(@projects).to_json
respond_to do |format|
format.html
@ -434,10 +433,7 @@ class TodosController < ApplicationController
@down_count = @count
respond_to do |format|
format.html {
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_tags_map = build_default_project_tags_map(@projects).to_json
}
format.html
format.m {
cookies[:mobile_url]= {:value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
render :action => "mobile_tag"
@ -471,8 +467,6 @@ class TodosController < ApplicationController
@page_title = "TRACKS::Calendar"
@projects = current_user.projects.find(:all)
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_tags_map = build_default_project_tags_map(@projects).to_json
due_today_date = Time.zone.now
due_this_week_date = Time.zone.now.end_of_week
@ -757,9 +751,6 @@ class TodosController < ApplicationController
end
end
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_tags_map = build_default_project_tags_map(@projects).to_json
render
end
end

View file

@ -166,4 +166,17 @@ module ApplicationHelper
return rt+rp+rts
end
def date_format_for_date_picker()
standard_format = current_user.prefs.date_format
translations = [
['%m', 'mm'],
['%d', 'dd'],
['%Y', 'yy'],
['%y', 'y']
]
translations.inject(standard_format) do |str, translation|
str.gsub(*translation)
end
end
end

View file

@ -11,19 +11,15 @@ module RecurringTodosHelper
end
def recurring_todo_remote_delete_icon
str = link_to( image_tag_for_delete,
link_to( image_tag_for_delete,
recurring_todo_path(@recurring_todo), :id => "delete_icon_"+@recurring_todo.id.to_s,
:class => "icon delete_icon", :title => "delete the recurring action '#{@recurring_todo.description}'")
set_behavior_for_delete_icon
str
end
def recurring_todo_remote_star_icon
str = link_to( image_tag_for_star(@recurring_todo),
link_to( image_tag_for_star(@recurring_todo),
toggle_star_recurring_todo_path(@recurring_todo),
:class => "icon star_item", :title => "star the action '#{@recurring_todo.description}'")
set_behavior_for_star_icon
str
end
def recurring_todo_remote_edit_icon
@ -31,7 +27,6 @@ module RecurringTodosHelper
str = link_to( image_tag_for_edit(@recurring_todo),
edit_recurring_todo_path(@recurring_todo),
:class => "icon edit_icon")
set_behavior_for_edit_icon
else
str = '<a class="icon">' + image_tag("blank.png") + "</a> "
end
@ -40,7 +35,6 @@ module RecurringTodosHelper
def recurring_todo_remote_toggle_checkbox
str = check_box_tag('item_id', toggle_check_recurring_todo_path(@recurring_todo), @recurring_todo.completed?, :class => 'item-checkbox')
set_behavior_for_toggle_checkbox
str
end
@ -53,26 +47,4 @@ module RecurringTodosHelper
def image_tag_for_edit(todo)
image_tag("blank.png", :title =>"Edit action", :class=>"edit_item", :id=> dom_id(todo, 'edit_icon'))
end
def set_behavior_for_delete_icon
parameters = "_source_view=#{@source_view}"
parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
apply_behavior '.item-container a.delete_icon:click', :prevent_default => true do |page|
page.confirming "'Are you sure that you want to ' + this.title + '?'" do
page << "itemContainer = this.up('.item-container'); itemContainer.startWaiting();"
page << remote_to_href(:method => 'delete', :with => "'#{parameters}'", :complete => "itemContainer.stopWaiting();")
end
end
end
def set_behavior_for_edit_icon
parameters = "_source_view=#{@source_view}"
parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
apply_behavior '.item-container a.edit_icon:click', :prevent_default => true do |page|
page << "Effect.Pulsate(this);"
page << remote_to_href(:method => 'get', :with => "'#{parameters}'")
end
end
end
end

View file

@ -8,52 +8,41 @@ module TodosHelper
end
def form_remote_tag_edit_todo( &block )
form_tag(
todo_path(@todo), {
form_remote_tag(
:url => todo_path(@todo),
:loading => "$('#submit_todo_#{@todo.id}').block({message: null})",
:html => {
:method => :put,
:id => dom_id(@todo, 'form'),
:class => dom_id(@todo, 'form') + " inline-form edit_todo_form" },
&block )
apply_behavior 'form.edit_todo_form', make_remote_form(
:method => :put,
:before => "todoSpinner = this.down('button.positive'); todoSpinner.startWaiting()",
:loaded => "todoSpinner.stopWaiting()",
:condition => "!(this.down('button.positive').isWaiting())"),
:prevent_default => true
end
def set_behavior_for_star_icon
apply_behavior '.item-container a.star_item:click',
remote_to_href(:method => 'put', :with => "{ _source_view : '#{@source_view}' }"),
:prevent_default => true
end
def remote_star_icon
str = link_to( image_tag_for_star(@todo),
link_to( image_tag_for_star(@todo),
toggle_star_todo_path(@todo),
:class => "icon star_item", :title => "star the action '#{@todo.description}'")
set_behavior_for_star_icon
str
end
def remote_edit_menu_item(parameters, todo)
return link_to_remote(
image_tag("edit_off.png", :mouseover => "edit_on.png", :alt => "", :align => "absmiddle")+" Edit",
image_tag("edit_off.png", :mouseover => "edit_on.png", :alt => "Edit", :align => "absmiddle", :id => 'edit_icon_todo_'+todo.id.to_s)+" Edit",
:url => {:controller => 'todos', :action => 'edit', :id => todo.id},
:method => 'get',
:with => "'#{parameters}'",
:before => todo_start_waiting_js(todo),
:complete => todo_stop_waiting_js)
:complete => todo_stop_waiting_js(todo))
end
def remote_delete_menu_item(parameters, todo)
return link_to_remote(
image_tag("delete_off.png", :mouseover => "delete_on.png", :alt => "", :align => "absmiddle")+" Delete",
image_tag("delete_off.png", :mouseover => "delete_on.png", :alt => "Delete", :align => "absmiddle")+" Delete",
:url => {:controller => 'todos', :action => 'destroy', :id => todo.id},
:method => 'delete',
:with => "'#{parameters}'",
:before => todo_start_waiting_js(todo),
:complete => todo_stop_waiting_js)
:complete => todo_stop_waiting_js(todo),
:confirm => "Are you sure that you want to delete the action '#{todo.description}'?")
end
def remote_defer_menu_item(days, todo)
@ -64,24 +53,24 @@ module TodosHelper
futuredate = (@todo.show_from || @todo.user.date) + days.days
if @todo.due && futuredate > @todo.due
return link_to_function(
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => "", :align => "absmiddle")+" Defer #{pluralize(days, "day")}",
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => "Defer #{pluralize(days, "day")}", :align => "absmiddle")+" Defer #{pluralize(days, "day")}",
"alert('Defer date is after due date. Please edit and adjust due date before deferring.')"
)
else
return link_to_remote(
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => "", :align => "absmiddle")+" Defer #{pluralize(days, "day")}",
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => "Defer #{pluralize(days, "day")}", :align => "absmiddle")+" Defer #{pluralize(days, "day")}",
:url => url,
:before => todo_start_waiting_js(todo),
:complete => todo_stop_waiting_js)
:complete => todo_stop_waiting_js(todo))
end
end
def todo_start_waiting_js(todo)
return "$('ul#{dom_id(todo)}').hide(); itemContainer = $('#{dom_id(todo)}'); itemContainer.startWaiting()"
return "$('#ul#{dom_id(todo)}').css('visibility', 'hidden'); $('##{dom_id(todo)}').block({message: null})"
end
def todo_stop_waiting_js
return "itemContainer.stopWaiting();"
def todo_stop_waiting_js(todo)
return "$('##{dom_id(todo)}').unblock();enable_rich_interaction();"
end
def image_tag_for_recurring_todo(todo)
@ -91,18 +80,9 @@ module TodosHelper
:class => "recurring_icon", :title => recurrence_pattern_as_text(todo.recurring_todo))
end
def set_behavior_for_toggle_checkbox
parameters = "_source_view=#{@source_view}"
parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
apply_behavior '.item-container input.item-checkbox:click',
remote_function(:url => javascript_variable('this.value'), :method => 'put',
:with => "'#{parameters}'")
end
def remote_toggle_checkbox
str = check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox')
set_behavior_for_toggle_checkbox
str
check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox')
end
def date_span
@ -213,10 +193,11 @@ module TodosHelper
end
def calendar_setup( input_field )
str = "Calendar.setup({ ifFormat:\"#{prefs.date_format}\""
str << ",firstDay:#{prefs.week_starts},showOthers:true,range:[2004, 2010]"
str << ",step:1,inputField:\"" + input_field + "\",cache:true,align:\"TR\" })\n"
javascript_tag str
# TODO:jQuery
#str = "Calendar.setup({ ifFormat:\"#{prefs.date_format}\""
#str << ",firstDay:#{prefs.week_starts},showOthers:true,range:[2004, 2010]"
#str << ",step:1,inputField:\"" + input_field + "\",cache:true,align:\"TR\" })\n"
#javascript_tag str
end
def item_container_id (todo)
@ -224,7 +205,7 @@ module TodosHelper
return "p#{todo.project_id}items" if todo.active?
return "tickler" if todo.deferred?
end
return "c#{todo.context_id}"
return "c#{todo.context_id}items"
end
def should_show_new_item
@ -266,6 +247,20 @@ module TodosHelper
array_or_string_for_javascript( current_user.contexts.collect{|c| escape_javascript(c.name) } )
end
def tag_names_for_autocomplete
array_or_string_for_javascript( Tag.all.collect{|c| escape_javascript(c.name) } )
end
def default_contexts_for_autocomplete
projects = current_user.projects.find(:all, :conditions => ['default_context_id is not null'])
Hash[*projects.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
end
def default_tags_for_autocomplete
projects = current_user.projects.find(:all, :conditions => ['default_tags != ""'])
Hash[*projects.map{ |p| [p.name, p.default_tags] }.flatten].to_json
end
def format_ical_notes(notes)
split_notes = notes.split(/\n/)
joined_notes = split_notes.join("\\n")

View file

@ -10,6 +10,13 @@ class User < ActiveRecord::Base
def find_by_params(params)
find(params['id'] || params['context_id']) || nil
end
def update_positions(context_ids)
context_ids.each_with_index do |id, position|
context = self.detect { |c| c.id == id.to_i }
raise "Context id #{id} not associated with user id #{@user.id}." if context.nil?
context.update_attribute(:position, position + 1)
end
end
end
has_many :projects,
:order => 'projects.position ASC',

View file

@ -3,31 +3,9 @@
<h2>
<% if collapsible -%>
<a href="#" class="container_toggle" id="toggle_c<%= context.id %>"><%= image_tag("collapse.png") %></a>
<% apply_behavior '.container_toggle:click', :prevent_default => true do |page|
page << " /* only handle the click if a previous click had finished its animation */
if (todoItems.lastEffect == null || todoItems.lastEffect.state=='finished') {
containerElem = this.up('.container')
toggleTarget = containerElem.down('.toggle_target')
if (Element.visible(toggleTarget))
{
todoItems.collapseNextActionListing(this, toggleTarget);
todoItems.contextCollapseCookieManager.setCookie(todoItems.buildCookieName(containerElem), true)
}
else
{
todoItems.expandNextActionListing(this, toggleTarget);
todoItems.contextCollapseCookieManager.clearCookie(todoItems.buildCookieName(containerElem))
}
}
"
end
-%>
<% end -%>
<% if source_view_is :context %>
<span class="in_place_editor_field" id="context_name_in_place_editor"><%= context.name %></span>
<%= in_place_editor 'context_name_in_place_editor', {
:url => { :controller => 'contexts', :action => 'update', :id => context.id, :field => 'name', :update_context_name => true, :escape => false},
:options=>"{method:'put'}", :script => true } %>
<span id="context_name"><%= context.name %></span>
<% else %>
<%= link_to_context( context ) %>
<% end %>
@ -37,11 +15,5 @@
<div class="message"><p>Currently there are no incomplete actions in this context</p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %>
<% if @not_done.empty?
# fix (hack) for #713
set_behavior_for_star_icon
set_behavior_for_toggle_checkbox
end
-%>
</div><!-- [end:items] -->
</div><!-- [end:c<%= context.id %>] -->
</div><!-- [end:c<%= context.id %>] -->

View file

@ -1,35 +1,28 @@
<% context = context_form
@context = context-%>
<div id="<%= dom_id(context, 'edit') %>" class="edit-form" style="display:none;">
<% form_tag(context_path(context), {:id => dom_id(context, 'edit_form'), :class => "inline-form "+dom_id(context, 'edit_form')+"-edit-context-form edit-context-form", :method => :put}) do -%>
<%= error_messages_for 'context' %>
<label for="context_name">Context name</label><br/>
<%= text_field('context', 'name', :class => 'context-name') %><br/>
<% form_remote_tag(:url => context_path(context), :html => {:id => dom_id(context, 'edit_form'), :class => "inline-form "+dom_id(context, 'edit_form')+"-edit-context-form edit-context-form", :method => :put}) do -%>
<%= error_messages_for 'context' %>
<label for="context_hide">Hide from front page?</label>
<%= check_box('context', 'hide', :class => 'context-hide') %>
<input type="hidden" name="wants_render" value="true" />
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="<%= dom_id(context, 'submit') %>" tabindex="15">
<%=image_tag("accept.png", :alt => "") %>
Update
</button>
<a href="javascript:void(0);" onclick="Element.toggle('<%= dom_id(context) %>');Element.toggle('<%= dom_id(context, 'edit') %>');" class="negative">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
</a>
</div>
<label for="context_name">Context name</label><br/>
<%= text_field('context', 'name', :class => 'context-name') %><br/>
<label for="context_hide">Hide from front page?</label>
<%= check_box('context', 'hide', :class => 'context-hide') %>
<input type="hidden" name="wants_render" value="true" />
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="<%= dom_id(context, 'submit') %>" tabindex="15">
<%=image_tag("accept.png", :alt => "") %>
Update
</button>
<a href="" onclick="" class="negative">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
</a>
</div>
<br/><br/>
<% end %>
<%= apply_behavior ".edit-context-form", make_remote_form(
:before => "this.up('div.edit-form').down('button.positive').startWaiting()",
:condition => "!(this.up('div.edit-form').down('button.positive')).isWaiting()"),
:external => true
@context = nil %>
</div>
</div>
<br/><br/>
<% end %>

View file

@ -19,23 +19,25 @@
<% else %>
<span class="grey">VISIBLE</span>
<% end %>
<a class="delete_context_button" href="<%= formatted_context_path(context, :js) %>" title="delete the context '<%= context.name %>'"><%= image_tag( "blank.png", :title => "Delete context", :class=>"delete_item") %></a>
<%= apply_behavior "a.delete_context_button:click", { :prevent_default => true, :external => true} do |page, element|
page.confirming "'Are you sure that you want to ' + this.title + '?'" do
element.up('.context').start_waiting
page << remote_to_href(:method => 'delete')
end
end -%>
<a class="edit_context_button" href="#"><%= image_tag( "blank.png", :title => "Edit context", :class=>"edit_item") %></a>
<%= apply_behavior 'a.edit_context_button:click', :prevent_default => true do |page, element|
element.up('.context').toggle
editform = element.up('.list').down('.edit-form')
editform.toggle
editform.visual_effect(:appear)
editform.down('input').focus
end
-%>
<%= link_to_remote(
image_tag( "blank.png", :title => "Delete context", :class=>"delete_item"),
:url => {:controller => 'contexts', :action => 'destroy', :id => context.id},
:method => 'delete',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(context)}').block({message:null});",
:complete => "$('#{dom_id(context)}').unblock();",
:confirm => "Are you sure that you want to delete the context '#{context.name}'?"
) %>
<%= link_to_remote(
image_tag( "blank.png", :title => "Edit context", :class=>"edit_item"),
:url => {:controller => 'contexts', :action => 'edit', :id => context.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(context)}').block({message:null});",
:complete => "$('#{dom_id(context)}').unblock();"
) %>
</div>
</div>
<%= render :partial => 'contexts/context_form', :object => context %>
</div>
<div id="<%= dom_id(context, 'edit') %>" class="edit-form" style="display:none;">
</div>
</div>

View file

@ -1,12 +1,12 @@
if @saved
container_name = 'list-contexts-' + (@context.hidden? ? 'hidden' : 'active')
page.hide 'contexts-empty-nd'
page.insert_html :bottom, "list-contexts", :partial => 'context_listing', :locals => { :context_listing => @context }
page.sortable "list-contexts", get_listing_sortable_options
page.insert_html :bottom, container_name, :partial => 'context_listing', :locals => { :context_listing => @context }
page.hide 'status'
page['badge_count'].replace_html @down_count
page.call "Form.reset", "context-form"
page.call "Form.focusFirstElement", "context-form"
page << '$("#context-form").clearForm();'
page << '$("#context-form input:text:first").focus();'
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('context')}"
end
end

View file

@ -0,0 +1,4 @@
page[dom_id(@context, 'edit')].replace_html :partial => 'context_form', :locals => { :context_form => @context }
page[@context].hide
page[dom_id(@context, 'edit')].show
page[dom_id(@context, 'edit_form')].find('input.context-name').focus

View file

@ -8,12 +8,6 @@
<div id="toggle_context_new" class="hide_form">
<a title="Hide new context form" accesskey="n">&laquo; Hide form</a>
<% apply_behavior '#toggle_context_new a:click', :prevent_default => true do |page|
page << "TracksForm.toggle('toggle_context_new', 'context_new', 'context-form',
'&laquo; Hide form', 'Hide new context form',
'Create a new context &#187;', 'Add a context');"
end
%>
</div>
<div id="context_new" class="context_new" style="display:block">
@ -21,9 +15,8 @@
:url => contexts_path,
:method => :post,
:html=> { :id => 'context-form', :name => 'context', :class => 'inline-form'},
:before => "$('context_new_submit').startWaiting()",
:complete => "$('context_new_submit').stopWaiting()",
:condition => "!$('context_new_submit').isWaiting()") do -%>
:before => "$('#context_new_submit').block({message: null})",
:complete => "$('#context_new_submit').unblock()") do -%>
<div id="status"><%= error_messages_for('context') %></div>
@ -49,8 +42,3 @@
sortable_element 'list-contexts-active', get_listing_sortable_options
sortable_element 'list-contexts-hidden', get_listing_sortable_options
-%>
<script type="text/javascript">
window.onload=function(){
Nifty("div#context_new_container","normal");
}
</script>

View file

@ -1,12 +1,9 @@
status_message = 'Context saved'
page.notify :notice, status_message, 5.0
if @context_state_changed
page << "jQuery('##{dom_id(@context, 'edit')}').hide();"
page.remove dom_id(@context, 'container')
page.insert_html :bottom, "list-contexts-#{@new_state}", :partial => 'context_listing', :object => @context
else
page.replace_html dom_id(@context, 'container'), :partial => 'context_listing', :object => @context
end
page.sortable "list-contexts-active", get_listing_sortable_options
page.sortable "list-contexts-hidden", get_listing_sortable_options
page.hide "busy"
page.visual_effect :highlight, dom_id(@context), :duration => 3

View file

@ -34,9 +34,3 @@
</table>
</div><!-- End of feeds -->
</div>
<script type="text/javascript">
window.onload=function(){
Nifty("div#feedlegend","normal");
}
</script>

View file

@ -15,9 +15,3 @@
</p>
</div><!-- End of feeds -->
</div><!-- End of display_box -->
<script type="text/javascript">
window.onload=function(){
Nifty("div#feedlegend","normal");
}
</script>

View file

@ -125,11 +125,3 @@
<div id="input_box">
<%= render :file => "sidebar/sidebar.html.erb" %>
</div><!-- End of input box -->
<script type="text/javascript">
window.onload=function(){
Nifty("div#feedicons-project","normal");
Nifty("div#feedicons-context","normal");
Nifty("div#feedlegend","normal");
}
</script>

View file

@ -3,7 +3,8 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= stylesheet_link_tag "scaffold" %>
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag 'jquery' %>
<%= javascript_include_tag 'jquery.cookie' %>
<title><%= @page_title -%></title>

View file

@ -6,22 +6,35 @@
<meta http-equiv="Refresh" content="<%= @prefs["refresh"].to_i*60 %>;url=<%= request.request_uri %>">
<% end -%>
<% bundle :name => "tracks_css" do %>
<%= stylesheet_link_tag *%w[ standard superfish calendar-system niftyCorners] %>
<%= stylesheet_link_tag *%w[ standard superfish niftyCorners jquery-ui jquery.autocomplete] %>
<% end %>
<%= stylesheet_link_tag "print", :media => "print" %>
<% bundle :name => "jquery" do %>
<%= javascript_include_tag "jquery-1.2.6.min" %>
<%= javascript_include_tag 'jquery' %>
<%= javascript_include_tag 'jquery-ui' %>
<%= javascript_include_tag 'jquery.cookie' %>
<%= javascript_include_tag 'jquery.blockUI' %>
<%= javascript_include_tag 'jquery.jeditable' %>
<%= javascript_include_tag 'jquery.autocomplete' %>
<% end %>
<% bundle :name => "tracks_js" do %>
<%= javascript_include_tag *%w[
hoverIntent superfish prototype
effects dragdrop controls application
calendar calendar-en calendar-setup
accesskey-hints todo-items niftycube
protoload flashobject lowpro
] %>
hoverIntent superfish application
accesskey-hints niftycube flashobject ] %>
<% end %>
<%= javascript_include_tag :unobtrusive %>
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>
<%= javascript_tag "var SOURCE_VIEW = '#{@source_view}';" %>
<%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %>
<script type="text/javascript">
<% if defined? context_names_for_autocomplete -%>
var contextNames = <%= context_names_for_autocomplete %>;
var projectNames = <%= project_names_for_autocomplete %>;
var defaultContexts = <%= default_contexts_for_autocomplete %>;
var defaultTags = <%= default_tags_for_autocomplete %>;
var tagNames = <%= tag_names_for_autocomplete %>;
var dateFormat = '<%= date_format_for_date_picker %>';
<% end -%>
</script>
<link rel="shortcut icon" href="<%= url_for(:controller => 'favicon.ico') %>" />
<%= auto_discovery_link_tag(:rss, {:controller => "todos", :action => "index", :format => 'rss', :token => "#{current_user.token}"}, {:title => "RSS feed of next actions"}) %>
<link rel="search" type="application/opensearchdescription+xml" title="Tracks" href="<%= search_plugin_path %>" />
@ -93,36 +106,5 @@
</div>
<%= render :partial => "shared/footer" %>
<script type="text/javascript">
jQuery(document).ready(function() { /* main menu */
jQuery('ul.sf-menu').superfish({
delay: 250,
animation: {opacity:'show',height:'show'},
autoArrows: false,
dropShadows: false,
speed: 'fast'
});
jQuery('ul.sf-item-menu').superfish({ /* context menu */
delay: 100,
animation: {opacity:'show',height:'show'},
autoArrows: false,
dropShadows: false,
speed: 'fast',
onBeforeShow: function() { /* highlight todo */
$(this.parent().parent().parent()).addClass("sf-item-selected");
},
onHide: function() { /* remove hightlight from todo */
$(this.parent().parent().parent()).removeClass("sf-item-selected");
}
});
/* for toggle notes link in mininav */
jQuery("#toggle-notes-nav").click(function () { jQuery(".todo_notes").toggle(); });
/* show the notes of a todo */
TodoBehavior.enableToggleNotes();
Nifty("div#todo_new_action_container","normal");
if ($('flash').visible()) { new Effect.Fade("flash",{duration:5.0}); }
});
</script>
</body>
</html>

View file

@ -61,7 +61,7 @@
<script type="text/javascript">
function showPreferredAuth() {
var preferredAuth = new CookieManager().getCookie('preferred_auth');
var preferredAuth = $.cookie('preferred_auth');
var databaseEnabled = <%= show_database_form ? 'true' : 'false' %>;
var openidEnabled = <%= show_openid_form ? 'true' : 'false' %>;
if (preferredAuth && preferredAuth == 'openid' && openidEnabled) {
@ -74,5 +74,28 @@ function showPreferredAuth() {
Login.showOpenid();
}
}
Event.observe(window, 'load', showPreferredAuth);
</script>
$(document).ready(showPreferredAuth);
var Login = {
showOpenid: function() {
$('#database_auth_form').hide();
$('#openid_auth_form').show();
$('#alternate_auth_openid').hide();
$('#alternate_auth_database').show();
$('#openid_url').focus();
$('#openid_url').select();
$.cookie('preferred_auth', 'openid');
},
showDatabase: function(container) {
$('#openid_auth_form').hide();
$('#database_auth_form').show();
$('#alternate_auth_database').hide();
$('#alternate_auth_openid').show();
$('#user_login').focus();
$('#user_login').select();
$.cookie('preferred_auth', 'database');
}
}
</script>

View file

@ -12,13 +12,13 @@
:id => "delete_note_"+note.id.to_s),
{:update => dom_id(note),
:loading => visual_effect(:fade, dom_id(note, 'container')),
:complete => "Element.remove('#{dom_id(note, 'container')}');",
:complete => "$('#{dom_id(note, 'container')}').remove();",
:url => note_path(note),
:method => :delete,
:confirm => "Are you sure that you want to delete the note \'#{note.id.to_s}\'?" },
{ :class => 'delete_note' }) -%>&nbsp;
<%= link_to_function(image_tag( "blank.png", :title => "Edit item", :class=>"edit_item"),
"Element.toggle('#{dom_id(note)}'); Element.toggle('#{dom_id(note, 'edit')}'); Effect.Appear('#{dom_id(note, 'edit')}'); Form.focusFirstElement('#{dom_id(note, 'edit_form')}');" ) + " | " %>
"$('##{dom_id(note)}').toggle(); $('##{dom_id(note, 'edit')}').show(); $('##{dom_id(note, 'edit_form')} textarea').focus();" ) + " | " %>
<%= link_to("In: " + note.project.name, project_path(note.project), :class=>"footer_link" ) %>&nbsp;|&nbsp;
Created: <%= format_date(note.created_at) %>
<% if note.updated_at? -%>
@ -37,4 +37,4 @@
<% end -%>
</div>
</div>
<% note = nil -%>
<% note = nil -%>

View file

@ -1,6 +0,0 @@
<div class="page_name_auto_complete" id="default_context_list" style="display:none;z-index:9999"></div>
<script type="text/javascript">
defaultContextAutoCompleter = new Autocompleter.Local('project_default_context_name', 'default_context_list', <%= context_names_for_autocomplete %>, {choices:100,autoSelect:false});
Event.observe($('project_default_context_name'), "focus", defaultContextAutoCompleter.activate.bind(defaultContextAutoCompleter));
Event.observe($('project_default_context_name'), "click", defaultContextAutoCompleter.activate.bind(defaultContextAutoCompleter));
</script>

View file

@ -1,10 +1,5 @@
<div class="container">
<h2>
<% if collapsible -%>
<a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a>
<% end -%>
<%= project.name -%>
</h2>
<h2 id="project_name"><% if collapsible %><a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a><% end %><%= project.name -%></h2>
<div id="<%= dom_id(project, "container")%>">
<%= render :partial => "projects/project_settings", :locals => { :project => project, :collapsible => collapsible } %>
</div>
@ -17,11 +12,5 @@
<div class="message"><p>Currently there are no incomplete actions in this project</p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "project" } %>
<% if @not_done.empty?
# fix (hack) for #713
set_behavior_for_star_icon
set_behavior_for_toggle_checkbox
end
-%>
</div>
</div>

View file

@ -1,7 +1,8 @@
<%
project = project_form
%>
<% form_tag project_path(project), { :id => dom_id(project, 'edit_form'), :class => "inline-form "+dom_id(project, 'edit_form')+"-edit-project-form", :method => :put } do -%>
<% form_remote_tag(:url => project_path(project), :html => { :id => dom_id(project, 'edit_form'), :class => "inline-form "+dom_id(project, 'edit_form')+"-edit-project-form", :method => :put }) do -%>
<%= source_view_tag( @source_view ) -%>
@ -18,7 +19,6 @@ project = project_form
<label for="project[default_context_name]">Default Context</label><br/>
<%= text_field_tag("project[default_context_name]", project.default_context.name, {:tabindex=>1,:size=> 25}) %>
<%= render :partial => 'default_context_autocomplete' %>
<br/>
<label for="project[default_tags]">Default Tags</label><br/>
@ -32,7 +32,7 @@ project = project_form
<%=image_tag("accept.png", :alt => "") %>
Update
</button>
<a href="javascript:void(0);" id="<%= dom_id(project, 'cancel') %>" onclick="Element.toggle('<%= dom_id(project) %>');Element.toggle('<%= dom_id(project, 'edit') %>');" class="negative">
<a href="#" id="<%= dom_id(project, 'cancel') %>" class="negative">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
</a>
@ -42,7 +42,3 @@ project = project_form
<% end -%>
<%= apply_behavior "."+dom_id(project, 'edit_form')+"-edit-project-form", make_remote_form(
:before => "$('"+dom_id(project, 'submit')+"').startWaiting();",
:condition => "!$('"+dom_id(project, 'submit')+"').isWaiting()",
:external => false) %>

View file

@ -19,20 +19,15 @@ suppress_edit_button ||= false
title="delete the project '<%= project.name %>'"><%= image_tag( "blank.png",
:title => "Delete project",
:class=>"delete_item") %></a>
<%= apply_behavior "a.delete_project_button:click", { :prevent_default => true, :external => true } do |page, element|
page.confirming "'Are you sure that you want to ' + this.title + '?'" do
element.up('.project').start_waiting
page << remote_to_href(:method => 'delete')
end
end -%>
<% unless suppress_edit_button -%>
<%= link_to_remote(
image_tag( "blank.png", :title => "Edit project", :class=>"edit_item"),
:url => {:controller => 'projects', :action => 'edit', :id => project.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(project)}').startWaiting();",
:complete => "$('#{dom_id(project)}').stopWaiting();"
:before => "$('#{dom_id(project)}').block({message:null});",
:complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();"
) %>
<% end -%>
@ -42,8 +37,3 @@ suppress_edit_button ||= false
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
</div>
</div>
<% if controller.action_name == 'create' %>
<script>
new Effect.Appear('<%= dom_id(project) %>');
</script>
<% end %>

View file

@ -19,8 +19,8 @@
:url => {:controller => 'projects', :action => 'edit', :id => project.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(project)}').startWaiting();",
:complete => "$('#{dom_id(project)}').stopWaiting();"
:before => "$('#{dom_id(project)}').block({message: null});",
:complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();"
) %>
</div>
<% unless project.description.blank? -%>
@ -28,4 +28,4 @@
<% end -%>
</div>
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
</div>
</div>

View file

@ -4,28 +4,13 @@
<div class="alpha_sort">
<%= link_to("Alphabetically", alphabetize_projects_path(:state => state),
:class => "alphabetize_link", :title => "Sort these projects alphabetically") %>
<% apply_behavior '.alphabetize_link:click', :prevent_default => true do |page, element|
page.confirming 'Are you sure that you want to sort these projects alphabetically? This will replace the existing sort order.' do
page << "alphaSort = this.up('.alpha_sort');
alphaSort.startWaiting();"
page << remote_to_href(:complete => "alphaSort.stopWaiting()")
end
end
%></div><span class="sort_separator">&nbsp;|&nbsp;</span><div class="tasks_sort">
</div><span class="sort_separator">&nbsp;|&nbsp;</span><div class="tasks_sort">
<%= link_to("By number of tasks", actionize_projects_path(:state => state),
:class => "actionize_link", :title => "Sort these projects by number of tasks") %>
<% apply_behavior '.actionize_link:click', :prevent_default => true do |page, element|
page.confirming 'Are you sure that you want to sort these projects by the number of tasks? This will replace the existing sort order.' do
page << "tasksSort = this.up('.tasks_sort');
tasksSort.startWaiting();"
page << remote_to_href(:complete => "tasksSort.stopWaiting()")
end
end
%></div>
</div>
</div>
<div id="list-<%= state %>-projects" class="project-list">
<%= render :partial => 'project_listing', :collection => project_state_group %>
</div>
<%= sortable_element "list-#{state}-projects", get_listing_sortable_options("list-#{state}-projects") %>
</div>

View file

@ -8,10 +8,10 @@ elsif @saved
page.replace_html "active-projects-count", @active_projects_count
page.insert_html :bottom, "list-active-projects", :partial => 'project_listing', :locals => { :project_listing => @project }
page.sortable "list-active-projects", get_listing_sortable_options('list-active-projects')
page.call "Form.reset", "project-form"
page.call "Form.focusFirstElement", "project-form"
page << "$('#project-form').clearForm();"
page << "$('#project-form input:text:first').focus();"
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('project')}"
end
page.hide "busy"
page.hide "busy"

View file

@ -1,4 +1,4 @@
page[dom_id(@project, 'edit')].replace_html :partial => 'project_form', :locals => { :project_form => @project }
page[@project].hide
page[dom_id(@project, 'edit')].show
page[dom_id(@project, 'edit_form')].down('input.project-name').focus
page[dom_id(@project, 'edit_form')].find('input.project-name').focus

View file

@ -14,20 +14,13 @@
<div id="toggle_project_new" class="hide_form">
<a title="Hide new project form" accesskey="n">&laquo; Hide form</a>
<% apply_behavior '#toggle_project_new a:click', :prevent_default => true do |page|
page << "TracksForm.toggle('toggle_project_new', 'project_new', 'project-form',
'&laquo; Hide form', 'Hide new project form',
'Create a new project &#187;', 'Add a project');"
end
%>
</div>
<div id="project_new" class="project_new" style="display:block">
<% form_remote_tag(:url => projects_path, :method => :post,
:html=> { :id=>'project-form', :name=>'project', :class => 'inline-form'},
:before => "$('project_new_project_submit').startWaiting()",
:complete => "$('project_new_project_submit').stopWaiting()",
:condition => "!$('project_new_project_submit').isWaiting()") do -%>
:before => "$('#project_new_project_submit').block({message:null})",
:complete => "$('#project_new_project_submit').unblock()") do -%>
<div id="status"><%= error_messages_for('project') %></div>
@ -40,7 +33,6 @@
<% unless @contexts.empty? -%>
<label for="default_context_name">Default Context (optional):</label><br />
<%= text_field_tag("project[default_context_name]", @project.default_context.name, :tabindex => 3) %>
<%= render :partial => 'default_context_autocomplete' %>
<br />
<% end -%>

View file

@ -11,7 +11,7 @@
<div class="container">
<div id="notes">
<div class="add_note_link"><%= link_to_function( "Add a note", "Element.toggle('new-note'); Form.focusFirstElement('form-new-note');", :id=>"add_note_href") %></div>
<div class="add_note_link"><%= link_to 'Add a note', '#' %> </div>
<h2>Notes</h2>
<div id="empty-n" style="display:<%= @project.notes.empty? ? 'block' : 'none'%>;">
<%= render :partial => "shared/empty",
@ -26,7 +26,7 @@
:method => :post,
:update => "notes",
:position => "bottom",
:complete => "new Effect.Highlight('notes');$('empty-n').hide();Form.reset('form-new-note');",
:complete => "$('#notes').effect('highlight', 1000);$('#empty-n').hide();$('#new-note form').clearForm();",
:html => {:id=>'form-new-note', :class => 'inline-form'} do %>
<%= hidden_field( "new_note", "project_id", "value" => "#{@project.id}" ) %>
<%= text_area( "new_note", "body", "cols" => 50, "rows" => 3, "tabindex" => 1 ) %>
@ -39,4 +39,4 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render :file => "sidebar/sidebar.html.erb" %>
</div><!-- End of input box -->
</div><!-- End of input box -->

View file

@ -19,4 +19,14 @@ else
page[dom_id(@project, 'edit')].hide
page.replace_html dom_id(@project, 'container'), :partial => 'project_settings', :locals => { :project => @project }
page[dom_id(@project)].show
page['todo_context_name'].value = @project.default_context.name if @project.default_context
page['#todo_project_name'].value = @project.name
page['tag_list'].value = @project.default_tags if @project.default_tags
page << "$('input[name=default_context_name]').val('#{@project.default_context.name}');" if @project.default_context
page << "defaultContexts = #{default_contexts_for_autocomplete};"
page << "defaultTags = #{default_tags_for_autocomplete};"
end
page.replace_html "sidebar", :file => 'sidebar/sidebar.html.erb'

View file

@ -1,10 +1,8 @@
page['project_name_in_place_editor'].replace_html @project.name
page['default_project_name_id'].value = @project.name
page['todo_project_name'].value = @project.name
# renew project auto complete array
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}; projectAutoCompleter.changed = true"
page << "var projectNames = #{project_names_for_autocomplete};"
status_message = "Name of project was changed"
page.notify :notice, status_message, 5.0

View file

@ -3,9 +3,9 @@
<% form_remote_tag(
:url => recurring_todo_path(@recurring_todo), :method => :put,
:html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' },
:before => "$('recurring_todo_edit_action_submit').startWaiting()",
:complete => "$('recurring_todo_edit_action_submit').stopWaiting();",
:condition => "!$('recurring_todo_edit_action_submit').isWaiting()") do
:before => "$('#recurring_todo_edit_action_submit').block({message: null})",
:complete => "$('#recurring_todo_edit_action_submit').unblock();$('#recurring-todo-form-edit-action').clearForm();") do
-%>
<div id="edit_status"><%= error_messages_for("item", :object_name => 'action') %></div>
@ -20,59 +20,13 @@
<label for="edit_recurring_todo_project_name">Project</label>
<input id="edit_recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="<%= @recurring_todo.project.nil? ? 'None' : @recurring_todo.project.name.gsub(/"/,"&quot;") %>" />
<div class="page_name_auto_complete" id="edit_project_list" style="display:none"></div>
<script type="text/javascript">
projectAutoCompleter = new Autocompleter.Local('edit_recurring_todo_project_name', 'edit_project_list', <%= project_names_for_autocomplete %>, {choices:100,autoSelect:false});
function selectDefaultContext() {
todoContextNameElement = $('edit_recurring_todo_context_name');
defaultContextName = todoContextNameElement.projectDefaultContextsMap[this.value];
if (defaultContextName && !todoContextNameElement.editedByTracksUser) {
todoContextNameElement.value = defaultContextName;
}
}
function selectDefaultTags() {
todoTagListElement = $('edit_recurring_todo_tag_list');
defaultTagList = todoTagListElement.projectDefaultTagsMap[this.value];
if (defaultTagList && !todoTagListElement.editedByTracksUser) {
todoTagListElement.value = defaultTagList;
}
}
Event.observe($('edit_recurring_todo_project_name'), "focus", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('edit_recurring_todo_project_name'), "click", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('edit_recurring_todo_project_name'), "blur", selectDefaultContext.bind($('edit_recurring_todo_project_name')));
Event.observe($('edit_recurring_todo_project_name'), "blur", selectDefaultTags.bind($('edit_recurring_todo_project_name')));
</script>
<label for="edit_recurring_todo_context_name">Context</label>
<input id="edit_recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%= @recurring_todo.context.name %>" />
<div class="page_name_auto_complete" id="edit_context_list" style="display:none"></div>
<script type="text/javascript">
var contextAutoCompleter;
function initializeNamesForAutoComplete(contextNamesForAutoComplete) {
if (contextNamesForAutoComplete.length == 0 || contextNamesForAutoComplete[0].length == 0) {
return;
}
contextAutoCompleter = new Autocompleter.Local('edit_recurring_todo_context_name', 'edit_context_list', contextNamesForAutoComplete, {choices:100,autoSelect:false});
Event.observe($('edit_recurring_todo_context_name'), "focus", function(){ $('edit_recurring_todo_context_name').editedByTracksUser = true; });
Event.observe($('edit_recurring_todo_context_name'), "focus", contextAutoCompleter.activate.bind(contextAutoCompleter));
Event.observe($('edit_recurring_todo_context_name'), "click", contextAutoCompleter.activate.bind(contextAutoCompleter));
}
function updateContextNamesForAutoComplete(contextNamesForAutoComplete) {
if (contextAutoCompleter) { // i.e. if we're already initialized
contextAutoCompleter.options.array = contextNamesForAutoComplete
} else {
initializeNamesForAutoComplete(contextNamesForAutoComplete)
}
}
initializeNamesForAutoComplete(<%= context_names_for_autocomplete %>);
$('edit_recurring_todo_context_name').projectDefaultContextsMap = eval('(' + <%= @default_project_context_name_map %> + ')');
</script>
<label for="edit_recurring_todo_tag_list">Tags (separate with commas)</label>
<%= text_field_tag "edit_recurring_todo_tag_list", @recurring_todo.tag_list, :size => 30, :tabindex => 5 -%>
<script type="text/javascript">
$('edit_recurring_todo_tag_list').projectDefaultTagsMap = eval('(' + <%= @default_project_tags_map %> + ')');
Event.observe($('edit_recurring_todo_tag_list'), "focus", function(){ $('edit_recurring_todo_tag_list').editedByTracksUser = true; });
</script>
</div>
</div>
<div id="recurring_edit_period_id">
@ -87,13 +41,13 @@
<div id="recurring_timespan">
<br/>
<label for="recurring_todo[start_from]">Starts on </label><%=
text_field_tag("recurring_todo_edit_start_from", format_date(@recurring_todo.start_from), "size" => 12, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %><br/>
text_field_tag("recurring_todo_edit_start_from", format_date(@recurring_todo.start_from), "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %><br/>
<br/>
<label for="recurring_todo[ends_on]">Ends on:</label><br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', @recurring_todo.ends_on == 'no_end_date')%> No end date<br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times', @recurring_todo.ends_on == 'ends_on_number_of_times')%> Ends after <%= text_field_tag("recurring_todo[number_of_occurences]", @recurring_todo.number_of_occurences, "size" => 3, "tabindex" => 7) %> times<br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date', @recurring_todo.ends_on == 'ends_on_end_date')%> Ends on <%=
text_field_tag('recurring_todo_edit_end_date', format_date(@recurring_todo.end_date), "size" => 12, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 8, "autocomplete" => "off") %><br/>
text_field_tag('recurring_todo_edit_end_date', format_date(@recurring_todo.end_date), "size" => 12, "class" => "Date", "tabindex" => 8, "autocomplete" => "off") %><br/>
</div></div>
<div id="recurring_edit_daily" style="display:<%= @recurring_todo.recurring_period == 'daily' ? 'block' : 'none' %> ">
<label>Settings for daily recurring actions</label><br/>
@ -149,13 +103,11 @@
<%=image_tag("accept.png", :alt => "") %>
Update
</button>
<button type="button" class="positive" id="recurring_todo_edit_action_cancel" tabindex="15" onclick="TracksForm.toggle_overlay();">
<button type="button" class="positive" id="recurring_todo_edit_action_cancel" tabindex="15">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
</button>
</div>
</div>
<% end %>
<%= calendar_setup( "recurring_todo_edit_start_from" ) %>
<%= calendar_setup( "recurring_todo_edit_end_date" ) %>
</div>

View file

@ -2,9 +2,8 @@
<% form_remote_tag(
:url => recurring_todos_path, :method => :post,
:html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' },
:before => "$('recurring_todo_new_action_submit').startWaiting()",
:complete => "$('recurring_todo_new_action_submit').stopWaiting();",
:condition => "!$('recurring_todo_new_action_submit').isWaiting()") do
:before => "$('#recurring_todo_new_action_submit').block({message: null})",
:complete => "$('#recurring_todo_new_action_submit').unblock();$('#recurring-todo-form-new-action').clearForm();") do
-%>
<div id="new_status"><%= error_messages_for("item", :object_name => 'action') %></div>
@ -17,59 +16,12 @@
<label for="recurring_todo_project_name">Project</label>
<input id="recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="" />
<div class="page_name_auto_complete" id="project_list" style="display:none"></div>
<script type="text/javascript">
projectAutoCompleter = new Autocompleter.Local('recurring_todo_project_name', 'project_list', <%= project_names_for_autocomplete %>, {choices:100,autoSelect:false});
function selectDefaultContext() {
todoContextNameElement = $('recurring_todo_context_name');
defaultContextName = todoContextNameElement.projectDefaultContextsMap[this.value];
if (defaultContextName && !todoContextNameElement.editedByTracksUser) {
todoContextNameElement.value = defaultContextName;
}
}
Event.observe($('recurring_todo_project_name'), "focus", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('recurring_todo_project_name'), "click", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('recurring_todo_project_name'), "blur", selectDefaultContext.bind($('recurring_todo_project_name')));
</script>
<label for="recurring_todo_context_name">Context</label>
<input id="recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="" />
<div class="page_name_auto_complete" id="context_list" style="display:none"></div>
<script type="text/javascript">
var contextAutoCompleter;
function initializeNamesForAutoComplete(contextNamesForAutoComplete) {
if (contextNamesForAutoComplete.length == 0 || contextNamesForAutoComplete[0].length == 0) {
return;
}
contextAutoCompleter = new Autocompleter.Local('recurring_todo_context_name', 'context_list', contextNamesForAutoComplete, {choices:100,autoSelect:false});
Event.observe($('recurring_todo_context_name'), "focus", function(){ $('recurring_todo_context_name').editedByTracksUser = true; });
Event.observe($('recurring_todo_context_name'), "focus", contextAutoCompleter.activate.bind(contextAutoCompleter));
Event.observe($('recurring_todo_context_name'), "click", contextAutoCompleter.activate.bind(contextAutoCompleter));
}
function updateContextNamesForAutoComplete(contextNamesForAutoComplete) {
if (contextAutoCompleter) { // i.e. if we're already initialized
contextAutoCompleter.options.array = contextNamesForAutoComplete
} else {
initializeNamesForAutoComplete(contextNamesForAutoComplete)
}
}
initializeNamesForAutoComplete(<%= context_names_for_autocomplete %>);
$('recurring_todo_context_name').projectDefaultContextsMap = eval('(' + <%= @default_project_context_name_map %> + ')');
</script>
<label for="tag_list">Tags (separate with commas)</label>
<%= text_field_tag "tag_list", nil, :size => 30, :tabindex => 5 -%>
<script type="text/javascript">
$('tag_list').projectDefaultTagsMap = eval('(' + <%= @default_project_tags_map %> + ')');
function selectDefaultTags() {
todoTagListElement = $('tag_list');
defaultTagList = todoTagListElement.projectDefaultTagsMap[this.value];
if (defaultTagList && !todoTagListElement.editedByTracksUser) {
todoTagListElement.value = defaultTagList;
}
}
Event.observe($('recurring_todo_project_name'), "blur", selectDefaultTags.bind($('recurring_todo_project_name')));
Event.observe($('tag_list'), "focus", function(){ $('tag_list').editedByTracksUser = true; });
</script>
</div>
</div>
<div id="recurring_period_id">
@ -79,18 +31,16 @@
<%= radio_button_tag('recurring_todo[recurring_period]', 'weekly')%> Weekly<br/>
<%= radio_button_tag('recurring_todo[recurring_period]', 'monthly')%> Monthly<br/>
<%= radio_button_tag('recurring_todo[recurring_period]', 'yearly')%> Yearly<br/>
<% apply_behaviour "#recurring_period:click",
"TracksForm.hide_all_recurring(); $('recurring_'+TracksForm.get_period()).show();" %>
</div>
<div id="recurring_timespan">
<br/>
<label for="recurring_todo[start_from]">Starts on </label><%=
text_field(:recurring_todo, :start_from, "value" => format_date(current_user.time), "size" => 12, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %><br/>
text_field(:recurring_todo, :start_from, "value" => format_date(current_user.time), "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %><br/>
<br/>
<label for="recurring_todo[ends_on]">Ends on:</label><br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', true)%> No end date<br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times')%> Ends after <%= text_field( :recurring_todo, :number_of_occurences, "size" => 3, "tabindex" => 7) %> times<br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date')%> Ends on <%= text_field(:recurring_todo, :end_date, "size" => 12, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 8, "autocomplete" => "off", "value" => "") %><br/>
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date')%> Ends on <%= text_field(:recurring_todo, :end_date, "size" => 12, "class" => "Date", "tabindex" => 8, "autocomplete" => "off", "value" => "") %><br/>
</div></div>
<div id="recurring_daily" style="display:block">
<label>Settings for daily recurring actions</label><br/>
@ -147,13 +97,11 @@
<%=image_tag("accept.png", :alt => "") %>
Create
</button>
<button type="button" class="positive" id="recurring_todo_new_action_cancel" tabindex="15" onclick="Form.reset('recurring-todo-form-new-action');Form.focusFirstElement('recurring-todo-form-new-action');TracksForm.hide_all_recurring(); $('recurring_daily').show();TracksForm.toggle_overlay();">
<button type="button" class="positive" id="recurring_todo_new_action_cancel" tabindex="15">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
</button>
</div>
</div>
<% end %>
<%= calendar_setup( "recurring_todo_start_from" ) %>
<%= calendar_setup( "recurring_todo_end_date" ) %>
</div>

View file

@ -4,9 +4,8 @@ page.replace_html 'new_status', "#{error_messages_for('recurring_todo')}"
page.notify :notice, @message, 5.0
if @recurring_saved
# reset form
page << "TracksForm.hide_all_recurring(); $('recurring_daily').show();"
page << "Form.reset('recurring-todo-form-new-action');"
page << "Form.focusFirstElement('recurring-todo-form-new-action');"
page << "TracksForm.hide_all_recurring(); $('#recurring_daily').show();"
page << "$('#recurring_todo_new_action_submit').unblock();$('#recurring-todo-form-new-action').clearForm();"
# hide overlayed edit form
page << "TracksForm.toggle_overlay();"
# insert new recurring todo

View file

@ -33,16 +33,4 @@
<div id="edit-recurring-todo" class="edit-form" style="display:none">
<div class='placeholder'>This should not be visible</div>
</div>
</div><%
# need to add behaviour for edit form here. Behaviour defined in partials are
# not generated for
apply_behaviour "#recurring_edit_period:click",
"TracksForm.hide_all_edit_recurring(); $('recurring_edit_'+TracksForm.get_edit_period()).show();"
-%>
<script type="text/javascript">
window.onload=function(){
Nifty("div#recurring_new_container","normal");
}
</script>
</div>

View file

@ -0,0 +1,3 @@
<% if @saved -%>
$('div#recurring_todo_<%= @recurring_todo.id %> a.star_item img').toggleClass('starred_todo').toggleClass('unstarred_todo');
<% end -%>

View file

@ -1,3 +0,0 @@
if @saved
page[@recurring_todo].down('a.star_item').down('img').toggleClassName('starred_todo').toggleClassName('unstarred_todo')
end

View file

@ -4,6 +4,3 @@
<%= submit_tag "Search" %>
<% end %>
</div>
<script type="text/javascript">
Form.focusFirstElement('search-form')
</script>

View file

@ -9,21 +9,15 @@
<div id="toggle_action_new" class="hide_form">
<a title="Hide new action form" accesskey="n" href="#">&laquo; Hide form</a>
<% apply_behavior '#toggle_action_new a:click', :prevent_default => true do |page|
page << "TracksForm.toggle('toggle_action_new', 'todo_new_action', 'todo-form-new-action',
'&laquo; Hide form', 'Hide next action form',
'Add a next action &#187;', 'Add a next action');"
end
-%>
</div>
<div id="todo_new_action" style="display:block">
<% form_remote_tag(
:url => todos_path, :method => :post,
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' },
:before => "$('todo_new_action_submit').startWaiting()",
:complete => "$('todo_new_action_submit').stopWaiting()",
:condition => "!$('todo_new_action_submit').isWaiting() && askIfNewContextProvided()") do -%>
:before => "$('#todo_new_action_submit').block({message:null})",
:complete => "$('#todo_new_action_submit').unblock()",
:condition => "askIfNewContextProvided()") do -%>
<div id="status"><%= error_messages_for("item", :object_name => 'action') %></div>
@ -44,21 +38,17 @@
<div class="page_name_auto_complete" id="context_list" style="display:none"></div>
<label for="tag_list">Tags (separate with commas)</label>
<%= text_field_tag "tag_list", @initial_tag_name, :size => 30, :tabindex => 5 %>
<%= text_field_tag "tag_list", @default_tags, :size => 30, :tabindex => 5 %>
<%= content_tag("div", "", :id => "tag_list_auto_complete", :class => "auto_complete") %>
<%= auto_complete_field 'tag_list', {
:url => {:controller => 'todos', :action => 'auto_complete_for_tag'},
:tokens => [',']
} %>
<div class="due_input">
<label for="todo_due">Due</label>
<%= text_field("todo", "due", "size" => 12, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %>
<%= text_field("todo", "due", "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %>
</div>
<div class="show_from_input">
<label for="todo_show_from">Show from</label>
<%= text_field("todo", "show_from", "size" => 12, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 7, "autocomplete" => "off") %>
<%= text_field("todo", "show_from", "size" => 12, "class" => "Date", "tabindex" => 7, "autocomplete" => "off") %>
</div>
<%= source_view_tag( @source_view ) %>
@ -72,67 +62,5 @@
</div>
</div>
<% end -%>
<script type="text/javascript" charset="utf-8">
var contextNames = <%= context_names_for_autocomplete %>;
var projectNames = <%= project_names_for_autocomplete %>;
function askIfNewContextProvided() {
var givenContextName = $('todo_context_name').value;
if (givenContextName.length == 0) return true; // do nothing and depend on rails validation error
for (var i = 0; i < contextNames.length; ++i) {
if (contextNames[i] == givenContextName) return true;
}
return confirm('New context "' + givenContextName + '" will be also created. Are you sure?');
}
var projectAutoCompleter = new Autocompleter.Local('todo_project_name', 'project_list', projectNames, {choices:100,autoSelect:false});
function selectDefaultContext() {
todoContextNameElement = $('todo_context_name');
defaultContextName = todoContextNameElement.projectDefaultContextsMap[this.value];
if (defaultContextName && !todoContextNameElement.editedByTracksUser) {
todoContextNameElement.value = defaultContextName;
}
}
function selectDefaultTags() {
todoTagListElement = $('tag_list');
defaultTags = todoTagListElement.projectDefaultTagsMap[this.value];
if (defaultTags && !todoTagListElement.editedByTracksUser) {
todoTagListElement.value = defaultTags;
}
}
Event.observe($('todo_project_name'), "focus", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('todo_project_name'), "click", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('todo_project_name'), "blur", selectDefaultContext.bind($('todo_project_name')));
Event.observe($('todo_project_name'), "blur", selectDefaultTags.bind($('todo_project_name')));
var contextAutoCompleter;
function initializeNamesForAutoComplete(contextNamesForAutoComplete) {
if (contextNamesForAutoComplete.length == 0 || contextNamesForAutoComplete[0].length == 0) {
return;
}
contextAutoCompleter = new Autocompleter.Local('todo_context_name', 'context_list', contextNamesForAutoComplete, {choices:100,autoSelect:false});
Event.observe($('todo_context_name'), "focus", function(){ $('todo_context_name').editedByTracksUser = true; });
Event.observe($('tag_list'), "focus", function(){ $('tag_list').editedByTracksUser = true; });
Event.observe($('todo_context_name'), "focus", contextAutoCompleter.activate.bind(contextAutoCompleter));
Event.observe($('todo_context_name'), "click", contextAutoCompleter.activate.bind(contextAutoCompleter));
}
function updateContextNamesForAutoComplete(contextNamesForAutoComplete) {
if (contextAutoCompleter) { // i.e. if we're already initialized
contextAutoCompleter.options.array = contextNamesForAutoComplete
} else {
initializeNamesForAutoComplete(contextNamesForAutoComplete)
}
}
initializeNamesForAutoComplete(contextNames);
$('todo_context_name').projectDefaultContextsMap = eval('(' + <%= @default_project_context_name_map %> + ')');
$('tag_list').projectDefaultTagsMap = eval('(' + <%= @default_project_tags_map %> + ')');
</script>
<%= calendar_setup( "todo_due" ) %>
<%= calendar_setup( "todo_show_from" ) %>
</div>
</div>

View file

@ -14,42 +14,12 @@
<label for="<%= dom_id(@todo, 'project_name') %>">Project</label>
<input id="<%= dom_id(@todo, 'project_name') %>" name="project_name" autocomplete="off" tabindex="10" size="30" type="text" value="<%= @todo.project.nil? ? 'None' : @todo.project.name.gsub(/"/,"&quot;") %>" />
<div class="page_name_auto_complete" id="<%= dom_id(@todo, 'project_list') %>" style="display:none"></div>
<script type="text/javascript">
<%= dom_id(@todo, 'project_autocompleter') %> = new Autocompleter.Local('<%= dom_id(@todo, 'project_name') %>', '<%= dom_id(@todo, 'project_list') %>', projectNames, {choices:100,autoSelect:false});
function selectDefaultContext() {
todoContextNameElement = $('<%= dom_id(@todo, 'context_name') %>');
defaultContextName = $('todo_context_name').projectDefaultContextsMap[this.value];
if (defaultContextName && !todoContextNameElement.editedByTracksUser) {
todoContextNameElement.value = defaultContextName;
}
}
function selectDefaultTags() {
todoTagListElement = $('<%= dom_id(@todo, 'tag_list') %>');
defaultTagList = $('tag_list').projectDefaultTagsMap[this.value];
if (defaultTagList && !todoTagListElement.editedByTracksUser) {
todoTagListElement.value = defaultTagList;
}
}
Event.observe($('<%= dom_id(@todo, 'project_name') %>'), "focus", <%= dom_id(@todo, 'project_autocompleter') %>.activate.bind(<%= dom_id(@todo, 'project_autocompleter') %>));
Event.observe($('<%= dom_id(@todo, 'project_name') %>'), "click", <%= dom_id(@todo, 'project_autocompleter') %>.activate.bind(<%= dom_id(@todo, 'project_autocompleter') %>));
Event.observe($('<%= dom_id(@todo, 'project_name') %>'), "blur", selectDefaultContext.bind($('<%= dom_id(@todo, 'project_name') %>')));
Event.observe($('<%= dom_id(@todo, 'project_name') %>'), "blur", selectDefaultTags.bind($('<%= dom_id(@todo, 'project_name') %>')));
</script>
</div>
<div class="context_input">
<label for="<%= dom_id(@todo, 'context_name') %>">Context</label>
<input id="<%= dom_id(@todo, 'context_name') %>" name="context_name" autocomplete="off" tabindex="11" size="30" type="text" value="<%= @todo.context.name %>" />
<div class="page_name_auto_complete" id="<%= dom_id(@todo, 'context_list') %>" style="display:none"></div>
<script type="text/javascript">
<%= dom_id(@todo, 'context_autocompleter') %> = new Autocompleter.Local('<%= dom_id(@todo, 'context_name') %>', '<%= dom_id(@todo, 'context_list') %>', contextNames, {choices:100,autoSelect:false});
Event.observe($('<%= dom_id(@todo, 'context_name') %>'), "focus", function(){ $('<%= dom_id(@todo, 'context_name') %>').editedByTracksUser = true; });
Event.observe($('<%= dom_id(@todo, 'tag_list') %>'), "focus", function(){ $('<%= dom_id(@todo, 'tag_list') %>').editedByTracksUser = true; });
Event.observe($('<%= dom_id(@todo, 'context_name') %>'), "focus", <%= dom_id(@todo, 'context_autocompleter') %>.activate.bind(<%= dom_id(@todo, 'context_autocompleter') %>));
Event.observe($('<%= dom_id(@todo, 'context_name') %>'), "click", <%= dom_id(@todo, 'context_autocompleter') %>.activate.bind(<%= dom_id(@todo, 'context_autocompleter') %>));
</script>
</div>
<label class="tag_list_label" for="<%= dom_id(@todo, 'tag_list') %>">Tags (separate with commas)</label>
@ -86,20 +56,9 @@
<%=image_tag("accept.png", :alt => "") %>
Update
</button>
<a href="javascript:void(0);" onclick="Element.toggle('<%= dom_id(@todo, 'line') %>');Element.toggle('<%= dom_id(@todo, 'edit') %>');" class="negative">
<a href="#" class="negative">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
</a>
</div>
</div>
<%= calendar_setup( dom_id(@todo, 'due') ) %>
<%= calendar_setup( dom_id(@todo, 'show_from') ) %>
<script>
jQuery(function(){
jQuery(".date_clear").click(function() {
/* add behavior to clear the date both buttons for show_from and due */
jQuery(this).prev().val('');
})})
</script>

View file

@ -8,7 +8,7 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
@z_index_counter = @z_index_counter - 1 # for IE z-index bug
%>
<div id="<%= dom_id(todo) %>" class="item-container">
<div id="<%= dom_id(todo, 'line') %>">
<div id="<%= dom_id(todo, 'line') %>" class="item-show">
<%= remote_star_icon %>
<%= remote_toggle_checkbox unless source_view_is :deferred %>
<ul class="sf-menu sf-item-menu"><li style="z-index:<%=@z_index_counter%>"><%= image_tag "downarrow.png", :alt=> "" %><ul id="ul<%= dom_id(todo) %>">
@ -37,4 +37,4 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
<div class="placeholder"> </div>
<% end -%>
</div>
</div>
</div>

View file

@ -59,17 +59,6 @@
var projectNames = <%= project_names_for_autocomplete %>;
$('todo_context_name').projectDefaultContextsMap = eval('(' + <%= @default_project_context_name_map %> + ')');
</script>
<!--
<input class="hide_tickler" id="hide_tickler" type="checkbox" tabindex="5" name="hide_tickler" checked="true"/>
<label for="hide_tickler"> Show actions in tickler</label>
<br/><br/>
-->
<p><%= link_to('<span class="feed">iCal</span>', {:format => 'ics', :token => current_user.token}, :title => "iCal feed" ) %>
- Get this calendar in iCal format</p>
</div>
<%
apply_behavior 'input.hide_tickler:click', :prevent_default => true do |page|
page << "alert('hiding action in tickler from calendar is not yet implemented');"
end
%>

View file

@ -6,11 +6,12 @@ if @saved
status_message = 'Added new context / ' + status_message if @new_context_created
page.notify :notice, status_message, 5.0
page['badge_count'].replace_html @down_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.send :record, "$('#todo-form-new-action').clearForm();$('#todo-form-new-action input:text:first').focus();"
page['todo_context_name'].value = @initial_context_name
page['todo_project_name'].value = @initial_project_name
page << "updateContextNamesForAutoComplete(#{context_names_for_autocomplete})" if @new_context_created
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}" if @new_project_created
page['tag_list'].value = @default_tags
#page << "updateContextNamesForAutoComplete(#{context_names_for_autocomplete})" if @new_context_created
#page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}" if @new_project_created
if should_show_new_item()
if @new_context_created
page.insert_html :top, 'display_box', :partial => 'contexts/context', :locals => { :context => @todo.context, :collapsible => true }
@ -21,7 +22,6 @@ if @saved
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
end
# make sure the behavior of the new/updated todo is enabled
page << "TodoBehavior.enableToggleNotes()"
page['tickler-empty-nd'].hide if source_view_is :deferred
end
else

View file

@ -4,7 +4,7 @@ if @saved
page['badge_count'].replace_html @down_count
# remove context if empty
page.visual_effect :fade, item_container_id(@todo), :duration => 0.4 if source_view_is_one_of(:todo, :deferred) && @remaining_in_context == 0
page.visual_effect(:fade, "c#{@todo.context_id}", :duration => 0.4) if (@remaining_in_context == 0)
# show message if there are no actions
page[empty_container_msg_div_id].show if !empty_container_msg_div_id.nil? && @down_count == 0

View file

@ -1,4 +1,4 @@
page[dom_id(@todo, 'form')].down('.placeholder').replace_html :partial => 'todos/edit_form'
page[dom_id(@todo, 'line')].hide
page[dom_id(@todo, 'form')].find('.placeholder').show().replace_html :partial => 'todos/edit_form'
page[dom_id(@todo, 'edit')].show
page[dom_id(@todo, 'form')].down('input#todo_description').focus
page[dom_id(@todo, 'line')].hide
page[dom_id(@todo, 'form')].find('input#todo_description').show().focus

View file

@ -14,7 +14,7 @@ if @saved
# remove container if empty
if @remaining_in_context == 0 && source_view_is(:todo)
page.visual_effect :fade, item_container_id(@todo), :duration => 0.4
page.visual_effect :fade, "c"+@todo.context.id.to_s, :duration => 0.4
end
if @original_item_was_deferred && source_view_is(:tag)
@ -42,6 +42,7 @@ if @saved
page.insert_html :bottom, item_container_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo, 'line'), {'startcolor' => "'#99ff99'"}
page.show "empty-d" if @completed_count == 0
page.show "c"+@todo.context.id.to_s
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil? # If we've checked something as undone, incomplete items can't be empty
end
@ -53,5 +54,3 @@ if @saved
else
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@todo.errors.count, "error")} prohibited this action from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @todo.errors.each_full { |msg| content_tag("li", msg) }), "id" => "errorExplanation", "class" => "errorExplanation")
end
# make sure the behavior of the new/updated todo is enabled
page << "TodoBehavior.enableToggleNotes()"

View file

@ -0,0 +1,3 @@
<% if @saved -%>
$('div#line_todo_<%= @todo.id %> a.star_item img').toggleClass('starred_todo').toggleClass('unstarred_todo');
<% end -%>

View file

@ -1,3 +0,0 @@
if @saved
page[@todo].down('a.star_item').down('img').toggleClassName('starred_todo').toggleClassName('unstarred_todo')
end

View file

@ -6,13 +6,6 @@ if @saved
status_message = 'Added new context / ' + status_message if @new_context_created
page.notify :notice, status_message, 5.0
# update auto completer arrays for edit form in right column, only for pages
# with that form
unless source_view_is_one_of(:calendar)
page << "contextAutoCompleter.options.array = #{context_names_for_autocomplete}; contextAutoCompleter.changed = true" if @new_context_created
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}; projectAutoCompleter.changed = true" if @new_project_created
end
if source_view_is_one_of(:todo, :context, :tag)
if @context_changed || @todo.deferred?
page[@todo].remove
@ -27,8 +20,8 @@ if @saved
end
else
source_view do |from|
from.todo { page.visual_effect :fade, item_container_id(@todo), :duration => 0.4 }
from.tag { page.visual_effect :fade, item_container_id(@todo), :duration => 0.4 }
from.todo { page.visual_effect :fade, "c#{@todo.context.id}", :duration => 0.4 }
from.tag { page.visual_effect :fade, "c#{@todo.context.id}", :duration => 0.4 }
from.context { page.show "c#{@original_item_context_id}empty-nd" }
end
end
@ -89,7 +82,8 @@ if @saved
elsif @todo_was_activated_from_deferred_state
page[@todo].remove
page['tickler-empty-nd'].show if (@deferred_count == 0)
page.insert_html :bottom, "p#{@todo.project_id}", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.insert_html :bottom, "p#{@todo.project_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
page["p#{@todo.project_id}empty-nd"].hide
page.replace_html "badge_count", @down_count
else
@ -141,9 +135,7 @@ if @saved
else
logger.error "unexpected source_view '#{params[:_source_view]}'"
end
# make sure the behavior of the new/updated todo is enabled
page << "TodoBehavior.enableToggleNotes()"
else
page.show 'error_status'
page.replace_html 'error_status', "#{error_messages_for('todo')}"
end
end

View file

@ -83,7 +83,6 @@ require 'tracks/todo_list'
require 'tracks/config'
require 'tagging_extensions' # Needed for tagging-specific extensions
require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557
require 'prototype_helper_extensions'
if ( SITE_CONFIG['authentication_schemes'].include? 'ldap')
require 'net/ldap' #requires ruby-net-ldap gem be installed

View file

@ -1,6 +1,4 @@
ActionController::Routing::Routes.draw do |map|
UJS::routes
map.with_options :controller => 'login' do |login|
login.login 'login', :action => 'login'
login.formatted_login 'login.:format', :action => 'login'

View file

@ -1,27 +0,0 @@
module ActionView
module Helpers
module PrototypeHelper
def remote_to_href(options = {})
remote_function(options.merge(:url => javascript_variable('this.href'))) + "\n"
end
class JavaScriptGenerator #:nodoc:
module GeneratorMethods
# Executes the content of the block if the user confirms the javascript confirmation. Example:
#
# page.confirming("Are you sure?") do
# page.visual_effect :hide, 'information'
# end
def confirming(message)
message = "'#{message}'" unless message =~ /^['"]/
self << "if (confirm(#{message})) {"
yield
self << "}"
end
end
end
end
end
end

View file

@ -19,7 +19,7 @@ var accessKeyHintsAdder = {
var elemTypes = new Array('a','area','button','input','label','legend','textarea');
for(var i = 0; i < elemTypes.length; i++)
{
this.addHint(document.getElementsByTagName(elemTypes[i]));
accessKeyHintsAdder.addHint(document.getElementsByTagName(elemTypes[i]));
}
},
@ -66,4 +66,4 @@ var accessKeyHintsAdder = {
}
Event.observe(window, "load", accessKeyHintsAdder.run.bindAsEventListener(accessKeyHintsAdder));
$(accessKeyHintsAdder.run);

View file

@ -1,84 +1,29 @@
var Login = {
showOpenid: function() {
if ($('database_auth_form')) $('database_auth_form').hide();
if ($('openid_auth_form')) $('openid_auth_form').show();
if ($('alternate_auth_openid')) $('alternate_auth_openid').hide();
if ($('alternate_auth_database')) $('alternate_auth_database').show();
if ($('openid_url')) $('openid_url').focus();
if ($('openid_url')) $('openid_url').select();
new CookieManager().setCookie('preferred_auth', 'openid');
},
showDatabase: function(container) {
if ($('openid_auth_form')) $('openid_auth_form').hide();
if ($('database_auth_form')) $('database_auth_form').show();
if ($('alternate_auth_database')) $('alternate_auth_database').hide();
if ($('alternate_auth_openid')) $('alternate_auth_openid').show();
if ($('user_login')) $('user_login').focus();
if ($('user_login')) $('user_login').select();
new CookieManager().setCookie('preferred_auth', 'database');
}
}
var TracksForm = {
toggle: function(toggleDivId, formContainerId, formId, hideLinkText, hideLinkTitle, showLinkText, showLinkTitle) {
$(formContainerId).toggle();
toggleDiv = $(toggleDivId);
toggleLink = toggleDiv.down('a');
if (toggleDiv.hasClassName('hide_form')) {
toggleLink.update(showLinkText).setAttribute('title', showLinkTitle);
toggle: function(toggleDivId, formContainerId, formId, hideLinkText,
hideLinkTitle, showLinkText, showLinkTitle) {
$('#'+formContainerId).toggle();
toggleDiv = $('#'+toggleDivId);
toggleLink = toggleDiv.find('a');
if (toggleDiv.hasClass('hide_form')) {
toggleLink.text(showLinkText).attr('title', showLinkTitle);
}
else {
toggleLink.update(hideLinkText).setAttribute('title', hideLinkTitle);
Form.focusFirstElement(formId);
toggleLink.text(hideLinkText).attr('title', hideLinkTitle);
$('#'+formId+' input:text:first').focus();
}
toggleDiv.toggleClassName('hide_form');
toggleDiv.toggleClass('hide_form');
},
get_period: function() {
if ($('recurring_todo_recurring_period_daily').checked) {
return 'daily';
}
else if ($('recurring_todo_recurring_period_weekly').checked) {
return 'weekly';
}
else if ($('recurring_todo_recurring_period_monthly').checked) {
return 'monthly';
}
else if ($('recurring_todo_recurring_period_yearly').checked) {
return 'yearly';
}
else {
return 'no period'
}
},
get_edit_period: function() {
if ($('recurring_edit_todo_recurring_period_daily').checked) {
return 'daily';
}
else if ($('recurring_edit_todo_recurring_period_weekly').checked) {
return 'weekly';
}
else if ($('recurring_edit_todo_recurring_period_monthly').checked) {
return 'monthly';
}
else if ($('recurring_edit_todo_recurring_period_yearly').checked) {
return 'yearly';
}
else {
return 'no period'
}
},
hide_all_recurring: function () {
$('recurring_daily').hide();
$('recurring_weekly').hide();
$('recurring_monthly').hide();
$('recurring_yearly').hide();
$('#recurring_daily').hide();
$('#recurring_weekly').hide();
$('#recurring_monthly').hide();
$('#recurring_yearly').hide();
},
hide_all_edit_recurring: function () {
$('recurring_edit_daily').hide();
$('recurring_edit_weekly').hide();
$('recurring_edit_monthly').hide();
$('recurring_edit_yearly').hide();
$('#recurring_edit_daily').hide();
$('#recurring_edit_weekly').hide();
$('#recurring_edit_monthly').hide();
$('#recurring_edit_yearly').hide();
},
toggle_overlay: function () {
el = document.getElementById("overlay");
@ -86,148 +31,394 @@ var TracksForm = {
}
}
var TodoBehavior = {
enableToggleNotes: function() {
jQuery(".show_notes").unbind('click').bind('click', function () {
jQuery(this).next().toggle("fast"); return false;
});
}
}
// uncomment the next four lines for easier debugging with FireBug
// Ajax.Responders.register({
// onException: function(source, exception) {
// console.error(exception);
// }
// });
$.fn.clearForm = function() {
return this.each(function() {
var type = this.type, tag = this.tagName.toLowerCase();
if (tag == 'form')
return $(':input',this).clearForm();
if (type == 'text' || type == 'password' || tag == 'textarea')
this.value = '';
else if (type == 'checkbox' || type == 'radio')
this.checked = false;
else if (tag == 'select')
this.selectedIndex = -1;
});
};
/* fade flashes automatically */
Event.observe(window, 'load', function() {
$A(document.getElementsByClassName('alert')).each(function(o) {
o.opacity = 100.0
Effect.Fade(o, {
duration: 8.0
})
});
/****************************************
* Unobtrusive jQuery written by Eric Allen
****************************************/
/* Set up authenticity token proplery */
$(document).ajaxSend(function(event, request, settings) {
if ( settings.type == 'POST' ) {
if(typeof(AUTH_TOKEN) != 'undefined'){
settings.data = (settings.data ? settings.data + "&" : "")
+ "authenticity_token=" + encodeURIComponent( AUTH_TOKEN ) + "&"
+ "_source_view=" + encodeURIComponent( SOURCE_VIEW );
} else {
settings.data = (settings.data ? settings.data + "&" : "")
+ "_source_view=" + encodeURIComponent( SOURCE_VIEW );
}
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
request.setRequestHeader("Accept", "text/javascript");
});
/**
* Provides a simple interface for creating, retrieving and clearing cookies.
* Adapted from Jonathan Buchanan's code at http://insin.woaf.net/code/javascript/cookiemanager.html
*/
CookieManager = Class.create();
CookieManager.prototype =
{
BROWSER_IS_IE:
(document.all
&& window.ActiveXObject
&& navigator.userAgent.toLowerCase().indexOf("msie") > -1
&& navigator.userAgent.toLowerCase().indexOf("opera") == -1),
/**
* I hate navigator string based browser detection too, but when Opera alone
* chokes on cookies containing double quotes...
*/
BROWSER_IS_OPERA:
(navigator.userAgent.toLowerCase().indexOf("opera") != -1),
initialize: function(options)
{
this.options = Object.extend({
shelfLife: 365,
userData: false
}, options || {});
this.cookieShelfLife = this.options.shelfLife;
this.userDataForIE = this.options.userData;
// Internet Explorer has a cookie handling bug - if the *combined size*
// of all cookies stored for a given domain is greater than 4096 bytes,
// document.cookie will return an empty string. Until this is fixed, we
// can fall back on IE's proprietary userData behaviour if necessary.
if (this.BROWSER_IS_IE && this.userDataForIE)
{
this.IE_CACHE_NAME = "storage";
if ($(this.IE_CACHE_NAME) == null)
{
var div = document.createElement("DIV");
div.id = this.IE_CACHE_NAME;
document.body.appendChild(div);
}
this.store = $(this.IE_CACHE_NAME);
this.store.style.behavior = "url('#default#userData')";
}
},
/**
* Returns the value of a cookie with the given name, or <code>null</code>
* if no such cookie exists.
*/
getCookie: function(aCookieName)
{
var result = null;
if (this.BROWSER_IS_IE && this.userDataForIE)
{
this.store.load(this.IE_CACHE_NAME);
result = this.store.getAttribute(aCookieName);
}
else
{
for (var i = 0; i < document.cookie.split('; ').length; i++)
{
var crumb = document.cookie.split('; ')[i].split('=');
if (crumb[0] == aCookieName && crumb[1] != null)
{
result = crumb[1];
break;
}
}
}
if (this.BROWSER_IS_OPERA && result != null)
{
result = result.replace(/%22/g, '"');
}
return result;
},
/**
* Sets a cookie with the given name and value.
*/
setCookie: function(aCookieName, aCookieValue)
{
if (this.BROWSER_IS_IE && this.userDataForIE)
{
this.store.setAttribute(aCookieName, aCookieValue);
this.store.save(this.IE_CACHE_NAME);
}
else
{
if (this.BROWSER_IS_OPERA)
{
aCookieValue = aCookieValue.replace(/"/g, "%22");
}
var date = new Date();
date.setTime(date.getTime() + (this.cookieShelfLife * 24*60*60*1000));
var expires = '; expires=' + date.toGMTString();
document.cookie = aCookieName + '=' + aCookieValue + expires + '; path=/';
}
},
/**
* Clears the cookie with the given name.
*/
clearCookie: function(aCookieName)
{
if (this.BROWSER_IS_IE && this.userDataForIE)
{
this.store.load(this.IE_CACHE_NAME);
this.store.removeAttribute(aCookieName);
this.store.save(this.IE_CACHE_NAME);
}
else
{
document.cookie =
aCookieName + '=;expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/';
}
todoItems = {
// public
ensureVisibleWithEffectAppear: function(elemId){
$('#'+elemId).fadeIn(400);
},
expandNextActionListing: function(itemsElem, skipAnimation) {
itemsElem = $(itemsElem);
if(skipAnimation == true) {
itemsElem.show();
}
else {
itemsElem.show('blind', 400);
}
todoItems.showContainer(itemsElem.parentNode);
},
collapseNextActionListing: function(itemsElem, skipAnimation) {
itemsElem = $(itemsElem);
if(skipAnimation == true) {
itemsElem.hide();
}
else {
itemsElem.hide('blind', 400);
}
todoItems.hideContainer(itemsElem.parentNode);
},
ensureContainerHeight: function(itemsElem) {
$(itemsElem).css({height: '', overflow: ''});
},
expandNextActionListingByContext: function(itemsElemId, skipAnimation){
todoItems.expandNextActionListing($('#'+itemsElemId).get(), skipAnimation);
},
// private
buildCookieName: function(containerElem) {
tracks_login = $.cookie('tracks_login');
return 'tracks_'+tracks_login+'_context_' + containerElem.id + '_collapsed';
},
showContainer: function(containerElem) {
imgSrc = $(containerElem).find('.container_toggle img').attr('src');
$(containerElem).find('.container_toggle img').attr('src', imgSrc.replace('expand', 'collapse'));
},
hideContainer: function (containerElem) {
imgSrc = $(containerElem).find('.container_toggle img').attr('src');
$(containerElem).find('.container_toggle img').attr('src', imgSrc.replace('collapse', 'expand'));
}
}
function setup_container_toggles(){
// bind handlers
$('.container_toggle').click(function(evt){
toggle_target = $(this.parentNode.parentNode).find('.toggle_target');
if(toggle_target.is(':visible')){
// hide it
imgSrc = $(this).find('img').attr('src');
$(this).find('img').attr('src', imgSrc.replace('collapse', 'expand'));
$.cookie(todoItems.buildCookieName(this.parentNode.parentNode), true);
} else {
// show it
imgSrc = $(this).find('img').attr('src');
$(this).find('img').attr('src', imgSrc.replace('expand', 'collapse'));
$.cookie(todoItems.buildCookieName(this.parentNode.parentNode), null);
}
toggle_target.toggle('blind');
});
// set to cookied state
$('.container.context').each(function(){
if($.cookie(todoItems.buildCookieName(this))){
imgSrc = $(this).find('.container_toggle img').attr('src');
$(this).find('.container_toggle img').attr('src', imgSrc.replace('collapse', 'expand'));
$(this).find('.toggle_target').hide();
}
});
}
function askIfNewContextProvided() {
var givenContextName = $('#todo_context_name').val();
if (givenContextName.length == 0) return true; // do nothing and depend on rails validation error
for (var i = 0; i < contextNames.length; ++i) {
if (contextNames[i] == givenContextName) return true;
}
return confirm('New context "' + givenContextName + '" will be also created. Are you sure?');
}
function update_order(event, ui){
container = $(ui.item).parent();
row = $(ui.item).children('.sortable_row');
url = '';
if(row.hasClass('context'))
url = '/contexts/order';
else if(row.hasClass('project'))
url = '/projects/order';
else {
console.log("Bad sortable list");
return;
}
$.post(url,
container.sortable("serialize"),
function(){row.effect('highlight', {}, 1000)},
'script');
}
/* Unobtrusive jQuery behavior */
function project_defaults(){
if(defaultContexts[$(this).val()] !== undefined) {
context_name = $(this).parents('form').find('input[name=context_name]');
if(context_name.attr('edited') === undefined){
context_name.val(defaultContexts[$(this).val()]);
}
}
if(defaultTags[$(this).val()] !== undefined) {
tag_list = $(this).parents('form').find('input[name=tag_list]');
if(tag_list.attr('edited') === undefined){
tag_list.val(defaultTags[$(this).val()]);
}
}
}
function enable_rich_interaction(){
$('input.Date').datepicker({'dateFormat': dateFormat});
/* Autocomplete */
$('input[name=context_name]').autocomplete(contextNames);
$('input[name=project[default_context_name]]').autocomplete(contextNames);
$('input[name=project_name]').autocomplete(projectNames);
$('input[name=tag_list]').autocomplete(tagNames, {multiple: true,multipleSeparator:','});
/* have to bind on keypress because of limitataions of live() */
$('input[name=project_name]').live('keypress', function(){
$(this).bind('blur', project_defaults);
});
$('input[name=context_name]').live('keypress', function(){
$(this).attr('edited', 'true');
});
$('input[name=tag_list]').live('keypress', function(){
$(this).attr('edited', 'true');
});
}
$(document).ready(function() {
$('#search-form #search').focus();
/* Nifty corners */
Nifty("div#recurring_new_container","normal");
Nifty("div#context_new_container","normal");
Nifty("div#feedlegend","normal");
Nifty("div#feedicons-project","normal");
Nifty("div#feedicons-context","normal");
Nifty("div#todo_new_action_container","normal");
/* Moved from standard.html.erb layout */
$('ul.sf-menu').superfish({
delay: 250,
animation: {opacity:'show',height:'show'},
autoArrows: false,
dropShadows: false,
speed: 'fast'
});
$('ul.sf-item-menu').superfish({ /* context menu */
delay: 100,
animation: {opacity:'show',height:'show'},
autoArrows: false,
dropShadows: false,
speed: 'fast',
onBeforeShow: function() { /* highlight todo */
$(this.parent().parent().parent()).addClass("sf-item-selected");
},
onHide: function() { /* remove hightlight from todo */
$(this.parent().parent().parent()).removeClass("sf-item-selected");
}
});
/* for toggle notes link in mininav */
$("#toggle-notes-nav").click(function () { $(".todo_notes").toggle(); });
/* show the notes of a todo */
$(".show_notes").live('click', function () {
$(this).next().toggle("fast"); return false;
});
/* fade flashes and alerts in automatically */
$(".alert").fadeOut(8000);
/* set behavior for star icon */
$(".item-container a.star_item").live('click', function (ev){
$.post(this.href, {_method: 'put'}, null, 'script');
return false;
});
/* set behavior for toggle checkboxes */
$(".item-container input.item-checkbox").live('click', function(ev){
params = {_method: 'put'};
if(typeof(TAG_NAME) !== 'undefined')
params._tag_name = TAG_NAME;
$.post(this.value, params, null, 'script');
});
setup_container_toggles();
$('#toggle_action_new').click(function(){
TracksForm.toggle('toggle_action_new', 'todo_new_action', 'todo-form-new-action',
'« Hide form', 'Hide next action form',
'Add a next action »', 'Add a next action');
});
$('.edit-form a.negative').live('click', function(){
$(this).parents('.container').find('.item-show').show();
$(this).parents('.container').find('.project').show();
$(this).parents('.edit-form').hide();
});
/* add behavior to clear the date both buttons for show_from and due */
$(".date_clear").live('click', function() {
$(this).prev().val('');
});
/* recurring todo behavior */
/* behavior for delete icon */
$('.item-container a.delete_icon').live('click', function(evt){
evt.preventDefault();
params = {};
if(typeof(TAG_NAME) !== 'undefined'){
params._tag_name = TAG_NAME;
}
if(confirm("Are you sure that you want to "+this.title+"?")){
itemContainer = $(this).parents(".item-container");
itemContainer.block({message: null});
params._method = 'delete';
$.post(this.href, params, function(){
itemContainer.unblock();
}, 'script');
}
});
/* behavior for edit icon */
$('.item-container a.edit_icon').live('click', function(evt){
evt.preventDefault();
params = {};
if(typeof(TAG_NAME) !== 'undefined'){
params._tag_name = TAG_NAME;
}
itemContainer = $(this).parents(".item-container");
$(this).effect('pulsate', {times: 1}, 800);
$.get(this.href, params, function(){
}, 'script');
});
$("#recurring_todo_new_action_cancel").click(function(){
$('#recurring-todo-form-new-action').clearForm();
$('#recurring-todo-form-new-action input:text:first').focus();
TracksForm.hide_all_recurring();
$('#recurring_daily').show();
TracksForm.toggle_overlay();
});
$("#recurring_todo_edit_action_cancel").live('click', function(){
$('#recurring-todo-form-edit-action').clearForm();
$('#recurring-todo-form-edit-action input:text:first').focus();
TracksForm.hide_all_recurring();
$('#recurring_daily').show();
TracksForm.toggle_overlay();
});
$("#recurring_edit_period input").live('click', function(){
$.each(['daily', 'weekly', 'monthly', 'yearly'], function(){
$('#recurring_edit_'+this).hide();
});
$('#recurring_edit_'+this.id.split('_')[5]).show();
});
$('div.context span#context_name').editable(function(value, settings){
context_id = $(this).parents('.container.context').get(0).id.split('c')[1];
highlight = function(){
$('div.context span#context_name').effect('highlight', {}, 500);
};
$.post('/contexts/update/'+context_id, {'context[name]': value}, highlight);
return(value);
}, {style: 'padding:0px', submit: "OK"});
/* Projects behavior */
save_project_name = function(value, settings){
project_id = $(this).parents('.container').children('div').get(0).id.split('_')[2];
highlight = function(){
$('h2#project_name').effect('highlight', {}, 500);
};
$.post('/projects/update/'+project_id, {'project[name]': value, 'update_project_name': 'true'}, highlight, 'script');
return(value);
};
$('h2#project_name').editable(save_project_name, {style: 'padding:0px', submit: "OK"});
$('.alphabetize_link').click(function(evt){
evt.preventDefault();
if(confirm('Are you sure that you want to sort these projects alphabetically? This will replace the existing sort order.')){
alphaSort = $(this).parents('.alpha_sort');
alphaSort.block({message:null});
$.post(this.href, {}, function(){alphaSort.unblock()}, 'script');
}
});
$('.actionize_link').click(function(evt){
evt.preventDefault();
if(confirm('Are you sure that you want to sort these projects by the number of tasks? This will replace the existing sort order.')){
taskSort = $(this).parents('.tasks_sort');
taskSort.block({message:null});
$.post(this.href, {}, function(){taskSort.unblock()}, 'script');
}
});
$('a.delete_project_button').live('click', function(evt){
evt.preventDefault();
if(confirm("Are you sure that you want to "+this.title+"?")){
$(this).parents('.project').block({message: null});
params = {_method: 'delete'};
$.post(this.href, params, null, 'script');
}
});
$('#toggle_project_new').click(function(evt){
TracksForm.toggle('toggle_project_new', 'project_new', 'project-form',
'« Hide form', 'Hide new project form',
'Create a new project »', 'Add a project');
});
$(".project-list .edit-form a.negative").live('click', function(evt){
evt.preventDefault();
$(this).parents('.list').find('.project').show();
$(this).parents('.edit-form').hide();
$(this).parents('.edit-form').find('form').clearForm();
});
$(".add_note_link a").live('click', function(){
$('#new-note').show();
$('#new-note form').clearForm();
$('#new-note form input:text:first').focus();
});
$("#list-active-projects").sortable({handle: '.handle', update: update_order});
$("#list-hidden-projects").sortable({handle: '.handle', update: update_order});
$("#list-completed-projects").sortable({handle: '.handle', update: update_order});
/* Contexts behavior */
$('#toggle_context_new').click(function(evt){
TracksForm.toggle('toggle_context_new', 'context_new', 'context-form',
'« Hide form', 'Hide new context form',
'Create a new context »', 'Add a context');
});
$("#list-contexts-active").sortable({handle: '.handle', update: update_order});
$("#list-contexts-hidden").sortable({handle: '.handle', update: update_order});
/* Gets called from some AJAX callbacks, too */
enable_rich_interaction();
});

View file

@ -1,127 +0,0 @@
// ** I18N
// Calendar EN language
// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
// Encoding: any
// Distributed under the same terms as the calendar itself.
// For translators: please use UTF-8 if possible. We strongly believe that
// Unicode is the answer to a real internationalized world. Also please
// include your contact information in the header, as can be seen above.
// full day names
Calendar._DN = new Array
("Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday");
// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary. We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
// Calendar._SDN_len = N; // short day name length
// Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.
// short day names
Calendar._SDN = new Array
("Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun");
// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 0;
// full month names
Calendar._MN = new Array
("January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December");
// short month names
Calendar._SMN = new Array
("Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec");
// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "About the calendar";
Calendar._TT["ABOUT"] =
"DHTML Date/Time Selector\n" +
"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." +
"\n\n" +
"Date selection:\n" +
"- Use the \xab, \xbb buttons to select year\n" +
"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
"- Hold mouse button on any of the above buttons for faster selection.";
Calendar._TT["ABOUT_TIME"] = "\n\n" +
"Time selection:\n" +
"- Click on any of the time parts to increase it\n" +
"- or Shift-click to decrease it\n" +
"- or click and drag for faster selection.";
Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)";
Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)";
Calendar._TT["GO_TODAY"] = "Go Today";
Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)";
Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)";
Calendar._TT["SEL_DATE"] = "Select date";
Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
Calendar._TT["PART_TODAY"] = " (today)";
// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Display %s first";
// This may be locale-dependent. It specifies the week-end days, as an array
// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "0,6";
Calendar._TT["CLOSE"] = "Close";
Calendar._TT["TODAY"] = "Today";
Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";
// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";
Calendar._TT["WK"] = "wk";
Calendar._TT["TIME"] = "Time:";

View file

@ -1,333 +0,0 @@
/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
* ---------------------------------------------------------------------------
*
* The DHTML Calendar
*
* Details and latest version at:
* http://dynarch.com/mishoo/calendar.epl
*
* This script is distributed under the GNU Lesser General Public License.
* Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
*
* This file defines helper functions for setting up the calendar. They are
* intended to help non-programmers get a working calendar on their site
* quickly. This script should not be seen as part of the calendar. It just
* shows you what one can do with the calendar, while in the same time
* providing a quick and simple method for setting it up. If you need
* exhaustive customization of the calendar creation process feel free to
* modify this code to suit your needs (this is recommended and much better
* than modifying calendar.js itself).
*/
// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $
/**
* This function "patches" an input field (or other element) to use a calendar
* widget for date selection.
*
* The "params" is a single object that can have the following properties:
*
* prop. name | description
* -------------------------------------------------------------------------------------------------
* inputField | the ID of an input field to store the date
* displayArea | the ID of a DIV or other element to show the date
* button | ID of a button or other element that will trigger the calendar
* eventName | event that will trigger the calendar, without the "on" prefix (default: "click")
* ifFormat | date format that will be stored in the input field
* daFormat | the date format that will be used to display the date in displayArea
* singleClick | (true/false) wether the calendar is in single click mode or not (default: true)
* firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc.
* align | alignment (default: "Br"); if you don't know what's this see the calendar documentation
* range | array with 2 elements. Default: [1900, 2999] -- the range of years available
* weekNumbers | (true/false) if it's true (default) the calendar will display week numbers
* flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
* flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
* disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
* onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay)
* onClose | function that gets called when the calendar is closed. [default]
* onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar.
* date | the date that the calendar will be initially displayed to
* showsTime | default: false; if true the calendar will include a time selector
* timeFormat | the time format; can be "12" or "24", default is "12"
* electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
* step | configures the step of the years in drop-down boxes; default: 2
* position | configures the calendar absolute position; default: null
* cache | if "true" (but default: "false") it will reuse the same calendar object, where possible
* showOthers | if "true" (but default: "false") it will show days from other months too
*
* None of them is required, they all have default values. However, if you
* pass none of "inputField", "displayArea" or "button" you'll get a warning
* saying "nothing to setup".
*/
Calendar.setup = function (params) {
function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
param_default("inputField", null);
param_default("displayArea", null);
param_default("button", null);
param_default("eventName", "click");
param_default("ifFormat", "%Y/%m/%d");
param_default("daFormat", "%Y/%m/%d");
param_default("singleClick", true);
param_default("disableFunc", null);
param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined
param_default("dateText", null);
param_default("firstDay", null);
param_default("align", "Br");
param_default("range", [1900, 2999]);
param_default("weekNumbers", true);
param_default("flat", null);
param_default("flatCallback", null);
param_default("onSelect", null);
param_default("onClose", null);
param_default("onUpdate", null);
param_default("date", null);
param_default("showsTime", false);
param_default("timeFormat", "24");
param_default("electric", true);
param_default("step", 2);
param_default("position", null);
param_default("cache", false);
param_default("showOthers", false);
param_default("multiple", null);
var tmp = ["inputField", "displayArea", "button"];
for (var i in tmp) {
if (typeof params[tmp[i]] == "string") {
params[tmp[i]] = document.getElementById(params[tmp[i]]);
}
}
if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code");
return false;
}
function onSelect(cal) {
var p = cal.params;
var update = (cal.dateClicked || p.electric);
if (update && p.inputField) {
p.inputField.value = cal.date.print(p.ifFormat);
if (typeof p.inputField.onchange == "function")
p.inputField.onchange();
}
if (update && p.displayArea)
p.displayArea.innerHTML = cal.date.print(p.daFormat);
if (update && typeof p.onUpdate == "function")
p.onUpdate(cal);
if (update && p.flat) {
if (typeof p.flatCallback == "function")
p.flatCallback(cal);
}
if (update && p.singleClick && cal.dateClicked)
cal.callCloseHandler();
};
if (params.flat != null) {
if (typeof params.flat == "string")
params.flat = document.getElementById(params.flat);
if (!params.flat) {
alert("Calendar.setup:\n Flat specified but can't find parent.");
return false;
}
var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
cal.showsOtherMonths = params.showOthers;
cal.showsTime = params.showsTime;
cal.time24 = (params.timeFormat == "24");
cal.params = params;
cal.weekNumbers = params.weekNumbers;
cal.setRange(params.range[0], params.range[1]);
cal.setDateStatusHandler(params.dateStatusFunc);
cal.getDateText = params.dateText;
if (params.ifFormat) {
cal.setDateFormat(params.ifFormat);
}
if (params.inputField && typeof params.inputField.value == "string") {
cal.parseDate(params.inputField.value);
}
cal.create(params.flat);
cal.show();
return false;
}
var triggerEl = params.button || params.displayArea || params.inputField;
triggerEl["on" + params.eventName] = function() {
var dateEl = params.inputField || params.displayArea;
var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
var mustCreate = false;
var cal = window.calendar;
if (dateEl)
params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
if (!(cal && params.cache)) {
window.calendar = cal = new Calendar(params.firstDay,
params.date,
params.onSelect || onSelect,
params.onClose || function(cal) { cal.hide(); });
cal.showsTime = params.showsTime;
cal.time24 = (params.timeFormat == "24");
cal.weekNumbers = params.weekNumbers;
mustCreate = true;
} else {
if (params.date)
cal.setDate(params.date);
cal.hide();
}
if (params.multiple) {
cal.multiple = {};
for (var i = params.multiple.length; --i >= 0;) {
var d = params.multiple[i];
var ds = d.print("%Y%m%d");
cal.multiple[ds] = d;
}
}
cal.showsOtherMonths = params.showOthers;
cal.yearStep = params.step;
cal.setRange(params.range[0], params.range[1]);
cal.params = params;
cal.setDateStatusHandler(params.dateStatusFunc);
cal.getDateText = params.dateText;
cal.setDateFormat(dateFmt);
if (mustCreate)
cal.create();
cal.refresh();
if (!params.position)
cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
else
cal.showAt(params.position[0], params.position[1]);
return false;
};
if (params.inputField) {
new DateDueKeyboardShortcutSupport(params.inputField, params.ifFormat, cal);
}
return cal;
};
/* Adds keyboard shortcuts to the passed in date field:
*
* 't' input today's date
* '+' or '=' increment the date in the field by one day
* '-' decrement the date in the field by one day
*
* If the calendar is visible, the shortcuts play nicely with it. If not,
* they still work properly. Pressing '+' when no date is entered in the
* field will set the date to tomorrow, and likewise '-' with no date
* entered will set the date to yesterday.
*/
DateDueKeyboardShortcutSupport = Class.create();
DateDueKeyboardShortcutSupport.prototype = {
initialize: function(element, dateFormat) {
this.element = $(element);
this.dateFormat = dateFormat || "%Y/%m/%d";
Event.observe(this.element,'keypress',this.onkeypress.bindAsEventListener(this));
title = this.element.getAttributeNode("title");
tooltip = 'Shortcuts: (t) today; (-) or (<) previous day; (+) or (>) next day; ([) previous week; (]) next week; ({) previous month; (}) next month; Click to show calendar';
if (title && title.value)
{
this.element.setAttribute("title", title.value + ' (' + tooltip + ')');
}
else
{
this.element.setAttribute("title", tooltip);
}
},
onkeypress: function(event) {
handled = true;
switch (this.getCharFromKeyPressEvent(event)) {
case "t":
this.setTextBoxToTodaysDate();
break;
case "+":
case ">":
case "=":
this.setTextBoxToNextDay();
break;
case "-":
case "<":
this.setTextBoxToPreviousDay();
break;
case "[":
this.setTextBoxToPreviousWeek();
break;
case "]":
this.setTextBoxToNextWeek();
break;
case "{":
this.setTextBoxToPreviousMonth();
break;
case "}":
this.setTextBoxToNextMonth();
break;
default:
handled = false;
break;
}
if (handled) {
this.cancel(event);
}
},
setTextBoxToChronicDate : function() {
today = new Date();
this.setDate(today);
},
setTextBoxToTodaysDate : function() {
today = new Date();
this.setDate(today);
},
setTextBoxToNextDay : function() {
this.addDaysToTextBoxDate(1);
},
setTextBoxToPreviousDay : function() {
this.addDaysToTextBoxDate(-1);
},
setTextBoxToNextWeek : function() {
this.addDaysToTextBoxDate(7);
},
setTextBoxToPreviousWeek : function() {
this.addDaysToTextBoxDate(-7);
},
addDaysToTextBoxDate : function(numDays) {
date = Date.parseDate(this.element.value, this.dateFormat);
date.setDate(date.getDate() + numDays);
this.setDate(date);
},
setTextBoxToNextMonth : function() {
date = Date.parseDate(this.element.value, this.dateFormat);
date.setMonth(date.getMonth() + 1);
this.setDate(date);
},
setTextBoxToPreviousMonth : function() {
date = Date.parseDate(this.element.value, this.dateFormat);
date.setMonth(date.getMonth() - 1);
this.setDate(date);
},
setDate : function(date) {
this.element.value = date.print(this.dateFormat);
if (window.calendar) {
window.calendar.setDate(date);
}
},
cancel : function(event) {
if (event.preventDefault) {
event.preventDefault();
}
event.returnValue = false;
},
getCharFromKeyPressEvent : function(event) {
var charCode = (event.charCode) ? event.charCode :
((event.keyCode) ? event.keyCode :
((event.which) ? event.which : 0));
return String.fromCharCode(charCode);
}
};

File diff suppressed because it is too large Load diff

View file

@ -1,963 +0,0 @@
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
if(typeof Effect == 'undefined')
throw("controls.js requires including script.aculo.us' effects.js library");
var Autocompleter = { };
Autocompleter.Base = Class.create({
baseInitialize: function(element, update, options) {
element = $(element);
this.element = element;
this.update = $(update);
this.hasFocus = false;
this.changed = false;
this.active = false;
this.index = 0;
this.entryCount = 0;
this.oldElementValue = this.element.value;
if(this.setOptions)
this.setOptions(options);
else
this.options = options || { };
this.options.paramName = this.options.paramName || this.element.name;
this.options.tokens = this.options.tokens || [];
this.options.frequency = this.options.frequency || 0.4;
this.options.minChars = this.options.minChars || 1;
this.options.onShow = this.options.onShow ||
function(element, update){
if(!update.style.position || update.style.position=='absolute') {
update.style.position = 'absolute';
Position.clone(element, update, {
setHeight: false,
offsetTop: element.offsetHeight
});
}
Effect.Appear(update,{duration:0.15});
};
this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
// Force carriage returns as token delimiters anyway
if (!this.options.tokens.include('\n'))
this.options.tokens.push('\n');
this.observer = null;
this.element.setAttribute('autocomplete','off');
Element.hide(this.update);
Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
},
show: function() {
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
if(!this.iefix &&
(Prototype.Browser.IE) &&
(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);" ' +
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
this.iefix = $(this.update.id+'_iefix');
}
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
},
fixIEOverlapping: function() {
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
},
hide: function() {
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
},
startIndicator: function() {
if(this.options.indicator) Element.show(this.options.indicator);
},
stopIndicator: function() {
if(this.options.indicator) Element.hide(this.options.indicator);
},
onKeyPress: function(event) {
if(this.active)
switch(event.keyCode) {
case Event.KEY_TAB:
case Event.KEY_RETURN:
this.selectEntry();
Event.stop(event);
case Event.KEY_ESC:
this.hide();
this.active = false;
Event.stop(event);
return;
case Event.KEY_LEFT:
case Event.KEY_RIGHT:
return;
case Event.KEY_UP:
this.markPrevious();
this.render();
Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
Event.stop(event);
return;
}
else
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
this.changed = true;
this.hasFocus = true;
if(this.observer) clearTimeout(this.observer);
this.observer =
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.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
},
onClick: function(event) {
var element = Event.findElement(event, 'LI');
this.index = element.autocompleteIndex;
this.selectEntry();
this.hide();
},
onBlur: function(event) {
// needed to make click events working
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
this.active = false;
},
render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}
},
markPrevious: function() {
if(this.index > 0) this.index--;
else this.index = this.entryCount-1;
this.getEntry(this.index).scrollIntoView(true);
},
markNext: function() {
if(this.index < this.entryCount-1) this.index++;
else this.index = 0;
this.getEntry(this.index).scrollIntoView(false);
},
getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},
getCurrentEntry: function() {
return this.getEntry(this.index);
},
selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
},
updateElement: function(selectedElement) {
if (this.options.updateElement) {
this.options.updateElement(selectedElement);
return;
}
var value = '';
if (this.options.select) {
var nodes = $(selectedElement).select('.' + this.options.select) || [];
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
var bounds = this.getTokenBounds();
if (bounds[0] != -1) {
var newValue = this.element.value.substr(0, bounds[0]);
var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
if (whitespace)
newValue += whitespace[0];
this.element.value = newValue + value + this.element.value.substr(bounds[1]);
} else {
this.element.value = value;
}
this.oldElementValue = this.element.value;
this.element.focus();
if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);
},
updateChoices: function(choices) {
if(!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
Element.cleanWhitespace(this.update.down());
if(this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
} else {
this.entryCount = 0;
}
this.stopIndicator();
this.index = 0;
if(this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
} else {
this.render();
}
}
},
addObservers: function(element) {
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
},
onObserverEvent: function() {
this.changed = false;
this.tokenBounds = null;
if(this.getToken().length>=this.options.minChars) {
this.getUpdatedChoices();
} else {
this.active = false;
this.hide();
}
this.oldElementValue = this.element.value;
},
getToken: function() {
var bounds = this.getTokenBounds();
return this.element.value.substring(bounds[0], bounds[1]).strip();
},
getTokenBounds: function() {
if (null != this.tokenBounds) return this.tokenBounds;
var value = this.element.value;
if (value.strip().empty()) return [-1, 0];
var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
var offset = (diff == this.oldElementValue.length ? 1 : 0);
var prevTokenPos = -1, nextTokenPos = value.length;
var tp;
for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
if (tp > prevTokenPos) prevTokenPos = tp;
tp = value.indexOf(this.options.tokens[index], diff + offset);
if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
}
return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
}
});
Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
var boundary = Math.min(newS.length, oldS.length);
for (var index = 0; index < boundary; ++index)
if (newS[index] != oldS[index])
return index;
return boundary;
};
Ajax.Autocompleter = Class.create(Autocompleter.Base, {
initialize: function(element, update, url, 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.url = url;
},
getUpdatedChoices: function() {
this.startIndicator();
var entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
},
onComplete: function(request) {
this.updateChoices(request.responseText);
}
});
// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
// text only at the beginning of strings in the
// autocomplete array. Defaults to true, which will
// match text at the beginning of any *word* in the
// strings in the autocomplete array. If you want to
// search anywhere in the string, additionally set
// the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
// a partial match (unlike minChars, which defines
// how many characters are required to do any match
// at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
// Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.
Autocompleter.Local = Class.create(Autocompleter.Base, {
initialize: function(element, update, array, options) {
this.baseInitialize(element, update, options);
this.options.array = array;
},
getUpdatedChoices: function() {
this.updateChoices(this.options.selector(this));
},
setOptions: function(options) {
this.options = Object.extend({
choices: 10,
partialSearch: true,
partialChars: 2,
ignoreCase: true,
fullSearch: false,
selector: function(instance) {
var ret = []; // Beginning matches
var partial = []; // Inside matches
var entry = instance.getToken();
var count = 0;
for (var i = 0; i < instance.options.array.length &&
ret.length < instance.options.choices ; i++) {
var elem = instance.options.array[i];
var foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase()) :
elem.indexOf(entry);
while (foundPos != -1) {
if (foundPos == 0 && elem.length != entry.length) {
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
elem.substr(entry.length) + "</li>");
break;
} else if (entry.length >= instance.options.partialChars &&
instance.options.partialSearch && foundPos != -1) {
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
foundPos + entry.length) + "</li>");
break;
}
}
foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
elem.indexOf(entry, foundPos + 1);
}
}
if (partial.length)
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
return "<ul>" + ret.join('') + "</ul>";
}
}, options || { });
}
});
// AJAX in-place editor and collection editor
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
setTimeout(function() {
Field.activate(field);
}, 1);
};
Ajax.InPlaceEditor = Class.create({
initialize: function(element, url, options) {
this.url = url;
this.element = element = $(element);
this.prepareOptions();
this._controls = { };
arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
Object.extend(this.options, options || { });
if (!this.options.formId && this.element.id) {
this.options.formId = this.element.id + '-inplaceeditor';
if ($(this.options.formId))
this.options.formId = '';
}
if (this.options.externalControl)
this.options.externalControl = $(this.options.externalControl);
if (!this.options.externalControl)
this.options.externalControlOnly = false;
this._originalBackground = this.element.getStyle('background-color') || 'transparent';
this.element.title = this.options.clickToEditText;
this._boundCancelHandler = this.handleFormCancellation.bind(this);
this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
this._boundFailureHandler = this.handleAJAXFailure.bind(this);
this._boundSubmitHandler = this.handleFormSubmission.bind(this);
this._boundWrapperHandler = this.wrapUp.bind(this);
this.registerListeners();
},
checkForEscapeOrReturn: function(e) {
if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
if (Event.KEY_ESC == e.keyCode)
this.handleFormCancellation(e);
else if (Event.KEY_RETURN == e.keyCode)
this.handleFormSubmission(e);
},
createControl: function(mode, handler, extraClasses) {
var control = this.options[mode + 'Control'];
var text = this.options[mode + 'Text'];
if ('button' == control) {
var btn = document.createElement('input');
btn.type = 'submit';
btn.value = text;
btn.className = 'editor_' + mode + '_button';
if ('cancel' == mode)
btn.onclick = this._boundCancelHandler;
this._form.appendChild(btn);
this._controls[mode] = btn;
} else if ('link' == control) {
var link = document.createElement('a');
link.href = '#';
link.appendChild(document.createTextNode(text));
link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
link.className = 'editor_' + mode + '_link';
if (extraClasses)
link.className += ' ' + extraClasses;
this._form.appendChild(link);
this._controls[mode] = link;
}
},
createEditField: function() {
var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
var fld;
if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
fld = document.createElement('input');
fld.type = 'text';
var size = this.options.size || this.options.cols || 0;
if (0 < size) fld.size = size;
} else {
fld = document.createElement('textarea');
fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
fld.cols = this.options.cols || 40;
}
fld.name = this.options.paramName;
fld.value = text; // No HTML breaks conversion anymore
fld.className = 'editor_field';
if (this.options.submitOnBlur)
fld.onblur = this._boundSubmitHandler;
this._controls.editor = fld;
if (this.options.loadTextURL)
this.loadExternalText();
this._form.appendChild(this._controls.editor);
},
createForm: function() {
var ipe = this;
function addText(mode, condition) {
var text = ipe.options['text' + mode + 'Controls'];
if (!text || condition === false) return;
ipe._form.appendChild(document.createTextNode(text));
};
this._form = $(document.createElement('form'));
this._form.id = this.options.formId;
this._form.addClassName(this.options.formClassName);
this._form.onsubmit = this._boundSubmitHandler;
this.createEditField();
if ('textarea' == this._controls.editor.tagName.toLowerCase())
this._form.appendChild(document.createElement('br'));
if (this.options.onFormCustomization)
this.options.onFormCustomization(this, this._form);
addText('Before', this.options.okControl || this.options.cancelControl);
this.createControl('ok', this._boundSubmitHandler);
addText('Between', this.options.okControl && this.options.cancelControl);
this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
addText('After', this.options.okControl || this.options.cancelControl);
},
destroy: function() {
if (this._oldInnerHTML)
this.element.innerHTML = this._oldInnerHTML;
this.leaveEditMode();
this.unregisterListeners();
},
enterEditMode: function(e) {
if (this._saving || this._editing) return;
this._editing = true;
this.triggerCallback('onEnterEditMode');
if (this.options.externalControl)
this.options.externalControl.hide();
this.element.hide();
this.createForm();
this.element.parentNode.insertBefore(this._form, this.element);
if (!this.options.loadTextURL)
this.postProcessEditField();
if (e) Event.stop(e);
},
enterHover: function(e) {
if (this.options.hoverClassName)
this.element.addClassName(this.options.hoverClassName);
if (this._saving) return;
this.triggerCallback('onEnterHover');
},
getText: function() {
return this.element.innerHTML.unescapeHTML();
},
handleAJAXFailure: function(transport) {
this.triggerCallback('onFailure', transport);
if (this._oldInnerHTML) {
this.element.innerHTML = this._oldInnerHTML;
this._oldInnerHTML = null;
}
},
handleFormCancellation: function(e) {
this.wrapUp();
if (e) Event.stop(e);
},
handleFormSubmission: function(e) {
var form = this._form;
var value = $F(this._controls.editor);
this.prepareSubmission();
var params = this.options.callback(form, value) || '';
if (Object.isString(params))
params = params.toQueryParams();
params.editorId = this.element.id;
if (this.options.htmlResponse) {
var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
Object.extend(options, {
parameters: params,
onComplete: this._boundWrapperHandler,
onFailure: this._boundFailureHandler
});
new Ajax.Updater({ success: this.element }, this.url, options);
} else {
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: params,
onComplete: this._boundWrapperHandler,
onFailure: this._boundFailureHandler
});
new Ajax.Request(this.url, options);
}
if (e) Event.stop(e);
},
leaveEditMode: function() {
this.element.removeClassName(this.options.savingClassName);
this.removeForm();
this.leaveHover();
this.element.style.backgroundColor = this._originalBackground;
this.element.show();
if (this.options.externalControl)
this.options.externalControl.show();
this._saving = false;
this._editing = false;
this._oldInnerHTML = null;
this.triggerCallback('onLeaveEditMode');
},
leaveHover: function(e) {
if (this.options.hoverClassName)
this.element.removeClassName(this.options.hoverClassName);
if (this._saving) return;
this.triggerCallback('onLeaveHover');
},
loadExternalText: function() {
this._form.addClassName(this.options.loadingClassName);
this._controls.editor.disabled = true;
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
this._form.removeClassName(this.options.loadingClassName);
var text = transport.responseText;
if (this.options.stripLoadedTextTags)
text = text.stripTags();
this._controls.editor.value = text;
this._controls.editor.disabled = false;
this.postProcessEditField();
}.bind(this),
onFailure: this._boundFailureHandler
});
new Ajax.Request(this.options.loadTextURL, options);
},
postProcessEditField: function() {
var fpc = this.options.fieldPostCreation;
if (fpc)
$(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
},
prepareOptions: function() {
this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
[this._extraDefaultOptions].flatten().compact().each(function(defs) {
Object.extend(this.options, defs);
}.bind(this));
},
prepareSubmission: function() {
this._saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
registerListeners: function() {
this._listeners = { };
var listener;
$H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
listener = this[pair.value].bind(this);
this._listeners[pair.key] = listener;
if (!this.options.externalControlOnly)
this.element.observe(pair.key, listener);
if (this.options.externalControl)
this.options.externalControl.observe(pair.key, listener);
}.bind(this));
},
removeForm: function() {
if (!this._form) return;
this._form.remove();
this._form = null;
this._controls = { };
},
showSaving: function() {
this._oldInnerHTML = this.element.innerHTML;
this.element.innerHTML = this.options.savingText;
this.element.addClassName(this.options.savingClassName);
this.element.style.backgroundColor = this._originalBackground;
this.element.show();
},
triggerCallback: function(cbName, arg) {
if ('function' == typeof this.options[cbName]) {
this.options[cbName](this, arg);
}
},
unregisterListeners: function() {
$H(this._listeners).each(function(pair) {
if (!this.options.externalControlOnly)
this.element.stopObserving(pair.key, pair.value);
if (this.options.externalControl)
this.options.externalControl.stopObserving(pair.key, pair.value);
}.bind(this));
},
wrapUp: function(transport) {
this.leaveEditMode();
// Can't use triggerCallback due to backward compatibility: requires
// binding + direct element
this._boundComplete(transport, this.element);
}
});
Object.extend(Ajax.InPlaceEditor.prototype, {
dispose: Ajax.InPlaceEditor.prototype.destroy
});
Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
initialize: function($super, element, url, options) {
this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
$super(element, url, options);
},
createEditField: function() {
var list = document.createElement('select');
list.name = this.options.paramName;
list.size = 1;
this._controls.editor = list;
this._collection = this.options.collection || [];
if (this.options.loadCollectionURL)
this.loadCollection();
else
this.checkForExternalText();
this._form.appendChild(this._controls.editor);
},
loadCollection: function() {
this._form.addClassName(this.options.loadingClassName);
this.showLoadingText(this.options.loadingCollectionText);
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
var js = transport.responseText.strip();
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
throw('Server returned an invalid collection representation.');
this._collection = eval(js);
this.checkForExternalText();
}.bind(this),
onFailure: this.onFailure
});
new Ajax.Request(this.options.loadCollectionURL, options);
},
showLoadingText: function(text) {
this._controls.editor.disabled = true;
var tempOption = this._controls.editor.firstChild;
if (!tempOption) {
tempOption = document.createElement('option');
tempOption.value = '';
this._controls.editor.appendChild(tempOption);
tempOption.selected = true;
}
tempOption.update((text || '').stripScripts().stripTags());
},
checkForExternalText: function() {
this._text = this.getText();
if (this.options.loadTextURL)
this.loadExternalText();
else
this.buildOptionList();
},
loadExternalText: function() {
this.showLoadingText(this.options.loadingText);
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
this._text = transport.responseText.strip();
this.buildOptionList();
}.bind(this),
onFailure: this.onFailure
});
new Ajax.Request(this.options.loadTextURL, options);
},
buildOptionList: function() {
this._form.removeClassName(this.options.loadingClassName);
this._collection = this._collection.map(function(entry) {
return 2 === entry.length ? entry : [entry, entry].flatten();
});
var marker = ('value' in this.options) ? this.options.value : this._text;
var textFound = this._collection.any(function(entry) {
return entry[0] == marker;
}.bind(this));
this._controls.editor.update('');
var option;
this._collection.each(function(entry, index) {
option = document.createElement('option');
option.value = entry[0];
option.selected = textFound ? entry[0] == marker : 0 == index;
option.appendChild(document.createTextNode(entry[1]));
this._controls.editor.appendChild(option);
}.bind(this));
this._controls.editor.disabled = false;
Field.scrollFreeActivate(this._controls.editor);
}
});
//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
//**** This only exists for a while, in order to let ****
//**** users adapt to the new API. Read up on the new ****
//**** API and convert your code to it ASAP! ****
Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
if (!options) return;
function fallback(name, expr) {
if (name in options || expr === undefined) return;
options[name] = expr;
};
fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
options.cancelLink == options.cancelButton == false ? false : undefined)));
fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
options.okLink == options.okButton == false ? false : undefined)));
fallback('highlightColor', options.highlightcolor);
fallback('highlightEndColor', options.highlightendcolor);
};
Object.extend(Ajax.InPlaceEditor, {
DefaultOptions: {
ajaxOptions: { },
autoRows: 3, // Use when multi-line w/ rows == 1
cancelControl: 'link', // 'link'|'button'|false
cancelText: 'cancel',
clickToEditText: 'Click to edit',
externalControl: null, // id|elt
externalControlOnly: false,
fieldPostCreation: 'activate', // 'activate'|'focus'|false
formClassName: 'inplaceeditor-form',
formId: null, // id|elt
highlightColor: '#ffff99',
highlightEndColor: '#ffffff',
hoverClassName: '',
htmlResponse: true,
loadingClassName: 'inplaceeditor-loading',
loadingText: 'Loading...',
okControl: 'button', // 'link'|'button'|false
okText: 'ok',
paramName: 'value',
rows: 1, // If 1 and multi-line, uses autoRows
savingClassName: 'inplaceeditor-saving',
savingText: 'Saving...',
size: 0,
stripLoadedTextTags: false,
submitOnBlur: false,
textAfterControls: '',
textBeforeControls: '',
textBetweenControls: ''
},
DefaultCallbacks: {
callback: function(form) {
return Form.serialize(form);
},
onComplete: function(transport, element) {
// For backward compatibility, this one is bound to the IPE, and passes
// the element directly. It was too often customized, so we don't break it.
new Effect.Highlight(element, {
startcolor: this.options.highlightColor, keepBackgroundImage: true });
},
onEnterEditMode: null,
onEnterHover: function(ipe) {
ipe.element.style.backgroundColor = ipe.options.highlightColor;
if (ipe._effect)
ipe._effect.cancel();
},
onFailure: function(transport, ipe) {
alert('Error communication with the server: ' + transport.responseText.stripTags());
},
onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
onLeaveEditMode: null,
onLeaveHover: function(ipe) {
ipe._effect = new Effect.Highlight(ipe.element, {
startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
restorecolor: ipe._originalBackground, keepBackgroundImage: true
});
}
},
Listeners: {
click: 'enterEditMode',
keydown: 'checkForEscapeOrReturn',
mouseover: 'enterHover',
mouseout: 'leaveHover'
}
});
Ajax.InPlaceCollectionEditor.DefaultOptions = {
loadingCollectionText: 'Loading options...'
};
// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
Form.Element.DelayedObserver = Class.create({
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));
}
});

View file

@ -1,973 +0,0 @@
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
if(Object.isUndefined(Effect))
throw("dragdrop.js requires including script.aculo.us' effects.js library");
var Droppables = {
drops: [],
remove: function(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,
tree: false
}, arguments[1] || { });
// cache containers
if(options.containment) {
options._containers = [];
var containment = options.containment;
if(Object.isArray(containment)) {
containment.each( function(c) { options._containers.push($(c)) });
} else {
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 containmentNode;
if(drop.tree) {
containmentNode = element.treeNode;
} else {
containmentNode = element.parentNode;
}
return drop._containers.detect(function(c) { return containmentNode == c });
},
isAffected: function(point, element, drop) {
return (
(drop.element!=element) &&
((!drop._containers) ||
this.isContained(element, drop)) &&
((!drop.accept) ||
(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.removeClassName(drop.element, drop.hoverclass);
this.last_active = null;
},
activate: function(drop) {
if(drop.hoverclass)
Element.addClassName(drop.element, drop.hoverclass);
this.last_active = drop;
},
show: function(point, element) {
if(!this.drops.length) return;
var drop, affected = [];
this.drops.each( function(drop) {
if(Droppables.isAffected(point, element, drop))
affected.push(drop);
});
if(affected.length>0)
drop = Droppables.findDeepestChild(affected);
if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
if (drop) {
Position.within(drop.element, point[0], point[1]);
if(drop.onHover)
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
if (drop != this.last_active) 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.last_active.onDrop) {
this.last_active.onDrop(element, this.last_active.element, event);
return true;
}
},
reset: function() {
if(this.last_active)
this.deactivate(this.last_active);
}
};
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) {
if(draggable.options.delay) {
this._timeout = setTimeout(function() {
Draggables._timeout = null;
window.focus();
Draggables.activeDraggable = draggable;
}.bind(this), draggable.options.delay);
} else {
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._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
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._cacheObserverCallbacks();
},
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);
});
if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
},
_cacheObserverCallbacks: function() {
['onStart','onEnd','onDrag'].each( function(eventName) {
Draggables[eventName+'Count'] = Draggables.observers.select(
function(o) { return o[eventName]; }
).length;
});
}
};
/*--------------------------------------------------------------------------*/
var Draggable = Class.create({
initialize: function(element) {
var defaults = {
handle: false,
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.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
queue: {scope:'_draggable', position:'end'}
});
},
endeffect: function(element) {
var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
queue: {scope:'_draggable', position:'end'},
afterFinish: function(){
Draggable._dragging[element] = false
}
});
},
zindex: 1000,
revert: false,
quiet: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
delay: 0
};
if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
Object.extend(defaults, {
starteffect: function(element) {
element._opacity = Element.getOpacity(element);
Draggable._dragging[element] = true;
new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
}
});
var options = Object.extend(defaults, arguments[1] || { });
this.element = $(element);
if(options.handle && Object.isString(options.handle))
this.handle = this.element.down('.'+options.handle, 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);
this._isScrollChild = Element.childOf(this.element, options.scroll);
}
Element.makePositioned(this.element); // fix IE
this.options = options;
this.dragging = false;
this.eventMouseDown = this.initDrag.bindAsEventListener(this);
Event.observe(this.handle, "mousedown", this.eventMouseDown);
Draggables.register(this);
},
destroy: function() {
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
Draggables.unregister(this);
},
currentDelta: function() {
return([
parseInt(Element.getStyle(this.element,'left') || '0'),
parseInt(Element.getStyle(this.element,'top') || '0')]);
},
initDrag: function(event) {
if(!Object.isUndefined(Draggable._dragging[this.element]) &&
Draggable._dragging[this.element]) return;
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if((tag_name = src.tagName.toUpperCase()) && (
tag_name=='INPUT' ||
tag_name=='SELECT' ||
tag_name=='OPTION' ||
tag_name=='BUTTON' ||
tag_name=='TEXTAREA')) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
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.delta)
this.delta = this.currentDelta();
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);
this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
if (!this._originallyAbsolute)
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);
if(!this.options.quiet){
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 + Position.deltaX;
p[1] += this.options.scroll.scrollTop + Position.deltaY;
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(Prototype.Browser.WebKit) window.scrollBy(0,0);
Event.stop(event);
},
finishDrag: function(event, success) {
this.dragging = false;
if(this.options.quiet){
Position.prepare();
var pointer = [Event.pointerX(event), Event.pointerY(event)];
Droppables.show(pointer, this.element);
}
if(this.options.ghosting) {
if (!this._originallyAbsolute)
Position.relativize(this.element);
delete this._originallyAbsolute;
Element.remove(this._clone);
this._clone = null;
}
var dropped = false;
if(success) {
dropped = Droppables.fire(event, this.element);
if (!dropped) dropped = false;
}
if(dropped && this.options.onDropped) this.options.onDropped(this.element);
Draggables.notify('onEnd', this, event);
var revert = this.options.revert;
if(revert && Object.isFunction(revert)) revert = revert(this.element);
var d = this.currentDelta();
if(revert && this.options.reverteffect) {
if (dropped == 0 || revert != 'failure')
this.options.reverteffect(this.element,
d[1]-this.delta[1], d[0]-this.delta[0]);
} else {
this.delta = d;
}
if(this.options.zindex)
this.element.style.zIndex = this.originalZ;
if(this.options.endeffect)
this.options.endeffect(this.element);
Draggables.deactivate(this);
Droppables.reset();
},
keyPress: function(event) {
if(event.keyCode!=Event.KEY_ESC) return;
this.finishDrag(event, false);
Event.stop(event);
},
endDrag: function(event) {
if(!this.dragging) return;
this.stopScrolling();
this.finishDrag(event, true);
Event.stop(event);
},
draw: function(point) {
var pos = Position.cumulativeOffset(this.element);
if(this.options.ghosting) {
var r = Position.realOffset(this.element);
pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
}
var d = this.currentDelta();
pos[0] -= d[0]; pos[1] -= d[1];
if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
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(Object.isFunction(this.options.snap)) {
p = this.options.snap(p[0],p[1],this);
} else {
if(Object.isArray(this.options.snap)) {
p = p.map( function(v, i) {
return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
} else {
p = p.map( function(v) {
return (v/this.options.snap).round()*this.options.snap }.bind(this));
}
}}
var style = this.element.style;
if((!this.options.constraint) || (this.options.constraint=='horizontal'))
style.left = p[0] + "px";
if((!this.options.constraint) || (this.options.constraint=='vertical'))
style.top = p[1] + "px";
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
},
stopScrolling: function() {
if(this.scrollInterval) {
clearInterval(this.scrollInterval);
this.scrollInterval = null;
Draggables._lastScrollPointer = null;
}
},
startScrolling: function(speed) {
if(!(speed[0] || speed[1])) return;
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] );
}
}
} 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);
if (this._isScrollChild) {
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 };
}
});
Draggable._dragging = { };
/*--------------------------------------------------------------------------*/
var SortableObserver = Class.create({
initialize: function(element, observer) {
this.element = $(element);
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))
this.observer(this.element)
}
});
var Sortable = {
SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
sortables: { },
_findRootElement: function(element) {
while (element.tagName.toUpperCase() != "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);
var s = Sortable.sortables[element.id];
if(s) {
Draggables.removeObserver(s.element);
s.droppables.each(function(d){ Droppables.remove(d) });
s.draggables.invoke('destroy');
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,
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
handle: false, // or a CSS class
only: false,
delay: 0,
hoverclass: null,
ghosting: false,
quiet: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
format: this.SERIALIZE_RULE,
// these take arrays of elements or ids and can be
// used for better initialization performance
elements: false,
handles: false,
onChange: Prototype.emptyFunction,
onUpdate: Prototype.emptyFunction
}, arguments[1] || { });
// clear any old sortable with same element
this.destroy(element);
// build options for the draggables
var options_for_draggable = {
revert: true,
quiet: options.quiet,
scroll: options.scroll,
scrollSpeed: options.scrollSpeed,
scrollSensitivity: options.scrollSensitivity,
delay: options.delay,
ghosting: options.ghosting,
constraint: options.constraint,
handle: options.handle };
if(options.starteffect)
options_for_draggable.starteffect = options.starteffect;
if(options.reverteffect)
options_for_draggable.reverteffect = options.reverteffect;
else
if(options.ghosting) options_for_draggable.reverteffect = function(element) {
element.style.top = 0;
element.style.left = 0;
};
if(options.endeffect)
options_for_draggable.endeffect = options.endeffect;
if(options.zindex)
options_for_draggable.zindex = options.zindex;
// build options for the droppables
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
tree: options.tree,
hoverclass: options.hoverclass,
onHover: Sortable.onHover
};
var options_for_tree = {
onHover: Sortable.onEmptyHover,
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass
};
// fix for gecko engine
Element.cleanWhitespace(element);
options.draggables = [];
options.droppables = [];
// drop on empty handling
if(options.dropOnEmpty || options.tree) {
Droppables.add(element, options_for_tree);
options.droppables.push(element);
}
(options.elements || this.findElements(element, options) || []).each( function(e,i) {
var handle = options.handles ? $(options.handles[i]) :
(options.handle ? $(e).select('.' + 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[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) {
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(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;
element.style.visibility = "hidden"; // fix gecko rendering
dropon.parentNode.insertBefore(element, dropon);
if(dropon.parentNode!=oldParentNode)
Sortable.options(oldParentNode).onChange(element);
Sortable.options(dropon.parentNode).onChange(element);
}
} else {
Sortable.mark(dropon, 'after');
var nextElement = dropon.nextSibling || null;
if(nextElement != element) {
var oldParentNode = element.parentNode;
element.style.visibility = "hidden"; // fix gecko rendering
dropon.parentNode.insertBefore(element, nextElement);
if(dropon.parentNode!=oldParentNode)
Sortable.options(oldParentNode).onChange(element);
Sortable.options(dropon.parentNode).onChange(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, only: droponOptions.only});
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);
droponOptions.onChange(element);
}
},
unmark: function() {
if(Sortable._marker) Sortable._marker.hide();
},
mark: function(dropon, position) {
// mark on ghosting only
var sortable = Sortable.options(dropon.parentNode);
if(sortable && !sortable.ghosting) return;
if(!Sortable._marker) {
Sortable._marker =
($('dropmarker') || Element.extend(document.createElement('DIV'))).
hide().addClassName('dropmarker').setStyle({position:'absolute'});
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
}
var offsets = Position.cumulativeOffset(dropon);
Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
if(position=='after')
if(sortable.overlap == 'horizontal')
Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
else
Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
Sortable._marker.show();
},
_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: [],
position: parent.children.length,
container: $(children[i]).down(options.treeTag)
};
/* 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;
},
tree: function(element) {
element = $(element);
var sortableOptions = this.options(element);
var options = Object.extend({
tag: sortableOptions.tag,
treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
format: sortableOptions.format
}, arguments[1] || { });
var root = {
id: null,
parent: null,
children: [],
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) + "[id]=" +
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) {
return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
};

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

104
public/javascripts/jquery-ui.js vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,808 @@
/*
* jQuery Autocomplete plugin 1.1
*
* Copyright (c) 2009 Jörn Zaefferer
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
*/
;(function($) {
$.fn.extend({
autocomplete: function(urlOrData, options) {
var isUrl = typeof urlOrData == "string";
options = $.extend({}, $.Autocompleter.defaults, {
url: isUrl ? urlOrData : null,
data: isUrl ? null : urlOrData,
delay: isUrl ? $.Autocompleter.defaults.delay : 10,
max: options && !options.scroll ? 10 : 150
}, options);
// if highlight is set to false, replace it with a do-nothing function
options.highlight = options.highlight || function(value) { return value; };
// if the formatMatch option is not specified, then use formatItem for backwards compatibility
options.formatMatch = options.formatMatch || options.formatItem;
return this.each(function() {
new $.Autocompleter(this, options);
});
},
result: function(handler) {
return this.bind("result", handler);
},
search: function(handler) {
return this.trigger("search", [handler]);
},
flushCache: function() {
return this.trigger("flushCache");
},
setOptions: function(options){
return this.trigger("setOptions", [options]);
},
unautocomplete: function() {
return this.trigger("unautocomplete");
}
});
$.Autocompleter = function(input, options) {
var KEY = {
UP: 38,
DOWN: 40,
DEL: 46,
TAB: 9,
RETURN: 13,
ESC: 27,
COMMA: 188,
PAGEUP: 33,
PAGEDOWN: 34,
BACKSPACE: 8
};
// Create $ object for input element
var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
var timeout;
var previousValue = "";
var cache = $.Autocompleter.Cache(options);
var hasFocus = 0;
var lastKeyPressCode;
var config = {
mouseDownOnSelect: false
};
var select = $.Autocompleter.Select(options, input, selectCurrent, config);
var blockSubmit;
// prevent form submit in opera when selecting with return key
$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
if (blockSubmit) {
blockSubmit = false;
return false;
}
});
// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
// a keypress means the input has focus
// avoids issue where input had focus before the autocomplete was applied
hasFocus = 1;
// track last key pressed
lastKeyPressCode = event.keyCode;
switch(event.keyCode) {
case KEY.UP:
event.preventDefault();
if ( select.visible() ) {
select.prev();
} else {
onChange(0, true);
}
break;
case KEY.DOWN:
event.preventDefault();
if ( select.visible() ) {
select.next();
} else {
onChange(0, true);
}
break;
case KEY.PAGEUP:
event.preventDefault();
if ( select.visible() ) {
select.pageUp();
} else {
onChange(0, true);
}
break;
case KEY.PAGEDOWN:
event.preventDefault();
if ( select.visible() ) {
select.pageDown();
} else {
onChange(0, true);
}
break;
// matches also semicolon
case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
case KEY.TAB:
case KEY.RETURN:
if( selectCurrent() ) {
// stop default to prevent a form submit, Opera needs special handling
event.preventDefault();
blockSubmit = true;
return false;
}
break;
case KEY.ESC:
select.hide();
break;
default:
clearTimeout(timeout);
timeout = setTimeout(onChange, options.delay);
break;
}
}).focus(function(){
// track whether the field has focus, we shouldn't process any
// results if the field no longer has focus
hasFocus++;
}).blur(function() {
hasFocus = 0;
if (!config.mouseDownOnSelect) {
hideResults();
}
}).click(function() {
// show select when clicking in a focused field
if ( hasFocus++ > 1 && !select.visible() ) {
onChange(0, true);
}
}).bind("search", function() {
// TODO why not just specifying both arguments?
var fn = (arguments.length > 1) ? arguments[1] : null;
function findValueCallback(q, data) {
var result;
if( data && data.length ) {
for (var i=0; i < data.length; i++) {
if( data[i].result.toLowerCase() == q.toLowerCase() ) {
result = data[i];
break;
}
}
}
if( typeof fn == "function" ) fn(result);
else $input.trigger("result", result && [result.data, result.value]);
}
$.each(trimWords($input.val()), function(i, value) {
request(value, findValueCallback, findValueCallback);
});
}).bind("flushCache", function() {
cache.flush();
}).bind("setOptions", function() {
$.extend(options, arguments[1]);
// if we've updated the data, repopulate
if ( "data" in arguments[1] )
cache.populate();
}).bind("unautocomplete", function() {
select.unbind();
$input.unbind();
$(input.form).unbind(".autocomplete");
});
function selectCurrent() {
var selected = select.selected();
if( !selected )
return false;
var v = selected.result;
previousValue = v;
if ( options.multiple ) {
var words = trimWords($input.val());
if ( words.length > 1 ) {
var seperator = options.multipleSeparator.length;
var cursorAt = $(input).selection().start;
var wordAt, progress = 0;
$.each(words, function(i, word) {
progress += word.length;
if (cursorAt <= progress) {
wordAt = i;
return false;
}
progress += seperator;
});
words[wordAt] = v;
// TODO this should set the cursor to the right position, but it gets overriden somewhere
//$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
v = words.join( options.multipleSeparator );
}
v += options.multipleSeparator;
}
$input.val(v);
hideResultsNow();
$input.trigger("result", [selected.data, selected.value]);
return true;
}
function onChange(crap, skipPrevCheck) {
if( lastKeyPressCode == KEY.DEL ) {
select.hide();
return;
}
var currentValue = $input.val();
if ( !skipPrevCheck && currentValue == previousValue )
return;
previousValue = currentValue;
currentValue = lastWord(currentValue);
if ( currentValue.length >= options.minChars) {
$input.addClass(options.loadingClass);
if (!options.matchCase)
currentValue = currentValue.toLowerCase();
request(currentValue, receiveData, hideResultsNow);
} else {
stopLoading();
select.hide();
}
};
function trimWords(value) {
if (!value)
return [""];
if (!options.multiple)
return [$.trim(value)];
return $.map(value.split(options.multipleSeparator), function(word) {
return $.trim(value).length ? $.trim(word) : null;
});
}
function lastWord(value) {
if ( !options.multiple )
return value;
var words = trimWords(value);
if (words.length == 1)
return words[0];
var cursorAt = $(input).selection().start;
if (cursorAt == value.length) {
words = trimWords(value)
} else {
words = trimWords(value.replace(value.substring(cursorAt), ""));
}
return words[words.length - 1];
}
// fills in the input box w/the first match (assumed to be the best match)
// q: the term entered
// sValue: the first matching result
function autoFill(q, sValue){
// autofill in the complete box w/the first match as long as the user hasn't entered in more data
// if the last user key pressed was backspace, don't autofill
if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
// fill in the value (keep the case the user has typed)
$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
// select the portion of the value not typed by the user (so the next character will erase)
$(input).selection(previousValue.length, previousValue.length + sValue.length);
}
};
function hideResults() {
clearTimeout(timeout);
timeout = setTimeout(hideResultsNow, 200);
};
function hideResultsNow() {
var wasVisible = select.visible();
select.hide();
clearTimeout(timeout);
stopLoading();
if (options.mustMatch) {
// call search and run callback
$input.search(
function (result){
// if no value found, clear the input box
if( !result ) {
if (options.multiple) {
var words = trimWords($input.val()).slice(0, -1);
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
}
else {
$input.val( "" );
$input.trigger("result", null);
}
}
}
);
}
};
function receiveData(q, data) {
if ( data && data.length && hasFocus ) {
stopLoading();
select.display(data, q);
autoFill(q, data[0].value);
select.show();
} else {
hideResultsNow();
}
};
function request(term, success, failure) {
if (!options.matchCase)
term = term.toLowerCase();
var data = cache.load(term);
// recieve the cached data
if (data && data.length) {
success(term, data);
// if an AJAX url has been supplied, try loading the data now
} else if( (typeof options.url == "string") && (options.url.length > 0) ){
var extraParams = {
timestamp: +new Date()
};
$.each(options.extraParams, function(key, param) {
extraParams[key] = typeof param == "function" ? param() : param;
});
$.ajax({
// try to leverage ajaxQueue plugin to abort previous requests
mode: "abort",
// limit abortion to this input
port: "autocomplete" + input.name,
dataType: options.dataType,
url: options.url,
data: $.extend({
q: lastWord(term),
limit: options.max
}, extraParams),
success: function(data) {
var parsed = options.parse && options.parse(data) || parse(data);
cache.add(term, parsed);
success(term, parsed);
}
});
} else {
// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
select.emptyList();
failure(term);
}
};
function parse(data) {
var parsed = [];
var rows = data.split("\n");
for (var i=0; i < rows.length; i++) {
var row = $.trim(rows[i]);
if (row) {
row = row.split("|");
parsed[parsed.length] = {
data: row,
value: row[0],
result: options.formatResult && options.formatResult(row, row[0]) || row[0]
};
}
}
return parsed;
};
function stopLoading() {
$input.removeClass(options.loadingClass);
};
};
$.Autocompleter.defaults = {
inputClass: "ac_input",
resultsClass: "ac_results",
loadingClass: "ac_loading",
minChars: 1,
delay: 400,
matchCase: false,
matchSubset: true,
matchContains: false,
cacheLength: 10,
max: 100,
mustMatch: false,
extraParams: {},
selectFirst: true,
formatItem: function(row) { return row[0]; },
formatMatch: null,
autoFill: false,
width: 0,
multiple: false,
multipleSeparator: ", ",
highlight: function(value, term) {
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
},
scroll: true,
scrollHeight: 180
};
$.Autocompleter.Cache = function(options) {
var data = {};
var length = 0;
function matchSubset(s, sub) {
if (!options.matchCase)
s = s.toLowerCase();
var i = s.indexOf(sub);
if (options.matchContains == "word"){
i = s.toLowerCase().search("\\b" + sub.toLowerCase());
}
if (i == -1) return false;
return i == 0 || options.matchContains;
};
function add(q, value) {
if (length > options.cacheLength){
flush();
}
if (!data[q]){
length++;
}
data[q] = value;
}
function populate(){
if( !options.data ) return false;
// track the matches
var stMatchSets = {},
nullData = 0;
// no url was specified, we need to adjust the cache length to make sure it fits the local data store
if( !options.url ) options.cacheLength = 1;
// track all options for minChars = 0
stMatchSets[""] = [];
// loop through the array and create a lookup structure
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
var rawValue = options.data[i];
// if rawValue is a string, make an array otherwise just reference the array
rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
var value = options.formatMatch(rawValue, i+1, options.data.length);
if ( value === false )
continue;
var firstChar = value.charAt(0).toLowerCase();
// if no lookup array for this character exists, look it up now
if( !stMatchSets[firstChar] )
stMatchSets[firstChar] = [];
// if the match is a string
var row = {
value: value,
data: rawValue,
result: options.formatResult && options.formatResult(rawValue) || value
};
// push the current match into the set list
stMatchSets[firstChar].push(row);
// keep track of minChars zero items
if ( nullData++ < options.max ) {
stMatchSets[""].push(row);
}
};
// add the data items to the cache
$.each(stMatchSets, function(i, value) {
// increase the cache size
options.cacheLength++;
// add to the cache
add(i, value);
});
}
// populate any existing data
setTimeout(populate, 25);
function flush(){
data = {};
length = 0;
}
return {
flush: flush,
add: add,
populate: populate,
load: function(q) {
if (!options.cacheLength || !length)
return null;
/*
* if dealing w/local data and matchContains than we must make sure
* to loop through all the data collections looking for matches
*/
if( !options.url && options.matchContains ){
// track all matches
var csub = [];
// loop through all the data grids for matches
for( var k in data ){
// don't search through the stMatchSets[""] (minChars: 0) cache
// this prevents duplicates
if( k.length > 0 ){
var c = data[k];
$.each(c, function(i, x) {
// if we've got a match, add it to the array
if (matchSubset(x.value, q)) {
csub.push(x);
}
});
}
}
return csub;
} else
// if the exact item exists, use it
if (data[q]){
return data[q];
} else
if (options.matchSubset) {
for (var i = q.length - 1; i >= options.minChars; i--) {
var c = data[q.substr(0, i)];
if (c) {
var csub = [];
$.each(c, function(i, x) {
if (matchSubset(x.value, q)) {
csub[csub.length] = x;
}
});
return csub;
}
}
}
return null;
}
};
};
$.Autocompleter.Select = function (options, input, select, config) {
var CLASSES = {
ACTIVE: "ac_over"
};
var listItems,
active = -1,
data,
term = "",
needsInit = true,
element,
list;
// Create results
function init() {
if (!needsInit)
return;
element = $("<div/>")
.hide()
.addClass(options.resultsClass)
.css("position", "absolute")
.appendTo(document.body);
list = $("<ul/>").appendTo(element).mouseover( function(event) {
if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
$(target(event)).addClass(CLASSES.ACTIVE);
}
}).click(function(event) {
$(target(event)).addClass(CLASSES.ACTIVE);
select();
// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
input.focus();
return false;
}).mousedown(function() {
config.mouseDownOnSelect = true;
}).mouseup(function() {
config.mouseDownOnSelect = false;
});
if( options.width > 0 )
element.css("width", options.width);
needsInit = false;
}
function target(event) {
var element = event.target;
while(element && element.tagName != "LI")
element = element.parentNode;
// more fun with IE, sometimes event.target is empty, just ignore it then
if(!element)
return [];
return element;
}
function moveSelect(step) {
listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
movePosition(step);
var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
if(options.scroll) {
var offset = 0;
listItems.slice(0, active).each(function() {
offset += this.offsetHeight;
});
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
} else if(offset < list.scrollTop()) {
list.scrollTop(offset);
}
}
};
function movePosition(step) {
active += step;
if (active < 0) {
active = listItems.size() - 1;
} else if (active >= listItems.size()) {
active = 0;
}
}
function limitNumberOfItems(available) {
return options.max && options.max < available
? options.max
: available;
}
function fillList() {
list.empty();
var max = limitNumberOfItems(data.length);
for (var i=0; i < max; i++) {
if (!data[i])
continue;
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
if ( formatted === false )
continue;
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
$.data(li, "ac_data", data[i]);
}
listItems = list.find("li");
if ( options.selectFirst ) {
listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
active = 0;
}
// apply bgiframe if available
if ( $.fn.bgiframe )
list.bgiframe();
}
return {
display: function(d, q) {
init();
data = d;
term = q;
fillList();
},
next: function() {
moveSelect(1);
},
prev: function() {
moveSelect(-1);
},
pageUp: function() {
if (active != 0 && active - 8 < 0) {
moveSelect( -active );
} else {
moveSelect(-8);
}
},
pageDown: function() {
if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
moveSelect( listItems.size() - 1 - active );
} else {
moveSelect(8);
}
},
hide: function() {
element && element.hide();
listItems && listItems.removeClass(CLASSES.ACTIVE);
active = -1;
},
visible : function() {
return element && element.is(":visible");
},
current: function() {
return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
},
show: function() {
var offset = $(input).offset();
element.css({
width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
top: offset.top + input.offsetHeight,
left: offset.left
}).show();
if(options.scroll) {
list.scrollTop(0);
list.css({
maxHeight: options.scrollHeight,
overflow: 'auto'
});
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
var listHeight = 0;
listItems.each(function() {
listHeight += this.offsetHeight;
});
var scrollbarsVisible = listHeight > options.scrollHeight;
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
if (!scrollbarsVisible) {
// IE doesn't recalculate width when scrollbar disappears
listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
}
}
}
},
selected: function() {
var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
return selected && selected.length && $.data(selected[0], "ac_data");
},
emptyList: function (){
list && list.empty();
},
unbind: function() {
element && element.remove();
}
};
};
$.fn.selection = function(start, end) {
if (start !== undefined) {
return this.each(function() {
if( this.createTextRange ){
var selRange = this.createTextRange();
if (end === undefined || start == end) {
selRange.move("character", start);
selRange.select();
} else {
selRange.collapse(true);
selRange.moveStart("character", start);
selRange.moveEnd("character", end);
selRange.select();
}
} else if( this.setSelectionRange ){
this.setSelectionRange(start, end);
} else if( this.selectionStart ){
this.selectionStart = start;
this.selectionEnd = end;
}
});
}
var field = this[0];
if ( field.createTextRange ) {
var range = document.selection.createRange(),
orig = field.value,
teststring = "<->",
textLength = range.text.length;
range.text = teststring;
var caretAt = field.value.indexOf(teststring);
field.value = orig;
this.selection(caretAt, caretAt + textLength);
return {
start: caretAt,
end: caretAt + textLength
}
} else if( field.selectionStart !== undefined ){
return {
start: field.selectionStart,
end: field.selectionEnd
}
}
};
})(jQuery);

View file

@ -0,0 +1,462 @@
/*!
* jQuery blockUI plugin
* Version 2.25 (29-AUG-2009)
* @requires jQuery v1.2.3 or later
*
* Examples at: http://malsup.com/jquery/block/
* Copyright (c) 2007-2008 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
*/
;(function($) {
if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
alert('blockUI requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery);
return;
}
$.fn._fadeIn = $.fn.fadeIn;
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
// retarded userAgent strings on Vista)
var mode = document.documentMode || 0;
var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;
// global $ methods for blocking/unblocking the entire page
$.blockUI = function(opts) { install(window, opts); };
$.unblockUI = function(opts) { remove(window, opts); };
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
$.growlUI = function(title, message, timeout, onClose) {
var $m = $('<div class="growlUI"></div>');
if (title) $m.append('<h1>'+title+'</h1>');
if (message) $m.append('<h2>'+message+'</h2>');
if (timeout == undefined) timeout = 3000;
$.blockUI({
message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
timeout: timeout, showOverlay: false,
onUnblock: onClose,
css: $.blockUI.defaults.growlCSS
});
};
// plugin method for blocking element content
$.fn.block = function(opts) {
return this.unblock({ fadeOut: 0 }).each(function() {
if ($.css(this,'position') == 'static')
this.style.position = 'relative';
if ($.browser.msie)
this.style.zoom = 1; // force 'hasLayout'
install(this, opts);
});
};
// plugin method for unblocking element content
$.fn.unblock = function(opts) {
return this.each(function() {
remove(this, opts);
});
};
$.blockUI.version = 2.25; // 2nd generation blocking at no extra cost!
// override these in your code to change the default behavior and style
$.blockUI.defaults = {
// message displayed when blocking (use null for no message)
message: '<h1>Please wait...</h1>',
title: null, // title string; only used when theme == true
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
theme: false, // set to true to use with jQuery UI themes
// styles for the message when blocking; if you wish to disable
// these and use an external stylesheet then do this in your code:
// $.blockUI.defaults.css = {};
css: {
padding: 0,
margin: 0,
width: '30%',
top: '40%',
left: '35%',
textAlign: 'center',
color: '#000',
border: '3px solid #aaa',
backgroundColor:'#fff',
cursor: 'wait'
},
// minimal style set used when themes are used
themedCSS: {
width: '30%',
top: '40%',
left: '35%'
},
// styles for the overlay
overlayCSS: {
opacity: 0.6,
cursor: 'wait'
},
// styles applied when using $.growlUI
growlCSS: {
width: '350px',
top: '10px',
left: '',
right: '10px',
border: 'none',
padding: '5px',
opacity: 0.6,
cursor: null,
color: '#fff',
backgroundColor: '#000',
'-webkit-border-radius': '10px',
'-moz-border-radius': '10px'
},
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
// (hat tip to Jorge H. N. de Vasconcelos)
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
// force usage of iframe in non-IE browsers (handy for blocking applets)
forceIframe: false,
// z-index for the blocking overlay
baseZ: 1000,
// set these to true to have the message automatically centered
centerX: true, // <-- only effects element blocking (page block controlled via css above)
centerY: true,
// allow body element to be stetched in ie6; this makes blocking look better
// on "short" pages. disable if you wish to prevent changes to the body height
allowBodyStretch: true,
// enable if you want key and mouse events to be disabled for content that is blocked
bindEvents: true,
// be default blockUI will supress tab navigation from leaving blocking content
// (if bindEvents is true)
constrainTabKey: true,
// fadeIn time in millis; set to 0 to disable fadeIn on block
fadeIn: 200,
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
fadeOut: 400,
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
timeout: 0,
// disable if you don't want to show the overlay
showOverlay: true,
// if true, focus will be placed in the first available input field when
// page blocking
focusInput: true,
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
applyPlatformOpacityRules: true,
// callback method invoked when unblocking has completed; the callback is
// passed the element that has been unblocked (which is the window object for page
// blocks) and the options that were passed to the unblock call:
// onUnblock(element, options)
onUnblock: null,
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
quirksmodeOffsetHack: 4
};
// private data and functions follow...
var pageBlock = null;
var pageBlockEls = [];
function install(el, opts) {
var full = (el == window);
var msg = opts && opts.message !== undefined ? opts.message : undefined;
opts = $.extend({}, $.blockUI.defaults, opts || {});
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
msg = msg === undefined ? opts.message : msg;
// remove the current block (if there is one)
if (full && pageBlock)
remove(window, {fadeOut:0});
// if an existing element is being used as the blocking content then we capture
// its current place in the DOM (and current display style) so we can restore
// it when we unblock
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
var node = msg.jquery ? msg[0] : msg;
var data = {};
$(el).data('blockUI.history', data);
data.el = node;
data.parent = node.parentNode;
data.display = node.style.display;
data.position = node.style.position;
if (data.parent)
data.parent.removeChild(node);
}
var z = opts.baseZ;
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
// layer1 is the iframe layer which is used to supress bleed through of underlying content
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
// layer3 is the message content that is displayed while blocking
var lyr1 = ($.browser.msie || opts.forceIframe)
? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
: $('<div class="blockUI" style="display:none"></div>');
var lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
var lyr3;
if (opts.theme && full) {
var s = '<div class="blockUI blockMsg blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+z+';display:none;position:fixed">' +
'<div class="ui-widget-header ui-dialog-titlebar blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
'<div class="ui-widget-content ui-dialog-content"></div>' +
'</div>';
lyr3 = $(s);
}
else {
lyr3 = full ? $('<div class="blockUI blockMsg blockPage" style="z-index:'+z+';display:none;position:fixed"></div>')
: $('<div class="blockUI blockMsg blockElement" style="z-index:'+z+';display:none;position:absolute"></div>');
}
// if we have a message, style it
if (msg) {
if (opts.theme) {
lyr3.css(themedCSS);
lyr3.addClass('ui-widget-content');
}
else
lyr3.css(css);
}
// style the overlay
if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
lyr2.css(opts.overlayCSS);
lyr2.css('position', full ? 'fixed' : 'absolute');
// make iframe layer transparent in IE
if ($.browser.msie || opts.forceIframe)
lyr1.css('opacity',0.0);
$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
if (opts.theme && opts.draggable && $.fn.draggable) {
lyr3.draggable({
handle: '.ui-dialog-titlebar',
cancel: 'li'
});
}
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
if (ie6 || expr) {
// give body 100% height
if (full && opts.allowBodyStretch && $.boxModel)
$('html,body').css('height','100%');
// fix ie6 issue when blocked element has a border width
if ((ie6 || !$.boxModel) && !full) {
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
var fixT = t ? '(0 - '+t+')' : 0;
var fixL = l ? '(0 - '+l+')' : 0;
}
// simulate fixed position
$.each([lyr1,lyr2,lyr3], function(i,o) {
var s = o[0].style;
s.position = 'absolute';
if (i < 2) {
full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
: s.setExpression('height','this.parentNode.offsetHeight + "px"');
full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
: s.setExpression('width','this.parentNode.offsetWidth + "px"');
if (fixL) s.setExpression('left', fixL);
if (fixT) s.setExpression('top', fixT);
}
else if (opts.centerY) {
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
s.marginTop = 0;
}
else if (!opts.centerY && full) {
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
s.setExpression('top',expression);
}
});
}
// show the message
if (msg) {
if (opts.theme)
lyr3.find('.ui-widget-content').append(msg);
else
lyr3.append(msg);
if (msg.jquery || msg.nodeType)
$(msg).show();
}
if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
lyr1.show(); // opacity is zero
if (opts.fadeIn) {
if (opts.showOverlay)
lyr2._fadeIn(opts.fadeIn);
if (msg)
lyr3.fadeIn(opts.fadeIn);
}
else {
if (opts.showOverlay)
lyr2.show();
if (msg)
lyr3.show();
}
// bind key and mouse events
bind(1, el, opts);
if (full) {
pageBlock = lyr3[0];
pageBlockEls = $(':input:enabled:visible',pageBlock);
if (opts.focusInput)
setTimeout(focus, 20);
}
else
center(lyr3[0], opts.centerX, opts.centerY);
if (opts.timeout) {
// auto-unblock
var to = setTimeout(function() {
full ? $.unblockUI(opts) : $(el).unblock(opts);
}, opts.timeout);
$(el).data('blockUI.timeout', to);
}
};
// remove the block
function remove(el, opts) {
var full = (el == window);
var $el = $(el);
var data = $el.data('blockUI.history');
var to = $el.data('blockUI.timeout');
if (to) {
clearTimeout(to);
$el.removeData('blockUI.timeout');
}
opts = $.extend({}, $.blockUI.defaults, opts || {});
bind(0, el, opts); // unbind events
var els;
if (full) // crazy selector to handle odd field errors in ie6/7
els = $('body').children().filter('.blockUI').add('body > .blockUI');
else
els = $('.blockUI', el);
if (full)
pageBlock = pageBlockEls = null;
if (opts.fadeOut) {
els.fadeOut(opts.fadeOut);
setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
}
else
reset(els, data, opts, el);
};
// move blocking element back into the DOM where it started
function reset(els,data,opts,el) {
els.each(function(i,o) {
// remove via DOM calls so we don't lose event handlers
if (this.parentNode)
this.parentNode.removeChild(this);
});
if (data && data.el) {
data.el.style.display = data.display;
data.el.style.position = data.position;
if (data.parent)
data.parent.appendChild(data.el);
$(data.el).removeData('blockUI.history');
}
if (typeof opts.onUnblock == 'function')
opts.onUnblock(el,opts);
};
// bind/unbind the handler
function bind(b, el, opts) {
var full = el == window, $el = $(el);
// don't bother unbinding if there is nothing to unbind
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
return;
if (!full)
$el.data('blockUI.isBlocked', b);
// don't bind events when overlay is not in use or if bindEvents is false
if (!opts.bindEvents || (b && !opts.showOverlay))
return;
// bind anchors and inputs for mouse and key events
var events = 'mousedown mouseup keydown keypress';
b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
// former impl...
// var $e = $('a,:input');
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
};
// event handler to suppress keyboard/mouse events when blocking
function handler(e) {
// allow tab navigation (conditionally)
if (e.keyCode && e.keyCode == 9) {
if (pageBlock && e.data.constrainTabKey) {
var els = pageBlockEls;
var fwd = !e.shiftKey && e.target == els[els.length-1];
var back = e.shiftKey && e.target == els[0];
if (fwd || back) {
setTimeout(function(){focus(back)},10);
return false;
}
}
}
// allow events within the message content
if ($(e.target).parents('div.blockMsg').length > 0)
return true;
// allow events for content that is not being blocked
return $(e.target).parents().children().filter('div.blockUI').length == 0;
};
function focus(back) {
if (!pageBlockEls)
return;
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
if (e)
e.focus();
};
function center(el, x, y) {
var p = el.parentNode, s = el.style;
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
if (x) s.left = l > 0 ? (l+'px') : '0';
if (y) s.top = t > 0 ? (t+'px') : '0';
};
function sz(el, p) {
return parseInt($.css(el,p))||0;
};
})(jQuery);

View file

@ -0,0 +1,96 @@
/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// CAUTION: Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};

View file

@ -0,0 +1,38 @@
(function($){$.fn.editable=function(target,options){if('disable'==target){$(this).data('disabled.editable',true);return;}
if('enable'==target){$(this).data('disabled.editable',false);return;}
if('destroy'==target){$(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');return;}
var settings=$.extend({},$.fn.editable.defaults,{target:target},options);var plugin=$.editable.types[settings.type].plugin||function(){};var submit=$.editable.types[settings.type].submit||function(){};var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;var callback=settings.callback||function(){};var onedit=settings.onedit||function(){};var onsubmit=settings.onsubmit||function(){};var onreset=settings.onreset||function(){};var onerror=settings.onerror||reset;if(settings.tooltip){$(this).attr('title',settings.tooltip);}
settings.autowidth='auto'==settings.width;settings.autoheight='auto'==settings.height;return this.each(function(){var self=this;var savedwidth=$(self).width();var savedheight=$(self).height();$(this).data('event.editable',settings.event);if(!$.trim($(this).html())){$(this).html(settings.placeholder);}
$(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;}
if(self.editing){return;}
if(false===onedit.apply(this,[settings,self])){return;}
e.preventDefault();e.stopPropagation();if(settings.tooltip){$(self).removeAttr('title');}
if(0==$(self).width()){settings.width=savedwidth;settings.height=savedheight;}else{if(settings.width!='none'){settings.width=settings.autowidth?$(self).width():settings.width;}
if(settings.height!='none'){settings.height=settings.autoheight?$(self).height():settings.height;}}
if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){$(this).html('');}
self.editing=true;self.revert=$(self).html();$(self).html('');var form=$('<form />');if(settings.cssclass){if('inherit'==settings.cssclass){form.attr('class',$(self).attr('class'));}else{form.attr('class',settings.cssclass);}}
if(settings.style){if('inherit'==settings.style){form.attr('style',$(self).attr('style'));form.css('display',$(self).css('display'));}else{form.attr('style',settings.style);}}
var input=element.apply(form,[settings,self]);var input_content;if(settings.loadurl){var t=setTimeout(function(){input.disabled=true;content.apply(form,[settings.loadtext,settings,self]);},100);var loaddata={};loaddata[settings.id]=self.id;if($.isFunction(settings.loaddata)){$.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));}else{$.extend(loaddata,settings.loaddata);}
$.ajax({type:settings.loadtype,url:settings.loadurl,data:loaddata,async:false,success:function(result){window.clearTimeout(t);input_content=result;input.disabled=false;}});}else if(settings.data){input_content=settings.data;if($.isFunction(settings.data)){input_content=settings.data.apply(self,[self.revert,settings]);}}else{input_content=self.revert;}
content.apply(form,[input_content,settings,self]);input.attr('name',settings.name);buttons.apply(form,[settings,self]);$(self).append(form);plugin.apply(form,[settings,self]);$(':input:visible:enabled:first',form).focus();if(settings.select){input.select();}
input.keydown(function(e){if(e.keyCode==27){e.preventDefault();reset.apply(form,[settings,self]);}});var t;if('cancel'==settings.onblur){input.blur(function(e){t=setTimeout(function(){reset.apply(form,[settings,self]);},500);});}else if('submit'==settings.onblur){input.blur(function(e){t=setTimeout(function(){form.submit();},200);});}else if($.isFunction(settings.onblur)){input.blur(function(e){settings.onblur.apply(self,[input.val(),settings]);});}else{input.blur(function(e){});}
form.submit(function(e){if(t){clearTimeout(t);}
e.preventDefault();if(false!==onsubmit.apply(form,[settings,self])){if(false!==submit.apply(form,[settings,self])){if($.isFunction(settings.target)){var str=settings.target.apply(self,[input.val(),settings]);$(self).html(str);self.editing=false;callback.apply(self,[self.innerHTML,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}}else{var submitdata={};submitdata[settings.name]=input.val();submitdata[settings.id]=self.id;if($.isFunction(settings.submitdata)){$.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));}else{$.extend(submitdata,settings.submitdata);}
if('PUT'==settings.method){submitdata['_method']='put';}
$(self).html(settings.indicator);var ajaxoptions={type:'POST',data:submitdata,dataType:'html',url:settings.target,success:function(result,status){if(ajaxoptions.dataType=='html'){$(self).html(result);}
self.editing=false;callback.apply(self,[result,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}},error:function(xhr,status,error){onerror.apply(form,[settings,self,xhr]);}};$.extend(ajaxoptions,settings.ajaxoptions);$.ajax(ajaxoptions);}}}
$(self).attr('title',settings.tooltip);return false;});});this.reset=function(form){if(this.editing){if(false!==onreset.apply(form,[settings,self])){$(self).html(self.revert);self.editing=false;if(!$.trim($(self).html())){$(self).html(settings.placeholder);}
if(settings.tooltip){$(self).attr('title',settings.tooltip);}}}};});};$.editable={types:{defaults:{element:function(settings,original){var input=$('<input type="hidden"></input>');$(this).append(input);return(input);},content:function(string,settings,original){$(':input:first',this).val(string);},reset:function(settings,original){original.reset(this);},buttons:function(settings,original){var form=this;if(settings.submit){if(settings.submit.match(/>$/)){var submit=$(settings.submit).click(function(){if(submit.attr("type")!="submit"){form.submit();}});}else{var submit=$('<button type="submit" />');submit.html(settings.submit);}
$(this).append(submit);}
if(settings.cancel){if(settings.cancel.match(/>$/)){var cancel=$(settings.cancel);}else{var cancel=$('<button type="cancel" />');cancel.html(settings.cancel);}
$(this).append(cancel);$(cancel).click(function(event){if($.isFunction($.editable.types[settings.type].reset)){var reset=$.editable.types[settings.type].reset;}else{var reset=$.editable.types['defaults'].reset;}
reset.apply(form,[settings,original]);return false;});}}},text:{element:function(settings,original){var input=$('<input />');if(settings.width!='none'){input.width(settings.width);}
if(settings.height!='none'){input.height(settings.height);}
input.attr('autocomplete','off');$(this).append(input);return(input);}},textarea:{element:function(settings,original){var textarea=$('<textarea />');if(settings.rows){textarea.attr('rows',settings.rows);}else if(settings.height!="none"){textarea.height(settings.height);}
if(settings.cols){textarea.attr('cols',settings.cols);}else if(settings.width!="none"){textarea.width(settings.width);}
$(this).append(textarea);return(textarea);}},select:{element:function(settings,original){var select=$('<select />');$(this).append(select);return(select);},content:function(data,settings,original){if(String==data.constructor){eval('var json = '+data);}else{var json=data;}
for(var key in json){if(!json.hasOwnProperty(key)){continue;}
if('selected'==key){continue;}
var option=$('<option />').val(key).append(json[key]);$('select',this).append(option);}
$('select',this).children().each(function(){if($(this).val()==json['selected']||$(this).text()==$.trim(original.revert)){$(this).attr('selected','selected');}});}}},addInputType:function(name,input){$.editable.types[name]=input;}};$.fn.editable.defaults={name:'value',id:'id',type:'text',width:'auto',height:'auto',event:'click.editable',onblur:'cancel',loadtype:'GET',loadtext:'Loading...',placeholder:'Click to edit',loaddata:{},submitdata:{},ajaxoptions:{}};})(jQuery);

19
public/javascripts/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(function($){$.ajaxSettings.accepts._default="text/javascript, text/html, application/xml, text/xml, */*"})(jQuery);(function($){$.fn.reset=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};$.fn.enable=function(){return this.each(function(){this.disabled=false})};$.fn.disable=function(){return this.each(function(){this.disabled=true})}})(jQuery);(function($){$.extend({fieldEvent:function(el,obs){var field=el[0]||el,e="change";if(field.type=="radio"||field.type=="checkbox"){e="click"}else{if(obs&&(field.type=="text"||field.type=="textarea"||field.type=="password")){e="keyup"}}return e}});$.fn.extend({delayedObserver:function(delay,callback){var el=$(this);if(typeof window.delayedObserverStack=="undefined"){window.delayedObserverStack=[]}if(typeof window.delayedObserverCallback=="undefined"){window.delayedObserverCallback=function(stackPos){var observed=window.delayedObserverStack[stackPos];if(observed.timer){clearTimeout(observed.timer)}observed.timer=setTimeout(function(){observed.timer=null;observed.callback(observed.obj,observed.obj.formVal())},observed.delay*1000);observed.oldVal=observed.obj.formVal()}}window.delayedObserverStack.push({obj:el,timer:null,delay:delay,oldVal:el.formVal(),callback:callback});var stackPos=window.delayedObserverStack.length-1;if(el[0].tagName=="FORM"){$(":input",el).each(function(){var field=$(this);field.bind($.fieldEvent(field,delay),function(){var observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.oldVal){return}else{window.delayedObserverCallback(stackPos)}})})}else{el.bind($.fieldEvent(el,delay),function(){var observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.oldVal){return}else{window.delayedObserverCallback(stackPos)}})}},formVal:function(){var el=this[0];if(el.tagName=="FORM"){return this.serialize()}if(el.type=="checkbox"||el.type=="radio"){return this.filter("input:checked").val()||""}else{return this.val()}}})})(jQuery);(function($){$.fn.extend({visualEffect:function(o,options){if(options){speed=options.duration*1000}else{speed=null}e=o.replace(/\_(.)/g,function(m,l){return l.toUpperCase()});return eval("$(this)."+e+"("+speed+")")},appear:function(speed,callback){return this.fadeIn(speed,callback)},blindDown:function(speed,callback){return this.show("blind",{direction:"vertical"},speed,callback)},blindUp:function(speed,callback){return this.hide("blind",{direction:"vertical"},speed,callback)},blindRight:function(speed,callback){return this.show("blind",{direction:"horizontal"},speed,callback)},blindLeft:function(speed,callback){this.hide("blind",{direction:"horizontal"},speed,callback);return this},dropOut:function(speed,callback){return this.hide("drop",{direction:"down"},speed,callback)},dropIn:function(speed,callback){return this.show("drop",{direction:"up"},speed,callback)},fade:function(speed,callback){return this.fadeOut(speed,callback)},fadeToggle:function(speed,callback){return this.animate({opacity:"toggle"},speed,callback)},fold:function(speed,callback){return this.hide("fold",{},speed,callback)},foldOut:function(speed,callback){return this.show("fold",{},speed,callback)},grow:function(speed,callback){return this.show("scale",{},speed,callback)},highlight:function(speed,callback){return this.show("highlight",{},speed,callback)},puff:function(speed,callback){return this.hide("puff",{},speed,callback)},pulsate:function(speed,callback){return this.show("pulsate",{},speed,callback)},shake:function(speed,callback){return this.show("shake",{},speed,callback)},shrink:function(speed,callback){return this.hide("scale",{},speed,callback)},squish:function(speed,callback){return this.hide("scale",{origin:["top","left"]},speed,callback)},slideUp:function(speed,callback){return this.hide("slide",{direction:"up"},speed,callback)},slideDown:function(speed,callback){return this.show("slide",{direction:"up"},speed,callback)},switchOff:function(speed,callback){return this.hide("clip",{},speed,callback)},switchOn:function(speed,callback){return this.show("clip",{},speed,callback)}})})(jQuery);

View file

@ -1,389 +0,0 @@
LowPro = {};
LowPro.Version = '0.2';
if (!Element.addMethods)
Element.addMethods = function(o) { Object.extend(Element.Methods, o) };
// Simple utility methods for working with the DOM
DOM = {
nextElement : function(element) {
element = $(element);
while (element = element.nextSibling)
if (element.nodeType == 1) return $(element);
return null;
},
previousElement : function(element) {
element = $(element);
while (element = element.previousSibling)
if (element.nodeType == 1) return $(element);
return null;
},
remove : function(element) {
return $(element).parentNode.removeChild(element);
},
insertAfter : function(element, node) {
return $(element).previousSibling.inserBefore(node);
},
replaceElement : function(element, node) {
$(element).parentNode.replaceChild(node, element);
return node;
}
};
// Add them to the element mixin
Element.addMethods(DOM);
// DOMBuilder for prototype
DOM.Builder = {
IE_TRANSLATIONS : {
'class' : 'className',
'for' : 'htmlFor'
},
ieAttrSet : function(attrs, attr, el) {
var trans;
if (trans = this.IE_TRANSLATIONS[attr]) el[trans] = attrs[attr];
else if (attr == 'style') el.style.cssText = attrs[attr];
else if (attr.match(/^on/)) el[attr] = new Function(attrs[attr]);
else el.setAttribute(attr, attrs[attr]);
},
tagFunc : function(tag) {
return function() {
var attrs, children;
if (arguments.length>0) {
if (arguments[0].nodeName || typeof arguments[0] == "string") children = arguments;
else { attrs = arguments[0]; children = [].slice.call(arguments, 1); };
}
return DOM.Builder.create(tag, attrs, children);
};
},
create : function(tag, attrs, children) {
attrs = attrs || {}; children = children || [];
var isIE = navigator.userAgent.match(/MSIE/);
var el = document.createElement((isIE && attrs.name) ? "<" + tag + " name=" + attrs.name + ">" : tag);
for (var attr in attrs) {
if (typeof attrs[attr] != 'function') {
if (isIE) this.ieAttrSet(attrs, attrs, el);
else el.setAttribute(attr, attrs[attr]);
};
}
for (var i=0; i<children.length; i++) {
if (typeof children[i] == 'string') children[i] = document.createTextNode(children[i]);
el.appendChild(children[i]);
}
return $(el);
}
};
// Automatically create node builders as $tagName.
(function() {
var els = ("p|div|span|strong|em|img|table|tr|td|th|thead|tbody|tfoot|pre|code|" +
"h1|h2|h3|h4|h5|h6|ul|ol|li|form|input|textarea|legend|fieldset|" +
"select|option|blockquote|cite|br|hr|dd|dl|dt|address|a|button|abbr|acronym|" +
"script|link|style|bdo|ins|del|object|param|col|colgroup|optgroup|caption|" +
"label|dfn|kbd|samp|var").split("|");
var el, i=0;
while (el = els[i++]) window['$' + el] = DOM.Builder.tagFunc(el);
})();
// Adapted from DOM Ready extension by Dan Webb
// http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype
// which was based on work by Matthias Miller, Dean Edwards and John Resig
//
// Usage:
//
// Event.onReady(callbackFunction);
Object.extend(Event, {
_domReady : function() {
if (arguments.callee.done) return;
arguments.callee.done = true;
if (Event._timer) clearInterval(Event._timer);
Event._readyCallbacks.each(function(f) { f() });
Event._readyCallbacks = null;
},
onReady : function(f) {
if (!this._readyCallbacks) {
var domReady = this._domReady;
if (domReady.done) return f();
if (document.addEventListener)
document.addEventListener("DOMContentLoaded", domReady, false);
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
document.getElementById("__ie_onload").onreadystatechange = function() {
if (this.readyState == "complete") { domReady(); }
};
/*@end @*/
if (/WebKit/i.test(navigator.userAgent)) {
this._timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) domReady();
}, 10);
}
Event.observe(window, 'load', domReady);
Event._readyCallbacks = [];
}
Event._readyCallbacks.push(f);
}
});
// Extend Element with observe and stopObserving.
Element.addMethods({
observe : function(el, event, callback) {
Event.observe(el, event, callback);
},
stopObserving : function(el, event, callback) {
Event.stopObserving(el, event, callback);
}
});
// Replace out existing event observe code with Dean Edwards' addEvent
// http://dean.edwards.name/weblog/2005/10/add-event/
Object.extend(Event, {
observe : function(el, type, func) {
el = $(el);
if (!func.$$guid) func.$$guid = Event._guid++;
if (!el.events) el.events = {};
var handlers = el.events[type];
if (!handlers) {
handlers = el.events[type] = {};
if (el["on" + type]) {
handlers[0] = el["on" + type];
}
}
handlers[func.$$guid] = func;
el["on" + type] = Event._handleEvent;
if (!Event.observers) Event.observers = [];
Event.observers.push([el, name, func, false]);
},
stopObserving : function(el, type, func) {
if (el.events && el.events[type]) delete el.events[type][func.$$guid];
},
_handleEvent : function(e) {
var returnValue = true;
e = e || Event._fixEvent(window.event);
var handlers = this.events[e.type], el = $(this);
for (var i in handlers) {
el.$$handleEvent = handlers[i];
if (el.$$handleEvent(e) === false) returnValue = false;
}
return returnValue;
},
_fixEvent : function(e) {
e.preventDefault = Event._preventDefault;
e.stopPropagation = Event._stopPropagation;
return e;
},
_preventDefault : function() { this.returnValue = false },
_stopPropagation : function() { this.cancelBubble = true },
_guid : 1
});
// Allows you to trigger an event element.
Object.extend(Event, {
trigger : function(element, event, fakeEvent) {
element = $(element);
fakeEvent = fakeEvent || { type : event };
this.observers.each(function(cache) {
if (cache[0] == element && cache[1] == event)
cache[2].call(element, fakeEvent);
});
}
});
// Based on event:Selectors by Justin Palmer
// http://encytemedia.com/event-selectors/
//
// Usage:
//
// Event.addBehavior({
// "selector:event" : function(event) { /* event handler. this refers to the element. */ },
// "selector" : function() { /* runs function on dom ready. this refers to the element. */ }
// ...
// });
//
// Multiple calls will add to exisiting rules. Event.addBehavior.reassignAfterAjax and
// Event.addBehavior.autoTrigger can be adjusted to needs.
Event.addBehavior = function(rules) {
var ab = this.addBehavior;
Object.extend(ab.rules, rules);
if (ab.autoTrigger) {
this.onReady(ab.load.bind(ab));
}
Ajax.Responders.register({
onComplete : function() {
if (Event.addBehavior.reassignAfterAjax)
setTimeout(function() { ab.load() }, 10);
}
});
};
Object.extend(Event.addBehavior, {
rules : {}, cache : [],
reassignAfterAjax : true,
autoTrigger : true,
load : function() {
this.unload();
for (var selector in this.rules) {
var observer = this.rules[selector];
var sels = selector.split(',');
sels.each(function(sel) {
var parts = sel.split(/:(?=[a-z]+$)/), css = parts[0], event = parts[1];
$$(css).each(function(element) {
if (event) {
$(element).observe(event, observer);
Event.addBehavior.cache.push([element, event, observer]);
} else {
if (!element.$$assigned || !element.$$assigned.include(observer)) {
if (observer.attach) observer.attach(element);
else observer.call($(element));
element.$$assigned = element.$$assigned || [];
element.$$assigned.push(observer);
}
}
});
});
}
},
unload : function() {
this.cache.each(function(c) {
Event.stopObserving.apply(Event, c);
});
}
});
Event.observe(window, 'unload', Event.addBehavior.unload.bind(Event.addBehavior));
// Behaviors can be bound to elements to provide an object orientated way of controlling elements
// and their behavior. Use Behavior.create() to make a new behavior class then use attach() to
// glue it to an element. Each element then gets it's own instance of the behavior and any
// methods called onxxx are bound to the relevent event.
//
// Usage:
//
// var MyBehavior = Behavior.create({
// onmouseover : function() { this.element.addClassName('bong') }
// });
// Event.addBehavior({ 'a.rollover' : MyBehavior });
Behavior = {
create : function(members) {
var behavior = function(element) { this.element = $(element) };
behavior.prototype.initialize = Prototype.K;
Object.extend(behavior.prototype, members);
Object.extend(behavior, Behavior.ClassMethods);
return behavior;
},
ClassMethods : {
attach : function(element) {
var bound = new this(element);
bound.initialize.apply(bound);
this._bindEvents(bound);
return bound;
},
_bindEvents : function(bound) {
for (var member in bound)
if (member.match(/^on(.+)/) && typeof bound[member] == 'function')
bound.element.observe(RegExp.$1, bound[member].bindAsEventListener(bound));
}
}
};
// Original code by Sylvian Zimmer
// http://www.sylvainzimmer.com/index.php/archives/2006/06/25/speeding-up-prototypes-selector/
// Optimises execution speed of the $$ function. Rewritten for readability by Justin Palmer.
//
// Turn off optimisation with LowPro.optimize$$ = false;
LowPro.SelectorLite = Class.create();
LowPro.SelectorLite.prototype = {
initialize: function(selectors) {
this.results = [];
this.selectors = [];
this.index = 0;
for(var i = selectors.length -1; i >= 0; i--) {
var params = { tag: '*', id: null, classes: [] };
var selector = selectors[i];
var needle = selector.length - 1;
do {
var id = selector.lastIndexOf("#");
var klass = selector.lastIndexOf(".");
var cursor = Math.max(id, klass);
if(cursor == -1) params.tag = selector.toUpperCase();
else if(id == -1 || klass == cursor) params.classes.push(selector.substring(klass + 1));
else if(!params.id) params.id = selector.substring(id + 1);
selector = selector.substring(0, cursor);
} while(cursor > 0);
this.selectors[i] = params;
}
},
get: function(root) {
this.findElements(root || document, this.index == (this.selectors.length - 1));
return this.results;
},
findElements: function(parent, descendant) {
var selector = this.selectors[this.index], results = [], element;
if (selector.id) {
element = $(selector.id);
if (element && (selector.tag == '*' || element.tagName == selector.tag) && (element.childOf(parent))) {
results = [element];
}
} else {
results = $A(parent.getElementsByTagName(selector.tag));
}
if (selector.classes.length == 1) {
results = results.select(function(target) {
return $(target).hasClassName(selector.classes[0]);
});
} else if (selector.classes.length > 1) {
results = results.select(function(target) {
var klasses = $(target).classNames();
return selector.classes.all(function(klass) {
return klasses.include(klass);
});
});
}
if (descendant) {
this.results = this.results.concat(results);
} else {
++this.index;
results.each(function(target) {
this.findElements(target, this.index == (this.selectors.length - 1));
}.bind(this));
}
}
};
LowPro.$$old=$$;
LowPro.optimize$$ = false;
$$ = function(a,b) {
if (LowPro.optimize$$ == false || b || a.indexOf("[")>=0)
return LowPro.$$old(a, b);
return new LowPro.SelectorLite(a.split(/\s+/)).get();
};

View file

@ -18,8 +18,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
var niftyOk=(document.getElementById && document.createElement && Array.prototype.push);
String.prototype.find=function(what){
return(this.indexOf(what)>=0 ? true : false);
function strFind(str, what){
return(str.indexOf(what)>=0 ? true : false);
}
var oldonload=window.onload;
@ -31,12 +31,12 @@ else window.onload=function(){NiftyLoad()};
function Nifty(selector,options){
if(niftyOk==false) return;
var i,v=selector.split(","),h=0;
if(options==null) options="";
if(options.find("fixed-height"))
if(options==undefined) options="";
if(strFind(options,"fixed-height"))
h=getElementsBySelector(v[0])[0].offsetHeight;
for(i=0;i<v.length;i++)
Rounded(v[i],options);
if(options.find("height")) SameHeight(selector,h);
if(strFind(options,"height")) SameHeight(selector,h);
}
function Rounded(selector,options){
@ -47,18 +47,18 @@ if(options!=""){
options=options.replace("top","tr tl");
options=options.replace("bottom","br bl");
options=options.replace("transparent","alias");
if(options.find("tl")){
if(strFind(options,"tl")){
top="both";
if(!options.find("tr")) top="left";
if(!strFind(options,"tr")) top="left";
}
else if(options.find("tr")) top="right";
if(options.find("bl")){
else if(strFind(options,"tr")) top="right";
if(strFind(options,"bl")){
bottom="both";
if(!options.find("br")) bottom="left";
if(!strFind(options,"br")) bottom="left";
}
else if(options.find("br")) bottom="right";
else if(strFind(options,"br")) bottom="right";
}
if(top=="" && bottom=="" && !options.find("none")){top="both";bottom="both";}
if(top=="" && bottom=="" && !strFind(options,"none")){top="both";bottom="both";}
v=getElementsBySelector(selector);
for(i=0;i<v.length;i++){
FixIE(v[i]);
@ -71,7 +71,7 @@ function AddTop(el,side,options){
var d=CreateEl("b"),lim=4,border="",p,i,btype="r",bk,color;
d.style.marginLeft="-"+getPadding(el,"Left")+"px";
d.style.marginRight="-"+getPadding(el,"Right")+"px";
if(options.find("alias") || (color=getBk(el))=="transparent"){
if(strFind(options,"alias") || (color=getBk(el))=="transparent"){
color="transparent";bk="transparent"; border=getParentBk(el);btype="t";
}
else{
@ -80,11 +80,11 @@ else{
d.style.background=bk;
d.className="niftycorners";
p=getPadding(el,"Top");
if(options.find("small")){
if(strFind(options,"small")){
d.style.marginBottom=(p-2)+"px";
btype+="s"; lim=2;
}
else if(options.find("big")){
else if(strFind(options,"big")){
d.style.marginBottom=(p-10)+"px";
btype+="b"; lim=8;
}
@ -99,7 +99,7 @@ function AddBottom(el,side,options){
var d=CreateEl("b"),lim=4,border="",p,i,btype="r",bk,color;
d.style.marginLeft="-"+getPadding(el,"Left")+"px";
d.style.marginRight="-"+getPadding(el,"Right")+"px";
if(options.find("alias") || (color=getBk(el))=="transparent"){
if(strFind(options,"alias") || (color=getBk(el))=="transparent"){
color="transparent";bk="transparent"; border=getParentBk(el);btype="t";
}
else{
@ -108,11 +108,11 @@ else{
d.style.background=bk;
d.className="niftycorners";
p=getPadding(el,"Bottom");
if(options.find("small")){
if(strFind(options,"small")){
d.style.marginTop=(p-2)+"px";
btype+="s"; lim=2;
}
else if(options.find("big")){
else if(strFind(options,"big")){
d.style.marginTop=(p-10)+"px";
btype+="b"; lim=8;
}
@ -172,8 +172,8 @@ for(i=0;i<els.length;i++){
function getElementsBySelector(selector){
var i,j,selid="",selclass="",tag=selector,tag2="",v2,k,f,a,s=[],objlist=[],c;
if(selector.find("#")){ //id selector like "tag#id"
if(selector.find(" ")){ //descendant selector like "tag#id tag"
if(strFind(selector,"#")){ //id selector like "tag#id"
if(strFind(selector," ")){ //descendant selector like "tag#id tag"
s=selector.split(" ");
var fs=s[0].split("#");
if(fs.length==1) return(objlist);
@ -195,11 +195,11 @@ if(selector.find("#")){ //id selector like "tag#id"
}
}
}
if(selector.find(".")){ //class selector like "tag.class"
if(strFind(selector,".")){ //class selector like "tag.class"
s=selector.split(".");
tag=s[0];
selclass=s[1];
if(selclass.find(" ")){ //descendant selector like tag1.classname tag2
if(strFind(selclass, " ")){ //descendant selector like tag1.classname tag2
s=selclass.split(" ");
selclass=s[0];
tag2=s[1];
@ -235,15 +235,15 @@ return(c);
function getBk(x){
var c=getStyleProp(x,"backgroundColor");
if(c==null || c=="transparent" || c.find("rgba(0, 0, 0, 0)"))
if(c==null || c=="transparent" || strFind(c,"rgba(0, 0, 0, 0)"))
return("transparent");
if(c.find("rgb")) c=rgb2hex(c);
if(strFind(c,"rgb")) c=rgb2hex(c);
return(c);
}
function getPadding(x,side){
var p=getStyleProp(x,"padding"+side);
if(p==null || !p.find("px")) return(0);
if(p==null || !strFind(p, "px")) return(0);
return(parseInt(p));
}
@ -283,4 +283,4 @@ for(i=0;i<3;i++){
if(r[i].length==1) r[i]="0"+r[i];
}
return("#"+r[0]+r[1]+r[2]);
}
}

View file

@ -1,82 +0,0 @@
/* protoload 0.1 beta by Andreas Kalsch
* last change: 09.07.2007
*
* This simple piece of code automates the creating of Ajax loading symbols.
* The loading symbol covers an HTML element with correct position and size - example:
* $('myElement').startWaiting() and $('myElement').stopWaiting()
*/
Protoload = {
// the script to wait this amount of msecs until it shows the loading element
timeUntilShow: 250,
// opacity of loading element
opacity: 0.8,
// Start waiting status - show loading element
startWaiting: function(element, className, timeUntilShow) {
if (typeof element == 'string')
element = document.getElementById(element);
if (className == undefined)
className = 'tracks__waiting';
if (timeUntilShow == undefined)
timeUntilShow = Protoload.timeUntilShow;
element._waiting = true;
if (!element._loading) {
var e = document.createElement('div');
(element.offsetParent || document.body).appendChild(element._loading = e);
e.style.position = 'absolute';
try {e.style.opacity = Protoload.opacity;} catch(e) {}
try {e.style.MozOpacity = Protoload.opacity;} catch(e) {}
try {e.style.filter = 'alpha(opacity='+Math.round(Protoload.opacity * 100)+')';} catch(e) {}
try {e.style.KhtmlOpacity = Protoload.opacity;} catch(e) {}
/*var zIndex = 0;
if (window.UI)
if (UI.zIndex)
zIndex = ++UI.zIndex;
if (!zIndex)
zIndex = ++Protoload._zIndex;
e.style.zIndex = zIndex;*/
}
element._loading.className = className;
window.setTimeout((function() {
if (this._waiting) {
var left = this.offsetLeft,
top = this.offsetTop,
width = this.offsetWidth,
height = this.offsetHeight,
l = this._loading;
l.style.left = left+'px';
l.style.top = top+'px';
l.style.width = width+'px';
l.style.height = height+'px';
l.style.display = 'inline';
}
}).bind(element), timeUntilShow);
},
// Get current waiting status
isWaiting: function(element) {
return element._waiting == true;
},
// Stop waiting status - hide loading element
stopWaiting: function(element) {
if (element._waiting) {
element._waiting = false;
element._loading.parentNode.removeChild(element._loading);
element._loading = null;
}
}/*,
_zIndex: 1000000*/
};
if (Prototype) {
Element.addMethods(Protoload);
Object.extend(Element, Protoload);
}
/* */

File diff suppressed because it is too large Load diff

View file

@ -1,47 +0,0 @@
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var Scriptaculous = {
Version: '1.6',
require: function(libraryName) {
// inserting via DOM fails in Safari 2.0, so brute force approach
document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
},
load: function() {
if((typeof Prototype=='undefined') ||
(typeof Element == 'undefined') ||
(typeof Element.Methods=='undefined') ||
parseFloat(Prototype.Version.split(".")[0] + "." +
Prototype.Version.split(".")[1]) < 1.5)
throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0");
$A(document.getElementsByTagName("script")).findAll( function(s) {
return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
}).each( function(s) {
var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
var includes = s.src.match(/\?.*load=([a-z,]*)/);
(includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(
function(include) { Scriptaculous.require(path+include+'.js') });
});
}
}
Scriptaculous.load();

View file

@ -1,171 +0,0 @@
/*
* ToDo Items
*
* Requires the prototype.js library
*
* Use the following markup to include the library:
* <script type="text/javascript" src="todo-items.js"></script>
*/
ToDoItems = Class.create();
ToDoItems.prototype = {
initialize: function()
{
/* keep track of last effect so you can check if the animation has finised */
this.lastEffect= null;
this.initialized = true;
this.contextCollapseCookieManager = new CookieManager();
this.toggleItemsMap = {};
this.toggleContainerMap = {};
this.containerItemsMap = {};
},
addNextActionListingToggles: function()
{
this.containerToggles = $$('.container_toggle');
containerTogglesClick = this.toggleNextActionListing.bindAsEventListener(this);
for(i=0; i < this.containerToggles.length; i++)
{
toggleElem = this.containerToggles[i];
containerElem = toggleElem.parentNode.parentNode
itemsElem = $(containerElem.id).select("div#"+containerElem.id+"items")[0];
this.toggleContainerMap[toggleElem.id] = containerElem;
this.toggleItemsMap[toggleElem.id] = itemsElem;
this.containerItemsMap[containerElem.id] = itemsElem;
}
this.setNextActionListingTogglesToCookiedState();
},
setNextActionListingTogglesToCookiedState: function()
{
for(i=0; i < this.containerToggles.length; i++)
{
toggleElem = this.containerToggles[i];
containerElem = this.toggleContainerMap[toggleElem.id];
collapsedCookie = this.contextCollapseCookieManager.getCookie(this.buildCookieName(containerElem));
itemsElem = this.toggleItemsMap[toggleElem.id];
isExpanded = Element.visible(itemsElem);
if (collapsedCookie && isExpanded)
{
this.collapseNextActionListing(toggleElem, itemsElem);
}
else if (!collapsedCookie && !isExpanded)
{
this.expandNextActionListing(toggleElem, itemsElem);
}
}
},
collapseAllNextActionListing: function(except)
{
for(i=0; i < this.containerToggles.length; i++)
{
toggleElem = this.containerToggles[i];
if (toggleElem != except)
{
itemsElem = this.toggleItemsMap[toggleElem.id];
isExpanded = Element.visible(itemsElem);
if (isExpanded)
{
this.collapseNextActionListing(toggleElem, itemsElem);
}
}
}
},
ensureVisibleWithEffectAppear: function(elemId)
{
if ($(elemId).style.display == 'none')
{
new Effect.Appear(elemId,{duration:0.4});
}
},
fadeAndRemoveItem: function(itemContainerElemId)
{
var fadingElemId = itemContainerElemId + '-fading';
$(itemContainerElemId).setAttribute('id',fadingElemId);
Element.removeClassName($(fadingElemId),'item-container');
new Effect.Fade(fadingElemId,{afterFinish:function(effect) { Element.remove(fadingElemId); }, duration:0.4});
},
toggleNextActionListing: function(event)
{
Event.stop(event);
toggleElem = Event.element(event).parentNode;
itemsElem = this.toggleItemsMap[toggleElem.id];
containerElem = this.toggleContainerMap[toggleElem.id];
if (Element.visible(itemsElem))
{
this.collapseNextActionListing(toggleElem, itemsElem);
this.contextCollapseCookieManager.setCookie(this.buildCookieName(containerElem), true)
}
else
{
this.expandNextActionListing(toggleElem, itemsElem);
this.contextCollapseCookieManager.clearCookie(this.buildCookieName(containerElem))
}
},
findToggleElemForContext : function(contextElem)
{
childElems = $A($(contextElem).getElementsByTagName('a'));
return childElems.detect(function(childElem) { return childElem.className == 'container_toggle' });
},
expandNextActionListing: function(toggleElem, itemsElem, skipAnimation)
{
itemsElem = $(itemsElem)
if (skipAnimation == true) {
itemsElem.style.display = 'block';
}
else
{
this.lastEffect = Effect.BlindDown(itemsElem, { duration: 0.4 });
}
toggleElem.setAttribute('title', 'Collapse');
imgElem = this.findToggleImgElem(toggleElem);
imgElem.src = imgElem.src.replace('expand','collapse');
imgElem.setAttribute('title','Collapse');
},
ensureContainerHeight: function(itemsElem)
{
itemsElem = $(itemsElem);
Element.setStyle(itemsElem, {height : ''});
Element.setStyle(itemsElem, {overflow : ''});
},
expandNextActionListingByContext: function(itemsElem, skipAnimation)
{
contextElem = this.findNearestParentByClassName($(itemsElem), "context");
toggleElem = this.findToggleElemForContext(contextElem);
this.expandNextActionListing(toggleElem, itemsElem, skipAnimation);
},
collapseNextActionListing: function(toggleElem, itemsElem)
{
this.lastEffect = Effect.BlindUp(itemsElem, { duration: 0.4});
toggleElem.setAttribute('title', 'Expand');
imgElem = this.findToggleImgElem(toggleElem);
imgElem.src = imgElem.src.replace('collapse','expand');
imgElem.setAttribute('title','Expand');
},
findToggleImgElem: function(toggleElem)
{
childImgElems = $A(toggleElem.getElementsByTagName('img'));
return childImgElems[0];
},
buildCookieName: function(containerElem)
{
tracks_login = this.contextCollapseCookieManager.getCookie('tracks_login');
return 'tracks_'+tracks_login+'_context_' + containerElem.id + '_collapsed';
},
findNearestParentByClassName: function(elem, parentClassName)
{
var parentElem = elem.parentNode;
while(parentElem)
{
if (Element.hasClassName(parentElem, parentClassName))
{
return parentElem;
}
parentElem = parentElem.parentNode;
}
return null;
}
}
todoItems = new ToDoItems();
Event.observe(window, "load", todoItems.addNextActionListingToggles.bindAsEventListener(todoItems));

View file

@ -1,233 +0,0 @@
/* The main calendar widget. DIV containing a table. */
div.calendar { position: relative; }
.calendar, .calendar table {
border: 1px solid #556;
font-size: 11px;
color: #000;
cursor: default;
background: #eef;
z-index: 110;
font-family: tahoma,verdana,sans-serif;
}
/* Header part -- contains navigation buttons and day names. */
.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */
text-align: center; /* They are the navigation buttons */
padding: 2px; /* Make the buttons seem like they're pressing */
}
.calendar .nav {
background: #778 url(../images/menuarrow.gif) no-repeat 100% 100%;
}
.calendar thead .title { /* This holds the current "month, year" */
font-weight: bold; /* Pressing it will take you to the current date */
text-align: center;
background: #fff;
color: #000;
padding: 2px;
}
.calendar thead .headrow { /* Row <TR> containing navigation buttons */
background: #778;
color: #fff;
}
.calendar thead .daynames { /* Row <TR> containing the day names */
background: #bdf;
}
.calendar thead .name { /* Cells <TD> containing the day names */
border-bottom: 1px solid #556;
padding: 2px;
text-align: center;
color: #000;
}
.calendar thead .weekend { /* How a weekend day name shows in header */
color: #a66;
}
.calendar thead .hilite { /* How do the buttons in header appear when hover */
background-color: #aaf;
color: #000;
border: 1px solid #04f;
padding: 1px;
}
.calendar thead .active { /* Active (pressed) buttons in header */
background-color: #77c;
padding: 2px 0px 0px 2px;
}
/* The body part -- contains all the days in month. */
.calendar tbody .day { /* Cells <TD> containing month days dates */
width: 2em;
color: #456;
text-align: right;
padding: 2px 4px 2px 2px;
}
.calendar tbody .day.othermonth {
font-size: 80%;
color: #bbb;
}
.calendar tbody .day.othermonth.oweekend {
color: #fbb;
}
.calendar table .wn {
padding: 2px 3px 2px 2px;
border-right: 1px solid #000;
background: #bdf;
}
.calendar tbody .rowhilite td {
background: #def;
}
.calendar tbody .rowhilite td.wn {
background: #eef;
}
.calendar tbody td.hilite { /* Hovered cells <TD> */
background: #def;
padding: 1px 3px 1px 1px;
border: 1px solid #bbb;
}
.calendar tbody td.active { /* Active (pressed) cells <TD> */
background: #cde;
padding: 2px 2px 0px 2px;
}
.calendar tbody td.selected { /* Cell showing today date */
font-weight: bold;
border: 1px solid #000;
padding: 1px 3px 1px 1px;
background: #fff;
color: #000;
}
.calendar tbody td.weekend { /* Cells showing weekend days */
color: #a66;
}
.calendar tbody td.today { /* Cell showing selected date */
font-weight: bold;
color: #00f;
}
.calendar tbody .disabled { color: #999; }
.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */
visibility: hidden;
}
.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */
display: none;
}
/* The footer part -- status bar and "Close" button */
.calendar tfoot .footrow { /* The <TR> in footer (only one right now) */
text-align: center;
background: #556;
color: #fff;
}
.calendar tfoot .ttip { /* Tooltip (status bar) cell <TD> */
background: #fff;
color: #445;
border-top: 1px solid #556;
padding: 1px;
}
.calendar tfoot .hilite { /* Hover style for buttons in footer */
background: #aaf;
border: 1px solid #04f;
color: #000;
padding: 1px;
}
.calendar tfoot .active { /* Active (pressed) style for buttons in footer */
background: #77c;
padding: 2px 0px 0px 2px;
}
/* Combo boxes (menus that display months/years for direct selection) */
.calendar .combo {
position: absolute;
display: none;
top: 0px;
left: 0px;
width: 4em;
cursor: default;
border: 1px solid #655;
background: #def;
color: #000;
font-size: 90%;
z-index: 100;
}
.calendar .combo .label,
.calendar .combo .label-IEfix {
text-align: center;
padding: 1px;
}
.calendar .combo .label-IEfix {
width: 4em;
}
.calendar .combo .hilite {
background: #acf;
}
.calendar .combo .active {
border-top: 1px solid #46a;
border-bottom: 1px solid #46a;
background: #eef;
font-weight: bold;
}
.calendar td.time {
border-top: 1px solid #000;
padding: 1px 0px;
text-align: center;
background-color: #f4f0e8;
}
.calendar td.time .hour,
.calendar td.time .minute,
.calendar td.time .ampm {
padding: 0px 3px 0px 4px;
border: 1px solid #889;
font-weight: bold;
background-color: #fff;
}
.calendar td.time .ampm {
text-align: center;
}
.calendar td.time .colon {
padding: 0px 2px 0px 3px;
font-weight: bold;
}
.calendar td.time span.hilite {
border-color: #000;
background-color: #667;
color: #fff;
}
.calendar td.time span.active {
border-color: #f00;
background-color: #000;
color: #0f0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

406
public/stylesheets/jquery-ui.css vendored Executable file
View file

@ -0,0 +1,406 @@
/*
* jQuery UI CSS Framework
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; outline: none; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; outline: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; outline: none; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; outline: none; }
.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; outline: none; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; outline: none; text-decoration: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; }
.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion
----------------------------------*/
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
.ui-accordion .ui-accordion-li-fix { display: inline; }
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker
----------------------------------*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}/* Dialog
----------------------------------*/
.ui-dialog { position: relative; padding: .2em; width: 300px; }
.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/* Progressbar
----------------------------------*/
.ui-progressbar { height:2em; text-align: left; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable
----------------------------------*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider
----------------------------------*/
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
----------------------------------*/
.ui-tabs { padding: .2em; zoom: 1; }
.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }

View file

@ -0,0 +1,48 @@
.ac_results {
padding: 0px;
border: 1px solid black;
background-color: white;
overflow: hidden;
z-index: 99999;
}
.ac_results ul {
width: 100%;
list-style-position: outside;
list-style: none;
padding: 0;
margin: 0;
}
.ac_results li {
margin: 0px;
padding: 2px 5px;
cursor: default;
display: block;
/*
if width will be 100% horizontal scrollbar will apear
when scroll mode will be used
*/
/*width: 100%;*/
font: menu;
font-size: 12px;
/*
it is very important, if line-height not setted or setted
in relative units scroll will be broken in firefox
*/
line-height: 16px;
overflow: hidden;
}
.ac_loading {
background: white url('indicator.gif') right center no-repeat;
}
.ac_odd {
background-color: #eee;
}
.ac_over {
background-color: #0A246A;
color: white;
}

View file

@ -1178,7 +1178,7 @@ button.positive, .widgets a.positive{
border:1px solid #d12f19;
color:#fff;
}
.tracks__waiting {
.blockUI.blockOverlay {
background-image:url('/images/waiting.gif');
background-repeat:no-repeat;
background-position:center center;

View file

@ -5,7 +5,6 @@ describe "/notes/_notes.rhtml" do
@project = mock_model(Project, :name => "a project")
@note = mock_model(Note, :body => "this is a note", :project => @project, :project_id => @project.id,
:created_at => Time.now, :updated_at? => false)
# @controller.template.stub!(:apply_behavior)
@controller.template.stub!(:format_date)
# @controller.template.stub!(:render)
# @controller.template.stub!(:form_remote_tag)

View file

@ -5,7 +5,6 @@ describe "/todos/_toggle_notes.rhtml" do
before :each do
@item = mock_model(Todo, :notes => "this is a note")
@controller.template.stub!(:apply_behavior)
@controller.template.stub!(:set_default_external!)
end

View file

@ -21,14 +21,6 @@ class ContextsControllerTest < TodoContainerControllerTestBase
assert_ajax_create_increments_count '@newcontext'
end
def test_create_context_with_ajax_success_rjs
ajax_create '@newcontext'
assert_rjs :insert_html, :bottom, "list-contexts"
assert_rjs :sortable, 'list-contexts', { :tag => 'div', :handle => 'handle', :complete => visual_effect(:highlight, 'list-contexts'), :url => order_contexts_path }
# not yet sure how to write the following properly...
assert_rjs :call, "Form.reset", "context-form"
assert_rjs :call, "Form.focusFirstElement", "context-form"
end
def test_create_via_ajax_with_comma_in_name_does_not_increment_number_of_contexts
assert_ajax_create_does_not_increment_count 'foo,bar'
@ -186,4 +178,4 @@ class ContextsControllerTest < TodoContainerControllerTestBase
def protect_against_forgery?
false
end
end
end

Some files were not shown because too many files have changed in this diff Show more