Permalink
Browse files

New version of footnotes installed. Changed the footnotes config to t…

…urn off bundled styling.
  • Loading branch information...
1 parent d3bec78 commit d30786256e0c4c90413fa4a43a5f5cb763cfce38 Jonathon Brenner committed Dec 25, 2008
Showing with 1,742 additions and 0 deletions.
  1. +49 −0 vendor/plugins/rails-footnotes/CHANGELOG
  2. +137 −0 vendor/plugins/rails-footnotes/README.markdown
  3. +18 −0 vendor/plugins/rails-footnotes/Rakefile
  4. +17 −0 vendor/plugins/rails-footnotes/init.rb
  5. +55 −0 vendor/plugins/rails-footnotes/lib/backtracer.rb
  6. +289 −0 vendor/plugins/rails-footnotes/lib/footnotes.rb
  7. +14 −0 vendor/plugins/rails-footnotes/lib/loader.rb
  8. +166 −0 vendor/plugins/rails-footnotes/lib/notes/abstract_note.rb
  9. +79 −0 vendor/plugins/rails-footnotes/lib/notes/components_note.rb
  10. +57 −0 vendor/plugins/rails-footnotes/lib/notes/controller_note.rb
  11. +19 −0 vendor/plugins/rails-footnotes/lib/notes/cookies_note.rb
  12. +19 −0 vendor/plugins/rails-footnotes/lib/notes/env_note.rb
  13. +40 −0 vendor/plugins/rails-footnotes/lib/notes/files_note.rb
  14. +53 −0 vendor/plugins/rails-footnotes/lib/notes/filters_note.rb
  15. +19 −0 vendor/plugins/rails-footnotes/lib/notes/general_note.rb
  16. +16 −0 vendor/plugins/rails-footnotes/lib/notes/javascripts_note.rb
  17. +33 −0 vendor/plugins/rails-footnotes/lib/notes/layout_note.rb
  18. +36 −0 vendor/plugins/rails-footnotes/lib/notes/log_note.rb
  19. +19 −0 vendor/plugins/rails-footnotes/lib/notes/params_note.rb
  20. +156 −0 vendor/plugins/rails-footnotes/lib/notes/queries_note.rb
  21. +59 −0 vendor/plugins/rails-footnotes/lib/notes/routes_note.rb
  22. +15 −0 vendor/plugins/rails-footnotes/lib/notes/session_note.rb
  23. +16 −0 vendor/plugins/rails-footnotes/lib/notes/stylesheets_note.rb
  24. +33 −0 vendor/plugins/rails-footnotes/lib/notes/view_note.rb
  25. +21 −0 vendor/plugins/rails-footnotes/templates/rescues/template_error.erb
  26. +190 −0 vendor/plugins/rails-footnotes/test/footnotes_test.rb
  27. +108 −0 vendor/plugins/rails-footnotes/test/notes/abstract_note_test.rb
  28. +9 −0 vendor/plugins/rails-footnotes/test/test_helper.rb
View
49 vendor/plugins/rails-footnotes/CHANGELOG
@@ -0,0 +1,49 @@
+TODO:
+ * Create ProfilerNote
+ * Javascript injection for partials
+
+== Footnotes v3.3
+Author: José Valim (jose.valim@gmail.com)
+Site: http://www.pagestacker.com/
+ http://josevalim.blogspot.com/
+ * Rails Edge (aka 2.2) compatibility;
+ * Initial Ruby 1.9 compatibility.
+
+== Footnotes v3.2.2
+ * Added trace to QueriesNote;
+ * Fixed incompatibility with Ultrasphinx (thanks to mhartl);
+ * Added W3C compatibility (thanks to tapajos);
+ * Added support to other log mechanisms in LogNote.
+
+== Footnotes v3.2.1
+ * Added some tests;
+ * Redefined Footnotes CSS and Javascripts to use concise names.
+
+== Footnotes v3.2
+ * Now you can easily add your own notes;
+ * Added numbers to tabs;
+ * Added Queries note;
+ * Added MySQL Query Analyzer.
+
+== Footnotes v3.1
+ * Code refactoring (using modules, except backtracer);
+ * Ability to cherry pick notes;
+ * Working on Rails 2.1.
+
+== Footnotes v3.0
+ * Some code refactoring;
+ * Stylesheets bug fixed: was showing not only css in Stylesheets div;
+ * Logtail fix: working with Rails 2.0 logger and in all OS, since it's Regexp based;
+ * Rails 1.2 (except backtrace) and 2.0 compatible;
+ * RoutingNavigator (based on Rick Olson plugin);
+ * FilterChain.
+
+== Textmate Footnotes v2.0
+Copyright (c) 2006 InquiryLabs, Inc.
+Author: Duane Johnson (duane.johnson@gmail.com)
+Site: http://inquirylabs.com/
+Description:
+ Creates clickable footnotes on each rendered page, as well as clickable
+ links in the backtrace should an error occur in your Rails app. Links take
+ you to the right place inside TextMate.
+ Enable only the TextMate on Macs in development mode
View
137 vendor/plugins/rails-footnotes/README.markdown
@@ -0,0 +1,137 @@
+Footnotes plugin for Rails (v3.3)
+-----------------------------------
+
+If you are developing in Rails you should know the plugin!
+
+It displays footnotes in your application for easy debugging, such as sessions, request parameters, cookies, log tail, filter chain and routes.
+
+Even more, it contains links to open files directly in textmate. And if Rails get an error, it appends Textmate links to backtrace file lines.
+
+Installation
+============
+
+The current version is only Rails Edge (aka Rails 2.2) compatible. Scroll down to check how to install early versions.
+
+If you just want a static copy of the plugin:
+
+ cd myapp
+ git clone git://github.com/drnic/rails-footnotes.git vendor/plugins/footnotes
+ rm -rf vendor/plugins/footnotes/.git
+
+If you are using Git for your own app, then you could use Git sub-modules or the tool [Braid](http://github.com/evilchelu/braid/tree/master).
+
+Early versions
+==============
+
+If you are running on Rails 2.1.x, you should use Footnotes v3.2.2:
+
+ cd myapp
+ git clone git://github.com/drnic/rails-footnotes.git vendor/plugins/footnotes
+ cd vendor/plugins/footnotes
+ git checkout v3.2.2
+ rm -rf ./.git
+
+If you are running on Rails 2.0.x or Rails 1.x, you should use Footnotes v3.0:
+
+ cd myapp
+ git clone git://github.com/drnic/rails-footnotes.git vendor/plugins/footnotes
+ cd vendor/plugins/footnotes
+ git checkout v3.0
+ rm -rf ./.git
+
+Remember that in Rails 1.x, after filters appear first than before filters in the Filters tab.
+
+Usage
+=====
+
+* Footnotes are applied in all actions under development. If You want to change this behaviour, check the loader.rb file.
+
+* Some features only work by default if you are under MacOSX and using Textmate.
+ If your editor supports out-of-the-box opening files like Textmate, e.g. txmt://open?url=file://path/to/file, you can put in your environment file the following line:
+
+ Footnotes::Filter.prefix = "editor://open?file://"
+
+ If it doesn't, you can enable this behavior in few steps. I've written a post about it [here](http://josevalim.blogspot.com/2008/06/textmate-protocol-behavior-on-any.html).
+
+* If you want to use your own stylesheet, you can disable the Footnotes stylesheet with:
+
+ Footnotes::Filter.no_style = true
+
+* Footnotes are appended at the end of the page, but if your page has a div with id "footnotes_holder", Footnotes will be inserted into this div.
+
+* If you want to open multiple notes at the same time, just put in your enviroment:
+
+ Footnotes::Filter.multiple_notes = true
+
+* Finally, you can cherry pick which notes you want to use, simply doing:
+
+ Footnotes::Filter.notes = [:session, :cookies, :params, :filters, :routes, :queries, :log, :general]
+
+Creating your own notes
+=======================
+
+Create your notes to integrate with Footnotes is easy.
+
+1. Create a Footnotes::Notes::YoursExampleNote class
+
+2. Implement the necessary methods (check abstract_note.rb file in lib/notes)
+
+3. Append yours example note in Footnotes::Filter.notes (usually at the end of your environment file or an initializer):
+
+ Footnotes::Filter.notes += [:yours_example]
+
+To create a note that shows info about the user logged in your application (@current_user) you just have to do:
+
+<pre><code>module Footnotes
+ module Notes
+ class CurrentUserNote < AbstractNote
+ # Always receives a controller
+ #
+ def initialize(controller)
+ @current_user = controller.instance_variable_get("@current_user")
+ end
+
+ # The name that will appear as legend in fieldsets
+ #
+ def legend
+ "Current user: #{@current_user.name}"
+ end
+
+ # This Note is only valid if we actually found an user
+ # If it's not valid, it won't be displayed
+ #
+ def valid?
+ @current_user
+ end
+
+ # The fieldset content
+ #
+ def content
+ escape(@current_user.inspect)
+ end
+ end
+ end
+end</code></pre>
+
+Then put in your environment:
+
+ Footnotes::Filter.notes += [:current_user]
+
+Who?
+====
+
+*Current Developer (v3.0 and above)*
+
+José Valim (jose.valim@gmail.com)
+http://josevalim.blogspot.com/
+
+
+*Original Author (v2.0)*
+
+Duane Johnson (duane.johnson@gmail.com)
+http://blog.inquirylabs.com/
+
+
+*License*
+
+See MIT License.
View
18 vendor/plugins/rails-footnotes/Rakefile
@@ -0,0 +1,18 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Test Footnotes plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for Footnotes plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'SimpleLocalization'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
View
17 vendor/plugins/rails-footnotes/init.rb
@@ -0,0 +1,17 @@
+# Footnotes is divided in three main files:
+#
+# * initialiazer.rb: Initialize the plugin and apply the footnotes as an after_filter;
+#
+# * footnotes.rb: Is the core and adds the debug options at the bottom of each page;
+#
+# * backtracer.rb: Append links to tour favorite editor in backtrace pages.
+#
+if (ENV['RAILS_ENV'] == 'development')
+ dir = File.dirname(__FILE__)
+ require File.join(dir,'lib','footnotes')
+ require File.join(dir,'lib','loader')
+ require File.join(dir,'lib','backtracer')
+
+ Footnotes::Filter.prefix ||= 'txmt://open?url=file://' if RUBY_PLATFORM.include?('darwin')
+ Footnotes::Filter.no_style = true
+end
View
55 vendor/plugins/rails-footnotes/lib/backtracer.rb
@@ -0,0 +1,55 @@
+module Footnotes
+ module Extensions
+ module Exception
+ def self.included(base)
+ base.class_eval do
+ alias_method_chain :clean_backtrace, :links
+ end
+ end
+
+ def add_links_to_backtrace(lines)
+ lines.collect do |line|
+ expanded = line.gsub '#{RAILS_ROOT}', RAILS_ROOT
+ if match = expanded.match(/^(.+):(\d+):in/) or match = expanded.match(/^(.+):(\d+)\s*$/)
+ file = File.expand_path(match[1])
+ line_number = match[2]
+ html = "<a href='#{Footnotes::Filter.prefix}#{file}&line=#{line_number}'>#{line}</a>"
+ else
+ line
+ end
+ end
+ end
+
+ def clean_backtrace_with_links
+ ::Footnotes::Filter.prefix ? add_links_to_backtrace(clean_backtrace_without_links) : clean_backtrace_without_links
+ end
+ end
+
+ module ActionView
+ def line_number_link
+ file = File.expand_path(@file_name)
+ "<a href='#{Footnotes::Filter.prefix}#{file}&line=#{line_number}'>#{line_number}</a>"
+ end
+ end
+
+ module ActionController
+ def self.included(base)
+ base.class_eval do
+ alias_method_chain :template_path_for_local_rescue, :links
+ end
+ end
+
+ def template_path_for_local_rescue_with_links(exception)
+ if ::ActionView::TemplateError === exception && ::Footnotes::Filter.prefix
+ File.dirname(__FILE__) + '/../templates/rescues/template_error.erb'
+ else
+ template_path_for_local_rescue_without_links(exception)
+ end
+ end
+ end
+ end
+end
+
+Exception.__send__ :include, Footnotes::Extensions::Exception
+ActionView::TemplateError.__send__ :include, Footnotes::Extensions::ActionView
+ActionController::Base.__send__ :include, Footnotes::Extensions::ActionController
View
289 vendor/plugins/rails-footnotes/lib/footnotes.rb
@@ -0,0 +1,289 @@
+module Footnotes
+ class Filter
+ @@no_style = false
+ @@multiple_notes = false
+ # Edit notes
+ @@notes = [ :components, :controller, :view, :layout, :stylesheets, :javascripts ]
+ # Show notes
+ @@notes += [ :session, :cookies, :params, :filters, :routes, :env, :queries, :log, :general ]
+
+ # :no_style => If you don't want the style to be appended to your pages
+ # :notes => Class variable that holds the notes to be processed
+ # :prefix => Prefix appended to FootnotesLinks
+ # :multiple_notes => Set to true if you want to open several notes at the same time
+ cattr_accessor :no_style, :notes, :prefix, :multiple_notes
+
+ class << self
+ # Method called to start the notes
+ # It's a before filter prepend in the controller
+ #
+ def before(controller)
+ Footnotes::Filter.start!(controller)
+ end
+
+ # Method that calls Footnotes to attach its contents
+ #
+ def after(controller)
+ filter = Footnotes::Filter.new(controller)
+ filter.add_footnotes!
+ filter.close!(controller)
+ end
+
+ # Calls the class method start! in each note
+ # Sometimes notes need to set variables or clean the environment to work properly
+ # This method allows this kind of setup
+ #
+ def start!(controller)
+ each_with_rescue(@@notes.flatten) do |note|
+ klass = eval("Footnotes::Notes::#{note.to_s.camelize}Note") if note.is_a?(Symbol) || note.is_a?(String)
+ klass.start!(controller) if klass.respond_to?(:start!)
+ end
+ end
+
+ # Process notes, discarding only the note if any problem occurs
+ #
+ def each_with_rescue(notes)
+ delete_me = []
+
+ notes.each do |note|
+ begin
+ yield note
+ rescue Exception => e
+ # Discard note if it has a problem
+ log_error("Footnotes #{note.to_s.camelize}Note Exception", e)
+ delete_me << note
+ next
+ end
+ end
+
+ delete_me.each{ |note| notes.delete(note) }
+ end
+
+ # Logs the error using specified title and format
+ #
+ def log_error(title, exception)
+ RAILS_DEFAULT_LOGGER.error "#{title}: #{exception}\n#{exception.backtrace.join("\n")}"
+ end
+
+ end
+
+ def initialize(controller)
+ @controller = controller
+ @template = controller.instance_variable_get(:@template)
+ @body = controller.response.body
+ @notes = []
+ end
+
+ def add_footnotes!
+ add_footnotes_without_validation! if valid?
+ rescue Exception => e
+ # Discard footnotes if there are any problems
+ self.class.log_error("Footnotes Exception", e)
+ end
+
+ # Calls the class method close! in each note
+ # Sometimes notes need to finish their work even after being read
+ # This method allows this kind of work
+ #
+ def close!(controller)
+ each_with_rescue(@notes) do |note|
+ note.class.close!(controller)
+ end
+ end
+
+ protected
+ def valid?
+ performed_render? && first_render? && valid_format? && valid_content_type? && @body.is_a?(String) && !component_request? && !xhr?
+ end
+
+ def add_footnotes_without_validation!
+ initialize_notes!
+ insert_styles unless @@no_style
+ insert_footnotes
+ end
+
+ def initialize_notes!
+ each_with_rescue(@@notes.flatten) do |note|
+ note = eval("Footnotes::Notes::#{note.to_s.camelize}Note").new(@controller) if note.is_a?(Symbol) || note.is_a?(String)
+ @notes << note if note.respond_to?(:valid?) && note.valid?
+ end
+ end
+
+ def performed_render?
+ @controller.instance_variable_get(:@performed_render)
+ end
+
+ def first_render?
+ @template.instance_variable_get(:@_first_render)
+ end
+
+ def valid_format?
+ [:html,:rhtml,:xhtml,:rxhtml].include?(@template.template_format.to_sym)
+ end
+
+ def valid_content_type?
+ c = @controller.response.headers['Content-Type'].to_s
+ (c.empty? || c =~ /html/)
+ end
+
+ def component_request?
+ @controller.instance_variable_get(:@parent_controller)
+ end
+
+ def xhr?
+ @controller.request.xhr?
+ end
+
+ #
+ # Insertion methods
+ #
+
+ def insert_styles
+ insert_text :before, /<\/head>/i, <<-HTML
+ <!-- Footnotes Style -->
+ <style type="text/css">
+ #footnotes_debug {margin: 2em 0 1em 0; text-align: center; color: #444; line-height: 16px;}
+ #footnotes_debug a {text-decoration: none; color: #444; line-height: 18px;}
+ #footnotes_debug table {text-align: center;}
+ #footnotes_debug table td {padding: 0 5px;}
+ #footnotes_debug tbody {text-align: left;}
+ #footnotes_debug legend {background-color: #FFF;}
+ #footnotes_debug fieldset {text-align: left; border: 1px dashed #aaa; padding: 0.5em 1em 1em 1em; margin: 1em 2em; color: #444; background-color: #FFF;}
+ /* Aditional Stylesheets */
+ #{@notes.map(&:stylesheet).compact.join("\n")}
+ </style>
+ <!-- End Footnotes Style -->
+ HTML
+ end
+
+ def insert_footnotes
+ # Fieldsets method should be called first
+ content = fieldsets
+
+ footnotes_html = <<-HTML
+ <!-- Footnotes -->
+ <div style="clear:both"></div>
+ <div id="footnotes_debug">
+ #{links}
+ #{content}
+ <script type="text/javascript">
+ function footnotes_close(){
+ #{close unless @@multiple_notes}
+ }
+ function footnotes_toogle(id){
+ s = document.getElementById(id).style;
+ before = s.display;
+ footnotes_close();
+ s.display = (before != 'block') ? 'block' : 'none'
+ location.href = '#footnotes_debug';
+ }
+ /* Additional Javascript */
+ #{@notes.map(&:javascript).compact.join("\n")}
+ </script>
+ </div>
+ <!-- End Footnotes -->
+ HTML
+ if @body =~ %r{<div[^>]+id=['"]footnotes_holder['"][^>]*>}
+ # Insert inside the "footnotes_holder" div if it exists
+ insert_text :after, %r{<div[^>]+id=['"]footnotes_holder['"][^>]*>}, footnotes_html
+ else
+ # Otherwise, try to insert as the last part of the html body
+ insert_text :before, /<\/body>/i, footnotes_html
+ end
+ end
+
+ # Process notes to gets their links
+ #
+ def links
+ links = Hash.new([])
+ order = []
+ each_with_rescue(@notes) do |note|
+ order << note.row
+ links[note.row] += [link_helper(note)]
+ end
+
+ html = ''
+ order.uniq!
+ order.each do |row|
+ html << "#{row.is_a?(String) ? row : row.to_s.camelize}: #{links[row].join(" | \n")}<br />"
+ end
+ html
+ end
+
+ # Process notes to get their content
+ #
+ def fieldsets
+ content = ''
+ each_with_rescue(@notes) do |note|
+ next unless note.fieldset?
+ content << <<-HTML
+ <fieldset id="#{note.to_sym}_debug_info" style="display: none">
+ <legend>#{note.legend}</legend>
+ <div>#{note.content}</div>
+ </fieldset>
+ HTML
+ end
+ content
+ end
+
+ # Process notes to get javascript code to close them all
+ # This method is used with multiple_notes is false
+ #
+ def close
+ javascript = ''
+ each_with_rescue(@notes) do |note|
+ next unless note.fieldset?
+ javascript << close_helper(note)
+ end
+ javascript
+ end
+
+ #
+ # Helpers
+ #
+
+ # Helper that creates the javascript code to close the note
+ #
+ def close_helper(note)
+ "document.getElementById('#{note.to_sym}_debug_info').style.display = 'none'\n"
+ end
+
+ # Helper that creates the link and javascript code when note is clicked
+ #
+ def link_helper(note)
+ onclick = note.onclick
+ unless href = note.link
+ href = '#'
+ onclick ||= "footnotes_toogle('#{note.to_sym}_debug_info');return false;" if note.fieldset?
+ end
+
+ "<a href=\"#{href}\" onclick=\"#{onclick}\">#{note.title}</a>"
+ end
+
+ # Inserts text in to the body of the document
+ # +pattern+ is a Regular expression which, when matched, will cause +new_text+
+ # to be inserted before or after the match. If no match is found, +new_text+ is appended
+ # to the body instead. +position+ may be either :before or :after
+ #
+ def insert_text(position, pattern, new_text)
+ index = case pattern
+ when Regexp
+ if match = @body.match(pattern)
+ match.offset(0)[position == :before ? 0 : 1]
+ else
+ @body.size
+ end
+ else
+ pattern
+ end
+ @body.insert index, new_text
+ end
+
+ # Instance each_with_rescue method
+ #
+ def each_with_rescue(*args, &block)
+ self.class.each_with_rescue(*args, &block)
+ end
+
+ end
+end
View
14 vendor/plugins/rails-footnotes/lib/loader.rb
@@ -0,0 +1,14 @@
+# Load all notes
+#
+Dir[File.join(File.dirname(__FILE__),'notes','*.rb')].each do |note|
+ require note
+end
+
+# The footnotes are applied by default to all actions. You can change this
+# behavior commenting the after_filter line below and putting it in Your
+# application. Then you can cherrypick in which actions it will appear.
+#
+class ActionController::Base
+ prepend_before_filter Footnotes::Filter
+ after_filter Footnotes::Filter
+end
View
166 vendor/plugins/rails-footnotes/lib/notes/abstract_note.rb
@@ -0,0 +1,166 @@
+module Footnotes
+ module Notes
+ # This is the abstrac class for notes.
+ #
+ class AbstractNote
+
+ class << self
+ # Returns the symbol that represents this note.
+ # It's the name of the class, underscored and without _note.
+ #
+ # For example, for ControllerNote it will return :controller.
+ #
+ def to_sym
+ @note_sym ||= self.title.underscore.to_sym
+ end
+
+ # Returns the title that represents this note.
+ # It's the name of the class without Note.
+ #
+ # For example, for ControllerNote it will return Controller.
+ #
+ def title
+ @note_title ||= self.name.match(/^Footnotes::Notes::(\w+)Note$/)[1]
+ end
+
+ # Return true if Note is included in notes array.
+ #
+ def included?
+ Footnotes::Filter.notes.include?(self.to_sym)
+ end
+
+ # Action to be called to start the Note.
+ # This is applied as a before_filter.
+ #
+ def start!(controller = nil)
+ end
+
+ # Action to be called after the Note was used.
+ # This is applied as an after_filter.
+ #
+ def close!(controller = nil)
+ end
+ end
+
+ # Initialize notes.
+ # Always receives a controller.
+ #
+ def initialize(controller = nil)
+ end
+
+ # Returns the symbol that represents this note.
+ #
+ def to_sym
+ self.class.to_sym
+ end
+
+ # Specifies in which row should appear the title.
+ # The default is :show.
+ #
+ def row
+ :show
+ end
+
+ # If valid?, create a tab on Footnotes Footer with the title returned.
+ # By default, returns the title of the class (defined above).
+ #
+ def title
+ self.class.title
+ end
+
+ # If fieldset?, create a fieldset with the value returned as legend.
+ # By default, returns the title of the class (defined above).
+ #
+ def legend
+ self.class.title
+ end
+
+ # If content is defined, fieldset? returns true and the value of content
+ # is displayed when the Note is clicked. See fieldset? below for more info.
+ #
+ # def content
+ # end
+
+ # Set href field for Footnotes links.
+ # If it's nil, Footnotes will use '#'.
+ #
+ def link
+ end
+
+ # Set onclick field for Footnotes links.
+ # If it's nil, Footnotes will make it open the fieldset.
+ #
+ def onclick
+ end
+
+ # Insert here any additional stylesheet.
+ # This is directly inserted into a <style> tag.
+ #
+ def stylesheet
+ end
+
+ # Insert here any additional javascript.
+ # This is directly inserted into a <script> tag.
+ #
+ def javascript
+ end
+
+ # Specifies when should create a note for it.
+ # By default, it's valid.
+ #
+ def valid?
+ true
+ end
+
+ # Specifies when should create a fieldset for it, considering it's valid.
+ #
+ def fieldset?
+ self.respond_to?(:content)
+ end
+
+ # Return if this note is incuded in Footnotes::Filter.notes.
+ #
+ def included?
+ self.class.included?
+ end
+
+ # Some helpers to generate notes.
+ #
+ protected
+ # Return if Footnotes::Filter.prefix exists or not.
+ # Some notes only work with prefix set.
+ #
+ def prefix?
+ Footnotes::Filter.prefix
+ end
+
+ # Escape HTML special characters.
+ #
+ def escape(text)
+ text.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')
+ end
+
+ # Gets a bidimensional array and create a table.
+ # The first array is used as label.
+ #
+ def mount_table(array, options = {})
+ header = array.shift
+ return '' if array.empty?
+
+ header = header.collect{|i| escape(i.to_s.humanize) }
+ rows = array.collect{|i| "<tr><td>#{i.join('</td><td>')}</td></tr>" }
+
+ <<-TABLE
+ <table #{hash_to_xml_attributes(options)}>
+ <thead><tr><th>#{header.join('</th><th>')}</th></tr></thead>
+ <tbody>#{rows.join}</tbody>
+ </table>
+ TABLE
+ end
+
+ def hash_to_xml_attributes(hash)
+ return hash.collect{ |key, value| "#{key.to_s}=\"#{value.gsub('"','\"')}\"" }.join(' ')
+ end
+ end
+ end
+end
View
79 vendor/plugins/rails-footnotes/lib/notes/components_note.rb
@@ -0,0 +1,79 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+require "#{File.dirname(__FILE__)}/controller_note"
+require "#{File.dirname(__FILE__)}/view_note"
+require "#{File.dirname(__FILE__)}/params_note"
+
+module Footnotes
+ module Notes
+ module ComponentsNote
+ def self.included(base)
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def to_sym
+ @note_sym ||= "#{self.title.underscore}_component_#{(rand*1000).to_i}".to_sym
+ end
+
+ def title
+ @note_title ||= self.name.match(/^Footnotes::Notes::(\w+)ComponentNote$/)[1]
+ end
+ end
+
+ def initialize(controller)
+ super
+ @controller = controller
+ end
+
+ def row
+ "#{@controller.controller_name.camelize}##{@controller.action_name.camelize} Component"
+ end
+
+ def legend
+ "#{super} for #{row}"
+ end
+ end
+
+ class ControllerComponentNote < ControllerNote; include ComponentsNote; end
+ class ViewComponentNote < ViewNote; include ComponentsNote; end
+ class ParamsComponentNote < ParamsNote; include ComponentsNote; end
+ end
+
+ module Components
+
+ def self.included(base)
+ base.class_eval do
+ alias_method_chain :add_footnotes!, :component
+ Footnotes::Filter.notes.delete(:components)
+ @@component_notes = [ :controller, :view, :params ]
+ end
+ end
+
+ def add_footnotes_with_component!
+ if component_request?
+ initialize_component_notes!
+ Footnotes::Filter.notes.unshift(*@notes)
+ else
+ add_footnotes_without_component!
+ Footnotes::Filter.notes.delete_if {|note| note.class.to_s =~ /(ComponentNote)$/}
+ end
+ end
+
+ protected
+ def initialize_component_notes!
+ @@component_notes.flatten.each do |note|
+ begin
+ note = eval("Footnotes::Notes::#{note.to_s.camelize}ComponentNote").new(@controller) if note.is_a?(Symbol) || note.is_a?(String)
+ @notes << note if note.respond_to?(:valid?) && note.valid?
+ rescue Exception => e
+ # Discard note if it has a problem
+ self.class.log_error("Footnotes #{note.to_s.camelize}ComponentNote Exception", e)
+ next
+ end
+ end
+ end
+
+ end
+end
+
+Footnotes::Filter.__send__ :include, Footnotes::Components if Footnotes::Filter.notes.include?(:components)
View
57 vendor/plugins/rails-footnotes/lib/notes/controller_note.rb
@@ -0,0 +1,57 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class ControllerNote < AbstractNote
+ def initialize(controller)
+ @controller = controller
+ end
+
+ def row
+ :edit
+ end
+
+ def link
+ escape(
+ Footnotes::Filter.prefix +
+ controller_filename +
+ (index_of_method ? "&line=#{controller_line_number + 1}&column=3" : '')
+ )
+ end
+
+ def valid?
+ prefix?
+ end
+
+ protected
+ # Some controller classes come with the Controller:: module and some don't
+ # (anyone know why? -- Duane)
+ def controller_filename
+ File.join(File.expand_path(RAILS_ROOT), 'app', 'controllers', "#{@controller.class.to_s.underscore}.rb").sub('/controllers/controllers/', '/controllers/')
+ end
+
+ def controller_text
+ @controller_text ||= IO.read(controller_filename)
+ end
+
+ def index_of_method
+ (controller_text =~ /def\s+#{@controller.action_name}[\s\(]/)
+ end
+
+ def controller_line_number
+ lines_from_index(controller_text, index_of_method)
+ end
+
+ def lines_from_index(string, index)
+ lines = string.to_a
+ running_length = 0
+ lines.each_with_index do |line, i|
+ running_length += line.length
+ if running_length > index
+ return i
+ end
+ end
+ end
+ end
+ end
+end
View
19 vendor/plugins/rails-footnotes/lib/notes/cookies_note.rb
@@ -0,0 +1,19 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class CookiesNote < AbstractNote
+ def initialize(controller)
+ @cookies = (controller.__send__(:cookies) || {}).symbolize_keys
+ end
+
+ def title
+ "Cookies (#{@cookies.length})"
+ end
+
+ def content
+ escape(@cookies.inspect)
+ end
+ end
+ end
+end
View
19 vendor/plugins/rails-footnotes/lib/notes/env_note.rb
@@ -0,0 +1,19 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class EnvNote < AbstractNote
+ def initialize(controller)
+ @env = controller.request.env.dup
+ end
+
+ def content
+ # Replace HTTP_COOKIE for a link
+ @env['HTTP_COOKIE'] = '<a href="#" style="color:#009" onclick="footnotes_toogle(\'cookies_debug_info\');return false;">See cookies on its tab</a>'
+
+ # Create the env table
+ mount_table(@env.to_a.sort.unshift([:key, :value]))
+ end
+ end
+ end
+end
View
40 vendor/plugins/rails-footnotes/lib/notes/files_note.rb
@@ -0,0 +1,40 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class FilesNote < AbstractNote
+ def initialize(controller)
+ @files = scan_text(controller.response.body)
+ parse_files!
+ end
+
+ def row
+ :edit
+ end
+
+ def content
+ @files.empty? ? "" : "<ul><li>#{@files.join("</li><li>")}</li></ul>"
+ end
+
+ def valid?
+ prefix?
+ end
+
+ protected
+ def scan_text(text)
+ []
+ end
+
+ def parse_files!
+ @files.collect! do |filename|
+ if filename =~ %r{^/}
+ full_filename = File.join(File.expand_path(RAILS_ROOT), 'public', filename)
+ %{<a href="#{Footnotes::Filter.prefix}#{full_filename}">#{filename}</a>}
+ else
+ %{<a href="#{filename}">#{filename}</a>}
+ end
+ end
+ end
+ end
+ end
+end
View
53 vendor/plugins/rails-footnotes/lib/notes/filters_note.rb
@@ -0,0 +1,53 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class FiltersNote < AbstractNote
+ def initialize(controller)
+ @controller = controller
+ @parsed_filters = parse_filters
+ end
+
+ def legend
+ "Filter chain for #{@controller.class.to_s}"
+ end
+
+ def content
+ mount_table(@parsed_filters.unshift([:name, :type, :actions]))
+ end
+
+ protected
+ # Get controller filter chain
+ #
+ def parse_filters
+ return @controller.class.filter_chain.collect do |filter|
+ [parse_method(filter.method), filter.type.inspect, controller_filtered_actions(filter).inspect]
+ end
+ end
+
+ # This receives a filter, creates a mock controller and check in which
+ # actions the filter is performed
+ #
+ def controller_filtered_actions(filter)
+ mock_controller = Footnotes::Extensions::MockController.new
+
+ return @controller.class.action_methods.select { |action|
+ mock_controller.action_name = action
+
+ #remove conditions (this would call a Proc on the mock_controller)
+ filter.options.merge!(:if => nil, :unless => nil)
+
+ filter.__send__(:should_run_callback?, mock_controller)
+ }.map(&:to_sym)
+ end
+
+ def parse_method(method = '')
+ escape(method.inspect.gsub(RAILS_ROOT, ''))
+ end
+ end
+ end
+
+ module Extensions
+ class MockController < Struct.new(:action_name); end
+ end
+end
View
19 vendor/plugins/rails-footnotes/lib/notes/general_note.rb
@@ -0,0 +1,19 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class GeneralNote < AbstractNote
+ def title
+ 'General Debug'
+ end
+
+ def legend
+ 'General (id="general_debug_info")'
+ end
+
+ def content
+ 'You can use this tab to debug other parts of your application, for example Javascript.'
+ end
+ end
+ end
+end
View
16 vendor/plugins/rails-footnotes/lib/notes/javascripts_note.rb
@@ -0,0 +1,16 @@
+require "#{File.dirname(__FILE__)}/files_note"
+
+module Footnotes
+ module Notes
+ class JavascriptsNote < FilesNote
+ def title
+ "Javascripts (#{@files.length})"
+ end
+
+ protected
+ def scan_text(text)
+ text.scan(/<script[^>]+src\s*=\s*['"]([^>?'"]+\.js)/im).flatten
+ end
+ end
+ end
+end
View
33 vendor/plugins/rails-footnotes/lib/notes/layout_note.rb
@@ -0,0 +1,33 @@
+require "#{File.dirname(__FILE__)}/view_note"
+
+module Footnotes
+ module Notes
+ class LayoutNote < AbstractNote
+ def initialize(controller)
+ @controller = controller
+ @template = controller.instance_variable_get('@template')
+ end
+
+ def row
+ :edit
+ end
+
+ def link
+ escape(Footnotes::Filter.prefix + layout_filename)
+ end
+
+ def valid?
+ prefix? && @controller.active_layout && layout_template
+ end
+
+ protected
+ def layout_template
+ @layout_template ||= @template.__send__(:_pick_template, @controller.active_layout)
+ end
+
+ def layout_filename
+ layout_template.filename
+ end
+ end
+ end
+end
View
36 vendor/plugins/rails-footnotes/lib/notes/log_note.rb
@@ -0,0 +1,36 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class LogNote < AbstractNote
+ def initialize(controller)
+ @controller = controller
+ end
+
+ def content
+ escape(log_tail).gsub("\n","<br />")
+ end
+
+ protected
+ def log_tail
+ filename = if RAILS_DEFAULT_LOGGER.instance_variable_get('@log')
+ RAILS_DEFAULT_LOGGER.instance_variable_get('@log').path
+ else
+ RAILS_DEFAULT_LOGGER.instance_variable_get('@logdev').filename
+ end
+ file_string = File.open(filename).read.to_s
+
+ # We try to select the specified action from the log
+ # If we can't find it, we get the last 100 lines
+ #
+ if rindex = file_string.rindex('Processing '+@controller.controller_class_name+'#'+@controller.action_name)
+ file_string[rindex..-1].gsub(/\e\[.+?m/, '')
+ else
+ lines = file_string.split("\n")
+ index = [lines.size-100,0].max
+ lines[index..-1].join("\n")
+ end
+ end
+ end
+ end
+end
View
19 vendor/plugins/rails-footnotes/lib/notes/params_note.rb
@@ -0,0 +1,19 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class ParamsNote < AbstractNote
+ def initialize(controller)
+ @params = controller.params.symbolize_keys
+ end
+
+ def title
+ "Params (#{@params.length})"
+ end
+
+ def content
+ escape(@params.inspect)
+ end
+ end
+ end
+end
View
156 vendor/plugins/rails-footnotes/lib/notes/queries_note.rb
@@ -0,0 +1,156 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class QueriesNote < AbstractNote
+ @@sql = []
+ cattr_accessor :sql
+
+ def self.start!(controller)
+ @@sql = [] unless controller.instance_variable_get('@parent_controller')
+ end
+
+ def self.to_sym
+ :queries
+ end
+
+ def title
+ "Queries (#{@@sql.length})"
+ end
+
+ def stylesheet
+<<-STYLESHEET
+ #queries_debug_info table td, #queries_debug_info table th{border:1px solid #A00; padding:0 3px; text-align:center;}
+ #queries_debug_info table thead, #queries_debug_info table tbody {color:#A00;}
+ #queries_debug_info p {background-color:#F3F3FF; border:1px solid #CCC; margin:12px; padding:4px 6px;}
+ #queries_debug_info a:hover {text-decoration:underline;}
+STYLESHEET
+ end
+
+ def javascript
+<<-JAVASCRIPT
+ function queries_toogle(type, id){
+ s = document.getElementById('q'+type+'_'+id).style
+ s.display = (s.display != 'block') ? 'block' : 'none'
+ location.href = '#qtitle_'+id
+ }
+JAVASCRIPT
+ end
+
+ def content
+ html = ''
+
+ @@sql.each_with_index do |item, i|
+ sql_links = []
+ sql_links << "<a href=\"#\" style=\"color:#A00;\" onclick=\"queries_toogle('table',#{i});return false\">explain</a>" if item.explain
+ sql_links << "<a href=\"#\" style=\"color:#00A;\" onclick=\"queries_toogle('trace',#{i});return false\">trace</a>" if item.trace
+
+html << <<-HTML
+ <b id="qtitle_#{i}">#{escape(item.type.to_s.upcase)}</b> (#{sql_links.join(' | ')})<br />
+ #{print_name_and_time(item.name, item.time)}<br />
+ #{print_query(item.query)}<br />
+ #{print_explain(i, item.explain) if item.explain}
+ <p id="qtrace_#{i}" style="display:none;">#{parse_trace(item.trace) if item.trace}</p><br />
+HTML
+ end
+
+ return html
+ end
+
+ protected
+ def parse_explain(results)
+ table = []
+ table << results.fetch_fields.map(&:name)
+ results.each{|row| table << row}
+ table
+ end
+
+ def parse_trace(trace)
+ trace.map do |t|
+ s = t.split(':')
+ "<a href=\"#{escape("#{Footnotes::Filter.prefix}#{RAILS_ROOT}/#{s[0]}&line=#{s[1].to_i}")}\">#{escape(t)}</a><br />"
+ end.join
+ end
+
+ def print_name_and_time(name, time)
+ "#{escape(name || 'SQL')} (#{sprintf('%f', time)}s)"
+ end
+
+ def print_query(query)
+ escape(query.to_s.gsub(/(\s)+/, ' ').gsub('`', ''))
+ end
+
+ def print_explain(i, explain)
+ mount_table(parse_explain(explain), :id => "qtable_#{i}", :style => 'margin:10px;display:none;')
+ end
+ end
+ end
+
+ module Extensions
+ class Sql
+ attr_accessor :type, :name, :time, :query, :explain, :trace
+
+ def initialize(type, name, time, query, explain)
+ @type = type
+ @name = name
+ @time = time
+ @query = query
+ @explain = explain
+
+ # Strip, select those ones from app and reject first two, because they are from the plugin
+ @trace = Kernel.caller.collect(&:strip).select{|i| i.gsub!(/^#{RAILS_ROOT}\//im, '') }[2..-1]
+ end
+ end
+
+ module QueryAnalyzer
+ def self.included(base)
+ base.class_eval do
+ alias_method_chain :execute, :analyzer
+ end
+ end
+
+ def execute_with_analyzer(query, name = nil)
+ query_results = nil
+ time = Benchmark.realtime { query_results = execute_without_analyzer(query, name) }
+
+ if query =~ /^(select|create|update|delete)\b/i
+ type = $&.downcase.to_sym
+ explain = nil
+
+ if adapter_name == 'MySQL' && type == :select
+ log_silence do
+ explain = execute_without_analyzer("EXPLAIN #{query}", name)
+ end
+ end
+ Footnotes::Notes::QueriesNote.sql << Footnotes::Extensions::Sql.new(type, name, time, query, explain)
+ end
+
+ query_results
+ end
+ end
+
+ module AbstractAdapter
+ def log_silence
+ result = nil
+ if @logger
+ @logger.silence do
+ result = yield
+ end
+ else
+ result = yield
+ end
+ result
+ end
+ end
+
+ end
+end
+
+if Footnotes::Notes::QueriesNote.included?
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.__send__ :include, Footnotes::Extensions::AbstractAdapter
+ ActiveRecord::ConnectionAdapters.local_constants.each do |adapter|
+ next unless adapter =~ /.*[^Abstract]Adapter$/
+ next if adapter =~ /SQLite.Adapter$/
+ eval("ActiveRecord::ConnectionAdapters::#{adapter}").__send__ :include, Footnotes::Extensions::QueryAnalyzer
+ end
+end
View
59 vendor/plugins/rails-footnotes/lib/notes/routes_note.rb
@@ -0,0 +1,59 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class RoutesNote < AbstractNote
+ def initialize(controller)
+ @controller = controller
+ @parsed_routes = parse_routes
+ end
+
+ def legend
+ "Routes for #{@controller.class.to_s}"
+ end
+
+ def content
+ mount_table(@parsed_routes.unshift([:path, :name, :options, :requirements]))
+ end
+
+ protected
+ def parse_routes
+ routes_with_name = ActionController::Routing::Routes.named_routes.to_a.flatten
+
+ return ActionController::Routing::Routes.filtered_routes(:controller => @controller.controller_name).collect do |route|
+ # Catch routes name if exists
+ i = routes_with_name.index(route)
+ name = i ? routes_with_name[i-1].to_s : ''
+
+ # Catch segments requirements
+ req = {}
+ route.segments.each do |segment|
+ next unless segment.is_a?(ActionController::Routing::DynamicSegment) && segment.regexp
+ req[segment.key.to_sym] = segment.regexp
+ end
+
+ [escape(name), route.segments.join, route.requirements.reject{|key,value| key == :controller}.inspect, req.inspect]
+ end
+ end
+ end
+ end
+
+ module Extensions
+ module Routes
+ # Filter routes according to the filter sent
+ #
+ def filtered_routes(filter = {})
+ return [] unless filter.is_a?(Hash)
+ return routes.reject do |r|
+ filter_diff = filter.diff(r.requirements)
+ route_diff = r.requirements.diff(filter)
+ (filter_diff == filter) || (filter_diff != route_diff)
+ end
+ end
+ end
+ end
+end
+
+if Footnotes::Notes::RoutesNote.included?
+ ActionController::Routing::RouteSet.__send__ :include, Footnotes::Extensions::Routes
+end
View
15 vendor/plugins/rails-footnotes/lib/notes/session_note.rb
@@ -0,0 +1,15 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class SessionNote < AbstractNote
+ def initialize(controller)
+ @session = (controller.session.instance_variable_get("@data") || {}).symbolize_keys
+ end
+
+ def content
+ escape(@session.inspect)
+ end
+ end
+ end
+end
View
16 vendor/plugins/rails-footnotes/lib/notes/stylesheets_note.rb
@@ -0,0 +1,16 @@
+require "#{File.dirname(__FILE__)}/files_note"
+
+module Footnotes
+ module Notes
+ class StylesheetsNote < FilesNote
+ def title
+ "Stylesheets (#{@files.length})"
+ end
+
+ protected
+ def scan_text(text)
+ text.scan(/<link[^>]+href\s*=\s*['"]([^>?'"]+\.css)/im).flatten
+ end
+ end
+ end
+end
View
33 vendor/plugins/rails-footnotes/lib/notes/view_note.rb
@@ -0,0 +1,33 @@
+require "#{File.dirname(__FILE__)}/abstract_note"
+
+module Footnotes
+ module Notes
+ class ViewNote < AbstractNote
+ def initialize(controller)
+ @controller = controller
+ @template = controller.instance_variable_get(:@template)
+ end
+
+ def row
+ :edit
+ end
+
+ def link
+ escape(Footnotes::Filter.prefix + filename)
+ end
+
+ def valid?
+ prefix? && first_render?
+ end
+
+ protected
+ def first_render?
+ @template.instance_variable_get(:@_first_render)
+ end
+
+ def filename
+ @filename ||= @template.instance_variable_get(:@_first_render).filename
+ end
+ end
+ end
+end
View
21 vendor/plugins/rails-footnotes/templates/rescues/template_error.erb
@@ -0,0 +1,21 @@
+<h1>
+ <%=h @exception.original_exception.class.to_s %> in
+ <%=h request.parameters["controller"].capitalize if request.parameters["controller"]%>#<%=h request.parameters["action"] %>
+</h1>
+
+<p>
+ Showing <i><%=h @exception.file_name %></i> where line <b>#<%= @exception.line_number_link rescue @exception.line_number %></b> raised:
+ <pre><code><%=h @exception.message %></code></pre>
+</p>
+
+<p>Extracted source (around line <b>#<%= @exception.line_number_link rescue @exception.line_number %></b>):
+<pre><code><%=h @exception.source_extract %></code></pre></p>
+
+<p><%=h @exception.sub_template_message %></p>
+
+<% @real_exception = @exception
+ @exception = @exception.original_exception || @exception %>
+<%= render(@rescues_path + "/_trace.erb", false) %>
+<% @exception = @real_exception %>
+
+<%= render(@rescues_path + "/_request_and_response.erb", false) %>
View
190 vendor/plugins/rails-footnotes/test/footnotes_test.rb
@@ -0,0 +1,190 @@
+require File.dirname(__FILE__) + '/test_helper'
+
+require 'action_controller'
+require 'action_controller/test_case'
+require 'action_controller/test_process'
+
+class FootnotesController < ActionController::Base; attr_accessor :template, :performed_render; end
+
+module Footnotes::Notes
+ class TestNote < AbstractNote
+ def self.to_sym; :test; end
+ def valid?; true; end
+ end
+end
+
+class FootnotesTest < Test::Unit::TestCase
+ def setup
+ @controller = FootnotesController.new
+ @controller.request = ActionController::TestRequest.new
+ @controller.response = ActionController::TestResponse.new
+ @controller.response.body = $html.dup
+
+ Footnotes::Filter.notes = [ :test ]
+ Footnotes::Filter.multiple_notes = false
+ @footnotes = Footnotes::Filter.new(@controller)
+ end
+
+ def test_footnotes_controller
+ index = @controller.response.body.index(/This is the HTML page/)
+ assert_equal 334, index
+ end
+
+ def test_foonotes_included
+ footnotes_perform!
+ assert_not_equal $html, @controller.response.body
+ end
+
+ def test_footnotes_not_included_when_request_is_xhr
+ @controller.request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
+ @controller.request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*'
+
+ footnotes_perform!
+ assert_equal $html, @controller.response.body
+ end
+
+ def test_footnotes_not_included_when_content_type_is_javascript
+ @controller.response.headers['Content-Type'] = 'text/javascript'
+
+ footnotes_perform!
+ assert_equal $html, @controller.response.body
+ end
+
+ def test_footnotes_included_when_content_type_is_html
+ @controller.response.headers['Content-Type'] = 'text/html'
+
+ footnotes_perform!
+ assert_not_equal $html, @controller.response.body
+ end
+
+ def test_footnotes_included_when_content_type_is_nil
+ footnotes_perform!
+ assert_not_equal $html, @controller.response.body
+ end
+
+ def test_not_included_when_body_is_not_a_string
+ @controller.response.body = Proc.new{ Time.now }
+ @footnotes = Footnotes::Filter.new(@controller)
+ assert_nothing_raised do
+ footnotes_perform!
+ end
+ end
+
+ def test_notes_are_initialized
+ footnotes_perform!
+ test_note = @footnotes.instance_variable_get('@notes').first
+ assert 'Footnotes::Notes::TestNote', test_note.class
+ assert :test, test_note.to_sym
+ end
+
+ def test_notes_links
+ footnotes_perform!
+ @footnotes.instance_variable_get('@notes').first.expects(:row).times(2)
+ footnotes_perform!
+ end
+
+ def test_notes_fieldset
+ footnotes_perform!
+ @footnotes.instance_variable_get('@notes').first.expects(:fieldset?).times(3)
+ footnotes_perform!
+ end
+
+ def test_multiple_notes
+ Footnotes::Filter.multiple_notes = true
+ footnotes_perform!
+ @footnotes.instance_variable_get('@notes').first.expects(:fieldset?).times(2)
+ footnotes_perform!
+ end
+
+ def test_notes_are_reset
+ footnotes_perform!
+ @footnotes.instance_variable_get('@notes').first.class.expects(:close!)
+ @footnotes.send(:close!, @controller)
+ end
+
+ def test_links_helper
+ note = Footnotes::Notes::TestNote.new
+ note.expects(:title).times(2).returns(:title)
+ assert_equal '<a href="#" onclick="">title</a>', @footnotes.send(:link_helper, note)
+
+ note.expects(:link).times(1).returns(:link)
+ assert_equal '<a href="link" onclick="">title</a>', @footnotes.send(:link_helper, note)
+ end
+
+ def test_links_helper_fieldset?
+ note = Footnotes::Notes::TestNote.new
+ note.expects(:title).times(1).returns(:title)
+ note.expects(:fieldset?).times(1).returns(true)
+ assert_equal '<a href="#" onclick="footnotes_toogle(\'test_debug_info\');return false;">title</a>', @footnotes.send(:link_helper, note)
+ end
+
+ def test_links_helper_onclick
+ note = Footnotes::Notes::TestNote.new
+ note.expects(:title).times(2).returns(:title)
+ note.expects(:onclick).times(2).returns(:onclick)
+ assert_equal '<a href="#" onclick="onclick">title</a>', @footnotes.send(:link_helper, note)
+
+ note.expects(:fieldset?).times(1).returns(true)
+ assert_equal '<a href="#" onclick="onclick">title</a>', @footnotes.send(:link_helper, note)
+ end
+
+ def test_insert_style
+ @controller.response.body = "<head></head><split><body></body>"
+ @footnotes = Footnotes::Filter.new(@controller)
+ footnotes_perform!
+ assert @controller.response.body.split('<split>').first.include?('<!-- Footnotes Style -->')
+ end
+
+ def test_insert_footnotes_inside_body
+ @controller.response.body = "<head></head><split><body></body>"
+ @footnotes = Footnotes::Filter.new(@controller)
+ footnotes_perform!
+ assert @controller.response.body.split('<split>').last.include?('<!-- End Footnotes -->')
+ end
+
+ def test_insert_footnotes_inside_holder
+ @controller.response.body = "<head></head><split><div id='footnotes_holder'></div>"
+ @footnotes = Footnotes::Filter.new(@controller)
+ footnotes_perform!
+ assert @controller.response.body.split('<split>').last.include?('<!-- End Footnotes -->')
+ end
+
+ def test_insert_text
+ @footnotes.send(:insert_text, :after, /<head>/, "Graffiti")
+ after = " <head>Graffiti\n"
+ assert_equal after, @controller.response.body.to_a[2]
+
+ @footnotes.send(:insert_text, :before, /<\/body>/, "Notes")
+ after = " Notes</body>\n"
+ assert_equal after, @controller.response.body.to_a[12]
+ end
+
+ protected
+ # First we make sure that footnotes will perform (long life to mocha!)
+ # Then we call add_footnotes!
+ #
+ def footnotes_perform!
+ @controller.template.expects(:instance_variable_get).returns(true)
+ @controller.template.expects(:template_format).returns('html')
+ @controller.performed_render = true
+
+ @footnotes.add_footnotes!
+ end
+end
+
+$html = <<HTML
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>HTML to XHTML Example: HTML page</title>
+ <link rel="Stylesheet" href="htmltohxhtml.css" type="text/css" media="screen">
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+ </head>
+ <body>
+ <p>This is the HTML page. It works and is encoded just like any HTML page you
+ have previously done. View <a href="htmltoxhtml2.htm">the XHTML version</a> of
+ this page to view the difference between HTML and XHTML.</p>
+ <p>You will be glad to know that no changes need to be made to any of your CSS files.</p>
+ </body>
+</html>
+HTML
View
108 vendor/plugins/rails-footnotes/test/notes/abstract_note_test.rb
@@ -0,0 +1,108 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class AbstractNoteTest < Test::Unit::TestCase
+ def setup
+ @note = Footnotes::Notes::AbstractNote.new
+ Footnotes::Filter.notes = [:abstract]
+ end
+
+ def test_respond_to_start_and_close
+ assert_respond_to Footnotes::Notes::AbstractNote, :start!
+ assert_respond_to Footnotes::Notes::AbstractNote, :close!
+ end
+
+ def test_respond_to_sym
+ assert_equal :abstract, Footnotes::Notes::AbstractNote.to_sym
+ assert_equal :abstract, @note.to_sym
+ end
+
+ def test_respond_to_included?
+ assert Footnotes::Notes::AbstractNote.included?
+ assert @note.included?
+ Footnotes::Filter.notes = []
+ assert !Footnotes::Notes::AbstractNote.included?
+ assert !@note.included?
+ end
+
+ def test_respond_to_row
+ assert_equal :show, @note.row
+ end
+
+ def test_respond_to_title
+ assert_respond_to @note, :title
+ end
+
+ def test_respond_to_legend
+ assert_respond_to @note, :legend
+ end
+
+ def test_respond_to_link
+ assert_respond_to @note, :link
+ end
+
+ def test_respond_to_onclick
+ assert_respond_to @note, :onclick
+ end
+
+ def test_respond_to_stylesheet
+ assert_respond_to @note, :stylesheet
+ end
+
+ def test_respond_to_javascript
+ assert_respond_to @note, :javascript
+ end
+
+ def test_respond_to_valid?
+ assert_respond_to @note, :valid?
+ assert @note.valid?
+ end
+
+ def test_respond_to_fieldset?
+ assert_respond_to @note, :fieldset?
+ assert !@note.fieldset?
+ end
+
+ def test_footnotes_prefix
+ assert !@note.send(:prefix?)
+ Footnotes::Filter.prefix = 'texteditor://open?url=file://'
+ assert @note.send(:prefix?)
+ end
+
+ def test_footnotes_escape
+ assert_equal '&lt;', @note.send(:escape,'<')
+ assert_equal '&amp;', @note.send(:escape,'&')
+ assert_equal '&gt;', @note.send(:escape,'>')
+ end
+
+ def test_footnotes_mount_table
+ assert_equal '', @note.send(:mount_table,[])
+ assert_equal '', @note.send(:mount_table,[['h1','h2','h3']], :class => 'table')
+
+ tab = <<-TABLE
+ <table class="table">
+ <thead><tr><th>H1</th></tr></thead>
+ <tbody><tr><td>r1c1</td></tr></tbody>
+ </table>
+ TABLE
+
+ assert_equal tab, @note.send(:mount_table,[['h1'],['r1c1']], :class => 'table')
+
+ tab = <<-TABLE
+ <table >
+ <thead><tr><th>H1</th><th>H2</th><th>H3</th></tr></thead>
+ <tbody><tr><td>r1c1</td><td>r1c2</td><td>r1c3</td></tr></tbody>
+ </table>
+ TABLE
+
+ assert_equal tab, @note.send(:mount_table,[['h1','h2','h3'],['r1c1','r1c2','r1c3']])
+
+ tab = <<-TABLE
+ <table >
+ <thead><tr><th>H1</th><th>H2</th><th>H3</th></tr></thead>
+ <tbody><tr><td>r1c1</td><td>r1c2</td><td>r1c3</td></tr><tr><td>r2c1</td><td>r2c2</td><td>r2c3</td></tr></tbody>
+ </table>
+ TABLE
+
+ assert_equal tab, @note.send(:mount_table,[['h1','h2','h3'],['r1c1','r1c2','r1c3'],['r2c1','r2c2','r2c3']])
+ end
+end
View
9 vendor/plugins/rails-footnotes/test/test_helper.rb
@@ -0,0 +1,9 @@
+require 'test/unit'
+require 'rubygems'
+require 'mocha'
+
+ENV["RAILS_ENV"] = "test"
+
+require 'active_support'
+require File.dirname(__FILE__) + '/../lib/footnotes'
+require File.dirname(__FILE__) + '/../lib/notes/abstract_note'

0 comments on commit d307862

Please sign in to comment.