diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbf0821 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/* \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..4ce5cc2 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,102 @@ +/*global module:false*/ +module.exports = function(grunt) { + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + meta: { + banner: '/* \n' + + ' * <%= pkg.name %> v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> \n' + + ' * <%= pkg.description %> \n' + + ' * <%= pkg.homepage %> \n' + + ' * \n' + + ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>; <%= pkg.license %> Licensed \n' + + ' */ \n\n' + }, + // JS Hint + jshint: { + options: { + globals: { + 'jQuery': true, + '$' : true + }, + browser: true, + curly: true, + eqeqeq: true, + forin: true, + freeze: true, + immed: true, + latedef: true, + newcap: true, + noarg: true, + nonew: true, + smarttabs: true, + sub: true, + undef: true, + validthis: true + }, + files: ['src/<%= pkg.codename %>.js'] + }, + // Concat + concat: { + options: { + banner: '<%= meta.banner %>' + }, + js: { + src: 'src/<%= pkg.codename %>.js', + dest: '<%= pkg.codename %>.js' + }, + css: { + src: 'src/<%= pkg.codename %>.css', + dest: '<%= pkg.codename %>.css' + } + }, + // Uglify + uglify: { + options: { + banner: '<%= meta.banner %>', + report: 'min' + }, + target: { + files: { + '<%= pkg.codename %>.min.js': [ '<%= pkg.codename %>.js' ] + } + } + }, + // jQuery Manifest + jquerymanifest: { + options: { + source: grunt.file.readJSON('package.json'), + overrides: { + name: '<%= pkg.id %>', + keywords: '<%= pkg.keywords %>', + homepage: '<%= pkg.homepage %>', + docs: '<%= pkg.homepage %>', + demo: '<%= pkg.homepage %>', + download: '<%= pkg.repository.url %>', + bugs: '<%= pkg.repository.url %>/issues', + dependencies: { + jquery: '>=1.7' + } + } + } + }, + //Bower sync + sync: { + all: { + options: { + sync: [ 'name', 'version', 'description', 'author', 'license', 'homepage' ] + } + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-jquerymanifest'); + grunt.loadNpmTasks('grunt-npm2bower-sync'); + + // Default task. + grunt.registerTask('default', [ 'jshint', 'concat', 'uglify', 'jquerymanifest', 'sync' ]); + +}; \ No newline at end of file diff --git a/README.md b/README.md index 07aa168..010b19e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -Shifter -======= +Built with Grunt +# Shifter A jQuery plugin for simple slide-out mobile navigation. Part of the formstone library. -[Documentation and Examples](http://www.benplum.com/formstone/shifter/) +- [Demo](http://www.benplum.com/components/Shifter/demo/index.html) +- [Documentation](http://www.benplum.com/formstone/shifter/) -Bower Support: `bower install Shifter` +#### Bower Support + +`bower install Shifter` diff --git a/bower.json b/bower.json index a49213e..d0c3b8e 100644 --- a/bower.json +++ b/bower.json @@ -1,32 +1,12 @@ { - "name": "Shifter", - "version": "1.0.0", - "description": "A jQuery plugin for simple slide-out mobile navigation.", - "keywords": [ - "javascript", - "jquery", - "responsive", - "mobile", - "navigation", - "menu", - "ui", - "formstone", - "benplum" - ], - "authors": [ - "Ben Plum" - ], - "license": "MIT", - "homepage": "http://www.benplum.com/formstone/shifter/", - "main": [ - "jquery.fs.shifter.css", - "jquery.fs.shifter.min.js" - ], - "ignore": [ - "*.json" - ], - "dependencies": { - "jquery": ">= 1.7.0" - }, - "devDependencies": {} + "name": "Shifter", + "version": "1.0.1", + "description": "A jQuery plugin for simple slide-out mobile navigation.", + "author": { + "name": "Ben Plum", + "email": "mr@benplum.com", + "url": "http://www.benplum.com" + }, + "license": "MIT", + "homepage": "http://www.benplum.com/formstone/shifter/" } \ No newline at end of file diff --git a/demo/ie/html5.js b/demo/ie/html5.js new file mode 100644 index 0000000..f9db562 --- /dev/null +++ b/demo/ie/html5.js @@ -0,0 +1,2 @@ +/* Pre-Define HTML5 Elements in IE */ +(function(){ var els = "source|address|article|aside|audio|canvas|command|datalist|details|dialog|figure|figcaption|footer|header|hgroup|keygen|mark|meter|menu|nav|picture|progress|ruby|section|time|video".split('|'); for(var i = 0; i < els.length; i++) { document.createElement(els[i]); } } )(); \ No newline at end of file diff --git a/demo/ie/matchMedia.ie8.js b/demo/ie/matchMedia.ie8.js new file mode 100644 index 0000000..2655fa8 --- /dev/null +++ b/demo/ie/matchMedia.ie8.js @@ -0,0 +1,130 @@ +/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license - IE8 VERSION! */ +window.matchMedia = window.matchMedia || (function(doc, undefined){ + + var docElem = doc.documentElement, + refNode = docElem.firstElementChild || docElem.firstChild, + // fakeBody required for + fakeBody = doc.createElement('body'), + div = doc.createElement('div'); + + div.id = 'mq-test-1'; + div.style.cssText = "position:absolute;top:-100em"; + fakeBody.style.background = "none"; + fakeBody.appendChild(div); + + var mqRun = function ( mq ) { + div.innerHTML = '­'; + docElem.insertBefore( fakeBody, refNode ); + bool = div.offsetWidth === 42; + docElem.removeChild( fakeBody ); + + return { matches: bool, media: mq }; + }, + + getEmValue = function () { + var ret, + body = docElem.body, + fakeUsed = false; + + div.style.cssText = "position:absolute;font-size:1em;width:1em"; + + if( !body ) { + body = fakeUsed = doc.createElement( "body" ); + body.style.background = "none"; + } + + body.appendChild( div ); + + docElem.insertBefore( body, docElem.firstChild ); + + if( fakeUsed ) { + docElem.removeChild( body ); + } else { + body.removeChild( div ); + } + + //also update eminpx before returning + ret = eminpx = parseFloat( div.offsetWidth ); + + return ret; + }, + + //cached container for 1em value, populated the first time it's needed + eminpx, + + // verify that we have support for a simple media query + mqSupport = mqRun( '(min-width: 0px)' ).matches; + + return function ( mq ) { + if( mqSupport ) { + return mqRun( mq ); + } else { + if (doc.body) { + var min = mq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), + max = mq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), + minnull = min === null, + maxnull = max === null, + currWidth = doc.body.offsetWidth, + em = 'em'; + + if( !!min ) { min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); } + if( !!max ) { max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); } + + bool = ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ); + + return { matches: bool, media: mq }; + } else { + return { matches: false, media: {} }; + } + } + }; + +}( document )); + +/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license - IE8 VERSION! */ +(function(){ + // monkeypatch unsupported addListener/removeListener with polling + if(typeof window.matchMedia( "" ) !== "undefined"){ + var oldMM = window.matchMedia; + + window.matchMedia = function( q ){ + var ret = oldMM( q ), + listeners = [], + last = false, + timer, + check = function(){ + var list = oldMM( q ), + unmatchToMatch = list.matches && !last, + matchToUnmatch = !list.matches && last; + + //fire callbacks only if transitioning to or from matched state + if( unmatchToMatch || matchToUnmatch ){ + for( var i =0, il = listeners.length; i< il; i++ ){ + listeners[ i ].call( ret, list ); + } + } + last = list.matches; + }; + + ret.addListener = function( cb ){ + listeners.push( cb ); + if( !timer ){ + timer = setInterval( check, 1000 ); + } + }; + + ret.removeListener = function( cb ){ + for( var i =0, il = listeners.length; i< il; i++ ){ + if( listeners[ i ] === cb ){ + listeners.splice( i, 1 ); + } + } + if( !listeners.length && timer ){ + clearInterval( timer ); + } + }; + + return ret; + }; + } +}()); \ No newline at end of file diff --git a/demo/ie/matchMedia.ie9.js b/demo/ie/matchMedia.ie9.js new file mode 100644 index 0000000..64b4ca3 --- /dev/null +++ b/demo/ie/matchMedia.ie9.js @@ -0,0 +1,121 @@ +/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ +window.matchMedia || (window.matchMedia = function() { + "use strict"; + + // For browsers that support matchMedium api such as IE 9 and webkit + var styleMedia = (window.styleMedia || window.media); + + // For those that don't support matchMedium + if (!styleMedia) { + var style = document.createElement('style'), + script = document.getElementsByTagName('script')[0], + info = null; + + style.type = 'text/css'; + style.id = 'matchmediajs-test'; + + script.parentNode.insertBefore(style, script); + + // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers + info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; + + styleMedia = { + matchMedium: function(media) { + var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; + + // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers + if (style.styleSheet) { + style.styleSheet.cssText = text; + } else { + style.textContent = text; + } + + // Test if media query is true or false + return info.width === '1px'; + } + }; + } + + return function(media) { + return { + matches: styleMedia.matchMedium(media || 'all'), + media: media || 'all' + }; + }; +}()); + +/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */ +(function(){ + // Bail out for browsers that have addListener support + if (window.matchMedia && window.matchMedia('all').addListener) { + return false; + } + + var localMatchMedia = window.matchMedia, + hasMediaQueries = localMatchMedia('only all').matches, + isListening = false, + timeoutID = 0, // setTimeout for debouncing 'handleChange' + queries = [], // Contains each 'mql' and associated 'listeners' if 'addListener' is used + handleChange = function(evt) { + // Debounce + clearTimeout(timeoutID); + + timeoutID = setTimeout(function() { + for (var i = 0, il = queries.length; i < il; i++) { + var mql = queries[i].mql, + listeners = queries[i].listeners || [], + matches = localMatchMedia(mql.media).matches; + + // Update mql.matches value and call listeners + // Fire listeners only if transitioning to or from matched state + if (matches !== mql.matches) { + mql.matches = matches; + + for (var j = 0, jl = listeners.length; j < jl; j++) { + listeners[j].call(window, mql); + } + } + } + }, 30); + }; + + window.matchMedia = function(media) { + var mql = localMatchMedia(media), + listeners = [], + index = 0; + + mql.addListener = function(listener) { + // Changes would not occur to css media type so return now (Affects IE <= 8) + if (!hasMediaQueries) { + return; + } + + // Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8) + // There should only ever be 1 resize listener running for performance + if (!isListening) { + isListening = true; + window.addEventListener('resize', handleChange, true); + } + + // Push object only if it has not been pushed already + if (index === 0) { + index = queries.push({ + mql : mql, + listeners : listeners + }); + } + + listeners.push(listener); + }; + + mql.removeListener = function(listener) { + for (var i = 0, il = listeners.length; i < il; i++){ + if (listeners[i] === listener){ + listeners.splice(i, 1); + } + } + }; + + return mql; + }; +}()); \ No newline at end of file diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 0000000..f97ef8c --- /dev/null +++ b/demo/index.html @@ -0,0 +1,110 @@ + + + + + + + Shifter Demo + + + + + + + + + + + + + + + + + + + + + + +
+ Menu +
+
+
+

Shifter Demo

+
+

A jQuery plugin for simple slide-out mobile navigation. Learn More.

+
+
+
+
+
+ + +

Basic

+

Shifter works by checking for target elements in the DOM and binding events to them. This allows you to markup and style pages anyway you'd like, but at a minimum you need three specifically classed elements (including the body tag):

+ +
$.shifter();
+
<html>
+	<body class="shifter">
+		<div class="shifter-page">
+			<!-- Page Content -->
+		</div>
+		<nav class="shifter-navigation">
+			<!-- Navigation -->
+		</nav>
+	</body>
+</html>
+ + + + +

Custom Widths

+

By default, Shifter will activate itself on screens smaller then 980 pixels wide. You can specify a different width by setting the maxWidth option on initialization.

+ +
$.shifter({
+	maxWidth: Infinity
+});
+ +
Demo
+

Click or tap the handle at the top-right of this page!

+
+ + +

IE Support

+

When supporting IE you will need to include a HTML5 enabler and matchMedia polyfill (IE 8, IE 9).

+ +
+
+
+ + + \ No newline at end of file diff --git a/fs-shifter-icon.png b/jquery.fs.shifter-icon.png similarity index 100% rename from fs-shifter-icon.png rename to jquery.fs.shifter-icon.png diff --git a/jquery.fs.shifter.css b/jquery.fs.shifter.css index 0d6c4a4..7849371 100644 --- a/jquery.fs.shifter.css +++ b/jquery.fs.shifter.css @@ -1,12 +1,11 @@ -/* - * Shifter Plugin [Formstone Library] - * @author Ben Plum - * @version 1.0.0 - * - * Copyright © 2013 Ben Plum - * Released under the MIT License - */ - +/* + * Shifter v1.0.1 - 2013-12-20 + * A jQuery plugin for simple slide-out mobile navigation. + * http://www.benplum.com/formstone/shifter/ + * + * Copyright 2013 Ben Plum; MIT Licensed + */ + .shifter-open { overflow: hidden !important; } .shifter-open .shifter-page * { pointer-events: none !important; } @@ -35,7 +34,7 @@ -o-transition: -o-transform 0.2s ease !important; transition: transform 0.2s ease !important; } - .shifter-active .shifter-handle { background: url(fs-shifter-icon.png) no-repeat center center; cursor: pointer; content: ''; display: block; float: right; height: 30px; width: 30px; + .shifter-active .shifter-handle { background: url(jquery.fs.shifter-icon.png) no-repeat center center; cursor: pointer; content: ''; display: block; float: right; height: 30px; width: 30px; overflow: hidden; text-indent: 110%; white-space: nowrap; -webkit-user-select: none; -moz-user-select: none; @@ -79,7 +78,7 @@ } /* Open */ - .shifter-open .shifter-navigation { pointer-events: all; + .shifter-open .shifter-navigation { pointer-events: all; z-index: 100\9; /* IE 9- */ -webkit-transform: translate3D(0px, 0px, 0px); -moz-transform: translate3D(0px, 0px, 0px); -ms-transform: translate3D(0px, 0px, 0px); diff --git a/jquery.fs.shifter.js b/jquery.fs.shifter.js index d77594f..f7a8105 100644 --- a/jquery.fs.shifter.js +++ b/jquery.fs.shifter.js @@ -1,13 +1,13 @@ -/* - * Shifter Plugin [Formtone Library] - * @author Ben Plum - * @version 1.0.0 - * - * Copyright © 2013 Ben Plum - * Released under the MIT License - */ +/* + * Shifter v1.0.1 - 2013-12-20 + * A jQuery plugin for simple slide-out mobile navigation. + * http://www.benplum.com/formstone/shifter/ + * + * Copyright 2013 Ben Plum; MIT Licensed + */ -if (jQuery) (function($) { +;(function ($, window) { + "use strict"; // Default Options var options = { @@ -92,12 +92,10 @@ if (jQuery) (function($) { // Navtive MQ Support if (window.matchMedia !== undefined) { - data.mediaQuery = window.matchMedia("(max-width:" + (options.maxWidth == Infinity ? "100000px" : options.maxWidth) + ")"); + data.mediaQuery = window.matchMedia("(max-width:" + (options.maxWidth === Infinity ? "100000px" : options.maxWidth) + ")"); data.mediaQuery.addListener(_respond); _respond(); } - } else { - console.warn("Shifter Elements Not Found"); } } @@ -131,4 +129,4 @@ if (jQuery) (function($) { } return this; }; -})(jQuery); +})(jQuery, window); \ No newline at end of file diff --git a/jquery.fs.shifter.min.js b/jquery.fs.shifter.min.js index ee17798..113ce55 100644 --- a/jquery.fs.shifter.min.js +++ b/jquery.fs.shifter.min.js @@ -1,10 +1,9 @@ -/* - * Shifter Plugin [Formtone Library] - * @author Ben Plum - * @version 0.0.7 - * - * Copyright © 2013 Ben Plum - * Released under the MIT License - */ +/* + * Shifter v1.0.1 - 2013-12-20 + * A jQuery plugin for simple slide-out mobile navigation. + * http://www.benplum.com/formstone/shifter/ + * + * Copyright 2013 Ben Plum; MIT Licensed + */ -if(jQuery)(function(c){var b,h,k,d;function n(a){e=c.extend(e,a||{});b=c("body");h=c(".shifter-page");k=c(".shifter-navigation");00&&h.$nav.length>0&&(g=!0,h.$body.addClass("shifter").on("touchstart.shifter click.shifter",".shifter-handle",e),void 0!==b.matchMedia&&(h.mediaQuery=b.matchMedia("(max-width:"+(1/0===f.maxWidth?"100000px":f.maxWidth)+")"),h.mediaQuery.addListener(d),d()))}function d(){h.mediaQuery.matches?i.enable():i.disable()}function e(a){a.preventDefault(),a.stopPropagation(),h.$body.hasClass("shifter-open")?i.close():i.open()}var f={maxWidth:"980px"},g=!1,h={},i={close:function(){g&&(h.$body.removeClass("shifter-open"),h.$nav.find("input").trigger("blur"))},enable:function(){g&&h.$body.addClass("shifter-active")},defaults:function(b){f=a.extend(f,b||{})},destroy:function(){g&&(h.$body.removeClass("shifter shifter-active shifter-open").off("touchstart.shifter click.shifter"),void 0!==b.matchMedia&&h.mediaQuery.removeListener(d),h={})},disable:function(){g&&h.$body.removeClass("shifter-active")},open:function(){g&&(h.$body.addClass("shifter-open"),h.$page.one("touchstart.shifter click.shifter",e))}};a.shifter=function(a){return i[a]?i[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?this:c.apply(this,arguments)}}(jQuery,window); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e4552f9 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "Shifter", + "id": "shifter", + "codename": "jquery.fs.shifter", + "version": "1.0.1", + "description": "A jQuery plugin for simple slide-out mobile navigation.", + "keywords": [ "javascript", "jquery", "responsive", "mobile", "navigation", "menu", "ui", "formstone", "benplum" ], + "repository": { + "type": "git", + "url": "https://github.com/benplum/Shifter" + }, + "homepage": "http://www.benplum.com/formstone/shifter/", + "license": "MIT", + "author": { + "name": "Ben Plum", + "email": "mr@benplum.com", + "url": "http://www.benplum.com" + }, + "devDependencies": { + "grunt-contrib-jshint": "~0.7.2", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-uglify": "~0.2.7", + "grunt-jquerymanifest": "~0.1.3", + "grunt-npm2bower-sync": "~0.3.0" + } +} diff --git a/shifter.jquery.json b/shifter.jquery.json index 8a6b97e..c7f2b99 100644 --- a/shifter.jquery.json +++ b/shifter.jquery.json @@ -1,32 +1,36 @@ { - "name": "shifter", - "title": "Shifter", - "description": "A jQuery plugin for simple slide-out mobile navigation.", - "keywords": [ - "responsive", - "mobile", - "navigation", - "menu", - "ui", - "formstone", - "benplum" - ], - "version": "1.0.0", - "author": { - "name": "Ben Plum", - "url": "http://www.benplum.com" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/mit-license.php" - } - ], - "docs": "http://www.benplum.com/formstone/shifter/", - "demo": "http://www.benplum.com/formstone/shifter/", - "download": "https://github.com/benplum/Shifter", - "bugs": "https://github.com/benplum/Shifter/issues", - "dependencies": { - "jquery": ">=1.7" - } + "name": "shifter", + "version": "1.0.1", + "title": "Shifter", + "author": { + "name": "Ben Plum", + "email": "mr@benplum.com", + "url": "http://www.benplum.com" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://opensource.org/licenses/MIT" + } + ], + "dependencies": { + "jquery": ">=1.7" + }, + "homepage": "http://www.benplum.com/formstone/shifter/", + "description": "A jQuery plugin for simple slide-out mobile navigation.", + "keywords": [ + "javascript", + "jquery", + "responsive", + "mobile", + "navigation", + "menu", + "ui", + "formstone", + "benplum" + ], + "docs": "http://www.benplum.com/formstone/shifter/", + "demo": "http://www.benplum.com/formstone/shifter/", + "download": "https://github.com/benplum/Shifter", + "bugs": "https://github.com/benplum/Shifter/issues" } \ No newline at end of file diff --git a/src/jquery.fs.shifter.css b/src/jquery.fs.shifter.css new file mode 100644 index 0000000..1104eb7 --- /dev/null +++ b/src/jquery.fs.shifter.css @@ -0,0 +1,109 @@ + .shifter-open { overflow: hidden !important; } + .shifter-open .shifter-page * { pointer-events: none !important; } + + .shifter .shifter-navigation { display: none; opacity: 0; } + .shifter .shifter-handle { display: none; } + + .shifter-active .shifter-page { background: #fff; box-shadow: 2px 0 2px rgba(0, 0, 0, 0.15); display: block; left: 0; min-height: 100%; overflow: hidden; position: relative; top: 0; z-index: 1; + -webkit-transform: translate3D(0px, 0px, 0px); + -moz-transform: translate3D(0px, 0px, 0px); + -ms-transform: translate3D(0px, 0px, 0px); + -o-transform: translate3D(0px, 0px, 0px); + transform: translate3D(0px, 0px, 0px); + } + .shifter-active .shifter-navigation { background: #fff; display: block; height: 100%; opacity: 1; pointer-events: none; position: fixed; top: 0; width: 270px; z-index: 0; } + + .shifter-active .shifter-page, + .shifter-active .shifter-navigation { + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + -o-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transition: -webkit-transform 0.2s ease !important; + -moz-transition: -moz-transform 0.2s ease !important; + -ms-transition: -ms-transform 0.2s ease !important; + -o-transition: -o-transform 0.2s ease !important; + transition: transform 0.2s ease !important; + } + .shifter-active .shifter-handle { background: url(jquery.fs.shifter-icon.png) no-repeat center center; cursor: pointer; content: ''; display: block; float: right; height: 30px; width: 30px; + overflow: hidden; text-indent: 110%; white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + } + + /* Right / Default */ + .shifter-active .shifter-navigation { right: 0; + -webkit-transform: translate3D(0px, 0px, 0px); + -moz-transform: translate3D(0px, 0px, 0px); + -ms-transform: translate3D(0px, 0px, 0px); + -o-transform: translate3D(0px, 0px, 0px); + transform: translate3D(0px, 0px, 0px); + } + + .shifter-open .shifter-page { + -webkit-transform: translate3D(-270px, 0px, 0px); + -moz-transform: translate3D(-270px, 0px, 0px); + -ms-transform: translate3D(-270px, 0px, 0px); + -o-transform: translate3D(-270px, 0px, 0px); + transform: translate3D(-270px, 0px, 0px); + } + + /* Left */ + .shifter-active.shifter-left .shifter-navigation { left: 0; + -webkit-transform: translate3D(0px, 0px, 0px); + -moz-transform: translate3D(0px, 0px, 0px); + -ms-transform: translate3D(0px, 0px, 0px); + -o-transform: translate3D(0px, 0px, 0px); + transform: translate3D(0px, 0px, 0px); + } + + .shifter-active.shifter-left.shifter-open .shifter-page { + -webkit-transform: translate3D(270px, 0px, 0px); + -moz-transform: translate3D(270px, 0px, 0px); + -ms-transform: translate3D(270px, 0px, 0px); + -o-transform: translate3D(270px, 0px, 0px); + transform: translate3D(270px, 0px, 0px); + } + + /* Open */ + .shifter-open .shifter-navigation { pointer-events: all; z-index: 100\9; /* IE 9- */ + -webkit-transform: translate3D(0px, 0px, 0px); + -moz-transform: translate3D(0px, 0px, 0px); + -ms-transform: translate3D(0px, 0px, 0px); + -o-transform: translate3D(0px, 0px, 0px); + transform: translate3D(0px, 0px, 0px); + } + + /* IE 10 ONLY */ + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + /* Right / Default */ + .shifter-active .shifter-navigation { right: 0; + -webkit-transform: translate3D(270px, 0px, 0px); + -moz-transform: translate3D(270px, 0px, 0px); + -ms-transform: translate3D(270px, 0px, 0px); + -o-transform: translate3D(270px, 0px, 0px); + transform: translate3D(270px, 0px, 0px); + } + + /* Left */ + .shifter-active.shifter-left .shifter-navigation { left: 0; + -webkit-transform: translate3D(-270px, 0px, 0px); + -moz-transform: translate3D(-270px, 0px, 0px); + -ms-transform: translate3D(-270px, 0px, 0px); + -o-transform: translate3D(-270px, 0px, 0px); + transform: translate3D(-270px, 0px, 0px); + } + + /* Open */ + .shifter-open .shifter-navigation { pointer-events: all; + -webkit-transform: translate3D(0px, 0px, 0px); + -moz-transform: translate3D(0px, 0px, 0px); + -ms-transform: translate3D(0px, 0px, 0px); + -o-transform: translate3D(0px, 0px, 0px); + transform: translate3D(0px, 0px, 0px); + } + } \ No newline at end of file diff --git a/src/jquery.fs.shifter.js b/src/jquery.fs.shifter.js new file mode 100644 index 0000000..213a796 --- /dev/null +++ b/src/jquery.fs.shifter.js @@ -0,0 +1,124 @@ +;(function ($, window) { + "use strict"; + + // Default Options + var options = { + maxWidth: "980px" + }; + + // Internal Data + var initialized = false, + data = {}; + + // Public Methods + var pub = { + + // Close Navigation + close: function() { + if (initialized) { + data.$body.removeClass("shifter-open"); + // Close mobile keyboard + data.$nav.find("input").trigger("blur"); + } + }, + + // Enable Shifter + enable: function() { + if (initialized) { + data.$body.addClass("shifter-active"); + } + }, + + // Set Defaults + defaults: function(opts) { + options = $.extend(options, opts || {}); + }, + + // Destroy Shifter + destroy: function() { + if (initialized) { + data.$body.removeClass("shifter shifter-active shifter-open") + .off("touchstart.shifter click.shifter"); + + // Navtive MQ Support + if (window.matchMedia !== undefined) { + data.mediaQuery.removeListener(_respond); + } + + data = {}; + } + }, + + // Disable Shifter + disable: function() { + if (initialized) { + data.$body.removeClass("shifter-active"); + } + }, + + // Open Navigation + open: function() { + if (initialized) { + data.$body.addClass("shifter-open"); + data.$page.one("touchstart.shifter click.shifter", _handleClick); + } + } + }; + + // Private Methods + + // Initialize + function _init(opts) { + // Local options + options = $.extend(options, opts || {}); + + data.$body = $("body"); + data.$page = $(".shifter-page"); + data.$nav = $(".shifter-navigation"); + + if (data.$page.length > 0 && data.$nav.length > 0) { + initialized = true; + + data.$body.addClass("shifter") + .on("touchstart.shifter click.shifter", ".shifter-handle", _handleClick); + + // Navtive MQ Support + if (window.matchMedia !== undefined) { + data.mediaQuery = window.matchMedia("(max-width:" + (options.maxWidth === Infinity ? "100000px" : options.maxWidth) + ")"); + data.mediaQuery.addListener(_respond); + _respond(); + } + } + } + + // Handle media query change + function _respond() { + if (data.mediaQuery.matches) { + pub.enable(); + } else { + pub.disable(); + } + } + + // Hanle clicks + function _handleClick(e) { + e.preventDefault(); + e.stopPropagation(); + + if (data.$body.hasClass("shifter-open")) { + pub.close(); + } else { + pub.open(); + } + } + + // Define Plugin + $.shifter = function(method) { + if (pub[method]) { + return pub[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method) { + return _init.apply(this, arguments); + } + return this; + }; +})(jQuery, window); \ No newline at end of file