Permalink
Browse files

Added everything.

  • Loading branch information...
0 parents commit 010b194b35468cc69098fea5cf415711969f6e3d @benschwarz committed Jul 13, 2012
Showing with 271 additions and 0 deletions.
  1. +22 −0 LICENSE-MIT
  2. +76 −0 README.md
  3. +45 −0 grunt.js
  4. +20 −0 index.html
  5. +72 −0 metaquery.js
  6. +1 −0 metaquery.min.js
  7. +35 −0 test/metaquery_test.js
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Ben Schwarz
+
+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.
@@ -0,0 +1,76 @@
+# metaquery
+
+A declarative breakpoint syntax. Defined in <meta>
+
+## Getting Started
+
+Download the [production version][min] or the [development version][max].
+
+[min]: https://raw.github.com/benschwarz/metaquery/master/metaquery.min.js
+[max]: https://raw.github.com/benschwarz/metaquery/master/metaquery.js
+
+In your markup:
+
+ <!doctype html>
+ <html>
+ <head>
+ <meta name="breakpoint" data="phone" media="(max-width: 480px)">
+ <meta name="breakpoint" data="small-tablet" media="(min-width: 480px) and (max-width: 600px)">
+ <meta name="breakpoint" data="tablet" media="(min-width: 600px) and (max-width: 1024px)">
+ <meta name="breakpoint" data="widescreen" media="(min-width: 1024px)">
+
+ <style>
+ .breakpoint-phone { background: red; }
+ .breakpoint-small-tablet { background: green; }
+ .breakpoint-tablet { background: blue; }
+ .breakpoint-widescreen { background: yellow; }
+ </style>
+ </head>
+ <body>
+ <img src="./images/small.jpg" data-breakpoint-template="./images/{{breakpoint}}.jpg">
+ </body>
+ <script src="./metaquery.js"></script>
+ </html>
+
+Now you'll have access to the breakpoints that you've defined in three places:
+
+* Via the CSS classes .breakpoint-<name-of-breakpoint> (shorter than media queries, no repeating yourself)
+* Via responsive image tags (use the declarative interface for defining a convention, then build with that)
+* Bind additional events in Javascript by inspecting the `MediaQueryList` objects via the `metaQuery.breakpoints` hash
+
+# Browser support / Older browsers
+
+## Note: These aren't going to work until I figure out addListener support for matchMedia.js
+
+* ~~IE < 8 doesn't support media queries. Considering using [respond.js][respond.js]~~
+* ~~Add the [matchMedia][matchMedia.js] polyfill for < Chrome 10, Firefox 6, Safari 5.1~~
+
+## Backstory
+
+I worked on a large HTML magazine that is edited by an editorial team. Each 'module' of a template is responsive, and requires unique styles and sometimes even scripts. After reflecting on the project for some time, what worked, what didn't I made some simple observations:
+
+* Writing media queries over and over again sucks. (Even though I used [the technique][responsive-design-with-sass] that I illustrated back in December 11')
+* If you want media query access in javascript, you'll create another media query with `matchMedia`
+* [picturefill][picturefill] is the best responsive image technique I've seen… until I authored templates for a massive magazine. The syntax is too long and easy to forget.
+* and finally, a summary of all three: a declarative interface is far nicer to use.
+
+After reading [Matt Wilcox's article], and the source of [picturefill][picturefill]
+
+## Contributing
+Please use [idiomatic.js][idiomatic.js] as a styleguide and take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt][grunt].
+
+## Release History
+_(Nothing yet)_
+
+## License
+Copyright (c) 2012 Ben Schwarz
+Licensed under the MIT license.
+
+
+[respond.js]: https://github.com/scottjehl/Respond
+[matchMedia.js]: https://github.com/paulirish/matchMedia.js
+[picturefill]: https://github.com/scottjehl/picturefill
+[Matt Wilcox's article]: http://mattwilcox.net/archive/entry/id/1091/
+[responsive-design-with-sass]: http://theint.ro/blogs/outro/4686992-responsive-design-with-sass
+[idiomatic.js]: https://github.com/rwldrn/idiomatic.js
+[grunt]: https://github.com/cowboy/grunt
@@ -0,0 +1,45 @@
+module.exports = function(grunt) {
+
+ // Project configuration.
+ grunt.initConfig({
+ min: {
+ dist: {
+ src: ['metaquery.js'],
+ dest: 'metaquery.min.js'
+ }
+ },
+ test: {
+ files: ['test/**/*.js']
+ },
+ lint: {
+ files: ['metaquery.js', 'test/**/*.js']
+ },
+ watch: {
+ files: '<config:lint.files>',
+ tasks: 'lint test'
+ },
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ boss: true,
+ eqnull: true
+ },
+ globals: {
+ exports: true,
+ module: false
+ }
+ },
+ uglify: {}
+ });
+
+ // Default task.
+ grunt.registerTask('default', 'lint min');
+
+};
@@ -0,0 +1,20 @@
+<!doctype html>
+<html>
+ <head>
+ <meta name="breakpoint" data="phone" media="(max-width: 480px)">
+ <meta name="breakpoint" data="small-tablet" media="(min-width: 480px) and (max-width: 600px)">
+ <meta name="breakpoint" data="tablet" media="(min-width: 600px) and (max-width: 1024px)">
+ <meta name="breakpoint" data="widescreen" media="(min-width: 1024px)">
+
+ <style>
+ .breakpoint-phone { background: red; }
+ .breakpoint-small-tablet { background: green; }
+ .breakpoint-tablet { background: blue; }
+ .breakpoint-widescreen { background: yellow; }
+ </style>
+ </head>
+ <body>
+ <img src="./images/phone.jpg" data-breakpoint-template="./images/{{breakpoint}}.jpg">
+ </body>
+ <script src="./metaquery.js"></script>
+</html>
@@ -0,0 +1,72 @@
+(function ( window, document, undefined ) {
+ window.metaQuery = {
+ breakpoints: {}
+ };
+
+ var addEventListener = window.addEventListener,
+
+ htmlClasses = function ( mq ) {
+ var name = window.metaQuery.breakpoints[mq.media],
+ htmlclasses = document.getElementsByTagName( 'html' )[0].classList;
+
+ if( mq.matches ) {
+ htmlclasses.add( 'breakpoint-' + name );
+ } else {
+ htmlclasses.remove( 'breakpoint-' + name );
+ }
+ },
+
+ images = function ( mq ) {
+ if( !mq.matches ) { return; }
+
+ var name = window.metaQuery.breakpoints[mq.media],
+ images = document.getElementsByTagName( 'img' );
+
+ for( var i = 0; i < images.length; i++ ) {
+ var attribute = images[i].getAttribute( 'data-breakpoint-template' );
+ if( attribute ) { images[i].src = attribute.replace( /\{\{breakpoint\}\}/, name ); }
+ }
+ },
+
+ // Called when a media query changes state
+ mqChange = function ( mq ) {
+ htmlClasses( mq );
+ images( mq );
+ },
+
+ collectBreakPoints = function () {
+ var meta = document.getElementsByTagName( 'meta' );
+
+ // Add classes to the HTML node when a breakpoint matches
+ for( var i = 0; i < meta.length; i++ ) {
+ if( meta[i].name === 'breakpoint' ) {
+ var name = meta[i].getAttribute( 'data' ),
+ query = meta[i].getAttribute( 'media' ),
+ mq = window.matchMedia( query );
+
+ /*
+ Store using mq.media, rather than the media query set,
+ because MediaQueryList returns it in a different order
+ then its entered in.
+ */
+ window.metaQuery.breakpoints[mq.media] = name;
+ mq.addListener( mqChange );
+ mqChange( mq );
+ }
+ }
+ };
+
+ // Public methods
+ window.metaQuery.init = collectBreakPoints;
+
+ // Add events to re-run metaQuery
+ addEventListener( 'DOMContentLoaded', function () {
+ window.metaQuery.init();
+ window.removeEventListener( 'load', window.metaQuery.init );
+ });
+
+ addEventListener( 'load', window.metaQuery.init );
+
+ return window.metaQuery;
+
+}( this, this.document ));

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -0,0 +1,35 @@
+/*global require:true */
+var metaquery = require('../metaquery.js');
+
+/*
+ ======== A Handy Little Nodeunit Reference ========
+ https://github.com/caolan/nodeunit
+
+ Test methods:
+ test.expect(numAssertions)
+ test.done()
+ Test assertions:
+ test.ok(value, [message])
+ test.equal(actual, expected, [message])
+ test.notEqual(actual, expected, [message])
+ test.deepEqual(actual, expected, [message])
+ test.notDeepEqual(actual, expected, [message])
+ test.strictEqual(actual, expected, [message])
+ test.notStrictEqual(actual, expected, [message])
+ test.throws(block, [error], [message])
+ test.doesNotThrow(block, [error], [message])
+ test.ifError(value)
+*/
+
+exports['awesome'] = {
+ setUp: function(done) {
+ // setup here
+ done();
+ },
+ 'no args': function(test) {
+ test.expect(1);
+ // tests here
+ test.equal(metaquery.awesome(), 'awesome', 'should be awesome.');
+ test.done();
+ }
+};

0 comments on commit 010b194

Please sign in to comment.