Add Bootstrap JS and CSS a modal box

@param array|KObjectConfig $config
@return string   The html output
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;
    }
818983
public function search($config = array())
    {
        $config = new KObjectConfigJson($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->getTemplate()->helper('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="'.$this->getTemplate()->escape($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>';
        $html .= '</div>';



        return $html;
    }
1162523
public function optionlist($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'options'   => array(),
            'name'      => 'id',
            '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="' . StringEscaper::attr($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 ObjectConfig)
                    {
                        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);
    }
71523
protected function buildBootstrapJs(array $config)
    {
        $path = !in_array($config['less_filter'], array('sass', 'scssphp')) ? "bower_components/bootstrap/js" : "bower_components/bootstrap-sass-official/assets/javascripts/bootstrap";

        return array(
            'inputs' => array(
                $this->normalizePath($config['bootswatch']['path'], $path, '/transition.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/alert.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/button.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/carousel.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/collapse.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/dropdown.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/modal.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/tooltip.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/popover.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/scrollspy.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/tab.js'),
                $this->normalizePath($config['bootswatch']['path'], $path, '/affix.js'),
                $this->normalizePath(dirname(__FILE__).'/../../Resources/js/bc-bootstrap-collection.js'),
            ),
            'output' => $this->normalizePath(isset($config['output_dir']) ? array($config['output_dir'], 'js/bootstrap.js') : 'js/bootstrap.js')
        );
    }
934687
public function vue($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append([
            'debug' => false,
            'vuex' => true,
            'entity' => null
        ]);

        $html = '';

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

            static::setLoaded('vue');
        }

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

            static::setLoaded('vuex');
        }

        if ($config->entity instanceof KModelEntityInterface)
        {
            $entity = $config->entity->toArray();
            $entity = is_numeric(key($entity)) ? current($entity) : $entity;
            $entity['_isNew'] = $config->entity->isNew();
            $entity['_name']  = KStringInflector::singularize($config->entity->getIdentifier()->name);

            $html .= $this->koowa($config);
            $html .= "
            <ktml:script src=\"assets://js/koowa.vue.js\" />
            <script>
                kQuery(function($) {
                    var form = $('.k-js-form-controller');
                    
                    if (form.length) {
                        form.data('controller').store = Koowa.EntityStore.create({
                            form: form,
                            entity: ".json_encode($entity)."
                        });
                    }
                });
            </script>
";
        }

        return $html;
    }
914490
protected function _initialize(KObjectConfig $config)
    {
        if($config->total != 0)
        {
            $config->limit  = (int) max($config->limit, 0);
            $config->offset = (int) max($config->offset, 0);

            if($config->limit > $config->total) {
                $config->offset = 0;
            }

            if(!$config->limit)
            {
                $config->offset = 0;
                $config->limit  = $config->total;
            }

            $config->count  = (int) ceil($config->total / $config->limit);

            if($config->offset > $config->total) {
                $config->offset = ($config->count-1) * $config->limit;
            }

            $config->current = (int) floor($config->offset / $config->limit) + 1;
        }
        else
        {
            $config->limit   = 0;
            $config->offset  = 0;
            $config->count   = 0;
            $config->current = 0;

            $config->show_pages = false;
        }

        if ($config->count === 1) {
            $config->show_pages = false;
        }

        parent::_initialize($config);
    }
1339442
public function option($config = array())
    {
        $config = new KObjectConfigJson($config);
        $config->append(array(
            'id'        => null,
            'name'      => 'id',
            'value'     => null,
            'label'     => '',
            'disabled'  => false,
            'level'     => 1,
            'attribs'   => array(),
        ));

        $option = new stdClass;
        $option->id       = $config->id;
        $option->name     = $config->name;
        $option->value 	  = $config->value;
        $option->label    = trim( $config->label ) ? $config->label : $config->value;
        $option->disabled = $config->disabled;
        $option->level    = $config->level;
        $option->attribs  = KObjectConfig::unbox($config->attribs);

        if($config->level) {
            $option->attribs['class'] = array('level'.$config->level);
        }

        if($config->disabled) {
            $option->attribs['class'] = array('k-is-disabled', 'disabled');
        }

        return $option;
    }
127467
protected function _initialize(KObjectConfig $config)
    {
        $config->append(array(
            'priority' => self::PRIORITY_LOW,
            'title'    => '',
            'class'    => '',
            'styles'   => array(),
            'attribs'  => array(
                'name'  => $this->getIdentifier()->package . '_' . $this->getIdentifier()->name,
                'first' => null,
                'last'  => null,
            )
        ));

        parent::_initialize($config);
    }
1051307
protected function _initialize(KObjectConfig $config)
    {
        $config->append(array(
            'debug'        => false,
            'cache'        => false,
            'cache_path'   => '',
            'cache_reload' => true,
            'template'     => 'default',
            'functions'    => array(
                'object'    => array($this, 'getObject'),
                'translate' => array($this->getObject('translator'), 'translate'),
                'json'      => 'json_encode',
                'format'    => 'sprintf',
                'replace'   => 'strtr',
            ),
        ));

        parent::_initialize($config);
    }
706026
protected function addFromConfig(array $config)
	{
		$bbcodeName = $config['bbcodeName'];
		$bbcode     = $config['bbcode'];
		$tag        = $config['tag'];

		// If the BBCode doesn't specify a tag name, it's the same as the BBCode
		if (!isset($bbcode->tagName))
		{
			$bbcode->tagName = $bbcodeName;
		}

		// Normalize this tag's templates
		$this->configurator->templateNormalizer->normalizeTag($tag);

		// Test whether this BBCode/tag is safe before adding it
		$this->configurator->templateChecker->checkTag($tag);

		// Add our BBCode then its tag
		$this->collection->add($bbcodeName, $bbcode);
		$this->configurator->tags->add($bbcode->tagName, $tag);

		return $bbcode;
	}
1255526
public function render($config = array())
    {
        // Load the language strings for toolbar button labels
        JFactory::getLanguage()->load('joomla', JPATH_ADMINISTRATOR);

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

        return $html;
    }
798829
public function radio($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'entity'  => null,
            'attribs' => array()
        ));

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

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

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

        return $html;
    }
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;
    }
435367
protected function _initialize(KObjectConfig $config)
    {
        $path       = rtrim($this->getObject('request')->getSiteUrl()->getPath(), '/');
        $nooku_path = $path.'/media/koowa/framework';
        $schemes    = array(
            'assets://js'  => $nooku_path.'/js',
            'assets://css' => $nooku_path.'/css',
            'assets://img' => $nooku_path.'/img',
            'assets://koowa' => $path.'/media/koowa/com_koowa',
            'media://'     => $path.'/media/',
            'root://'      => $path.'/',
            'base://'      => rtrim($this->getObject('request')->getBaseUrl()->getPath(), '/').'/'
        );

        if (empty(static::$_component_assets))
        {
            $components = $this->getObject('object.bootstrapper')->getComponents();

            foreach($components as $component)
            {
                $identifier = $this->getIdentifier($component);

                // Only register reusable components such as files and koowa
                if ($identifier->domain === 'koowa')
                {
                    $key         = 'assets://'.$identifier->package;
                    $destination = $path.'/media/koowa/com_'.$identifier->package;

                    static::$_component_assets[$key] = $destination;
                }
            }
        }

        $schemes = array_merge($schemes, static::$_component_assets);

        // Override default scheme with the media/ folder
        $schemes['assets://'] = $path.'/media/';

        $config->append(array(
            'schemes' => $schemes,
        ));

        parent::_initialize($config);
    }
74793
protected function _initialize(KObjectConfig $config)
    {
        if(!defined('JOOMLATOOLS_PLATFORM'))
        {
            $query = $this->getObject('lib:database.query.select')
                ->table('template_styles')
                ->columns('template')
                ->where('client_id = :client_id AND home = :home')
                ->bind(array(
                    'client_id' => JFactory::getApplication()->getClientId(), 'home' => 1
                ));

            $template = $this->getObject('lib:database.adapter.mysqli')->select($query, KDatabase::FETCH_FIELD);
        }
        else $template = JFactory::getApplication()->getTemplate();

        $config->append([
            'override_paths' => [
                JPATH_THEMES.'/'.$template.'/html',
                JPATH_THEMES.'/system/html'         // #117: For backwards compatibility purposes
            ]
        ]);

        parent::_initialize($config);
    }
384393
public function modal($config = array())
    {
        $config = new ObjectConfigJson($config);
        $config->append(array(
            'debug'    => \Kodekit::getInstance()->isDebug(),
            'selector' => '[data-k-modal]',
            'data'     => 'k-modal',
            'options_callback' => null,
            'options'  => array('type' => 'image')
        ));

        $html = '';

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

            static::setLoaded('modal');
        }

        if(!static::isLoaded('modal-select2-fix'))
        {
            $html .= "<script>

                // WORKAROUND FOR ISSUE: #873

                kQuery(function($)
                {
                    $.magnificPopup.instance._onFocusIn = function(e)
                    {
                        // Do nothing if target element is select2 input
                        if( $(e.target).hasClass('select2-search__field') ) {
                            return true;
                        }
            
                        // Else call parent method
                        $.magnificPopup.proto._onFocusIn.call(this,e);
                    };
                });
            </script>";

            static::setLoaded('modal-select2-fix');
        }

        $options   = (string)$config->options;
        $signature = md5('modal-'.$config->selector.$config->options_callback.$options);

        if (!static::isLoaded($signature))
        {
            if ($config->options_callback) {
                $options = $config->options_callback.'('.$options.')';
            }

            $html .= "<script>
            kQuery(function($){
                $('$config->selector').each(function(idx, el) {
                    var el = $(el);
                    var data = el.data('$config->data');
                    var options = ".$options.";
                    if (data) {
                        $.extend(true, options, data);
                    }
                    el.magnificPopup(options);
                });
            });
            </script>";

            static::setLoaded($signature);
        }

        return $html;
    }
403398
protected function buildCssWithLess(array $config)
    {
        $bootstrapFile = $config['assets_dir'].'/less/bootstrap.less';
        if (true === isset($config['customize']['variables_file']) &&
            null !== $config['customize']['variables_file']) {
            $bootstrapFile = $config['customize']['bootstrap_output'];
        }

        $inputs = array(
            $bootstrapFile,
            __DIR__.'/../Resources/less/form.less'
        );
        if ('fa' === $config['icon_prefix']) {
            $inputs[] = $config['fontawesome_dir'].'/less/font-awesome.less';
        }

        return array(
            'inputs'  => $inputs,
            'filters' => array($config['css_preprocessor']),
            'output'  => $config['output_dir'].'css/bootstrap.css'
        );
    }