Changeset 463
- Timestamp:
- 2007-04-30 21:49:51 (2 years ago)
- Files:
-
- trunk/TODO (modified) (1 diff)
- trunk/app/controllers/application.rb (modified) (2 diffs)
- trunk/app/models/node.rb (modified) (1 diff)
- trunk/app/models/page.rb (modified) (1 diff)
- trunk/lib/parser/lib/parser.rb (modified) (11 diffs)
- trunk/lib/parser/lib/rules/zafu.rb (modified) (2 diffs)
- trunk/lib/parser/test/parser_test.rb (modified) (1 diff)
- trunk/lib/parser/test/zafu.yml (modified) (7 diffs)
- trunk/lib/parser/test/zafu_insight.yml (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/TODO
r455 r463 1 1 2 2 == Todo 3 * What if a Note/Contact contains pages and one of these pages has 'custom_base' set ? 3 4 * Replace Trans... with Gettext 4 5 * BUG: flash not working in UsersController when updating preferences. trunk/app/controllers/application.rb
r459 r463 129 129 # there, they are searched in the database and compiled into 'app/views/templates/compiled'. 130 130 def template_url(opts={}) 131 skin_name = opts[:skin] || (@node ? @node[:skin] : nil) || 'default'132 skin_name =skin_name.gsub(/[^a-zA-Z]/,'') # security131 @skin_name = opts[:skin] || (@node ? @node[:skin] : nil) || 'default' 132 @skin_name = @skin_name.gsub(/[^a-zA-Z]/,'') # security 133 133 mode = opts[:mode] || params[:mode] 134 134 format = opts[:format] || params[:format] || 'html' 135 135 klass = @node.class 136 # FIXME: rescue_template = opts[:rescue_template] || '/templates/fixed/default/any' 137 # FIXME: @skin_obj = nil 138 # classes : 136 137 # possible classes for the master template : 139 138 klasses = [] 140 139 klass.kpath.split(//).each_index { |i| klasses << klass.kpath[0..i] } 141 142 best_match = { 143 :conditions => ["tkpath IN (?) AND format = ? AND mode #{mode ? '=' : 'IS'} ?", klasses, format, mode], 144 :select => "*, (template_contents.skin_name = '#{skin_name}') AS skin_ok", 140 141 template = secure(Template) { Template.find(:first, 142 :conditions => ["tkpath IN (?) AND format = ? AND mode #{mode ? '=' : 'IS'} ? AND template_contents.node_id = nodes.id", klasses, format, mode], 143 :from => "nodes, template_contents", 144 :select => "nodes.*, template_contents.*, (template_contents.skin_name = #{@skin_name}) AS skin_ok", 145 145 :order => "length(tkpath) DESC, skin_ok DESC" 146 } 147 148 if skin_name == 'default' 149 template = TemplateContent.find(:first, best_match) 150 skin_root = "#{SITES_ROOT}/shared" 151 else 152 best_match[:conditions][0] += " AND template_contents.node_id = nodes.id" 153 best_match[:from] = "nodes, template_contents" 154 best_match[:select] = "nodes.*, template_contents.*, (template_contents.skin_name = #{skin_name}) AS skin_ok", 155 template = secure(Template) { Template.find(:first, best_match) } 156 157 skin_root = "#{SITES_ROOT}/#{visitor.site.host}" 158 end 159 146 )} 147 148 # FIXME use a default fixed template. 160 149 raise ActiveRecord::RecordNotFound unless template 161 150 162 151 mode = "_#{mode}" if mode 152 # FIXME use fullpath instead of 'skin_name' 153 skin_root = "#{SITES_ROOT}/#{visitor.site.host}" 163 154 skin_path = "/#{template[:skin_name]}/#{template[:klass]}#{mode}.#{format}" 164 155 main_path = "/#{visitor.lang}/main.erb" … … 166 157 167 158 if File.exists?(url) 168 if skin_name == 'default' && (File.stat(url).mtime < File.stat("#{skin_root}/zafu#{skin_path}").mtime || RAILS_ENV == 'development') 159 # FIXME: use CachedPage to store the compiled template instead of this File.stat test 160 if File.stat(url).mtime < template.v_updated_at 161 # template changed, render 169 162 FileUtils.rmtree("#{skin_root}/zafu.compiled#{skin_path}") 170 elsif skin_name != 'default' && (File.stat(url).mtime < template.v_updated_at || RAILS_ENV == 'development') 171 FileUtils.rmtree("#{skin_root}/zafu.compiled#{skin_path}") 172 else 173 # we can use the cached version 174 return url 175 end 176 end 177 178 # render zafu 179 response.template.instance_variable_set(:@session, session) 180 skin_helper = response.template 181 res = ZafuParser.new_with_url(skin_path, :helper => skin_helper).render 182 FileUtils::mkpath(File.dirname(url)) unless File.exists?(File.dirname(url)) 183 File.open(url, "wb") { |f| f.syswrite(res) } 163 response.template.instance_variable_set(:@session, session) 164 skin_helper = response.template 165 res = ZafuParser.new_with_url(skin_path, :helper => skin_helper).render 166 FileUtils::mkpath(File.dirname(url)) unless File.exists?(File.dirname(url)) 167 File.open(url, "wb") { |f| f.syswrite(res) } 168 end 169 end 184 170 185 171 return url 186 172 end 187 173 174 # Return a template's content from an url. If the url does not start with a '/', we try by replacing the 175 # first element with the current skin_name and if it does not work, we try with the full url. If the url 176 # start with a '/' we use the full url directly. 188 177 # tested in MainControllerTest 189 178 def template_text_for_url(url) 190 191 url = url[1..-1] # strip leading '/' 192 url = url.split('/') 193 skin_name = url.shift 194 if skin_name == 'default' 195 path = File.join(SITES_ROOT, 'shared', 'zafu', 'default', *url) 196 if File.exists?(path) 197 File.read(path) 198 else 199 nil 200 end 201 else 202 if @skin_obj && @skin_obj[:name] == skin_name 203 skin = @skin_obj 204 end 205 skin ||= secure(Skin) { Skin.find_by_name(skin_name) } 179 @skin ||= {} 180 if url =~ /^\// 181 url = url[1..-1].split('/') 182 skin_names = [url.shift] 183 else 184 url = url.split('/') 185 skin_names = [@skin_name, url.shift] 186 end 187 188 partial = nil 189 skin_names.each do |skin_name| 190 skin = @skin[skin_name] ||= secure(Skin) { Skin.find_by_name(skin_name) } 206 191 path = (skin.fullpath.split('/') + url).join('/') 207 partial = secure(TextDocument) { TextDocument.find_by_path(path) } 208 partial.version.text 209 end 210 rescue ActiveRecord::RecordNotFound 211 return nil 192 break if partial = secure(TextDocument) { TextDocument.find_by_path(path) } 193 end 194 partial ? partial.version.text : nil 212 195 end 213 196 trunk/app/models/node.rb
r455 r463 146 146 node = find(:first, :conditions=>"zip = #{zip.to_i}") 147 147 raise ActiveRecord::RecordNotFound unless node 148 node149 end150 151 # Find an node by it's full path. Cache 'fullpath' if found.152 def find_by_path(path)153 return nil unless scope = scoped_methods[0]154 return nil unless scope[:create]155 visitor = scoped_methods[0][:create][:visitor] # use secure scope to get visitor156 node = self.find_by_fullpath(path)157 if node.nil?158 path = path.split('/')159 last = path.pop160 Node.with_exclusive_scope do161 node = Node.find(visitor.site[:root_id])162 path.each do |p|163 raise ActiveRecord::RecordNotFound unless node = Node.find_by_name_and_parent_id(p, node[:id])164 end165 end166 raise ActiveRecord::RecordNotFound unless node = self.find_by_name_and_parent_id(last, node[:id])167 path << last168 node.fullpath = path.join('/')169 # bypass callbacks here170 Node.connection.execute "UPDATE #{Node.table_name} SET fullpath='#{path.join('/').gsub("'",'"')}' WHERE id='#{node[:id]}'"171 end172 148 node 173 149 end trunk/app/models/page.rb
r455 r463 15 15 Page 16 16 end 17 17 18 # Find an node by it's full path. Cache 'fullpath' if found. 19 def find_by_path(path) 20 return nil unless scope = scoped_methods[0] 21 return nil unless scope[:create] 22 visitor = scoped_methods[0][:create][:visitor] # use secure scope to get visitor 23 node = self.find_by_fullpath(path) 24 if node.nil? 25 path = path.split('/') 26 last = path.pop 27 Node.with_exclusive_scope do 28 node = Node.find(visitor.site[:root_id]) 29 path.each do |p| 30 raise ActiveRecord::RecordNotFound unless node = Node.find_by_name_and_parent_id(p, node[:id]) 31 end 32 end 33 raise ActiveRecord::RecordNotFound unless node = self.find_by_name_and_parent_id(last, node[:id]) 34 path << last 35 node.fullpath = path.join('/') 36 # bypass callbacks here 37 Node.connection.execute "UPDATE #{Node.table_name} SET fullpath='#{path.join('/').gsub("'",'"')}' WHERE id='#{node[:id]}'" 38 end 39 node 40 end 41 18 42 def select_classes 19 43 list = subclasses.inject([]) do |list, k| trunk/lib/parser/lib/parser.rb
r455 r463 10 10 11 11 def template_text_for_url(url) 12 url = url[1..-1] # strip leading '/'13 url = url.gsub('/','_')14 if test = @strings[url ]12 url = url[1..-1] if url[0..0] == '/' # just ignore the 'relative' or 'absolute' tricks. 13 14 if test = @strings[url.gsub('/','_')] 15 15 test['src'] 16 16 else … … 56 56 helper = opts[:helper] || ParserModule::DummyHelper.new 57 57 text, absolute_url = self.find_template_text(url,helper) 58 current_folder = absolute_url ? absolute_url.split('/')[0..-2].join('/') : '/'58 current_folder = absolute_url ? absolute_url.split('/')[1..-2].join('/') : nil 59 59 self.new(text, :helper=>helper, :current_folder=>current_folder, :included_history=>[absolute_url]) 60 60 end … … 63 63 # This method is used when 'including' text 64 64 def find_template_text(url, helper, current_folder=nil) 65 current_folder ||= '/'66 # remove trailing '/'67 if current_folder[-1..-1] == '/'68 current_folder = current_folder[0..-2]69 end70 65 71 if url[0..0] == '/' 72 # absolute url 73 urls = [url,"#{url}/_#{url.split('/').last}"] 74 else 75 # relative path 76 urls = ["#{current_folder}/#{url}", "#{current_folder}/#{url}/_#{url.split('/').last}", 77 "/default/#{url}", "/default/#{url}/_#{url.split('/').last}"] 66 if (url[0..0] != '/') && current_folder 67 url = "#{current_folder}/#{url}" 78 68 end 79 69 80 text = absolute_url = nil 81 urls.each do |template_url| 82 if text = helper.send(:template_text_for_url,template_url) 83 absolute_url = template_url 84 break 85 end 86 end 87 text ||= "<span class='parser_error'>template '#{url}' not found</span>" 88 return [text, absolute_url] 70 text = helper.send(:template_text_for_url, url) || "<span class='parser_error'>template '#{url}' not found</span>" 71 url = "/#{url}" unless url[0..0] == '/' # has to be an absolute path 72 return [text, url] 89 73 end 90 74 … … 119 103 end 120 104 105 def replace_with(obj) 106 @blocks = obj.blocks 107 @params = obj.params 108 end 109 121 110 def render(context={}) 122 111 return '' if context["no_#{@method}".to_sym] … … 132 121 end 133 122 if replacer = (@context[:parts] || {})[@context[:name]] 134 @blocks = replacer.blocks 135 @params = replacer.params 123 replace_with(replacer) 136 124 end 137 125 end … … 177 165 def r_include 178 166 expand_with(:preflight=>true) 179 @blocks = @included_blocks || @blocks180 167 if @parts != {} 181 expand_with(:parts => (@context[:parts] || {}).merge(@parts))182 else 183 expand_with 168 expand_with(:parts => (@context[:parts] || {}).merge(@parts), :blocks => @included_blocks) 169 else 170 expand_with(:blocks => @included_blocks) 184 171 end 185 172 end … … 221 208 text = @text 222 209 @options[:included_history] ||= [] 223 @options[:current_folder] ||= '/'210 224 211 @text, absolute_url = self.class.find_template_text(@params[:template], @options[:helper], @options[:current_folder]) 212 225 213 if absolute_url 226 214 if @options[:included_history].include?(absolute_url) … … 228 216 else 229 217 @options[:included_history] += [absolute_url] 230 @options[:current_folder] = absolute_url.split('/')[0..-2].join('/') 231 end 232 end 218 @options[:current_folder] = absolute_url.split('/')[1..-2].join('/') 219 end 220 end 221 233 222 @text = before_parse(@text) 234 223 enter(:void) # scan fetched text … … 254 243 end 255 244 245 # Build blocks 256 246 def store(obj) 257 247 if obj.kind_of?(String) && @blocks.last.kind_of?(String) … … 262 252 end 263 253 254 # Set output during render 264 255 def out(obj) 265 256 @result << obj … … 398 389 399 390 def expand_with(acontext={}) 391 blocks = acontext.delete(:blocks) || @blocks 400 392 res = "" 401 393 @pass = {} # current object sees some information from it's direct descendants 402 394 @parts = {} 403 395 new_context = @context.merge(acontext) 404 @blocks.each do |b|396 blocks.each do |b| 405 397 if b.kind_of?(String) 406 398 res << b trunk/lib/parser/lib/rules/zafu.rb
r455 r463 3 3 module Zafu 4 4 module Tags 5 attr_accessor :html_tag, :html_tag_params 6 7 def replace_with(obj) 8 super 9 @html_tag = obj.html_tag || @html_tag 10 @html_tag_params = obj.html_tag_params || @html_tag_params 11 end 5 12 6 13 def render(context={}) … … 241 248 elsif @text =~ /\A[^>]*?>/ 242 249 # html tag 250 store opts[:space_before] 243 251 flush $& 244 252 else trunk/lib/parser/test/parser_test.rb
r370 r463 33 33 testfile :zafu, :zafu_asset, :zafu_insight, :zazen 34 34 def test_single 35 do_test('zafu', ' tada')35 do_test('zafu', 'complex_example') 36 36 end 37 37 def test_zazen_image_no_image trunk/lib/parser/test/zafu.yml
r315 r463 110 110 res: "<span class='parser_error'>[include error: /infinite/bar --> /infinite/foo --> /infinite/bar ]</span>" 111 111 112 other_context:112 default_context: 113 113 src: "from other: <z:include template='menu'/> and <z:include template='/include/menu'/>" 114 114 res: "from other: the [test]menu[/test] is nice and include_menu: the [test]menu[/test] is nice" … … 125 125 src: | 126 126 Some people say <z:hello/> 127 Some say <z:include template=' menu'/>127 Some say <z:include template='/default/menu'/> 128 128 <ul class='list' do='set_context' life='ok'> 129 129 <li>truc</li> … … 138 138 <li>truc</li> 139 139 <li>machin</li> 140 [test {> :life=>'ok'}]<li>sunny day</li>[/test]141 </ul>140 [test {> :life=>'ok'}] <li>sunny day</li> 141 [/test] </ul> 142 142 the [test {> :var=>'complex'}]menu[/test] is nice 143 143 … … 163 163 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 164 164 <title do='test'>node title</title> 165 end 165 166 res: | 166 167 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 167 168 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 168 [test]<title>node title</title> [/test]169 169 [test]<title>node title</title> 170 [/test]end 170 171 no_tag: 171 172 src: "<z:set_context no_test='true'>this is a <z:test>test</z:test>dog</z:set_context>" … … 201 202 202 203 name: 203 src: "super: <z:void name='super'>hey <z: text text='ho' name='man'/></z:void>"204 src: "super: <z:void name='super'>hey <z:void name='man' do='text' text='ho'/></z:void>" 204 205 res: "super: hey ho" 205 206 … … 213 214 214 215 name_title: 215 src: "title: <h1 do=' text' text='dummy' name='title'>blah</h1>"216 src: "title: <h1 do='void' name='title' do='text' text='dummy'>blah</h1>" 216 217 res: "title: <h1>dummy</h1>" 217 218 … … 226 227 227 228 res: | 228 [test]<p>blah</p> [/test]229 [ test]<p>blah</p>[/test]230 ok229 [test]<p>blah</p> 230 [/test][test]<p>blah</p> 231 [/test]ok 231 232 232 233 names: trunk/lib/parser/test/zafu_insight.yml
r311 r463 13 13 include: 14 14 src: "<z:include template='/menu'><z:with part='a'>do <z:inspect/></z:with></z:include>" 15 res: "var a: do [inspect {> :menu=>'true', :name=>'a', :parts=>' '}/]"15 res: "var a: do [inspect {> :menu=>'true', :name=>'a', :parts=>'ado [inspect {> :preflight=>'true'}/]'}/]"
