Class: Nokogiri::XML::Element
- Inherits:
-
Object
- Object
- Nokogiri::XML::Element
- Defined in:
- lib/html2fortitude/html.rb
Overview
Constant Summary collapse
- BUILT_IN_RENDERING_HELPERS =
%w{render}
- VALID_JAVASCRIPT_SCRIPT_TYPES =
[ 'text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript']
- VALID_JAVASCRIPT_LANGUAGE_TYPES =
[ 'javascript', 'ecmascript' ]
- VALID_CSS_TYPES =
[ 'text/css' ]
Instance Method Summary collapse
-
#can_skip_text_or_rawtext_prefix?(code) ⇒ Boolean
Given a section of code that we're going to output, can we skip putting 'text' or 'rawtext' in front of it? We can do this under the following scenarios:.
-
#code_can_be_used_as_a_method_argument?(code) ⇒ Boolean
Given a section of code that we're going to output, can we use it as a method argument directly? Or do we need to nest it inside a block to the tag?.
-
#contents_as_direct_input_to_tag(tag_name, tabs, options, attributes_hash) ⇒ Object
Some HTML tags like
Given a section of code that we're going to output, can we skip putting 'text' or 'rawtext' in front of it? We can do this under the following scenarios:
- The code is a single line, and contains no semicolons; and
- The method it's calling is either 'render' (which Fortitude implements internally) or a helper method that Fortitude automatically outputs the return value from.
415 416 417 418 419 420 421 422 423
# File 'lib/html2fortitude/html.rb', line 415 def can_skip_text_or_rawtext_prefix?(code) return false if code =~ /[\r\n]/mi return false if code =~ /;/mi method = $1 if code =~ /^\s*([A-Za-z_][A-Za-z0-9_]*[\!\?\=]?)[\s\(]/ method ||= $1 if code =~ /^\s*([A-Za-z_][A-Za-z0-9_]*[\!\?\=]?)$/ = Fortitude::Rails::Helpers.(method.strip.downcase) if method ( && [:transform] == :output_return_value) || (method && BUILT_IN_RENDERING_HELPERS.include?(method.strip.downcase)) end
#code_can_be_used_as_a_method_argument?(code) ⇒ Boolean
Given a section of code that we're going to output, can we use it as a method argument directly? Or do we need to nest it inside a block to the tag?
In other words, can we say just:
p(...code...)
...or do we need to say:
p { text(...code...) }
437 438 439
# File 'lib/html2fortitude/html.rb', line 437 def code_can_be_used_as_a_method_argument?(code) code !~ /[\r\n;]/ && (! can_skip_text_or_rawtext_prefix?(code)) end
#contents_as_direct_input_to_tag(tag_name, tabs, options, attributes_hash) ⇒ Object
Some HTML tags like
If this is a
This is used to support blocks like form_for -- this tells the next element that it needs to put a close parenthesis on the end, since we end up outputting something like:
text(form_for do |f| text(f.text_field :name) end)
452 453 454
# File 'lib/html2fortitude/html.rb', line 452 def is_loud_block! @is_loud_block = true end
#is_text_element_starting_with_newline?(node) ⇒ Boolean
Kinda just like what it says ;)
442 443 444
# File 'lib/html2fortitude/html.rb', line 442 def is_text_element_starting_with_newline?(node) node && node.is_a?(::Nokogiri::XML::Text) && node.to_s =~ /^\s*[\r\n]/ end
#result_for_fortitude_tag(tabs, options, output) ⇒ Object
If this is a
, , or element, return the Fortitude code for it. Otherwise, returns nil. 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
# File 'lib/html2fortitude/html.rb', line 515 def result_for_fortitude_tag(tabs, , output) # Here's where the real heart of a lot of our ERb processing happens. We process the special tags: # # * +<fortitude_loud>+ -- equivalent to ERb's +<%= %>+; # * +<fortitude_silent>+ -- equivalent to ERb's +<% %>+; # * +<fortitude_block>+ -- used when a +<%=+ or +<%+ starts a block of Ruby code; encloses the whole thing if FORTITUDE_TAGS.include?(name) case name # This is ERb +<%= %>+ -- i.e., code we need to output the return value of when "fortitude_loud" # Extract any instance variables, add 'needs' for them, and turn them into method calls t = extract_needs_from!(CGI.unescapeHTML(inner_text), ) lines = t.split("\n").map { |s| s.strip } outputting_method = if attribute("raw") then "rawtext" else "text" end # Handle this case: # <%= form_for(@user) do |f| %> # <%= f.whatever %> # <% end %> if self.next && self.next.is_a?(::Nokogiri::XML::Element) && self.next.name == 'fortitude_block' self.next.is_loud_block! # What gets output is whatever the code returns, so we put the method on the last line of the block lines[-1] = "#{outputting_method}(" + lines[-1] elsif lines.length == 1 && can_skip_text_or_rawtext_prefix?(lines.first) # OK, we're good -- this means there's only a single line, and we're calling a Rails helper method # that automatically outputs, so we don't actually have to use 'text' or 'rawtext' else # What gets output is whatever the code returns, so we put the method on the last line of the block lines[-1] = "#{outputting_method}(" + lines[-1] + ")" end return lines.map {|s| output + s + "\n"}.join # This is ERb +<% %>+ -- i.e., code we just need to run when "fortitude_silent" # Extract any instance variables, add 'needs' for them, and turn them into method calls t = extract_needs_from!(CGI.unescapeHTML(inner_text), ) return t.split("\n").map do |line| next "" if line.strip.empty? "#{output}#{line.strip}\n" end.join # This is ERb +<%+ or +<%=+ that starts a Ruby block when "fortitude_block" needs_coda = true unless self.next && self.next.is_a?(::Nokogiri::XML::Element) && self.next.name == 'fortitude_silent' && self.next.inner_text =~ /^\s*els(e|if)\s*$/i coda = if needs_coda then "\n#{tabulate(tabs)}end" else "" end coda << ")" if @is_loud_block coda << "\n" children_text = render_children("", tabs, ).rstrip return children_text + coda when "fortitude_spacer" return %{text " "\n} else raise "Unknown special tag: #{name.inspect}" end end end
#to_fortitude(tabs, options) ⇒ Object
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
# File 'lib/html2fortitude/html.rb', line 574 def to_fortitude(tabs, ) return "" if converted_to_fortitude # Get <script> and <style> elements out of the way. direct_input = contents_for_direct_input(tabs, ) return direct_input if direct_input output = tabulate(tabs) # Get <fortitude_loud>, <fortitude_silent>, and <fortitude_block> elements out of the way. fortitude_result = result_for_fortitude_tag(tabs, , output) return fortitude_result if fortitude_result output << "#{name}" attributes_text = fortitude_attributes() if attr_hash && attr_hash.length > 0 direct_content = nil render_children = true # If the element only has a single run of text as its content, try just passing it as a direct argument to # our tag method, rather than starting a block if children.try(:size) == 1 && children.first.is_a?(::Nokogiri::XML::Text) direct_content = quoted_string_for_text(child.to_s.strip) render_children = false # If the element only has one thing as its content, and that's an ERb +<%= %>+ block, try just passing that # code directly as a method argument, if we can do that elsif children.try(:size) == 1 && children.first.is_a?(::Nokogiri::XML::Element) && children.first.name == "fortitude_loud" && code_can_be_used_as_a_method_argument?(child.inner_text) it = extract_needs_from!(child.inner_text, ) direct_content = "#{it.strip}" # Put parentheses around it if we have attributes, and it's a method call without parentheses direct_content = "(#{direct_content})" if attributes_text && direct_content =~ /^\s*[A-Za-z_][A-Za-z0-9_]*[\!\?\=]?\s+\S/ render_children = false end # Produce the arguments to our tag method... if attributes_text && direct_content output << "(#{direct_content}, #{attributes_text})" elsif direct_content output << "(#{direct_content})" elsif attributes_text output << "(#{attributes_text})" end # Render the children, if we need to. if render_children && children && children.size >= 1 children_output = render_children("", tabs, ).strip output << " #{element_block_start()}\n" output << tabulate(tabs + 1) output << children_output output << "\n#{tabulate(tabs)}#{element_block_end()}\n" else output << "\n" unless is_text_element_starting_with_newline?(self.next) end output end