From 0de1d7fb4b77215db124527fc7940c84e74954f0 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 19 May 2016 23:18:32 +0200 Subject: [PATCH] Overhauled search area --- com.woltlab.wcf/coreObject.xml | 3 + .../templates/pageHeaderSearch.tpl | 53 +++++++---- .../install/files/js/WCF.Search.Message.js | 93 ------------------- .../install/files/js/WoltLab/WCF/Ui/Mobile.js | 45 +-------- .../js/WoltLab/WCF/Ui/Page/Header/Fixed.js | 30 +++++- .../files/js/WoltLab/WCF/Ui/Search/Input.js | 7 +- .../files/js/WoltLab/WCF/Ui/Search/Page.js | 31 +++++++ wcfsetup/install/files/style/layout/form.scss | 2 + .../files/style/layout/pageHeader.scss | 75 ++++++--------- .../files/style/layout/pageHeaderSticky.scss | 9 +- wcfsetup/install/files/style/ui/dropdown.scss | 5 + wcfsetup/install/lang/de.xml | 1 + wcfsetup/install/lang/en.xml | 1 + 13 files changed, 140 insertions(+), 215 deletions(-) create mode 100644 wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Page.js diff --git a/com.woltlab.wcf/coreObject.xml b/com.woltlab.wcf/coreObject.xml index d17f941e8b..997f4d7435 100644 --- a/com.woltlab.wcf/coreObject.xml +++ b/com.woltlab.wcf/coreObject.xml @@ -62,5 +62,8 @@ + + + diff --git a/com.woltlab.wcf/templates/pageHeaderSearch.tpl b/com.woltlab.wcf/templates/pageHeaderSearch.tpl index 8b466883e2..07403e5e07 100644 --- a/com.woltlab.wcf/templates/pageHeaderSearch.tpl +++ b/com.woltlab.wcf/templates/pageHeaderSearch.tpl @@ -1,43 +1,58 @@ {capture assign='__searchFormLink'}{link controller='Search'}{/link}{/capture} -{capture assign='__searchInputPlaceholder'}{lang}wcf.global.search.enterSearchTerm{/lang}{/capture} -{capture assign='__searchDropdownOptions'}{/capture} -{assign var='__searchHiddenInputFields' value=''} {event name='settings'}
- + + - + + {if !$searchObjectTypeName|empty}{/if} + + {@SECURITY_TOKEN_INPUT_TAG}
- {@$__searchHiddenInputFields} + {if !$searchObjectTypeName|empty}{/if} + {@SECURITY_TOKEN_INPUT_TAG} {if !OFFLINE || $__wcf->session->getPermission('admin.general.canViewPageDuringOfflineMode')} {/if} \ No newline at end of file diff --git a/wcfsetup/install/files/js/WCF.Search.Message.js b/wcfsetup/install/files/js/WCF.Search.Message.js index 2dcc011e01..5ba9834583 100644 --- a/wcfsetup/install/files/js/WCF.Search.Message.js +++ b/wcfsetup/install/files/js/WCF.Search.Message.js @@ -94,96 +94,3 @@ WCF.Search.Message.KeywordList = WCF.Search.Base.extend({ this._itemIndex = -1; } }); - -/** - * Handles the search area box. - * - * @param jQuery searchArea - */ -WCF.Search.Message.SearchArea = Class.extend({ - /** - * search area object - * @var jQuery - */ - _searchArea: null, - - /** - * Initializes the WCF.Search.Message.SearchArea class. - * - * @param jQuery searchArea - */ - init: function(searchArea) { - this._searchArea = searchArea; - - var $keywordList = new WCF.Search.Message.KeywordList(this._searchArea.find('input[type=search]'), $.proxy(this._callback, this)); - $keywordList.setDelay(500); - - // forward clicks on the search icon to input field - var self = this; - var $input = this._searchArea.find('input[type=search]'); - this._searchArea.click(function(event) { - // only forward clicks if the search element itself is the target - if (event.target == self._searchArea[0]) { - $input.focus().trigger('click'); - return false; - } - }); - - if (this._searchArea.hasClass('dropdown')) { - var $containerID = this._searchArea.wcfIdentify(); - var $dropdownMenu = WCF.Dropdown.getDropdownMenu($containerID); - var $form = this._searchArea.find('form'); - if ($form.length === 0) $form = this._searchArea.parent(); - - $form.submit(function() { - // copy checkboxes and hidden fields into form - $dropdownMenu.find('input[type=hidden]').appendTo($form); - $dropdownMenu.find('input[type=checkbox]:checked').each(function(index, input) { - var $input = $(input); - - $('').appendTo($form); - }); - }); - - var $enableFlexWidth = true; - require(['Ui/Screen'], function(UiScreen) { - UiScreen.on('screen-md-down', { - match: function() { $enableFlexWidth = false; }, - unmatch: function() { $enableFlexWidth = true; }, - setup: function() { $enableFlexWidth = false; } - }) - }); - - $dropdownMenu.addClass('pageHeaderSearchDropdown'); - WCF.Dropdown.registerCallback($containerID, (function(containerID, action) { - if ($enableFlexWidth && action === 'open' && elById('pageHeader').classList.contains('sticky')) { - var width = elById('pageHeaderSearch').clientWidth + elById('topMenu').clientWidth; - if (width < 200) width = 200; - - this._searchArea.css('width', width + 'px'); - $dropdownMenu.css('width', width + 'px'); - } - else { - this._searchArea.css('width', ''); - $dropdownMenu.css('width', ''); - } - }).bind(this)); - - $(window).scroll((function () { - this._searchArea.css('width', ''); - }).bind(this)); - } - }, - - /** - * Callback for WCF.Search.Message.KeywordList. - * - * @param object data - * @return boolean - */ - _callback: function(data) { - this._searchArea.find('input[type=search]').val(data.label); - this._searchArea.find('form').submit(); - return false; - } -}); \ No newline at end of file diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Mobile.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Mobile.js index 8a167d54be..6594e0298e 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Mobile.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Mobile.js @@ -18,7 +18,6 @@ define( var _options = {}; var _pageMenuMain = null; var _pageMenuUser = null; - var _sidebar = null; /** * @exports WoltLab/WCF/Ui/Mobile @@ -36,7 +35,6 @@ define( _buttonGroupNavigations = elByClass('buttonGroupNavigation'); _main = elById('main'); - _sidebar = elBySel('#main > div > div > .sidebar', _main); if (Environment.touch()) { document.documentElement.classList.add('touch'); @@ -78,8 +76,7 @@ define( }, _init: function() { - //this._initSidebarToggleButtons(); - //this._initSearchBar(); + this._initSearchBar(); this._initButtonGroupNavigation(); this._initMobileMenu(); @@ -87,46 +84,6 @@ define( DomChangeListener.add('WoltLab/WCF/Ui/Mobile', this._initButtonGroupNavigation.bind(this)); }, - _initSidebarToggleButtons: function() { - if (_sidebar === null) return; - - var sidebarPosition = (_main.classList.contains('sidebarOrientationLeft')) ? 'Left' : ''; - sidebarPosition = (sidebarPosition) ? sidebarPosition : (_main.classList.contains('sidebarOrientationRight') ? 'Right' : ''); - - if (!sidebarPosition) { - return; - } - - // use icons if language item is empty/non-existent - var languageShowSidebar = 'wcf.global.sidebar.show' + sidebarPosition + 'Sidebar'; - if (languageShowSidebar === Language.get(languageShowSidebar) || Language.get(languageShowSidebar) === '') { - languageShowSidebar = elCreate('span'); - languageShowSidebar.className = 'icon icon16 fa-angle-double-' + sidebarPosition.toLowerCase(); - } - - var languageHideSidebar = 'wcf.global.sidebar.hide' + sidebarPosition + 'Sidebar'; - if (languageHideSidebar === Language.get(languageHideSidebar) || Language.get(languageHideSidebar) === '') { - languageHideSidebar = elCreate('span'); - languageHideSidebar.className = 'icon icon16 fa-angle-double-' + (sidebarPosition === 'Left' ? 'right' : 'left'); - } - - // add toggle buttons - var showSidebar = elCreate('span'); - showSidebar.className = 'button small mobileSidebarToggleButton'; - showSidebar.addEventListener('click', function() { _main.classList.add('mobileShowSidebar'); }); - if (languageShowSidebar instanceof Element) showSidebar.appendChild(languageShowSidebar); - else showSidebar.textContent = languageShowSidebar; - - var hideSidebar = elCreate('span'); - hideSidebar.className = 'button small mobileSidebarToggleButton'; - hideSidebar.addEventListener('click', function() { _main.classList.remove('mobileShowSidebar'); }); - if (languageHideSidebar instanceof Element) hideSidebar.appendChild(languageHideSidebar); - else hideSidebar.textContent = languageHideSidebar; - - elBySel('.content').appendChild(showSidebar); - _sidebar.appendChild(hideSidebar); - }, - _initSearchBar: function() { var _searchBar = elBySel('.searchBar'); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Page/Header/Fixed.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Page/Header/Fixed.js index 4d67555563..7767452fb6 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Page/Header/Fixed.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Page/Header/Fixed.js @@ -6,10 +6,11 @@ * @license GNU Lesser General Public License * @module WoltLab/WCF/Ui/Page/Header/Fixed */ -define(['Core', 'EventHandler', 'Ui/CloseOverlay', 'Ui/Screen', 'Ui/SimpleDropdown'], function(Core, EventHandler, UiCloseOverlay, UiScreen, UiSimpleDropdown) { +define(['Core', 'EventHandler', 'Ui/Alignment', 'Ui/CloseOverlay', 'Ui/Screen', 'Ui/SimpleDropdown'], function(Core, EventHandler, UiAlignment, UiCloseOverlay, UiScreen, UiSimpleDropdown) { "use strict"; - var _pageHeader, _pageHeaderContainer, _triggerHeight, _isFixed = false, _isMobile = false; + var _pageHeader, _pageHeaderContainer, _searchInputContainer, _triggerHeight; + var _isFixed = false, _isMobile = false; /** * @exports WoltLab/WCF/Ui/Page/Header/Fixed @@ -53,10 +54,24 @@ define(['Core', 'EventHandler', 'Ui/CloseOverlay', 'Ui/Screen', 'Ui/SimpleDropdo * @protected */ _initSearchBar: function() { + var searchContainer = elById('pageHeaderSearch'); + searchContainer.addEventListener(WCF_CLICK_EVENT, function(event) { + event.preventDefault(); + event.stopPropagation(); + }); + var searchInput = elById('pageHeaderSearchInput'); - UiSimpleDropdown.registerCallback('pageHeaderSearchInputContainer', function() { + var searchLabel = elBySel('.pageHeaderSearchLabel'); + _searchInputContainer = elById('pageHeaderSearchInputContainer'); + + var menu = elById('topMenu'); + searchLabel.addEventListener(WCF_CLICK_EVENT, function() { if ((_isFixed || _isMobile) && !_pageHeader.classList.contains('searchBarOpen')) { + UiAlignment.set(_searchInputContainer, menu, { + horizontal: 'right' + }); + _pageHeader.classList.add('searchBarOpen'); searchInput.focus(); } @@ -81,12 +96,19 @@ define(['Core', 'EventHandler', 'Ui/CloseOverlay', 'Ui/Screen', 'Ui/SimpleDropdo * @protected */ _scroll: function() { + var wasFixed = _isFixed; + _isFixed = (window.scrollY > _triggerHeight); _pageHeader.classList[_isFixed ? 'add' : 'remove']('sticky'); _pageHeaderContainer.classList[_isFixed ? 'add' : 'remove']('stickyPageHeader'); - _pageHeader.classList.remove('searchBarOpen'); + if (!_isFixed && wasFixed) { + _pageHeader.classList.remove('searchBarOpen'); + ['bottom', 'left', 'right', 'top'].forEach(function(propertyName) { + _searchInputContainer.style.removeProperty(propertyName); + }); + } } }; }); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Input.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Input.js index 2aeb3ebf03..ad9b046acd 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Input.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Input.js @@ -27,7 +27,7 @@ define(['Ajax', 'Core', 'EventKey', 'Dom/Util', 'Ui/SimpleDropdown'], function(A if (!(this._element instanceof Element)) { throw new TypeError("Expected a valid DOM element."); } - else if (this._element.nodeName !== 'INPUT' || this._element.type !== 'text') { + else if (this._element.nodeName !== 'INPUT' || (this._element.type !== 'search' && this._element.type !== 'text')) { throw new Error('Expected an input[type="text"].'); } @@ -44,6 +44,7 @@ define(['Ajax', 'Core', 'EventKey', 'Dom/Util', 'Ui/SimpleDropdown'], function(A className: '', interfaceName: 'wcf\\data\\ISearchAction' }, + callbackDropdownInit: null, callbackSelect: null, delay: 500, minLength: 3, @@ -251,6 +252,10 @@ define(['Ajax', 'Core', 'EventKey', 'Dom/Util', 'Ui/SimpleDropdown'], function(A this._list.className = 'dropdownMenu'; createdList = true; + + if (typeof this._options.callbackDropdownInit === 'function') { + this._options.callbackDropdownInit(this._list); + } } else { // reset current list diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Page.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Page.js new file mode 100644 index 0000000000..11e846efc0 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Search/Page.js @@ -0,0 +1,31 @@ +define(['Dom/Util', './Input'], function(DomUtil, UiSearchInput) { + "use strict"; + + var _dropdownMenu = null; + + return { + init: function () { + var searchInput = elById('pageHeaderSearchInput'); + + new UiSearchInput(searchInput, { + ajax: { + className: 'wcf\\data\\search\\keyword\\SearchKeywordAction' + }, + callbackDropdownInit: function(dropdownMenu) { + dropdownMenu.classList.add('dropdownMenuPageSearch'); + + elData(dropdownMenu, 'dropdown-alignment-horizontal', 'right'); + + var minWidth = searchInput.clientWidth; + dropdownMenu.style.setProperty('min-width', minWidth + 'px', ''); + + // calculate offset to ignore the width caused by the submit button + var parent = searchInput.parentNode; + var offsetRight = (DomUtil.offset(parent).left + parent.clientWidth) - (DomUtil.offset(searchInput).left + minWidth); + var offsetTop = DomUtil.styleAsInt(window.getComputedStyle(parent), 'padding-bottom'); + dropdownMenu.style.setProperty('transform', 'translateX(-' + Math.ceil(offsetRight) + 'px) translateY(-' + offsetTop + 'px)', ''); + } + }); + } + }; +}); diff --git a/wcfsetup/install/files/style/layout/form.scss b/wcfsetup/install/files/style/layout/form.scss index e03cc2cd57..6584fb74de 100644 --- a/wcfsetup/install/files/style/layout/form.scss +++ b/wcfsetup/install/files/style/layout/form.scss @@ -139,6 +139,8 @@ select { > .inputPrefix, > .inputSuffix { + align-items: center; + display: flex; flex: 0 0 auto; &.button { diff --git a/wcfsetup/install/files/style/layout/pageHeader.scss b/wcfsetup/install/files/style/layout/pageHeader.scss index 649f488211..ac7576f452 100644 --- a/wcfsetup/install/files/style/layout/pageHeader.scss +++ b/wcfsetup/install/files/style/layout/pageHeader.scss @@ -173,8 +173,6 @@ } .pageHeaderSearchInputContainer .pageHeaderSearchInput { - padding-bottom: 10px; - padding-top: 10px; width: 200px; } } @@ -259,32 +257,41 @@ } .pageHeaderSearchInputContainer { - display: inline-block; + background-color: $wcfHeaderSearchBoxBackground; + border-radius: 2px; + display: inline-flex; + padding: 2px; position: relative; - &:hover { - .pageHeaderSearchInput { - background-color: $wcfHeaderSearchBoxBackgroundActive; - color: $wcfHeaderSearchBoxTextActive; - } - - .pageHeaderSearchInputButton > .icon { - color: $wcfHeaderSearchBoxTextActive; - } + .pageHeaderSearchType > .button { + border-radius: 2px 0 0 2px; + padding: 4px 7px; + } + + .pageHeaderSearchInputButton { + border-radius: 0 2px 2px 0; + padding: 4px 7px; } .pageHeaderSearchInput { - background-color: $wcfHeaderSearchBoxBackground; + background-color: transparent; border-width: 0; color: $wcfHeaderSearchBoxText; - padding: 6px 30px 6px 8px; - &:focus { - background-color: $wcfHeaderSearchBoxBackgroundActive; + &:focus, + &:hover { + background-color: transparent; color: $wcfHeaderSearchBoxTextActive; - ~ .pageHeaderSearchInputButton > .icon { - color: $wcfHeaderSearchBoxTextActive; + /* set placeholder color */ + &::-webkit-input-placeholder { /* WebKit browsers */ + color: $wcfHeaderSearchBoxPlaceholderActive; + } + &::-moz-placeholder { /* Mozilla Firefox 19+ */ + color: $wcfHeaderSearchBoxPlaceholderActive; + } + &:-ms-input-placeholder { /* Internet Explorer 10+ */ + color: $wcfHeaderSearchBoxPlaceholderActive; } } @@ -298,42 +305,12 @@ &:-ms-input-placeholder { /* Internet Explorer 10+ */ color: $wcfHeaderSearchBoxPlaceholder; } - + /* remove broken cancel-button (webkit) */ &::-webkit-search-cancel-button { display:none; } } - - &:hover .pageHeaderSearchInput, - .pageHeaderSearchInput:focus { - /* set placeholder color */ - &::-webkit-input-placeholder { /* WebKit browsers */ - color: $wcfHeaderSearchBoxPlaceholderActive; - } - &::-moz-placeholder { /* Mozilla Firefox 19+ */ - color: $wcfHeaderSearchBoxPlaceholderActive; - } - &:-ms-input-placeholder { /* Internet Explorer 10+ */ - color: $wcfHeaderSearchBoxPlaceholderActive; - } - } - - .pageHeaderSearchInputButton { - background: none; - border: 0 none; - height: 20px; - margin: -10px 5px 0 0; - padding: 0; - position: absolute; - right: 0; - top: 50%; - width: 20px; - - > .icon { - color: $wcfHeaderSearchBoxText; - } - } } @include screen-md-down { diff --git a/wcfsetup/install/files/style/layout/pageHeaderSticky.scss b/wcfsetup/install/files/style/layout/pageHeaderSticky.scss index 856d9d635f..6f0454e24d 100644 --- a/wcfsetup/install/files/style/layout/pageHeaderSticky.scss +++ b/wcfsetup/install/files/style/layout/pageHeaderSticky.scss @@ -123,18 +123,17 @@ } &:not(.searchBarOpen) { - .pageHeaderSearchInput, - .pageHeaderSearchInputButton { + .pageHeaderSearchInputContainer { display: none; } } &.searchBarOpen { .pageHeaderSearchInputContainer { - height: 100%; + border-top-left-radius: 0; + border-top-right-radius: 0; position: absolute; - top: 100%; - transform: translateX(-50px); + top: 50px !important; z-index: 100; } diff --git a/wcfsetup/install/files/style/ui/dropdown.scss b/wcfsetup/install/files/style/ui/dropdown.scss index 43d0134dd7..4e71dc5723 100644 --- a/wcfsetup/install/files/style/ui/dropdown.scss +++ b/wcfsetup/install/files/style/ui/dropdown.scss @@ -129,6 +129,11 @@ visibility: hidden; z-index: 450; + &.dropdownMenuPageSearch { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + &.dropdownArrowRight { &::after { left: auto; diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 5aa6866dc8..9fadb24a4e 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -2631,6 +2631,7 @@ Fehler sind beispielsweise: + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index cfa8db0c76..de37302ca8 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -2667,6 +2667,7 @@ Errors are: + -- 2.20.1