void setup_node( dom::element node )
    {
      dom::element on = node.find_first("option[check='on'],options[check='on']");
      dom::element off = node.find_first("option[check='off'],options[check='off']");
      dom::element mixed = node.find_first("options[check='mixed']");

      const wchar_t* _prev = node.get_attribute(CHECK_ATTR);
      std::wstring  prev = _prev?_prev:L"";
      
      if( mixed.is_valid() || (on.is_valid() && off.is_valid()))
      {
        node.set_attribute(CHECK_ATTR,L"mixed");
        if(prev != L"mixed") node.update();
      }
      else if( on.is_valid() )
      {
        node.set_attribute(CHECK_ATTR,L"on");
        if(prev != L"on") node.update();
      }
      else
      {
        node.set_attribute(CHECK_ATTR,L"off");
        if(prev != L"off") node.update();
      }
    }
  void sort_rows( dom::element& table, int column_no )
  {
    row_sorter rs( column_no );

    int fr = fixed_rows( table );
    table.sort(rs,fr);
    table.update(true);
  }
  // selects all options in multiselect.
  inline void select_all_options(dom::element& select_el )
  {
    selected_cb all_options;
    select_el.find_all(&all_options, "option"); // select all currently selected <option>s

    for( int n = int(all_options.elements.size()) - 1; n >= 0 ; --n )
       all_options.elements[n].set_state(STATE_CHECKED,0, false); // set state
    select_el.update();
  }
  // clear checked states in multiselect <select>.
  // this simply resets :checked state for all checked <option>'s
  inline void clear_all_options(dom::element& select_el )
  {
    selected_cb selected;
    select_el.find_all(&selected, "option:checked,[role='option']:checked"); // select all currently selected <option>s

    for( int n = int(selected.elements.size()) - 1; n >= 0 ; --n )
      selected.elements[n].set_state(0, STATE_CHECKED, false); // reset state

    select_el.update();
  }
    virtual BOOL on_event (HELEMENT he, HELEMENT target, BEHAVIOR_EVENTS type, UINT_PTR reason ) 
    { 
      if( type != UI_STATE_CHANGED ) 
        return FALSE; // we handle only UI_STATE_CHANGED here.
      
      assert(objects_bar.is_valid());

      // call of getCurrentObjects method
      json::value stack = dom::element(he).xcall("getCurrentObjects"); 
      assert(stack.is_array());

      objects_bar.clear();
      int n = stack.length();
      for( int i = 0; i < n; ++i )
      {
        dom::element li = dom::element::create("li", stack.nth(i).to_string());
        objects_bar.append(li);
      }
      objects_bar.update();      
      return FALSE; /*mark it as not handled because some other behaviors in the chain may want to handle it */ 
    }
/** Set value of the DOM element. Sets value for elements recognized by get_ctl_type() function. 
 * \param[in] el \b const dom::element&, The element.
 * \param[in] v \b const value_t&, The value.
 **/
  inline void set_value(dom::element& el, const value_t& v )
  {
    switch(get_ctl_type(el))
    {
      case CTL_UNKNOWN:         break;
      case CTL_EDIT:
      case CTL_DECIMAL:
      case CTL_CURRENCY:
      case CTL_PASSWORD:
      case CTL_NUMERIC: 
      case CTL_PROGRESS:        
      case CTL_SLIDER:          
      case CTL_SELECT_SINGLE:   
      case CTL_SELECT_MULTIPLE: 
      case CTL_DD_SELECT:       
      case CTL_TEXTAREA:
      case CTL_DATE:
      case CTL_CALENDAR:
      case CTL_HIDDEN:
      default:
        el.set_value(v);
        break;
      // special cases:
      case CTL_BUTTON:          break;
      case CTL_CHECKBOX:        set_checkbox_bits(el,v); break;
      case CTL_RADIO:           set_radio_index(el,v);  break;
      case CTL_HTMLAREA:        
       {
          utf8::ostream os; os << v.get( L"" );
          el.set_html( os.data(), os.length() );
          el.update();
        } break;
      case CTL_NO:
        assert(false);
        break;
    }
  }
    //toggles checkmark
    void toggle_checkmark( dom::element select, dom::element item )
    {
      const wchar_t* _old_state = item.get_attribute(CHECK_ATTR);
      std::wstring  old_state = _old_state?_old_state:L"";

      if( streq(item.get_element_type(), "options"))
      {
        // non-terminal node case 
        
        // inner function
        struct child_toggler: dom::callback
        {
          const wchar_t* state;
          child_toggler(const wchar_t* st): state(st) {}
          inline bool on_element(HELEMENT he) 
          { 
            htmlayout::dom::element item = he; 
            item.set_attribute( CHECK_ATTR, state );
            return false;
          }
        };
        
        const wchar_t* new_state;
        NODE_STATE old_state = get_state(item);
        if(old_state == NODE_OFF)
          new_state = L"on";
        else 
          new_state = L"off";

        child_toggler ct( new_state );
        // do it for all children
        item.find_all(&ct, "option,options");
        // and for itself
        item.set_attribute( CHECK_ATTR, new_state );
        item.update();
      }
      else if( streq(item.get_element_type(), "option"))
      {
        // terminal node
        const wchar_t* new_state;
        if(wcseq(item.get_attribute("check"),L"on"))
        {
          new_state = L"off";
        }
        else 
          new_state = L"on";

        item.set_attribute( CHECK_ATTR, new_state );
        item.update();
      }
      
      // as state was changed we need to update parent chain here too.
      dom::element p = item.parent();
      while( p.is_valid() && p != select )
      {
        if( streq(p.get_element_type(),"options" ))
        {
          setup_node(p);
        }
        p = p.parent();
      }

    }