Generates an HTML select list

@param   array|KObjectConfig     $config An optional array with configuration options
@return  string  Html
358358
public function optionlist($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'options'   => array(),
            'selected'  => null,
            'disabled'  => null,
            'translate' => false,
            'attribs'   => array('size' => 1),
        ));

        $html = array();

        $html[] = '<select name="'. $config->name .'" '. $this->buildAttributes($config->attribs) .'>';

        foreach($config->options as $group => $options)
        {
            if (is_numeric($group)) {
                $options = array($options);
            } else {
                $html[] = '<optgroup label="' . $this->getTemplate()->escape($group) . '">';
            }

            foreach ($options as $option)
            {
                $value = $option->value;
                $label = $config->translate ? $this->getObject('translator')->translate( $option->label ) : $option->label;

                $extra = '';
                if(isset($option->disabled) && $option->disabled) {
                    $extra .= 'disabled="disabled"';
                }

                if(isset($option->attribs)) {
                    $extra .= ' '.$this->buildAttributes($option->attribs);
                }

                if(!is_null($config->selected))
                {
                    if ($config->selected instanceof KObjectConfig)
                    {
                        foreach ($config->selected as $selected)
                        {
                            $sel = is_object($selected) ? $selected->value : $selected;
                            if ((string) $value == (string) $sel)
                            {
                                $extra .= 'selected="selected"';
                                break;
                            }
                        }
                    }
                    else $extra .= ((string) $value == (string) $config->selected ? ' selected="selected"' : '');
                }

                $html[] = '<option value="'. $value .'" '.$extra.'>' . $label . '</option>';
            }

            if (!is_numeric($group)) {
                $html[] = '</optgroup>';
            }
        }

        $html[] = '</select>';

        return implode(PHP_EOL, $html);
    }
817736
public function renderForm( $config = [], $html = [] ) {

		$formView = CodeGenUtil::isAbsolutePath( $this->formView, true ) ? $this->formView : "$this->template/$this->formView";

		return $this->render( $formView, [
			'widget' => $this,
			'infoHtml' => $html[ 'infoHtml' ],
			'fieldsHtml' => $html[ 'fieldsHtml' ]
		] );
	}
80665
public function search($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'search'          => null,
            'submit_on_clear' => true,
            'placeholder'     => $this->getObject('translator')->translate('Find by title or description&hellip;')
        ));

        $html = '';

        if ($config->submit_on_clear)
        {
            $html .= $this->createHelper('behavior')->jquery();
            $html .= '
            <script>
            (function() {
            var value = '.json_encode($config->search).',
                submitForm = function(form) {
                    if (form.length) {
                        var controller = form.data("controller");
                        if (typeof controller === "object" && controller !== null
                                && controller.grid && typeof controller.grid.uncheckAll !== "undefined") {
                            controller.grid.uncheckAll();
                        }

                        form[0].submit();
                    }
                },
                send = function(event) {
                    var v = kQuery(this).val();

                    if (v) {
                        kQuery(".k-search__empty").addClass("k-is-visible");
                    } else {
                        kQuery(".k-search__empty").removeClass("k-is-visible");
                    }

                    if (event.which === 13 || (event.type === "blur" && (v || value) && v != value)) {
                        event.preventDefault();
                        submitForm(kQuery(this).parents("form"));
                    }
                };

            kQuery(function($) {
                $(".k-search__field").keypress(send).blur(send);
                var empty_button = $(".k-search__empty");
                
                if (value) {
                    empty_button.addClass("k-is-visible");
                }
                
                empty_button.click(function(event) {
                    event.preventDefault();

                    var input = $(this).siblings("input");
                    input.val("");

                    if (value) {
                        submitForm(input.parents("form"));
                    }
                });
            });
            })();
            </script>';
        }

        $html .= '<div class="k-search k-search--has-both-buttons">';
        $html .= '<label for="k-search-input">' . $this->getObject('translator')->translate('Search') . '</label>';
        $html .= '<input id="k-search-input" type="search" name="search" class="k-search__field" placeholder="'.$config->placeholder.'" value="'.StringEscaper::attr($config->search).'" />';
        $html .= '<button type="submit" class="k-search__submit">';
        $html .= '<span class="k-icon-magnifying-glass" aria-hidden="true"></span>';
        $html .= '<span class="k-visually-hidden">' . $this->getObject('translator')->translate('Search') . '</span>';
        $html .= '</button>';
        $html .= '<button type="button" class="k-search__empty">';
        $html .= '<span class="k-search__empty-area">';
        $html .= '<span class="k-icon-x" aria-hidden="true"></span>';
        $html .= '<span class="k-visually-hidden">' . $this->getObject('translator')->translate('Clear search') . '</span>';
        $html .= '</span>';
        $html .= '</button>';

        if ($config->search) {
            $html .= '<div class="k-scopebar__item-label k-scopebar__item-label--numberless"></div>';
        }

        $html .= '</div>';



        return $html;
    }
352814
public function bootstrap($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'debug' => JFactory::getApplication()->getCfg('debug')
        ));

        $html = '';

        if ($this->getTemplate()->decorator() === 'joomla')
        {
            $config->append([
                'css' => file_exists(JPATH_THEMES.'/'.JFactory::getApplication()->getTemplate().'/enable-koowa-bootstrap.txt')
            ]);

            if ($config->javascript && !static::isLoaded('bootstrap-javascript'))
            {
                $html .= $this->jquery($config);
                JHtml::_('bootstrap.framework');

                static::setLoaded('bootstrap-javascript');

                $config->javascript = false;
            }
        }

        $html .= parent::bootstrap($config);
        return $html;
    }
1340960
public function access($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'entity'  		=> null,
            'field'		=> 'access'
        ));

        $db = JFactory::getDbo();
        $query = $db->getQuery(true);

        $query->select('a.title AS text');
        $query->from('#__viewlevels AS a');
        $query->where('id = '.(int) $config->entity->{$config->field});
        $query->group('a.id, a.title, a.ordering');
        $query->order('a.ordering ASC');
        $query->order($query->qn('title') . ' ASC');

        // Get the options.
        $db->setQuery($query);
        $html = $db->loadResult();

        return $html;
    }
1156247
public function dialog($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'command' => NULL
        ));

        $html = $this->command($config);

        return $html;
    }
1007320
public function autocomplete($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'element'  => null,
            'options_callback' => null, // wraps the call to select2 options in JavaScript, can be used to add JS code
            'options'  => array(
                'minimumInputLength' => 2,
                'validate'      => false, //Toggle if the forms validation helper is loaded
                'queryVarName'  => 'search',
                'width'         => 'resolve',
                'name'          => '',
                'model'		    => $config->model,
                'placeholder'   => $config->prompt,
                'allowClear'    => $config->deselect,
                'value'         => $config->value,
                'text'          => $config->text,
                'selected'      => $config->selected,
                'url'           => $config->ajax_url,
                'multiple'      => false
            )
        ))->append(array(
            'options' => array(
                'label' => $config->text
            )
        ));

        $html ='';

        if (!$config->options->url instanceof HttpUrl) {
            $config->options->url = $this->getObject('lib:http.url', ['url' => $config->options->url]);
        }

        if(!empty($config->name))
        {
            $config->options->url->setQuery(array('fields['.$config->name.']' => $config->value.','.$config->text), true);
            $config->options->url = (string)$config->options->url;
        }

        $options   = $config->options;
        $signature = md5('autocomplete-'.$config->element.$config->options_callback.$options);

        if($config->element && !static::isLoaded($signature))
        {
            $options = (string) $options;

            if ($config->options_callback) {
                $options = $config->options_callback.'('.$options.')';
            }

            $html .= $this->select2(array('element' => false));

            if (!static::isLoaded('kodekit-select2-autocomplete')) {
                $html .= '<script>
                if(!Kodekit) {
                    var Kodekit = typeof Koowa !== "undefined" ?  Koowa : {};
                }
                
                Kodekit.getSelect2Options = function(options) {
                    var defaults = {
                        width: "resolve",
                        minimumInputLength: 2,
                        theme: "bootstrap",
                        ajax: {
                            url: options.url,
                            delay: 100,
                            data: function (params) {
                                var page  = params.page || 1,  // page is the one-based page number tracked by Select2
                                    query = {
                                        limit: 10, // page size
                                        offset: (page-1)*10
                                    };
                                query[options.queryVarName] = params.term;
            
                                return query;
                            },
                            processResults: function (data, page) {
                                var results = [],
                                    more = (page * 10) < data.meta.total; // whether or not there are more results available
            
                                kQuery.each(data.data, function(i, item) {
                                    // Change format to what select2 expects
                                    item.id   = item.attributes[options.value];
                                    item.text = item.attributes[options.text];
            
                                    results.push(item);
                                });
            
                                // notice we return the value of more so Select2 knows if more results can be loaded
                                return {results: results, more: more};
                            }
                        }
                    };
                    
                    var settings = kQuery.extend( {}, defaults, options);
                    
                    return settings;
                };
                </script>';

                static::setLoaded('kodekit-select2-autocomplete');
            }

            $html .= '<script>
            kQuery(function($){
                $("'.$config->element.'").select2(Kodekit.getSelect2Options('.$options.'));
            });</script>';

            static::setLoaded($signature);
        }

        return $html;
    }
636439
public function title($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'command' => NULL,
        ));

        $title = $this->getObject('translator')->translate($config->command->title);
        $html  = '';

        if (!empty($title))
        {
            $html = parent::title($config);

            if (JFactory::getApplication()->isAdmin())
            {
                $app = JFactory::getApplication();
                $app->JComponentTitle = $title;

                JFactory::getDocument()->setTitle($app->getCfg('sitename') . ' - ' . JText::_('JADMINISTRATION') . ' - ' . $title);
            }
        }

        return $html;
    }
968429
public function checkbox($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'entity'  => null,
            'attribs' => array()
        ))->append(array(
            'column' => $config->entity->getIdentityKey()
        ));

        if($config->entity->isLockable() && $config->entity->isLocked())
        {
            $html = $this->createHelper('behavior')->tooltip();
            $html .= '<span class="k-icon-lock-locked"
                            data-k-tooltip
                            title="'.$this->createHelper('grid')->lock_message(array('entity' => $config->entity)).'">
                    </span>';
        }
        else
        {
            $column = $config->column;
            $value  = StringEscaper::attr($config->entity->{$column});

            $attribs = $this->buildAttributes($config->attribs);

            $html = '<input type="checkbox" class="k-js-grid-checkbox" name="%s[]" value="%s" %s />';
            $html = sprintf($html, $column, $value, $attribs);
        }

        return $html;
    }
196499
public function bootstrap($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'debug' => \Kodekit::getInstance()->isDebug(),
            'css'   => true,
            'javascript' => false
        ));

        $html = '';

        if ($config->javascript && !static::isLoaded('bootstrap-javascript'))
        {
            $html .= $this->jquery($config);
            $html .= '<ktml:script src="assets://js/'.($config->debug ? 'build/' : 'min/').'bootstrap.js" />';

            static::setLoaded('bootstrap-javascript');
        }

        if ($config->css && !static::isLoaded('bootstrap-css'))
        {
            $html .= '<ktml:style src="assets://css/bootstrap.css" />';

            static::setLoaded('bootstrap-css');
        }

        return $html;
    }
429731
public function vue($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'debug' => JFactory::getApplication()->getCfg('debug')
        ));

        return parent::vue($config);
    }
758744
protected function _items(KObjectConfig $config)
    {
        $elements  = array();

        // First
        $offset  = 0;
        $active  = $offset != $config->offset;
        $props   = array('page' => 1, 'offset' => $offset, 'limit' => $config->limit, 'current' => false, 'active' => $active );

        $elements['first'] = (object) $props;

        // Previous
        $offset  = max(0, ($config->current - 2) * $config->limit);
        $active  = $offset != $config->offset;
        $props   = array('page' => $config->current - 1, 'offset' => $offset, 'limit' => $config->limit, 'current' => false, 'active' => $active);
        $elements['previous'] = (object) $props;

        // Pages
        $elements['pages'] = array();
        foreach($this->_offsets($config) as $page => $offset)
        {
            $current = $offset == $config->offset;
            $props = array('page' => $page, 'offset' => $offset, 'limit' => $config->limit, 'current' => $current, 'active' => !$current);
            $elements['pages'][] = (object) $props;
        }

        // Next
        $offset  = min(($config->count-1) * $config->limit, ($config->current) * $config->limit);
        $active  = $offset != $config->offset;
        $props   = array('page' => $config->current + 1, 'offset' => $offset, 'limit' => $config->limit, 'current' => false, 'active' => $active);
        $elements['next'] = (object) $props;

        // Last
        $offset  = ($config->count - 1) * $config->limit;
        $active  = $offset != $config->offset;
        $props   = array('page' => $config->count, 'offset' => $offset, 'limit' => $config->limit, 'current' => false, 'active' => $active);
        $elements['last'] = (object) $props;

        return $elements;
    }
910606
public function bootstrap($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'debug' => false,
            'css'   => true,
            'javascript' => false
        ));

        $html = '';

        if ($config->javascript && !static::isLoaded('bootstrap-javascript'))
        {
            $html .= $this->jquery($config);
            $html .= '<ktml:script src="assets://js/'.($config->debug ? 'build/' : 'min/').'bootstrap.js" />';

            static::setLoaded('bootstrap-javascript');
        }

        if ($config->css && !static::isLoaded('bootstrap-css'))
        {
            $html .= '<ktml:style src="assets://css/bootstrap.css" />';

            static::setLoaded('bootstrap-css');
        }

        return $html;
    }
153140
public function publish($config = array())
    {
        $translator = $this->getObject('translator');

        $config = new KObjectConfigJson($config);
        $config->append(array(
            'entity'    => null,
            'field'     => 'enabled',
            'clickable' => true
        ))->append(array(
            'enabled'   => (bool) $config->entity->{$config->field},
        ))->append(array(
            'alt'       => $config->enabled ? $translator->translate('Published') : $translator->translate('Unpublished'),
            'tooltip'   => $config->enabled ? $translator->translate('Unpublish Item') : $translator->translate('Publish Item'),
            'color'     => $config->enabled ? '#468847' : '#b94a48',
            'icon'      => $config->enabled ? 'enabled' : 'disabled',
        ));

        return $this->enable($config);
    }
1364783
public function load($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'debug' => JFactory::getApplication()->getCfg('debug'),
            'wrapper_class' => array(
                JFactory::getLanguage()->isRtl() ? 'k-ui-rtl' : 'k-ui-ltr'
            )
        ));
        
        if($this->getTemplate()->decorator() === 'koowa')
        {
            $layout = $this->getTemplate()->getParameters()->layout;

            if (JFactory::getApplication()->isSite() && $layout === 'form') {
                $config->domain = 'admin';
            }
        }

        $identifier = $this->getTemplate()->getIdentifier();
        $menu       = JFactory::getApplication()->getMenu()->getActive();

        if ($identifier->type === 'com' && $menu)
        {
            if ($suffix = htmlspecialchars($menu->params->get('pageclass_sfx')))
            {
                $config->append(array(
                    'wrapper_class' => array($suffix)
                ));
            }
        }

        $html = parent::load($config);

        return $html;
    }
1126429
protected function _autocomplete($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'name'     => '',
            'attribs'  => array(
                'id' => 'select2-element-'.mt_rand(1000, 100000)
            ),
            'model'    => KStringInflector::pluralize($this->getIdentifier()->package),
            'validate' => true,
            'prompt'   => '- '.$this->getObject('translator')->translate('Select').' -',
            'deselect' => true,
        ))->append(array(
            'element'    => '#'.$config->attribs->id,
            'options'    => array('multiple' => (bool) $config->attribs->multiple),
            'value'      => $config->name,
            'selected'   => $config->{$config->name},
        ))->append(array(
            'label'      => $config->value,
        ))->append(array(
            'text'       => $config->label,
            'filter'     => array('sort' => $config->label),
        ));

        //Add name to attribs
        $config->attribs->name = $config->name;

        //Get the model object
        if(!$config->model instanceof KModelInterface)
        {
            $config->append(array(
                'identifier' => 'com://'.$this->getIdentifier()->domain.'/'.$this->getIdentifier()->package.'.model.'.$config->model
            ));

            $model = $this->getObject($config->identifier);
        }
        else $model = $config->model;

        //Get the autocomplete url
        if (!$config->url)
        {
            $identifier = $this->getIdentifier($model);
            $parts      = array(
                'component' => $identifier->package,
                'view'      => $identifier->name,
                'format'    => 'json'
            );

            if ($config->filter) {
                $parts = array_merge($parts, KObjectConfig::unbox($config->filter));
            }

            $config->url = $this->getTemplate()->route($parts, false, false);
        }

        $html = '';
        $html .= $this->getTemplate()->createHelper('behavior')->autocomplete($config);

        //Get the selected items
        $options = array();
        if ((is_scalar($config->selected) || is_null($config->selected)) ? !empty($config->selected) : count($config->selected))
        {
            $selected = $config->selected;

            if(!$selected instanceof KModelEntityInterface)
            {
                $selected = $model->setState(KObjectConfig::unbox($config->filter))
                                  ->setState(array($config->value => KObjectConfig::unbox($selected)))
                                  ->fetch();
            }

            foreach($selected as $entity)
            {
                $options[]  = $this->option(array(
                    'value' => $entity->{$config->value},
                    'label' => $entity->{$config->label},
                    'attribs' => array('selected' => true)
                ));
            }
        }

        $html .= $this->optionlist(array(
            'name'     => $config->name,
            'id'       => $config->id,
            'options' => $options,
            'deselect' => false,
            'select2'  => false,
            'attribs'  => $config->attribs
        ));

        return $html;
    }
80080
public function buildTreeHtml($keys = [], $items = [], $config = [], $selected = []) {
        $configDefault = [
            'id' => 'nestable',
            'class' => 'dd',
            'containerClass' => 'dd-list',
            'itemClass' => 'dd-item',
            'labelClass' => 'dd-handle',
            'actions' => [],
        ];
        $config = array_merge($configDefault, $config);

        // root items
        $asRoot = false;
        if (empty($items)) {
            $asRoot = true;
            $items[] = [
                '_id' => $this->owner->getAttribute('_id'),
                'name' => $this->owner->getAttribute('name'),
                'lft' => $this->owner->getAttribute($this->leftAttribute),
                'rgt' => $this->owner->getAttribute($this->rightAttribute),
            ];
            $children = $this->children()->all();
            foreach ($children as $child) {
                $items[] = [
                    '_id' => $child->owner->getAttribute('_id'),
                    'name' => $child->owner->getAttribute('name'),
                    $this->leftAttribute => $child->owner->getAttribute($this->leftAttribute),
                    $this->rightAttribute => $child->owner->getAttribute($this->rightAttribute),
                ];
            }
            $keys = $this->buildTreeKeys($items);
        }
        
        $list = Html::beginTag('ol', ['class' => $config['containerClass']]);
        foreach ($keys as $key => $row) {
            if (isset($config['actions'])) {
                $actions = str_replace ('{_id}', $items[$key]['_id'], $config['actions']);

                if (is_array($selected) && in_array($items[$key]['_id'], $selected)) {
                    $actions = str_replace ('{check}', 'checked', $actions);
                }
            }

            if (count($row)) {
                $list .= Html::tag('li', $actions.'<div class="' . $config['labelClass'] . '">' . $items[$key]['name']  . '</div>' . $this->buildTreeHtml($row, $items, $config, $selected), ['class' => $config['itemClass'], 'data-id' => $items[$key]['_id']]);
            } else {
                $list .= Html::tag('li', $actions.'<div class="' . $config['labelClass'] . '">' . $items[$key]['name'] . '</div>', ['class' => $config['itemClass'], 'data-id' => $items[$key]['_id']]);
            }
        }
        $list .= Html::endTag('ol');

//        if (strpos($list, Html::beginTag('li', ['class' => $config['itemClass'], 'data-id' => $items[$key]['_id']])) === false) {
//            $list = '';
//        }
        
        if ($asRoot){
            $list = Html::tag('div', $list, ['id' => $config['id'], 'class' => $config['class']]);
        }
        return $list;
    }