/** * Generate the widget and return it as string * @return string */ public function generate() { $arrSet = array(); $arrValues = array(); $blnHasOrder = $this->strOrderField != '' && is_array($this->{$this->strOrderField}); if (!empty($this->varValue)) { $objItems = $this->Database->execute("SELECT * FROM " . $this->foreignTable . " WHERE id IN (" . implode(',', array_map('intval', (array) $this->varValue)) . ") ORDER BY sorting"); if ($objItems !== null) { while ($objItems->next()) { $arrSet[] = $objItems->id; $arrValues[$objItems->id] = TreePickerHelper::generateItemLabel($objItems, $this->foreignTable, $this->objDca, null, $this->pickerCallback); } } // Apply a custom sort order if ($blnHasOrder) { $arrNew = array(); foreach ($this->{$this->strOrderField} as $i) { if (isset($arrValues[$i])) { $arrNew[$i] = $arrValues[$i]; unset($arrValues[$i]); } } if (!empty($arrValues)) { foreach ($arrValues as $k => $v) { $arrNew[$k] = $v; } } $arrValues = $arrNew; unset($arrNew); } $orderCallback = $this->orderCallback; // Use callback to order things if (is_array($orderCallback)) { $strClass = $orderCallback[0]; $strMethod = $orderCallback[1]; $arrValues = \System::importStatic($strClass)->{$strMethod}($arrValues); } elseif (is_callable($orderCallback)) { $arrValues = $orderCallback($arrValues); } } // Load the fonts for the drag hint $GLOBALS['TL_CONFIG']['loadGoogleFonts'] = true; $return = '<input type="hidden" name="' . $this->strName . '" id="ctrl_' . $this->strId . '" value="' . implode(',', $arrSet) . '">' . ($blnHasOrder ? ' <input type="hidden" name="' . $this->strOrderName . '" id="ctrl_' . $this->strOrderId . '" value="' . $this->{$this->strOrderField} . '">' : '') . ' <div class="selector_container">' . ($blnHasOrder && count($arrValues) ? ' <p class="sort_hint">' . $GLOBALS['TL_LANG']['MSC']['dragItemsHint'] . '</p>' : '') . ' <ul id="sort_' . $this->strId . '" class="' . ($blnHasOrder ? 'sortable' : '') . '">'; foreach ($arrValues as $k => $v) { $return .= '<li data-id="' . $k . '">' . $v . '</li>'; } $return .= '</ul> <p><a href="system/modules/widget_tree_picker/public/treepicker.php?do=' . \Input::get('do') . '&table=' . $this->strTable . '&field=' . $this->strField . '&act=show&id=' . $this->activeRecord->id . '&value=' . implode(',', $arrSet) . '&rt=' . REQUEST_TOKEN . '" class="tl_submit" onclick="Backend.getScrollOffset();TreePicker.openModal({\'width\':765,\'title\':\'' . specialchars($GLOBALS['TL_LANG']['MSC']['treepicker']) . '\',\'url\':this.href,\'id\':\'' . $this->strId . '\'});return false">' . $GLOBALS['TL_LANG']['MSC']['changeSelection'] . '</a></p>' . ($blnHasOrder ? ' <script>Backend.makeMultiSrcSortable("sort_' . $this->strId . '", "ctrl_' . $this->strOrderId . '")</script>' : '') . ' <script> var script = document.createElement("script"); script.src = "system/modules/widget_tree_picker/assets/treepicker.min.js"; document.getElementsByTagName("head")[0].appendChild(script); </script> </div>'; if (!\Environment::get('isAjaxRequest')) { $return = '<div>' . $return . '</div>'; } return $return; }
/** * Recursively render the itemtree * @param integer * @param integer * @param boolean * @param boolean * @return string */ protected function renderItemTree($id, $intMargin, $blnNoRecursion = false) { static $session; $session = $this->Session->getData(); $flag = substr($this->strField, 0, 2); $node = 'tree_' . $this->strTable . '_' . $this->strField; $xtnode = 'tree_' . $this->strTable . '_' . $this->strName; // Get the session data and toggle the nodes if (\Input::get($flag . 'tg')) { $session[$node][\Input::get($flag . 'tg')] = isset($session[$node][\Input::get($flag . 'tg')]) && $session[$node][\Input::get($flag . 'tg')] == 1 ? 0 : 1; $this->Session->setData($session); $this->redirect(preg_replace('/(&(amp;)?|\\?)' . $flag . 'tg=[^& ]*/i', '', \Environment::get('request'))); } $objItem = $this->Database->prepare("SELECT * FROM " . $this->foreignTable . " WHERE id=?")->limit(1)->execute($id); // Return if there is no result if ($objItem->numRows < 1) { return ''; } $return = ''; $intSpacing = 20; $childs = array(); // Check whether there are child records if (!$blnNoRecursion) { $objNodes = $this->Database->prepare("SELECT id FROM " . $this->foreignTable . " WHERE pid=? ORDER BY sorting")->execute($id); if ($objNodes->numRows) { $childs = $objNodes->fetchEach('id'); } } $return .= "\n " . '<li class="tl_file toggle_select" onmouseover="Theme.hoverDiv(this, 1)" onmouseout="Theme.hoverDiv(this, 0)"><div class="tl_left" style="padding-left:' . ($intMargin + $intSpacing) . 'px">'; $session[$node][$id] = is_numeric($session[$node][$id]) ? $session[$node][$id] : 0; $level = $intMargin / $intSpacing + 1; $blnIsOpen = $session[$node][$id] == 1 || in_array($id, $this->arrNodes); if (!empty($childs)) { $img = $blnIsOpen ? 'folMinus.gif' : 'folPlus.gif'; $alt = $blnIsOpen ? $GLOBALS['TL_LANG']['MSC']['collapseNode'] : $GLOBALS['TL_LANG']['MSC']['expandNode']; $return .= '<a href="' . $this->addToUrl($flag . 'tg=' . $id) . '" title="' . specialchars($alt) . '" onclick="return TreePicker.toggle(this,\'' . $xtnode . '_' . $id . '\',\'' . $this->strField . '\',\'' . $this->strName . '\',' . $level . ')">' . \Image::getHtml($img, '', 'style="margin-right:2px"') . '</a>'; } $label = TreePickerHelper::generateItemLabel($objItem, $this->foreignTable, $this->objDca); // Add the current item if (!empty($childs)) { $return .= '<a href="' . $this->addToUrl('node=' . $objItem->id) . '" title="' . specialchars(strip_tags($label)) . '">' . $label . '</a></div> <div class="tl_right">'; } else { $return .= '<span style="margin-left:' . $intSpacing . 'px;"></span>' . $label . '</div> <div class="tl_right">'; } $showInput = true; // HOOK: toggle input visibility if (isset($GLOBALS['TL_HOOKS']['widgetTreePickerToggleInput']) && is_array($GLOBALS['TL_HOOKS']['widgetTreePickerToggleInput'])) { foreach ($GLOBALS['TL_HOOKS']['widgetTreePickerToggleInput'] as $callback) { $this->import($callback[0]); $showInput = $this->{$callback[0]}->{$callback[1]}($objItem, $this); } } if ($showInput) { // Add checkbox or radio button switch ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['fieldType']) { case 'checkbox': $input = '<input type="checkbox" name="' . $this->strName . '[]" id="' . $this->strName . '_' . $id . '" class="tl_tree_checkbox" value="' . specialchars($id) . '" onfocus="Backend.getScrollOffset()"' . ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['selectParents'] ? ' onclick="TreePicker.selectParents(this)"' : '') . static::optionChecked($id, $this->varValue) . '>'; break; default: case 'radio': $input = '<input type="radio" name="' . $this->strName . '" id="' . $this->strName . '_' . $id . '" class="tl_tree_radio" value="' . specialchars($id) . '" onfocus="Backend.getScrollOffset()"' . static::optionChecked($id, $this->varValue) . '>'; break; } // HOOK: modify input markup if (isset($GLOBALS['TL_HOOKS']['widgetTreePickerModifyInput']) && is_array($GLOBALS['TL_HOOKS']['widgetTreePickerModifyInput'])) { foreach ($GLOBALS['TL_HOOKS']['widgetTreePickerModifyInput'] as $callback) { $this->import($callback[0]); $input = $this->{$callback[0]}->{$callback[1]}($input, $objItem, $this); } } $return .= $input; } $return .= '</div><div style="clear:both"></div></li>'; // Begin a new submenu if (!empty($childs) && ($blnIsOpen || $this->Session->get($this->getSearchSessionKey()) != '')) { $return .= '<li class="parent" id="' . $node . '_' . $id . '"><ul class="level_' . $level . '">'; for ($k = 0, $c = count($childs); $k < $c; $k++) { $return .= $this->renderItemTree($childs[$k], $intMargin + $intSpacing); } $return .= '</ul></li>'; } return $return; }