/** * @dataProvider disposition_provider */ public function test_parse_disposition($header, $expected) { $header_list = array($header); $parsed = WP_REST_Attachments_Controller::get_filename_from_disposition($header_list); $this->assertEquals($expected, $parsed); }
public static function bb_gallery_shortcode($attr, $content = '') { if (is_feed() || is_array($attr) && !empty($attr['mode']) && $attr['mode'] === 'wordpress') { # invoke the standard WordPress gallery shortcode function unset($attr['mode']); return gallery_shortcode($attr); } if (is_array($attr) && !empty($attr['mode']) && $attr['mode'] === 'get_first') { # in this mode only the first image is returned for use as a representative image for a gallery unset($attr['mode']); $get_first = TRUE; ob_start(); #TODO: set underlying SQL LIMIT to 1 } foreach (['thumbnail', 'medium', 'medium_large', 'large', 'full'] as $size) { $label = "{$size}_width"; $width = intval(get_option("{$size}_size_w")); if (!$width && $size === 'medium_large') { $width = 768; } $width = intval(1.125 * $width); if ($size === 'thumbnail') { ${$label} = $width; } else { ${$label} = $prev_width + 1; } $prev_width = $width; } ob_start(); require_once dirname(__FILE__) . '/bbg_xiv-gallery_templates_wp_rest.php'; $templates = ob_get_clean(); $post = get_post(); static $instance = 10000; # not 0 to create a different space from the WordPress "gallery" shortcode $instance++; static $bbg_xiv_data = ['version' => '1.0']; $bbg_xiv_data['ajaxurl'] = admin_url('admin-ajax.php'); $bbg_xiv_data['bbg_xiv_flex_min_width'] = get_option('bbg_xiv_flex_min_width', 128); $bbg_xiv_data['bbg_xiv_flex_min_width_for_caption'] = get_option('bbg_xiv_flex_min_width_for_caption', 96); $bbg_xiv_data['bbg_xiv_max_search_results'] = get_option('bbg_xiv_max_search_results', 250); $bbg_xiv_data['bbg_xiv_flex_min_width_for_dense_view'] = get_option('bbg_xiv_flex_min_width_for_dense_view', 1280); $bbg_xiv_data['bbg_xiv_flex_number_of_dense_view_columns'] = get_option('bbg_xiv_flex_number_of_dense_view_columns', 10); $bbg_xiv_data['bbg_xiv_carousel_interval'] = get_option('bbg_xiv_carousel_interval', 2500); $bbg_xiv_data['bbg_xiv_disable_flexbox'] = get_option('bbg_xiv_disable_flexbox', FALSE); $bbg_xiv_data['bbg_xiv_default_view'] = get_option('bbg_xiv_default_view', 'Gallery'); $bbg_xiv_data['bbg_xiv_wp_rest_api'] = self::$wp_rest_api_available && self::$use_wp_rest_api_if_available; # translations for JavaScript side $bbg_xiv_lang['Nothing Found'] = __('Nothing Found', 'bb_gallery'); $bbg_xiv_lang['Search Results for'] = __('Search Results for', 'bb_gallery'); $bbg_xiv_lang['Page'] = __('Page', 'bb_gallery'); $bbg_xiv_lang['of'] = __('of', 'bb_gallery'); $bbg_xiv_lang['Images'] = __('Images', 'bb_gallery'); $bbg_xiv_lang['to'] = __('to', 'bb_gallery'); $bbg_xiv_lang['galleryOfGalleriesTitle'] = __('Each image below represents a gallery. Please click on an image to load its gallery.', 'bb_gallery'); $default_flags = []; switch (get_option('bbg_xiv_use_tiles', 'Cover')) { case 'Cover': $default_flags[] = 'tiles'; break; case 'Contain': $default_flags[] = 'tiles'; $default_flags[] = 'contain'; break; case 'Fill': $default_flags[] = 'tiles'; $default_flags[] = 'fill'; break; } if (get_option('bbg_xiv_use_embedded_carousel', TRUE)) { $default_flags[] = 'embedded-carousel'; } if (is_array($attr)) { if (!empty($attr['mode']) && $attr['mode'] === "galleries") { # this is a proprietary mode to display altgallery entries as a gallery of representative images $gallery_icons_mode = TRUE; } if (!empty($attr['view'])) { # this sets the initial view of a gallery - gallery, carousel or tabs $default_view = $attr['view']; } if (!empty($attr['flags'])) { # flag to set embedded carousel mode $flags = $attr['flags']; } } # merge the default flags and the flags from the shortcode if (empty($flags)) { $flags = $default_flags; } else { $flags = explode(',', $flags); $flags = array_merge($default_flags, $flags); $flags = array_unique($flags); } # handle cancel flags foreach (['embedded-carousel', 'tiles', 'contain', 'fill'] as $flag) { if (($i = array_search('no-' . $flag, $flags)) !== FALSE) { unset($flags[$i]); if (($j = array_search($flag, $flags)) !== FALSE) { unset($flags[$j]); } } } $flags = implode(',', $flags); $galleries = []; if ($content) { # Unfortunately (and also I think incorrectly) the 'the_content' filter wptexturize() from formatting.php will process the parameters of shortcodes # prettifying the quote marks. So, we need to undo this mutilation and restore the original content. # Opinion: WordPress seems to love regex but regex is simply inadequate for parsing HTML! $content = preg_replace('/‘|’|“|”|′|″/', '"', $content); if (preg_match_all('#\\[altgallery\\s+title="([^"]+)"\\s+([^\\]]+)\\]#m', $content, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $gallery = $galleries[] = (object) ['title' => $match[1], 'specifiers' => $match[2]]; if (!empty($gallery_icons_mode)) { $gallery->specifiers = preg_replace_callback(['/(^|\\s+)(image)="(\\d+)"/', '/(^|\\s+)(caption)="([^"]*)"/'], function ($matches) use($gallery) { $gallery->{$matches}[2] = $matches[3]; return ''; }, $gallery->specifiers); if (empty($gallery->image)) { # no image specified so use the first image of the gallery $gallery_attr = ['mode' => 'get_first']; preg_replace_callback('/(\\w+)=("|\')(.*?)\\2/', function ($matches) use(&$gallery_attr) { $gallery_attr[$matches[1]] = $matches[3]; }, $gallery->specifiers); $attachment = self::bb_gallery_shortcode($gallery_attr); $gallery->image = self::$wp_rest_api_available && self::$use_wp_rest_api_if_available ? $attachment['id'] : $attachment->ID; } if (empty($gallery->caption)) { $gallery->caption = $gallery->title; } } } } if (!empty($gallery_icons_mode)) { // construct a 'ids' parameter with ids of gallery icons $attr['ids'] = implode(',', array_map(function ($gallery) { return $gallery->image; }, $galleries)); } } if (!empty($attr['ids'])) { // 'ids' is explicitly ordered, unless you specify otherwise. if (empty($attr['orderby'])) { $attr['orderby'] = 'post__in'; } $attr['include'] = $attr['ids']; } /** * Filter the default gallery shortcode output. * * If the filtered output isn't empty, it will be used instead of generating * the default gallery template. * * @since 2.5.0 * @since 4.2.0 The `$instance` parameter was added. * * @see gallery_shortcode() * * @param string $output The gallery output. Default empty. * @param array $attr Attributes of the gallery shortcode. * @param int $instance Unique numeric ID of this gallery shortcode instance. */ $output = apply_filters('post_gallery', '', $attr, $instance); if ($output != '') { return $output; } $atts = shortcode_atts(array('order' => 'ASC', 'orderby' => 'menu_order', 'id' => $post ? $post->ID : 0, 'size' => 'thumbnail', 'include' => '', 'exclude' => '', 'link' => '', 'bb_tags' => ''), $attr, 'gallery'); $id = intval($atts['id']); $selector = "gallery-{$instance}"; if (self::$wp_rest_api_available && self::$use_wp_rest_api_if_available) { # map gallery shortcode parameters to WP REST API parameters $orderby_map = ['menu_order' => 'menu_order', 'title' => 'title', 'post_date' => 'date', 'rand' => 'rand', 'ID' => 'id', 'post__in' => 'include']; $order_map = ['ASC' => 'asc', 'DESC' => 'desc']; # Initialize the Backbone.js collection using data from the WP REST API for the WP REST API model $attributes = ['author' => [], 'author_exclude' => [], 'menu_order' => '', 'offset' => '', 'order' => $order_map[$atts['order']], 'orderby' => $orderby_map[$atts['orderby']], 'page' => 1, 'include' => [], 'exclude' => [], 'per_page' => 10, 'slug' => '', 'parent' => '', 'parent_exclude' => '', 'status' => 'publish', 'search' => '']; if (!empty($atts['bb_tags'])) { // Translate the terms of the proprietary 'bb_tags' attribute to ids $bb_tags = array_map('trim', explode(',', $atts['bb_tags'])); $attributes['bb-tags'] = get_terms(['taxonomy' => 'bb_tags', 'slug' => $bb_tags, 'name' => $bb_tags, 'fields' => 'ids']); } else { if (!empty($atts['include'])) { $attributes['include'] = explode(',', $atts['include']); $attributes['per_page'] = count($attributes['include']); } elseif (!empty($atts['exclude'])) { $attributes['parent'] = [$id]; $attributes['exclude'] = explode(',', $atts['exclude']); $attributes['per_page'] = 1024; } else { $attributes['parent'] = [$id]; $attributes['per_page'] = 1024; } } if (!empty($get_first)) { $attributes['per_page'] = 1; } $request = new WP_REST_Request('GET', '/wp/v2/media'); $request->set_query_params($attributes); # TODO: $request may need to set some of the params below #$request->set_body_params( wp_unslash( $_POST ) ); #$request->set_file_params( $_FILES ); #$request->set_headers( $this->get_headers( wp_unslash( $_SERVER ) ) ); #$request->set_body( $this->get_raw_data() ); #$request->set_url_params( $args ); #$request->set_attributes( $handler ); #$request->set_default_params( $defaults ); self::add_additional_rest_fields(); $controller = new WP_REST_Attachments_Controller("attachment"); $attachments = $controller->get_items($request)->data; if (!empty($get_first)) { ob_end_clean(); return reset($attachments); } if (!empty($gallery_icons_mode)) { # replace title and caption for image with title and caption for gallery and also remember the gallery index foreach ($galleries as $i => $gallery) { if (empty($attachments[$i])) { # this is an error probably caused by a duplicate image id continue; } $attachment =& $attachments[$i]; if ((int) $gallery->image === (int) $attachment['id']) { # if this is not true then there probably is a duplicate image id $attachment['gallery_index'] = $i; $attachment['title']['rendered'] = $gallery->title; $attachment['caption'] = $gallery->caption; $attachment['description'] = ''; } } } $bbg_xiv_data["{$selector}-data"] = json_encode($attachments); } else { // initialize the Backbone.js collection using data for my proprietary model // Handle the proprietary 'bb_tags' attribute - this specifies a gallery by a taxonomy expression if (!empty($atts['bb_tags'])) { $bb_tags = explode(',', $atts['bb_tags']); $tax_query = array(); // search by both slug and name $tax_query['relation'] = 'OR'; $tax_query[] = array('taxonomy' => 'bb_tags', 'field' => 'slug', 'terms' => $bb_tags); $tax_query[] = array('taxonomy' => 'bb_tags', 'field' => 'name', 'terms' => $bb_tags); $_attachments = get_posts(array('post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'], 'tax_query' => $tax_query, 'posts_per_page' => empty($get_first) ? -1 : 1, 'offset' => 0)); $attachments = array(); foreach ($_attachments as $key => $val) { $attachments[$val->ID] = $_attachments[$key]; } } elseif (!empty($atts['include'])) { $_attachments = get_posts(array('include' => empty($get_first) ? $atts['include'] : (string) explode(',', $atts['include'])[0], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'])); $attachments = array(); foreach ($_attachments as $key => $val) { $attachments[$val->ID] = $_attachments[$key]; } } elseif (!empty($atts['exclude'])) { $attachments = get_children(array('post_parent' => $id, 'exclude' => $atts['exclude'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'], 'numberposts' => empty($get_first) ? -1 : 1)); } else { $attachments = get_children(array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'], 'numberposts' => empty($get_first) ? -1 : 1)); } if (!empty($get_first)) { ob_end_clean(); return reset($attachments); } #if ( empty( $attachments ) ) { # return ''; #} self::bbg_xiv_do_attachments($attachments); if (!empty($gallery_icons_mode)) { # replace title and caption for image with title and caption for gallery and also remember the gallery index foreach ($galleries as $i => $gallery) { $attachment = $attachments[$gallery->image]; $attachment->gallery_index = $i; $attachment->post_title = $gallery->title; $attachment->post_excerpt = $gallery->caption; $attachment->post_content = ''; } } $bbg_xiv_data["{$selector}-data"] = json_encode(array_values($attachments)); } wp_localize_script('bbg_xiv-gallery', 'bbg_xiv', $bbg_xiv_data); wp_localize_script('bbg_xiv-gallery', 'bbg_xiv_lang', $bbg_xiv_lang); $float = is_rtl() ? 'right' : 'left'; $size_class = sanitize_html_class($atts['size']); # The "Table View" is primarily intended for developers and should be disabled for production environmemts. $table_nav_item = ''; if (get_option('bbg_xiv_table')) { $table_nav_item = <<<EOD <li><a href="#">Table</a></li> EOD; } $translations = ['GALLERY MENU' => __('GALLERY MENU', 'bb_gallery'), 'IMAGES:' => __('IMAGES:', 'bb_gallery'), 'GALLERIES:' => __('GALLERIES:', 'bb_gallery'), 'View' => __('View', 'bb_gallery'), 'Gallery' => __('Gallery', 'bb_gallery'), 'Carousel' => __('Carousel', 'bb_gallery'), 'Justified' => __('Justified', 'bb_gallery'), 'Tabs' => __('Tabs', 'bb_gallery'), 'Dense' => __('Dense', 'bb_gallery'), 'VIEWS' => __('VIEWS', 'bb_gallery'), 'GALLERIES' => __('GALLERIES', 'bb_gallery'), 'Home' => __('Home', 'bb_gallery'), 'Titles' => __('Titles', 'bb_gallery'), 'Search Images on Site' => __('Search Images on Site', 'bb_gallery'), 'Options' => __('Options', 'bb_gallery'), 'Help' => __('Help', 'bb_gallery'), 'get help' => __('get help', 'bb_gallery'), 'configure bandwidth, carousel interval, ...' => __('configure bandwidth, carousel interval, ...', 'bb_gallery'), 'return to home gallery' => __('return to home gallery', 'bb_gallery'), 'show/hide image titles' => __('show/hide image titles', 'bb_gallery'), 'Carousel Time Interval in ms' => __('Carousel Time Interval in ms', 'bb_gallery'), 'Minimum Width for Gallery Images in px' => __('Minimum Width for Gallery Images in px', 'bb_gallery'), 'Maximum Number of Images Returned by Search' => __('Maximum Number of Images Returned by Search', 'bb_gallery'), 'Number of Columns in the Dense View' => __('Number of Columns in the Dense View', 'bb_gallery'), 'Bandwidth' => __('Bandwidth', 'bb_gallery'), 'Auto' => __('Auto', 'bb_gallery'), 'High' => __('High', 'bb_gallery'), 'Medium' => __('Medium', 'bb_gallery'), 'Low' => __('Low', 'bb_gallery'), 'Interface' => __('Interface', 'bb_gallery'), 'Mouse' => __('Mouse', 'bb_gallery'), 'Touch' => __('Touch', 'bb_gallery'), 'Save' => __('Save', 'bb_gallery'), 'Cancel' => __('Cancel', 'bb_gallery'), 'Help' => __('Help', 'bb_gallery')]; if (!$galleries) { for ($i = 1; $i <= self::$gallery_menu_items_count; $i++) { $option = get_option("bbg_xiv_gallery_menu_{$i}", ''); if (preg_match('/^"([^"]+)":(.+)$/', $option, $matches) === 1) { $galleries[] = (object) ['title' => $matches[1], 'specifiers' => $matches[2]]; } } } ob_start(); wp_nonce_field(self::$nonce_action); $nonce_field = ob_get_clean(); $output = $templates; $output .= <<<EOD <div class="bbg_xiv-bootstrap bbg_xiv-gallery"> <nav role="navigation" class="navbar navbar-inverse bbg_xiv-gallery_navbar"> <div class="navbar-header"> <button type="button" data-target="#{$selector}-navbarCollapse" data-toggle="collapse" class="navbar-toggle"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="#" class="navbar-brand bbg_xiv-images_brand">{$translations['GALLERY MENU']}</a> </div> <div id="{$selector}-navbarCollapse" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li class="dropdown bbg_xiv-select_view"> <a data-toggle="dropdown" class="dropdown-toggle bbg_xiv-selected_view" href="#"><span>{$translations['View']}</span> <b class="caret"></b></a> <ul role="menu" class="dropdown-menu bbg_xiv-view_menu"> <li class="dropdown-header">{$translations['VIEWS']}</li> <li class="bbg_xiv-view bbg_xiv-view_gallery active"><a data-view="Gallery" href="#">{$translations['Gallery']}</a></li> <li class="bbg_xiv-view bbg_xiv-view_carousel bbg_xiv-hide_for_gallery_icons"><a data-view="Carousel" href="#">{$translations['Carousel']}</a></li> <li class="bbg_xiv-view bbg_xiv-view_justified bbg_xiv-hide_for_gallery_icons"><a data-view="Justified" href="#">{$translations['Justified']}</a></li> <li class="bbg_xiv-view bbg_xiv-view_tabs"><a data-view="Tabs" href="#">{$translations['Tabs']}</a></li> <li class="bbg_xiv-view bbg_xiv-hide_for_gallery_icons bbg_xiv-large_viewport_only"><a data-view="Dense" href="#">{$translations['Dense']}</a></li> <!-- TODO: Add entry for new views here. --> {$table_nav_item} EOD; if ($galleries) { # output menu items for dynamically loaded galleries $output .= <<<EOD <li class="divider"></li> <li class="dropdown-header">{$translations['GALLERIES']}</li> <li class="bbg_xiv-alt_gallery bbg_xiv-alt_gallery_home active"><a data-view="gallery_home" data-specifiers='' href="#">{$translations['Home']}</a></li> EOD; foreach ($galleries as $i => $gallery) { $output .= <<<EOD <li class="bbg_xiv-alt_gallery"><a data-view="gallery_{$i}" data-specifiers='{$gallery->specifiers}' href="#">{$gallery->title}</a></li> EOD; } } $output .= <<<EOD </ul> </li> </ul> <form role="search" class="navbar-form navbar-left bbg_xiv-search_form"> <div class="form-group"> <input type="text" placeholder="{$translations['Search Images on Site']}" class="form-control"> </div> <button type="submit" class="btn btn-default bbg_xiv-search" title="start search"><span class="glyphicon glyphicon-search"></span></button> {$nonce_field} </form> <button type="button" class="btn btn-info bbg_xiv-help" title="{$translations['get help']}"> <span class="glyphicon glyphicon-question-sign"></span> <span class="bbg_xiv-navbar_button_text">{$translations['Help']}</span> </button> <button type="button" class="btn btn-info bbg_xiv-configure" title="{$translations['configure bandwidth, carousel interval, ...']}"> <span class="glyphicon glyphicon-cog"></span> <span class="bbg_xiv-navbar_button_text">{$translations['Options']}</span> </button> <button type="button" class="btn btn-info bbg_xiv-home" title="{$translations['return to home gallery']}"> <span class="glyphicon glyphicon-home"></span> <span class="bbg_xiv-navbar_button_text">{$translations['Home']}</span> </button> <button type="button" class="btn btn-info bbg_xiv-titles" title="{$translations['show/hide image titles']}"> <span class="glyphicon glyphicon-subtitles"></span> <span class="bbg_xiv-navbar_button_text">{$translations['Titles']}</span> </button> </div> </nav> EOD; # Optionally show titles of dynamically loadable galleries as tab items if ($galleries && empty($gallery_icons_mode) && get_option('bbg_xiv_use_gallery_tabs', TRUE)) { $output .= <<<EOD <!-- Gallery Tabs --> <div class="bbg_xiv-container bbg_xiv-gallery_tabs_container"> <nav role="navigation" class="navbar navbar-default"> <div class="navbar-header"> <button type="button" data-target="#gallery_tabbar_collapse" data-toggle="collapse" class="navbar-toggle"> <span class="sr-only">Toggle galleries</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="#" class="navbar-brand bbg_xiv-tabs_brand">{$translations['GALLERIES:']}</a> </div> <div id="gallery_tabbar_collapse" class="collapse navbar-collapse bbg_xiv-closed"> <ul class="nav nav-tabs"> <li class="bbg_xiv-tabs_title"><a href="#">{$translations['GALLERIES:']}</a></li> <li class="active"><a data-view="gallery_home" data-specifiers='' href="#">{$translations['Home']}</a></li> EOD; foreach ($galleries as $i => $gallery) { $output .= <<<EOD <li><a data-view="gallery_{$i}" data-specifiers='{$gallery->specifiers}' href="#">{$gallery->title}</a></li> EOD; } $output .= <<<EOD </ul> </div> <span class="glyphicon glyphicon-collapse-down"></span> </nav> </div> EOD; } $class_gallery_icons_mode = empty($gallery_icons_mode) ? '' : ' bbg_xiv-gallery_icons_mode'; $class_default_view = empty($default_view) ? '' : ' bbg_xiv-default_view_' . $default_view; $flags = empty($flags) ? '' : $flags; $output .= <<<EOD <!-- Search or Gallery Headings --> <div id="{$selector}-heading" class="bbg_xiv-search_header"> <span class="bbg_xiv-search_heading_first"></span><br> <button class="btn btn-primary btn-sm bbg_xiv-search_scroll_left" disabled><span class="glyphicon glyphicon-chevron-left"></span></button> <span class="bbg_xiv-search_heading_second"></span> <button class="btn btn-primary btn-sm bbg_xiv-search_scroll_right"><span class="glyphicon glyphicon-chevron-right"></span></button> </div> <div id="{$selector}-alt_gallery_heading" class="bbg_xiv-alt_gallery_header"> <span class="bbg_xiv-alt_gallery_heading"></span> </div> <div id="{$selector}" class="gallery galleryid-{$id} gallery-size-{$size_class} bbg_xiv-gallery_envelope{$class_gallery_icons_mode}{$class_default_view}" data-flags="{$flags}"> <div class="ui-loader"><span class="ui-icon-loading"></span></div> </div> <div class="bbg_xiv-configure_outer"> </div> <div class="bbg_xiv-configure_inner"> <button class="bbg_xiv-configure_close"><span class="glyphicon glyphicon-remove"></span></button> <h1>BB Gallery Options</h1> <form class="form-horizontal"> <div class="form-group"> <label for="bbg_xiv-carousel_delay" class="control-label col-sm-9 col-md-offset-2 col-md-6">{$translations['Carousel Time Interval in ms']}</label> <div class="col-sm-3 col-md-2"> <input type="number" class="form-control" id="bbg_xiv-carousel_delay" min="1000" step="100"> </div> </div> <div class="form-group"> <label for="bbg_xiv-min_image_width" class="control-label col-sm-9 col-md-offset-2 col-md-6">{$translations['Minimum Width for Gallery Images in px']}</label> <div class="col-sm-3 col-md-2"> <input type="number" class="form-control" id="bbg_xiv-min_image_width" min="32" max="1024"> </div> </div> <div class="form-group"> <label for="bbg_xiv-max_search_results" class="control-label col-sm-9 col-md-offset-2 col-md-6">{$translations['Maximum Number of Images Returned by Search']}</label> <div class="col-sm-3 col-md-2"> <input type="number" class="form-control" id="bbg_xiv-max_search_results" min="1" max="{$bbg_xiv_data['bbg_xiv_max_search_results']}"> </div> </div> <div class="form-group bbg_xiv-mouse_only_option"> <label for="bbg_xiv-columns_in_dense_view" class="control-label col-sm-9 col-md-offset-2 col-md-6">{$translations['Number of Columns in the Dense View']}</label> <div class="col-sm-3 col-md-2"> <input type="number" class="form-control" id="bbg_xiv-columns_in_dense_view" min="2" max="32"> </div> </div> <div class="form-group"> <label for="bbg_xiv-bandwidth" class="control-label col-sm-3 col-md-offset-2 col-md-2">{$translations['Bandwidth']}</label> <div class="col-sm-9 col-md-6"> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-bandwidth" value="auto" id="bbg_xiv-bandwidth_auto" checked> <span class="bbg_xiv-radio_text">{$translations['Auto']}</span> </span> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-bandwidth" value="normal" id="bbg_xiv-bandwidth_normal"> <span class="bbg_xiv-radio_text">{$translations['High']}</span> </span> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-bandwidth" value="low" id="bbg_xiv-bandwidth_low"> <span class="bbg_xiv-radio_text">{$translations['Medium']}</span> </span> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-bandwidth" value="very low" id="bbg_xiv-bandwidth_very_low"> <span class="bbg_xiv-radio_text">{$translations['Low']}</span> </span> </div> </div> <div class="form-group"> <label for="bbg_xiv-interface" class="control-label col-sm-3 col-md-offset-2 col-md-2">{$translations['Interface']}</label> <div class="col-sm-9 col-md-6"> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-interface" value="auto" id="bbg_xiv-interface_auto" checked> <span class="bbg_xiv-radio_text">{$translations['Auto']}</span> </span> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-interface" value="mouse" id="bbg_xiv-interface_mouse"> <span class="bbg_xiv-radio_text">{$translations['Mouse']}</span> </span> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-interface" value="touch" id="bbg_xiv-interface_touch"> <span class="bbg_xiv-radio_text">{$translations['Touch']}</span> </span> <span class="bbg_xiv-radio_input"> <input type="radio" class="form-control" name="bbg_xiv-interface" value="null" id="bbg_xiv-interface_null" disabled> <span class="bbg_xiv-radio_text"></span> </span> </div> </div> <br> <div class="form-group"> <div class="col-sm-offset-4 col-sm-8"> <button type="button" class="btn btn-primary bbg_xiv-options_btn bbg_xiv-save_options">{$translations['Save']}</button> <button type="button" class="btn btn-default bbg_xiv-options_btn bbg_xiv-cancel_options">{$translations['Cancel']}</button> <button type="button" class="btn btn-info bbg_xiv-options_btn bbg_xiv-help_options">{$translations['Help']}</button> </div> </div> </form> </div> </div> EOD; return $output; }