module Spider; module Components class List < Spider::Widget tag 'list' i_attribute :lines, :required => :datasource i_attr_accessor :queryset, :required => :datasource i_attr_accessor :model, :required => :datasource i_attribute :keys is_attribute :delete, :default => false, :process => lambda{ |v| return true if v == "true"; return false if v == "false"; v } is_attribute :delete_param is_attribute :delete_mode, :default => 'all' is_attribute :sortable; is_attribute :collapsable; is_attribute :collapsed is_attribute :tree is_attr_accessor :actions is_attribute :sub_elements is_attribute :is_child is_attribute :paginate, :type => Fixnum, :default => false is_attribute :searchable, :type => Spider::DataTypes::Bool # Display message if list is empty attribute :show_empty, :type => Spider::DataTypes::Bool # Display empty (default: false) is_attribute :show_empty_list, :type => Spider::DataTypes::Bool i_attribute :dereference_junction i_attribute :dereference_sort, :type => Spider::DataTypes::Bool, :default => false i_attribute :dereference_delete, :type => Spider::DataTypes::Bool, :default => true is_attribute :list_tag, :default => 'ul' i_attribute :element i_attribute :parent_obj def widget_init(action='') super @sortable = @sortable.to_sym if @sortable @tree = @tree.to_sym if @tree @model = const_get_full(@model) if @model.is_a?(String) if (@model && !@queryset) @queryset = @tree ? @model.roots : @model.all elsif @queryset @model = @queryset.model end end def prepare @scene.start_list_tag = "<#{@list_tag}>" @scene.close_list_tag = "" @sublists = [] if (@sub_elements && @sub_elements.is_a?(String)) @sub_elements = @sub_elements.split(/,\s+/).map{ |el| el.to_sym } end @sub_elements ||= [] @requested_sublists ||= [] if (@attributes[:paginate]) @page = params['page'] if params['page'] @page ||= 1 @page = @page.to_i @offset = ((@page - 1) * @attributes[:paginate]) @scene.page = @page end @keys = [] @delete_keys = [] @values = [] if (params['delete']) delete(params['delete']) end @dereference_junction = @dereference_junction.to_sym if @dereference_junction css_model = @dereference_junction ? @model.elements[@dereference_junction].model : @model @scene.model_class = css_model_class(css_model) @css_classes << 'sortable' if @sortable @css_classes << 'collapsable' if @collapsable @css_classes << 'collapsed' if @collapsed @css_classes << 'sublist' if @attributes[:is_child] @css_classes << 'tree' if @attributes[:tree] @scene.show_empty = @attributes[:show_empty] if (!@lines && @queryset) if (@attributes[:paginate]) @queryset.offset = @offset @queryset.limit = @attributes[:paginate] end @scene.search_submit_text = _("Go") @scene.search_clear_text = _("Clear") @search_query = params['q'] || session['q'] @search_query = nil if params['clear'] session['q'] = @search_query if (@attributes[:searchable] && @search_query) @scene.search_query = @search_query.to_s @queryset.condition.and(@queryset.model.free_query_condition(@search_query)) end end if (@widget_target) first, rest = @widget_target.split('/', 2) if first =~ /sublist_(\d+)_(.+)/ cnt = $1.to_i sublist_id = $2 found = @requested_sublists.select{ |sbl| sbl['id'] == sublist_id }[0] row = @queryset[cnt] if (@dereference_junction) row = row.get(@dereference_junction) end create_requested_sublist(found, row, cnt) if (found) end end super end def run if (!@lines && @queryset) @lines = [] cnt = 0 @queryset.each do |row| if (@dereference_junction) dr_keys = keys_string(row) row = row.get(@dereference_junction) end @keys << keys_string(row) if (@dereference_junction && !@dereference_sort) @sort_keys ||= [] @sort_keys << dr_keys end @delete_keys << ((@dereference_junction && !@dereference_delete) ? dr_keys : @keys.last) cnt2 = 0 if @tree && row.get(@tree).length > 0 sl = create_sublist("sublist_#{cnt}_#{cnt2+=1}") if (@dereference_junction && @model.elements[@tree].model == @model.elements[@dereference_junction].model) sl.attributes[:dereference_junction] = nil end sl.queryset = row.get(@tree) @sublists[cnt] ||= [] @sublists[cnt] << sl sl.run end @sub_elements.each do |el| sub = row.get(el) sl = create_sublist("sublist_#{cnt}_#{el}") sl.queryset = sub @sublists[cnt] ||= [] @sublists[cnt] << sl sl.run end @requested_sublists.each do |sbl| sl = create_requested_sublist(sbl, row, cnt) sl.run end @values << row @lines << format_line(row) cnt += 1 end if (@attributes[:paginate]) @scene.has_more = @queryset.has_more? @scene.pages = (@queryset.total_rows.to_f / @attributes[:paginate]).ceil end end @lines ||= [] @scene.lines = @lines @scene.keys = @keys @scene.values = @values @scene.sublists = @sublists @scene.delete_keys = @delete_keys @scene.sort_keys = @sort_keys @attributes[:delete] = @request.path if @attributes[:delete] == true if (@attributes[:delete]) @scene.delete_link = @attributes[:delete] if (@delete_param) @scene.delete_link += "?#{@delete_param}" else @scene.delete_link += "?_w#{param_name(self)}[delete]=" end end end def create_requested_sublist(sbl, row, cnt) attributes = sbl.attributes.clone if (attributes['element']) el = @model.elements[attributes['element'].to_sym] #next unless el # may be ok if the query is polymorphic # if (sl['tree'] && el && el.attributes[:reverse]) # sub = el.model.send("#{sl['tree']}_roots") # sub.condition[el.attributes[:reverse]] = row # else sub = row.get(attributes['element'].to_sym) # end end el_name = attributes['element'] attributes.delete('element') sl = create_sublist("sublist_#{cnt}_#{attributes['id']}", attributes) if (el && el.model != @model) sl.attributes[:model] = el.model sl.attributes[:dereference_junction] = nil unless attributes['dereference_junction'] end if (el) sl.attributes[:element] = el sl.attributes[:parent_obj] = row end sl.parse_runtime_content_xml("#{sbl.innerHTML}") sl.queryset = sub sl.css_classes << "sublist_#{el_name}" @sublists[cnt] ||= [] @sublists[cnt] << sl return sl end def create_sublist(name, attributes = {}) w = create_widget(self.class, name, @request, @response) if (attributes['inherit_template'] && @template) w.template = @template end w.attributes[:tree] = @tree w.attributes[:actions] = @actions w.attributes[:is_child] = true @attributes.each do |key, val| w.attributes[key.to_sym] = val end attributes.each do |key, val| w.attributes[key.to_sym] = val if w.class.attribute?(key) end w.widget_before return w end def keys_string(obj) obj.keys_string end def format_line(obj) obj.to_s end def parse_runtime_content(doc, src_path='') doc = super return doc if doc.children.empty? doc.root.children_of_type('sublist').each do |sl| raise ArgumentError, "Sublist of #{@id} does not have an id" unless sl['id'] @requested_sublists ||= [] @requested_sublists << sl end return doc.root end __.json def sort(id, pos) raise "List #{@id} is not sortable" unless @sortable obj = @model.new(id) obj.set(@sortable, pos) obj.save $out << "{res: 'ok'}" end __.json def tree_sort(id, parent_id, prev_id=nil) #debugger raise "List #{@id} is not a tree" unless @tree raise "List #{@id} is not sortable" unless @sortable obj = @model.new(id) parent = @model.new(parent_id) if parent_id && !parent_id.empty? prev = @model.new(prev_id) if prev_id && !prev_id.empty? unless parent || prev if (@parent_obj.class == @model) parent = @parent_obj else raise "No parent or prev given" end end tree_el = @model.elements[@tree] obj_parent = obj.get(tree_el.attributes[:reverse]) # if (obj_parent) @model.mapper.tree_remove(tree_el, obj) # end if (prev) @model.mapper.tree_insert_node_right(tree_el, obj, prev) else @model.mapper.tree_insert_node_first(tree_el, obj, parent) end obj.save $out << "{res: 'ok'}" end def delete(id) if (@delete_mode == 'all') obj = @model.new(id) if (@tree) obj.mapper.tree_delete(@model.elements[@tree], obj) else obj.delete end else end end end end; end