require 'volt/page/targets/helpers/comment_searchers' # A dom template is used to optimize going from a template name to # dom nodes and bindings. It stores a copy of the template's parsed # dom nodes, then when a new instance is requested, it updates the # dom markers (comments) for new binding numbers and returns a cloneNode'd # version of the dom nodes and the bindings. class DomTemplate include CommentSearchers def initialize(page, template_name) template = page.templates[template_name] if template html = template['html'] @bindings = template['bindings'] else html = "
-- < missing template #{template_name.inspect.gsub('<', '<').gsub('>', '>')} > --
" @bindings = {} end @nodes = build_from_html(html) track_binding_anchors end # Returns the dom nodes and bindings def make_new bindings = update_binding_anchors!(`self.nodes`) new_nodes = `self.nodes.cloneNode(true)` return [new_nodes, bindings] end # Finds each of the binding anchors in the temp dom, then stores a reference # to them so they can be quickly updated without using xpath to find them again. def track_binding_anchors @binding_anchors = {} # Loop through the bindings, find in nodes. @bindings.each_pair do |name,binding| if name.is_a?(String) # Find the dom node for an attribute anchor node = nil %x{ node = self.nodes.querySelector('#' + name); } @binding_anchors[name] = node else # Find the dom node for a comment anchor start_comment = find_by_comment("$#{name}", @nodes) end_comment = find_by_comment("$/#{name}", @nodes) @binding_anchors[name] = [start_comment, end_comment] end end end # Takes the binding_anchors and updates them with new numbers (comments and id's) # then returns the bindings updated to the new numbers. def update_binding_anchors!(nodes) new_bindings = {} @binding_anchors.each_pair do |name, anchors| new_name = @@binding_number @@binding_number += 1 if name.is_a?(String) if name[0..1] == 'id' # A generated id # update the id `anchors.setAttribute('id', 'id' + new_name);` new_bindings["id#{new_name}"] = @bindings[name] else # Assume a fixed id, should not be updated # TODO: Might want to check the page to see if a node # with this id already exists and raise if it does. # Copy from existing binding new_bindings[name] = @bindings[name] end else start_comment, end_comment = anchors %x{ start_comment.textContent = " $" + new_name + " "; end_comment.textContent = " $/" + new_name + " "; } # %x{ # start_comment.innerText = " $" + new_name + " "; # end_comment.innerText = " $/" + new_name + " "; # } new_bindings[new_name] = @bindings[name] end end return new_bindings end end