'URL'] */ public $descriptionProperties = []; /** * @var string object property to use as a description. */ public $descriptionProperty; /** * @var string Message to display when there are no records in the list. */ public $noRecordsMessage = 'No records found'; /** * @var string Message to display when the Delete button is clicked. */ public $deleteConfirmation = 'Do you really want to delete selected templates?'; /** * @var string Specifies the item type. */ public $itemType; /* * Public methods */ public function __construct($controller, $alias, callable $dataSource) { $this->alias = $alias; $this->dataSource = $dataSource; $this->theme = Theme::getEditTheme(); parent::__construct($controller, []); if (!Request::isXmlHttpRequest()) $this->resetSelection(); $configFile = 'config_' . snake_case($alias) .'.yaml'; $config = $this->makeConfig($configFile); foreach ($config as $field=>$value) { if (property_exists($this, $field)) $this->$field = $value; } $this->bindToController(); } /** * Renders the widget. * @return string */ public function render() { return $this->makePartial('body', [ 'data'=>$this->getData() ]); } /* * Event handlers */ public function onSearch() { $this->setSearchTerm(Input::get('search')); $this->extendSelection(); return $this->updateList(); } public function onGroupStatusUpdate() { $this->setGroupStatus(Input::get('group'), Input::get('status')); } public function onSelect() { $this->extendSelection(); } public function onUpdate() { $this->extendSelection(); return $this->updateList(); } /* * Methods for the internal use */ protected function getData() { // Load the data $items = call_user_func($this->dataSource); $normalizedItems = []; foreach ($items as $item) $normalizedItems[] = $this->normalizeItem($item); usort($normalizedItems, function($a, $b) { return strcmp($a->title, $b->title); }); // Apply the search $filteredItems = []; $searchTerm = Str::lower($this->getSearchTerm()); if (strlen($searchTerm)) { $words = explode(' ', $searchTerm); foreach ($normalizedItems as $item) { if ($this->itemMatchesSearch($words, $item)) $filteredItems[] = $item; } } else $filteredItems = $normalizedItems; // Group the items $result = []; $foundGroups = []; foreach ($filteredItems as $itemData) { $pos = strpos($itemData->fileName, '/'); if ($pos !== false) { $group = substr($itemData->fileName, 0, $pos); if (!array_key_exists($group, $foundGroups)) { $newGroup = (object)[ 'title' => $group, 'items' => [] ]; $foundGroups[$group] = $newGroup; } $foundGroups[$group]->items[] = $itemData; } else $result[] = $itemData; } foreach ($foundGroups as $group) $result[] = $group; return $result; } protected function normalizeItem($item) { $description = null; if ($descriptionProperty = $this->descriptionProperty) $description = $item->$descriptionProperty; $descriptions = []; foreach ($this->descriptionProperties as $property=>$title) { if ($item->$property) $descriptions[$title] = $item->$property; } $result = [ 'title' => $this->getItemTitle($item), 'fileName' => $item->getFileName(), 'description' => $description, 'descriptions' => $descriptions ]; return (object)$result; } protected function getItemTitle($item) { $titleProperty = $this->titleProperty; if ($titleProperty) return $item->$titleProperty ?: $item->getFileName(); return $item->getFileName(); } protected function setSearchTerm($term) { $this->searchTerm = trim($term); $this->putSession('search', $this->searchTerm); } protected function getSearchTerm() { return $this->searchTerm !== false ? $this->searchTerm : $this->getSession('search'); } protected function updateList() { return ['#'.$this->getId('template-list') => $this->makePartial('items', ['items'=>$this->getData()])]; } protected function itemMatchesSearch(&$words, $item) { foreach ($words as $word) { $word = trim($word); if (!strlen($word)) continue; if (!$this->itemContainsWord($word, $item)) return false; } return true; } protected function itemContainsWord($word, $item) { if (strlen($item->title)) { if (Str::contains(Str::lower($item->title), $word)) return true; } else if (Str::contains(Str::lower($item->fileName), $word)) return true; if (Str::contains(Str::lower($item->description), $word) && strlen($item->description)) return true; foreach ($item->descriptions as $value) if (Str::contains(Str::lower($value), $word) && strlen($value)) return true; return false; } protected function getGroupStatus($group) { $statuses = $this->getGroupStatuses(); if (array_key_exists($group, $statuses)) return $statuses[$group]; return false; } protected function getThemeSessionKey($prefix) { return $prefix.$this->theme->getDirName(); } protected function getGroupStatuses() { if ($this->groupStatusCache !== false) return $this->groupStatusCache; $groups = $this->getSession($this->getThemeSessionKey('groups'), []); if (!is_array($groups)) return $this->groupStatusCache = []; return $this->groupStatusCache = $groups; } protected function setGroupStatus($group, $status) { $statuses = $this->getGroupStatuses(); $statuses[$group] = $status; $this->groupStatusCache = $statuses; $this->putSession($this->getThemeSessionKey('groups'), $statuses); } protected function getSelectedTemplates() { if ($this->selectedTemplatesCache !== false) return $this->selectedTemplatesCache; $templates = $this->getSession($this->getThemeSessionKey('selected'), []); if (!is_array($templates)) return $this->selectedTemplatesCache = []; return $this->selectedTemplatesCache = $templates; } protected function extendSelection() { $items =Input::get('template', []); $currentSelection = $this->getSelectedTemplates(); $this->putSession($this->getThemeSessionKey('selected'), array_merge($currentSelection, $items)); } protected function resetSelection() { $this->putSession($this->getThemeSessionKey('selected'), []); } protected function isTemplateSelected($item) { $selectedTemplates = $this->getSelectedTemplates(); if (!is_array($selectedTemplates) || !isset($selectedTemplates[$item->fileName])) return false; return $selectedTemplates[$item->fileName]; } }