hQuery.php
Element.php
1 <?php
2 namespace duzun\hQuery;
3 
4 // ------------------------------------------------------------------------
5 class_exists('duzun\\hQuery\\Node', false) or require_once __DIR__ . DIRECTORY_SEPARATOR . 'Node.php';
6 
7 // ------------------------------------------------------------------------
12 class Element extends Node implements \ArrayAccess {
13  // ------------------------------------------------------------------------
14  // Iterator
15  protected $_ich = NULL; // Iterator Cache
16  // ------------------------------------------------------------------------
17  public function toArray($cch=true) {
18  if($cch && isset($this->_ich) && count($this->ids) === count($this->_ich)) return $this->_ich;
19  $ret = array();
20  if($cch) {
21  foreach($this->ids as $b => $e) {
22  $ret[$b] = isset($this->_ich[$b])
23  ? $this->_ich[$b]
24  : ( $this->_ich[$b] = new self($this->doc, array($b=>$e)) )
25  ;
26  }
27  }
28  else {
29  foreach($this->ids as $b => $e) {
30  $ret[$b] = new self($this->doc, array($b=>$e));
31  }
32  }
33  return $ret;
34  }
35 
36  // ------------------------------------------------------------------------
37  public function __get($name) {
38  switch($name) {
39  case 'innerHTML':
40  case 'html' : return $this->html();
41  case 'outerHtml': return $this->outerHtml();
42  case 'textContent':
43  case 'text' : return $this->text();
44  case 'attr' : return $this->attr();
45  case 'value' :
46  case 'val' : return $this->val();
47  case 'nodeName' : return $this->nodeName(false);
48  case 'parent' : return $this->parent();
49  case 'children' : return $this->children();
50  case 'nextElementSibling' : return $this->nextElementSibling();
51  case 'previousElementSibling' : return $this->previousElementSibling();
52  case 'className': $name = 'class'; break;
53  }
54  // return parent::__get($name);
55 
56  if($this->_prop && array_key_exists($name, $this->_prop)) return $this->_prop[$name];
57  switch($name) {
58  case 'id':
59  case 'class':
60  case 'alt':
61  case 'title':
62  case 'src':
63  case 'href':
64  // case 'protocol':
65  // case 'host':
66  // case 'port':
67  // case 'hostname':
68  // case 'pathname':
69  // case 'search':
70  // case 'hash':
71  default:
72  return $this->attr($name);
73  }
74  }
75  // ------------------------------------------------------------------------
76  // ArrayAccess methods:
77 
78  public function offsetSet($offset, $value) {
79  if(is_null($offset)) {
80  // $this->_data[] = $value; // ???
81  }
82  if(is_int($offset)) {
83  $i = array_slice($this->ids, $offset, 1, true);
84  // ??? can't manipulate collection's contents
85  }
86  else {
87  $this->__set($offset, $value); // set a property
88  }
89  }
90 
91  public function offsetGet($offset) {
92  return is_int($offset)
93  ? $this->get($offset) // an element from collection
94  : $this->__get($offset) // a property
95  ;
96  }
97 
98  public function offsetExists($offset) {
99  if(is_int($offset)) {
100  return 0 <= $offset && $offset < count($this->ids);
101  }
102  return $this->__isset($offset);
103  }
104 
105  public function offsetUnset($offset) {
106  if(is_int($offset)) {
107  $i = array_slice($this->ids, $offset, 1, true);
108  if($i) {
109  $i = key($i);
110  unset($this->ids[$i], $this->_ich[$i]);
111  }
112  }
113  else {
114  unset($this->_prop[$offset]);
115  }
116  }
117 
118  // ------------------------------------------------------------------------
124  public function current() {
125  $k = key($this->ids);
126  if($k === NULL) return false;
127  if(count($this->ids) == 1) return $this;
128  if(!isset($this->_ich[$k])) $this->_ich[$k] = new self($this->doc, array($k=>$this->ids[$k]));
129  return $this->_ich[$k];
130  }
131 
132  // ------------------------------------------------------------------------
138  public function val() {
139  $el = count($this) > 1 ? $this->get(0) : $this;
140  switch(strtoupper($el->nodeName(false))) {
141  case 'TEXTAREA':
142  return $el->html();
143  case 'INPUT':
144  switch(strtoupper($el->attr('type'))) {
145  case 'CHECKBOX': if ( $el->attr('checked') === false ) return false;
146  default: return $el->attr('value');
147  }
148  return $el->html();
149  case 'SELECT': // ???
150 
151  default: return false;
152  }
153  }
154 
161  public function hasClass($className) {
162  $ret = $this->doc()->hasClass($this, $className);
163  if ( !is_array($ret) ) return $ret;
164  if ( count($this) < 2 ) return reset($ret);
165 
166  return max($ret);
167  }
168 
176  public function get($idx) {
177  $i = array_slice($this->ids, $idx, 1, true);
178  if(!$i) return NULL;
179 
180  // Try read cache first
181  $k = key($i);
182  if(isset($this->_ich[$k])) return $this->_ich[$k];
183 
184  // Create wraper instance for $i
185  $o = new self($this->doc, $i);
186 
187  // Save to cache
188  $this->_ich[$k] = $o;
189 
190  return $o;
191  }
192 
200  public function eq($idx) {
201  $i = array_slice($this->ids, $idx, 1, true) or
202  $i = array();
203  // Create wraper instance for $i
204  $o = new self($this->doc, $i);
205  return $o;
206  }
207 
216  public function slice($idx, $len=NULL) {
217  $c = $this->count();
218  if($idx < $c) $ids = array();
219  else
220  if(isset($len)) {
221  if($idx == 0 && $len == $c) {
222  return $this; // ???
223  $ids = $this->ids;
224  }
225  $ids = array_slice($this->ids, $idx, $len, true);
226  }
227  else {
228  if($idx == 0) {
229  return $this; // ???
230  $ids = $this->ids;
231  }
232  $ids = array_slice($this->ids, $idx, $this->count(), true);
233  }
234  $o = new self($this->doc, $ids);
235  $o->_ich = &$this->_ich; // share iterator cache for iteration
236  return $o;
237  }
238 
244  public function parent() {
245  $p = $this->_parent();
246  return $p ? new self($this->doc, $p) : NULL;
247  }
248 
254  public function children() {
255  $p = $this->_children();
256  return $p ? new self($this->doc, $p) : NULL;
257  }
258 
265  $p = $this->_prev();
266  return $p ? new self($this->doc, $p) : NULL;
267  }
268 
274  function nextElementSibling() {
275  $p = $this->_next();
276  return $p ? new self($this->doc, $p) : NULL;
277  }
278 
279 }
nodeName($caseFolding=NULL, $id=NULL)
Definition: Node.php:194
text($id=NULL)
Definition: Node.php:187
hasClass($className)
Definition: Element.php:161
html($id=NULL)
Definition: Node.php:142
outerHtml($id=NULL)
Definition: Node.php:165
slice($idx, $len=NULL)
Definition: Element.php:216
attr($attr=NULL, $to_str=false)
Definition: Node.php:62