UNPKG

sort-media-queries

Version:
253 lines (227 loc) 5.41 kB
var extend = require('xtend'); var mqTypes = ['blank','all','minWidth','minHeight','maxWidth','maxHeight','print']; /** * @param {Array} rules * @param {String} type * @param {String} prop * * @return {Boolean} */ function itemsValid ( rules, type, prop ) { var flag = true; for ( var i = 0, rulesLength = rules.length; i < rulesLength; i++ ) { if ( typeof(rules[i]) !== type || ( prop && !rules[i].hasOwnProperty(prop) ) ) { flag = false; break; } } return flag; } /** * @param {Array} rules * @param {String} type * @param {String} prop * * @return {Boolean} */ function allValid ( rules, type, prop ) { if ( !rules || !rules.length || typeof(rules) === 'string' ) { return 'none'; } if ( (type === 'object' && (!prop || typeof(prop) !== 'string')) || !itemsValid(rules, type, prop) ) { return 'some'; } return 'all'; } /** * Normalize between array with strings and array with objects * * @param {Array} rules * @param {String} type * @param {String} prop * * @return {Object} */ function prepareRules ( rules, type, prop ) { var collection = []; var o = {}; for ( var i = 0, rulesLength = rules.length; i < rulesLength; i++ ) { if ( type === 'string' ) { o = extend({}, { __media: rules[i] }); } else { o = extend({}, rules[i]); o.__media = rules[i][prop]; } collection.push(o); } return collection; } /** * @param {Boolean} isMax * * @return {Function} */ function determineSortOrder ( isMax ) { /** * Determine sort order based on provided arguments * * @param {Object} a * @param {Object} b * * @return {Integer} */ return function ( a, b ) { var sortValA = a.sortVal; var sortValB = b.sortVal; var ruleA = a.item.__media; var ruleB = b.item.__media; isMax = typeof(isMax) !== 'undefined' ? isMax : false; // Consider print for sorting if sortVals are equal if ( sortValA === sortValB ) { if ( ruleA.match(/print/) ) { // a contains print and should be sorted after b return 1; } if ( ruleB.match(/print/) ) { // b contains print and should be sorted after a return -1; } } // Return descending sort order for max-(width|height) media queries if ( isMax ) { return sortValB - sortValA; } // Return ascending sort order return sortValA - sortValB; }; } /** * @return {Object} */ function createCollection () { var mqCollection = {}; for ( var i = 0, mqTypesLength = mqTypes.length; i < mqTypesLength; i++ ) { mqCollection[mqTypes[i]] = []; } return mqCollection; } /** * @param {Object} collection * @param {Array} rules * * @return {Object} */ function addRulesToCollection ( collection, rules ) { // Sort media queries by kind, this is needed to output them in the right order for ( var i = 0, rulesLength = rules.length; i < rulesLength; i++ ) { var item = rules[i]; var rule = item.__media; var collectionType = 'blank'; var valMatch = rule.match(/\d+/g); if ( rule.match(/min-width/) ) { collectionType = 'minWidth'; } else if ( rule.match(/min-height/) ) { collectionType = 'minHeight'; } else if ( rule.match(/max-width/) ) { collectionType = 'maxWidth'; } else if ( rule.match(/max-height/) ) { collectionType = 'maxHeight'; } else if ( rule.match(/print/) ) { collectionType = 'print'; } else if ( rule.match(/all/) ) { collectionType = 'all'; } collection[collectionType].push({ item: item, sortVal: valMatch ? valMatch[0] : 0 }); } return collection; } /** * @param {Object} collection * * @return {Object} */ function sortCollection ( collection ) { var sorter; for ( var collectionType in collection ) { if ( collection.hasOwnProperty(collectionType) ) { sorter = determineSortOrder(false); if ( collectionType === 'maxWidth' || collectionType === 'maxHeight' ) { sorter = determineSortOrder(true); } collection[collectionType].sort(sorter); } } return collection; } /** * @param {Object} collection * @param {String} type * @param {String} prop * * @return {Array} */ function transformCollection ( collection, type, prop ) { var transformed = []; var collectionItem; function iterateCollectionItem ( collectionItem ) { var resultVal; for ( var i = 0, typeLength = collectionItem.length; i < typeLength; i++ ) { if ( type === 'string' ) { resultVal = collectionItem[i].item.__media; } else { resultVal = collectionItem[i].item; delete resultVal.__media; } transformed.push(resultVal); } } for ( var i = 0, mqTypesLength = mqTypes.length; i < mqTypesLength; i++ ) { iterateCollectionItem(collection[mqTypes[i]]); } return transformed; } /** * @param {Array} rules * @param {String} type * @param {String} prop * * @return {Array} */ function sortInit ( rules, type, prop ) { switch ( allValid(rules, type, prop) ) { case 'none': return []; case 'some': return rules; } var collection = createCollection(); rules = prepareRules(rules, type, prop); addRulesToCollection(collection, rules); sortCollection(collection); return transformCollection(collection, type, prop); } /** * @param {Array} rules * @param {String} prop * * @return {Array} */ module.exports = function ( rules, prop ) { if ( rules ) { if ( prop ) { return sortInit(rules, 'object', prop); } return sortInit(rules, 'string'); } return []; };