dry_haml_handlebars 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/.project +18 -0
- data/.rvmrc +1 -0
- data/Gemfile +5 -0
- data/MIT-LICENSE +20 -0
- data/README.md +76 -0
- data/Rakefile +1 -0
- data/dry_haml_handlebars.gemspec +30 -0
- data/lib/action_controller/base.rb +80 -0
- data/lib/action_view/base.rb +31 -0
- data/lib/action_view/helpers/capture_helper.rb +20 -0
- data/lib/dry_haml_handlebars/handler.rb +395 -0
- data/lib/dry_haml_handlebars/register.rb +9 -0
- data/lib/dry_haml_handlebars/version.rb +3 -0
- data/lib/dry_haml_handlebars.rb +149 -0
- data/vendor/assets/javascripts/underscore.js +1065 -0
- metadata +135 -0
data/.gitignore
ADDED
data/.project
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<projectDescription>
|
3
|
+
<name>dry_haml_handlebars</name>
|
4
|
+
<comment></comment>
|
5
|
+
<projects>
|
6
|
+
</projects>
|
7
|
+
<buildSpec>
|
8
|
+
<buildCommand>
|
9
|
+
<name>com.aptana.ide.core.unifiedBuilder</name>
|
10
|
+
<arguments>
|
11
|
+
</arguments>
|
12
|
+
</buildCommand>
|
13
|
+
</buildSpec>
|
14
|
+
<natures>
|
15
|
+
<nature>org.radrails.rails.core.railsnature</nature>
|
16
|
+
<nature>com.aptana.ruby.core.rubynature</nature>
|
17
|
+
</natures>
|
18
|
+
</projectDescription>
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.2-p180@dry_haml_handlebars --create
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
**NOTE** this gem is work in progress, I'll flesh out the instructions once it's stabilized
|
2
|
+
|
3
|
+
dry_haml_handlebars plugin
|
4
|
+
============
|
5
|
+
|
6
|
+
This gem may be of use to you if:
|
7
|
+
|
8
|
+
* angle brackets burn your eyes (read: you like using haml)
|
9
|
+
* NOTE: if you're fine with angle brackets, stop reading, you're probably better off just using mustache
|
10
|
+
* see http://railscasts.com/episodes/295-sharing-mustache-templates
|
11
|
+
* you want your app to consume its own API and do most rendering clientside (e.g. using backbone.js, spine.js etc.)
|
12
|
+
* but you still need to render server-side (so the googlebot and paranoid no-js people can see your lovely, lovely content)
|
13
|
+
* and, importantly, you prefer DRY apps to WET ones (i.e. you don't want to write equivalent clientside and serverside templates)
|
14
|
+
|
15
|
+
Still here? Ok, this gem lets you:
|
16
|
+
|
17
|
+
* write templates using a haml/handlebars.js hybrid
|
18
|
+
* the haml describes the structure of the document while the handlebars syntax is used for substitution and logical flow
|
19
|
+
* it assumes you are using the rabl gem to generate JSON data for your view
|
20
|
+
|
21
|
+
What it does is:
|
22
|
+
|
23
|
+
* convert your hybrid templates to valid haml in which the handlebars markup is just treated as text
|
24
|
+
* then runs that through the standard haml handler to generate regular handlebars templates (html + curly braces)
|
25
|
+
* when rendering serverside it uses execjs and your rabl-generated JSON to render the template
|
26
|
+
* but it also ships pre-compiled versions of your templates and JSON data to the client (using the gon gem) so that you can switch to clientside rendering for subsequent requests
|
27
|
+
|
28
|
+
Installation
|
29
|
+
=======
|
30
|
+
|
31
|
+
Add this to your Gemfile if using Bundler: `gem 'dry_haml_handlebars'`
|
32
|
+
|
33
|
+
Or install the gem from the command line: `gem install dry_haml_handlebars`
|
34
|
+
|
35
|
+
Setup
|
36
|
+
=======
|
37
|
+
|
38
|
+
Usage
|
39
|
+
=====
|
40
|
+
|
41
|
+
Hybrid haml/handlebars syntax
|
42
|
+
-----------------------------
|
43
|
+
|
44
|
+
The syntax for your templates is a readable mix of haml and handlebars:
|
45
|
+
|
46
|
+
```haml
|
47
|
+
.entry
|
48
|
+
.h1 {{title}}
|
49
|
+
{{#if subtitle}}
|
50
|
+
.h2 {{subtitle}}
|
51
|
+
{{/if}}
|
52
|
+
.h3 By
|
53
|
+
= link_to "{{author.name}}", user_path("{{author.id}}"), 'data-remote' => true
|
54
|
+
posted at {{localize created_at}}
|
55
|
+
.body
|
56
|
+
{{{body}}}
|
57
|
+
```
|
58
|
+
|
59
|
+
Benefits:
|
60
|
+
|
61
|
+
* the brevity and structural clarity that haml provides
|
62
|
+
* the ability to use standard rails helpers to generate html
|
63
|
+
* concise flow constrol and substitution via handlebars
|
64
|
+
* the ability to use custom handlebars helpers (e.g. localize)
|
65
|
+
* seamless integration with your JSON API - structure the JSON (via rabl), then structure the view around it
|
66
|
+
|
67
|
+
*more to follow...*
|
68
|
+
|
69
|
+
Acknowledgements
|
70
|
+
================
|
71
|
+
|
72
|
+
Thanks to the authors of:
|
73
|
+
|
74
|
+
* the handlebars gem (made server side compilation easy)
|
75
|
+
|
76
|
+
Copyright (c) 2012 PeepAll Ltd, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "dry_haml_handlebars/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "dry_haml_handlebars"
|
7
|
+
s.version = DryHamlHandlebars::VERSION
|
8
|
+
s.authors = ["Jonathan Chambers"]
|
9
|
+
s.email = ["j.chambers@gmx.net"]
|
10
|
+
s.homepage = "https://github.com/jmchambers/dry_haml_handlebars"
|
11
|
+
s.summary = "Write haml templates, use both server and clientside (via handlebars.js)"
|
12
|
+
s.description = "Write haml views once, and then use them for both server and clientside rendering (using automagically precompiled handlebars templates)"
|
13
|
+
|
14
|
+
s.rubyforge_project = "dry_haml_handlebars"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "rails", "~> 3.2.0"
|
22
|
+
s.add_dependency "therubyracer"
|
23
|
+
s.add_dependency "haml-rails", "~> 0.3.4"
|
24
|
+
s.add_dependency "handlebars_assets", "~> 0.4.4" # was "~> 0.4.4"
|
25
|
+
s.add_dependency "rabl", "0.7.1" # "0.6.12" #this is locked down because the author's minor increments consistently break everything, grrrrr!
|
26
|
+
s.add_dependency "gon", "~> 3.0.2"
|
27
|
+
|
28
|
+
s.license = 'MIT'
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ActionController
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def render_extra_content_for(*args)
|
5
|
+
options = args.extract_options!
|
6
|
+
args.each do |identifier|
|
7
|
+
name, path = get_content_for_name_and_path(identifier, options)
|
8
|
+
DryHamlHandlebars.content_cache.add_item(name, path)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def get_content_for_name_and_path(identifier, options)
|
16
|
+
|
17
|
+
case identifier
|
18
|
+
when Symbol
|
19
|
+
|
20
|
+
name = identifier
|
21
|
+
|
22
|
+
possible_folders = [
|
23
|
+
Rails.root.join( *%w[app views] << params[:controller] ).to_s,
|
24
|
+
Rails.root.join( *%w[app views application] ).to_s
|
25
|
+
]
|
26
|
+
|
27
|
+
if folders = options[:prepend_search_folders]
|
28
|
+
possible_folders = folders + possible_folders
|
29
|
+
end
|
30
|
+
|
31
|
+
if folders = options[:append_search_folders]
|
32
|
+
possible_folders += folders
|
33
|
+
end
|
34
|
+
|
35
|
+
possible_filenames = [
|
36
|
+
"#{params[:action]}_#{name}.html.haml",
|
37
|
+
"#{name}.html.haml",
|
38
|
+
"#{params[:action]}_content_for_#{name}.html.haml",
|
39
|
+
"content_for_#{name}.html.haml"
|
40
|
+
]
|
41
|
+
|
42
|
+
possible_paths = []
|
43
|
+
|
44
|
+
possible_folders.each do |folder|
|
45
|
+
possible_filenames.each do |fname|
|
46
|
+
possible_paths << File.join( folder, fname )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
path = possible_paths.find { |p| File.exist?(p) }
|
51
|
+
raise "couldn't find any of the following expected files:\n#{possible_paths.join("\n")}" if path.nil?
|
52
|
+
|
53
|
+
when Array
|
54
|
+
|
55
|
+
path = Rails.root.join( *%w[app views] << "#{identifier.last}.html.haml" ).to_s
|
56
|
+
name = identifier.first.to_sym
|
57
|
+
|
58
|
+
when String
|
59
|
+
|
60
|
+
path = Rails.root.join( *%w[app views] << "#{identifier}.html.haml" ).to_s
|
61
|
+
name_match = identifier.match(/.*content_for_(?<name>\w*)/)
|
62
|
+
if name_match
|
63
|
+
name = name_match[:name].to_sym
|
64
|
+
else
|
65
|
+
name = identifier
|
66
|
+
end
|
67
|
+
|
68
|
+
else
|
69
|
+
raise ArgumentError, "expected identifier to be a Array, Symbol or String, but got #{identifier}"
|
70
|
+
end
|
71
|
+
|
72
|
+
raise "the file #{path} does not exist" unless File.exist?(path)
|
73
|
+
|
74
|
+
return name, path
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActionView
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def handlebars_render(*args, &block)
|
5
|
+
|
6
|
+
#we simply wrap render so that we can detect that 'handlebars_render' was the calling function
|
7
|
+
#we do this by adding a local variable :handlebars_partial => true
|
8
|
+
|
9
|
+
if args.first.is_a?(Hash)
|
10
|
+
|
11
|
+
options = args.first
|
12
|
+
options[:locals] ||= {}
|
13
|
+
options[:locals].merge!(:__handlebars_partial => true)
|
14
|
+
|
15
|
+
elsif args.last.is_a?(Hash)
|
16
|
+
|
17
|
+
locals = args.last
|
18
|
+
locals[:__handlebars_partial] = true
|
19
|
+
|
20
|
+
else
|
21
|
+
|
22
|
+
args << {:__handlebars_partial => true}
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
render(*args, &block)
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module CaptureHelper
|
4
|
+
|
5
|
+
# WARNING: content_for is ignored in caches. So you shouldn't use it
|
6
|
+
# for elements that will be fragment cached.
|
7
|
+
def handlebars_content_for(name, content = nil, flush = false)
|
8
|
+
|
9
|
+
if content
|
10
|
+
flush ? @view_flow.set(name, content) : @view_flow.append(name, content)
|
11
|
+
nil
|
12
|
+
else
|
13
|
+
@view_flow.get(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,395 @@
|
|
1
|
+
module DryHamlHandlebars
|
2
|
+
|
3
|
+
INDENT = /\A(?<indent>\s*)/
|
4
|
+
CONTENT = /#{INDENT}\S+.*\Z/
|
5
|
+
BLOCK_START = /(?<start>#{INDENT}{{#(?<keyword>\w+))/
|
6
|
+
|
7
|
+
require 'haml/template/plugin'
|
8
|
+
|
9
|
+
def self.dedent_hbs(source)
|
10
|
+
lines = source.lines.to_a
|
11
|
+
mod_lines = lines.clone
|
12
|
+
lines.each_with_index do |line1, i1|
|
13
|
+
|
14
|
+
if (l1_match = line1.match BLOCK_START)
|
15
|
+
|
16
|
+
l1_index = i1
|
17
|
+
l1_indent = l1_match[:indent] ? l1_match[:indent].length : 0
|
18
|
+
l1_text = l1_match[:start]
|
19
|
+
|
20
|
+
#binding.pry if i1 == 7
|
21
|
+
|
22
|
+
next_match = nil
|
23
|
+
next_line = lines[l1_index+1..-1].detect { |l| next_match = l.match(CONTENT) }
|
24
|
+
|
25
|
+
next unless next_match
|
26
|
+
next_line_indent = next_match[:indent] ? next_match[:indent].length : 0
|
27
|
+
next unless (indent = next_line_indent - l1_indent) > 0
|
28
|
+
|
29
|
+
|
30
|
+
l2_text = l1_text.sub("{{#", "{{/")
|
31
|
+
else_text = " " * l1_indent + "{{else}}"
|
32
|
+
else_index = nil
|
33
|
+
l2_index = lines[l1_index+1..-1].each_with_index.each do |line2, i2|
|
34
|
+
else_index = i2 if line2.starts_with? else_text
|
35
|
+
break i2 + l1_index+1 if line2.starts_with? l2_text
|
36
|
+
end
|
37
|
+
|
38
|
+
(l1_index+1..l2_index-1).each_with_index do |index, i|
|
39
|
+
next if i == else_index
|
40
|
+
mod_lines[index] = mod_lines[index][indent..-1]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
mod_lines.join
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
attr_accessor :on_next_request
|
50
|
+
end
|
51
|
+
|
52
|
+
class Handler < Haml::Plugin
|
53
|
+
|
54
|
+
class << self
|
55
|
+
|
56
|
+
def call(template, options = {})
|
57
|
+
|
58
|
+
view_match = template.identifier.match(/^#{Rails.root.join('app', 'views')}[\/](?<view_path>[\/\w]+)[\/](?<view_name>\w+).html/)
|
59
|
+
relative_view_path = view_match[:view_path]
|
60
|
+
view_name = view_match[:view_name]
|
61
|
+
view_type = get_view_type(template, relative_view_path, view_name)
|
62
|
+
|
63
|
+
env = Rails.env.to_sym
|
64
|
+
out = []
|
65
|
+
|
66
|
+
#when in dev mode we can set this variable to true on each request (in the app controller)
|
67
|
+
#and we scan for all changed partials (whether needed for the current view or not)
|
68
|
+
#this is intended to ensure that all changes are picked up ready for deployment
|
69
|
+
#even if the dev forgets to run the view that requires a changed partial
|
70
|
+
#the rule is, render ANY page, and ALL partials should be re-compiled (if needed)
|
71
|
+
#while for changed templates, you MUST run the view that you have changed
|
72
|
+
if DryHamlHandlebars.on_next_request.values.any?
|
73
|
+
DryHamlHandlebars.on_next_request.keys.each do |method|
|
74
|
+
DryHamlHandlebars.on_next_request[method] = false
|
75
|
+
case method
|
76
|
+
when :compile_all_partials
|
77
|
+
out += compile_and_load_all_partials
|
78
|
+
else
|
79
|
+
DryHamlHandlebars.send method
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
if [:layout, :ignored_partial].include? view_type
|
85
|
+
out << super(template)
|
86
|
+
return out.join("\n")
|
87
|
+
end
|
88
|
+
|
89
|
+
partial_name = [relative_view_path.gsub('/', '_'), view_name[1..-1]].join('_')
|
90
|
+
rabl_path, template_path, compiled_template_path = generate_file_names(relative_view_path, view_name)
|
91
|
+
if options[:force_handlebars_compile] or !File.exist?(compiled_template_path) or ( [:development, :test].include?(env) and ( File.mtime(compiled_template_path) < File.mtime(template.identifier) ) )
|
92
|
+
source = template.source
|
93
|
+
source = DryHamlHandlebars.dedent_hbs(source)
|
94
|
+
template.instance_variable_set "@source", source
|
95
|
+
rendered_haml = <<-RUBY
|
96
|
+
rendered_haml = eval(%q( #{super(template)} )).html_safe
|
97
|
+
RUBY
|
98
|
+
else
|
99
|
+
rendered_haml = nil
|
100
|
+
end
|
101
|
+
|
102
|
+
runner = Runner.new(
|
103
|
+
template,
|
104
|
+
rendered_haml,
|
105
|
+
view_type,
|
106
|
+
view_name,
|
107
|
+
partial_name,
|
108
|
+
relative_view_path,
|
109
|
+
rabl_path,
|
110
|
+
template_path,
|
111
|
+
compiled_template_path
|
112
|
+
)
|
113
|
+
|
114
|
+
out << runner.run
|
115
|
+
out.join("\n")
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
def compile_and_load_all_partials
|
120
|
+
partials = Dir.glob(Rails.root.join('app', 'views', '**', '_*.html.haml'))
|
121
|
+
out = []
|
122
|
+
partials.each do |fname|
|
123
|
+
File.open(fname) do |file|
|
124
|
+
source = file.read
|
125
|
+
next unless source.starts_with?('-#handlebars_partial')
|
126
|
+
source = DryHamlHandlebars.dedent_hbs(source)
|
127
|
+
template = ActionView::Template.new(source, fname, nil, {:locals => ["__handlebars_partial"]})
|
128
|
+
out << call(template, :force_handlebars_compile => true)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
out
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_view_type(template, relative_view_path, view_name)
|
135
|
+
|
136
|
+
#we have 4 types of view;
|
137
|
+
# 1) layout - always handled by haml, no hbs/js versions are generated
|
138
|
+
# 2) template - rendered as handlebars, we expect there to be html.haml AND .rabl for the JSON
|
139
|
+
# 3) partial - pulled into view by handlebars syntax {{>name}}
|
140
|
+
# 4) ignored_partial - a regular partial, it will be rendered by Haml, with no handlebars-related processing
|
141
|
+
|
142
|
+
if relative_view_path == 'layouts'
|
143
|
+
:layout
|
144
|
+
elsif template.locals.include?("__handlebars_partial")
|
145
|
+
:partial
|
146
|
+
elsif view_name.starts_with? "_"
|
147
|
+
:ignored_partial
|
148
|
+
else
|
149
|
+
:template
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
def generate_file_names(relative_view_path, view_name)
|
155
|
+
|
156
|
+
template_partial_path = Rails.root.join( *%w(app assets templates) << "#{relative_view_path}" )
|
157
|
+
compiled_template_partial_path = Rails.root.join( *%w(app assets compiled_templates) << "#{relative_view_path}" )
|
158
|
+
|
159
|
+
rabl_path = Rails.root.join( 'app', 'views', relative_view_path, "#{view_name}.rabl" )
|
160
|
+
template_path = File.join( template_partial_path, "#{view_name}.hbs" )
|
161
|
+
compiled_template_path = File.join( compiled_template_partial_path, "#{view_name}.js" )
|
162
|
+
|
163
|
+
FileUtils.mkdir_p template_partial_path unless File.directory? template_partial_path
|
164
|
+
FileUtils.mkdir_p compiled_template_partial_path unless File.directory? compiled_template_partial_path
|
165
|
+
|
166
|
+
return rabl_path, template_path, compiled_template_path
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
class Runner
|
175
|
+
|
176
|
+
def initialize(template, rendered_haml = nil, view_type, view_name, partial_name, relative_view_path, rabl_path, template_path, compiled_template_path)
|
177
|
+
@template = template
|
178
|
+
@rendered_haml = rendered_haml
|
179
|
+
@view_type = view_type
|
180
|
+
@view_name = view_name
|
181
|
+
@partial_name = partial_name
|
182
|
+
@relative_view_path = relative_view_path
|
183
|
+
@rabl_path = rabl_path
|
184
|
+
@template_path = template_path
|
185
|
+
@compiled_template_path = compiled_template_path
|
186
|
+
end
|
187
|
+
|
188
|
+
def run
|
189
|
+
|
190
|
+
content_cache = DryHamlHandlebars.content_cache
|
191
|
+
out = []
|
192
|
+
|
193
|
+
if @rendered_haml
|
194
|
+
|
195
|
+
out << @rendered_haml
|
196
|
+
out << compile_hbs
|
197
|
+
|
198
|
+
case @view_type
|
199
|
+
when :template
|
200
|
+
|
201
|
+
out << name_template
|
202
|
+
out << gen_template_loader
|
203
|
+
|
204
|
+
when :partial
|
205
|
+
|
206
|
+
out << name_partial
|
207
|
+
out << gen_partial_loader
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
out << write_asset_files
|
212
|
+
out << get_hbs_context
|
213
|
+
out << load_template
|
214
|
+
|
215
|
+
else #if we don't have any rendered haml (we're probably in production)
|
216
|
+
|
217
|
+
out << get_hbs_context
|
218
|
+
out << name_template
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
out << set_locale if defined? SimplesIdeias::I18n
|
223
|
+
|
224
|
+
case @view_type
|
225
|
+
when :template
|
226
|
+
|
227
|
+
out << render_rabl
|
228
|
+
out << set_gon_variable
|
229
|
+
|
230
|
+
if content_cache.store.present? #do we need to render some content for another view?
|
231
|
+
|
232
|
+
content_cache.store.each do |item|
|
233
|
+
|
234
|
+
name = item.name
|
235
|
+
path = item.path
|
236
|
+
content_cache.remove_item(item)
|
237
|
+
|
238
|
+
#NOTE: this call will overwrite all eval'd variables set below, except for template_names
|
239
|
+
#we store this in a stack and pop the last name when we get to render_template()
|
240
|
+
#it doesn't matter about the other variables as we're finished with them by this stage
|
241
|
+
#and it keeps the eval code simpler if we just reuse them
|
242
|
+
|
243
|
+
out << render_content_for(name, path)
|
244
|
+
|
245
|
+
end
|
246
|
+
content_cache.clear #just to be sure
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
out << render_template
|
251
|
+
|
252
|
+
when :partial
|
253
|
+
|
254
|
+
out << render_handlebars_partial_command
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
out.join("\n")
|
259
|
+
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
def compile_hbs
|
264
|
+
<<-RUBY
|
265
|
+
compiled_hbs = HandlebarsAssets::Handlebars.precompile( rendered_haml )
|
266
|
+
RUBY
|
267
|
+
end
|
268
|
+
|
269
|
+
def name_template
|
270
|
+
<<-RUBY
|
271
|
+
template_names ||= []
|
272
|
+
template_names << '#{File.join(@relative_view_path, @view_name).to_s}'
|
273
|
+
RUBY
|
274
|
+
end
|
275
|
+
|
276
|
+
def name_partial
|
277
|
+
<<-RUBY
|
278
|
+
partial_name = '#{@partial_name}'
|
279
|
+
RUBY
|
280
|
+
end
|
281
|
+
|
282
|
+
def gen_template_loader
|
283
|
+
<<-'RUBY'
|
284
|
+
hbs_loader = "(function() {
|
285
|
+
this.HandlebarsTemplates || (this.HandlebarsTemplates = {});
|
286
|
+
this.HandlebarsTemplates['#{template_names.last}'] = Handlebars.template(#{compiled_hbs});
|
287
|
+
return HandlebarsTemplates['#{template_names.last}'];
|
288
|
+
}).call(this)"
|
289
|
+
RUBY
|
290
|
+
end
|
291
|
+
|
292
|
+
def gen_partial_loader
|
293
|
+
<<-'RUBY'
|
294
|
+
hbs_loader = "(function() {
|
295
|
+
this.Handlebars.registerPartial('#{partial_name}', Handlebars.template(#{compiled_hbs}));
|
296
|
+
}).call(this)"
|
297
|
+
RUBY
|
298
|
+
end
|
299
|
+
|
300
|
+
def write_asset_files
|
301
|
+
<<-RUBY
|
302
|
+
File.open('#{@template_path}', 'w+') {|f| f.write(rendered_haml) }
|
303
|
+
File.open('#{@compiled_template_path}', 'w+') {|f| f.write(hbs_loader) }
|
304
|
+
RUBY
|
305
|
+
end
|
306
|
+
|
307
|
+
def get_hbs_context
|
308
|
+
<<-RUBY
|
309
|
+
hbs_context = HandlebarsAssets::Handlebars.send(:context)
|
310
|
+
RUBY
|
311
|
+
end
|
312
|
+
|
313
|
+
def set_locale
|
314
|
+
<<-RUBY
|
315
|
+
hbs_context.eval("I18n.locale = '#{I18n.locale.to_s}'")
|
316
|
+
RUBY
|
317
|
+
end
|
318
|
+
|
319
|
+
def load_template
|
320
|
+
<<-RUBY
|
321
|
+
File.open('#{@compiled_template_path}') do |file|
|
322
|
+
hbs_context.eval(file.read, '#{@view_name}.js')
|
323
|
+
end
|
324
|
+
RUBY
|
325
|
+
end
|
326
|
+
|
327
|
+
def render_rabl
|
328
|
+
|
329
|
+
if File.exist? @rabl_path
|
330
|
+
|
331
|
+
rabl_handler = ActionView::Template.handler_for_extension :rabl
|
332
|
+
rabl_source = File.read(@rabl_path)
|
333
|
+
rabl_template = ActionView::Template.new(rabl_source, @rabl_path, rabl_handler, {:locals => @template.locals})
|
334
|
+
rabl_call = rabl_handler.call rabl_template
|
335
|
+
|
336
|
+
<<-RUBY
|
337
|
+
rabl_call_str = %q( #{rabl_call} )
|
338
|
+
rendered_rabl = eval(rabl_call_str).html_safe
|
339
|
+
RUBY
|
340
|
+
|
341
|
+
else
|
342
|
+
|
343
|
+
<<-RUBY
|
344
|
+
rendered_rabl ||= '{}'.html_safe
|
345
|
+
RUBY
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
def set_gon_variable
|
352
|
+
<<-'RUBY'
|
353
|
+
Gon::Request.id = request.object_id
|
354
|
+
Gon::Request.env = request.env
|
355
|
+
Gon.view_data ||= JSON.parse(rendered_rabl)
|
356
|
+
RUBY
|
357
|
+
end
|
358
|
+
|
359
|
+
def render_template
|
360
|
+
<<-'RUBY'
|
361
|
+
current_template_name = template_names.pop
|
362
|
+
hbs_context.eval( "HandlebarsTemplates['#{current_template_name}'](#{rendered_rabl})" )
|
363
|
+
RUBY
|
364
|
+
end
|
365
|
+
|
366
|
+
def render_handlebars_partial_command
|
367
|
+
<<-RUBY
|
368
|
+
'{{> #{@partial_name}}}'.html_safe
|
369
|
+
RUBY
|
370
|
+
end
|
371
|
+
|
372
|
+
def render_content_for(name, path)
|
373
|
+
|
374
|
+
haml_handler = ActionView::Template.handler_for_extension :haml
|
375
|
+
haml_source = File.read(path)
|
376
|
+
haml_template = ActionView::Template.new(haml_source, path, haml_handler, {})
|
377
|
+
haml_call = haml_handler.call haml_template
|
378
|
+
|
379
|
+
<<-RUBY
|
380
|
+
@view_flow.set( :#{name}, eval(%q( #{haml_call} )).html_safe )
|
381
|
+
RUBY
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|
389
|
+
|
390
|
+
|
391
|
+
|
392
|
+
|
393
|
+
|
394
|
+
|
395
|
+
|