Module: Vapir::ElementHelper

Includes:
ElementClassAndModuleMethods
Included in:
Area, Button, CheckBox, Dd, Div, Dl, Dt, Element, Em, FileField, Form, Frame, H1, H2, H3, H4, H5, H6, Hidden, Image, InputElement, Label, Li, Link, Map, Ol, Option, P, Pre, Radio, SelectList, Span, Strong, TBody, Table, TableCell, TableRow, TextField, Ul
Defined in:
lib/vapir-common/element.rb

Instance Method Summary collapse

Methods included from ElementClassAndModuleMethods

#add_container_method_extra_args, #all_dom_attr_aliases, #all_dom_attrs, #class_array_append, #class_array_get, #class_hash_get, #class_hash_merge, #container_collection_methods, #container_method_extra_args, #container_single_methods, #default_how, #dom_attr, #dom_attr_locate_alias, #dom_function, #dom_setter, #element_collection, #factory, #inspect_these, #inspect_this_if, #parent_element_module, #set_or_get_class_var, #specifiers

Instance Method Details

#add_specifier(specifier) ⇒ Object



249
250
251
# File 'lib/vapir-common/element.rb', line 249

def add_specifier(specifier)
  class_array_append 'specifiers', specifier
end

#container_collection_method(*method_names) ⇒ Object



279
280
281
# File 'lib/vapir-common/element.rb', line 279

def container_collection_method(*method_names)
  class_array_append 'container_collection_methods', *method_names
end

#container_single_method(*method_names) ⇒ Object



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/vapir-common/element.rb', line 253

def container_single_method(*method_names)
  class_array_append 'container_single_methods', *method_names
  element_module=self
  method_names.each do |method_name|
    Vapir::Element.module_eval do
      # these methods (Element#parent_table, Element#parent_div, etc)
      # iterate through parent nodes looking for a parent of the specified
      # type. if no element of that type is found which is a parent of
      # self, returns nil. 
      define_method("parent_#{method_name}") do
        element_class=element_class_for(element_module)
        parentNode=element_object
        while true
          parentNode=parentNode.parentNode
          unless parentNode && parentNode != document_object # don't ascend up to the document. #TODO/Fix - for IE, comparing WIN32OLEs doesn't really work, this comparison is pointless. 
            return nil
          end
          matched=Vapir::ElementObjectCandidates.match_candidates([parentNode], element_class.specifiers, element_class.all_dom_attr_aliases)
          if matched.size > 0
            return element_class.new(:element_object, parentNode, extra_for_contained) # this is a little weird, passing extra_for_contained so that this is the container of its parent. 
          end
        end
      end
    end
  end
end

#included(including_class) ⇒ Object



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/vapir-common/element.rb', line 285

def included(including_class)
  including_class.send :extend, ElementClassAndModuleMethods
  
  # get Container modules that the including_class includes (ie, Vapir::Firefox::TextField includes the Vapir::Firefox::Container Container module)
  container_modules=including_class.included_modules.select do |mod|
    mod.included_modules.include?(Vapir::Container)
  end
  
  container_modules.each do |container_module|
    class_array_get('container_single_methods').each do |container_single_method|
      # define both bang-methods (like #text_field!) and not (#text_field) with corresponding :locate option for element_by_howwhat
      [ {:method_name => container_single_method, :locate => true}, 
        {:method_name => container_single_method.to_s+'!', :locate => :assert},
        {:method_name => container_single_method.to_s+'?', :locate => :nil_unless_exists},
      ].each do |method_hash|
        unless container_module.method_defined?(method_hash[:method_name])
          container_module.module_eval do
            define_method(method_hash[:method_name]) do |how, *what_args| # can't take how, what as args because blocks don't do default values so it will want 2 args
              #locate! # make sure self is located before trying contained stuff 
              what=what_args.shift # what is the first what_arg
              other_attribute_keys=including_class.container_method_extra_args
              if what_args.size>other_attribute_keys.length
                raise ArgumentError, "\##{method_hash[:method_name]} takes 1 to #{2+other_attribute_keys.length} arguments! Got #{([how, what]+what_args).map{|a|a.inspect}.join(', ')}}"
              end
              if what_args.size == 0
                other_attributes= nil
              else
                other_attributes={}
                what_args.each_with_index do |arg, i|
                  other_attributes[other_attribute_keys[i]]=arg
                end
              end
              element_by_howwhat(including_class, how, what, :locate => method_hash[:locate], :other_attributes => other_attributes)
            end
          end
        end
      end
    end
    class_array_get('container_collection_methods').each do |container_multiple_method|
      container_module.module_eval do
        # returns an ElementCollection of Elements that are instances of the including class 
        define_method(container_multiple_method) do
          ElementCollection.new(self, including_class, extra_for_contained)
        end
      end
      container_module.module_eval do
        define_method('child_'+container_multiple_method.to_s) do
          ElementCollection.new(self, including_class, extra_for_contained.merge(:candidates => :childNodes))
        end
        define_method('show_'+container_multiple_method.to_s) do |*io|
          io=io.first||$stdout # io is a *array so that you don't have to give an arg (since procs don't do default args)
          element_collection=ElementCollection.new(self, including_class, extra_for_contained)
          io.write("There are #{element_collection.length} #{container_multiple_method}\n")
          element_collection.each do |element|
            io.write(element.to_s)
          end
        end
        alias_deprecated "show#{container_multiple_method.to_s.capitalize}", "show_"+container_multiple_method.to_s
      end
    end
  end

  # copy constants (like Specifiers) onto classes when inherited
  # this is here to set the constants of the Element modules below onto the actual classes that instantiate 
  # per-browser (Vapir::IE::TextField, Vapir::Firefox::TextField, etc) so that calling #const_defined? on those 
  # returns true, and so that the constants defined here clobber any inherited stuff from superclasses
  # which is unwanted. 
  self.constants.each do |const| # copy all of its constants onto wherever it was included
    to_copy=self.const_get(const)
    to_copy=to_copy.dup if [Hash, Array, Set].any?{|klass| to_copy.is_a?(klass) }
    including_class.const_set(const, to_copy)
  end
  
  # now the constants (above) have switched away from constants to class variables, pretty much, so copy those.
  self.class_variables.each do |class_var|
    to_copy=class_variable_get(class_var)
    to_copy=to_copy.dup if [Hash, Array, Set].any?{|klass| to_copy.is_a?(klass) }
    including_class.send(:class_variable_set, class_var, to_copy)
  end
  
  class << including_class
    def attributes_to_inspect
      super_attrs=superclass.respond_to?(:attributes_to_inspect) ? superclass.attributes_to_inspect : []
      super_attrs + class_array_get('attributes_to_inspect')
    end
    def all_dom_attrs
      super_attrs=superclass.respond_to?(:all_dom_attrs) ? superclass.all_dom_attrs : []
      super_attrs + class_array_get('dom_attrs')
    end
    def all_dom_attr_aliases
      aliases=class_hash_get('dom_attr_aliases').dup
      super_aliases=superclass.respond_to?(:all_dom_attr_aliases) ? superclass.all_dom_attr_aliases : {}
      super_aliases.each_pair do |attr, alias_list|
        aliases[attr] = (aliases[attr] || Set.new) + alias_list
      end
      aliases
    end
  end
end