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', this._initButtonGroupNavigation
.bind(this));
98 if (_messageGroups
) this.rebuildShadow(_messageGroups
, '.messageGroupLink');
101 _initSearchBar: function() {
102 var _searchBar
= elById('pageHeaderSearch');
103 var _searchInput
= elById('pageHeaderSearchInput');
105 EventHandler
.add('com.woltlab.wcf.MainMenuMobile', 'more', function(data
) {
106 if (data
.identifier
=== 'com.woltlab.wcf.search') {
107 _searchBar
.style
.setProperty('top', elById('pageHeader').offsetHeight
+ 'px', '');
108 _searchBar
.classList
.add('open');
109 _searchInput
.focus();
111 data
.handler
.close(true);
115 _main
.addEventListener(WCF_CLICK_EVENT
, function() { _searchBar
.classList
.remove('open'); });
118 _initButtonGroupNavigation: function() {
119 for (var i
= 0, length
= _buttonGroupNavigations
.length
; i
< length
; i
++) {
120 var navigation
= _buttonGroupNavigations
[i
];
122 if (navigation
.classList
.contains('jsMobileButtonGroupNavigation')) continue;
123 else navigation
.classList
.add('jsMobileButtonGroupNavigation');
125 navigation
.parentNode
.classList
.add('hasMobileNavigation');
127 var button
= elCreate('a');
128 button
.className
= 'dropdownLabel';
130 var span
= elCreate('span');
131 span
.className
= 'icon icon24 fa-ellipsis-v';
132 button
.appendChild(span
);
134 var list
= elBySel('.buttonList', navigation
);
135 list
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
136 event
.stopPropagation();
139 (function(navigation
, button
) {
140 button
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
141 event
.preventDefault();
142 event
.stopPropagation();
144 navigation
.classList
.toggle('open');
146 })(navigation
, button
);
148 navigation
.insertBefore(button
, navigation
.firstChild
);
152 _initMessages: function() {
153 Array
.prototype.forEach
.call(_messages
, function(message
) {
154 if (_knownMessages
.has(message
)) {
158 var navigation
= elBySel('.jsMobileNavigation', message
);
159 var quickOptions
= elBySel('.messageQuickOptions', message
);
162 quickOptions
.addEventListener(WCF_CLICK_EVENT
, function (event
) {
164 event
.preventDefault();
165 event
.stopPropagation();
167 navigation
.classList
.toggle('open');
172 navigation
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
173 event
.stopPropagation();
175 // mimic dropdown behavior
176 window
.setTimeout(function () {
177 navigation
.classList
.remove('open');
182 _knownMessages
.add(message
);
186 _initMobileMenu: function() {
187 if (_options
.enableMobileMenu
) {
188 _pageMenuMain
= new UiPageMenuMain();
189 _pageMenuUser
= new UiPageMenuUser();
192 elBySelAll('.boxMenu', null, function(boxMenu
) {
193 boxMenu
.addEventListener(WCF_CLICK_EVENT
, function(event
) {
194 event
.stopPropagation();
196 if (event
.target
=== boxMenu
) {
197 event
.preventDefault();
199 boxMenu
.classList
.add('open');
205 _closeAllMenus: function() {
206 elBySelAll('.jsMobileButtonGroupNavigation.open, .jsMobileNavigation.open, .boxMenu.open', null, function (menu
) {
207 menu
.classList
.remove('open');
211 rebuildShadow: function(elements
, linkSelector
) {
212 var element
, parent
, shadow
;
213 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
214 element
= elements
[i
];
215 parent
= element
.parentNode
;
217 shadow
= DomTraverse
.childByClass(parent
, 'mobileLinkShadow');
218 if (shadow
=== null) {
219 if (elBySel(linkSelector
, element
).href
) {
220 shadow
= elCreate('a');
221 shadow
.className
= 'mobileLinkShadow';
222 shadow
.href
= elBySel(linkSelector
, element
).href
;
224 parent
.appendChild(shadow
);
225 parent
.classList
.add('mobileLinkShadowContainer');
231 removeShadow: function(elements
) {
232 var element
, parent
, shadow
;
233 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
234 element
= elements
[i
];
235 parent
= element
.parentNode
;
237 if (parent
.classList
.contains('mobileLinkShadowContainer')) {
238 shadow
= DomTraverse
.childByClass(parent
, 'mobileLinkShadow');
239 if (shadow
!== null) {
243 parent
.classList
.remove('mobileLinkShadowContainer');