HtmlDropdown   F
last analyzed

Complexity

Total Complexity 84

Size/Duplication

Total Lines 450
Duplicated Lines 0 %

Importance

Changes 12
Bugs 4 Features 0
Metric Value
eloc 197
c 12
b 4
f 0
dl 0
loc 450
rs 2
wmc 84

48 Methods

Rating   Name   Duplication   Size   Complexity  
A getItem() 0 2 1
A removeArrow() 0 4 2
A setAction() 0 3 1
A addItem() 0 4 1
A setOn() 0 3 1
A addIcons() 0 4 3
A asDropdown() 0 11 2
A addSearchInputItem() 0 2 1
A addItems() 0 8 5
A setPointing() 0 2 1
A getDataField() 0 2 1
A setAllowAdditions() 0 3 1
A setIcon() 0 3 1
A insertItem() 0 7 1
A count() 0 2 1
A beforeAddItem() 0 14 4
A setCompact() 0 3 1
A setValue() 0 3 1
A setVertical() 0 3 1
A setDefaultText() 0 3 1
A setSelect() 0 17 4
A asButton() 0 6 2
A setClearable() 0 3 1
A setPropertyValues() 0 14 4
A fromDatabaseObject() 0 2 1
A addIcon() 0 8 2
A addDividerItem() 0 2 1
A getInput() 0 2 1
A asSearch() 0 3 1
A setInline() 0 3 1
A addCircularLabelItem() 0 2 1
A addInput() 0 7 2
A jsAddItem() 0 4 1
A setShowOnFocus() 0 3 1
A getField() 0 2 1
A asSelect() 0 14 5
A setFullTextSearch() 0 3 1
A run() 0 8 3
A setSimple() 0 3 1
A addMiniAvatarImageItem() 0 2 1
A __construct() 0 24 4
A each() 0 5 2
A addHeaderItem() 0 2 1
A setOnRemove() 0 3 1
A applyValue() 0 11 6
A setOnAdd() 0 3 1
A compile() 0 3 1
A asSubmenu() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like HtmlDropdown often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use HtmlDropdown, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Ajax\semantic\html\modules;
3
4
use Ajax\JsUtils;
5
use Ajax\common\html\HtmlDoubleElement;
6
use Ajax\common\html\html5\HtmlInput;
7
use Ajax\semantic\html\base\HtmlSemDoubleElement;
8
use Ajax\semantic\html\base\constants\Direction;
9
use Ajax\semantic\html\base\traits\LabeledIconTrait;
10
use Ajax\semantic\html\collections\form\traits\FieldTrait;
11
use Ajax\semantic\html\content\HtmlDropdownItem;
12
use Ajax\semantic\html\elements\HtmlIcon;
13
use Ajax\service\JArray;
14
15
class HtmlDropdown extends HtmlSemDoubleElement {
16
	use FieldTrait,LabeledIconTrait {
17
		addIcon as addIconP;
18
	}
19
20
	protected $mClass = "menu";
21
22
	protected $mTagName = "div";
23
24
	protected $items = array();
25
26
	protected $_params = array(
27
		"action" => "nothing",
28
		"on" => "hover",
29
		"showOnFocus" => true
30
	);
31
32
	protected $input;
33
34
	protected $value;
35
36
	protected $_associative;
37
38
	protected $_multiple;
39
40
	public function __construct($identifier, $value = "", $items = array(), $associative = true) {
41
		parent::__construct($identifier, "div");
42
		$this->_template = include dirname(__FILE__) . '/../templates/tplDropdown.php';
43
		$this->setProperty("class", "ui dropdown");
44
		$this->_multiple = false;
45
		$content = [];
46
		$text = '';
47
		if ($value instanceof HtmlSemDoubleElement) {
48
			$text = $value;
49
		} elseif ($value !== null) {
50
			$text = new HtmlSemDoubleElement("text-" . $this->identifier, "div");
51
			$text->setClass("text");
52
			$this->setValue($value);
53
		}
54
		if ($text != null) {
55
			$content = [
56
				"text" => $text
57
			];
58
		}
59
		$content["arrow"] = new HtmlIcon($identifier . "-icon", "dropdown");
60
		$this->content = $content;
61
		$this->tagName = "div";
62
		$this->_associative = $associative;
63
		$this->addItems($items);
64
	}
65
66
	public function getField() {
67
		return $this->input;
68
	}
69
70
	public function getDataField() {
71
		return $this->input;
72
	}
73
74
	public function addItem($item, $value = NULL, $image = NULL, $description = NULL) {
75
		$itemO = $this->beforeAddItem($item, $value, $image, $description);
76
		$this->items[] = $itemO;
77
		return $itemO;
78
	}
79
80
	public function addIcon($icon, $before = true, $labeled = false) {
81
		$this->removeArrow();
82
		$this->addIconP($icon, $before, $labeled);
83
		$elm = $this->getElementById("text-" . $this->identifier, $this->content);
84
		if (isset($elm)) {
85
			$elm->setWrapAfter("");
86
		}
87
		return $this;
88
	}
89
90
	public function addIcons($icons) {
91
		$count = $this->count();
92
		for ($i = 0; $i < \sizeof($icons) && $i < $count; $i ++) {
93
			$this->getItem($i)->addIcon($icons[$i]);
94
		}
95
	}
96
97
	/**
98
	 * Insert an item at a position
99
	 *
100
	 * @param mixed $item
101
	 * @param int $position
102
	 * @return HtmlDropdownItem
103
	 */
104
	public function insertItem($item, $position = 0) {
105
		$itemO = $this->beforeAddItem($item);
106
		$start = array_slice($this->items, 0, $position);
107
		$end = array_slice($this->items, $position);
108
		$start[] = $item;
109
		$this->items = array_merge($start, $end);
110
		return $itemO;
111
	}
112
113
	protected function removeArrow() {
114
		if (\sizeof($this->content) > 1) {
115
			unset($this->content["arrow"]);
116
			$this->content = \array_values($this->content);
117
		}
118
	}
119
120
	protected function beforeAddItem($item, $value = NULL, $image = NULL, $description = NULL) {
121
		$itemO = $item;
122
		if (\is_array($item)) {
123
			$description = JArray::getValue($item, "description", 3);
124
			$value = JArray::getValue($item, "value", 1);
125
			$image = JArray::getValue($item, "image", 2);
126
			$item = JArray::getValue($item, "item", 0);
127
		}
128
		if (! $item instanceof HtmlDropdownItem) {
129
			$itemO = new HtmlDropdownItem("dd-item-" . $this->identifier . "-" . \sizeof($this->items), $item, $value, $image, $description);
130
		} elseif ($itemO instanceof HtmlDropdownItem) {
131
			$this->addToProperty("class", "vertical");
132
		}
133
		return $itemO;
134
	}
135
136
	/*
137
	 * (non-PHPdoc)
138
	 * @see \Ajax\bootstrap\html\base\BaseHtml::fromDatabaseObject()
139
	 */
140
	public function fromDatabaseObject($object, $function) {
141
		$this->addItem($function($object));
142
	}
143
144
	public function addInput($name) {
145
		if (! isset($name))
146
			$name = "input-" . $this->identifier;
147
		$this->setAction("activate");
148
		$this->input = new HtmlInput($name, "hidden");
149
		$this->input->setIdentifier("input-" . $this->identifier);
150
		return $this->input;
151
	}
152
153
	/**
154
	 * Adds a search input item
155
	 *
156
	 * @param string $placeHolder
157
	 * @param string $icon
158
	 * @return HtmlDropdownItem
159
	 */
160
	public function addSearchInputItem($placeHolder = NULL, $icon = NULL) {
161
		return $this->addItem(HtmlDropdownItem::searchInput($placeHolder, $icon));
162
	}
163
164
	/**
165
	 * Adds a divider item
166
	 *
167
	 * @return HtmlDropdownItem
168
	 */
169
	public function addDividerItem() {
170
		return $this->addItem(HtmlDropdownItem::divider());
171
	}
172
173
	/**
174
	 * Adds an header item
175
	 *
176
	 * @param string $caption
177
	 * @param string $icon
178
	 * @return HtmlDropdownItem
179
	 */
180
	public function addHeaderItem($caption = NULL, $icon = NULL) {
181
		return $this->addItem(HtmlDropdownItem::header($caption, $icon));
182
	}
183
184
	/**
185
	 * Adds an item with a circular label
186
	 *
187
	 * @param string $caption
188
	 * @param string $color
189
	 * @return HtmlDropdownItem
190
	 */
191
	public function addCircularLabelItem($caption, $color) {
192
		return $this->addItem(HtmlDropdownItem::circular($caption, $color));
193
	}
194
195
	/**
196
	 *
197
	 * @param string $caption
198
	 * @param string $image
199
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
200
	 */
201
	public function addMiniAvatarImageItem($caption, $image) {
202
		return $this->addItem(HtmlDropdownItem::avatar($caption, $image));
203
	}
204
205
	public function addItems($items) {
206
		if (\is_array($items) && $this->_associative) {
207
			foreach ($items as $k => $v) {
208
				$this->addItem($v)->setData($k);
209
			}
210
		} else {
211
			foreach ($items as $item) {
212
				$this->addItem($item);
213
			}
214
		}
215
	}
216
217
	/**
218
	 * Sets the values of a property for each item in the collection
219
	 *
220
	 * @param string $property
221
	 * @param array|mixed $values
222
	 * @return $this
223
	 */
224
	public function setPropertyValues($property, $values) {
225
		$i = 0;
226
		if (\is_array($values) === false) {
227
			$values = \array_fill(0, $this->count(), $values);
228
		}
229
		foreach ($values as $value) {
230
			$c = $this->items[$i ++];
231
			if (isset($c)) {
232
				$c->setProperty($property, $value);
233
			} else {
234
				return $this;
235
			}
236
		}
237
		return $this;
238
	}
239
240
	public function each($callBack) {
241
		foreach ($this->items as $index => $value) {
242
			$callBack($index, $value);
243
		}
244
		return $this;
245
	}
246
247
	public function getItem($index) {
248
		return $this->items[$index];
249
	}
250
251
	/**
252
	 *
253
	 * @return int
254
	 */
255
	public function count() {
256
		return \sizeof($this->items);
257
	}
258
259
	/**
260
	 *
261
	 * @param boolean $dropdown
262
	 */
263
	public function asDropdown($dropdown) {
264
		if ($dropdown === false) {
265
			$this->_template = include dirname(__FILE__) . '/../templates/tplDropdownMenu.php';
266
			$dropdown = "menu";
267
		} else {
268
			$dropdown = "dropdown";
269
			$this->mClass = "menu";
270
		}
271
		return $this->addToPropertyCtrl("class", $dropdown, array(
272
			"menu",
273
			"dropdown"
274
		));
275
	}
276
277
	public function setVertical() {
278
		return $this->addToPropertyCtrl("class", "vertical", array(
279
			"vertical"
280
		));
281
	}
282
283
	public function setInline() {
284
		return $this->addToPropertyCtrl("class", "inline", [
285
			"inline"
286
		]);
287
	}
288
289
	public function setSimple() {
290
		return $this->addToPropertyCtrl("class", "simple", array(
291
			"simple"
292
		));
293
	}
294
295
	public function asButton($floating = false) {
296
		$this->removeArrow();
297
		if ($floating)
298
			$this->addToProperty("class", "floating");
299
		$this->removePropertyValue("class", "selection");
300
		return $this->addToProperty("class", "button");
301
	}
302
303
	public function asSelect($name = NULL, $multiple = false, $selection = true) {
304
		$this->_multiple = $multiple;
305
		if (isset($name))
306
			$this->addInput($name);
307
		if ($multiple) {
308
			$this->addToProperty("class", "multiple");
309
		}
310
		if ($selection) {
311
			if ($this->propertyContains("class", "button") === false)
312
				$this->addToPropertyCtrl("class", "selection", array(
313
					"selection"
314
				));
315
		}
316
		return $this;
317
	}
318
319
	public function asSearch($name = NULL, $multiple = false, $selection = true) {
320
		$this->asSelect($name, $multiple, $selection);
321
		return $this->addToProperty("class", "search");
322
	}
323
324
	public function setSelect($name = NULL, $multiple = false) {
325
		$this->_template = '<%tagName% id="%identifier%" %properties%>%items%</%tagName%>';
326
		if (! isset($name))
327
			$name = "select-" . $this->identifier;
328
		$this->input = null;
329
		if ($multiple) {
330
			$this->setProperty("multiple", true);
331
			$this->addToProperty("class", "multiple");
332
		}
333
		$this->setAction("activate");
334
		$this->tagName = "select";
335
		$this->setProperty("name", $name);
336
		$this->content = null;
337
		foreach ($this->items as $item) {
338
			$item->asOption();
339
		}
340
		return $this;
341
	}
342
343
	public function asSubmenu($pointing = NULL) {
344
		$this->setClass("ui dropdown link item");
345
		if (isset($pointing)) {
346
			$this->setPointing($pointing);
347
		}
348
		return $this;
349
	}
350
351
	public function setPointing($value = Direction::NONE) {
352
		return $this->addToPropertyCtrl("class", $value . " pointing", Direction::getConstantValues("pointing"));
353
	}
354
355
	public function setValue($value) {
356
		$this->value = $value;
357
		return $this;
358
	}
359
360
	public function setDefaultText($text) {
361
		$this->content["text"] = new HtmlSemDoubleElement("", "div", "default text", $text);
362
		return $this;
363
	}
364
365
	private function applyValue() {
366
		$value = $this->value;
367
		if (isset($this->input) && isset($value)) {
368
			$this->input->setProperty("value", $value);
369
		} else {
370
			$this->setProperty("value", $value);
371
		}
372
		$textElement = $this->getElementById("text-" . $this->identifier, $this->content);
373
		if (isset($textElement) && ($textElement instanceof HtmlDoubleElement) && ! $this->_multiple)
374
			$textElement->setContent($value);
375
		return $this;
376
	}
377
378
	/*
379
	 * (non-PHPdoc)
380
	 * @see BaseHtml::run()
381
	 */
382
	public function run(JsUtils $js) {
383
		if ($this->propertyContains("class", "simple") === false) {
384
			if (isset($this->_bsComponent) === false) {
385
				$this->_bsComponent = $js->semantic()->dropdown("#" . $this->identifier, $this->_params);
386
				$this->_bsComponent->setItemSelector(".item");
387
			}
388
			$this->addEventsOnRun($js);
389
			return $this->_bsComponent;
390
		}
391
	}
392
393
	public function setCompact() {
394
		return $this->addToPropertyCtrl("class", "compact", array(
395
			"compact"
396
		));
397
	}
398
399
	public function setAction($action) {
400
		$this->_params["action"] = $action;
401
		return $this;
402
	}
403
404
	public function setOn($on) {
405
		$this->_params["on"] = $on;
406
		return $this;
407
	}
408
409
	public function setShowOnFocus($value) {
410
		$this->_params["showOnFocus"] = $value;
411
		return $this;
412
	}
413
414
	public function setAllowAdditions($value) {
415
		$this->_params["allowAdditions"] = $value;
416
		return $this;
417
	}
418
419
	public function setFullTextSearch($value) {
420
		$this->_params["fullTextSearch"] = $value;
421
		return $this;
422
	}
423
424
	public function compile(JsUtils $js = NULL, &$view = NULL) {
425
		$this->applyValue();
426
		return parent::compile($js, $view);
427
	}
428
429
	public function getInput() {
430
		return $this->input;
431
	}
432
433
	public function setIcon($icon = "dropdown") {
434
		$this->content["arrow"] = new HtmlIcon($this->identifier . "-icon", $icon);
435
		return $this;
436
	}
437
438
	public function jsAddItem($caption, $value = null) {
439
		$value = $value ?? $caption;
440
		$js = "var first=$('#{$this->identifier} .item').first();if(first!=undefined){var newItem =first.clone();first.parent().append(newItem);newItem.html({$caption});newItem.attr('data-value',{$value}).removeClass('active filtered');}";
441
		return $js;
442
	}
443
444
	public function setClearable($value) {
445
		$this->_params["clearable"] = $value;
446
		return $this;
447
	}
448
449
	/**
450
	 * Is called after a dropdown selection is added using a multiple select dropdown, only receives the added value
451
	 * Parameters addedValue, addedText, $addedChoice
452
	 */
453
	public function setOnAdd($jsCode) {
454
		$this->_params["onAdd"] = $jsCode;
455
		return $this;
456
	}
457
458
	/**
459
	 * Is called after a dropdown selection is removed using a multiple select dropdown, only receives the removed value
460
	 * Parameters removedValue, removedText, $removedChoice
461
	 */
462
	public function setOnRemove($jsCode) {
463
		$this->_params["onRemove"] = $jsCode;
464
		return $this;
465
	}
466
}
467