module ModelTags include Radiant::Taggable class TagError < StandardError; end desc %{ } tag 'model' do |tag| raise TagError, "'#{tag.name}' tag must contain a 'name' attribute." unless tag.attr['name'] tag.locals.model = tag.attr['name'].classify.constantize tag.locals.user = "x" # XXX TODO XXX tag.expand end desc %{ } tag 'model:find' do |tag| parms = Hash.new records = [] if tag.attr['id'] # if id was given then return that record records[0] = tag.locals.model.find tag.attr['id'] else # searching for a set of records based on the given parameters [:order, :limit, :offset ].each do |p| if tag.attr[p] || tag.attr[p.to_s] parms[p] = tag.attr[p] || tag.attr[p.to_s] end end # -- combine conditions with r:filters:conditions conditions = get_conditions(tag) parms[:conditions] = conditions if conditions # now we have the conditions and such if tag.attr['distinct'] # if dictinct records are queried # TODO XXX : ditinct(...) should be secured sql = "select distinct(#{tag.attr['distinct']}) from #{tag.locals.model.table_name} " if parms[:conditions] sql += " where (#{parms[:conditions]}) " end if parms[:order] sql += " order by #{parms[:order]} " end if parms[:limit] sql += " limit #{parms[:limit]} " end records = tag.locals.model.find_by_sql sql else # lookup records based on the parameters records = tag.locals.model.find(:all,parms) end end tag.locals.records = records tag.expand end desc %{ } tag 'model:find:each' do |tag| # -- each -- result = [] if non_empty(tag) records = tag.locals.records records.each do |record| tag.locals.record = record result << tag.expand end end result end desc %{ } tag 'model:find:each:value' do |tag| ret = nil if tag.attr['name'] ret = tag.locals.record[tag.attr['name']] end # resulting value may be changed with these two attributes: # - if_found, - unless_found if_or_unless_value(tag,ret) end desc %{ } tag 'model:find:count' do |tag| if non_empty(tag) tag.locals.records.size.to_s else "0" end end desc %{ } tag 'model:find:if_returned' do |tag| # -- each -- if non_empty(tag) tag.expand end end desc %{ } tag 'model:find:unless_returned' do |tag| # -- each -- unless non_empty(tag) tag.expand end end # --------------------------------------------------------- # Calculated values, generated by Model or Entity functions desc %{ } tag 'function' do |tag| if tag.attr['name'] if tag.locals.model.respond_to?("function_is_allowed_to?") && tag.locals.model.function_is_allowed_to?(tag.attr['name'],tag.locals.user) # XXX TODO XXX parms = tag.attr['params'].split(",") if tag.attr['params'] c = get_conditions(tag) ret = tag.locals.model.send(tag.attr['name'],parms,c) # calcval may return string, array and hash tag.locals.calcval = ret tag.locals.calcvals = ret tag.expand end end end desc %{ } tag 'each:function' do |tag| if tag.attr['name'] if tag.locals.record.respond_to?("function_is_allowed_to?") && tag.locals.record.function_is_allowed_to?(tag.attr['name'],tag.locals.user) # XXX TODO XXX parms = tag.attr['params'].split(",") if tag.attr['params'] c = get_conditions(tag) ret = tag.locals.record.send(tag.attr['name'],parms,c) # calcval may return string, array and hash tag.locals.calcval = ret tag.locals.calcvals = ret tag.expand end end end desc %{ } tag 'function:each' do |tag| if tag.locals.calcvals && tag.locals.calcvals.size > 0 result = [] tag.locals.calcvals.each do |r| tag.locals.calcval = r result << tag.expand end result end end desc %{ } tag 'function:each:value' do |tag| ret = calcval_value(tag) # resulting value may be changed with these two attributes: # - if_found, - unless_found if_or_unless_value(tag,ret) end desc %{ } tag 'function:count' do |tag| calcval_count(tag) end desc %{ } tag 'function:if_returned' do |tag| if calcval_non_empty(tag) tag.expand end end # ------------------------------------------------------------------------ # A group of entities may be stored in the session. That I call container. # These need a special controller that has access to session data. desc %{ } tag 'add_item_to' do |tag| model_name = tag.locals.model.to_s if tag.locals.model model_name ||= "String" # -- action = tag.attr['action'] || "/container/add_item_to" update_value = tag.attr['container'] || "#{model_name}_container" url = tag.attr['url'] || '/' quantity = tag.attr['quantity'] || "1" text = tag.expand # -- parameters -- id = tag.locals.record['id'] if tag.locals.record id ||= tag.locals.calcval['id'] if (tag.locals.calcval && tag.locals.calcval['id']) id_param = %{eid: '#{id}'} url_param = %{url: '#{url}'} container_param = %{container: '#{update_value}'} model_param = %{model: '#{tag.locals.model.to_s}'} quantity_param = %{quantity: '#{quantity}'} # -- construnct javascript -- parameters = %{{#{id_param}, #{url_param}, #{container_param}, #{model_param}, #{quantity_param}}} oncomplete = %{function(request){new Effect.Highlight("#{update_value}",{duration:0.5});}} options = %{{asynchronous:true, evalScripts:true, onComplete:#{oncomplete}, parameters:#{parameters}}} ajax_updater = %{ #{text} } end desc %{ } tag 'remove_item_from' do |tag| model_name = tag.locals.model.to_s if tag.locals.model model_name ||= "String" # -- action = tag.attr['action'] || "/container/remove_item_from" update_value = tag.attr['container'] || "#{model_name}_container" url = tag.attr['url'] || '/' quantity = tag.attr['quantity'] || "1" text = tag.expand # -- parameters -- id = tag.locals.record['id'] if tag.locals.record id ||= tag.locals.calcval['id'] if (tag.locals.calcval && tag.locals.calcval['id']) id_param = %{eid: '#{id}'} url_param = %{url: '#{url}'} container_param = %{container: '#{update_value}'} model_param = %{model: '#{tag.locals.model.to_s}'} quantity_param = %{quantity: '#{quantity}'} # -- construnct javascript -- parameters = %{{#{id_param}, #{url_param}, #{container_param}, #{model_param}, #{quantity_param}}} oncomplete = %{function(request){new Effect.Highlight("#{update_value}",{duration:0.5});}} options = %{{asynchronous:true, evalScripts:true, onComplete:#{oncomplete}, parameters:#{parameters}}} ajax_updater = %{ #{text} } end desc %{ } tag 'container_item' do |tag| model_name = nil model = tag.locals.model id = nil request = tag.globals.page.request # -- if request if request.parameters['model'] model_name = request.parameters['model'] model = model_name.classify.constantize if model_name end id = request.parameters['eid'] # -- tag.locals.model = model tag.locals.id = id tag.locals.quantity = request.parameters['quantity'] tag.locals.container = request.parameters['container'] tag.locals.url = request.parameters['url'] end tag.locals.record = model.find(id) if (model && id) if tag.locals.record tag.expand end end # ----------------------------------------------------- # Code duplication for clarity. One tag would do for both # container_item and model:find:each desc %{ } tag 'container_item:value' do |tag| ret = nil if tag.attr['name'] ret = tag.locals.record[tag.attr['name']] end # resulting value may be changed with these two attributes: # - if_found, - unless_found if_or_unless_value(tag,ret) end # this tag is placed here in order to make functions work # on the container_items, so # container_item:each:function may be used desc %{ } tag 'container_item:each' do |tag| tag.expand end desc %{ } tag 'container_item:quantity' do |tag| tag.locals.quantity.to_s end desc %{ } tag 'container_item:subtotal_for' do |tag| total_for = tag.attr['field'] || 'price' suppress = (tag.attr['suppress_if_zero'] && tag.attr['suppress_if_zero'] == "true") ? true : false subtotal = 0.0 quantity = tag.locals.quantity.to_f || 1.0 if tag.locals.record subtotal = tag.locals.record[total_for].to_f end if subtotal>0.0 suppress = false end if suppress nil else (subtotal * quantity).to_s end end private def calcval_value(tag) ret = nil if tag.attr['name'] ret = tag.locals.calcval[tag.attr['name']] else ret = tag.locals.calcval end ret end def calcval_count(tag) if tag.locals.calcvals tag.locals.calcvals.size.to_s else "0" end end def calcval_non_empty(tag) # treats nil, empty array, and empty string the same way ( tag.locals.calcvals && tag.locals.calcvals.respond_to?("size") && tag.locals.calcvals.size>0 ) || ( tag.locals.calcval && tag.locals.calcval.respond_to?("length") && tag.locals.calcval.length>0 ) end def non_empty(tag) records = tag.locals.records records && records.size>0 end def get_conditions(tag) ret = tag.locals.conditions if tag.attr['conditions'] if tag.locals.conditions ret = "#{tag.attr['conditions']} AND #{tag.locals.conditions}" else ret = tag.attr['conditions'] end end ret end def if_or_unless_value(tag,ret) newret = ret.to_s if tag.attr['if_found'] && ret && ret.length > 0 newret = tag.attr['if_found'] end if tag.attr['unless_found'] && (!ret || ret.length == 0) newret = tag.attr['unless_found'] end newret end end