|
|
@ -18,12 +18,14 @@ var defaults = { |
|
|
|
mediaQuery: false, |
|
|
|
replace: true, |
|
|
|
landscape: false, |
|
|
|
landscapeUnit: 'vh' |
|
|
|
landscapeUnit: 'vw', |
|
|
|
landscapeWidth: 568 |
|
|
|
}; |
|
|
|
|
|
|
|
module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { |
|
|
|
|
|
|
|
var opts = objectAssign({}, defaults, options); |
|
|
|
|
|
|
|
var pxRegex = getUnitRegexp(opts.unitToConvert); |
|
|
|
var satisfyPropList = createPropListMatcher(opts.propList); |
|
|
|
var landscapeRules = []; |
|
|
@ -35,39 +37,60 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { |
|
|
|
|
|
|
|
if (opts.exclude && file) { |
|
|
|
if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') { |
|
|
|
if (!handleExclude(opts.exclude, file)) return; |
|
|
|
if (isExclude(opts.exclude, file)) return; |
|
|
|
} else if (Object.prototype.toString.call(opts.exclude) === '[object Array]') { |
|
|
|
for (let i = 0; i < opts.exclude.length; i++) { |
|
|
|
if (!handleExclude(opts.exclude[i], file)) return; |
|
|
|
if (isExclude(opts.exclude[i], file)) return; |
|
|
|
} |
|
|
|
} else { |
|
|
|
throw new Error('options.exclude should be RegExp or Array.'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!validateParams(rule.parent.params, opts.mediaQuery)) return; |
|
|
|
if (blacklistedSelector(opts.selectorBlackList, rule.selector)) return; |
|
|
|
|
|
|
|
if (opts.landscape && !rule.parent.params) { |
|
|
|
var landscapeRule = rule.clone().removeAll(); |
|
|
|
landscapeRules.push(landscapeRule); |
|
|
|
|
|
|
|
rule.walkDecls(function(decl) { |
|
|
|
if (decl.value.indexOf(opts.unitToConvert) === -1) return; |
|
|
|
if (!satisfyPropList(decl.prop)) return; |
|
|
|
|
|
|
|
landscapeRule.append(decl.clone({ |
|
|
|
value: decl.value.replace(pxRegex, createPxReplace(opts, opts.landscapeUnit)) |
|
|
|
})); |
|
|
|
var landscapeDecl = decl.clone({ |
|
|
|
value: decl.value.replace(pxRegex, createPxReplace(opts, opts.landscapeUnit, opts.landscapeWidth)) |
|
|
|
}); |
|
|
|
|
|
|
|
if (opts.replace) { |
|
|
|
landscapeRule.append(landscapeDecl); |
|
|
|
} else { |
|
|
|
landscapeRule.append([decl.clone(), landscapeDecl]); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
if (landscapeRule.nodes.length > 0) { |
|
|
|
landscapeRules.push(landscapeRule); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!validateParams(rule.parent.params, opts.mediaQuery)) return; |
|
|
|
|
|
|
|
rule.walkDecls(function(decl, i) { |
|
|
|
if (decl.value.indexOf(opts.unitToConvert) === -1) return; |
|
|
|
if (!satisfyPropList(decl.prop)) return; |
|
|
|
|
|
|
|
var unit = getUnit(decl.prop, opts); |
|
|
|
var value = decl.value.replace(pxRegex, createPxReplace(opts, unit)); |
|
|
|
var unit; |
|
|
|
var size; |
|
|
|
var params = rule.parent.params; |
|
|
|
|
|
|
|
if (opts.landscape && params && params.indexOf('landscape') !== -1) { |
|
|
|
unit = opts.landscapeUnit; |
|
|
|
size = opts.landscapeWidth; |
|
|
|
} else { |
|
|
|
unit = getUnit(decl.prop, opts); |
|
|
|
size = opts.viewportWidth; |
|
|
|
} |
|
|
|
|
|
|
|
var value = decl.value.replace(pxRegex, createPxReplace(opts, unit, size)); |
|
|
|
|
|
|
|
if (declarationExists(decl.parent, decl.prop, value)) return; |
|
|
|
|
|
|
@ -82,29 +105,24 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { |
|
|
|
if (landscapeRules.length > 0) { |
|
|
|
var landscapeRoot = new postcss.atRule({ params: '(orientation: landscape)', name: 'media' }); |
|
|
|
|
|
|
|
landscapeRules.forEach(rule => landscapeRoot.append(rule)); |
|
|
|
landscapeRules.forEach(function(rule) { |
|
|
|
landscapeRoot.append(rule); |
|
|
|
}); |
|
|
|
css.append(landscapeRoot); |
|
|
|
} |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
function handleExclude (reg, file) { |
|
|
|
if (Object.prototype.toString.call(reg) !== '[object RegExp]') { |
|
|
|
throw new Error('options.exclude should be RegExp.'); |
|
|
|
} |
|
|
|
return file.match(reg) === null; |
|
|
|
} |
|
|
|
|
|
|
|
function getUnit(prop, opts) { |
|
|
|
return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit; |
|
|
|
} |
|
|
|
|
|
|
|
function createPxReplace(opts, viewportUnit) { |
|
|
|
function createPxReplace(opts, viewportUnit, viewportSize) { |
|
|
|
return function (m, $1) { |
|
|
|
if (!$1) return m; |
|
|
|
var pixels = parseFloat($1); |
|
|
|
if (pixels <= opts.minPixelValue) return m; |
|
|
|
var parsedVal = toFixed((pixels / opts.viewportWidth * 100), opts.unitPrecision); |
|
|
|
var parsedVal = toFixed((pixels / viewportSize * 100), opts.unitPrecision); |
|
|
|
return parsedVal === 0 ? '0' : parsedVal + viewportUnit; |
|
|
|
}; |
|
|
|
} |
|
|
@ -123,6 +141,13 @@ function blacklistedSelector(blacklist, selector) { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function isExclude(reg, file) { |
|
|
|
if (Object.prototype.toString.call(reg) !== '[object RegExp]') { |
|
|
|
throw new Error('options.exclude should be RegExp.'); |
|
|
|
} |
|
|
|
return file.match(reg) !== null; |
|
|
|
} |
|
|
|
|
|
|
|
function declarationExists(decls, prop, value) { |
|
|
|
return decls.some(function (decl) { |
|
|
|
return (decl.prop === prop && decl.value === value); |
|
|
@ -130,5 +155,5 @@ function declarationExists(decls, prop, value) { |
|
|
|
} |
|
|
|
|
|
|
|
function validateParams(params, mediaQuery) { |
|
|
|
return !params || (params && mediaQuery && params.indexOf('landscape') === -1); |
|
|
|
return !params || (params && mediaQuery); |
|
|
|
} |