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