2 * Modifies the interface to provide a better usability for mobile devices.
4 * @author Alexander Ebert
5 * @copyright 2001-2016 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @module WoltLabSuite/Core/Ui/Mobile
10 [ 'Core', 'Environment', 'EventHandler', 'Language', 'List', 'Dom/ChangeListener', 'Dom/Traverse', 'Ui/CloseOverlay', 'Ui/Screen', './Page/Menu/Main', './Page/Menu/User'],
11 function(Core
, Environment
, EventHandler
, Language
, List
, DomChangeListener
, DomTraverse
, UiCloseOverlay
, UiScreen
, UiPageMenuMain
, UiPageMenuUser
)
15 var _buttonGroupNavigations
= elByClass('buttonGroupNavigation');
17 var _knownMessages
= new List();
19 var _messages
= elByClass('message');
21 var _pageMenuMain
= null;
22 var _pageMenuUser
= null;
23 var _messageGroups
= null;
26 * @exports WoltLabSuite/Core/Ui/Mobile
30 * Initializes the mobile UI.
32 * @param {Object=} options initialization options
34 setup: function(options
) {
35 _options
= Core
.extend({
36 enableMobileMenu
: true
39 _main
= elById('main');
41 if (Environment
.touch()) {
42 document
.documentElement
.classList
.add('touch');
45 if (Environment
.platform() !== 'desktop') {
46 document
.documentElement
.classList
.add('mobile');
49 var messageGroupList
= elBySel('.messageGroupList');
50 if (messageGroupList
) _messageGroups
= elByClass('messageGroup', messageGroupList
);
52 UiScreen
.on('screen-md-down', {
53 match
: this.enable
.bind(this),
54 unmatch
: this.disable
.bind(this),
55 setup
: this._init
.bind(this)
60 * Enables the mobile UI.
65 if (_options
.enableMobileMenu
) {
66 _pageMenuMain
.enable();
67 _pageMenuUser
.enable();
70 if (_messageGroups
) this.rebuildShadow(_messageGroups
, '.messageGroupLink');
74 * Disables the mobile UI.
79 if (_options
.enableMobileMenu
) {
80 _pageMenuMain
.disable();
81 _pageMenuUser
.disable();
84 if (_messageGroups
) this.removeShadow(_messageGroups
);
90 this._initSearchBar();
91 this._initButtonGroupNavigation();
93 this._initMobileMenu();
95 UiCloseOverlay
.add('WoltLabSuite/Core/Ui/Mobile', this._closeAllMenus
.bind(this));
96 DomChangeListener
.add('WoltLabSuite/Core/Ui/Mobile', (function() {
97 this._initButtonGroupNavigation();
101 if (_messageGroups
) this.rebuildShadow(_messageGroups
, '.messageGroupLink');
104 _initSearchBar: function() {
105 var _searchBar
= elById('pageHeaderSearch');
106 var _searchInput
= elById('pageHeaderSearchInput');
108 EventHandler
.add('com.woltlab.wcf.MainMenuMobile', 'more', function(data
) {
109 if (data
.identifier
=== 'com.woltlab.wcf.search') {
110 _searchBar
.style
.setProperty('top', elById('pageHeader').offsetHeight
+ 'px', '');
111 _searchBar
.classList
.add('open');
112 _searchInput
.focus();
114 data
.handler
.close(true);
118 _main
.addEventListener(WCF_CLICK_EVENT
, function() { _searchBar
.classList
.remove('open'); });
121 _initButtonGroupNavigation: function() {
122 for (var i
= 0, length
= _buttonGroupNavigations
.length
; i
< length
; i
++) {
123 var navigation
= _buttonGroupNavigations
[i
];
125 if (navigation
.classList
.contains('jsMobileButtonGroupNavigation')) continue;
126 else navigation
.classList
.add('jsMobileButtonGroupNavigation');
128 navigation
.parentNode
.classList
.add('hasMobileNavigation');
130 var button
= elCreate('a');
131 button
.className
= 'dropdownLabel';
133 var span
= elCreate('span');
134 span
.className
= 'icon icon24 fa-ellipsis-v';
135 button
.appendChild(span
);
137 var list
= elBySel('.buttonList', navigation
);
138 list
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
139 event
.stopPropagation();
141 navigation
.classList
.remove('open');
144 (function(navigation
, button
) {
145 button
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
146 event
.preventDefault();
147 event
.stopPropagation();
149 navigation
.classList
.toggle('open');
151 })(navigation
, button
);
153 navigation
.insertBefore(button
, navigation
.firstChild
);
157 _initMessages: function() {
158 Array
.prototype.forEach
.call(_messages
, function(message
) {
159 if (_knownMessages
.has(message
)) {
163 var navigation
= elBySel('.jsMobileNavigation', message
);
164 var quickOptions
= elBySel('.messageQuickOptions', message
);
167 quickOptions
.addEventListener(WCF_CLICK_EVENT
, function (event
) {
169 event
.preventDefault();
170 event
.stopPropagation();
172 navigation
.classList
.toggle('open');
177 navigation
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
178 event
.stopPropagation();
180 // mimic dropdown behavior
181 window
.setTimeout(function () {
182 navigation
.classList
.remove('open');
187 _knownMessages
.add(message
);
191 _initMobileMenu: function() {
192 if (_options
.enableMobileMenu
) {
193 _pageMenuMain
= new UiPageMenuMain();
194 _pageMenuUser
= new UiPageMenuUser();
197 elBySelAll('.boxMenu', null, function(boxMenu
) {
198 boxMenu
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
199 event
.stopPropagation();
201 if (event
.target
=== boxMenu
) {
202 event
.preventDefault();
204 boxMenu
.classList
.add('open');
210 _closeAllMenus: function() {
211 elBySelAll('.jsMobileButtonGroupNavigation.open, .jsMobileNavigation.open, .boxMenu.open', null, function (menu
) {
212 menu
.classList
.remove('open');
216 rebuildShadow: function(elements
, linkSelector
) {
217 var element
, parent
, shadow
;
218 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
219 element
= elements
[i
];
220 parent
= element
.parentNode
;
222 shadow
= DomTraverse
.childByClass(parent
, 'mobileLinkShadow');
223 if (shadow
=== null) {
224 if (elBySel(linkSelector
, element
).href
) {
225 shadow
= elCreate('a');
226 shadow
.className
= 'mobileLinkShadow';
227 shadow
.href
= elBySel(linkSelector
, element
).href
;
229 parent
.appendChild(shadow
);
230 parent
.classList
.add('mobileLinkShadowContainer');
236 removeShadow: function(elements
) {
237 var element
, parent
, shadow
;
238 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
239 element
= elements
[i
];
240 parent
= element
.parentNode
;
242 if (parent
.classList
.contains('mobileLinkShadowContainer')) {
243 shadow
= DomTraverse
.childByClass(parent
, 'mobileLinkShadow');
244 if (shadow
!== null) {
248 parent
.classList
.remove('mobileLinkShadowContainer');