bool belongs_to( dom::element parent, dom::element child ) { if( !child.is_valid()) return false; if( parent == child ) return true; return belongs_to( parent, child.parent() ); }
dom::element target_item(const dom::element& ctl, dom::element target) { if( target == ctl ) return dom::element(); if( !target.is_valid() ) return target; dom::element target_parent = target.parent(); if( !target_parent.is_valid() ) return target; if( target.test("li > .caption") ) return target_parent; // only if click on "caption" element of <li>. Returns that <li> element. return target_item( ctl, target.parent() ); }
bool is_fullpath(dom::element &el) { BOOL bFullPath = (el.get_attribute("fullpath") != NULL); if ( !bFullPath ) { dom::element ep = el.parent(); bFullPath = (ep.is_valid())?(ep.get_attribute("fullpath") != NULL):FALSE; } return bFullPath; }
// returns bit mask - checkboxes set inline value_t get_checkbox_bits(dom::element& el ) { selected_cb selected; dom::element r = el.parent(); // ATTN: I assume here that all checkboxes in the group belong to the same parent! r.find_all(&selected, "[type='checkbox'][name='%S']", el.get_attribute("name")); int m = 1, v = 0; for( unsigned int n = 0; n < selected.elements.size(); ++n, m <<= 1 ) if ( selected.elements[n].get_state(STATE_CHECKED) ) v |= m; return selected.elements.size()==1?value_t(v==1):value_t(v); // for alone checkbox we return true/false }
inline value_t get_radio_index( dom::element& el ) { selected_cb selected; dom::element r = el.parent(); // ATTN: I assume here that all radios in the group belong to the same parent! r.find_all(&selected, "[type='radio'][name='%S']", el.get_attribute("name")); for( unsigned int n = 0; n < selected.elements.size(); ++n ) if ( selected.elements[n].get_state(STATE_CHECKED) ) return value_t(int(n)); return value_t(); }
// sets checkboxes by bit mask inline void set_checkbox_bits(dom::element& el, const value_t& t ) { selected_cb selected; dom::element r = el.parent(); // ATTN: I assume here that all checkboxes in the group belong to the same parent! r.find_all(&selected, "[type='checkbox'][name='%S']", el.get_attribute("name")); int m = 1, v = selected.elements.size()==1?(t.get(false)?1:0):t.get(0); for( unsigned int n = 0; n < selected.elements.size(); ++n, m <<= 1 ) { dom::element& e = selected.elements[n]; if( (v & m) != 0) e.set_state( STATE_CHECKED, 0 ) ; else e.set_state( 0, STATE_CHECKED ) ; } }
inline void set_radio_index( dom::element& el, const value_t& t ) { selected_cb selected; dom::element r = el.parent(); // ATTN: I assume here that all radios in the group belong to the same parent! r.find_all(&selected, "[type='radio'][name='%S']", el.get_attribute("name")); unsigned int idx = (unsigned int)t.get(0); for( unsigned int n = 0; n < selected.elements.size(); ++n ) { dom::element& e = selected.elements[n]; if ( n == idx) e.set_state(STATE_CHECKED, 0); else e.set_state(0, STATE_CHECKED); } }
inline void set_radio_index( dom::element& el, const json::value& t ) { selected_cb selected; dom::element r = el.parent(); // ATTN: I assume here that all radios in the group belong to the same parent! r.find_all(&selected, "[type='radio'][name='%S']", el.get_attribute("name")); unsigned int idx = (unsigned int)t.get(0); for( unsigned int n = 0; n < selected.elements.size(); ++n ) { dom::element& e = selected.elements[n]; if ( n == idx) { e.set_value(json::value(true)); break; } } }
BOOL select_next_option( dom::element& option ) { dom::element next = option.next_sibling(); if( !next.is_valid() ) goto ADD_NEW; if( !aux::streq(next.get_element_type(),"option") ) goto ADD_NEW; next.set_state(STATE_FOCUS); return TRUE; ADD_NEW: std::wstring text = option.text(); if(text.empty() || text == L" ") { ::MessageBeep(MB_ICONEXCLAMATION); return FALSE; } dom::element select = option.parent(); next = dom::element::create("option", L" "); select.insert(next,option.index()+1); select.update(); next.set_state(STATE_FOCUS); return TRUE; }
dom::element target_row(const dom::element& table, const dom::element& target) { if( !target.is_valid() || target.parent() == table) return target; return target_row(table,target.parent()); }
dom::element target_header(const dom::element& header_row, const dom::element& target) { if( !target.is_valid() || target.parent() == header_row) return target; return target_header(header_row,target.parent()); }
//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(); } }