mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-20 17:20:12 +01:00
Merge branch 'master' of git://github.com/bsag/tracks
This commit is contained in:
commit
e743dd79c3
1641 changed files with 90344 additions and 58968 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -9,3 +9,5 @@ nbproject
|
|||
vendor/plugins/query_trace/
|
||||
db/schema.rb
|
||||
.dotest
|
||||
public/javascripts/cache
|
||||
public/stylesheets/cache
|
||||
|
|
@ -32,13 +32,13 @@ class ApplicationController < ActionController::Base
|
|||
before_filter :set_time_zone
|
||||
prepend_before_filter :login_required
|
||||
prepend_before_filter :enable_mobile_content_negotiation
|
||||
after_filter :restore_content_type_for_mobile
|
||||
after_filter :set_charset
|
||||
|
||||
|
||||
|
||||
include ActionView::Helpers::TextHelper
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
extend ActionView::Helpers::SanitizeHelper::ClassMethods
|
||||
helper_method :format_date, :markdown
|
||||
|
||||
# By default, sets the charset to UTF-8 if it isn't already set
|
||||
|
|
@ -148,18 +148,12 @@ class ApplicationController < ActionController::Base
|
|||
# during the processing and then setting it to 'text/html' in an
|
||||
# 'after_filter' -LKM 2007-04-01
|
||||
def mobile?
|
||||
return params[:format] == 'm' || response.content_type == MOBILE_CONTENT_TYPE
|
||||
return params[:format] == 'm'
|
||||
end
|
||||
|
||||
def enable_mobile_content_negotiation
|
||||
if mobile?
|
||||
request.accepts.unshift(Mime::Type::lookup(MOBILE_CONTENT_TYPE))
|
||||
end
|
||||
end
|
||||
|
||||
def restore_content_type_for_mobile
|
||||
if mobile?
|
||||
response.content_type = 'text/html'
|
||||
request.format = :m
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -234,8 +228,13 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def init_data_for_sidebar
|
||||
@projects = @projects || current_user.projects.find(:all, :include => [:default_context ])
|
||||
@contexts = @contexts || current_user.contexts
|
||||
@completed_projects = current_user.projects.completed
|
||||
@hidden_projects = current_user.projects.hidden
|
||||
@active_projects = current_user.projects.active
|
||||
|
||||
@active_contexts = current_user.contexts.active
|
||||
@hidden_contexts = current_user.contexts.hidden
|
||||
|
||||
init_not_done_counts
|
||||
if prefs.show_hidden_projects_in_sidebar
|
||||
init_project_hidden_todo_counts(['project'])
|
||||
|
|
@ -244,13 +243,13 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def init_not_done_counts(parents = ['project','context'])
|
||||
parents.each do |parent|
|
||||
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || Todo.count(:conditions => ['user_id = ? and state = ?', current_user.id, 'active'], :group => :#{parent}_id)")
|
||||
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
|
||||
def init_project_hidden_todo_counts(parents = ['project','context'])
|
||||
parents.each do |parent|
|
||||
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || Todo.count(:conditions => ['user_id = ? and (state = ? or state = ?)', current_user.id, 'project_hidden', 'active'], :group => :#{parent}_id)")
|
||||
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,9 @@ class ContextsController < ApplicationController
|
|||
:conditions => ['todos.state = ? AND (todos.project_id IS ? OR projects.state = ?)', 'active', nil, 'active'],
|
||||
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
|
||||
:include => [:project, :tags])
|
||||
|
||||
@projects = current_user.projects
|
||||
|
||||
@count = @not_done_todos.size
|
||||
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
|
||||
end
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class TodosController < ApplicationController
|
|||
format.m do
|
||||
@return_path=cookies[:mobile_url]
|
||||
# todo: use function for this fixed path
|
||||
@return_path='/mobile' if @return_path.nil?
|
||||
@return_path='/m' if @return_path.nil?
|
||||
if @saved
|
||||
redirect_to @return_path
|
||||
else
|
||||
|
|
@ -400,7 +400,8 @@ class TodosController < ApplicationController
|
|||
:conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'completed'],
|
||||
:order => 'todos.completed_at DESC')
|
||||
|
||||
@contexts = current_user.contexts.find(:all)
|
||||
@projects = current_user.projects
|
||||
@contexts = current_user.contexts
|
||||
@contexts_to_show = @contexts.reject {|x| x.hide? }
|
||||
|
||||
# Set count badge to number of items with this tag
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
module NotesHelper
|
||||
def truncated_note(note, characters = 50)
|
||||
sanitize(textilize_without_paragraph(truncate(note.body, characters, "...")))
|
||||
sanitize(textilize_without_paragraph(truncate(note.body, :length => characters, :omission => "...")))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ module ProjectsHelper
|
|||
def project_next_prev
|
||||
html = ''
|
||||
unless @previous_project.nil?
|
||||
project_name = truncate(@previous_project.name, 40, "...")
|
||||
project_name = truncate(@previous_project.name, :length => 40, :omission => "...")
|
||||
html << link_to_project(@previous_project, "« #{project_name}")
|
||||
end
|
||||
html << ' | ' if @previous_project && @next_project
|
||||
unless @next_project.nil?
|
||||
project_name = truncate(@next_project.name, 40, "...")
|
||||
project_name = truncate(@next_project.name, :length => 40, :omission => "...")
|
||||
html << link_to_project(@next_project, "#{project_name} »")
|
||||
end
|
||||
html
|
||||
|
|
@ -34,12 +34,12 @@ module ProjectsHelper
|
|||
def project_next_prev_mobile
|
||||
html = ''
|
||||
unless @previous_project.nil?
|
||||
project_name = truncate(@previous_project.name, 40, "...")
|
||||
project_name = truncate(@previous_project.name, :length => 40, :omission => "...")
|
||||
html << link_to_project_mobile(@previous_project, "5", "« 5-#{project_name}")
|
||||
end
|
||||
html << ' | ' if @previous_project && @next_project
|
||||
unless @next_project.nil?
|
||||
project_name = truncate(@next_project.name, 40, "...")
|
||||
project_name = truncate(@next_project.name, :length => 40, :omission => "...")
|
||||
html << link_to_project_mobile(@next_project, "6", "6-#{project_name} »")
|
||||
end
|
||||
html
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ module TodosHelper
|
|||
"<span class=\"tag\">" +
|
||||
link_to(t.name, {:action => "tag", :controller => "todos", :id => t.name+".m"}) +
|
||||
"</span>"}.join('')
|
||||
"<span class=\"tags\">#{tag_list}</span>"
|
||||
if not tag_list.empty? then "<span class=\"tags\">#{tag_list}</span>" end
|
||||
end
|
||||
|
||||
def deferred_due_date
|
||||
|
|
@ -242,13 +242,13 @@ module TodosHelper
|
|||
end
|
||||
|
||||
def project_names_for_autocomplete
|
||||
array_or_string_for_javascript( ['None'] + @projects.select{ |p| p.active? }.collect{|p| escape_javascript(p.name) } )
|
||||
array_or_string_for_javascript( ['None'] + current_user.projects.active.collect{|p| escape_javascript(p.name) } )
|
||||
end
|
||||
|
||||
def context_names_for_autocomplete
|
||||
# #return array_or_string_for_javascript(['Create a new context']) if
|
||||
# @contexts.empty?
|
||||
array_or_string_for_javascript( @contexts.collect{|c| escape_javascript(c.name) } )
|
||||
array_or_string_for_javascript( current_user.contexts.collect{|c| escape_javascript(c.name) } )
|
||||
end
|
||||
|
||||
def format_ical_notes(notes)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
class MessageGateway < ActionMailer::Base
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
extend ActionView::Helpers::SanitizeHelper::ClassMethods
|
||||
|
||||
def receive(email)
|
||||
user = User.find(:first, :include => [:preference], :conditions => ["preferences.sms_email = ?", email.from[0].strip])
|
||||
if user.nil?
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def at_midnight(date)
|
||||
return TimeZone[prefs.time_zone].local(date.year, date.month, date.day, 0, 0, 0)
|
||||
return ActiveSupport::TimeZone[prefs.time_zone].local(date.year, date.month, date.day, 0, 0, 0)
|
||||
end
|
||||
|
||||
def generate_token
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ if not @not_done.empty?
|
|||
# only show a context when there are actions in it
|
||||
-%>
|
||||
<h2><%=mobile_context.name%></h2>
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<table cellpadding="0" cellspacing="0" border="0" class="c">
|
||||
<%= render :partial => "todos/mobile_todo",
|
||||
:collection => @not_done,
|
||||
:locals => { :parent_container_type => "context" }-%>
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@
|
|||
|
||||
<div id="input_box">
|
||||
<%= render :partial => "shared/add_new_item_form" %>
|
||||
<%= render "sidebar/sidebar" %>
|
||||
<%= render :template => "sidebar/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
</div><!-- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<%= render "sidebar/sidebar" %>
|
||||
<%= render :template => "sidebar/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
|
|
|||
|
|
@ -5,9 +5,16 @@
|
|||
<% if @prefs.refresh != 0 -%>
|
||||
<meta http-equiv="Refresh" content="<%= @prefs["refresh"].to_i*60 %>;url=<%= request.request_uri %>">
|
||||
<% end -%>
|
||||
<%= javascript_include_merged :tracks %>
|
||||
<% bundle do %>
|
||||
<%= javascript_include_tag *%w[
|
||||
prototype effects dragdrop controls application
|
||||
calendar calendar-en calendar-setup
|
||||
accesskey-hints todo-items niftycube
|
||||
protoload flashobject lowpro
|
||||
] %>
|
||||
<%= stylesheet_link_tag *%w[ standard calendar-system niftyCorners] %>
|
||||
<% end %>
|
||||
<%= javascript_include_tag :unobtrusive %>
|
||||
<%= stylesheet_link_merged :tracks %>
|
||||
<%= stylesheet_link_tag "print", :media => "print" %>
|
||||
|
||||
<link rel="shortcut icon" href="<%= url_for(:controller => 'favicon.ico') %>" />
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<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));
|
||||
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>
|
||||
|
|
@ -74,5 +74,5 @@
|
|||
|
||||
<div id="input_box">
|
||||
<%= render :partial => "shared/add_new_item_form" %>
|
||||
<%= render "sidebar/sidebar" %>
|
||||
<%= render :template => "sidebar/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ if @recurring_saved
|
|||
page.hide 'recurring-todos-empty-nd'
|
||||
page.insert_html :bottom,
|
||||
'recurring_todos_container',
|
||||
:partial => 'recurring_todos/recurring_todo'
|
||||
:partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo}
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
# update badge count
|
||||
page['badge_count'].replace_html @count
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ if @saved
|
|||
|
||||
if @recurring_todo.completed?
|
||||
# show completed recurring todo
|
||||
page.insert_html :top, "completed_recurring_todos_container", :partial => 'recurring_todos/recurring_todo'
|
||||
page.insert_html :top, "completed_recurring_todos_container", :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
|
||||
# set empty messages
|
||||
|
|
@ -14,7 +14,7 @@ if @saved
|
|||
# recurring_todo is activated
|
||||
|
||||
# show completed recurring todo
|
||||
page.insert_html :top, "recurring_todos_container", :partial => 'recurring_todos/recurring_todo'
|
||||
page.insert_html :top, "recurring_todos_container", :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
|
||||
# inform user if a new todo has been created because of the activation
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ if @saved
|
|||
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}; projectAutoCompleter.changed = true" if @new_project_created
|
||||
|
||||
# replace old recurring todo with updated todo
|
||||
page.replace dom_id(@recurring_todo), :partial => 'recurring_todos/recurring_todo'
|
||||
page.replace dom_id(@recurring_todo), :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
@todo = nil
|
||||
@initial_context_name = @context.name unless @context.nil?
|
||||
@initial_context_name ||= @project.default_context.name unless @project.nil? || @project.default_context.nil?
|
||||
@initial_context_name ||= @contexts[0].name unless @contexts[0].nil?
|
||||
@initial_context_name ||= current_user.contexts.first.name unless current_user.contexts.first.nil?
|
||||
@initial_project_name = @project.name unless @project.nil?
|
||||
%>
|
||||
<div id="todo_new_action_container">
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
<div id="sidebar">
|
||||
<% # show active items before hidden / completed items -%>
|
||||
<% # show active items before hidden / completed items -%>
|
||||
|
||||
<%= render :partial => "sidebar/project_list",
|
||||
:locals => { :list_name => 'Active Projects',
|
||||
:projects => @projects.select{|p| p.active? } } -%>
|
||||
:projects => @active_projects } -%>
|
||||
|
||||
<%= render :partial => "sidebar/context_list",
|
||||
:locals => { :list_name => 'Active Contexts',
|
||||
:contexts => @contexts.reject{|c| c.hide? } } -%>
|
||||
:contexts => @active_contexts } -%>
|
||||
|
||||
<% if prefs.show_hidden_projects_in_sidebar -%>
|
||||
<%= render :partial => "sidebar/project_list",
|
||||
:locals => { :list_name => 'Hidden Projects',
|
||||
:projects => @projects.select{|p| p.hidden? } } -%>
|
||||
:projects => @hidden_projects } -%>
|
||||
<% end -%>
|
||||
|
||||
<% if prefs.show_completed_projects_in_sidebar -%>
|
||||
<%= render :partial => "sidebar/project_list",
|
||||
:locals => { :list_name => 'Completed Projects',
|
||||
:projects => @projects.select{|p| p.completed? } } -%>
|
||||
:projects => @completed_projects } -%>
|
||||
<% end -%>
|
||||
|
||||
<% if prefs.show_hidden_contexts_in_sidebar -%>
|
||||
<%= render :partial => "sidebar/context_list",
|
||||
:locals => { :list_name => 'Hidden Contexts',
|
||||
:contexts => @contexts.select{|c| c.hide? } } -%>
|
||||
:contexts => @hidden_contexts } -%>
|
||||
<% end -%>
|
||||
|
||||
<div class="integrations-link"><ul>
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ end
|
|||
-%><%=@actions_per_context[@actions_per_context.size()-1]['total'].to_i*100/@sum%>&
|
||||
&pie_labels=<%
|
||||
0.upto @actions_per_context.size()-2 do | i |
|
||||
%><%=truncate(@actions_per_context[i]['name'],@truncate_chars, '...')%>,<%
|
||||
%><%=truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...')%>,<%
|
||||
end
|
||||
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'],@truncate_chars,'...') %>&
|
||||
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], :legnth => @truncate_chars, :omission => '...') %>&
|
||||
&links=<%
|
||||
0.upto @actions_per_context.size()-2 do | i |
|
||||
%><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']%>,<%
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ end
|
|||
-%><%=@actions_per_context[@actions_per_context.size()-1]['total'].to_i*100/@sum%>&
|
||||
&pie_labels=<%
|
||||
0.upto @actions_per_context.size()-2 do | i |
|
||||
%><%=truncate(@actions_per_context[i]['name'], @truncate_chars, '...') %>,<%
|
||||
%><%=truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...') %>,<%
|
||||
end
|
||||
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], @truncate_chars, '...') %>&
|
||||
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], :length => @truncate_chars, :omission => '...') %>&
|
||||
&links=<%
|
||||
0.upto @actions_per_context.size()-2 do | i |
|
||||
%><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']%>,<%
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ if mobile_todo.starred?
|
|||
else
|
||||
bullet = "<span class=r>» </span>"
|
||||
end -%>
|
||||
<div class="t" id="<%= dom_id(mobile_todo) %>">
|
||||
<tr valign="top"><td><%= bullet %></td><td><%
|
||||
<tr class="t" id="<%= dom_id(mobile_todo) %>" valign="top"><td><%= bullet %></td><td><%
|
||||
if mobile_todo.completed?
|
||||
-%><span class="m_t_d">
|
||||
<% else
|
||||
|
|
@ -23,4 +22,4 @@ end -%>
|
|||
")</span>" -%>
|
||||
<% end -%>
|
||||
<%= tag_list_mobile -%>
|
||||
</span></td></tr></div>
|
||||
</span></td></tr>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ if @saved
|
|||
page.insert_html :top, 'display_box', :partial => 'contexts/context', :locals => { :context => @todo.context, :collapsible => true }
|
||||
else
|
||||
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}" if source_view_is_one_of(:todo, :deferred)
|
||||
page.insert_html :bottom, item_container_id(@todo) + 'items', :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type, :source_view => @source_view }
|
||||
page.insert_html :bottom, item_container_id(@todo) + 'items', :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type, :source_view => @source_view }
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,5 +10,7 @@
|
|||
|
||||
<div id="input_box">
|
||||
<%= render :partial => "shared/add_new_item_form" %>
|
||||
<%= render "sidebar/sidebar" %>
|
||||
<%- # TODO: this used to be render :template, but somehow it was not
|
||||
#rendered after the rails2.2.2 upgrade -%>
|
||||
<%= render :file => "sidebar/sidebar.html.erb" %>
|
||||
</div><!-- End of input box -->
|
||||
|
|
@ -11,5 +11,5 @@
|
|||
|
||||
<div id="input_box">
|
||||
<%= render :partial => "shared/add_new_item_form" %>
|
||||
<%= render "sidebar/sidebar" %>
|
||||
<%= render :template => "sidebar/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
|
|
@ -23,5 +23,5 @@
|
|||
|
||||
<div id="input_box">
|
||||
<%= render :partial => "shared/add_new_item_form" %>
|
||||
<%= render "sidebar/sidebar" %>
|
||||
<%= render :template => "sidebar/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
|
|
@ -5,7 +5,7 @@ if @saved
|
|||
|
||||
# completed todos move from their context to the completed container
|
||||
unless @prefs.hide_completed_actions?
|
||||
page.insert_html :top, "completed_containeritems", :partial => 'todos/todo', :locals => { :parent_container_type => "completed" }
|
||||
page.insert_html :top, "completed_containeritems", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => "completed" }
|
||||
page.visual_effect :highlight, dom_id(@todo, 'line'), {'startcolor' => "'#99ff99'"}
|
||||
page[empty_container_msg_div_id].show if @down_count == 0 && !empty_container_msg_div_id.nil?
|
||||
page.show 'tickler-empty-nd' if source_view_is(:project) && @deferred_count == 0
|
||||
|
|
@ -33,7 +33,7 @@ if @saved
|
|||
else
|
||||
# todo is activated from completed container
|
||||
page.call "todoItems.ensureVisibleWithEffectAppear", item_container_id(@todo)
|
||||
page.insert_html :bottom, item_container_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
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[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
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ if @saved
|
|||
page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
|
||||
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
|
||||
# show all todos in context
|
||||
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
end
|
||||
|
||||
# update badge count
|
||||
|
|
@ -52,7 +52,7 @@ if @saved
|
|||
end
|
||||
end
|
||||
else
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
end
|
||||
elsif source_view_is :project
|
||||
|
|
@ -63,17 +63,17 @@ if @saved
|
|||
elsif @todo.deferred?
|
||||
page[@todo].remove
|
||||
page.show("p#{@original_item_project_id}empty-nd") if (@remaining_undone_in_project == 0)
|
||||
page.insert_html :bottom, "tickler", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.insert_html :bottom, "tickler", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page['tickler-empty-nd'].hide
|
||||
page.replace_html "badge_count", @down_count
|
||||
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 => { :parent_container_type => parent_container_type }
|
||||
page.insert_html :bottom, "p#{@todo.project_id}", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page["p#{@todo.project_id}empty-nd"].hide
|
||||
page.replace_html "badge_count", @down_count
|
||||
else
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
end
|
||||
elsif source_view_is :deferred
|
||||
|
|
@ -87,7 +87,7 @@ if @saved
|
|||
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}"
|
||||
page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
|
||||
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
|
||||
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page.replace_html("badge_count", @down_count)
|
||||
page.delay(0.5) do
|
||||
page.call "todoItems.ensureContainerHeight", "c#{@original_item_context_id}items"
|
||||
|
|
@ -95,18 +95,18 @@ if @saved
|
|||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
end
|
||||
else
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
end
|
||||
elsif source_view_is :stats
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
elsif source_view_is :calendar
|
||||
if @due_date_changed
|
||||
page[@todo].remove
|
||||
page.show "empty_"+@original_item_due_id if @old_due_empty
|
||||
page.hide "empty_"+@new_due_id
|
||||
page.insert_html :bottom, @new_due_id, :partial => 'todos/todo'
|
||||
page.insert_html :bottom, @new_due_id, :partial => 'todos/todo', :locals => {:todo => @todo}
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
else
|
||||
if @todo.due.nil?
|
||||
|
|
@ -114,7 +114,7 @@ if @saved
|
|||
page[@todo].remove
|
||||
page.show "empty_"+@original_item_due_id if @old_due_empty
|
||||
else
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
|
||||
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
|
||||
page.visual_effect :highlight, dom_id(@todo), :duration => 3
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
---
|
||||
javascripts:
|
||||
- tracks:
|
||||
- prototype
|
||||
- effects
|
||||
- dragdrop
|
||||
- controls
|
||||
- application
|
||||
- calendar
|
||||
- calendar-en
|
||||
- calendar-setup
|
||||
- accesskey-hints
|
||||
- todo-items
|
||||
- niftycube
|
||||
- protoload
|
||||
- flashobject
|
||||
- lowpro
|
||||
stylesheets:
|
||||
- tracks:
|
||||
- standard
|
||||
- calendar-system
|
||||
- niftyCorners
|
||||
|
|
@ -67,7 +67,7 @@ module Rails
|
|||
|
||||
class << self
|
||||
def rubygems_version
|
||||
Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
|
||||
Gem::RubyGemsVersion rescue nil
|
||||
end
|
||||
|
||||
def gem_version
|
||||
|
|
@ -82,14 +82,14 @@ module Rails
|
|||
|
||||
def load_rubygems
|
||||
require 'rubygems'
|
||||
|
||||
unless rubygems_version >= '0.9.4'
|
||||
$stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
||||
min_version = '1.3.1'
|
||||
unless rubygems_version >= min_version
|
||||
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
||||
exit 1
|
||||
end
|
||||
|
||||
rescue LoadError
|
||||
$stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
||||
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
||||
exit 1
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ class Rails::Configuration
|
|||
attr_accessor :action_web_service
|
||||
end
|
||||
|
||||
# Leave this alone or set it to one or more of ['database', 'ldap', 'open_id'].
|
||||
# If you choose ldap, see the additional configuration options further down.
|
||||
AUTHENTICATION_SCHEMES = ['database']
|
||||
|
||||
Rails::Initializer.run do |config|
|
||||
# Skip frameworks you're not going to use
|
||||
# config.frameworks -= [ :action_web_service, :action_mailer ]
|
||||
|
|
@ -22,6 +26,8 @@ Rails::Initializer.run do |config|
|
|||
config.action_web_service = Rails::OrderedOptions.new
|
||||
config.load_paths += %W( #{RAILS_ROOT}/app/apis )
|
||||
|
||||
config.action_controller.use_accept_header = true
|
||||
|
||||
# Add additional load paths for your own custom dirs
|
||||
# config.load_paths += %W( #{RAILS_ROOT}/app/services )
|
||||
|
||||
|
|
@ -33,10 +39,10 @@ Rails::Initializer.run do |config|
|
|||
# (create the session table with 'rake create_sessions_table')
|
||||
config.action_controller.session_store = :active_record_store
|
||||
|
||||
# config.action_controller.session = {
|
||||
# :session_key => '_tracks_session_id',
|
||||
# :secret => SALT * (30.0 / SALT.length).ceil #must be at least 30 characters
|
||||
# }
|
||||
config.action_controller.session = {
|
||||
:session_key => '_tracks_session_id',
|
||||
:secret => SALT * (30.0 / SALT.length).ceil #must be at least 30 characters
|
||||
}
|
||||
|
||||
# Enable page/fragment caching by setting a file-based store
|
||||
# (remember to create the caching directory and make it readable to the application)
|
||||
|
|
@ -70,9 +76,6 @@ end
|
|||
|
||||
# Include your application configuration below
|
||||
|
||||
# Leave this alone or set it to one or more of ['database', 'ldap', 'open_id'].
|
||||
# If you choose ldap, see the additional configuration options further down.
|
||||
AUTHENTICATION_SCHEMES = ['database']
|
||||
|
||||
require 'name_part_finder'
|
||||
require 'tracks/todo_list'
|
||||
|
|
@ -96,9 +99,6 @@ end
|
|||
# setting this to true will make the cookies only available over HTTPS
|
||||
TRACKS_COOKIES_SECURE = false
|
||||
|
||||
MOBILE_CONTENT_TYPE = 'tracks/mobile'
|
||||
Mime::Type.register(MOBILE_CONTENT_TYPE, :m)
|
||||
|
||||
tracks_version='1.7-devel'
|
||||
|
||||
# comment out next two lines if you do not want (or can not) the date of the
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# Add new mime types for use in respond_to blocks:
|
||||
# Mime::Type.register "text/richtext", :rtf
|
||||
# Mime::Type.register "application/x-mobile", :mobile
|
||||
Mime::Type.register_alias "text/html", :m
|
||||
|
|
@ -2,7 +2,7 @@ namespace :tracks do
|
|||
desc 'Replace the password of USER with a new one.'
|
||||
task :password => :environment do
|
||||
|
||||
Dependencies.load_paths.unshift(File.dirname(__FILE__) + "/..../vendor/gems/highline-1.4.0/lib")
|
||||
Dependencies.load_paths.unshift(File.dirname(__FILE__) + "/../../vendor/gems/highline-1.5.0/lib")
|
||||
require "highline/import"
|
||||
|
||||
user = User.find_by_login(ENV['USER'])
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
raise "To avoid rake task loading problems: run 'rake clobber' in vendor/plugins/rspec" if File.directory?(File.join(File.dirname(__FILE__), *%w[.. .. vendor plugins rspec pkg]))
|
||||
raise "To avoid rake task loading problems: run 'rake clobber' in vendor/plugins/rspec-rails" if File.directory?(File.join(File.dirname(__FILE__), *%w[.. .. vendor plugins rspec-rails pkg]))
|
||||
|
||||
# In rails 1.2, plugins aren't available in the path until they're loaded.
|
||||
# Check to see if the rspec plugin is installed first and require
|
||||
# it if it is. If not, use the gem version.
|
||||
rspec_base = File.expand_path(File.dirname(__FILE__) + '/../../rspec/lib')
|
||||
rspec_base = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec/lib')
|
||||
$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
|
||||
require 'spec/rake/spectask'
|
||||
require 'spec/translator'
|
||||
|
||||
spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? "db:test:prepare" : :noop
|
||||
task :noop do
|
||||
|
|
@ -64,13 +66,6 @@ namespace :spec do
|
|||
end
|
||||
end
|
||||
|
||||
desc "Translate/upgrade specs using the built-in translator"
|
||||
task :translate do
|
||||
translator = ::Spec::Translator.new
|
||||
dir = RAILS_ROOT + '/spec'
|
||||
translator.translate(dir, dir)
|
||||
end
|
||||
|
||||
# Setup specs for stats
|
||||
task :statsetup do
|
||||
require 'code_statistics'
|
||||
22
public/javascripts/controls.js
vendored
22
public/javascripts/controls.js
vendored
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
||||
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
|
||||
// (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
|
||||
|
|
@ -37,10 +37,10 @@
|
|||
if(typeof Effect == 'undefined')
|
||||
throw("controls.js requires including script.aculo.us' effects.js library");
|
||||
|
||||
var Autocompleter = { }
|
||||
var Autocompleter = { };
|
||||
Autocompleter.Base = Class.create({
|
||||
baseInitialize: function(element, update, options) {
|
||||
element = $(element)
|
||||
element = $(element);
|
||||
this.element = element;
|
||||
this.update = $(update);
|
||||
this.hasFocus = false;
|
||||
|
|
@ -209,13 +209,13 @@ Autocompleter.Base = Class.create({
|
|||
},
|
||||
|
||||
markPrevious: function() {
|
||||
if(this.index > 0) this.index--
|
||||
if(this.index > 0) this.index--;
|
||||
else this.index = this.entryCount-1;
|
||||
this.getEntry(this.index).scrollIntoView(false);
|
||||
this.getEntry(this.index).scrollIntoView(true);
|
||||
},
|
||||
|
||||
markNext: function() {
|
||||
if(this.index < this.entryCount-1) this.index++
|
||||
if(this.index < this.entryCount-1) this.index++;
|
||||
else this.index = 0;
|
||||
this.getEntry(this.index).scrollIntoView(false);
|
||||
},
|
||||
|
|
@ -457,7 +457,7 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {
|
|||
}
|
||||
}
|
||||
if (partial.length)
|
||||
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
||||
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
|
||||
return "<ul>" + ret.join('') + "</ul>";
|
||||
}
|
||||
}, options || { });
|
||||
|
|
@ -474,7 +474,7 @@ Field.scrollFreeActivate = function(field) {
|
|||
setTimeout(function() {
|
||||
Field.activate(field);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
|
||||
Ajax.InPlaceEditor = Class.create({
|
||||
initialize: function(element, url, options) {
|
||||
|
|
@ -604,7 +604,7 @@ Ajax.InPlaceEditor = Class.create({
|
|||
this.triggerCallback('onEnterHover');
|
||||
},
|
||||
getText: function() {
|
||||
return this.element.innerHTML;
|
||||
return this.element.innerHTML.unescapeHTML();
|
||||
},
|
||||
handleAJAXFailure: function(transport) {
|
||||
this.triggerCallback('onFailure', transport);
|
||||
|
|
@ -780,7 +780,7 @@ Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
|
|||
onSuccess: function(transport) {
|
||||
var js = transport.responseText.strip();
|
||||
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
|
||||
throw 'Server returned an invalid collection representation.';
|
||||
throw('Server returned an invalid collection representation.');
|
||||
this._collection = eval(js);
|
||||
this.checkForExternalText();
|
||||
}.bind(this),
|
||||
|
|
|
|||
41
public/javascripts/dragdrop.js
vendored
41
public/javascripts/dragdrop.js
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
|
||||
// (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/
|
||||
|
|
@ -121,7 +121,7 @@ var Droppables = {
|
|||
if(this.last_active)
|
||||
this.deactivate(this.last_active);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var Draggables = {
|
||||
drags: [],
|
||||
|
|
@ -218,7 +218,7 @@ var Draggables = {
|
|||
).length;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -331,8 +331,8 @@ var Draggable = Class.create({
|
|||
|
||||
if(this.options.ghosting) {
|
||||
this._clone = this.element.cloneNode(true);
|
||||
this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
|
||||
if (!this.element._originallyAbsolute)
|
||||
this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
|
||||
if (!this._originallyAbsolute)
|
||||
Position.absolutize(this.element);
|
||||
this.element.parentNode.insertBefore(this._clone, this.element);
|
||||
}
|
||||
|
|
@ -403,9 +403,9 @@ var Draggable = Class.create({
|
|||
}
|
||||
|
||||
if(this.options.ghosting) {
|
||||
if (!this.element._originallyAbsolute)
|
||||
if (!this._originallyAbsolute)
|
||||
Position.relativize(this.element);
|
||||
delete this.element._originallyAbsolute;
|
||||
delete this._originallyAbsolute;
|
||||
Element.remove(this._clone);
|
||||
this._clone = null;
|
||||
}
|
||||
|
|
@ -478,10 +478,10 @@ var Draggable = Class.create({
|
|||
} 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))
|
||||
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))
|
||||
return (v/this.options.snap).round()*this.options.snap }.bind(this));
|
||||
}
|
||||
}}
|
||||
|
||||
|
|
@ -560,7 +560,7 @@ var Draggable = Class.create({
|
|||
H = documentElement.clientHeight;
|
||||
} else {
|
||||
W = body.offsetWidth;
|
||||
H = body.offsetHeight
|
||||
H = body.offsetHeight;
|
||||
}
|
||||
}
|
||||
return { top: T, left: L, width: W, height: H };
|
||||
|
|
@ -608,7 +608,8 @@ var Sortable = {
|
|||
},
|
||||
|
||||
destroy: function(element){
|
||||
var s = Sortable.options(element);
|
||||
element = $(element);
|
||||
var s = Sortable.sortables[element.id];
|
||||
|
||||
if(s) {
|
||||
Draggables.removeObserver(s.element);
|
||||
|
|
@ -689,14 +690,14 @@ var Sortable = {
|
|||
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);
|
||||
|
|
@ -851,11 +852,11 @@ var Sortable = {
|
|||
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)
|
||||
this._tree(child.container, options, child);
|
||||
|
||||
parent.children.push (child);
|
||||
}
|
||||
|
|
@ -880,7 +881,7 @@ var Sortable = {
|
|||
children: [],
|
||||
container: element,
|
||||
position: 0
|
||||
}
|
||||
};
|
||||
|
||||
return Sortable._tree(element, options, root);
|
||||
},
|
||||
|
|
@ -940,14 +941,14 @@ var Sortable = {
|
|||
}).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;
|
||||
|
|
@ -965,8 +966,8 @@ Element.findChildren = function(element, only, recursive, tagName) {
|
|||
});
|
||||
|
||||
return (elements.length>0 ? elements.flatten() : []);
|
||||
}
|
||||
};
|
||||
|
||||
Element.offsetSize = function (element, type) {
|
||||
return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
|
||||
}
|
||||
};
|
||||
98
public/javascripts/effects.js
vendored
98
public/javascripts/effects.js
vendored
|
|
@ -70,25 +70,20 @@ var Effect = {
|
|||
Transitions: {
|
||||
linear: Prototype.K,
|
||||
sinoidal: function(pos) {
|
||||
return (-Math.cos(pos*Math.PI)/2) + 0.5;
|
||||
return (-Math.cos(pos*Math.PI)/2) + .5;
|
||||
},
|
||||
reverse: function(pos) {
|
||||
return 1-pos;
|
||||
},
|
||||
flicker: function(pos) {
|
||||
var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
|
||||
var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
|
||||
return pos > 1 ? 1 : pos;
|
||||
},
|
||||
wobble: function(pos) {
|
||||
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
|
||||
return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
|
||||
},
|
||||
pulse: function(pos, pulses) {
|
||||
pulses = pulses || 5;
|
||||
return (
|
||||
((pos % (1/pulses)) * pulses).round() == 0 ?
|
||||
((pos * pulses * 2) - (pos * pulses * 2).floor()) :
|
||||
1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
|
||||
);
|
||||
return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
|
||||
},
|
||||
spring: function(pos) {
|
||||
return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
|
||||
|
|
@ -249,18 +244,30 @@ Effect.Base = Class.create({
|
|||
this.totalTime = this.finishOn-this.startOn;
|
||||
this.totalFrames = this.options.fps*this.options.duration;
|
||||
|
||||
eval('this.render = function(pos){ '+
|
||||
'if (this.state=="idle"){this.state="running";'+
|
||||
codeForEvent(this.options,'beforeSetup')+
|
||||
(this.setup ? 'this.setup();':'')+
|
||||
codeForEvent(this.options,'afterSetup')+
|
||||
'};if (this.state=="running"){'+
|
||||
'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
|
||||
'this.position=pos;'+
|
||||
codeForEvent(this.options,'beforeUpdate')+
|
||||
(this.update ? 'this.update(pos);':'')+
|
||||
codeForEvent(this.options,'afterUpdate')+
|
||||
'}}');
|
||||
this.render = (function() {
|
||||
function dispatch(effect, eventName) {
|
||||
if (effect.options[eventName + 'Internal'])
|
||||
effect.options[eventName + 'Internal'](effect);
|
||||
if (effect.options[eventName])
|
||||
effect.options[eventName](effect);
|
||||
}
|
||||
|
||||
return function(pos) {
|
||||
if (this.state === "idle") {
|
||||
this.state = "running";
|
||||
dispatch(this, 'beforeSetup');
|
||||
if (this.setup) this.setup();
|
||||
dispatch(this, 'afterSetup');
|
||||
}
|
||||
if (this.state === "running") {
|
||||
pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
|
||||
this.position = pos;
|
||||
dispatch(this, 'beforeUpdate');
|
||||
if (this.update) this.update(pos);
|
||||
dispatch(this, 'afterUpdate');
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
this.event('beforeStart');
|
||||
if (!this.options.sync)
|
||||
|
|
@ -507,17 +514,16 @@ Effect.Highlight = Class.create(Effect.Base, {
|
|||
|
||||
Effect.ScrollTo = function(element) {
|
||||
var options = arguments[1] || { },
|
||||
scrollOffsets = document.viewport.getScrollOffsets(),
|
||||
elementOffsets = $(element).cumulativeOffset(),
|
||||
max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
|
||||
scrollOffsets = document.viewport.getScrollOffsets(),
|
||||
elementOffsets = $(element).cumulativeOffset();
|
||||
|
||||
if (options.offset) elementOffsets[1] += options.offset;
|
||||
|
||||
return new Effect.Tween(null,
|
||||
scrollOffsets.top,
|
||||
elementOffsets[1] > max ? max : elementOffsets[1],
|
||||
elementOffsets[1],
|
||||
options,
|
||||
function(p){ scrollTo(scrollOffsets.left, p.round()) }
|
||||
function(p){ scrollTo(scrollOffsets.left, p.round()); }
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -568,7 +574,7 @@ Effect.Puff = function(element) {
|
|||
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
|
||||
Object.extend({ duration: 1.0,
|
||||
beforeSetupInternal: function(effect) {
|
||||
Position.absolutize(effect.effects[0].element)
|
||||
Position.absolutize(effect.effects[0].element);
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.effects[0].element.hide().setStyle(oldStyle); }
|
||||
|
|
@ -625,7 +631,7 @@ Effect.SwitchOff = function(element) {
|
|||
afterFinishInternal: function(effect) {
|
||||
effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}, arguments[1] || { }));
|
||||
};
|
||||
|
|
@ -674,7 +680,7 @@ Effect.Shake = function(element) {
|
|||
new Effect.Move(effect.element,
|
||||
{ x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
|
||||
effect.element.undoPositioned().setStyle(oldStyle);
|
||||
}}) }}) }}) }}) }}) }});
|
||||
}}); }}); }}); }}); }}); }});
|
||||
};
|
||||
|
||||
Effect.SlideDown = function(element) {
|
||||
|
|
@ -816,7 +822,7 @@ Effect.Grow = function(element) {
|
|||
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
|
||||
}
|
||||
}, options)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -877,11 +883,13 @@ Effect.Shrink = function(element) {
|
|||
|
||||
Effect.Pulsate = function(element) {
|
||||
element = $(element);
|
||||
var options = arguments[1] || { };
|
||||
var oldOpacity = element.getInlineOpacity();
|
||||
var transition = options.transition || Effect.Transitions.sinoidal;
|
||||
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
|
||||
reverser.bind(transition);
|
||||
var options = arguments[1] || { },
|
||||
oldOpacity = element.getInlineOpacity(),
|
||||
transition = options.transition || Effect.Transitions.linear,
|
||||
reverser = function(pos){
|
||||
return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
|
||||
};
|
||||
|
||||
return new Effect.Opacity(element,
|
||||
Object.extend(Object.extend({ duration: 2.0, from: 0,
|
||||
afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
|
||||
|
|
@ -934,7 +942,7 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
effect.transforms.each(function(transform) {
|
||||
effect.element.style[transform.style] = '';
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
this.start(options);
|
||||
|
|
@ -945,7 +953,7 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
|
||||
color = color.parseColor();
|
||||
return $R(0,2).map(function(i){
|
||||
return parseInt( color.slice(i*2+1,i*2+3), 16 )
|
||||
return parseInt( color.slice(i*2+1,i*2+3), 16 );
|
||||
});
|
||||
}
|
||||
this.transforms = this.style.map(function(pair){
|
||||
|
|
@ -978,7 +986,7 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
transform.unit != 'color' &&
|
||||
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
update: function(position) {
|
||||
|
|
@ -1074,14 +1082,14 @@ if (document.defaultView && document.defaultView.getComputedStyle) {
|
|||
Element.getStyles = function(element) {
|
||||
element = $(element);
|
||||
var css = element.currentStyle, styles;
|
||||
styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
|
||||
hash.set(property, css[property]);
|
||||
return hash;
|
||||
styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
|
||||
results[property] = css[property];
|
||||
return results;
|
||||
});
|
||||
if (!styles.opacity) styles.set('opacity', element.getOpacity());
|
||||
if (!styles.opacity) styles.opacity = element.getOpacity();
|
||||
return styles;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Effect.Methods = {
|
||||
morph: function(element, style) {
|
||||
|
|
@ -1090,7 +1098,7 @@ Effect.Methods = {
|
|||
return element;
|
||||
},
|
||||
visualEffect: function(element, effect, options) {
|
||||
element = $(element)
|
||||
element = $(element);
|
||||
var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
|
||||
new Effect[klass](element, options);
|
||||
return element;
|
||||
|
|
@ -1109,7 +1117,7 @@ $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
|
|||
element = $(element);
|
||||
Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
|
||||
return element;
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
629
public/javascripts/prototype.js
vendored
629
public/javascripts/prototype.js
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -60,10 +60,6 @@ h4.notice {
|
|||
color: #007E00;
|
||||
}
|
||||
|
||||
div.t {
|
||||
padding-left:5px;
|
||||
}
|
||||
|
||||
span.tag {
|
||||
font-size: XX-small;
|
||||
background-color: #CCE7FF;
|
||||
|
|
@ -126,3 +122,7 @@ span.prj, span.ctx{
|
|||
.errors {
|
||||
background: #FFC2C2;
|
||||
}
|
||||
|
||||
table.c {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
|
|
|||
4
script/autospec
Executable file
4
script/autospec
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env ruby
|
||||
ENV['RSPEC'] = 'true' # allows autotest to discover rspec
|
||||
ENV['AUTOTEST'] = 'true' # allows autotest to run w/ color on linux
|
||||
system (RUBY_PLATFORM =~ /mswin|mingw/ ? 'autotest.bat' : 'autotest'), *ARGV
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env ruby
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../vendor/plugins/rspec/lib"))
|
||||
require 'rubygems'
|
||||
require 'spec'
|
||||
exit ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(ARGV, STDERR, STDOUT))
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ module LuckySneaks
|
|||
it "should not be valid if #{attribute} length is more than #{maximum}" do
|
||||
instance.send "#{attribute}=", 'x'*(maximum+1)
|
||||
instance.errors_on(attribute).should include(
|
||||
options[:message_too_long] || ActiveRecord::Errors.default_error_messages[:too_long] % maximum
|
||||
options[:message_too_long] || I18n.t('activerecord.errors.messages.too_long', :count => maximum)
|
||||
)
|
||||
end if maximum
|
||||
|
||||
it "should not be valid if #{attribute} length is less than #{minimum}" do
|
||||
instance.send "#{attribute}=", 'x'*(minimum-1)
|
||||
instance.errors_on(attribute).should include(
|
||||
options[:message_to_short] || ActiveRecord::Errors.default_error_messages[:too_short] % minimum
|
||||
options[:message_to_short] || I18n.t('activerecord.errors.messages.too_short', :count => minimum)
|
||||
)
|
||||
end if minimum
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,32 +3,36 @@ require File.dirname(__FILE__) + '/../../spec_helper'
|
|||
describe "/notes/_notes.rhtml" do
|
||||
before :each do
|
||||
@project = mock_model(Project, :name => "a project")
|
||||
@note = mock_model(Note, :body => "this is a note", :project => @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!(:apply_behavior)
|
||||
@controller.template.stub!(:format_date)
|
||||
@controller.template.stub!(:render)
|
||||
@controller.template.stub!(:form_remote_tag)
|
||||
# @controller.template.stub!(:render)
|
||||
# @controller.template.stub!(:form_remote_tag)
|
||||
end
|
||||
|
||||
it "should render" do
|
||||
pending "figure out how to mock or work with with UJS"
|
||||
render :partial => "/notes/notes", :locals => {:notes => @note}
|
||||
response.should have_tag("div.note_footer")
|
||||
end
|
||||
|
||||
it "should auto-link URLs" do
|
||||
pending "figure out how to mock or work with with UJS"
|
||||
@note.stub!(:body).and_return("http://www.google.com/")
|
||||
render :partial => "/notes/notes", :locals => {:notes => @note}
|
||||
response.should have_tag("a[href=\"http://www.google.com/\"]")
|
||||
end
|
||||
|
||||
it "should auto-link embedded URLs" do
|
||||
pending "figure out how to mock or work with with UJS"
|
||||
@note.stub!(:body).and_return("this is cool: http://www.google.com/")
|
||||
render :partial => "/notes/notes", :locals => {:notes => @note}
|
||||
response.should have_tag("a[href=\"http://www.google.com/\"]")
|
||||
end
|
||||
|
||||
it "should parse Textile links correctly" do
|
||||
pending "figure out how to mock or work with with UJS"
|
||||
@note.stub!(:body).and_return("\"link\":http://www.google.com/")
|
||||
render :partial => "/notes/notes", :locals => {:notes => @note}
|
||||
response.should have_tag("a[href=\"http://www.google.com/\"]")
|
||||
|
|
|
|||
4
stories/all.rb
Normal file
4
stories/all.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
dir = File.dirname(__FILE__)
|
||||
Dir[File.expand_path("#{dir}/**/*.rb")].uniq.each do |file|
|
||||
require file
|
||||
end
|
||||
|
|
@ -1,136 +1,3 @@
|
|||
ENV["RAILS_ENV"] = "test"
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
||||
$:.unshift File.join(File.dirname(__FILE__), *%w[.. vendor plugings rspec lib])
|
||||
require 'test_help'
|
||||
require 'test/unit/testresult'
|
||||
require 'spec'
|
||||
require 'spec/rails'
|
||||
require 'spec/story'
|
||||
require 'webrat/selenium'
|
||||
require 'action_controller/test_process'
|
||||
|
||||
module Spec
|
||||
module Story
|
||||
class StepGroup
|
||||
def include_steps_for(name)
|
||||
require File.expand_path(File.dirname(__FILE__) + "/steps/#{name}")
|
||||
step_matchers = rspec_story_steps[name.to_sym]
|
||||
warn "WARNING: 0 step matchers found for include_steps_for(:#{name}). Are you missing an include?" if step_matchers.empty?
|
||||
self << step_matchers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Test::Unit.run = true
|
||||
|
||||
class SeleniumRailsStory < Test::Unit::TestCase
|
||||
include Spec::Matchers
|
||||
include Spec::Rails::Matchers
|
||||
|
||||
def initialize #:nodoc:
|
||||
# TODO - eliminate this hack, which is here to stop
|
||||
# Rails Stories from dumping the example summary.
|
||||
Spec::Runner::Options.class_eval do
|
||||
def examples_should_be_run?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@_result = Test::Unit::TestResult.new
|
||||
end
|
||||
|
||||
def should_see(text_or_regexp)
|
||||
if text_or_regexp.is_a?(Regexp)
|
||||
response.should have_tag("*", text_or_regexp)
|
||||
else
|
||||
response.should have_tag("*", /#{Regexp.escape(text_or_regexp)}/i)
|
||||
end
|
||||
end
|
||||
|
||||
def should_not_see(text_or_regexp)
|
||||
if text_or_regexp.is_a?(Regexp)
|
||||
response.should_not have_tag("*", text_or_regexp)
|
||||
else
|
||||
response.should_not have_tag("*", /#{Regexp.escape(text_or_regexp)}/i)
|
||||
end
|
||||
end
|
||||
|
||||
def response
|
||||
webrat_session.response_body
|
||||
end
|
||||
|
||||
def logged_in_as(user)
|
||||
visits("/selenium_helper/login?as=#{user.login}")
|
||||
end
|
||||
|
||||
def selenium
|
||||
SeleniumDriverManager.instance.running_selenium_driver
|
||||
end
|
||||
|
||||
def badge_count_should_show(count)
|
||||
response.should have_tag('#badge_count', count.to_s)
|
||||
end
|
||||
|
||||
def method_missing(name, *args)
|
||||
if webrat_session.respond_to?(name)
|
||||
webrat_session.send(name, *args)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def webrat_session
|
||||
@webrat_session ||= begin
|
||||
Webrat::SeleniumSession.new(SeleniumDriverManager.instance.running_selenium_driver)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DatabaseResetListener
|
||||
include Singleton
|
||||
|
||||
def scenario_started(*args)
|
||||
if defined?(ActiveRecord::Base)
|
||||
connection = ActiveRecord::Base.connection
|
||||
%w[users].each do |table|
|
||||
connection.execute "DELETE FROM #{table}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing sym, *args, &block
|
||||
# ignore all messages you don't care about
|
||||
end
|
||||
end
|
||||
|
||||
class CookieResetListener
|
||||
include Singleton
|
||||
|
||||
def scenario_started(*args)
|
||||
%w[tracks_login auth_token _session_id].each do |cookie_name|
|
||||
SeleniumDriverManager.instance.running_selenium_driver.get_eval("window.document.cookie = '#{cookie_name}=;expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/';")
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing sym, *args, &block
|
||||
# ignore all messages you don't care about
|
||||
end
|
||||
end
|
||||
|
||||
class Spec::Story::Runner::ScenarioRunner
|
||||
def initialize
|
||||
@listeners = [DatabaseResetListener.instance, CookieResetListener.instance]
|
||||
end
|
||||
end
|
||||
|
||||
class Spec::Story::GivenScenario
|
||||
def perform(instance, name = nil)
|
||||
scenario = Spec::Story::Runner::StoryRunner.scenario_from_current_story @name
|
||||
runner = Spec::Story::Runner::ScenarioRunner.new
|
||||
runner.instance_variable_set(:@listeners,[])
|
||||
runner.run(scenario, instance)
|
||||
end
|
||||
end
|
||||
require 'spec/rails/story_adapter'
|
||||
|
|
@ -223,8 +223,8 @@ class ProjectsControllerTest < TodoContainerControllerTestBase
|
|||
login_as :admin_user
|
||||
u = users(:admin_user)
|
||||
post :actionize, :state => "active", :format => 'js'
|
||||
assert_equal 1, projects(:gardenclean).position
|
||||
assert_equal 2, projects(:moremoney).position
|
||||
assert_equal 2, projects(:gardenclean).position
|
||||
assert_equal 1, projects(:moremoney).position
|
||||
assert_equal 3, projects(:timemachine).position
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
|
||||
assert_xml_select 'rss[version="2.0"]' do
|
||||
assert_select 'channel' do
|
||||
assert_select '>title', 'Tracks Actions'
|
||||
assert_select '>title', 'Actions'
|
||||
assert_select '>description', "Actions for #{users(:admin_user).display_name}"
|
||||
assert_select 'language', 'en-us'
|
||||
assert_select 'ttl', '40'
|
||||
|
|
@ -205,7 +205,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
|
||||
assert_xml_select 'rss[version="2.0"]' do
|
||||
assert_select 'channel' do
|
||||
assert_select '>title', 'Tracks Actions'
|
||||
assert_select '>title', 'Actions'
|
||||
assert_select '>description', "Actions for #{users(:admin_user).display_name}"
|
||||
assert_select 'item', 5 do
|
||||
assert_select 'title', /.+/
|
||||
|
|
@ -240,7 +240,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
# #puts @response.body
|
||||
|
||||
assert_xml_select 'feed[xmlns="http://www.w3.org/2005/Atom"]' do
|
||||
assert_xml_select '>title', 'Tracks Actions'
|
||||
assert_xml_select '>title', 'Actions'
|
||||
assert_xml_select '>subtitle', "Actions for #{users(:admin_user).display_name}"
|
||||
assert_xml_select 'entry', 11 do
|
||||
assert_xml_select 'title', /.+/
|
||||
|
|
@ -450,7 +450,7 @@ class TodosControllerTest < Test::Rails::TestCase
|
|||
|
||||
# check that the new_todo is in the tickler to show next month
|
||||
assert !new_todo.show_from.nil?
|
||||
assert_equal Time.utc(today.year, today.month+1, today.day), new_todo.show_from
|
||||
assert_equal Time.utc(today.year, today.month, today.day)+1.month, new_todo.show_from
|
||||
end
|
||||
|
||||
def test_check_for_next_todo
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ class ContextXmlApiTest < ActionController::IntegrationTest
|
|||
end
|
||||
|
||||
def test_fails_with_invalid_xml_format
|
||||
authenticated_post_xml_to_context_create "<foo></bar>"
|
||||
assert_equal 500, @integration_session.status
|
||||
# Fails too hard for test to catch
|
||||
# authenticated_post_xml_to_context_create "<foo></bar>"
|
||||
# assert_equal 500, @integration_session.status
|
||||
end
|
||||
|
||||
def test_fails_with_invalid_xml_format2
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ class ProjectXmlApiTest < ActionController::IntegrationTest
|
|||
end
|
||||
|
||||
def test_fails_with_invalid_xml_format
|
||||
authenticated_post_xml_to_project_create "<foo></bar>"
|
||||
assert_equal 500, @integration_session.status
|
||||
#Fails too hard for test to catch
|
||||
# authenticated_post_xml_to_project_create "<foo></bar>"
|
||||
# assert_equal 500, @integration_session.status
|
||||
end
|
||||
|
||||
def test_fails_with_invalid_xml_format2
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@ class UsersXmlApiTest < ActionController::IntegrationTest
|
|||
assert_404_invalid_xml
|
||||
end
|
||||
|
||||
def test_fails_with_invalid_xml_format
|
||||
authenticated_post_xml_to_user_create "<foo></bar>"
|
||||
assert_equal 500, @integration_session.status
|
||||
end
|
||||
# Fails too hard for test to catch
|
||||
# def test_fails_with_invalid_xml_format
|
||||
# authenticated_post_xml_to_user_create "<foo></bar>"
|
||||
# assert_equal 500, @integration_session.status
|
||||
# end
|
||||
|
||||
def test_fails_with_invalid_xml_format2
|
||||
authenticated_post_xml_to_user_create "<request><username>foo</username></request>"
|
||||
|
|
|
|||
|
|
@ -19,3 +19,6 @@ wait_for_not_visible "todo_9"
|
|||
|
||||
# check that newly added action is not there
|
||||
wait_for_not_visible "xpath=//span[text()='a new action']"
|
||||
|
||||
# toggle c1 back. Selenium does not reset cookies
|
||||
click "css=#toggle_c1"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ login :as => 'admin'
|
|||
|
||||
open "/"
|
||||
# we should start with 10 actions on home page
|
||||
assert_text 'badge_count', '10'
|
||||
assert_text 'badge_count', '11'
|
||||
|
||||
# set project to hidden state
|
||||
open "/projects/2"
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ wait_for_element_present "show_from_todo_9"
|
|||
type "show_from_todo_9", "1/1/2030"
|
||||
click "css=#submit_todo_9"
|
||||
wait_for_element_not_present "todo_9"
|
||||
assert_text 'badge_count', '9'
|
||||
assert_text 'badge_count', '10'
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ wait_for_element_present "show_from_todo_5"
|
|||
type "show_from_todo_5", "1/1/2030"
|
||||
click "css=#submit_todo_5"
|
||||
wait_for_element_not_present "todo_5"
|
||||
assert_text 'badge_count', '9'
|
||||
assert_text 'badge_count', '10'
|
||||
wait_for_not_visible "c5"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
setup :fixtures => :all
|
||||
login :as => 'admin'
|
||||
open "/"
|
||||
wait_for_element_present '//div[@id="line_todo_5"]//img[@alt="Defer_1"]/..'
|
||||
click '//div[@id="line_todo_5"]//img[@alt="Defer_1"]/..'
|
||||
wait_for_element_present '//div[@id="line_todo_5"]//img[@alt="Defer 1 day"]/..'
|
||||
click '//div[@id="line_todo_5"]//img[@alt="Defer 1 day"]/..'
|
||||
wait_for_element_not_present "todo_5"
|
||||
assert_text 'badge_count', '9'
|
||||
assert_text 'badge_count', '10'
|
||||
wait_for_not_visible "c5"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ setup :fixtures => :all
|
|||
login :as => 'admin'
|
||||
|
||||
open '/m'
|
||||
wait_for_text 'css=h1 span.count', '10'
|
||||
wait_for_text 'css=h1 span.count', '11'
|
||||
|
||||
click_and_wait "link=0-Add new action"
|
||||
|
||||
|
|
@ -15,4 +15,4 @@ select "todo_due_2i", "label=January"
|
|||
select "todo_due_1i", "label=2009"
|
||||
click_and_wait "//input[@value='Create']"
|
||||
|
||||
wait_for_text 'css=h1 span.count', '11'
|
||||
wait_for_text 'css=h1 span.count', '12'
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ setup :fixtures => :all
|
|||
login :as => 'admin'
|
||||
|
||||
open '/m'
|
||||
wait_for_text 'css=h1 span.count', '10'
|
||||
wait_for_text 'css=h1 span.count', '11'
|
||||
|
||||
open '/todos/6.m'
|
||||
wait_for_page_to_load 3000
|
||||
|
||||
open_and_wait '/todos/6.m'
|
||||
click "done"
|
||||
click_and_wait "//input[@value='Update']"
|
||||
|
||||
wait_for_text 'css=h1 span.count', '9'
|
||||
wait_for_text 'css=h1 span.count', '10'
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ login :as => 'admin'
|
|||
# open home page
|
||||
open '/m'
|
||||
wait_for_title "All actions"
|
||||
wait_for_text 'css=h1 span.count', '10'
|
||||
wait_for_text 'css=h1 span.count', '11'
|
||||
|
||||
# open context page
|
||||
click_and_wait "link=2-Contexts"
|
||||
# verify_title "All actions in context agenda"
|
||||
# choose agenda context
|
||||
click_and_wait "link=agenda"
|
||||
wait_for_text 'css=h1 span.count', '5'
|
||||
wait_for_text 'css=h1 span.count', '6'
|
||||
|
||||
# click on tag foo to go to tag page
|
||||
click_and_wait "link=foo"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
setup :fixtures => :all
|
||||
login :as => 'admin'
|
||||
open '/projects/1'
|
||||
assert_checked 'project_state_active', 'ignored'
|
||||
assert_checked 'project_state_active'
|
||||
assert_attribute 'css=#project_status .active span', 'class', 'active_state'
|
||||
assert_attribute 'css=#project_status .hidden span', 'class', 'inactive_state'
|
||||
assert_text 'badge_count', '2'
|
||||
|
|
@ -11,4 +11,4 @@ wait_for_attribute 'css=#project_status .hidden span', 'class', 'active_state'
|
|||
assert_text 'badge_count', '2'
|
||||
open '/projects/1'
|
||||
assert_text 'badge_count', '2'
|
||||
assert_checked 'project_state_hidden', 'ignored'
|
||||
assert_checked 'project_state_hidden'
|
||||
|
|
|
|||
|
|
@ -20,4 +20,4 @@ assert_text 'badge_count', '4'
|
|||
|
||||
open '/projects/1'
|
||||
assert_text 'badge_count', '4'
|
||||
assert_checked 'project_state_hidden', 'ignored'
|
||||
assert_checked 'project_state_hidden'
|
||||
|
|
|
|||
|
|
@ -51,4 +51,10 @@ module SeleniumOnRails::TestBuilderAccessors
|
|||
yield
|
||||
wait_for_context_count "${expected_context_count}"
|
||||
end
|
||||
|
||||
def click_and_wait clickable
|
||||
click clickable
|
||||
wait_for_page_to_load 3000
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -68,5 +68,6 @@ class PrototypeHelperExtensionsTest < Test::Unit::TestCase
|
|||
false
|
||||
end
|
||||
|
||||
attr_accessor :output_buffer
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
Below is a complete listing of changes for each revision of HighLine.
|
||||
|
||||
== 1.5.0
|
||||
|
||||
* Fixed a bug that would prevent Readline from showing all completions.
|
||||
(reported by Yaohan Chen)
|
||||
* Added the ability to pass a block to HighLine#agree().
|
||||
(patch by Yaohan Chen)
|
||||
|
||||
== 1.4.0
|
||||
|
||||
* Made the code grabbing terminal size a little more cross-platform by
|
||||
|
|
@ -9,7 +9,7 @@ require "rubygems"
|
|||
require "highline/import"
|
||||
|
||||
loop do
|
||||
cmd = ask("Enter command: ", %w{save load reset quit}) do |q|
|
||||
cmd = ask("Enter command: ", %w{save sample load reset quit}) do |q|
|
||||
q.readline = true
|
||||
end
|
||||
say("Executing \"#{cmd}\"...")
|
||||
|
|
@ -29,7 +29,7 @@ require "abbrev"
|
|||
#
|
||||
class HighLine
|
||||
# The version of the installed library.
|
||||
VERSION = "1.4.0".freeze
|
||||
VERSION = "1.5.0".freeze
|
||||
|
||||
# An internal HighLine error. User code does not need to trap this.
|
||||
class QuestionError < StandardError
|
||||
|
|
@ -173,7 +173,8 @@ class HighLine
|
|||
# A shortcut to HighLine.ask() a question that only accepts "yes" or "no"
|
||||
# answers ("y" and "n" are allowed) and returns +true+ or +false+
|
||||
# (+true+ for "yes"). If provided a +true+ value, _character_ will cause
|
||||
# HighLine to fetch a single character response.
|
||||
# HighLine to fetch a single character response. A block can be provided
|
||||
# to further configure the question as in HighLine.ask()
|
||||
#
|
||||
# Raises EOFError if input is exhausted.
|
||||
#
|
||||
|
|
@ -183,6 +184,8 @@ class HighLine
|
|||
q.responses[:not_valid] = 'Please enter "yes" or "no".'
|
||||
q.responses[:ask_on_error] = :question
|
||||
q.character = character
|
||||
|
||||
yield q if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -577,8 +580,9 @@ class HighLine
|
|||
@output = old_output
|
||||
|
||||
# prep auto-completion
|
||||
completions = @question.selection.abbrev
|
||||
Readline.completion_proc = lambda { |string| completions[string] }
|
||||
Readline.completion_proc = lambda do |string|
|
||||
@question.selection.grep(/\A#{Regexp.escape(string)}/)
|
||||
end
|
||||
|
||||
# work-around ugly readline() warnings
|
||||
old_verbose = $VERBOSE
|
||||
|
|
@ -44,6 +44,14 @@ class TestHighLine < Test::Unit::TestCase
|
|||
assert_equal(true, @terminal.agree("Yes or no? ", :getc))
|
||||
end
|
||||
|
||||
def test_agree_with_block
|
||||
@input << "\n\n"
|
||||
@input.rewind
|
||||
|
||||
assert_equal(true, @terminal.agree("Yes or no? ") { |q| q.default = "y" })
|
||||
assert_equal(false, @terminal.agree("Yes or no? ") { |q| q.default = "n" })
|
||||
end
|
||||
|
||||
def test_ask
|
||||
name = "James Edward Gray II"
|
||||
@input << name << "\n"
|
||||
10
vendor/plugins/arts/lib/arts.rb
vendored
10
vendor/plugins/arts/lib/arts.rb
vendored
|
|
@ -38,7 +38,7 @@ module Arts
|
|||
raise "Invalid content type"
|
||||
end
|
||||
else
|
||||
assert_match Regexp.new("new Insertion\.#{position.to_s.camelize}(.*#{item_id}.*,.*?);"),
|
||||
assert_match /Element\.insert\("#{item_id}", \{.*#{position.to_s.downcase}.*\}.*\)\;/,
|
||||
@response.body
|
||||
end
|
||||
end
|
||||
|
|
@ -130,4 +130,12 @@ module Arts
|
|||
return create_generator.send(:arguments_for_call, args)
|
||||
end
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
# hack for rails 2.2.2
|
||||
def with_output_buffer(lines=[], &block)
|
||||
block.call
|
||||
end
|
||||
|
||||
end
|
||||
122
vendor/plugins/asset_packager/CHANGELOG
vendored
122
vendor/plugins/asset_packager/CHANGELOG
vendored
|
|
@ -1,122 +0,0 @@
|
|||
------------------------------------------------------------------------
|
||||
r52 | sbecker | 2007-11-04 01:38:21 -0400 (Sun, 04 Nov 2007) | 3 lines
|
||||
|
||||
* Allow configuration of which environments the helpers should merge scripts with the Synthesis::AssetPackage.merge_environments variable.
|
||||
* Refactored tests so they can all run together, and not depend on what the RAILS_ENV constant is.
|
||||
* Only add file extension if it was explicitly passed in, fixes other helpers in rails.
|
||||
------------------------------------------------------------------------
|
||||
r51 | sbecker | 2007-10-26 16:24:48 -0400 (Fri, 26 Oct 2007) | 1 line
|
||||
|
||||
* Updated jsmin.rb to latest version from 2007-07-20
|
||||
------------------------------------------------------------------------
|
||||
r50 | sbecker | 2007-10-23 23:16:07 -0400 (Tue, 23 Oct 2007) | 1 line
|
||||
|
||||
Updated CHANGELOG
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r49 | sbecker | 2007-10-23 23:13:27 -0400 (Tue, 23 Oct 2007) | 1 line
|
||||
|
||||
* Finally committed the subdirectory patch. (Thanks James Coglan!)
|
||||
------------------------------------------------------------------------
|
||||
r48 | sbecker | 2007-10-15 15:10:43 -0400 (Mon, 15 Oct 2007) | 1 line
|
||||
|
||||
* Speed up rake tasks and remove rails environment dependencies
|
||||
------------------------------------------------------------------------
|
||||
r43 | sbecker | 2007-07-02 15:30:29 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Updated the docs regarding testing.
|
||||
------------------------------------------------------------------------
|
||||
r42 | sbecker | 2007-07-02 15:27:00 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* For production helper test, build packages once - on first setup.
|
||||
------------------------------------------------------------------------
|
||||
r41 | sbecker | 2007-07-02 15:14:13 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Put build_all in test setup and delete_all in test teardown so all tests will pass the on first run of test suite.
|
||||
------------------------------------------------------------------------
|
||||
r40 | sbecker | 2007-07-02 14:55:28 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Fix quotes, add contact info
|
||||
------------------------------------------------------------------------
|
||||
r39 | sbecker | 2007-07-02 14:53:52 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Add note on how to run the tests for asset packager.
|
||||
------------------------------------------------------------------------
|
||||
r38 | sbecker | 2007-01-25 15:36:42 -0500 (Thu, 25 Jan 2007) | 1 line
|
||||
|
||||
added CHANGELOG w/ subversion log entries
|
||||
------------------------------------------------------------------------
|
||||
r37 | sbecker | 2007-01-25 15:34:39 -0500 (Thu, 25 Jan 2007) | 1 line
|
||||
|
||||
updated jsmin with new version from 2007-01-23
|
||||
------------------------------------------------------------------------
|
||||
r35 | sbecker | 2007-01-15 19:22:16 -0500 (Mon, 15 Jan 2007) | 1 line
|
||||
|
||||
require synthesis/asset_package in rake tasks, as Rails 1.2 seems to necessitate
|
||||
------------------------------------------------------------------------
|
||||
r34 | sbecker | 2007-01-05 12:22:09 -0500 (Fri, 05 Jan 2007) | 1 line
|
||||
|
||||
do a require before including in action view, because when running migrations, the plugin lib files don't automatically get required, causing the include to error out
|
||||
------------------------------------------------------------------------
|
||||
r33 | sbecker | 2006-12-23 02:03:41 -0500 (Sat, 23 Dec 2006) | 1 line
|
||||
|
||||
updating readme with various tweaks
|
||||
------------------------------------------------------------------------
|
||||
r32 | sbecker | 2006-12-23 02:03:12 -0500 (Sat, 23 Dec 2006) | 1 line
|
||||
|
||||
updating readme with various tweaks
|
||||
------------------------------------------------------------------------
|
||||
r31 | sbecker | 2006-12-23 01:52:25 -0500 (Sat, 23 Dec 2006) | 1 line
|
||||
|
||||
updated readme to show how to use different media for stylesheets
|
||||
------------------------------------------------------------------------
|
||||
r28 | sbecker | 2006-11-27 21:02:14 -0500 (Mon, 27 Nov 2006) | 1 line
|
||||
|
||||
updated compute_public_path, added check for images
|
||||
------------------------------------------------------------------------
|
||||
r27 | sbecker | 2006-11-10 18:28:29 -0500 (Fri, 10 Nov 2006) | 1 line
|
||||
|
||||
tolerate extra periods in source asset names. fixed subversion revision checking to be file specific, instead of repository specific.
|
||||
------------------------------------------------------------------------
|
||||
r26 | sbecker | 2006-06-24 17:04:27 -0400 (Sat, 24 Jun 2006) | 1 line
|
||||
|
||||
convert asset_packages_yml var to a class var
|
||||
------------------------------------------------------------------------
|
||||
r25 | sbecker | 2006-06-24 12:37:47 -0400 (Sat, 24 Jun 2006) | 1 line
|
||||
|
||||
Added ability to include assets by package name. In development, include all uncompressed asset files. In production, include the single compressed asset.
|
||||
------------------------------------------------------------------------
|
||||
r24 | sbecker | 2006-06-19 21:57:23 -0400 (Mon, 19 Jun 2006) | 1 line
|
||||
|
||||
Updates to README and about.yml
|
||||
------------------------------------------------------------------------
|
||||
r23 | sbecker | 2006-06-19 14:55:39 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Modifying about.yml and README
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r21 | sbecker | 2006-06-19 12:18:32 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
added "formerly known as MergeJS"
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r20 | sbecker | 2006-06-19 12:14:46 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Updating docs
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r19 | sbecker | 2006-06-19 11:26:08 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
removing compiled test assets from subversion
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r18 | sbecker | 2006-06-19 11:19:59 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Initial import.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r17 | sbecker | 2006-06-19 11:18:56 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Creating directory.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
173
vendor/plugins/asset_packager/README
vendored
173
vendor/plugins/asset_packager/README
vendored
|
|
@ -1,173 +0,0 @@
|
|||
= AssetPackager
|
||||
|
||||
JavaScript and CSS Asset Compression for Production Rails Apps
|
||||
|
||||
== Description
|
||||
|
||||
When it comes time to deploy your new web application, instead of
|
||||
sending down a dozen JavaScript and CSS files full of formatting
|
||||
and comments, this Rails plugin makes it simple to merge and
|
||||
compress JavaScript and CSS down into one or more files, increasing
|
||||
speed and saving bandwidth.
|
||||
|
||||
When in development, it allows you to use your original versions
|
||||
and retain formatting and comments for readability and debugging.
|
||||
|
||||
Because not all browsers will dependably cache JavaScript and CSS
|
||||
files with query string parameters, AssetPackager writes a timestamp
|
||||
or subversion revision stamp (if available) into the merged file names.
|
||||
Therefore files are correctly cached by the browser AND your users
|
||||
always get the latest version when you re-deploy.
|
||||
|
||||
This code is released under the MIT license (like Ruby). You’re free
|
||||
to rip it up, enhance it, etc. And if you make any enhancements,
|
||||
I’d like to know so I can add them back in. Thanks!
|
||||
|
||||
* Formerly known as MergeJS.
|
||||
|
||||
== Credit
|
||||
|
||||
This Rails Plugin was inspired by Cal Henderson's article
|
||||
"Serving JavaScript Fast" on Vitamin:
|
||||
http://www.thinkvitamin.com/features/webapps/serving-javascript-fast
|
||||
|
||||
It also uses the Ruby JavaScript Minifier created by
|
||||
Douglas Crockford.
|
||||
http://www.crockford.com/javascript/jsmin.html
|
||||
|
||||
== Key Features
|
||||
|
||||
* Merges and compresses JavaScript and CSS when running in production.
|
||||
* Uses uncompressed originals when running in development.
|
||||
* Handles caching correctly. (No querystring parameters - filename timestamps)
|
||||
* Versions each package individually. Updates to files in one won't re-trigger downloading the others.
|
||||
* Uses subversion revision numbers instead of timestamps if within a subversion controlled directory.
|
||||
* Guarantees new version will get downloaded the next time you deploy.
|
||||
|
||||
== Components
|
||||
|
||||
* Rake Task for merging and compressing JavaScript and CSS files.
|
||||
* Helper functions for including these JavaScript and CSS files in your views.
|
||||
* YAML configuration file for mapping JavaScript and CSS files to merged versions.
|
||||
* Rake Task for auto-generating the YAML file from your existing JavaScript files.
|
||||
|
||||
== How to Use:
|
||||
|
||||
1. Download and install the plugin:
|
||||
./script/plugin install http://sbecker.net/shared/plugins/asset_packager
|
||||
|
||||
2. Run the rake task "asset:packager:create_yml" to generate the /config/asset_packages.yml
|
||||
file the first time. You will need to reorder files under 'base' so dependencies are loaded
|
||||
in correct order. Feel free to rename or create new file packages.
|
||||
|
||||
IMPORTANT: JavaScript files can break once compressed if each statement doesn't end with a semi-colon.
|
||||
The minifier puts multiple statements on one line, so if the semi-colon is missing, the statement may no
|
||||
longer makes sense and cause a syntax error.
|
||||
|
||||
Example from a fresh rails app after running the rake task. (Stylesheets is blank because a
|
||||
default rails app has no stylesheets yet.):
|
||||
|
||||
---
|
||||
javascripts:
|
||||
- base:
|
||||
- prototype
|
||||
- effects
|
||||
- dragdrop
|
||||
- controls
|
||||
- application
|
||||
stylesheets:
|
||||
- base: []
|
||||
|
||||
Example with multiple merged files:
|
||||
|
||||
---
|
||||
javascripts:
|
||||
- base:
|
||||
- prototype
|
||||
- effects
|
||||
- controls
|
||||
- dragdrop
|
||||
- application
|
||||
- secondary:
|
||||
- foo
|
||||
- bar
|
||||
stylesheets:
|
||||
- base:
|
||||
- screen
|
||||
- header
|
||||
- secondary:
|
||||
- foo
|
||||
- bar
|
||||
|
||||
3. Run the rake task "asset:packager:build_all" to generate the compressed, merged versions
|
||||
for each package. Whenever you rearrange the yaml file, you'll need to run this task again.
|
||||
Merging and compressing is expensive, so this is something we want to do once, not every time
|
||||
your app starts. Thats why its a rake task.
|
||||
|
||||
4. Use the helper functions whenever including these files in your application. See below for examples.
|
||||
|
||||
5. Potential warning: css compressor function currently removes CSS comments. This might blow
|
||||
away some CSS hackery. To disable comment removal, comment out /lib/synthesis/asset_package.rb line 176.
|
||||
|
||||
== JavaScript Examples
|
||||
|
||||
Example call:
|
||||
<%= javascript_include_merged 'prototype', 'effects', 'controls', 'dragdrop', 'application', 'foo', 'bar' %>
|
||||
|
||||
In development, this generates:
|
||||
<script type="text/javascript" src="/javascripts/prototype.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/effects.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/controls.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/dragdrop.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/application.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/foo.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/bar.js"></script>
|
||||
|
||||
In production, this generates:
|
||||
<script type="text/javascript" src="/javascripts/base_1150571523.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/secondary_1150729166.js"></script>
|
||||
|
||||
Now supports symbols and :defaults as well:
|
||||
<%= javascript_include_merged :defaults %>
|
||||
<%= javascript_include_merged :foo, :bar %>
|
||||
|
||||
== Stylesheet Examples
|
||||
|
||||
Example call:
|
||||
<%= stylesheet_link_merged 'screen', 'header' %>
|
||||
|
||||
In development, this generates:
|
||||
<link href="/stylesheets/screen.css" media="screen" rel="Stylesheet" type="text/css" />
|
||||
<link href="/stylesheets/header.css" media="screen" rel="Stylesheet" type="text/css" />
|
||||
|
||||
In production this generates:
|
||||
<link href="/stylesheets/base_1150729166.css" media="screen" rel="Stylesheet" type="text/css" />
|
||||
|
||||
== Different CSS Media
|
||||
|
||||
All options for stylesheet_link_tag still work, so if you want to specify a different media type:
|
||||
<%= stylesheet_link_merged :secondary, 'media' => 'print' %>
|
||||
|
||||
== Running the tests
|
||||
|
||||
So you want to run the tests eh? Ok, then listen:
|
||||
|
||||
This plugin has a full suite of tests. But since they
|
||||
depend on rails, it has to be run in the context of a
|
||||
rails app, in the vendor/plugins directory. Observe:
|
||||
|
||||
> rails newtestapp
|
||||
> cd newtestapp
|
||||
> ./script/plugin install http://sbecker.net/shared/plugins/asset_packager
|
||||
> cd vendor/plugins/asset_packager/
|
||||
> rake # all tests pass
|
||||
|
||||
== License
|
||||
Copyright (c) 2006 Scott Becker - http://synthesis.sbecker.net
|
||||
Contact Email: becker.scott@gmail.com
|
||||
|
||||
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.
|
||||
22
vendor/plugins/asset_packager/Rakefile
vendored
22
vendor/plugins/asset_packager/Rakefile
vendored
|
|
@ -1,22 +0,0 @@
|
|||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the asset_packager plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the asset_packager plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'AssetPackager'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
8
vendor/plugins/asset_packager/about.yml
vendored
8
vendor/plugins/asset_packager/about.yml
vendored
|
|
@ -1,8 +0,0 @@
|
|||
author: Scott Becker
|
||||
name: AssetPackager
|
||||
summary: JavaScript and CSS Asset Compression for Production Rails Apps
|
||||
homepage: http://synthesis.sbecker.net/pages/asset_packager
|
||||
plugin: http://sbecker.net/shared/plugins/asset_packager
|
||||
license: MIT
|
||||
version: 0.2
|
||||
rails_version: 1.1.2+
|
||||
2
vendor/plugins/asset_packager/init.rb
vendored
2
vendor/plugins/asset_packager/init.rb
vendored
|
|
@ -1,2 +0,0 @@
|
|||
require 'synthesis/asset_package_helper'
|
||||
ActionView::Base.send :include, Synthesis::AssetPackageHelper
|
||||
1
vendor/plugins/asset_packager/install.rb
vendored
1
vendor/plugins/asset_packager/install.rb
vendored
|
|
@ -1 +0,0 @@
|
|||
# Install hook code here
|
||||
205
vendor/plugins/asset_packager/lib/jsmin.rb
vendored
205
vendor/plugins/asset_packager/lib/jsmin.rb
vendored
|
|
@ -1,205 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
# jsmin.rb 2007-07-20
|
||||
# Author: Uladzislau Latynski
|
||||
# This work is a translation from C to Ruby of jsmin.c published by
|
||||
# Douglas Crockford. Permission is hereby granted to use the Ruby
|
||||
# version under the same conditions as the jsmin.c on which it is
|
||||
# based.
|
||||
#
|
||||
# /* jsmin.c
|
||||
# 2003-04-21
|
||||
#
|
||||
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
#
|
||||
# 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 shall be used for Good, not Evil.
|
||||
#
|
||||
# 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.
|
||||
|
||||
EOF = -1
|
||||
$theA = ""
|
||||
$theB = ""
|
||||
|
||||
# isAlphanum -- return true if the character is a letter, digit, underscore,
|
||||
# dollar sign, or non-ASCII character
|
||||
def isAlphanum(c)
|
||||
return false if !c || c == EOF
|
||||
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
||||
c == '\\' || c[0] > 126)
|
||||
end
|
||||
|
||||
# get -- return the next character from stdin. Watch out for lookahead. If
|
||||
# the character is a control character, translate it to a space or linefeed.
|
||||
def get()
|
||||
c = $stdin.getc
|
||||
return EOF if(!c)
|
||||
c = c.chr
|
||||
return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
|
||||
return "\n" if (c == "\r")
|
||||
return " "
|
||||
end
|
||||
|
||||
# Get the next character without getting it.
|
||||
def peek()
|
||||
lookaheadChar = $stdin.getc
|
||||
$stdin.ungetc(lookaheadChar)
|
||||
return lookaheadChar.chr
|
||||
end
|
||||
|
||||
# mynext -- get the next character, excluding comments.
|
||||
# peek() is used to see if a '/' is followed by a '/' or '*'.
|
||||
def mynext()
|
||||
c = get
|
||||
if (c == "/")
|
||||
if(peek == "/")
|
||||
while(true)
|
||||
c = get
|
||||
if (c <= "\n")
|
||||
return c
|
||||
end
|
||||
end
|
||||
end
|
||||
if(peek == "*")
|
||||
get
|
||||
while(true)
|
||||
case get
|
||||
when "*"
|
||||
if (peek == "/")
|
||||
get
|
||||
return " "
|
||||
end
|
||||
when EOF
|
||||
raise "Unterminated comment"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
|
||||
# action -- do something! What you do is determined by the argument: 1
|
||||
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
||||
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
||||
# single character. Wow! action recognizes a regular expression if it is
|
||||
# preceded by ( or , or =.
|
||||
def action(a)
|
||||
if(a==1)
|
||||
$stdout.write $theA
|
||||
end
|
||||
if(a==1 || a==2)
|
||||
$theA = $theB
|
||||
if ($theA == "\'" || $theA == "\"")
|
||||
while (true)
|
||||
$stdout.write $theA
|
||||
$theA = get
|
||||
break if ($theA == $theB)
|
||||
raise "Unterminated string literal" if ($theA <= "\n")
|
||||
if ($theA == "\\")
|
||||
$stdout.write $theA
|
||||
$theA = get
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if(a==1 || a==2 || a==3)
|
||||
$theB = mynext
|
||||
if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
|
||||
$theA == ":" || $theA == "[" || $theA == "!" ||
|
||||
$theA == "&" || $theA == "|" || $theA == "?" ||
|
||||
$theA == "{" || $theA == "}" || $theA == ";" ||
|
||||
$theA == "\n"))
|
||||
$stdout.write $theA
|
||||
$stdout.write $theB
|
||||
while (true)
|
||||
$theA = get
|
||||
if ($theA == "/")
|
||||
break
|
||||
elsif ($theA == "\\")
|
||||
$stdout.write $theA
|
||||
$theA = get
|
||||
elsif ($theA <= "\n")
|
||||
raise "Unterminated RegExp Literal"
|
||||
end
|
||||
$stdout.write $theA
|
||||
end
|
||||
$theB = mynext
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# jsmin -- Copy the input to the output, deleting the characters which are
|
||||
# insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
# replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
# Most spaces and linefeeds will be removed.
|
||||
def jsmin
|
||||
$theA = "\n"
|
||||
action(3)
|
||||
while ($theA != EOF)
|
||||
case $theA
|
||||
when " "
|
||||
if (isAlphanum($theB))
|
||||
action(1)
|
||||
else
|
||||
action(2)
|
||||
end
|
||||
when "\n"
|
||||
case ($theB)
|
||||
when "{","[","(","+","-"
|
||||
action(1)
|
||||
when " "
|
||||
action(3)
|
||||
else
|
||||
if (isAlphanum($theB))
|
||||
action(1)
|
||||
else
|
||||
action(2)
|
||||
end
|
||||
end
|
||||
else
|
||||
case ($theB)
|
||||
when " "
|
||||
if (isAlphanum($theA))
|
||||
action(1)
|
||||
else
|
||||
action(3)
|
||||
end
|
||||
when "\n"
|
||||
case ($theA)
|
||||
when "}","]",")","+","-","\"","\\", "'", '"'
|
||||
action(1)
|
||||
else
|
||||
if (isAlphanum($theA))
|
||||
action(1)
|
||||
else
|
||||
action(3)
|
||||
end
|
||||
end
|
||||
else
|
||||
action(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ARGV.each do |anArg|
|
||||
$stdout.write "// #{anArg}\n"
|
||||
end
|
||||
|
||||
jsmin
|
||||
|
|
@ -1,233 +0,0 @@
|
|||
require 'yaml'
|
||||
|
||||
module Synthesis
|
||||
class AssetPackage
|
||||
|
||||
# class variables
|
||||
@@asset_packages_yml = $asset_packages_yml ||
|
||||
(File.exists?("#{RAILS_ROOT}/config/asset_packages.yml") ? YAML.load_file("#{RAILS_ROOT}/config/asset_packages.yml") : nil)
|
||||
|
||||
# singleton methods
|
||||
class << self
|
||||
|
||||
def merge_environments=(environments)
|
||||
@@merge_environments = environments
|
||||
end
|
||||
|
||||
def merge_environments
|
||||
@@merge_environments ||= ["production"]
|
||||
end
|
||||
|
||||
def parse_path(path)
|
||||
/^(?:(.*)\/)?([^\/]+)$/.match(path).to_a
|
||||
end
|
||||
|
||||
def find_by_type(asset_type)
|
||||
@@asset_packages_yml[asset_type].map { |p| self.new(asset_type, p) }
|
||||
end
|
||||
|
||||
def find_by_target(asset_type, target)
|
||||
package_hash = @@asset_packages_yml[asset_type].find {|p| p.keys.first == target }
|
||||
package_hash ? self.new(asset_type, package_hash) : nil
|
||||
end
|
||||
|
||||
def find_by_source(asset_type, source)
|
||||
path_parts = parse_path(source)
|
||||
package_hash = @@asset_packages_yml[asset_type].find do |p|
|
||||
key = p.keys.first
|
||||
p[key].include?(path_parts[2]) && (parse_path(key)[1] == path_parts[1])
|
||||
end
|
||||
package_hash ? self.new(asset_type, package_hash) : nil
|
||||
end
|
||||
|
||||
def targets_from_sources(asset_type, sources)
|
||||
package_names = Array.new
|
||||
sources.each do |source|
|
||||
package = find_by_target(asset_type, source) || find_by_source(asset_type, source)
|
||||
package_names << (package ? package.current_file : source)
|
||||
end
|
||||
package_names.uniq
|
||||
end
|
||||
|
||||
def sources_from_targets(asset_type, targets)
|
||||
source_names = Array.new
|
||||
targets.each do |target|
|
||||
package = find_by_target(asset_type, target)
|
||||
source_names += (package ? package.sources.collect do |src|
|
||||
package.target_dir.gsub(/^(.+)$/, '\1/') + src
|
||||
end : target.to_a)
|
||||
end
|
||||
source_names.uniq
|
||||
end
|
||||
|
||||
def build_all
|
||||
@@asset_packages_yml.keys.each do |asset_type|
|
||||
@@asset_packages_yml[asset_type].each { |p| self.new(asset_type, p).build }
|
||||
end
|
||||
end
|
||||
|
||||
def delete_all
|
||||
@@asset_packages_yml.keys.each do |asset_type|
|
||||
@@asset_packages_yml[asset_type].each { |p| self.new(asset_type, p).delete_all_builds }
|
||||
end
|
||||
end
|
||||
|
||||
def create_yml
|
||||
unless File.exists?("#{RAILS_ROOT}/config/asset_packages.yml")
|
||||
asset_yml = Hash.new
|
||||
|
||||
asset_yml['javascripts'] = [{"base" => build_file_list("#{RAILS_ROOT}/public/javascripts", "js")}]
|
||||
asset_yml['stylesheets'] = [{"base" => build_file_list("#{RAILS_ROOT}/public/stylesheets", "css")}]
|
||||
|
||||
File.open("#{RAILS_ROOT}/config/asset_packages.yml", "w") do |out|
|
||||
YAML.dump(asset_yml, out)
|
||||
end
|
||||
|
||||
log "config/asset_packages.yml example file created!"
|
||||
log "Please reorder files under 'base' so dependencies are loaded in correct order."
|
||||
else
|
||||
log "config/asset_packages.yml already exists. Aborting task..."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# instance methods
|
||||
attr_accessor :asset_type, :target, :target_dir, :sources
|
||||
|
||||
def initialize(asset_type, package_hash)
|
||||
target_parts = self.class.parse_path(package_hash.keys.first)
|
||||
@target_dir = target_parts[1].to_s
|
||||
@target = target_parts[2].to_s
|
||||
@sources = package_hash[package_hash.keys.first]
|
||||
@asset_type = asset_type
|
||||
@asset_path = ($asset_base_path ? "#{$asset_base_path}/" : "#{RAILS_ROOT}/public/") +
|
||||
"#{@asset_type}#{@target_dir.gsub(/^(.+)$/, '/\1')}"
|
||||
@extension = get_extension
|
||||
@match_regex = Regexp.new("\\A#{@target}_\\d+.#{@extension}\\z")
|
||||
end
|
||||
|
||||
def current_file
|
||||
@target_dir.gsub(/^(.+)$/, '\1/') +
|
||||
Dir.new(@asset_path).entries.delete_if { |x| ! (x =~ @match_regex) }.sort.reverse[0].chomp(".#{@extension}")
|
||||
end
|
||||
|
||||
def build
|
||||
delete_old_builds
|
||||
create_new_build
|
||||
end
|
||||
|
||||
def delete_old_builds
|
||||
Dir.new(@asset_path).entries.delete_if { |x| ! (x =~ @match_regex) }.each do |x|
|
||||
File.delete("#{@asset_path}/#{x}") unless x.index(revision.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_all_builds
|
||||
Dir.new(@asset_path).entries.delete_if { |x| ! (x =~ @match_regex) }.each do |x|
|
||||
File.delete("#{@asset_path}/#{x}")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def revision
|
||||
unless @revision
|
||||
revisions = [1]
|
||||
@sources.each do |source|
|
||||
revisions << get_file_revision("#{@asset_path}/#{source}.#{@extension}")
|
||||
end
|
||||
@revision = revisions.max
|
||||
end
|
||||
@revision
|
||||
end
|
||||
|
||||
def get_file_revision(path)
|
||||
if File.exists?(path)
|
||||
begin
|
||||
`svn info #{path}`[/Last Changed Rev: (.*?)\n/][/(\d+)/].to_i
|
||||
rescue # use filename timestamp if not in subversion
|
||||
File.mtime(path).to_i
|
||||
end
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def create_new_build
|
||||
if File.exists?("#{@asset_path}/#{@target}_#{revision}.#{@extension}")
|
||||
log "Latest version already exists: #{@asset_path}/#{@target}_#{revision}.#{@extension}"
|
||||
else
|
||||
File.open("#{@asset_path}/#{@target}_#{revision}.#{@extension}", "w") {|f| f.write(compressed_file) }
|
||||
log "Created #{@asset_path}/#{@target}_#{revision}.#{@extension}"
|
||||
end
|
||||
end
|
||||
|
||||
def merged_file
|
||||
merged_file = ""
|
||||
@sources.each {|s|
|
||||
File.open("#{@asset_path}/#{s}.#{@extension}", "r") { |f|
|
||||
merged_file += f.read + "\n"
|
||||
}
|
||||
}
|
||||
merged_file
|
||||
end
|
||||
|
||||
def compressed_file
|
||||
case @asset_type
|
||||
when "javascripts" then compress_js(merged_file)
|
||||
when "stylesheets" then compress_css(merged_file)
|
||||
end
|
||||
end
|
||||
|
||||
def compress_js(source)
|
||||
jsmin_path = "#{RAILS_ROOT}/vendor/plugins/asset_packager/lib"
|
||||
tmp_path = "#{RAILS_ROOT}/tmp/#{@target}_#{revision}"
|
||||
|
||||
# write out to a temp file
|
||||
File.open("#{tmp_path}_uncompressed.js", "w") {|f| f.write(source) }
|
||||
|
||||
# compress file with JSMin library
|
||||
`ruby #{jsmin_path}/jsmin.rb <#{tmp_path}_uncompressed.js >#{tmp_path}_compressed.js \n`
|
||||
|
||||
# read it back in and trim it
|
||||
result = ""
|
||||
File.open("#{tmp_path}_compressed.js", "r") { |f| result += f.read.strip }
|
||||
|
||||
# delete temp files if they exist
|
||||
File.delete("#{tmp_path}_uncompressed.js") if File.exists?("#{tmp_path}_uncompressed.js")
|
||||
File.delete("#{tmp_path}_compressed.js") if File.exists?("#{tmp_path}_compressed.js")
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def compress_css(source)
|
||||
source.gsub!(/\s+/, " ") # collapse space
|
||||
source.gsub!(/\/\*(.*?)\*\/ /, "") # remove comments - caution, might want to remove this if using css hacks
|
||||
source.gsub!(/\} /, "}\n") # add line breaks
|
||||
source.gsub!(/\n$/, "") # remove last break
|
||||
source.gsub!(/ \{ /, " {") # trim inside brackets
|
||||
source.gsub!(/; \}/, "}") # trim inside brackets
|
||||
source
|
||||
end
|
||||
|
||||
def get_extension
|
||||
case @asset_type
|
||||
when "javascripts" then "js"
|
||||
when "stylesheets" then "css"
|
||||
end
|
||||
end
|
||||
|
||||
def log(message)
|
||||
puts message
|
||||
end
|
||||
|
||||
def self.build_file_list(path, extension)
|
||||
re = Regexp.new(".#{extension}\\z")
|
||||
file_list = Dir.new(path).entries.delete_if { |x| ! (x =~ re) }.map {|x| x.chomp(".#{extension}")}
|
||||
# reverse javascript entries so prototype comes first on a base rails app
|
||||
file_list.reverse! if extension == "js"
|
||||
file_list
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue