mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
2349 lines
79 KiB
Ruby
2349 lines
79 KiB
Ruby
# page format: {:uuid=>"9f7b8942-82ee-4695-8a61-d95f15f5dba3", :type=>:structure, :ufs=>:"org.gxg.gui.page", :title=>"Page", :version=>0.0, :mime_types=>"", :content=>{:component_type=>"page", :publish_path=>"", :background_uuid=>"", :menubar_uuid=>"", :attributes=>{}, :classes=>"", :style=>{}, :browsing=>{:draggable=>{}, :droppable=>{}, :resizable=>{}, :selectable=>{}, :sortable=>{}, :tool_tip=>{}, :alt_text=>""}, :authoring=>{:draggable=>{}, :droppable=>{}, :resizable=>{}, :selectable=>{}, :sortable=>{}, :tool_tip=>{}, :alt_text=>""}, :options=>{}, :value=>nil, :script=>"", :sub_components=>[]}}
|
|
#
|
|
# component format: {:uuid=>:"c44d8b14-1a97-4c6f-b07a-6999ca310241", :type=>:structure, :ufs=>:"org.gxg.gui.component", :title=>"Gui Component", :version=>0.0, :mime_types=>[], :content=>{:component_type=>"unspecified", :attributes=>{}, :classes=>"", :style=>{}, :browsing=>{:draggable=>{}, :droppable=>{}, :resizable=>{}, :selectable=>{}, :sortable=>{}, :tool_tip=>{}, :alt_text=>""}, :authoring=>{:draggable=>{}, :droppable=>{}, :resizable=>{}, :selectable=>{}, :sortable=>{}, :tool_tip=>{}, :alt_text=>""}, :options=>{}, :value=>nil, :script=>"", :sub_components=>[]}}
|
|
#{
|
|
# :component_type => "page",
|
|
# :publish_path => "",
|
|
# :background_uuid => "",
|
|
# :menubar_uuid => "",
|
|
# :attributes => {},
|
|
# :classes => "",
|
|
# :style => {},
|
|
# :browsing => {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""},
|
|
# :authoring => {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""},
|
|
# :options => {},
|
|
# :value => nil,
|
|
# :script => "",
|
|
# :sub_components => []
|
|
#}
|
|
module GxG
|
|
DISPLAY_DETAILS = {:host_path => "", :use_ssl => false, :connection => nil, :object => nil, :mode => :browsing}
|
|
module Css
|
|
@@CssCache = []
|
|
@@CssRuleProperties = {}
|
|
#
|
|
class CSSRule
|
|
# Provide EASY interface to native CSS Rule.
|
|
def initialize(the_native_rule)
|
|
@native_rule = the_native_rule
|
|
@name = (`#{@native_rule}.selectorText` || "").to_s.to_sym
|
|
end
|
|
#
|
|
def native_object()
|
|
@native_rule
|
|
end
|
|
#
|
|
def inspect()
|
|
"<CSSRule: #{@name}>"
|
|
end
|
|
#
|
|
def name()
|
|
@name
|
|
end
|
|
#
|
|
def keys()
|
|
GxG::Css::valid_properties()
|
|
end
|
|
#
|
|
def [](the_key)
|
|
result = nil
|
|
csskey = @@CssRuleProperties[(the_key)]
|
|
if csskey
|
|
result = `#{@native_rule}.style[#{csskey}]`
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def []=(the_key, the_value)
|
|
#
|
|
csskey = @@CssRuleProperties[(the_key)]
|
|
if csskey
|
|
`#{@native_rule}.style[#{csskey}] = #{(the_value || "")}`
|
|
else
|
|
# ignore invalid keys
|
|
end
|
|
the_value
|
|
end
|
|
#
|
|
def merge(properties={})
|
|
properties.keys.each do |the_key|
|
|
self[(the_key)] = properties[(the_key)]
|
|
end
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
def self.refresh_css_cache()
|
|
sheets = `document.styleSheets.length`.to_i
|
|
if sheets > 0
|
|
new_cache = []
|
|
(0..(sheets - 1)).each do |sheet_index|
|
|
begin
|
|
ruleset = `document.styleSheets[#{sheet_index}].cssRules`
|
|
rescue Exception => the_error
|
|
ruleset = `document.styleSheets[#{sheet_index}].rules`
|
|
end
|
|
if ruleset
|
|
rules = (`#{ruleset}.length`.to_i)
|
|
if rules > 0
|
|
(0..(rules - 1)).each do |rule_index|
|
|
begin
|
|
native_rule = `document.styleSheets[#{sheet_index}].cssRules[#{rule_index}]`
|
|
rescue Exception => the_error
|
|
native_rule = `document.styleSheets[#{sheet_index}].rules[#{rule_index}]`
|
|
end
|
|
if native_rule
|
|
new_cache << GxG::Css::CSSRule.new(native_rule)
|
|
if @@CssRuleProperties.size == 0
|
|
`Object.keys(#{native_rule}.style)`.each do |the_property_label|
|
|
if the_property_label
|
|
if ["0", "1", "3", "4", "5", "6", "7", "8", "9"].include?(the_property_label[0])
|
|
the_key = the_property_label.to_sym
|
|
else
|
|
key_text = (the_property_label[0].capitalize + the_property_label[1..-1]).split_camelcase
|
|
if key_text.is_a?(String)
|
|
key_text = [(key_text)]
|
|
end
|
|
the_key = key_text.join("-").downcase.to_sym
|
|
end
|
|
unless @@CssRuleProperties.keys.include?(the_key)
|
|
@@CssRuleProperties[(the_key)] = the_property_label.to_s
|
|
end
|
|
end
|
|
end
|
|
end
|
|
#
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
@@CssCache = new_cache
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def self.valid_properties()
|
|
@@CssRuleProperties.keys
|
|
end
|
|
#
|
|
def self.get_property_name(the_key=nil)
|
|
result = nil
|
|
if the_key.is_a?(::Symbol)
|
|
result = @@CssRuleProperties[(the_key)]
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def self.rules()
|
|
result = []
|
|
@@CssCache.each do |entry|
|
|
result << entry.name
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def self.find_rule(the_rule_selector=nil)
|
|
result = []
|
|
@@CssCache.each do |entry|
|
|
if entry.name == (the_rule_selector.to_s.to_sym)
|
|
result << entry
|
|
end
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def self.set_rule(the_rule_selector=nil, the_properties={}, options={:merge => true})
|
|
# find existing
|
|
# overwrite or merge (options)
|
|
# create if non-existent
|
|
found = GxG::Css::find_rule(the_rule_selector)
|
|
if found.size > 0
|
|
found.each do |the_rule_entry|
|
|
the_rule = the_rule_entry.values[0]
|
|
if options[:overwrite] == true
|
|
@@CssRuleProperties.keys.each do |clear_key|
|
|
unless the_properties.keys.include?(clear_key)
|
|
`#{the_rule.native_object()}.style[#{@@CssRuleProperties[(clear_key)]}] = ""`
|
|
end
|
|
end
|
|
end
|
|
the_properties.keys.each do |the_key|
|
|
csskey = @@CssRuleProperties[(the_key)]
|
|
if csskey
|
|
`#{the_rule.native_object()}.style[#{csskey}] = #{the_properties[(the_key)]}`
|
|
else
|
|
# ignore invalid keys
|
|
end
|
|
end
|
|
end
|
|
else
|
|
# create it
|
|
rule_body = {}
|
|
the_properties.keys.each do |property_key|
|
|
csskey = @@CssRuleProperties[(property_key)]
|
|
if csskey
|
|
rule_body[(csskey)] = the_properties[(property_key)]
|
|
end
|
|
end
|
|
sheet_index = (`document.styleSheets.length`.to_i - 1)
|
|
rules = `document.styleSheets[#{sheet_index}].cssRules`
|
|
until rules do
|
|
sheet_index -= 1
|
|
if sheet_index < 0
|
|
rules = nil
|
|
break
|
|
end
|
|
rules = `document.styleSheets[#{sheet_index}].cssRules`
|
|
end
|
|
if rules
|
|
#
|
|
rule_index = (`#{rules}.length`.to_i - 1)
|
|
response_code = `document.styleSheets[#{sheet_index}].addRule(#{the_rule_selector},"",#{rule_index})`.to_i
|
|
if response_code == -1
|
|
begin
|
|
native_rule = `document.styleSheets[#{sheet_index}].cssRules[#{rule_index}]`
|
|
rescue Exception => the_error
|
|
native_rule = `document.styleSheets[#{sheet_index}].rules[#{rule_index}]`
|
|
end
|
|
the_properties.keys.each do |property_key|
|
|
csskey = @@CssRuleProperties[(property_key)]
|
|
if csskey
|
|
`#{native_rule}.style[#{csskey}] = #{the_properties[(property_key)]}`
|
|
end
|
|
end
|
|
@@CssCache << GxG::Css::CSSRule.new(native_rule)
|
|
end
|
|
end
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def self.remove_rule(the_rule_selector=nil)
|
|
found_indexes = []
|
|
@@CssCache.each_with_index do |entry, index|
|
|
if entry.name == the_rule_selector.to_s.to_sym
|
|
found_indexes << index
|
|
end
|
|
end
|
|
found = []
|
|
found_indexes.reverse.each do |the_index|
|
|
found << @@CssCache.delete_at(the_index)
|
|
end
|
|
if found.size > 0
|
|
found.each do |the_rule|
|
|
native_rule = the_rule.native_object()
|
|
the_sheet = `#{native_rule}.parentStyleSheet`
|
|
if the_sheet
|
|
rule_count = `#{the_sheet}.cssRules.length`.to_i
|
|
if rule_count > 0
|
|
(0..(rule_count - 1)).to_a.reverse.each do |rule_index|
|
|
other_native_rule = `#{the_sheet}.cssRules[#{rule_index}]`
|
|
if other_native_rule
|
|
if `#{native_rule}.selectorText == #{other_native_rule}.selectorText`
|
|
`#{the_sheet}.deleteRule(#{rule_index})`
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
module Graphics
|
|
class WebGL
|
|
#
|
|
end
|
|
#
|
|
class Svg
|
|
#
|
|
end
|
|
#
|
|
class Canvas
|
|
#
|
|
end
|
|
end
|
|
#
|
|
module Gui
|
|
#
|
|
class Display
|
|
# There is typically only one of these instantiated.
|
|
# url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
|
|
def self.valid_properties()
|
|
GxG::Css::valid_properties()
|
|
end
|
|
#
|
|
def initialize(settings={})
|
|
if GxG::DISPLAY_DETAILS[:object].is_a?(GxG::Gui::Display)
|
|
raise Exception, "Display has already been constructed."
|
|
else
|
|
@uuid = (settings[:uuid] || GxG::uuid_generate)
|
|
@remote_uuid = nil
|
|
@channel = nil
|
|
@update_queue = []
|
|
@document = ::Document
|
|
@dom_object = ::Element.find('body')
|
|
#
|
|
@attributes = {}
|
|
@classes = ""
|
|
@style = {}
|
|
@browsing = {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""}
|
|
@authoring = {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""}
|
|
@options = {}
|
|
@value = nil
|
|
#
|
|
@update_timer = post_event_periodic(0.333) do
|
|
self.transmit_update()
|
|
end
|
|
GxG::DISPLAY_DETAILS[:object] = self
|
|
GxG::register(self)
|
|
GxG::Css::refresh_css_cache()
|
|
end
|
|
self
|
|
end
|
|
#
|
|
def uuid()
|
|
@uuid
|
|
end
|
|
#
|
|
def set_remote_uuid(the_uuid=nil)
|
|
if the_uuid
|
|
@remote_uuid = the_uuid
|
|
end
|
|
end
|
|
#
|
|
def dom_object()
|
|
@dom_object
|
|
end
|
|
#
|
|
def establish_dom_link()
|
|
# No-op : already establish
|
|
end
|
|
#
|
|
def channel()
|
|
@channel
|
|
end
|
|
#
|
|
def set_channel(the_channel=nil)
|
|
@channel = the_channel
|
|
end
|
|
#
|
|
def export_display(local_export=false)
|
|
# Export entire key-frame of display state data.
|
|
# build up export db pairs:
|
|
export_db = []
|
|
link_db = [(self)]
|
|
while link_db.size > 0 do
|
|
entry = link_db.shift
|
|
parent = GxG::parent_of(entry)
|
|
if parent
|
|
new_record = {:uuid => entry.uuid.to_s, :parent_uuid => parent.uuid.to_s, :type => nil, :attributes => {}, :classes => "", :style => {}, :browsing => {}, :authoring => {}, :options => {}, :value => nil, :content => []}
|
|
new_record[:type] = GxG::Gui::GuiComponent::class_to_key(entry.class).to_s
|
|
else
|
|
if local_export == true
|
|
new_record = {:uuid => @uuid.to_s, :parent_uuid => nil, :type => "display", :attributes => {}, :classes => "", :style => {}, :browsing => {}, :authoring => {}, :options => {}, :value => nil, :content => []}
|
|
else
|
|
new_record = {:uuid => @remote_uuid.to_s, :parent_uuid => nil, :type => "display", :attributes => {}, :classes => "", :style => {}, :browsing => {}, :authoring => {}, :options => {}, :value => nil, :content => []}
|
|
end
|
|
end
|
|
new_record[:attributes] = entry.get_attributes()
|
|
new_record[:classes] = entry.get_classes()
|
|
new_record[:style] = entry.get_style()
|
|
new_record[:browsing] = entry.get_features()
|
|
new_record[:authoring] = entry.get_authoring_features()
|
|
new_record[:options] = entry.get_options()
|
|
new_record[:value] = entry.get_value()
|
|
export_db << {:object => entry, :record => new_record}
|
|
GxG::children_of(entry).each do |the_child|
|
|
link_db << the_child
|
|
end
|
|
end
|
|
object_record = Proc.new do |the_object|
|
|
found = nil
|
|
export_db.each do |export_record|
|
|
if the_object.object_id == export_record[:object].object_id
|
|
found = export_record
|
|
break
|
|
end
|
|
end
|
|
found
|
|
end
|
|
# Assemble export contents of records
|
|
link_db = [(self)]
|
|
while link_db.size > 0 do
|
|
# {:uuid => "<the-uuid>", :parent_uuid => "<the-uuid>", :type => "<the-type-specifier>", :classes => "", :style => {}, :features => {}, :value => nil, :content => []}
|
|
entry = link_db.shift
|
|
the_record = object_record.call(entry)
|
|
if the_record
|
|
GxG::children_of(entry).each do |the_child|
|
|
child_record = object_record.call(the_child)
|
|
the_record[:record][:content] << child_record[:record]
|
|
link_db << the_child
|
|
end
|
|
end
|
|
#
|
|
end
|
|
(export_db[0] || {})[:record]
|
|
end
|
|
#
|
|
def import_display(import_records={})
|
|
result = false
|
|
if import_records.size > 0
|
|
old_list = GxG::register_uuid_list()
|
|
retain_list = [(@uuid.to_sym)]
|
|
import_db = []
|
|
link_db = [(import_records)]
|
|
while link_db.size > 0 do
|
|
entry = link_db.shift
|
|
# do a format check on the record?
|
|
if (entry[:uuid] && entry[:type] && entry[:attributes] && entry[:classes] && entry[:style] && entry[:browsing] && entry[:authoring] && entry[:options] && entry[:content])
|
|
entry[:object] = GxG::object_by_uuid(entry[:uuid].to_sym)
|
|
unless entry[:object]
|
|
# create object
|
|
parent = nil
|
|
if entry[:parent_uuid]
|
|
parent = GxG::object_by_uuid(entry[:parent_uuid].to_sym)
|
|
end
|
|
the_class = GxG::Gui::GuiComponent::key_to_class(entry[:type].to_sym)
|
|
unless the_class == GxG::Gui::Display
|
|
entry[:object] = the_class.new({:uuid => entry[:uuid].to_sym, :parent => (parent || self)})
|
|
end
|
|
end
|
|
if entry[:object]
|
|
retain_list << entry[:object].uuid.to_sym
|
|
end
|
|
import_db << entry
|
|
entry[:content].each do |the_record|
|
|
link_db << the_record
|
|
end
|
|
else
|
|
raise ArgumentError, "Malformed import record."
|
|
end
|
|
end
|
|
# Set object internal data.
|
|
while import_db.size > 0 do
|
|
entry = import_db.shift
|
|
if entry
|
|
entry[:object].set_attributes(entry[:attributes])
|
|
entry[:object].set_classes(entry[:classes])
|
|
entry[:object].set_style(entry[:style])
|
|
entry[:object].set_features(entry[:browsing])
|
|
entry[:object].set_authoring_features(entry[:authoring])
|
|
entry[:object].set_options(entry[:options])
|
|
entry[:object].set_value(entry[:value])
|
|
end
|
|
end
|
|
# Render new state information to the DOM.
|
|
post_event(:display) do
|
|
self.render_dom
|
|
end
|
|
# Eliminate objects NOT included in this key-frame importation.
|
|
old_list.each do |the_key|
|
|
unless retain_list.include?(the_key)
|
|
# unregister the_key object_by_uuid
|
|
old_object = GxG::object_by_uuid(the_key)
|
|
unless old_object.is_a?(::GxG::Gui::Display)
|
|
if GxG::unregister(the_key) && old_object
|
|
# de-activate object
|
|
old_object.deactivate()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
result = true
|
|
end
|
|
result
|
|
end
|
|
# Server synchronization methods:
|
|
def transmit_keyframe()
|
|
keyframe = self.export_display()
|
|
if keyframe.is_a?(::Hash)
|
|
gxg_message = new_message
|
|
gxg_message[:sender] = @uuid
|
|
gxg_message[:to] = @remote_uuid
|
|
gxg_message[:body] = {:method => "import_display", :parameters => keyframe}
|
|
@channel.remote_call(gxg_message)
|
|
end
|
|
end
|
|
#
|
|
def transmit_update()
|
|
if @update_queue.size > 0
|
|
gxg_message = new_message
|
|
gxg_message[:sender] = @uuid
|
|
gxg_message[:to] = @remote_uuid
|
|
gxg_message[:body] = {:method => "receive_update", :parameters => {:operation => "update", :records => @update_queue}}
|
|
@channel.remote_call(gxg_message)
|
|
@update_queue = []
|
|
end
|
|
end
|
|
#
|
|
def transmit_event(the_event_frame=nil)
|
|
if the_event_frame.is_any?(::Hash, ::Array)
|
|
gxg_message = new_message
|
|
gxg_message[:sender] = @uuid
|
|
gxg_message[:to] = @remote_uuid
|
|
gxg_message[:body] = {:method => "receive_update", :parameters => {:operation => "pass_event", :events => the_event_frame}}
|
|
@channel.remote_call(gxg_message)
|
|
end
|
|
end
|
|
#
|
|
def receive_update(operation_frame={})
|
|
if operation_frame.is_a?(::Hash)
|
|
case operation_frame[:operation]
|
|
when "update"
|
|
if operation_frame[:records].is_a?(::Array)
|
|
operation_frame[:records].each do |the_delta|
|
|
dom_sync = true
|
|
the_object = GxG::object_by_uuid(the_delta[:uuid].to_sym)
|
|
if the_object
|
|
if the_delta[:attributes].is_a?(::Hash)
|
|
the_object.set_attributes(the_delta[:attributes])
|
|
end
|
|
if the_delta[:classes]
|
|
the_object.set_classes(the_delta[:classes])
|
|
end
|
|
if the_delta[:style].is_a?(::Hash)
|
|
the_object.set_style(the_delta[:style])
|
|
end
|
|
if the_delta[:browsing].is_a?(::Hash)
|
|
the_object.set_features(the_delta[:browsing])
|
|
end
|
|
if the_delta[:authoring].is_a?(::Hash)
|
|
the_object.set_authoring_features(the_delta[:authoring])
|
|
end
|
|
if the_delta[:options].is_a?(::Hash)
|
|
# Options only come FROM the server (One-Way)
|
|
if the_delta[:options][:visibility]
|
|
dom_sync = false
|
|
case the_delta[:options][:visibility]
|
|
when "show"
|
|
the_object.show()
|
|
when "hide"
|
|
the_object.hide()
|
|
when "toggle"
|
|
the_object.toggle_visibility()
|
|
end
|
|
else
|
|
the_object.set_options(the_delta[:options])
|
|
end
|
|
end
|
|
if the_delta[:value]
|
|
the_object.set_value(the_delta[:value])
|
|
end
|
|
if dom_sync == true
|
|
the_object.sync_to_dom()
|
|
end
|
|
else
|
|
puts "No Object for #{the_delta[:uuid]}"
|
|
end
|
|
end
|
|
end
|
|
when "remove"
|
|
if operation_frame[:operation][:manifest].is_a?(::Array)
|
|
operation_frame[:operation][:manifest].each do |the_uuid|
|
|
the_object = GxG::object_by_uuid(the_uuid.to_sym)
|
|
if the_object
|
|
the_object.deactivate()
|
|
GxG::unregister(the_uuid.to_sym)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
#
|
|
def post_update(the_delta=nil)
|
|
if the_delta.is_a?(::Hash)
|
|
@update_queue << the_delta
|
|
end
|
|
end
|
|
#
|
|
def process_event(the_frame=nil)
|
|
if the_frame.is_a?(::Hash)
|
|
record = {:type => the_frame[:event].type.to_s, :details => {}}
|
|
# ???
|
|
# puts "#{the_frame[:event].public_methods.sort.inspect}"
|
|
# common details
|
|
record[:details][:page_x] = the_frame[:event].page_x
|
|
record[:details][:page_y] = the_frame[:event].page_y
|
|
record[:details][:which] = the_frame[:event].which
|
|
record[:details][:meta_key] = the_frame[:event].meta_key
|
|
record[:details][:alt_key] = the_frame[:event].alt_key
|
|
record[:details][:shift_key] = the_frame[:event].shift_key
|
|
record[:details][:control_key] = the_frame[:event].ctrl_key
|
|
if the_frame[:data]
|
|
record[:details][:data] = the_frame[:data]
|
|
else
|
|
record[:details][:data] = nil
|
|
end
|
|
# type-specific details
|
|
the_frame[:event] = record
|
|
#
|
|
self.transmit_event(the_frame)
|
|
end
|
|
end
|
|
# State setting methods:
|
|
def get_attributes()
|
|
@attributes
|
|
end
|
|
#
|
|
def set_attributes(data={})
|
|
@attributes = data
|
|
end
|
|
#
|
|
def get_style()
|
|
@style
|
|
end
|
|
#
|
|
def set_style(style_data={})
|
|
@style = style_data
|
|
end
|
|
#
|
|
def get_value()
|
|
@value
|
|
end
|
|
#
|
|
def set_value(data=nil)
|
|
@value = data
|
|
end
|
|
#
|
|
def get_classes()
|
|
@classes
|
|
end
|
|
#
|
|
def set_classes(data="")
|
|
@classes = data
|
|
end
|
|
#
|
|
def get_features()
|
|
@browsing
|
|
end
|
|
#
|
|
def set_features(data={})
|
|
@browsing = data
|
|
end
|
|
#
|
|
def get_authoring_features()
|
|
@authoring
|
|
end
|
|
#
|
|
def set_authoring_features(data={})
|
|
@authoring = data
|
|
end
|
|
#
|
|
def get_options()
|
|
@options
|
|
end
|
|
#
|
|
def set_options(data={})
|
|
@options = data
|
|
end
|
|
#
|
|
def generate_html()
|
|
accumulator = []
|
|
contents = GxG::children_of(self)
|
|
contents.each do |the_object|
|
|
accumulator << the_object.generate_html()
|
|
end
|
|
accumulator.join("\n")
|
|
end
|
|
#
|
|
def render_dom(settings={})
|
|
# FIX: Make non-recursive, iterative.
|
|
# Generate a complete replacement for the current DOM content.
|
|
# Assume NO dom_objects are internally available to the child objects.
|
|
# Call generate_html on each child
|
|
new_dom_html = self.generate_html()
|
|
::Element.find('body').append(::Element::parse(new_dom_html))
|
|
# call establish_dom_link on each object after DOM commit.
|
|
link_db = [(self)]
|
|
while link_db.size > 0 do
|
|
entry = link_db.shift
|
|
GxG::children_of(entry).each do |the_object|
|
|
the_object.activate()
|
|
link_db << the_object
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
def refresh_dom()
|
|
link_db = [(self)]
|
|
while link_db.size > 0 do
|
|
entry = link_db.shift
|
|
GxG::children_of(entry).each do |the_object|
|
|
the_object.sync_to_dom()
|
|
link_db << the_object
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
def switch_to_mode(the_mode=:browsing)
|
|
if the_mode.is_a?(String)
|
|
the_mode = the_mode.to_sym
|
|
end
|
|
if GxG::DISPLAY_DETAILS[:mode] == :authoring
|
|
if the_mode == :browsing
|
|
# switch back to browsing mode
|
|
GxG::DISPLAY_DETAILS[:mode] = :browsing
|
|
link_db = [(self)]
|
|
while link_db.size > 0 do
|
|
entry = link_db.shift
|
|
GxG::children_of(entry).each do |the_object|
|
|
the_object.sync_from_dom()
|
|
the_object.activate()
|
|
link_db << the_object
|
|
end
|
|
end
|
|
# TODO: update server gui-mode as well
|
|
end
|
|
else
|
|
if the_mode == :authoring
|
|
# switch to authoring mode
|
|
GxG::DISPLAY_DETAILS[:mode] = :authoring
|
|
link_db = [(self)]
|
|
while link_db.size > 0 do
|
|
entry = link_db.shift
|
|
GxG::children_of(entry).each do |the_object|
|
|
the_object.sync_from_dom()
|
|
the_object.activate()
|
|
link_db << the_object
|
|
end
|
|
end
|
|
# TODO: update server gui-mode as well
|
|
end
|
|
end
|
|
end
|
|
#
|
|
def activate()
|
|
# No-op for display object
|
|
end
|
|
#
|
|
def deactivate(settings={})
|
|
# No-op for display object
|
|
end
|
|
end
|
|
#
|
|
class GuiComponent
|
|
# Abstract Class - only instantiate sub-classes.
|
|
def self.class_mapping()
|
|
{
|
|
:display => GxG::Gui::Display,
|
|
:background => GxG::Gui::Background,
|
|
:page => GxG::Gui::Page,
|
|
:window => GxG::Gui::Window,
|
|
:menubar => GxG::Gui::MenuBar,
|
|
:accordion => GxG::Gui::Accordion,
|
|
:accordion_section => GxG::Gui::AccordionSection,
|
|
:accordion_section_label => GxG::Gui::AccordionSectionLabel,
|
|
:accordion_section_content => GxG::Gui::AccordionSectionContent,
|
|
:anchor => GxG::Gui::Anchor,
|
|
:button => GxG::Gui::Button,
|
|
:division => GxG::Gui::Division,
|
|
:input_label => GxG::Gui::InputLabel,
|
|
:paragraph => GxG::Gui::Paragraph,
|
|
:text_lable => GxG::Gui::TextLabel,
|
|
:legend => GxG::Gui::Legend,
|
|
:list_item => GxG::Gui::ListItem,
|
|
:ordered_list => GxG::Gui::OrderedList,
|
|
:unordered_list => GxG::Gui::UnorderedList,
|
|
:control_group => GxG::Gui::ControlGroup,
|
|
:field_set => GxG::Gui::FieldSet,
|
|
:text_input => GxG::Gui::TextInput,
|
|
:date_picker => GxG::Gui::DatePicker,
|
|
:menu => GxG::Gui::Menu,
|
|
:select_menu => GxG::Gui::SelectMenu,
|
|
:select_menu_option => GxG::Gui::SelectMenuOption,
|
|
:slider => GxG::Gui::Slider,
|
|
:spinner => GxG::Gui::Spinner,
|
|
:progress_bar => GxG::Gui::ProgressBar,
|
|
:tabs => GxG::Gui::Tabs,
|
|
:tab_section => GxG::Gui::TabSection,
|
|
:table => GxG::Gui::Table,
|
|
:table_row => GxG::Gui::TableRow,
|
|
:table_header => GxG::Gui::TableHeader,
|
|
:table_data => GxG::Gui::TableData,
|
|
:image => GxG::Gui::Image
|
|
}
|
|
end
|
|
#
|
|
def self.key_to_class(the_key)
|
|
GxG::Gui::GuiComponent::class_mapping()[(the_key)]
|
|
end
|
|
#
|
|
def self.class_to_key(the_class)
|
|
result = nil
|
|
mapping = GxG::Gui::GuiComponent::class_mapping()
|
|
mapping.keys.each do |the_key|
|
|
if mapping[(the_key)] == the_class
|
|
result = the_key
|
|
break
|
|
end
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def initialize(settings={})
|
|
@uuid = (settings[:uuid] || GxG::uuid_generate)
|
|
@parent = settings[:parent]
|
|
# Class, Style, and Features are for cached for browse-mode only.
|
|
@base_tag = "div"
|
|
@attributes = {}
|
|
@classes = ""
|
|
@style = {}
|
|
@browsing = {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""}
|
|
@authoring = {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""}
|
|
@options = {}
|
|
@value = nil
|
|
@dom_object = nil
|
|
@visible = true
|
|
GxG::register(self,@parent)
|
|
end
|
|
#
|
|
def uuid()
|
|
@uuid
|
|
end
|
|
#
|
|
def dom_object()
|
|
@dom_object
|
|
end
|
|
#
|
|
def visible?()
|
|
@visible
|
|
end
|
|
#
|
|
def hide()
|
|
if @dom_object
|
|
@dom_object.hide()
|
|
@visible = false
|
|
end
|
|
end
|
|
#
|
|
def show()
|
|
if @dom_object
|
|
@dom_object.show()
|
|
@visible = true
|
|
end
|
|
end
|
|
#
|
|
def toggle_visibility()
|
|
if @dom_object
|
|
if @visible == true
|
|
self.hide()
|
|
else
|
|
self.show()
|
|
end
|
|
end
|
|
end
|
|
#
|
|
def establish_dom_link()
|
|
#
|
|
@dom_object = Element.find("##{@uuid.to_s}")
|
|
if @dom_object
|
|
# Set event traps on @dom_object
|
|
# ???
|
|
@dom_object.on :dblclick do |event|
|
|
GxG::DISPLAY_DETAILS[:object].process_event({:uuid => @uuid, :event => event})
|
|
end
|
|
@dom_object.on :mouseup do |event|
|
|
GxG::DISPLAY_DETAILS[:object].process_event({:uuid => @uuid, :event => event})
|
|
end
|
|
@dom_object.on :mousedown do |event|
|
|
GxG::DISPLAY_DETAILS[:object].process_event({:uuid => @uuid, :event => event})
|
|
end
|
|
# @dom_object.on :mouseenter do |event|
|
|
# GxG::DISPLAY_DETAILS[:object].process_event({:uuid => @uuid, :event => event})
|
|
# end
|
|
# @dom_object.on :mouseleave do |event|
|
|
# GxG::DISPLAY_DETAILS[:object].process_event({:uuid => @uuid, :event => event})
|
|
# end
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def get_dom_features()
|
|
valid_draggable_options = {:add_classes => "addClasses", :append_to => "appendTo", :axis => "axis", :cancel => "cancel", :classes => "classes", :connect_to_sortable => "connectToSortable", :containment => "containment", :cursor => "cursor", :cursor_at => "cursorAt", :delay => "delay", :disabled => "disabled", :distance => "distance", :grid => "grid", :handle => "handle", :helper => "helper", :iframe_fix => "iframeFix", :opacity => "opacity", :refresh_positions => "refreshPositions", :revert => "revert", :revert_duration => "revertDuration", :scope => "scope", :scroll => "scroll", :scroll_sensitivity => "scrollSensitivity", :scroll_speed => "scrollSpeed", :snap => "snap", :snap_mode => "snapMode", :snap_tolerance => "snapTolerance", :stack => "stack", :z_index => "z-index"}
|
|
valid_droppable_options = {:accept => "accept", :active_class => "activeClass", :add_classes => "addClasses", :classes => "classes", :disabled => "disabled", :greedy => "greedy", :hover_class => "hoverClass", :scope => "scope", :tolerance => "tolerance"}
|
|
valid_resizable_options = {:also_resize => "alsoResize", :animate => "animate", :animate_duration => "animateDuration", :animate_easing => "animateEasing", :aspect_ration => "aspectRatio", :auto_hide => "autoHide", :cancel => "cancel", :classes => "classes", :containment => "containment", :delay => "delay", :disabled => "disabled", :distance => "distance", :ghost => "ghost", :grid => "grid", :handles => "handles", :helper => "helper", :max_height => "maxHeight", :max_width => "maxWidth"}
|
|
valid_selectable_options = {:append_to => "appendTo", :auto_refresh => "autoRefresh", :cancel => "cancel", :classes => "classes", :delay => "delay", :disabled => "disabled", :distance => "distance", :filter => "filter", :tolerance => "tolerance"}
|
|
valid_sortable_options = {:append_to => "appendTo", :axis => "axis", :cancel => "cancel", :classes => "classes", :connect_with => "connectWith", :cursor => "cursor", :cursor_at => "cursorAt", :delay => "delay", :disabled => "disabled", :distance => "distance", :drop_on_empty => "dropOnEmpty", :grid => "grid", :handle => "handle", :helper => "helper", :items => "items", :opacity => "opacity", :placeholder => "placeholder", :revert => "revert", :scroll => "scroll", :scroll_sensitivity => "scrollSensitivity", :scroll_speed => "scrollSpeed", :tolerance => "tolerance", :z_index => "z-index"}
|
|
# TODO: include tool_tip in process.
|
|
the_features = {:draggable => {}, :droppable => {}, :resizable => {}, :selectable => {}, :sortable => {}, :tool_tip => {}, :alt_text => ""}
|
|
if @dom_object
|
|
begin
|
|
valid_draggable_options.keys.each do |the_option_key|
|
|
unless [].include?(the_option_key)
|
|
the_features[:draggable][(the_option_key)] = @dom_object.draggable("option",(valid_draggable_options[(the_option_key)]))
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
end
|
|
#
|
|
begin
|
|
valid_droppable_options.keys.each do |the_option_key|
|
|
unless [].include?(the_option_key)
|
|
the_features[:droppable][(the_option_key)] = @dom_object.droppable("option",(valid_droppable_options[(the_option_key)]))
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
end
|
|
#
|
|
begin
|
|
valid_resizable_options.keys.each do |the_option_key|
|
|
unless [].include?(the_option_key)
|
|
the_features[:resizable][(the_option_key)] = @dom_object.resizable("option",(valid_resizable_options[(the_option_key)]))
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
end
|
|
#
|
|
begin
|
|
valid_selectable_options.keys.each do |the_option_key|
|
|
unless [].include?(the_option_key)
|
|
the_features[:selectable][(the_option_key)] = @dom_object.selectable("option",(valid_selectable_options[(the_option_key)]))
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
end
|
|
#
|
|
begin
|
|
valid_sortable_options.keys.each do |the_option_key|
|
|
unless [].include?(the_option_key)
|
|
the_features[:sortable][(the_option_key)] = @dom_object.sortable("option",(valid_sortable_options[(the_option_key)]))
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
end
|
|
#
|
|
end
|
|
#
|
|
the_features
|
|
end
|
|
#
|
|
def set_dom_features(the_features=nil)
|
|
valid_draggable_options = {:add_classes => "addClasses", :append_to => "appendTo", :axis => "axis", :cancel => "cancel", :classes => "classes", :connect_to_sortable => "connectToSortable", :containment => "containment", :cursor => "cursor", :cursor_at => "cursorAt", :delay => "delay", :disabled => "disabled", :distance => "distance", :grid => "grid", :handle => "handle", :helper => "helper", :iframe_fix => "iframeFix", :opacity => "opacity", :refresh_positions => "refreshPositions", :revert => "revert", :revert_duration => "revertDuration", :scope => "scope", :scroll => "scroll", :scroll_sensitivity => "scrollSensitivity", :scroll_speed => "scrollSpeed", :snap => "snap", :snap_mode => "snapMode", :snap_tolerance => "snapTolerance", :stack => "stack", :z_index => "z-index"}
|
|
valid_droppable_options = {:accept => "accept", :active_class => "activeClass", :add_classes => "addClasses", :classes => "classes", :disabled => "disabled", :greedy => "greedy", :hover_class => "hoverClass", :scope => "scope", :tolerance => "tolerance"}
|
|
valid_resizable_options = {:also_resize => "alsoResize", :animate => "animate", :animate_duration => "animateDuration", :animate_easing => "animateEasing", :aspect_ration => "aspectRatio", :auto_hide => "autoHide", :cancel => "cancel", :classes => "classes", :containment => "containment", :delay => "delay", :disabled => "disabled", :distance => "distance", :ghost => "ghost", :grid => "grid", :handles => "handles", :helper => "helper", :max_height => "maxHeight", :max_width => "maxWidth"}
|
|
valid_selectable_options = {:append_to => "appendTo", :auto_refresh => "autoRefresh", :cancel => "cancel", :classes => "classes", :delay => "delay", :disabled => "disabled", :distance => "distance", :filter => "filter", :tolerance => "tolerance"}
|
|
valid_sortable_options = {:append_to => "appendTo", :axis => "axis", :cancel => "cancel", :classes => "classes", :connect_with => "connectWith", :cursor => "cursor", :cursor_at => "cursorAt", :delay => "delay", :disabled => "disabled", :distance => "distance", :drop_on_empty => "dropOnEmpty", :grid => "grid", :handle => "handle", :helper => "helper", :items => "items", :opacity => "opacity", :placeholder => "placeholder", :revert => "revert", :scroll => "scroll", :scroll_sensitivity => "scrollSensitivity", :scroll_speed => "scrollSpeed", :tolerance => "tolerance", :z_index => "z-index"}
|
|
#
|
|
unless the_features.is_a?(::Hash)
|
|
the_features = @browsing
|
|
end
|
|
if @dom_object
|
|
if the_features[:draggable][:enable] == true
|
|
@dom_object.draggable()
|
|
the_features[:draggable].keys.each do |the_option_key|
|
|
if valid_draggable_options.keys.include?(the_option_key) && the_option_key != :enable
|
|
@dom_object.draggable("option",(valid_draggable_options[(the_option_key)]),(the_features[:draggable][(the_option_key)]))
|
|
end
|
|
end
|
|
else
|
|
# @dom_object.draggable('disable')
|
|
end
|
|
if the_features[:droppable][:enable] == true
|
|
@dom_object.droppable()
|
|
the_features[:droppable].keys.each do |the_option_key|
|
|
if valid_droppable_options.keys.include?(the_option_key) && the_option_key != :enable
|
|
@dom_object.droppable("option",(valid_droppable_options[(the_option_key)]),(the_features[:droppable][(the_option_key)]))
|
|
end
|
|
end
|
|
else
|
|
# @dom_object.droppable('disable')
|
|
end
|
|
if the_features[:resizable][:enable] == true
|
|
@dom_object.resizable()
|
|
the_features[:resizable].keys.each do |the_option_key|
|
|
if valid_resizable_options.keys.include?(the_option_key) && the_option_key != :enable
|
|
@dom_object.resizable("option",(valid_resizable_options[(the_option_key)]),(the_features[:resizable][(the_option_key)]))
|
|
end
|
|
end
|
|
else
|
|
# @dom_object.resizable('disable')
|
|
end
|
|
if the_features[:selectable][:enable] == true
|
|
@dom_object.selectable()
|
|
the_features[:selectable].keys.each do |the_option_key|
|
|
if valid_selectable_options.keys.include?(the_option_key) && the_option_key != :enable
|
|
@dom_object.selectable("option",(valid_selectable_options[(the_option_key)]),(the_features[:selectable][(the_option_key)]))
|
|
end
|
|
end
|
|
else
|
|
# @dom_object.selectable('disable')
|
|
end
|
|
if the_features[:sortable][:enable] == true
|
|
@dom_object.sortable()
|
|
the_features[:sortable].keys.each do |the_option_key|
|
|
if valid_sortable_options.keys.include?(the_option_key) && the_option_key != :enable
|
|
@dom_object.sortable("option",(valid_sortable_options[(the_option_key)]),(the_features[:sortable][(the_option_key)]))
|
|
end
|
|
end
|
|
else
|
|
# @dom_object.sortable('disable')
|
|
end
|
|
end
|
|
#
|
|
true
|
|
end
|
|
#
|
|
def activate()
|
|
unless @dom_object
|
|
self.establish_dom_link
|
|
end
|
|
if @dom_object
|
|
#
|
|
unless self.is_any?(GxG::Gui::Background, GxG::Gui::Page, GxG::Gui::Window)
|
|
# unless in :authoring mode:
|
|
if GxG::DISPLAY_DETAILS[:mode] == :authoring
|
|
self.set_dom_features(@authoring)
|
|
else
|
|
self.set_dom_features(@browsing)
|
|
end
|
|
# TODO: figure out how to incorporate @browsing[:tool_tip]
|
|
end
|
|
#
|
|
end
|
|
#
|
|
end
|
|
#
|
|
def deactivate(settings={})
|
|
if @dom_object
|
|
begin
|
|
@dom_object.remove
|
|
rescue Exception
|
|
end
|
|
@dom_object = nil
|
|
end
|
|
end
|
|
#
|
|
def components()
|
|
GxG::children_of(self)
|
|
end
|
|
#
|
|
def add_component(the_type=nil, settings={})
|
|
result = nil
|
|
if the_type.is_any?(::String, ::Symbol)
|
|
# [:display, :background, :page, :window, :menubar, :accordion, :accordion_section, :accordion_section_label, :accordion_section_content, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :list_item, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :select_menu_option, :slider, :spinner, :progress_bar, :tabs, :tab_section]
|
|
viable = []
|
|
case GxG::Gui::GuiComponent::class_to_key(self.class)
|
|
when :background
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :page
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :menubar
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :window
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :accordion
|
|
viable = [:accordion_section]
|
|
when :accordion_section
|
|
viable = [:accordion_section_label, :accordion_section_content]
|
|
when :accordion_section_label
|
|
viable = []
|
|
when :accordion_section_content
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :anchor
|
|
viable = []
|
|
when :button
|
|
viable = []
|
|
when :division
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :input_label
|
|
viable = []
|
|
when :paragraph
|
|
viable = []
|
|
when :text_label
|
|
viable = []
|
|
when :legend
|
|
viable = []
|
|
when :list_item
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :ordered_list
|
|
viable = [:list_item]
|
|
when :unordered_list
|
|
viable = [:list_item]
|
|
when :control_group
|
|
viable = [:anchor, :button, :input_label, :text_lable, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar]
|
|
when :field_set
|
|
viable = [:anchor, :button, :input_label, :text_lable, :text_input, :legend, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar]
|
|
when :text_input
|
|
viable = []
|
|
when :date_picker
|
|
viable = []
|
|
when :menu
|
|
viable = []
|
|
when :select_menu
|
|
viable = [:select_menu_option]
|
|
when :select_menu_option
|
|
viable = []
|
|
when :slider
|
|
viable = []
|
|
when :spinner
|
|
viable = []
|
|
when :progress_bar
|
|
viable = []
|
|
when :tabs
|
|
viable = [:tab_section]
|
|
when :tab_section
|
|
viable = [:accordion, :anchor, :button, :division, :input_label, :paragraph, :text_lable, :legend, :ordered_list, :unordered_list, :control_group, :field_set, :text_input, :date_picker, :menu, :select_menu, :slider, :spinner, :progress_bar, :tabs, :table, :image]
|
|
when :table
|
|
viable = [:table_row]
|
|
when :table_row
|
|
viable = [:table_header, :table_data]
|
|
when :image
|
|
viable = []
|
|
end
|
|
#
|
|
if viable.include?(the_type.to_sym)
|
|
the_class = GxG::Gui::GuiComponent::key_to_class(the_type.to_sym)
|
|
if the_class
|
|
result = the_class.new(settings.merge({:parent => self}))
|
|
else
|
|
# err
|
|
end
|
|
else
|
|
# err
|
|
end
|
|
#
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def receive_an_update(the_delta=nil)
|
|
if the_delta.is_a?(::Hash)
|
|
# TODO: fine-grained updates
|
|
if the_delta[:attributes].is_a?(::Hash)
|
|
self.set_attributes(the_delta[:attributes])
|
|
end
|
|
if the_delta[:classes]
|
|
self.set_classes(the_delta[:classes])
|
|
end
|
|
if the_delta[:style].is_a?(::Hash)
|
|
self.set_style(the_delta[:style])
|
|
end
|
|
if the_delta[:browsing].is_a?(::Hash)
|
|
self.set_features(the_delta[:browsing])
|
|
end
|
|
if the_delta[:authoring].is_a?(::Hash)
|
|
self.set_authoring_features(the_delta[:authoring])
|
|
end
|
|
if the_delta[:options].is_a?(::Hash)
|
|
self.set_options(the_delta[:options])
|
|
end
|
|
if the_delta[:value]
|
|
self.set_value(the_delta[:value])
|
|
end
|
|
self.sync_to_dom()
|
|
# ???
|
|
end
|
|
end
|
|
#
|
|
def get_attributes()
|
|
@attributes
|
|
end
|
|
#
|
|
def set_attributes(data={})
|
|
@attributes = data
|
|
end
|
|
#
|
|
def get_style()
|
|
@style
|
|
end
|
|
#
|
|
def set_style(style_data={})
|
|
@style = style_data
|
|
end
|
|
#
|
|
def get_value()
|
|
@value
|
|
end
|
|
#
|
|
def set_value(data=nil)
|
|
@value = data
|
|
end
|
|
#
|
|
def get_classes()
|
|
@classes
|
|
end
|
|
#
|
|
def set_classes(data=nil)
|
|
@classes = data.to_s
|
|
end
|
|
#
|
|
def get_features()
|
|
@browsing
|
|
end
|
|
#
|
|
def set_features(data={})
|
|
@browsing = data
|
|
end
|
|
#
|
|
def get_authoring_features()
|
|
@authoring
|
|
end
|
|
#
|
|
def set_authoring_features(data={})
|
|
@authoring = data
|
|
end
|
|
#
|
|
def get_options()
|
|
@options
|
|
end
|
|
#
|
|
def set_options(data={})
|
|
# ???
|
|
if data.is_a?(::Hash)
|
|
data.keys.each do |op_key|
|
|
if op_key == :visibility
|
|
case op_key
|
|
when "hide"
|
|
self.hide()
|
|
when "show"
|
|
self.show()
|
|
when "toggle"
|
|
self.toggle_visibility()
|
|
end
|
|
else
|
|
@options[(op_key.to_sym)] = data[(op_key)]
|
|
end
|
|
end
|
|
end
|
|
#
|
|
end
|
|
# Rendering to DOM
|
|
def generate_html()
|
|
# TODO: figure out where to incorporate @browsing[:alt_text] (string) into html tag output. (508 compliance)
|
|
if @classes.size > 0
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}' class='#{@classes.to_s}'"
|
|
else
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}'"
|
|
end
|
|
#
|
|
if @attributes.size > 0
|
|
@attributes.keys.each do |the_key|
|
|
result = result + " #{the_key.to_s}='#{@attributes[(the_key)].to_s}'"
|
|
end
|
|
end
|
|
#
|
|
if @style.keys.size > 0
|
|
style_string = " style='"
|
|
else
|
|
style_string = ""
|
|
end
|
|
@style.keys.each do |the_key|
|
|
unless @style[(the_key)] == ""
|
|
# ???
|
|
# the_property = GxG::Css::get_property_name(the_key)
|
|
the_property = (the_key.to_s.gsub("_","-"))
|
|
if the_property
|
|
style_string = style_string + " #{the_property.to_s}: #{@style[(the_key)].to_s};"
|
|
end
|
|
end
|
|
end
|
|
if style_string.size > 0
|
|
result = (result + style_string + "'")
|
|
end
|
|
if ["button", "input", "li", "option", "progress", "param"].include?(@base_tag)
|
|
# value is in the main tag def.
|
|
if @attributes[:value]
|
|
result = result + ">"
|
|
else
|
|
if @value
|
|
result = (result + " value='" + @value.to_s + "'>")
|
|
else
|
|
result = result + ">"
|
|
end
|
|
end
|
|
else
|
|
# close the main tag def.
|
|
result = result + ">"
|
|
end
|
|
accumulator = []
|
|
contents = GxG::children_of(self)
|
|
contents.each do |the_object|
|
|
accumulator << the_object.generate_html()
|
|
end
|
|
if (@attributes[:value] || self.respond_to?(:set_dom_value))
|
|
result = (result + accumulator.join("\n") + "</#{@base_tag.to_s}>")
|
|
else
|
|
if ["button", "input", "li", "option", "progress", "param"].include?(@base_tag)
|
|
result = (result + accumulator.join("\n") + "</#{@base_tag.to_s}>")
|
|
else
|
|
# value is in-line text
|
|
if @value
|
|
result = (result + @value.to_s + accumulator.join("\n") + "</#{@base_tag.to_s}>")
|
|
else
|
|
result = (result + accumulator.join("\n") + "</#{@base_tag.to_s}>")
|
|
end
|
|
end
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def sync_to_dom()
|
|
if @dom_object
|
|
@dom_object.attr("class",@classes)
|
|
@style.keys.each do |css_key|
|
|
the_name = ::GxG::Css::get_property_name(css_key)
|
|
if the_name
|
|
@dom_object.css(the_name.to_s,@style[(css_key)])
|
|
end
|
|
end
|
|
@attributes.keys.each do |attr_key|
|
|
@dom_object.attr(attr_key.to_s,@attributes[(attr_key)])
|
|
end
|
|
unless @attributes[:value]
|
|
unless @base_tag == "div"
|
|
# @dom_object.innerHTML = @value.to_s
|
|
@dom_object.html(@value.to_s).fadeIn(500)
|
|
end
|
|
end
|
|
#
|
|
if GxG::DISPLAY_DETAILS[:mode] == :authoring
|
|
self.set_dom_features(self.get_authoring_features())
|
|
else
|
|
self.set_dom_features(self.get_features())
|
|
end
|
|
#
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def sync_from_dom()
|
|
# Produces a state delta record to send to the server, as well as sets state to match dom.
|
|
delta = nil
|
|
if @dom_object
|
|
delta = {}
|
|
the_class = @dom_object.attr("class")
|
|
if the_class != @classes
|
|
@classes = the_class
|
|
delta[:classes] = the_class
|
|
end
|
|
new_style = {}
|
|
::GxG::Css::valid_properties.each do |prop_key|
|
|
the_name = ::GxG::Css::get_property_name(prop_key)
|
|
if the_name && @style[(prop_key)]
|
|
new_style[(prop_key)] = @dom_object.css(the_name.to_s)
|
|
end
|
|
end
|
|
if new_style.size > 0
|
|
if new_style != @style
|
|
@style = new_style
|
|
delta[:style] = new_style
|
|
end
|
|
end
|
|
if @attributes.size > 0
|
|
delta[:attributes] = {}
|
|
end
|
|
@attributes.keys.each do |attr_key|
|
|
unless attr_key.to_s == "class" || attr_key.to_s == "style"
|
|
the_attribute = @dom_object.attr(attr_key.to_s)
|
|
if @attributes[(attr_key)] != the_attribute
|
|
@attributes[(attr_key)] = the_attribute
|
|
delta[:attributes][(attr_key)] = the_attribute
|
|
end
|
|
end
|
|
end
|
|
unless @attributes[:value]
|
|
unless @base_tag == "div"
|
|
the_value = @dom_object.innerHTML
|
|
if @value != the_value
|
|
@value = the_value
|
|
delta[:value] = the_value
|
|
end
|
|
end
|
|
end
|
|
#
|
|
the_features = self.get_dom_features()
|
|
if GxG::DISPLAY_DETAILS[:mode] == :authoring
|
|
if @authoring != the_features
|
|
@authoring = the_features
|
|
delta[:authoring] = the_features
|
|
end
|
|
else
|
|
if @browsing != the_features
|
|
@browsing = the_features
|
|
delta[:browsing] = the_features
|
|
end
|
|
end
|
|
#
|
|
if delta.size > 0
|
|
delta[:uuid] = @uuid
|
|
else
|
|
delta = nil
|
|
end
|
|
end
|
|
delta
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Background < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "div"
|
|
# z-index of 0 or 1
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Page < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "div"
|
|
# z-index of 50
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Window < GuiComponent
|
|
#
|
|
#Window Options:
|
|
# Extended Options:
|
|
#closable
|
|
#
|
|
#Type: Boolean
|
|
#
|
|
#Usage: enable/disable close button
|
|
#
|
|
#Default: true
|
|
#maximizable
|
|
#
|
|
#Type: Boolean
|
|
#
|
|
#Usage: enable/disable maximize button
|
|
#
|
|
#Default: false
|
|
#minimizable
|
|
#
|
|
#Type: Boolean
|
|
#
|
|
#Usage: enable/disable minimize button
|
|
#
|
|
#Default: false
|
|
#collapsable
|
|
#
|
|
#Type: Boolean
|
|
#
|
|
#Usage: enable/disable collapse button
|
|
#
|
|
#Default: false
|
|
#minimizeLocation
|
|
#
|
|
#Type: String
|
|
#
|
|
#Usage: sets alignment of minimized dialogues
|
|
#
|
|
#Default: 'left'
|
|
#
|
|
#Valid: 'left', 'right'
|
|
#dblclick
|
|
#
|
|
#Type: Boolean, String
|
|
#
|
|
#Usage: set action on double click
|
|
#
|
|
#Default: false
|
|
#
|
|
#Valid: false, 'maximize', 'minimize', 'collapse'
|
|
#titlebar
|
|
#
|
|
#Type: Boolean, String
|
|
#
|
|
#Default: false
|
|
#
|
|
#Valid: false, 'none', 'transparent'
|
|
#icons
|
|
#
|
|
#Type: Object
|
|
#
|
|
#Default:
|
|
#
|
|
#{
|
|
# "close" : "ui-icon-circle-closethick", // new in v1.0.1
|
|
# "maximize" : "ui-icon-extlink",
|
|
# "minimize" : "ui-icon-minus",
|
|
# "restore" : "ui-icon-newwin"
|
|
#}
|
|
#
|
|
#Valid: <jQuery UI icon class>
|
|
# Basic Example:
|
|
# $("<div>This is content</div>")
|
|
# .dialog({ "title" : "My Dialog" })
|
|
# .dialogExtend({
|
|
# "maximizable" : true,
|
|
# "dblclick" : "maximize",
|
|
# "icons" : { "maximize" : "ui-icon-arrow-4-diag" }
|
|
# });
|
|
#
|
|
# So: @dom_object.dialog(standard_options).dialogExtend(extended_options)
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "div"
|
|
# minimum z-index of 100, managed by jQuery
|
|
# `#{@dom_object}.dialog(#{JSON.generate(standard_options)}).dialogExtend(#{JSON.generate(extended_options)})`
|
|
self
|
|
end
|
|
#
|
|
def activate()
|
|
super()
|
|
if @dom_object
|
|
valid_standard_options = {:append_to => "appendTo", :auto_open => "autoOpen", :buttons => "buttons", :classes => "classes",
|
|
:close_on_escape => "closeOnEscape", :close_text => "closeText", :dialog_class => "dialogClass", :draggable => "draggable",
|
|
:height => "height", :hide => "hide", :max_height => "maxHeight", :max_width => "maxWidth", :min_height => "minHeight",
|
|
:min_width => "minWidth", :modal => "modal", :position => "position", :resizable => "resizable", :show => "show", :title => "title",
|
|
:width => "width"}
|
|
valid_extended_options = {:closable => "closable", :maximizable => "maximizable", :minimizable => "minimizable",
|
|
:collapsable => "collapsable", :minimize_location => "minimizeLocation", :double_click => "dblclick", :titlebar => "titlebar",
|
|
:icons => "icons"}
|
|
standard_options = {}
|
|
extended_options = {}
|
|
@options.keys.each do |the_option|
|
|
if valid_standard_options.keys.include?(the_option)
|
|
standard_options[(valid_standard_options[(the_option)])] = @options[(the_option)]
|
|
end
|
|
if valid_extended_options.keys.include?(the_option)
|
|
extended_options[(valid_extended_options[(the_option)])] = @options[(the_option)]
|
|
end
|
|
end
|
|
#`#{@dom_object}.dialog(#{JSON.generate(standard_options)}).dialogExtend(#{JSON.generate(extended_options)})`
|
|
if extended_options.size > 0
|
|
@dom_object.dialog(standard_options).dialogExtend(extended_options)
|
|
else
|
|
@dom_object.dialog(standard_options)
|
|
end
|
|
end
|
|
end
|
|
#
|
|
def hide()
|
|
if @dom_object
|
|
@dom_object.dialog("hide")
|
|
@visible = false
|
|
end
|
|
end
|
|
#
|
|
def show()
|
|
if @dom_object
|
|
@dom_object.dialog("show")
|
|
@visible = true
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Accordion < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# `#{@dom_object}.accordion();`
|
|
# has: Title, and Content (sections)
|
|
self
|
|
end
|
|
#
|
|
def activate()
|
|
unless @dom_object
|
|
self.establish_dom_link
|
|
end
|
|
if @dom_object
|
|
@dom_object.accordion();
|
|
end
|
|
# super()
|
|
true
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class AccordionSection < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# has: AccordionSectionLabel, and AccordionSectionContent: (any)
|
|
# some compound-obj slight of hand here.
|
|
#
|
|
@banner = nil
|
|
@content = nil
|
|
self
|
|
end
|
|
#
|
|
def establish_dom_link()
|
|
unless @banner && @content
|
|
contents = GxG::children_of(self)
|
|
contents.each do |the_object|
|
|
if the_object.is_a?(GxG::Gui::AccordionSectionLabel)
|
|
@banner = the_object
|
|
end
|
|
if the_object.is_a?(GxG::Gui::AccordionSectionContent)
|
|
@content = the_object
|
|
end
|
|
if @banner && @content
|
|
break
|
|
end
|
|
end
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def activate()
|
|
unless @banner && @content
|
|
self.establish_dom_link()
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def deactivate()
|
|
true
|
|
end
|
|
#
|
|
def generate_html()
|
|
accumulator = []
|
|
contents = GxG::children_of(self)
|
|
contents.each do |the_object|
|
|
accumulator << the_object.generate_html()
|
|
end
|
|
accumulator.join("\n")
|
|
end
|
|
#
|
|
def sync_to_dom()
|
|
# this is called on the banner and content elsewhere
|
|
true
|
|
end
|
|
#
|
|
def sync_from_dom()
|
|
# this is called on the banner and content elsewhere ?
|
|
nil
|
|
end
|
|
#
|
|
def hide()
|
|
# No-op
|
|
end
|
|
#
|
|
def show()
|
|
# No-op
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class AccordionSectionLabel < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "H3"
|
|
# text held in @value ?
|
|
self
|
|
end
|
|
#
|
|
def set_options(options={})
|
|
@options = options
|
|
if options[:font_size].is_a?(Numeric)
|
|
# Font size in EM units only
|
|
case options[:font_size].to_f
|
|
when 2.0
|
|
@base_tag = "H1"
|
|
when 1.5
|
|
@base_tag = "H2"
|
|
when 1.17
|
|
@base_tag = "H3"
|
|
when 1.0
|
|
@base_tag = "H4"
|
|
when 0.83
|
|
@base_tag = "H5"
|
|
when 0.67
|
|
@base_tag = "H6"
|
|
else
|
|
@base_tag = "H3"
|
|
@style[:'font-size'] = "#{options[:font_size].to_f}em"
|
|
end
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class AccordionSectionContent < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Anchor < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "a"
|
|
# a (anchor) tag
|
|
# has: href, and text value.
|
|
self
|
|
end
|
|
#
|
|
def generate_html()
|
|
super({:href => "#"})
|
|
end
|
|
end
|
|
#
|
|
class Button < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "button"
|
|
# button tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class RadioButton < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "input"
|
|
@attributes[:type] = "radio"
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class CheckBoxButton < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "input"
|
|
@attributes[:type] = "checkbox"
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Division < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "div"
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class InputLabel < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "label"
|
|
# label tag
|
|
# for=(a control uuid)
|
|
self
|
|
end
|
|
#
|
|
def set_options(options={})
|
|
@options = options
|
|
if options[:font_size].is_a?(Numeric)
|
|
# Font size in EM units only
|
|
@style[:'font-size'] = "#{options[:font_size].to_f}em"
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Paragraph < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "p"
|
|
# p tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class TextLabel < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "h1"
|
|
# h1 tag
|
|
self
|
|
end
|
|
#
|
|
def set_options(options={})
|
|
@options = options
|
|
if options[:font_size].is_a?(Numeric)
|
|
# Font size in EM units only
|
|
@style[:'font-size'] = "#{options[:font_size].to_f}em"
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Legend < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "legend"
|
|
# legend tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class ListItem < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "li"
|
|
# li tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class OrderedList < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "ol"
|
|
# ol tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class UnorderedList < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "ul"
|
|
# ul tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class ControlGroup < GuiComponent
|
|
# See: http://jqueryui.com/controlgroup/
|
|
def initialize(settings)
|
|
super(settings)
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class FieldSet < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "fieldset"
|
|
# fieldset tag
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class TextInput < GuiComponent
|
|
# See: http://jqueryui.com/controlgroup/
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "input"
|
|
@attributes[:type] = "text"
|
|
# input tag, type="text"
|
|
# For auto-complete: `#{@dom_object}.autocomplete({source: <JS-Array>});`
|
|
self
|
|
end
|
|
#
|
|
def generate_html()
|
|
super({:type => "text"})
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class DatePicker < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "input"
|
|
# `#{@dom_object}.datepicker();`
|
|
# input tag, type="text"
|
|
self
|
|
end
|
|
#
|
|
def generate_html()
|
|
super({:type => "text"})
|
|
end
|
|
#
|
|
def establish_dom_link()
|
|
super()
|
|
if @dom_object
|
|
@dom_object.datepicker()
|
|
end
|
|
true
|
|
end
|
|
end
|
|
#
|
|
class MenuBar < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# sections have: title
|
|
# @record[:style][:z_index] = 99
|
|
self
|
|
end
|
|
#
|
|
def establish_dom_link()
|
|
# No event linking for menubar - just a place holder object.
|
|
@dom_object = Element.find("##{@uuid.to_s}")
|
|
end
|
|
end
|
|
#
|
|
class Menu < GuiComponent
|
|
private
|
|
#
|
|
def menu_body_html(menu_hash=nil)
|
|
result = ""
|
|
# FIX: watch your stack depth !
|
|
unless menu_hash
|
|
menu_hash = @options[:menu_definition]
|
|
end
|
|
if menu_hash.is_a?(::Hash)
|
|
menu_hash.keys.each do |choice|
|
|
if menu_hash[(choice)].is_a?(::Array)
|
|
result = (result + "<li><div>" + "<img src='#{menu_hash[(choice)][0].to_s}' alt='#{choice.to_s}' width='16' height='16'>" + choice.to_s + "</div></li>")
|
|
#
|
|
end
|
|
if menu_hash[(choice)].is_a?(::Hash)
|
|
result = (result + "<li><div>" + choice.to_s + "</div><ul>" + menu_body_html(menu_hash[(choice)]) + "</ul></li>")
|
|
#
|
|
end
|
|
if menu_hash[(choice)].is_any?(::String, ::Symbol)
|
|
result = (result + "<li><div>" + menu_hash[(choice)] + "</div></li>")
|
|
end
|
|
#
|
|
end
|
|
end
|
|
#
|
|
result
|
|
end
|
|
#
|
|
public
|
|
#
|
|
def decode_choice(selection=nil,menu_hash=nil)
|
|
result = nil
|
|
# FIX: watch your stack depth !
|
|
unless menu_hash
|
|
menu_hash = @options[:menu_definition]
|
|
end
|
|
if menu_hash.is_a?(::Hash)
|
|
menu_hash.keys.each do |choice|
|
|
if menu_hash[(choice)].is_a?(::Array)
|
|
if choice.to_s == selection
|
|
result = menu_hash[(choice)][1]
|
|
break
|
|
end
|
|
#
|
|
end
|
|
if menu_hash[(choice)].is_a?(::Hash)
|
|
result = decode_choice(selection,menu_hash[(choice)])
|
|
if result
|
|
break
|
|
end
|
|
end
|
|
if menu_hash[(choice)].is_any?(::String, ::Symbol)
|
|
if choice.to_s == selection
|
|
result = menu_hash[(choice)]
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "ul"
|
|
# Needs custom generateHTML
|
|
# Contains Ordered and Unordered Lists: class='ui-state-disabled' to disable menu any menu item/sub-item.
|
|
# Idea:
|
|
# @options[:menu_definition] contains the menu definition.
|
|
# Structure: key is text label of choice, value is a) code associated, b) Array with image path to icon then code associated (later: 3rd item key-code).
|
|
# If Hash = sub-menu following same pattern
|
|
# trap menuselect to match string with @options[:menu_definition] hash/sub-hash
|
|
# ???
|
|
self
|
|
end
|
|
#
|
|
def establish_dom_link()
|
|
@dom_object = Element.find("##{@uuid.to_s}")
|
|
true
|
|
end
|
|
#
|
|
def activate()
|
|
unless @dom_object
|
|
self.establish_dom_link
|
|
end
|
|
if @dom_object
|
|
# Set event traps on @dom_object
|
|
@dom_object.menu()
|
|
self.hide()
|
|
@dom_object.on :menuselect do |event,ui|
|
|
self.hide()
|
|
data = self.decode_choice(`#{ui}.item.text()`)
|
|
if data
|
|
GxG::DISPLAY_DETAILS[:object].process_event({:uuid => @uuid, :event => event, :data => data})
|
|
end
|
|
end
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def set_options(the_options={})
|
|
if the_options.is_a?(::Hash)
|
|
the_options.keys.each do |op_key|
|
|
if op_key == :visibility
|
|
case op_key
|
|
when "hide"
|
|
self.hide()
|
|
when "show"
|
|
self.show()
|
|
when "toggle"
|
|
self.toggle_visibility()
|
|
end
|
|
else
|
|
#
|
|
if op_key == :menu_definition
|
|
if @options[:menu_definition].hash != the_options[:menu_definition].hash
|
|
@options[:menu_definition] = the_options[:menu_definition]
|
|
if @dom_object
|
|
@dom_object.html(menu_body_html())
|
|
end
|
|
end
|
|
else
|
|
@options[(op_key.to_sym)] = the_options[(op_key)]
|
|
end
|
|
#
|
|
end
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
def generate_html()
|
|
if @classes.size > 0
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}' class='#{@classes.to_s}'"
|
|
else
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}'"
|
|
end
|
|
#
|
|
if @attributes.size > 0
|
|
@attributes.keys.each do |the_key|
|
|
result = result + " #{the_key.to_s}='#{@attributes[(the_key)].to_s}'"
|
|
end
|
|
end
|
|
#
|
|
if @style.keys.size > 0
|
|
style_string = " style='"
|
|
else
|
|
style_string = ""
|
|
end
|
|
@style.keys.each do |the_key|
|
|
unless @style[(the_key)] == ""
|
|
#the_property = GxG::Css::get_property_name(the_key)
|
|
the_property = (the_key.to_s.gsub("_","-"))
|
|
if the_property
|
|
style_string = style_string + " #{the_property.to_s}: #{@style[(the_key)].to_s};"
|
|
end
|
|
end
|
|
end
|
|
if style_string.size > 0
|
|
result = (result + style_string + "'")
|
|
end
|
|
result = (result + ">" + menu_body_html() + "</#{@base_tag.to_s}>")
|
|
result
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class SelectMenu < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "select"
|
|
# select tag
|
|
# Contains: SelectMenuOption(s).
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class SelectMenuOption < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "option"
|
|
# option tag
|
|
# <option selected="selected">Blah Blah</option> to select the SelectMenuOption.
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Slider < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# div tag
|
|
# `#{@dom_object}.slider();`
|
|
# Read Value: `#{@dom_object}.slider('value');`
|
|
# Write Value: `#{@dom_object}.slider('value', the_value);`
|
|
self
|
|
end
|
|
#
|
|
def activate()
|
|
unless @dom_object
|
|
self.establish_dom_link()
|
|
end
|
|
if @dom_object
|
|
@dom_object.slider()
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Spinner < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "input"
|
|
# input tag
|
|
# `#{@dom_object}.spinner();`
|
|
# Read Value: `#{@dom_object}.spinner('value');`
|
|
# Write Value: `#{@dom_object}.spinner('value', the_value);`
|
|
self
|
|
end
|
|
#
|
|
def activate()
|
|
if @dom_object
|
|
@dom_object.spinner()
|
|
end
|
|
end
|
|
end
|
|
#
|
|
class ProgressBar < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# uses div tag
|
|
# `#{@dom_object}.progressbar({value: 37});`
|
|
# Read Progress Percentage Value: `#{@dom_object}.progressbar('value');`
|
|
# Write Progress Percentage Value: `#{@dom_object}.progressbar('value', the_percentage);`
|
|
# Inner div tag for progress-label: <div class="progress-label">Loading...</div>
|
|
self
|
|
end
|
|
#
|
|
def activate()
|
|
unless @dom_object
|
|
self.establish_dom_link()
|
|
end
|
|
if @dom_object
|
|
@dom_object.progressbar()
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Tabs < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# div tag
|
|
# `#{@dom_object}.tabs();`
|
|
# <div id="tabs">
|
|
# <ul>
|
|
# <li><a href="#tabs-1">Nunc tincidunt</a></li>
|
|
# <li><a href="#tabs-2">Proin dolor</a></li>
|
|
# <li><a href="#tabs-3">Aenean lacinia</a></li>
|
|
# </ul>
|
|
# <div id="tabs-1">
|
|
# <p>Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.</p>
|
|
# </div>
|
|
# <div id="tabs-2">
|
|
# <p>Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.</p>
|
|
# </div>
|
|
# <div id="tabs-3">
|
|
# <p>Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.</p>
|
|
# <p>Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.</p>
|
|
# </div>
|
|
# </div>
|
|
self
|
|
end
|
|
#
|
|
def activate()
|
|
unless @dom_object
|
|
self.establish_dom_link()
|
|
end
|
|
if @dom_object
|
|
@dom_object.tabs()
|
|
end
|
|
end
|
|
#
|
|
def generate_html()
|
|
if @classes.size > 0
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}' class='#{@classes.to_s}'"
|
|
else
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}'"
|
|
end
|
|
#
|
|
if @attributes.size > 0
|
|
@attributes.keys.each do |the_key|
|
|
result = result + " #{the_key.to_s}='#{@attributes[(the_key)].to_s}'"
|
|
end
|
|
end
|
|
#
|
|
if @style.keys.size > 0
|
|
style_string = " style='"
|
|
else
|
|
style_string = ""
|
|
end
|
|
@style.keys.each do |the_key|
|
|
unless @style[(the_key)] == ""
|
|
the_property = GxG::Css::get_property_name(the_key)
|
|
if the_property
|
|
style_string = style_string + " #{the_property.to_s}: #{@style[(the_key)].to_s};"
|
|
end
|
|
end
|
|
end
|
|
if style_string.size > 0
|
|
result = (result + style_string + "'")
|
|
end
|
|
result = result + ">"
|
|
section_headers = []
|
|
accumulator = []
|
|
contents = GxG::children_of(self)
|
|
contents.each do |the_object|
|
|
section_headers << {:uuid => the_object.uuid.to_s, :title => the_object.get_options()[:title].to_s}
|
|
accumulator << the_object.generate_html()
|
|
end
|
|
result = result + "<ul>"
|
|
section_headers.each do |the_record|
|
|
result = result + "<li><a href='##{the_record[:uuid].to_s}'>#{the_record[:title].to_s}</a></li>"
|
|
end
|
|
result = result + "</ul>"
|
|
result = (result + accumulator.join("\n") + "</#{@base_tag.to_s}>")
|
|
#
|
|
result
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class TabSection < GuiComponent
|
|
# has label (bound to content uuid) and content (any): options = {:title => "Tab Label Text"}
|
|
def hide()
|
|
# No-op
|
|
end
|
|
def show()
|
|
# No-op
|
|
end
|
|
end
|
|
#
|
|
class Table < GuiComponent
|
|
# ???
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "table"
|
|
self
|
|
end
|
|
end
|
|
#
|
|
class TableRow < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "tr"
|
|
self
|
|
end
|
|
end
|
|
#
|
|
class TableHeader < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "th"
|
|
self
|
|
end
|
|
end
|
|
#
|
|
class TableData < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "td"
|
|
self
|
|
end
|
|
end
|
|
#
|
|
class Image < GuiComponent
|
|
def initialize(settings)
|
|
super(settings)
|
|
@base_tag = "img"
|
|
# REQUIRES attributes src=ImageURL and alt=TEXT to be set
|
|
# set width and height in attributes, NOT style
|
|
self
|
|
end
|
|
#
|
|
def generate_html()
|
|
if @classes.size > 0
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}' class='#{@classes.to_s}'"
|
|
else
|
|
result = "<#{@base_tag.to_s} id='#{@uuid.to_s}'"
|
|
end
|
|
#
|
|
if @attributes.size > 0
|
|
@attributes.keys.each do |the_key|
|
|
result = result + " #{the_key.to_s}='#{@attributes[(the_key)].to_s}'"
|
|
end
|
|
end
|
|
#
|
|
if @style.keys.size > 0
|
|
style_string = " style='"
|
|
else
|
|
style_string = ""
|
|
end
|
|
@style.keys.each do |the_key|
|
|
unless @style[(the_key)] == ""
|
|
the_property = GxG::Css::get_property_name(the_key)
|
|
if the_property
|
|
style_string = style_string + " #{the_property.to_s}: #{@style[(the_key)].to_s};"
|
|
end
|
|
end
|
|
end
|
|
if style_string.size > 0
|
|
result = (result + style_string + "'")
|
|
end
|
|
result = result + ">"
|
|
# NO end tag on img tag
|
|
result
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class ToolTip < GuiComponent
|
|
#
|
|
def initialize(settings)
|
|
super(settings)
|
|
# This should be a modifier method (feature)- not a component.
|
|
# uses *any* tag
|
|
# `#{any_dom_object}.tooltip();`
|
|
# Set the title attribute on the tag to allow display of the tooltip.
|
|
self
|
|
end
|
|
#
|
|
end
|
|
#
|
|
end
|
|
end
|