From d25fc9ad8dbceb66fcf5f0c24184ca94c0406bdf Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:52:46 +0100 Subject: [PATCH 01/84] Actively load active record --- stoptime.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/stoptime.rb b/stoptime.rb index d82f63a..dec6e67 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -12,6 +12,7 @@ require "action_view" require "active_support" require "camping" +require "camping/ar" require "markaby" require "pathname" require "sass/plugin/rack" From ed864e746aa7530f60af67cd38b7043044f47122 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:24 +0100 Subject: [PATCH 02/84] Fix up some hacks that generate errors when used with Mab --- stoptime.rb | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index dec6e67..929d7fc 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -78,20 +78,28 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -class StopTime::Mab +module StopTime::Mab SUPPORTED = [:get, :post] - # Adds a method override field in form tags for (usually) unsupported - # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. - def tag!(tag, *attrs) - return super unless tag == :form && block_given? - attrs = attrs.last.is_a?(Hash) ? attrs.last : {} - meth = attrs[:method] - attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) - super(tag, attrs) do - input :type => 'hidden', :name => '_method', :value => meth if override - yield - end + # # Adds a method override field in form tags for (usually) unsupported + # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. + # def tag!(tag, *attrs) + # return super unless tag == :form && block_given? + # attrs = attrs.last.is_a?(Hash) ? attrs.last : {} + # meth = attrs[:method] + # attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) + # super(tag, attrs) do + # input :type => 'hidden', :name => '_method', :value => meth if override + # yield + # end + # end + + def tag!(name, *args) + Kernel.p [name, args] + content = args.shift unless args.first.is_a?(Hash) + attrs = args.inject { |a,b| a.merge(b) } + Kernel.p [name, content, args] + super(name, content, attrs) end end From d3083e6fc5e19d8eae24f55d1f0658f5d83d4a1e Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:43 +0100 Subject: [PATCH 03/84] More Mab compability: different doctype and text escaping --- stoptime.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 929d7fc..981f34e 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1349,7 +1349,8 @@ module StopTime::Views # The main layout used by all views. def layout - xhtml_strict do + doctype! + html do head do title "Stop… Camping Time!" # FIXME: improve static serving so that the hack below is not needed. @@ -1383,8 +1384,8 @@ module StopTime::Views h3 { a customer.name, :href => R(CustomersN, customer.id) } if @tasks[customer].empty? p do - text "No projects/tasks found! Create one " + - "#{a "here", :href => R(CustomersNTasksNew, customer.id)}." + text! "No projects/tasks found! Create one " + + "#{a "here", :href => R(CustomersNTasksNew, customer.id)}." end else table.overview do @@ -1543,7 +1544,7 @@ module StopTime::Views h2 "Customers" if @customers.empty? p do - text "None found! You can create one " + + text! "None found! You can create one " + "#{a "here", :href => R(CustomersNew)}." end else @@ -1705,8 +1706,8 @@ module StopTime::Views if @invoices.values.flatten.empty? p do - text "Found none! You can create one by " - "#{a "selecting a customer", :href => R(Customers)}." + text! "Found none! You can create one by " + "#{a "selecting a customer", :href => R(Customers)}." end else @invoices.keys.sort.each do |key| @@ -1994,7 +1995,7 @@ module StopTime::Views # menu item. def _menu_link(label, ctrl) # FIXME: dirty hack? - if self.helpers.class.to_s.match(/^#{ctrl.to_s}/) + if self.class.to_s.match(/^#{ctrl.to_s}/) li.selected { a label, :href => R(ctrl) } else li { a label, :href => R(ctrl) } From d40a4db28ed58cdf0f536e99cb27ade09514bebe Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:15 +0100 Subject: [PATCH 04/84] Actually load Mab instead of Markaby --- stoptime.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 981f34e..9dad845 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -12,12 +12,10 @@ require "action_view" require "active_support" require "camping" -require "camping/ar" -require "markaby" +require "camping/mab" require "pathname" require "sass/plugin/rack" -Markaby::Builder.set(:indent, 2) Camping.goes :StopTime unless defined? PUBLIC_DIR From b690f52d64336f0130f40c0346a73e3394c89f1c Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:37 +0100 Subject: [PATCH 05/84] Leave the form method override stuff for now --- stoptime.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 9dad845..3d7c5a9 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -76,8 +76,9 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -module StopTime::Mab - SUPPORTED = [:get, :post] +# FIXME: update for Mab! +module StopTime::Helpers + #SUPPORTED = [:get, :post] # # Adds a method override field in form tags for (usually) unsupported # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. @@ -92,14 +93,6 @@ module StopTime::Mab # end # end - def tag!(name, *args) - Kernel.p [name, args] - content = args.shift unless args.first.is_a?(Hash) - attrs = args.inject { |a,b| a.merge(b) } - Kernel.p [name, content, args] - super(name, content, attrs) - end - end # = The Stop… Camping Time! models From 30440288d9544959a9d8631c9f7f716adbc57fa4 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:56 +0100 Subject: [PATCH 06/84] Updated views to use the instance vars and no longer rely on Markaby's method_missing --- stoptime.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 3d7c5a9..2d17e9c 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1407,7 +1407,7 @@ module StopTime::Views # FIXME: This should be done in a nicer way. def time_entries(task_id=nil) if task_id.present? - h2 "Registered #{task.billed? ? "billed" : "unbilled"} time" + h2 "Registered #{@task.billed? ? "billed" : "unbilled"} time" else h2 "Timeline" end @@ -1497,7 +1497,7 @@ module StopTime::Views "what you are doing!" end end - form :action => R(*target), :method => :post do + form :action => R(*@target), :method => :post do ol do li do label "Customer", :for => "customer" @@ -1651,7 +1651,7 @@ module StopTime::Views p.warn do em "This task is already billed! Only make changes if you know " + "what you are doing!" - end if task.billed? + end if @task.billed? form :action => R(*@target), :method => :post do ol do li do @@ -1673,7 +1673,7 @@ module StopTime::Views end end end - if task.billed? + if @task.billed? li do label "Billed in invoice" a @task.invoice.number, @@ -1760,7 +1760,7 @@ module StopTime::Views tr do td do a task.comment_or_name, - :href => R(CustomersNTasksN, customer.id, task.id) + :href => R(CustomersNTasksN, task.customer.id, task.id) end if line[1].blank? # FIXME: information of time spent is available in the summary From d4ee3a65843f142dd6edca085a91d2f26bcfefef Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:57:51 +0100 Subject: [PATCH 07/84] Port the Markaby method override support to Mab --- stoptime.rb | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 2d17e9c..5a7ddda 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -77,21 +77,24 @@ end # = The Stop… Camping Time! Markaby extensions # FIXME: update for Mab! -module StopTime::Helpers - #SUPPORTED = [:get, :post] +module StopTime::Mab + SUPPORTED = [:get, :post] - # # Adds a method override field in form tags for (usually) unsupported - # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. - # def tag!(tag, *attrs) - # return super unless tag == :form && block_given? - # attrs = attrs.last.is_a?(Hash) ? attrs.last : {} - # meth = attrs[:method] - # attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) - # super(tag, attrs) do - # input :type => 'hidden', :name => '_method', :value => meth if override - # yield - # end - # end + def mab_done(tag) + return super unless tag.name == :form + + meth = tag.attributes[:method] + tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) + # Inject a hidden input element with the proper method to the tag block + # if the form method is unsupported. + orig_blk = tag.block + tag.block = proc do + input :type => 'hidden', :name => '_method', :value => meth + orig_blk.call + end if override + end + + include Mab::Indentation end From 54da1353e654ca9e981c235156baf97138d9183a Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:58:04 +0100 Subject: [PATCH 08/84] Remove the double doctype, fix indentation --- stoptime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 5a7ddda..4a3ec51 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1343,7 +1343,6 @@ module StopTime::Views # The main layout used by all views. def layout - doctype! html do head do title "Stop… Camping Time!" @@ -1539,7 +1538,7 @@ module StopTime::Views if @customers.empty? p do text! "None found! You can create one " + - "#{a "here", :href => R(CustomersNew)}." + "#{a "here", :href => R(CustomersNew)}." end else table.customers do From e29a95466308010fb6bd08c8c95fa2d21f7dffe8 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 15:02:59 +0100 Subject: [PATCH 09/84] Bumped dependency versions in the README --- README | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 98efcfd..72effe8 100644 --- a/README +++ b/README @@ -18,11 +18,11 @@ invoicing. Stop… Camping Time! is a Camping application, so you need: -* Ruby 1.8 (>= 1.8.6) or 1.9 (>= 1.9.1) -* Camping (>= 2.0) with +* Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) +* Camping (>= 2.2) with * Active Record (>= 2.3) - * Markaby, and optionally: - * Mongrel (for testing and deployment without Apache/Rackup) + * Markaby (>= 0.1.0) , and optionally: + * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: From a064cd952c63c1e80a8374c756ce068dbefb160f Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Tue, 31 Jan 2012 22:34:26 +0100 Subject: [PATCH 10/84] Small cleanup for the block override that works with recent Mab --- stoptime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 4a3ec51..3b63bd9 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -87,8 +87,7 @@ module StopTime::Mab tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) # Inject a hidden input element with the proper method to the tag block # if the form method is unsupported. - orig_blk = tag.block - tag.block = proc do + tag.block do |orig_blk| input :type => 'hidden', :name => '_method', :value => meth orig_blk.call end if override From 3f594d49d078d7dc45a0f67f10b21694262f39c8 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:52:46 +0100 Subject: [PATCH 11/84] Actively load active record --- stoptime.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/stoptime.rb b/stoptime.rb index d90923e..a67f41e 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -12,6 +12,7 @@ require "action_view" require "active_support" require "camping" +require "camping/ar" require "markaby" require "pathname" require "sass/plugin/rack" From 0e2c9ee02e4b40e7d57857adc5429adae0f1f012 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:24 +0100 Subject: [PATCH 12/84] Fix up some hacks that generate errors when used with Mab --- stoptime.rb | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index a67f41e..709f870 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -78,20 +78,28 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -module StopTime::Helpers +module StopTime::Mab SUPPORTED = [:get, :post] - # Adds a method override field in form tags for (usually) unsupported - # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. - def tag!(tag, *attrs) - return super unless tag == :form && block_given? - attrs = attrs.last.is_a?(Hash) ? attrs.last : {} - meth = attrs[:method] - attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) - super(tag, attrs) do - input :type => 'hidden', :name => '_method', :value => meth if override - yield - end + # # Adds a method override field in form tags for (usually) unsupported + # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. + # def tag!(tag, *attrs) + # return super unless tag == :form && block_given? + # attrs = attrs.last.is_a?(Hash) ? attrs.last : {} + # meth = attrs[:method] + # attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) + # super(tag, attrs) do + # input :type => 'hidden', :name => '_method', :value => meth if override + # yield + # end + # end + + def tag!(name, *args) + Kernel.p [name, args] + content = args.shift unless args.first.is_a?(Hash) + attrs = args.inject { |a,b| a.merge(b) } + Kernel.p [name, content, args] + super(name, content, attrs) end end From 395271f0b1f97f79de1b27489665ac021d3bac77 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:43 +0100 Subject: [PATCH 13/84] More Mab compability: different doctype and text escaping --- stoptime.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 709f870..2b9a233 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1352,7 +1352,8 @@ module StopTime::Views # The main layout used by all views. def layout - xhtml_strict do + doctype! + html do head do title "Stop… Camping Time!" # FIXME: improve static serving so that the hack below is not needed. @@ -1386,8 +1387,8 @@ module StopTime::Views h3 { a customer.name, :href => R(CustomersN, customer.id) } if @tasks[customer].empty? p do - text "No projects/tasks found! Create one " + - "#{a "here", :href => R(CustomersNTasksNew, customer.id)}." + text! "No projects/tasks found! Create one " + + "#{a "here", :href => R(CustomersNTasksNew, customer.id)}." end else table.overview do @@ -1546,7 +1547,7 @@ module StopTime::Views h2 "Customers" if @customers.empty? p do - text "None found! You can create one " + + text! "None found! You can create one " + "#{a "here", :href => R(CustomersNew)}." end else @@ -1707,8 +1708,8 @@ module StopTime::Views if @invoices.values.flatten.empty? p do - text "Found none! You can create one by " - "#{a "selecting a customer", :href => R(Customers)}." + text! "Found none! You can create one by " + "#{a "selecting a customer", :href => R(Customers)}." end else @invoices.keys.sort.each do |key| @@ -1996,7 +1997,7 @@ module StopTime::Views # menu item. def _menu_link(label, ctrl) # FIXME: dirty hack? - if self.helpers.class.to_s.match(/^#{ctrl.to_s}/) + if self.class.to_s.match(/^#{ctrl.to_s}/) li.selected { a label, :href => R(ctrl) } else li { a label, :href => R(ctrl) } From 0e810f5b50908fe14a4f602fde414be50748c928 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:15 +0100 Subject: [PATCH 14/84] Actually load Mab instead of Markaby --- stoptime.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 2b9a233..6543339 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -12,12 +12,10 @@ require "action_view" require "active_support" require "camping" -require "camping/ar" -require "markaby" +require "camping/mab" require "pathname" require "sass/plugin/rack" -Markaby::Builder.set(:indent, 2) Camping.goes :StopTime unless defined? PUBLIC_DIR From 96197af487b20a36d3c3aae049ba4abe944e61bc Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:37 +0100 Subject: [PATCH 15/84] Leave the form method override stuff for now --- stoptime.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 6543339..21ede29 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -76,8 +76,9 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -module StopTime::Mab - SUPPORTED = [:get, :post] +# FIXME: update for Mab! +module StopTime::Helpers + #SUPPORTED = [:get, :post] # # Adds a method override field in form tags for (usually) unsupported # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. @@ -92,14 +93,6 @@ module StopTime::Mab # end # end - def tag!(name, *args) - Kernel.p [name, args] - content = args.shift unless args.first.is_a?(Hash) - attrs = args.inject { |a,b| a.merge(b) } - Kernel.p [name, content, args] - super(name, content, attrs) - end - end # = The Stop… Camping Time! models From e100fec8e3f765b4443cc7db37a1488a5811ea6b Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:56 +0100 Subject: [PATCH 16/84] Updated views to use the instance vars and no longer rely on Markaby's method_missing --- stoptime.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 21ede29..4eac2b2 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1410,7 +1410,7 @@ module StopTime::Views # FIXME: This should be done in a nicer way. def time_entries(task_id=nil) if task_id.present? - h2 "Registered #{task.billed? ? "billed" : "unbilled"} time" + h2 "Registered #{@task.billed? ? "billed" : "unbilled"} time" else h2 "Timeline" end @@ -1500,7 +1500,7 @@ module StopTime::Views "what you are doing!" end end - form :action => R(*target), :method => :post do + form :action => R(*@target), :method => :post do ol do li do label "Customer", :for => "customer" @@ -1653,7 +1653,7 @@ module StopTime::Views p.warn do em "This task is already billed! Only make changes if you know " + "what you are doing!" - end if task.billed? + end if @task.billed? form :action => R(*@target), :method => :post do ol do li do @@ -1675,7 +1675,7 @@ module StopTime::Views end end end - if task.billed? + if @task.billed? li do label "Billed in invoice" a @task.invoice.number, @@ -1762,7 +1762,7 @@ module StopTime::Views tr do td do a task.comment_or_name, - :href => R(CustomersNTasksN, customer.id, task.id) + :href => R(CustomersNTasksN, task.customer.id, task.id) end if line[1].blank? # FIXME: information of time spent is available in the summary From 474b2a22d93e45c48f0bfbcbb223846fb94a4878 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:57:51 +0100 Subject: [PATCH 17/84] Port the Markaby method override support to Mab --- stoptime.rb | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 4eac2b2..e3a0708 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -77,21 +77,24 @@ end # = The Stop… Camping Time! Markaby extensions # FIXME: update for Mab! -module StopTime::Helpers - #SUPPORTED = [:get, :post] +module StopTime::Mab + SUPPORTED = [:get, :post] - # # Adds a method override field in form tags for (usually) unsupported - # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. - # def tag!(tag, *attrs) - # return super unless tag == :form && block_given? - # attrs = attrs.last.is_a?(Hash) ? attrs.last : {} - # meth = attrs[:method] - # attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) - # super(tag, attrs) do - # input :type => 'hidden', :name => '_method', :value => meth if override - # yield - # end - # end + def mab_done(tag) + return super unless tag.name == :form + + meth = tag.attributes[:method] + tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) + # Inject a hidden input element with the proper method to the tag block + # if the form method is unsupported. + orig_blk = tag.block + tag.block = proc do + input :type => 'hidden', :name => '_method', :value => meth + orig_blk.call + end if override + end + + include Mab::Indentation end From df07a61803dd94933968349b06801232619cb872 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:58:04 +0100 Subject: [PATCH 18/84] Remove the double doctype, fix indentation --- stoptime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index e3a0708..273868f 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1346,7 +1346,6 @@ module StopTime::Views # The main layout used by all views. def layout - doctype! html do head do title "Stop… Camping Time!" @@ -1542,7 +1541,7 @@ module StopTime::Views if @customers.empty? p do text! "None found! You can create one " + - "#{a "here", :href => R(CustomersNew)}." + "#{a "here", :href => R(CustomersNew)}." end else table.customers do From d81480a2d030dae145cbf2d6d747b7ba6179a669 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 15:02:59 +0100 Subject: [PATCH 19/84] Bumped dependency versions in the README --- README | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 98efcfd..72effe8 100644 --- a/README +++ b/README @@ -18,11 +18,11 @@ invoicing. Stop… Camping Time! is a Camping application, so you need: -* Ruby 1.8 (>= 1.8.6) or 1.9 (>= 1.9.1) -* Camping (>= 2.0) with +* Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) +* Camping (>= 2.2) with * Active Record (>= 2.3) - * Markaby, and optionally: - * Mongrel (for testing and deployment without Apache/Rackup) + * Markaby (>= 0.1.0) , and optionally: + * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: From 9173b7485090d784c14eec4cb86d46332f1ad124 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Tue, 31 Jan 2012 22:34:26 +0100 Subject: [PATCH 20/84] Small cleanup for the block override that works with recent Mab --- stoptime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 273868f..991e27f 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -87,8 +87,7 @@ module StopTime::Mab tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) # Inject a hidden input element with the proper method to the tag block # if the form method is unsupported. - orig_blk = tag.block - tag.block = proc do + tag.block do |orig_blk| input :type => 'hidden', :name => '_method', :value => meth orig_blk.call end if override From bc99fdad4d2000726f054e37bb48dbd0fabc5900 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 21 May 2012 17:11:06 +0200 Subject: [PATCH 21/84] Small Mab compatibility fix --- stoptime.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 991e27f..9c4b905 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1563,10 +1563,10 @@ module StopTime::Views td { customer.short_name || "–"} td do if customer.address_street.present? - text customer.address_street + text! customer.address_street br - text customer.address_postal_code + " " + - customer.address_city + text! customer.address_postal_code + " " + + customer.address_city else "–" end From 544036f93a77b13dd92f2de70963ed7ed348c7b6 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 21 May 2012 17:11:29 +0200 Subject: [PATCH 22/84] Replaced the dependency on Markaby by Mab --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 72effe8..f71727a 100644 --- a/README +++ b/README @@ -21,7 +21,7 @@ Stop… Camping Time! is a Camping application, so you need: * Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) * Camping (>= 2.2) with * Active Record (>= 2.3) - * Markaby (>= 0.1.0) , and optionally: + * Mab (>= 0.0.1) , and optionally: * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: From 419d08a6eb6360e2247d5ecd5d208f869b4bfe17 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:52:46 +0100 Subject: [PATCH 23/84] Actively load active record --- stoptime.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/stoptime.rb b/stoptime.rb index d90923e..a67f41e 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -12,6 +12,7 @@ require "action_view" require "active_support" require "camping" +require "camping/ar" require "markaby" require "pathname" require "sass/plugin/rack" From 3a824c2026941a5fafc59eadfe1b718fbea179b9 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:24 +0100 Subject: [PATCH 24/84] Fix up some hacks that generate errors when used with Mab --- stoptime.rb | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index a67f41e..709f870 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -78,20 +78,28 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -module StopTime::Helpers +module StopTime::Mab SUPPORTED = [:get, :post] - # Adds a method override field in form tags for (usually) unsupported - # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. - def tag!(tag, *attrs) - return super unless tag == :form && block_given? - attrs = attrs.last.is_a?(Hash) ? attrs.last : {} - meth = attrs[:method] - attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) - super(tag, attrs) do - input :type => 'hidden', :name => '_method', :value => meth if override - yield - end + # # Adds a method override field in form tags for (usually) unsupported + # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. + # def tag!(tag, *attrs) + # return super unless tag == :form && block_given? + # attrs = attrs.last.is_a?(Hash) ? attrs.last : {} + # meth = attrs[:method] + # attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) + # super(tag, attrs) do + # input :type => 'hidden', :name => '_method', :value => meth if override + # yield + # end + # end + + def tag!(name, *args) + Kernel.p [name, args] + content = args.shift unless args.first.is_a?(Hash) + attrs = args.inject { |a,b| a.merge(b) } + Kernel.p [name, content, args] + super(name, content, attrs) end end From d3129a11c1dc2b5bce905f92a880c7ebb3b942ba Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:43 +0100 Subject: [PATCH 25/84] More Mab compability: different doctype and text escaping --- stoptime.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 709f870..2b9a233 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1352,7 +1352,8 @@ module StopTime::Views # The main layout used by all views. def layout - xhtml_strict do + doctype! + html do head do title "Stop… Camping Time!" # FIXME: improve static serving so that the hack below is not needed. @@ -1386,8 +1387,8 @@ module StopTime::Views h3 { a customer.name, :href => R(CustomersN, customer.id) } if @tasks[customer].empty? p do - text "No projects/tasks found! Create one " + - "#{a "here", :href => R(CustomersNTasksNew, customer.id)}." + text! "No projects/tasks found! Create one " + + "#{a "here", :href => R(CustomersNTasksNew, customer.id)}." end else table.overview do @@ -1546,7 +1547,7 @@ module StopTime::Views h2 "Customers" if @customers.empty? p do - text "None found! You can create one " + + text! "None found! You can create one " + "#{a "here", :href => R(CustomersNew)}." end else @@ -1707,8 +1708,8 @@ module StopTime::Views if @invoices.values.flatten.empty? p do - text "Found none! You can create one by " - "#{a "selecting a customer", :href => R(Customers)}." + text! "Found none! You can create one by " + "#{a "selecting a customer", :href => R(Customers)}." end else @invoices.keys.sort.each do |key| @@ -1996,7 +1997,7 @@ module StopTime::Views # menu item. def _menu_link(label, ctrl) # FIXME: dirty hack? - if self.helpers.class.to_s.match(/^#{ctrl.to_s}/) + if self.class.to_s.match(/^#{ctrl.to_s}/) li.selected { a label, :href => R(ctrl) } else li { a label, :href => R(ctrl) } From d41b70f0d835e8edecf8689419183522cdc39467 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:15 +0100 Subject: [PATCH 26/84] Actually load Mab instead of Markaby --- stoptime.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 2b9a233..6543339 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -12,12 +12,10 @@ require "action_view" require "active_support" require "camping" -require "camping/ar" -require "markaby" +require "camping/mab" require "pathname" require "sass/plugin/rack" -Markaby::Builder.set(:indent, 2) Camping.goes :StopTime unless defined? PUBLIC_DIR From 51f0bdfa9c4acb1342f1e03f1f5b1cc2369c97f4 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:37 +0100 Subject: [PATCH 27/84] Leave the form method override stuff for now --- stoptime.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 6543339..21ede29 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -76,8 +76,9 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -module StopTime::Mab - SUPPORTED = [:get, :post] +# FIXME: update for Mab! +module StopTime::Helpers + #SUPPORTED = [:get, :post] # # Adds a method override field in form tags for (usually) unsupported # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. @@ -92,14 +93,6 @@ module StopTime::Mab # end # end - def tag!(name, *args) - Kernel.p [name, args] - content = args.shift unless args.first.is_a?(Hash) - attrs = args.inject { |a,b| a.merge(b) } - Kernel.p [name, content, args] - super(name, content, attrs) - end - end # = The Stop… Camping Time! models From 3c620040560ee02708f02b664cd14bf9ad96683b Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:56 +0100 Subject: [PATCH 28/84] Updated views to use the instance vars and no longer rely on Markaby's method_missing --- stoptime.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 21ede29..4eac2b2 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1410,7 +1410,7 @@ module StopTime::Views # FIXME: This should be done in a nicer way. def time_entries(task_id=nil) if task_id.present? - h2 "Registered #{task.billed? ? "billed" : "unbilled"} time" + h2 "Registered #{@task.billed? ? "billed" : "unbilled"} time" else h2 "Timeline" end @@ -1500,7 +1500,7 @@ module StopTime::Views "what you are doing!" end end - form :action => R(*target), :method => :post do + form :action => R(*@target), :method => :post do ol do li do label "Customer", :for => "customer" @@ -1653,7 +1653,7 @@ module StopTime::Views p.warn do em "This task is already billed! Only make changes if you know " + "what you are doing!" - end if task.billed? + end if @task.billed? form :action => R(*@target), :method => :post do ol do li do @@ -1675,7 +1675,7 @@ module StopTime::Views end end end - if task.billed? + if @task.billed? li do label "Billed in invoice" a @task.invoice.number, @@ -1762,7 +1762,7 @@ module StopTime::Views tr do td do a task.comment_or_name, - :href => R(CustomersNTasksN, customer.id, task.id) + :href => R(CustomersNTasksN, task.customer.id, task.id) end if line[1].blank? # FIXME: information of time spent is available in the summary From f1b5f5168b8a6b5b39752e704c344fd91d86b846 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:57:51 +0100 Subject: [PATCH 29/84] Port the Markaby method override support to Mab --- stoptime.rb | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 4eac2b2..e3a0708 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -77,21 +77,24 @@ end # = The Stop… Camping Time! Markaby extensions # FIXME: update for Mab! -module StopTime::Helpers - #SUPPORTED = [:get, :post] +module StopTime::Mab + SUPPORTED = [:get, :post] - # # Adds a method override field in form tags for (usually) unsupported - # # methods by browsers (i.e. PUT and DELETE) by injecting a hidden field. - # def tag!(tag, *attrs) - # return super unless tag == :form && block_given? - # attrs = attrs.last.is_a?(Hash) ? attrs.last : {} - # meth = attrs[:method] - # attrs[:method] = 'post' if override = !SUPPORTED.include?(meth) - # super(tag, attrs) do - # input :type => 'hidden', :name => '_method', :value => meth if override - # yield - # end - # end + def mab_done(tag) + return super unless tag.name == :form + + meth = tag.attributes[:method] + tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) + # Inject a hidden input element with the proper method to the tag block + # if the form method is unsupported. + orig_blk = tag.block + tag.block = proc do + input :type => 'hidden', :name => '_method', :value => meth + orig_blk.call + end if override + end + + include Mab::Indentation end From 29ad270f0fd2564b16bf18179171a6ff5815230c Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:58:04 +0100 Subject: [PATCH 30/84] Remove the double doctype, fix indentation --- stoptime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index e3a0708..273868f 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1346,7 +1346,6 @@ module StopTime::Views # The main layout used by all views. def layout - doctype! html do head do title "Stop… Camping Time!" @@ -1542,7 +1541,7 @@ module StopTime::Views if @customers.empty? p do text! "None found! You can create one " + - "#{a "here", :href => R(CustomersNew)}." + "#{a "here", :href => R(CustomersNew)}." end else table.customers do From 8fd7f45efce768007805e3b9d11d08ca81d21199 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 15:02:59 +0100 Subject: [PATCH 31/84] Bumped dependency versions in the README --- README | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 98efcfd..72effe8 100644 --- a/README +++ b/README @@ -18,11 +18,11 @@ invoicing. Stop… Camping Time! is a Camping application, so you need: -* Ruby 1.8 (>= 1.8.6) or 1.9 (>= 1.9.1) -* Camping (>= 2.0) with +* Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) +* Camping (>= 2.2) with * Active Record (>= 2.3) - * Markaby, and optionally: - * Mongrel (for testing and deployment without Apache/Rackup) + * Markaby (>= 0.1.0) , and optionally: + * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: From 5c364e1d10eb2726ffc5aa7038d5d55e7ac102f8 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Tue, 31 Jan 2012 22:34:26 +0100 Subject: [PATCH 32/84] Small cleanup for the block override that works with recent Mab --- stoptime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 273868f..991e27f 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -87,8 +87,7 @@ module StopTime::Mab tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) # Inject a hidden input element with the proper method to the tag block # if the form method is unsupported. - orig_blk = tag.block - tag.block = proc do + tag.block do |orig_blk| input :type => 'hidden', :name => '_method', :value => meth orig_blk.call end if override From 482e7eabebeaa81e119e5d8f89fcb870ff867aa6 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:52:46 +0100 Subject: [PATCH 33/84] Actively load active record --- stoptime.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/stoptime.rb b/stoptime.rb index 991e27f..e14e4a7 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -13,6 +13,7 @@ require "action_view" require "active_support" require "camping" require "camping/mab" +require "camping/ar" require "pathname" require "sass/plugin/rack" From b47f8376134e2c23b42123e61bf588b5fcb0ac8c Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:24 +0100 Subject: [PATCH 34/84] Fix up some hacks that generate errors when used with Mab --- stoptime.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/stoptime.rb b/stoptime.rb index e14e4a7..50837c2 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -77,7 +77,6 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -# FIXME: update for Mab! module StopTime::Mab SUPPORTED = [:get, :post] From 968ec1ab991ebe041956d7be2e7f48721577ad97 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 25 Jan 2012 15:53:43 +0100 Subject: [PATCH 35/84] More Mab compability: different doctype and text escaping --- stoptime.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/stoptime.rb b/stoptime.rb index 50837c2..cc31d76 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1345,6 +1345,7 @@ module StopTime::Views # The main layout used by all views. def layout + doctype! html do head do title "Stop… Camping Time!" From aa9f0e9dc0c6fe81a825596eda13252034b40713 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 12:57:37 +0100 Subject: [PATCH 36/84] Leave the form method override stuff for now --- stoptime.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index cc31d76..7a0892b 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -77,8 +77,9 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -module StopTime::Mab - SUPPORTED = [:get, :post] +# FIXME: update for Mab! +module StopTime::Helpers + #SUPPORTED = [:get, :post] def mab_done(tag) return super unless tag.name == :form From b25226ac7e5eee88bae1ad11328523c1315157b1 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:57:51 +0100 Subject: [PATCH 37/84] Port the Markaby method override support to Mab --- stoptime.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 7a0892b..cc31d76 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -77,9 +77,8 @@ module StopTime end # = The Stop… Camping Time! Markaby extensions -# FIXME: update for Mab! -module StopTime::Helpers - #SUPPORTED = [:get, :post] +module StopTime::Mab + SUPPORTED = [:get, :post] def mab_done(tag) return super unless tag.name == :form From 8ce00648f3e5dc830e1367ff9f0ce3d0a8ab730f Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 30 Jan 2012 13:58:04 +0100 Subject: [PATCH 38/84] Remove the double doctype, fix indentation --- stoptime.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/stoptime.rb b/stoptime.rb index cc31d76..50837c2 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1345,7 +1345,6 @@ module StopTime::Views # The main layout used by all views. def layout - doctype! html do head do title "Stop… Camping Time!" From 9df0a55e4bfc776ce41a357ec8090b1e804d242c Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 21 May 2012 17:11:06 +0200 Subject: [PATCH 39/84] Small Mab compatibility fix --- stoptime.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 50837c2..b9ff21d 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1563,10 +1563,10 @@ module StopTime::Views td { customer.short_name || "–"} td do if customer.address_street.present? - text customer.address_street + text! customer.address_street br - text customer.address_postal_code + " " + - customer.address_city + text! customer.address_postal_code + " " + + customer.address_city else "–" end From 1a72b797c132074f7a27ee7a215223ae3a8df79d Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 21 May 2012 17:11:29 +0200 Subject: [PATCH 40/84] Replaced the dependency on Markaby by Mab --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 72effe8..f71727a 100644 --- a/README +++ b/README @@ -21,7 +21,7 @@ Stop… Camping Time! is a Camping application, so you need: * Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) * Camping (>= 2.2) with * Active Record (>= 2.3) - * Markaby (>= 0.1.0) , and optionally: + * Mab (>= 0.0.1) , and optionally: * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: From 33581f8bb00270d3b3bf790a8c60d5538dcdfe25 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 21 May 2012 19:51:46 +0200 Subject: [PATCH 41/84] Update the invoice template for isodoc >= 0.9 (was 0.6) --- templates/invoice.tex.erb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/invoice.tex.erb b/templates/invoice.tex.erb index 6463d38..aaed31b 100644 --- a/templates/invoice.tex.erb +++ b/templates/invoice.tex.erb @@ -4,11 +4,11 @@ \usepackage{array} \usepackage[utf8]{inputenc} +\usepackage{pxfonts} \setupdocument{ %% Language and style, dutch, fill, - fontpackage=pxfonts, %% Company info. company=<%= @company.name %>, who=<%= @company.contact_name %>, @@ -24,8 +24,8 @@ <% unless @company.contact_name.blank? %> \addresswhotext: & \who \\ <% end %><% end %> & \street\\ & \zip\ \city\\[.2em] -<% unless @company.phone.blank? %> \phonetext: & \lead\phone\\ -<% end %><% unless @company.cell.blank? %> \cellphonetext: & \lead\cellphone\\ +<% unless @company.phone.blank? %> \phonetext: & \phoneprefix\phone\\ +<% end %><% unless @company.cell.blank? %> \cellphonetext: & \phoneprefix\cellphone\\ <% end %><% unless @company.email.blank? %> \emailtext: & \email\\[.2em] <% end %><% unless @company.chamber.blank? %> \chambertext: & \chamber\\ <% end %><% unless @company.vatno.blank? %> \vatnotext: & \vatno @@ -86,7 +86,7 @@ \newcommand{\ihnosubtotal}[1]{\cmidrule[.0em]{4-4}&&&\\} \newcommand{\ihvat}[1]{\textit{Btw-heffing <%= "%d\\%%" % @config["vat_rate"] %>}&&&\currency~#1\\} \newcommand{\ihtotal}[1]{\cmidrule[.05em]{4-4}% - \textbf{\Totaltext}&&&\textbf{\currency~#1}} + \textbf{\totaltext}&&&\textbf{\currency~#1}} \begin{document} From 3b54b935046411ba5f569bc159cfd34dd2b3c3e2 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Wed, 6 Jun 2012 11:28:59 +0200 Subject: [PATCH 42/84] Added support for Ruby 1.9 --- stoptime.rb | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index d90923e..b5c615d 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1,4 +1,5 @@ #!/usr/bin/env camping +# encoding: UTF-8 # # stoptime.rb - The Stop… Camping Time! time registration and invoicing application. # @@ -31,6 +32,12 @@ unless defined? PUBLIC_DIR # Set up SASS. Sass::Plugin.options[:template_location] = "templates/sass" + # Set the default encodings. + if RUBY_VERSION =~ /^1\.9/ + Encoding.default_external = Encoding::UTF_8 + Encoding.default_internal = Encoding::UTF_8 + end + # Set the default date(/time) format. ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!( :default => "%Y-%m-%d %H:%M", @@ -2037,8 +2044,10 @@ module StopTime::Views def _format_period(period) period = period.map { |m| m.to_formatted_s(:month_and_year) }.uniq case period.length - when 1: period.first - when 2: period.join("–") + when 1 + period.first + when 2 + period.join("–") end end @@ -2058,11 +2067,11 @@ module StopTime::Views def _form_input_radio(name, value, default=false, *opts) input_val = @input[name] if input_val == value or (input_val.blank? and default) - input :type => "radio", :id => "#{name}_#{value}", - :name => name, :value => value, :checked => true, *opts + input({:type => "radio", :id => "#{name}_#{value}", + :name => name, :value => value, :checked => true}, *opts) else - input :type => "radio", :id => "#{name}_#{value}", - :name => name, :value => value, *opts + input({:type => "radio", :id => "#{name}_#{value}", + :name => name, :value => value}, *opts) end end @@ -2071,11 +2080,11 @@ module StopTime::Views # Additional options can be passed via the collection _opts_. def _form_input_checkbox(name, value=true, *opts) if @input[name] == value - input :type => "checkbox", :id => "#{name}_#{value}", :name => name, - :value => value, :checked => true, *opts + input({:type => "checkbox", :id => "#{name}_#{value}", :name => name, + :value => value, :checked => true}, *opts) else - input :type => "checkbox", :id => "#{name}_#{value}", :name => name, - :value => value, *opts + input({:type => "checkbox", :id => "#{name}_#{value}", :name => name, + :value => value}, *opts) end end @@ -2119,12 +2128,12 @@ module StopTime::Views else select :name => name, :id => name do opts.keys.sort.each do |key| - option "— #{key} —", :disabled => true + option("— #{key} —", {:disabled => true}) opts[key].sort_by { |o| o.last }.each do |opt_val, opt_str| if @input[name] == opt_val - option opt_str, :value => opt_val, :selected => true + option(opt_str, {:value => opt_val, :selected => true}) else - option opt_str, :value => opt_val + option(opt_str, {:value => opt_val}) end end end From 808b09f91fbfa6cbd79b6c31c6c10b77c588998d Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Fri, 28 Sep 2012 10:09:42 +0200 Subject: [PATCH 43/84] Add vat_rate field to the Task model --- stoptime.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/stoptime.rb b/stoptime.rb index be269c3..c29fc21 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -214,6 +214,7 @@ module StopTime::Models # [name] description (String) # [fixed_cost] fixed cost of the task (Float) # [hourly_rate] hourly rate for the task (Float) + # [vat_rate] VAT rate at time of billing (Float) # [invoice_comment] extra comment for the invoice (String) # [created_at] time of creation (Time) # [updated_at] time of last update (Time) @@ -633,6 +634,21 @@ module StopTime::Models end end + class VATRatePerTaskSupport < V 1.94 # :nodoc: + def self.up + add_column(Task.table_name, :vat_rate, :float) + config = Config.instance + Task.all.each do |t| + t.vat_rate = config['vat_rate'] + t.save + end + end + + def self.down + remove_column(Task.table_name, :vat_rate) + end + end + end # StopTime::Models # = The Stop… Camping Time! controllers From b7f74e23ec87965290913a71175081943dc0bd2a Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Fri, 28 Sep 2012 11:56:36 +0200 Subject: [PATCH 44/84] Extend Task#summary to also return the VAT --- stoptime.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index c29fc21..90a8aa0 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -268,21 +268,25 @@ module StopTime::Models end # Returns a time and cost summary of the registered time on the task - # by means of Array of three values. - # In case of a fixed cost task, only the third value is set to the - # fixed cost. + # by means of Array of four values. + # In case of a fixed cost task, the first value is the total of time + # (in hours), the third value is the fixed cost, and the fourth value + # is the VAT. # In case of a task with an hourly rate, the first value is # the total of time (in hours), the second value is the hourly rate, - # and the third value is the total amount (time times rate). + # the third value is the total amount (time times rate), and the fourth + # value is the VAT. def summary case type when "fixed_cost" total = time_entries.inject(0.0) { |summ, te| summ + te.hours_total } - [total, nil, fixed_cost] + [total, nil, fixed_cost, fixed_cost * (vat_rate/100.0)] when "hourly_rate" - time_entries.inject([0.0, hourly_rate, 0.0]) do |summ, te| + time_entries.inject([0.0, hourly_rate, 0.0, 0.0]) do |summ, te| + total_cost = te.hours_total * hourly_rate summ[0] += te.hours_total - summ[2] += te.hours_total * hourly_rate + summ[2] += total_cost + summ[3] += total_cost * (vat_rate/100.0) summ end end From cd29a51680f386cc4247d0d6ecb0a6d1502fc808 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Fri, 28 Sep 2012 11:57:14 +0200 Subject: [PATCH 45/84] Add Invoice#vat_summary to return a VAT summary grouped by VAT rate --- stoptime.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/stoptime.rb b/stoptime.rb index 90a8aa0..628857a 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -367,6 +367,16 @@ module StopTime::Models return summ end + # Returns a total per VAT rate of the contained tasks (Hash of Float to + # Fixnum). + def vat_summary + vatsumm = Hash.new(0.0) + summary.each do |task, summ| + vatsumm[task.vat_rate] += summ[3] + end + return vatsumm + end + # Returns the invoice period based on the contained tasks (Array of Time). # See also Task#bill_period. def period From 537b0d47ead67a996dd5198c0c8b1be51c2fea41 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Fri, 28 Sep 2012 11:58:38 +0200 Subject: [PATCH 46/84] Modify Invoice#total_amount to take different VAT rates into account --- stoptime.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 628857a..55193af 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -393,12 +393,16 @@ module StopTime::Models # Returns the total amount (including VAT). def total_amount - subtotal = summary.inject(0.0) { |tot, (task, summ)| tot + summ[2] } + subtotal, vattotal = summary.inject([0.0, 0.0]) do |tot, (task, summ)| + tot[0] += summ[2] + tot[1] += summ[3] + tot + end + if company_info.vatno.blank? subtotal else - config = Config.instance - subtotal * (1 + config["vat_rate"]/100.0) + subtotal + vattotal end end end From b45bb356ef2fd3a509d9049f5d8b48622c055019 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Fri, 28 Sep 2012 12:00:42 +0200 Subject: [PATCH 47/84] Add VAT rate specific summaries to the template and invoice_form view --- stoptime.rb | 22 ++++++++++++---------- templates/invoice.tex.erb | 14 ++++++++------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 55193af..2732803 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1058,6 +1058,7 @@ module StopTime::Controllers @company = @invoice.company_info @tasks = @invoice.summary + @vat = @invoice.vat_summary @period = @invoice.period if @format == "html" @@ -1833,28 +1834,29 @@ module StopTime::Views end end unless task.fixed_cost? end - if @company.vatno.blank? - vat = 0 - else + vattotal = 0.0 + if @company.vatno.present? tr.total do td { i "Sub-total" } td "" td "" td.right { "€ %.2f" % subtotal } end - vat = subtotal * @config["vat_rate"]/100.0 - tr do - td { i "VAT %d%%" % @config["vat_rate"] } - td "" - td "" - td.right { "€ %.2f" % vat } + @vat.keys.sort.each do |rate| + vattotal += @vat[rate] + tr do + td { i "VAT %d%%" % rate } + td "" + td "" + td.right { "€ %.2f" % @vat[rate] } + end end end tr.total do td { b "Total" } td "" td "" - td.right { "€ %.2f" % (subtotal + vat) } + td.right { "€ %.2f" % (subtotal + vattotal) } end end diff --git a/templates/invoice.tex.erb b/templates/invoice.tex.erb index aaed31b..cdc2692 100644 --- a/templates/invoice.tex.erb +++ b/templates/invoice.tex.erb @@ -84,7 +84,7 @@ \newcommand{\ihsubtotal}[1]{\cmidrule[.0em]{4-4}% \textit{Subtotaal}&&&\currency~#1\\} \newcommand{\ihnosubtotal}[1]{\cmidrule[.0em]{4-4}&&&\\} -\newcommand{\ihvat}[1]{\textit{Btw-heffing <%= "%d\\%%" % @config["vat_rate"] %>}&&&\currency~#1\\} +\newcommand{\ihvat}[2]{\textit{Btw-heffing #1}&&&\currency~#2\\} \newcommand{\ihtotal}[1]{\cmidrule[.05em]{4-4}% \textbf{\totaltext}&&&\textbf{\currency~#1}} @@ -108,15 +108,17 @@ <% end subtotal += line[2] end + vattotal = 0.0 if @company.vatno.blank? - vat = 0 %> \ihnosubtotal{} <% else - vat = subtotal * @config["vat_rate"]/100.0 %> - \ihsubtotal{<%= number_with_precision(subtotal) %>} - \ihvat{<%= number_with_precision(vat) %>}<% +%> \ihsubtotal{<%= number_with_precision(subtotal) %>}<% + @vat.keys.sort.each do |rate| + vattotal += @vat[rate] %> + \ihvat{<%= "%d\\%%" % rate %>}{<%= number_with_precision(@vat[rate]) %>}<% + end end %> - \ihtotal{<%= number_with_precision(subtotal + vat) %>} + \ihtotal{<%= number_with_precision(subtotal + vattotal) %>} \end{ihtable} \vspace{2em} From 8b943d788ca32295f1342ef05f3b26146924d115 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Fri, 28 Sep 2012 16:08:45 +0200 Subject: [PATCH 48/84] Make the VAT rate of a task editable via the form, default to global VAT rate This is the last commit needed to support VAT rates per tasks (closes: #e7b5a7). --- stoptime.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stoptime.rb b/stoptime.rb index 2732803..3ced3ba 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -835,6 +835,7 @@ module StopTime::Controllers @task.hourly_rate = @input.hourly_rate # FIXME: catch invalid task types! end + @task.vat_rate = @input.vat_rate @task.save if @task.invalid? @errors = @task.errors @@ -867,7 +868,8 @@ module StopTime::Controllers def get(customer_id) @customer = Customer.find(customer_id) @customer_list = Customer.all.map { |c| [c.id, c.shortest_name] } - @task = Task.new(:hourly_rate => @customer.hourly_rate) + @task = Task.new(:hourly_rate => @customer.hourly_rate, + :vat_rate => @config["vat_rate"]) @input = @task.attributes @input["type"] = @task.type # FIXME: find nicer way! @input["customer"] = @customer.id @@ -1718,6 +1720,9 @@ module StopTime::Views end end end + li do + _form_input_with_label("VAT rate", "vat_rate", :text) + end if @task.billed? li do label "Billed in invoice" From dc89386278a6ff61c329527783228fbc1fca9ffb Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 30 Sep 2012 13:52:27 +0200 Subject: [PATCH 49/84] Move config.yaml to config.yaml.example and ignore it to improve deployment --- .gitignore | 1 + config.yaml => config.yaml.example | 0 2 files changed, 1 insertion(+) rename config.yaml => config.yaml.example (100%) diff --git a/.gitignore b/.gitignore index 0a0f9bd..25693b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .sass-cache +config.yaml htpasswd db/* public/invoices/*.pdf diff --git a/config.yaml b/config.yaml.example similarity index 100% rename from config.yaml rename to config.yaml.example From 53018191054eb4c09107261b3eccb204f6db7e86 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Thu, 6 Jun 2013 21:49:20 +0200 Subject: [PATCH 50/84] Fix the way the DATE_FORMATS are set to suit AR3.2 (closes: #9dfc93) --- stoptime.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 3ced3ba..b59a6e1 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -39,13 +39,13 @@ unless defined? PUBLIC_DIR end # Set the default date(/time) format. - ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!( + Time::DATE_FORMATS.merge!( :default => "%Y-%m-%d %H:%M", :month_and_year => "%B %Y", :date_only => "%Y-%m-%d", :time_only => "%H:%M", :day_code => "%Y%m%d") - ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!( + Date::DATE_FORMATS.merge!( :default => "%Y-%m-%d", :month_and_year => "%B %Y") end From aa79757af4498c896a59574bd6a89d530811f976 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 15:11:25 +0200 Subject: [PATCH 51/84] Tweak column definitions so that they work with HTML5 and Mab 0.0.3 --- stoptime.rb | 74 ++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index b59a6e1..20fda21 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -1428,9 +1428,9 @@ module StopTime::Views end else table.overview do - col.task {} - col.hours {} - col.amount {} + col.task + col.hours + col.amount @tasks[customer].each do |task| tr do summary = task.summary @@ -1461,15 +1461,15 @@ module StopTime::Views end table.timeline do unless task_id.present? - col.customer {} - col.task {} + col.customer + col.task end - col.date {} - col.start_time {} - col.end_time {} - col.comment {} - col.hours {} - col.flag {} + col.date + col.start_time + col.end_time + col.comment + col.hours + col.flag tr do unless task_id.present? th "Customer" @@ -1588,11 +1588,11 @@ module StopTime::Views end else table.customers do - col.name {} - col.short_name {} - col.address {} - col.email {} - col.phone {} + col.name + col.short_name + col.address + col.email + col.phone tr do th "Name" th "Short name" @@ -1795,10 +1795,10 @@ module StopTime::Views end table.tasks do - col.task {} - col.reg_hours {} - col.hourly_rate {} - col.amount {} + col.task + col.reg_hours + col.hourly_rate + col.amount tr do th { "Project/Task" } th.right { "Registered time" } @@ -1881,13 +1881,13 @@ module StopTime::Views h3 "Projects/Tasks with an Hourly Rate" unless @hourly_rate_tasks.empty? table.invoice_select do - col.flag {} - col.date {} - col.start_time {} - col.end_time {} - col.comment {} - col.hours {} - col.amount {} + col.flag + col.date + col.start_time + col.end_time + col.comment + col.hours + col.amount tr do th "Bill?" th "Date" @@ -1925,11 +1925,11 @@ module StopTime::Views unless @fixed_cost_tasks.empty? h3 "Fixed Cost Projects/Tasks" table.tasks do - col.flag {} - col.task {} - col.comment {} - col.hours {} - col.amount {} + col.flag + col.task + col.comment + col.hours + col.amount tr do th "Bill?" th "Project/Task" @@ -2050,11 +2050,11 @@ module StopTime::Views p "None found!" else table.invoices do - col.number {} - col.date {} - col.period {} - col.amount {} - col.flag {} + col.number + col.date + col.period + col.amount + col.flag tr do th "Number" th "Date" From 800dd3106f31053eeac2bfb619d936c53a60d2f3 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 15:17:13 +0200 Subject: [PATCH 52/84] Adapt StopTime::Mab#mab_done to follow Mab 0.0.3 API changes --- stoptime.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stoptime.rb b/stoptime.rb index 20fda21..eef0707 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -88,13 +88,13 @@ module StopTime::Mab SUPPORTED = [:get, :post] def mab_done(tag) - return super unless tag.name == :form + return super unless tag._name == :form - meth = tag.attributes[:method] - tag.attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) + meth = tag._attributes[:method] + tag._attributes[:method] = 'post' if override = !SUPPORTED.include?(meth) # Inject a hidden input element with the proper method to the tag block # if the form method is unsupported. - tag.block do |orig_blk| + tag._block do |orig_blk| input :type => 'hidden', :name => '_method', :value => meth orig_blk.call end if override From 2746e2e9bd95c8b82608519eb0e66389794f7f1a Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 15:19:53 +0200 Subject: [PATCH 53/84] Update the requirements in the README for Camping 2.2/Mab 0.0.3 --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index f71727a..ac6b0dc 100644 --- a/README +++ b/README @@ -19,9 +19,9 @@ invoicing. Stop… Camping Time! is a Camping application, so you need: * Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) -* Camping (>= 2.2) with +* Camping (>= 2.1.532) with * Active Record (>= 2.3) - * Mab (>= 0.0.1) , and optionally: + * Mab (>= 0.0.3) , and optionally: * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: From de71183c26a5e8df818020755c4437045dbaadee Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 15:34:46 +0200 Subject: [PATCH 54/84] Update the README for the 3.2 versions of Rails module depends --- README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index ac6b0dc..cc27350 100644 --- a/README +++ b/README @@ -20,14 +20,14 @@ Stop… Camping Time! is a Camping application, so you need: * Ruby 1.8 (>= 1.8.7) or 1.9 (>= 1.9.3) * Camping (>= 2.1.532) with - * Active Record (>= 2.3) + * Active Record (>= 3.2) * Mab (>= 0.0.3) , and optionally: * Thin or Mongrel (for testing and deployment without Apache/Rackup) The following Ruby libraries are required: -* ActionPack (>= 2.3) for ActionView -* ActiveSupport (>= 2.3) +* ActionPack (>= 3.2) for ActionView +* ActiveSupport (>= 3.2) * Rack (for deployment using Apache/Rackup) * Sass or Haml (which at the moment includes Sass) From 2c4fb79c23d0195175f87f29a445cb09811fa56d Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 15:42:35 +0200 Subject: [PATCH 55/84] Set the default VAT rate to 21% in the example config --- config.yaml.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yaml.example b/config.yaml.example index 3f3e4fe..687778f 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -4,7 +4,7 @@ #hourly_rate: 20.0 # The VAT rate -#vat_rate: 19.0 +#vat_rate: 21.0 # The invoice ID format (see strftime(3) and %N for the sequence number) #invoice_id: %Y%N From b7b660ffc5b67152233b999c9fb90b383e5c3866 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 20:25:12 +0200 Subject: [PATCH 56/84] Modify StopTime#Mab#mab_done to transform underscores to dashes in classes --- stoptime.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stoptime.rb b/stoptime.rb index eef0707..f38194d 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -88,6 +88,12 @@ module StopTime::Mab SUPPORTED = [:get, :post] def mab_done(tag) + # Transform underscores into dashs in class names + if tag._attributes.has_key?(:class) and tag._attributes[:class].present? + tag._attributes[:class] = tag._attributes[:class].gsub('_', '-') + end + + # The followin method processing is only for form tags. return super unless tag._name == :form meth = tag._attributes[:method] From 6db3e52148083934be0a9cd458a2058962a98abf Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 16 Jun 2013 20:25:59 +0200 Subject: [PATCH 57/84] Add Bootstrap files (version 2.3.2) --- public/images/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes public/images/glyphicons-halflings.png | Bin 0 -> 12799 bytes public/javascripts/bootstrap.js | 2280 ++++++++ public/javascripts/bootstrap.min.js | 6 + public/stylesheets/bootstrap-responsive.css | 1109 ++++ .../stylesheets/bootstrap-responsive.min.css | 9 + public/stylesheets/bootstrap.css | 5204 +++++++++++++++++ public/stylesheets/bootstrap.min.css | 9 + 8 files changed, 8617 insertions(+) create mode 100644 public/images/glyphicons-halflings-white.png create mode 100644 public/images/glyphicons-halflings.png create mode 100644 public/javascripts/bootstrap.js create mode 100644 public/javascripts/bootstrap.min.js create mode 100644 public/stylesheets/bootstrap-responsive.css create mode 100644 public/stylesheets/bootstrap-responsive.min.css create mode 100644 public/stylesheets/bootstrap.css create mode 100644 public/stylesheets/bootstrap.min.css diff --git a/public/images/glyphicons-halflings-white.png b/public/images/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae GIT binary patch literal 8777 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 B7G?kd literal 0 HcmV?d00001 diff --git a/public/images/glyphicons-halflings.png b/public/images/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9969993201f9cee63cf9f49217646347297b643 GIT binary patch literal 12799 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 literal 0 HcmV?d00001 diff --git a/public/javascripts/bootstrap.js b/public/javascripts/bootstrap.js new file mode 100644 index 0000000..643e71c --- /dev/null +++ b/public/javascripts/bootstrap.js @@ -0,0 +1,2280 @@ +/* =================================================== + * bootstrap-transition.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + /* ALERT DATA-API + * ============== */ + + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + /* BUTTON DATA-API + * =============== */ + + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + + , to: function (pos) { + var activeIndex = this.getActiveIndex() + , that = this + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activeIndex == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + e = $.Event('slide', { + relatedTarget: $next[0] + , direction: direction + }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + /* CAROUSEL DATA-API + * ================= */ + + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + , slideIndex + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + + e.preventDefault() + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning || this.$element.hasClass('in')) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning || !this.$element.hasClass('in')) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSE NO CONFLICT + * ==================== */ + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('