diff --git a/.gitignore b/.gitignore
index c0e499a..da35d0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# IDE files
.idea
-# Dependency directory
-bower_components/
\ No newline at end of file
+# Dependencies
+bower_components/
+node_modules/
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..5cd057c
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,67 @@
+module.exports = function(grunt) {
+ "use strict";
+
+ // Project configuration.
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ banner:
+ '/*! angular-adaptive v<%= pkg.version %>: <%= pkg.description %>\n' +
+ ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
+ ' * Licensed under <%= pkg.license %>\n' +
+ ' * <%= pkg.homepage %>' +
+ ' */\n\n',
+ uglify: {
+ nonMinMatchMediaListener: {
+ options: {
+ banner: '<%= banner %>',
+ mangle: false,
+ compress: false,
+ preserveComments: 'some',
+ beautify: {
+ beautify: true,
+ indent_level: 2
+ }
+ },
+ files: {
+ 'dest/adaptive.src.js': ['src/matchMedia.js', 'src/matchMedia.addListener.js', 'src/adaptive.js']
+ }
+ },
+ minMatchMediaListener: {
+ options: {
+ banner: '<%= banner %>'
+ },
+ files: {
+ 'dest/adaptive.min.js': ['src/matchMedia.js', 'src/matchMedia.addListener.js', 'src/adaptive.js']
+ }
+ }
+ },
+ jshint: {
+ files: ['src/adaptive.js'],
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: false,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ boss: true,
+ eqnull: true,
+ smarttabs: true,
+ node: true,
+ strict: false,
+ globals: {
+ angular: false
+ }
+ }
+ }
+ });
+
+ grunt.loadNpmTasks( 'grunt-contrib-jshint' );
+ grunt.loadNpmTasks( 'grunt-contrib-uglify' );
+
+ // Default task.
+ grunt.registerTask('default', ['jshint', 'uglify']);
+
+};
diff --git a/README.md b/README.md
index 6dbf848..4b7c48a 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,83 @@
# angular-adaptive
A hybrid between adaptive and responsive templating. Provides a directive to dynamically load device specific templates in a responsive manner.
+## Installation
+* Install as a [bower](http://bower.io) dependency using:
+```
+bower install angular-adaptive --save
+```
+* Include the supplied `angular-adaptive.min.js` script to you app.
+```html
+
+```
+* Add `'angular-adaptive'` as a module dependency in your angular app.
+```javascript
+angular.module('someApp', ['angular-adaptive']);
+```
+### Configuration
+The **angular-adaptive** can be configured using `adaptiveConfigProvider` in the **config** of your **angular** app module.
+```javascript
+angular
+ .module('someApp', [
+ 'angular-adaptive'
+ ])
+ .config(function(adaptiveConfigProvider) {
+ adaptiveConfigProvider.config({
+ devices: [
+ {
+ name: "large",
+ mediaQuery: "screen and (min-width: 1140px)"
+ },
+ {
+ name: "medium",
+ mediaQuery: "screen and (min-width: 768px) and (max-width: 1280px)"
+ },
+ {
+ name: "small",
+ mediaQuery: "screen and (max-width: 767px)"
+ }
+ ]
+ });
+ });
+```
+#### Defaults
+```javascript
+devices: [
+ {
+ name: "desktop",
+ mediaQuery: "screen and (min-width: 768px)"
+ },
+ {
+ name: "mobile",
+ mediaQuery: "screen and (max-width: 767px)"
+ }
+]
+```
+## Usage
+By default, **angular-adaptive** provides two device configurations (`desktop` and `mobile`) based on the screen widths (See [Defaults](#Defaults)). The device names can be used as the attributes of the `adaptive` directive to provide the respective template file to render when the `mediaQuery` of a certain device is matched.
+```html
+
+```
+# Support
+This script uses the [matchMedia](https://github.com/paulirish/matchMedia.js) polyfill to suppport older versions of Internet Explorer.
+# License
+The MIT License (MIT)
+
+Copyright (c) 2016 Junaid Ilyas
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/bower.json b/bower.json
index f3fd629..c917bbe 100644
--- a/bower.json
+++ b/bower.json
@@ -4,7 +4,7 @@
"Junaid Ilyas "
],
"description": "A hybrid between adaptive and responsive templating. Provides a directive to dynamically load device specific templates in a responsive manner.",
- "main": "angular-adaptive.js",
+ "main": "dest/adaptive.min.js",
"moduleType": [
"globals"
],
@@ -15,10 +15,11 @@
"templates"
],
"license": "MIT",
- "homepage": "https://github.com/junaidilyas/angular-adaptive",
+ "homepage": "https://junaidilyas.github.io/angular-adaptive",
"ignore": [
"**/.*",
- "bower_components"
+ "bower_components",
+ "node_modules"
],
"dependencies": {
"angular": "1.1.x - *"
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0dd3902
--- /dev/null
+++ b/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "angular-adaptive",
+ "version": "0.1.0",
+ "description": "A hybrid between adaptive and responsive templating. Provides a directive to dynamically load device specific templates in a responsive manner.",
+ "main": "dest/adaptive.min.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/junaidilyas/angular-adaptive.git"
+ },
+ "keywords": [
+ "angular",
+ "adaptive",
+ "responsive",
+ "templates"
+ ],
+ "author": "Junaid Ilyas ",
+ "homepage": "https://junaidilyas.github.io/angular-adaptive",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/junaidilyas/angular-adaptive/issues"
+ },
+ "devDependencies": {
+ "grunt": "^0.4.5",
+ "grunt-cli": "^0.1.13",
+ "grunt-contrib-jshint": "^0.12.0",
+ "grunt-contrib-uglify": "^0.11.0"
+ }
+}
diff --git a/angular-adaptive.js b/src/adaptive.js
similarity index 65%
rename from angular-adaptive.js
rename to src/adaptive.js
index 061b913..5450b2d 100644
--- a/angular-adaptive.js
+++ b/src/adaptive.js
@@ -1,6 +1,13 @@
(function () {
'use strict';
+ /**
+ * angular-adaptive - A hybrid between adaptive and responsive templating.
+ * @version v0.1.0
+ * @link https://junaidilyas.github.io/angular-adaptive
+ * @author Junaid Ilyas
+ * @license MIT License, http://www.opensource.org/licenses/MIT
+ */
var module = angular.module('angular-adaptive', []);
module.directive('adaptive', function ($compile, $window, adaptiveConfig) {
@@ -25,11 +32,20 @@
}
};
- var mql = $window.matchMedia(device.mediaQuery);
- mql.addListener(device.loadTemplate);
- device.loadTemplate(mql);
+ device.mql = $window.matchMedia(device.mediaQuery);
+ device.mql.addListener(device.loadTemplate);
+ device.loadTemplate(device.mql);
}
});
+
+ // remove all listeners on element destroy.
+ element.on('$destroy', function() {
+ angular.forEach(devices, function(device) {
+ if (device.mql) {
+ device.mql.removeListener(device.loadTemplate);
+ }
+ });
+ });
};
return {
@@ -59,6 +75,6 @@
$get: function() {
return opts;
}
- }
+ };
});
})();
diff --git a/src/matchMedia.addListener.js b/src/matchMedia.addListener.js
new file mode 100644
index 0000000..b5a3a1c
--- /dev/null
+++ b/src/matchMedia.addListener.js
@@ -0,0 +1,75 @@
+/*! 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;
+ };
+}());
diff --git a/src/matchMedia.js b/src/matchMedia.js
new file mode 100644
index 0000000..803f626
--- /dev/null
+++ b/src/matchMedia.js
@@ -0,0 +1,46 @@
+/*! 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'
+ };
+ };
+}());