examples/lm/x_data.lua
author Myhailo Danylenko <isbear@ukrpost.net>
Mon, 06 Apr 2009 17:21:19 +0300
changeset 70 e43e386c8a33
parent 68 742878c74b8e
permissions -rw-r--r--
Vcard-temp avatar * Docgen handles preformatted text * Forms can add fields * Ping help * Easy way to publish vcard-temp photo * File mime-type detection


-- DATA FORMS (XEP-0004)

-- library

local form_field = require 'lm.form_field'

--

local F = { }
local M = { }
M.__index = M

-- form.new       -- new form
-- form.parse     -- parse existing form -- according to form type!
-- form:type      -- get type
-- form:desc      -- get title, instructions
-- form:format    -- format form -- according to form type!
-- form:fields    -- iterator, returns field objects
-- form:add       -- create field
-- form:field     -- get field
-- ?? form:del    -- delete field
-- field.new      -- create field
-- field:index    -- get index
-- field:type     -- get type
-- field:name     -- get var
-- field:desc     -- get label, desc
-- field:value    -- get/set value
-- field:values   -- get values
-- field:clear    -- clear value
-- field:options  -- get options
-- field:required -- get required

-- form    may have 'fixed' fields and should be ordered
-- submit  must not have 'fixed' fields and may be not ordered
-- cancel  must not have anything
-- result  should not have 'fixed', may be not ordered and can contain reported/item... multiple instances.

function F.new ( args )
	local form  = {
		xmlns        = 'jabber:x:data',
		ftype        = args.type or 'form',
		title        = args.title,
		instructions = args.instructions,
		f            = { },
	}
	setmetatable ( form, M )
	return form
end

function F.parse ( x )
	local title = x:child ( 'title' )
	if title then
		title = title:value ()
	end

	local instructions = x:child ( 'instructions' )
	if instructions then
		instructions = instructions:value ()
	end

	local f = F.new { type = x:attribute ( 'type' ), title = title, instructions = instructions }

	local field = x:child ()
	while field do
		local name = field:name ()
		if name == 'field' then
			local ftype = field:attribute ( 'type' ) or 'text-single'
			local var   = field:attribute ( 'var' )
			local r = {
				type  = ftype,
				label = field:attribute ( 'label' ),
			}

			local desc = field:child ( 'desc' )
			if desc then
				r.desc = desc:value ()
			end

			if field:child ( 'required' ) then
				r.required = true
			end

			if ftype == 'jid-multi' or ftype == 'list-multi' or ftype == 'text-multi' or ftype == 'list-single' then
				local values  = { }
				local options = { }

				local item = field:child ()
				while item do
					local name = item:name ()
					if name == 'value' then
						table.insert ( values, item:value () )
					elseif name == 'option' then
						options[item:child( 'value' ):value ()] = item:attribute ( 'label' ) or ''
					end
					item = item:next ()
				end

				if ftype == 'list-single' then
					local value = field:child ( 'value' )
					if value then
						r.value = value:value ()
					end
				else
					r.value = values
				end

				if ftype == 'list-multi' or ftype == 'list-single' then
					r.options = options
				end
			else
				local value = field:child ( 'value' )
				if value then
					r.value = value:value ()
				end
			end

			f:add ( var, r )
		end

		field = field:next ()
	end

	return f
end

function M.type ( form )
	return form.ftype
end

function M.desc ( form )
	return form.title, form.instructions
end

function M.format ( form, root, format_as )
	local ft = format_as or form:type ()

	root.x = { xmlns = 'jabber:x:data', type = ft }

	if ft == 'cancel' then
		return root
	end

	if ft == 'form' then
		local title, instructions = form:desc ()
		if title then
			root.x.title = { title }
		end
		if instructions then
			root.x.instructions = { instructions }
		end
	end

	local fields = { }
	for i, field in form:fields () do
		local ftype = field:type ()

		local options, label, desc, required
		if ft == 'form' then
			label, desc = field:desc ()
			if desc then
				desc = { desc }
			end

			if field:required () then
				required = { }
			end
		
			for option, label in field:options () do
				table.insert ( options, { label = label, value = { option } } )
			end
		end

		local value
		if ftype == 'list-multi' or ftype == 'text-multi' or ftype == 'jid-multi' then
			if ft == 'form' then
				for option, label in field:options () do
					table.insert ( options, { label = label, value = { option } } )
				end
			end

			value = { }
			for j, v in field:values () do
				table.insert ( value, { v } )
			end
		else
			value = { field:value () }
		end

		if ftype ~= 'fixed' or ft == 'form' then
			table.insert ( fields, {
					type   = ftype,
					var    = field:name (),
					label  = label,
					desc   = desc,
					value  = value,
					option = options
				} )
		end
	end
	root.x.field = fields

	return root
end

function M.fields ( form )
	return ipairs ( form.f )
end

function M.add ( form, var, fld )
	fld.var   = var
	fld.index = #form.f + 1 -- XXX
	if not fld.type then
		fld.type = 'text-single'
	end
	local obj = form_field.new ( fld )
	table.insert ( form.f, obj )
	form.f[var] = obj
	return obj
end

function M.field ( form, var )
	-- works well on indices
	return form.f[var]
end

return F

-- vim: se ts=4: --