Skip to content
This repository was archived by the owner on Jul 3, 2024. It is now read-only.

Added eCSStender::matchMedia method #12

Merged
merged 4 commits into from
Jul 18, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
*v1.2.8 (2011-07-14)
* added eCSStender::matchMedia() method

*v1.2.6.6* (2010-08-26)
* bugfix: don't call determinePath() on embedded stylesheets

Expand Down
225 changes: 222 additions & 3 deletions src/eCSStender.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,28 @@ License: MIT License (see homepage)
HYPHEN = '-',
OPEN_CURLY = '{',
CLOSE_CURLY = '}',
COMMA = ',',
DIV = 'div',
TYPE = 'type',
COMPLETE = 'complete',
BODY = 'body',
ORIENTATION = 'orientation',
PORTRAIT = 'portrait',
LANDSCAPE = 'landscape',
WIDTH = 'width',
MAXWIDTH = 'max-width',
MINWIDTH = 'min-width',
DEVWIDTH = 'device-width',
DEVMAXWIDTH = 'max-device-width',
DEVMINWIDTH = 'min-device-width',
HEIGHT = 'height',
MAXHEIGHT = 'max-height',
MINHEIGHT = 'min-height',
DEVHEIGHT = 'device-height',
DEVMAXHEIGHT = 'max-device-height',
DEVMINHEIGHT = 'min-device-height',
PX = 'px',
PT = 'pt',

// Regex Bits
ANYTHING = '.*?',
Expand All @@ -76,6 +95,7 @@ License: MIT License (see homepage)
__s = 0, // index of current stylesheet
__style_objects = {}, // style rules to track
__media_groups = {},
__media_queries = {}, // all styles where a CSS3-style media queries is in use
__xhr = NULL,
__initialized = FALSE,
__ignored_css = [],
Expand Down Expand Up @@ -121,11 +141,13 @@ License: MIT License (see homepage)
REGEXP_ATRULE = /@([\w-]+)(.*?)\{([^}]*)\}/ig,
// for splitting properties from values
REGEXP_P_V = /:(?!\/\/)/,
// for detecting CSS3-style media queries
REGEXP_MQ_PARENS = /\(.*:.*\)/,

// eCSStender Object
eCSStender = {
name: ECSSTENDER,
version: '1.2.7',
version: '1.2.8',
fonts: [],
pages: {},
at: {},
Expand Down Expand Up @@ -158,6 +180,7 @@ License: MIT License (see homepage)
{
validateCache();
runTests();
getMediaQueryStyles();
eCSStend();
triggerCallbacks();
writeBrowserCache();
Expand All @@ -181,6 +204,15 @@ License: MIT License (see homepage)
__xhr = TRUE;
}
}
function getMediaQueryStyles() {
var mediaQueryRegex = newRegExp(REGEXP_MQ_PARENS);
for( var styleObject in __style_objects ) {
if( mediaQueryRegex.test(styleObject) ) {
__media_queries[ styleObject ] = __style_objects[ styleObject ];
}
}
eCSStender.mediaQueryStyles = __media_queries;
}
function parseStyles()
{
var s=0, sLen=__stylesheets.length, media, m, mLen;
Expand Down Expand Up @@ -2428,7 +2460,194 @@ License: MIT License (see homepage)
}
};
eCSStender.toggleClass = toggleClass;

/**
* eCSStender.matchMedia()
* returns true if the media query matches the state of rendered document
* and false if it does not (does not take into account things like "screen",
* "print" or "handheld", though native support does)
*
* based on http://dev.w3.org/csswg/cssom-view/
* uses native matchMedia if available
*
* @param str query - the media query to test
*/
function matchMedia( query ) {
if( defined( WINDOW.matchMedia ) ) {
console.log(query, WINDOW.matchMedia(query).matches);
return WINDOW.matchMedia( query ).matches;
} else {
function convertToPixels( val ) {
var
number = parseInt(val.replace(/[^\d]+/g, ''), 10),
unit = val.replace(number, '');
switch(unit) {
case PX:
break;
case PT:
number = number * 96 / 72;
break;
default:
break;
}
return number;
}
var
getWidth,
getHeight;
getWidth = function() {
var _body = document.getElementsByTagName(BODY)[0];
return _body.clientWidth + convertToPixels( getCSSValue( _body, 'margin-left' ) ) + convertToPixels( getCSSValue( _body, 'margin-right' ) );
}
if( defined( window.innerHeight ) ) {
getHeight = function() { return window.innerHeight; }
} else if ( defined( document.documentElement ) && defined( document.documentElement.clientHeight ) && document.documentElement.clientHeight ) {
getHeight = function() { return document.documentElement.clientHeight; }
} else {
getHeight = function() { return document.getElementsByTagName(BODY)[0].clientHeight; }
}

matchMedia = function( query ) {
if(query.indexOf(COMMA) > -1) { // handle OR conditions
var
queries = query.split(COMMA),
i = queries.length;
while( i ) {
var q = queries[i - 1];
q = trim(q);
if( matchMedia(q) ) { // if any of the conditions match, we can return true and bail
return TRUE;
}
i--;
}
}
var
queries = query.split(' and '), // split the query into each condition
matches = TRUE, // optimism
mediaQueryRegex = newRegExp(REGEXP_MQ_PARENS),
W = getWidth(),
DW = screen.width,
H = getHeight(),
DH = screen.height;
i = queries.length;
while ( i ) {
var q = queries[i - 1];
if(mediaQueryRegex.test(q)) { // we only test query parts in the style of (property:value)
var
q = q.split(COLON),
prop = q[0].toLowerCase(),
val = q[1];

prop = prop.replace(/^\(/, EMPTY);
val = val.replace(/\)$/, EMPTY);

if( prop != ORIENTATION ) {
val = convertToPixels(val);
}
switch( prop ) {
case ORIENTATION:
switch( val ) {
case LANDSCAPE:
if( W < H )
{
matches = FALSE;
}
break;
case PORTRAIT:
if( W > H )
{
matches = FALSE;
}
break;
default:
// we only support landscape and portrait
break;
}
break;
case WIDTH:
if( W != val )
{
matches = FALSE;
}
break;
case MAXWIDTH:
if( W > val )
{
matches = FALSE;
}
break;
case MINWIDTH:
if( W < val )
{
matches = FALSE;
}
break;
case DEVWIDTH:
if( DW != val )
{
matches = FALSE;
}
break;
case DEVMAXWIDTH:
if( DW > val )
{
matches = FALSE;
}
break;
case DEVMINWIDTH:
if( DW < val )
{
matches = FALSE;
}
break;
case HEIGHT:
if( H != val )
{
matches = FALSE;
}
break;
case MAXHEIGHT:
if( H > val )
{
matches = FALSE;
}
break;
case MINHEIGHT:
if( H < val )
{
matches = FALSE;
}
break;
case DEVHEIGHT:
if( DH != val )
{
matches = FALSE;
}
break;
case DEVMAXHEIGHT:
if( DH > val )
{
matches = FALSE;
}
break;
case DEVMINHEIGHT:
if( DH < val )
{
matches = FALSE;
}
break;
default:
break;
}
}
i--;
};

return matches;
}
return matchMedia( query );
}
}
eCSStender.matchMedia = matchMedia;
/*-------------------------------------*
* DOM Loaded Trigger *
* Based on jQuery's *
Expand Down Expand Up @@ -2480,5 +2699,5 @@ License: MIT License (see homepage)
}
}
})();

})();
86 changes: 85 additions & 1 deletion tests/js/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,89 @@ eCSStender.onComplete(function(){
matches = eCSStender.lookup({'selector':'#bar'},'*');
ok( matches.length===0, 'array of css files ignored' );
});

module('Media Queries');
test( 'eCSStender::matchMedia', function(){
ok( typeof(eCSStender.matchMedia) == 'function', 'eCSStender::matchMedia() exists' );
if( typeof(window.matchMedia) != 'undefined' && false ) {
ok(true, 'window.matchMedia exists, these tests are using the native method');
}
var
W = $(window).width(),
H = $(window).height(),
DW = screen.width,
DH = screen.height,
O = W > H ? 'landscape' : 'portrait';

// orientation
ok( eCSStender.matchMedia('screen and (orientation:portrait)') == (O == 'portrait'), '(orientation:portrait) ' + (O == 'portrait' ? 'matched' : 'does not match') );
ok( eCSStender.matchMedia('screen and (orientation:landscape)') == (O == 'landscape'), '(orientation:landscape) ' + (O == 'landscape' ? 'matched' : 'does not match') );

// width
ok( eCSStender.matchMedia('screen and (width:' + W + 'px)'), 'width set to window width matches' );
ok( !eCSStender.matchMedia('screen and (width:' + (W - 100) + 'px)'), 'width set to window width - 100 does not match' );
ok( !eCSStender.matchMedia('screen and (width:' + (W + 100) + 'px)'), 'width set to window width + 100 does not match' );

// max-width
ok( eCSStender.matchMedia('screen and (max-width:' + W + 'px)'), 'max-width set to window width matches' );
ok( !eCSStender.matchMedia('screen and (max-width:' + (W - 100) + 'px)'), 'max-width set to window width - 100 does not match' );
ok( eCSStender.matchMedia('screen and (max-width:' + (W + 100) + 'px)'), 'max-width set to window width + 100 matches' );

// min-width
ok( eCSStender.matchMedia('screen and (min-width:' + W + 'px)'), 'min-width set to window width matches' );
ok( eCSStender.matchMedia('screen and (min-width:' + (W - 100) + 'px)'), 'min-width set to window width - 100 matches' );
ok( !eCSStender.matchMedia('screen and (min-width:' + (W + 100) + 'px)'), 'min-width set to window width + 100 does not match' );

// device-width
ok( eCSStender.matchMedia('screen and (device-width:' + DW + 'px)'), 'device-width set to device-width matches' );
ok( !eCSStender.matchMedia('screen and (device-width:' + (DW - 100) + 'px)'), 'device-width set to device-width - 100 does not match' );
ok( !eCSStender.matchMedia('screen and (device-width:' + (DW + 100) + 'px)'), 'device-width set to device-width + 100 does not match' );

// max-device-width
ok( eCSStender.matchMedia('screen and (max-device-width:' + DW + 'px)'), 'max-device-width set to device-width matches' );
ok( !eCSStender.matchMedia('screen and (max-device-width:' + (DW - 100) + 'px)'), 'max-device-width set to device-width - 100 does not match' );
ok( eCSStender.matchMedia('screen and (max-device-width:' + (DW + 100) + 'px)'), 'max-device-width set to device-width + 100 matches' );

// min-device-width
ok( eCSStender.matchMedia('screen and (min-device-width:' + DW + 'px)'), 'min-device-width set to device-width matches' );
ok( eCSStender.matchMedia('screen and (min-device-width:' + (DW - 100) + 'px)'), 'min-device-width set to device-width - 100 matches' );
ok( !eCSStender.matchMedia('screen and (min-device-width:' + (DW + 100) + 'px)'), 'min-device-width set to device-width + 100 does not match' );

// height
ok( eCSStender.matchMedia('screen and (height:' + H + 'px)'), 'height set to window height matches' );
ok( !eCSStender.matchMedia('screen and (height:' + (H - 100) + 'px)'), 'height set to window height - 100 does not match' );
ok( !eCSStender.matchMedia('screen and (height:' + (H + 100) + 'px)'), 'height set to window height + 100 does not match' );

// max-height
ok( eCSStender.matchMedia('screen and (max-height:' + H + 'px)'), 'max-height set to window height matches' );
ok( !eCSStender.matchMedia('screen and (max-height:' + (H - 100) + 'px)'), 'max-height set to window height - 100 does not match' );
ok( eCSStender.matchMedia('screen and (max-height:' + (H + 100) + 'px)'), 'max-height set to window height + 100 matches' );

// min-height
ok( eCSStender.matchMedia('screen and (min-height:' + H + 'px)'), 'min-height set to window height matches' );
ok( eCSStender.matchMedia('screen and (min-height:' + (H - 100) + 'px)'), 'min-height set to window height - 100 matches' );
ok( !eCSStender.matchMedia('screen and (min-height:' + (H + 100) + 'px)'), 'min-height set to window height + 100 does not match' );

// device-height
ok( eCSStender.matchMedia('screen and (device-height:' + DH + 'px)'), 'device-height set to device-height matches' );
ok( !eCSStender.matchMedia('screen and (device-height:' + (DH - 100) + 'px)'), 'device-height set to device-height - 100 does not match' );
ok( !eCSStender.matchMedia('screen and (device-height:' + (DH + 100) + 'px)'), 'device-height set to device-height + 100 does not match' );

// max-device-height
ok( eCSStender.matchMedia('screen and (max-device-height:' + DH + 'px)'), 'max-device-height set to device-height matches' );
ok( !eCSStender.matchMedia('screen and (max-device-height:' + (DH - 100) + 'px)'), 'max-device-height set to device-height - 100 does not match' );
ok( eCSStender.matchMedia('screen and (max-device-height:' + (DH + 100) + 'px)'), 'max-device-height set to device-height + 100 matches' );

// min-device-height
ok( eCSStender.matchMedia('screen and (min-device-height:' + DH + 'px)'), 'min-device-height set to device-height matches' );
ok( eCSStender.matchMedia('screen and (min-device-height:' + (DH - 100) + 'px)'), 'min-device-height set to device-height - 100 matches' );
ok( !eCSStender.matchMedia('screen and (min-device-height:' + (DH + 100) + 'px)'), 'min-device-height set to device-height + 100 does not match' );

// complex rules
ok( eCSStender.matchMedia('screen and (min-width:' + (W - 100) + 'px) and (max-width:' + (W + 100) + 'px)'), '' + 'screen and (min-width:' + (W - 100) + 'px) and (max-width:' + (W + 100) + 'px) matches');
ok( eCSStender.matchMedia('screen and (min-height:' + (H - 100) + 'px) and (max-height:' + (H + 100) + 'px)'), '' + 'screen and (min-height:' + (H - 100) + 'px) and (max-height:' + (H + 100) + 'px) matches');
ok( eCSStender.matchMedia('screen and (min-width:' + (W - 100) + 'px), screen and (max-width:' + (W + 100) + 'px)'), '' + 'screen and (min-width:' + (W - 100) + 'px), screen and (max-width:' + (W + 100) + 'px) matches');
ok( eCSStender.matchMedia('screen and (min-width:' + (W - 100) + 'px) and (orientation:' + O + ')'), '' + 'screen and (min-width:' + (W - 100) + 'px) and (orientation:' + O + ') matches');
ok( !eCSStender.matchMedia('screen and (min-width:' + (W - 100) + 'px) and (orientation:' + ( O == 'portrait' ? 'landscape' : 'portrait' ) + ')'), '' + 'screen and (min-width:' + (W - 100) + 'px) and (orientation:' + ( O == 'portrait' ? 'landscape' : 'portrait' ) + ') does not match');
ok( !eCSStender.matchMedia('screen and (max-width:' + (W - 100) + 'px), screen and (orientation:' + ( O == 'portrait' ? 'landscape' : 'portrait' ) + ')'), '' + 'screen and (max-width:' + (W - 100) + 'px), screen and (orientation:' + ( O == 'portrait' ? 'landscape' : 'portrait' ) + ') does not match');
});
});