summaryrefslogtreecommitdiffstats
path: root/core/js
diff options
context:
space:
mode:
authorThomas Müller <thomas.mueller@tmit.eu>2014-03-28 10:27:15 +0100
committerThomas Müller <thomas.mueller@tmit.eu>2014-03-28 10:27:15 +0100
commite3b951f4122f0a5d8531faaf4082bfb356366847 (patch)
tree87246f2eaba0c89db88496184b72c6b49eb4d77e /core/js
parentccc55f40e6be7c9cc5e5484721998b2d60aeedc9 (diff)
parenteeaefd84c3911a166920084947ad1018c744e6a6 (diff)
downloadnextcloud-server-e3b951f4122f0a5d8531faaf4082bfb356366847.tar.gz
nextcloud-server-e3b951f4122f0a5d8531faaf4082bfb356366847.zip
Merge pull request #7724 from owncloud/mobile
[WIP] Mobile optimization for base layout and Files app
Diffstat (limited to 'core/js')
-rw-r--r--core/js/js.js108
-rw-r--r--core/js/share.js8
-rw-r--r--core/js/tests/specs/coreSpec.js104
3 files changed, 216 insertions, 4 deletions
diff --git a/core/js/js.js b/core/js/js.js
index 3d3185f12c1..721a5a2e927 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -482,6 +482,53 @@ var OC={
}).show();
}, 'html');
}
+ },
+
+ // for menu toggling
+ registerMenu: function($toggle, $menuEl) {
+ $menuEl.addClass('menu');
+ $toggle.addClass('menutoggle');
+ $toggle.on('click.menu', function(event) {
+ if ($menuEl.is(OC._currentMenu)) {
+ $menuEl.hide();
+ OC._currentMenu = null;
+ OC._currentMenuToggle = null;
+ return false;
+ }
+ // another menu was open?
+ else if (OC._currentMenu) {
+ // close it
+ OC._currentMenu.hide();
+ }
+ $menuEl.show();
+ OC._currentMenu = $menuEl;
+ OC._currentMenuToggle = $toggle;
+ return false
+ });
+ },
+
+ unregisterMenu: function($toggle, $menuEl) {
+ // close menu if opened
+ if ($menuEl.is(OC._currentMenu)) {
+ $menuEl.hide();
+ OC._currentMenu = null;
+ OC._currentMenuToggle = null;
+ }
+ $toggle.off('click.menu').removeClass('menutoggle');
+ $menuEl.removeClass('menu');
+ },
+
+ /**
+ * Wrapper for matchMedia
+ *
+ * This is makes it possible for unit tests to
+ * stub matchMedia (which doesn't work in PhantomJS)
+ */
+ _matchMedia: function(media) {
+ if (window.matchMedia) {
+ return window.matchMedia(media);
+ }
+ return false;
}
};
OC.search.customResults={};
@@ -940,6 +987,67 @@ function initCore() {
$('a.action').tipsy({gravity:'s', fade:true, live:true});
$('td .modified').tipsy({gravity:'s', fade:true, live:true});
$('input').tipsy({gravity:'w', fade:true});
+
+ // toggle for menus
+ $(document).on('mouseup.closemenus', function(event) {
+ var $el = $(event.target);
+ if ($el.closest('.menu').length || $el.closest('.menutoggle').length) {
+ // don't close when clicking on the menu directly or a menu toggle
+ return false;
+ }
+ if (OC._currentMenu) {
+ OC._currentMenu.hide();
+ }
+ OC._currentMenu = null;
+ OC._currentMenuToggle = null;
+ });
+
+
+ /**
+ * Set up the main menu toggle to react to media query changes.
+ * If the screen is small enough, the main menu becomes a toggle.
+ * If the screen is bigger, the main menu is not a toggle any more.
+ */
+ function setupMainMenu() {
+ // toggle the navigation on mobile
+ if (!OC._matchMedia) {
+ return;
+ }
+ var mq = OC._matchMedia('(max-width: 768px)');
+ var lastMatch = mq.matches;
+ var $toggle = $('#header #owncloud');
+ var $navigation = $('#navigation');
+
+ function updateMainMenu() {
+ // mobile mode ?
+ if (lastMatch && !$toggle.hasClass('menutoggle')) {
+ // init the menu
+ OC.registerMenu($toggle, $navigation);
+ $toggle.data('oldhref', $toggle.attr('href'));
+ $toggle.attr('href', '#');
+ $navigation.hide();
+ }
+ else {
+ OC.unregisterMenu($toggle, $navigation);
+ $toggle.attr('href', $toggle.data('oldhref'));
+ $navigation.show();
+ }
+ }
+
+ updateMainMenu();
+
+ // TODO: debounce this
+ $(window).resize(function() {
+ if (lastMatch !== mq.matches) {
+ lastMatch = mq.matches;
+ updateMainMenu();
+ }
+ });
+ }
+
+ if (window.matchMedia) {
+ setupMainMenu();
+ }
}
$(document).ready(initCore);
diff --git a/core/js/share.js b/core/js/share.js
index 9ee50ff6963..e769edd0a21 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -48,7 +48,7 @@ OC.Share={
var action = $(file).find('.fileactions .action[data-action="Share"]');
var img = action.find('img').attr('src', image);
action.addClass('permanent');
- action.html(' '+t('core', 'Shared')).prepend(img);
+ action.html(' <span>'+t('core', 'Shared')+'</span>').prepend(img);
} else {
var dir = $('#dir').val();
if (dir.length > 1) {
@@ -63,7 +63,7 @@ OC.Share={
if (img.attr('src') != OC.imagePath('core', 'actions/public')) {
img.attr('src', image);
$(action).addClass('permanent');
- $(action).html(' '+t('core', 'Shared')).prepend(img);
+ $(action).html(' <span>'+t('core', 'Shared')+'</span>').prepend(img);
}
});
}
@@ -103,10 +103,10 @@ OC.Share={
var img = action.find('img').attr('src', image);
if (shares) {
action.addClass('permanent');
- action.html(' '+ escapeHTML(t('core', 'Shared'))).prepend(img);
+ action.html(' <span>'+ escapeHTML(t('core', 'Shared'))+'</span>').prepend(img);
} else {
action.removeClass('permanent');
- action.html(' '+ escapeHTML(t('core', 'Share'))).prepend(img);
+ action.html(' <span>'+ escapeHTML(t('core', 'Share'))+'</span>').prepend(img);
}
}
}
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index 069546387c7..57ea5be8be0 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -279,5 +279,109 @@ describe('Core base tests', function() {
expect(OC.generateUrl('apps/files/download{file}', {file: '/Welcome.txt'})).toEqual(OC.webroot + '/index.php/apps/files/download/Welcome.txt');
});
});
+ describe('Main menu mobile toggle', function() {
+ var oldMatchMedia;
+ var $toggle;
+ var $navigation;
+
+ beforeEach(function() {
+ oldMatchMedia = OC._matchMedia;
+ // a separate method was needed because window.matchMedia
+ // cannot be stubbed due to a bug in PhantomJS:
+ // https://github.com/ariya/phantomjs/issues/12069
+ OC._matchMedia = sinon.stub();
+ $('#testArea').append('<div id="header">' +
+ '<a id="owncloud" href="#"></a>' +
+ '</div>' +
+ '<div id="navigation"></div>');
+ $toggle = $('#owncloud');
+ $navigation = $('#navigation');
+ });
+
+ afterEach(function() {
+ OC._matchMedia = oldMatchMedia;
+ });
+ it('Sets up menu toggle in mobile mode', function() {
+ OC._matchMedia.returns({matches: true});
+ window.initCore();
+ expect($toggle.hasClass('menutoggle')).toEqual(true);
+ expect($navigation.hasClass('menu')).toEqual(true);
+ });
+ it('Does not set up menu toggle in desktop mode', function() {
+ OC._matchMedia.returns({matches: false});
+ window.initCore();
+ expect($toggle.hasClass('menutoggle')).toEqual(false);
+ expect($navigation.hasClass('menu')).toEqual(false);
+ });
+ it('Switches on menu toggle when mobile mode changes', function() {
+ var mq = {matches: false};
+ OC._matchMedia.returns(mq);
+ window.initCore();
+ expect($toggle.hasClass('menutoggle')).toEqual(false);
+ mq.matches = true;
+ $(window).trigger('resize');
+ expect($toggle.hasClass('menutoggle')).toEqual(true);
+ });
+ it('Switches off menu toggle when mobile mode changes', function() {
+ var mq = {matches: true};
+ OC._matchMedia.returns(mq);
+ window.initCore();
+ expect($toggle.hasClass('menutoggle')).toEqual(true);
+ mq.matches = false;
+ $(window).trigger('resize');
+ expect($toggle.hasClass('menutoggle')).toEqual(false);
+ });
+ it('Clicking menu toggle toggles navigation in mobile mode', function() {
+ OC._matchMedia.returns({matches: true});
+ window.initCore();
+ $navigation.hide(); // normally done through media query triggered CSS
+ expect($navigation.is(':visible')).toEqual(false);
+ $toggle.click();
+ expect($navigation.is(':visible')).toEqual(true);
+ $toggle.click();
+ expect($navigation.is(':visible')).toEqual(false);
+ });
+ it('Clicking menu toggle does not toggle navigation in desktop mode', function() {
+ OC._matchMedia.returns({matches: false});
+ window.initCore();
+ expect($navigation.is(':visible')).toEqual(true);
+ $toggle.click();
+ expect($navigation.is(':visible')).toEqual(true);
+ });
+ it('Switching to mobile mode hides navigation', function() {
+ var mq = {matches: false};
+ OC._matchMedia.returns(mq);
+ window.initCore();
+ expect($navigation.is(':visible')).toEqual(true);
+ mq.matches = true;
+ $(window).trigger('resize');
+ expect($navigation.is(':visible')).toEqual(false);
+ });
+ it('Switching to desktop mode shows navigation', function() {
+ var mq = {matches: true};
+ OC._matchMedia.returns(mq);
+ window.initCore();
+ expect($navigation.is(':visible')).toEqual(false);
+ mq.matches = false;
+ $(window).trigger('resize');
+ expect($navigation.is(':visible')).toEqual(true);
+ });
+ it('Switch to desktop with opened menu then back to mobile resets toggle', function() {
+ var mq = {matches: true};
+ OC._matchMedia.returns(mq);
+ window.initCore();
+ expect($navigation.is(':visible')).toEqual(false);
+ $toggle.click();
+ expect($navigation.is(':visible')).toEqual(true);
+ mq.matches = false;
+ $(window).trigger('resize');
+ expect($navigation.is(':visible')).toEqual(true);
+ mq.matches = true;
+ $(window).trigger('resize');
+ expect($navigation.is(':visible')).toEqual(false);
+ $toggle.click();
+ expect($navigation.is(':visible')).toEqual(true);
+ });
+ });
});