chushihua
This commit is contained in:
+174
@@ -0,0 +1,174 @@
|
||||
'use strict';
|
||||
|
||||
var css = require('css');
|
||||
var extend = require('extend');
|
||||
|
||||
var defaultConfig = {
|
||||
baseDpr: 2, // base device pixel ratio (default: 2)
|
||||
remUnit: 75, // rem unit value (default: 75)
|
||||
remPrecision: 6, // rem value precision (default: 6)
|
||||
forcePxComment: 'px', // force px comment (default: `px`)
|
||||
keepComment: 'no' // no transform value comment (default: `no`)
|
||||
};
|
||||
|
||||
var pxRegExp = /\b(\d+(\.\d+)?)px\b/;
|
||||
|
||||
function Px2rem(options) {
|
||||
this.config = {};
|
||||
extend(this.config, defaultConfig, options);
|
||||
}
|
||||
|
||||
// generate @1x, @2x and @3x version stylesheet
|
||||
Px2rem.prototype.generateThree = function (cssText, dpr) {
|
||||
dpr = dpr || 2;
|
||||
var self = this;
|
||||
var config = self.config;
|
||||
var astObj = css.parse(cssText);
|
||||
|
||||
function processRules(rules) {
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
var rule = rules[i];
|
||||
if (rule.type === 'media') {
|
||||
processRules(rule.rules); // recursive invocation while dealing with media queries
|
||||
continue;
|
||||
} else if (rule.type === 'keyframes') {
|
||||
processRules(rule.keyframes); // recursive invocation while dealing with keyframes
|
||||
continue;
|
||||
} else if (rule.type !== 'rule' && rule.type !== 'keyframe') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var declarations = rule.declarations;
|
||||
for (var j = 0; j < declarations.length; j++) {
|
||||
var declaration = declarations[j];
|
||||
// need transform: declaration && has 'px'
|
||||
if (declaration.type === 'declaration' && pxRegExp.test(declaration.value)) {
|
||||
var nextDeclaration = rule.declarations[j + 1];
|
||||
if (nextDeclaration && nextDeclaration.type === 'comment') { // next next declaration is comment
|
||||
if (nextDeclaration.comment.trim() === config.keepComment) { // no transform
|
||||
declarations.splice(j + 1, 1); // delete corresponding comment
|
||||
continue;
|
||||
} else if (nextDeclaration.comment.trim() === config.forcePxComment) { // force px
|
||||
declarations.splice(j + 1, 1); // delete corresponding comment
|
||||
}
|
||||
}
|
||||
declaration.value = self._getCalcValue('px', declaration.value, dpr); // common transform
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processRules(astObj.stylesheet.rules);
|
||||
|
||||
return css.stringify(astObj);
|
||||
};
|
||||
|
||||
// generate rem version stylesheet
|
||||
Px2rem.prototype.generateRem = function (cssText) {
|
||||
var self = this;
|
||||
var config = self.config;
|
||||
var astObj = css.parse(cssText);
|
||||
|
||||
function processRules(rules, noDealPx) { // FIXME: keyframes do not support `force px` comment
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
var rule = rules[i];
|
||||
if (rule.type === 'media') {
|
||||
processRules(rule.rules); // recursive invocation while dealing with media queries
|
||||
continue;
|
||||
} else if (rule.type === 'keyframes') {
|
||||
processRules(rule.keyframes, true); // recursive invocation while dealing with keyframes
|
||||
continue;
|
||||
} else if (rule.type !== 'rule' && rule.type !== 'keyframe') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!noDealPx) {
|
||||
// generate 3 new rules which has [data-dpr]
|
||||
var newRules = [];
|
||||
for (var dpr = 1; dpr <= 3; dpr++) {
|
||||
var newRule = {};
|
||||
newRule.type = rule.type;
|
||||
newRule.selectors = rule.selectors.map(function (sel) {
|
||||
return '[data-dpr="' + dpr + '"] ' + sel;
|
||||
});
|
||||
newRule.declarations = [];
|
||||
newRules.push(newRule);
|
||||
}
|
||||
}
|
||||
|
||||
var declarations = rule.declarations;
|
||||
for (var j = 0; j < declarations.length; j++) {
|
||||
var declaration = declarations[j];
|
||||
// need transform: declaration && has 'px'
|
||||
if (declaration.type === 'declaration' && pxRegExp.test(declaration.value)) {
|
||||
var nextDeclaration = rule.declarations[j + 1];
|
||||
if (nextDeclaration && nextDeclaration.type === 'comment') { // next next declaration is comment
|
||||
if (nextDeclaration.comment.trim() === config.forcePxComment) { // force px
|
||||
// do not transform `0px`
|
||||
if (declaration.value === '0px') {
|
||||
declaration.value = '0';
|
||||
declarations.splice(j + 1, 1); // delete corresponding comment
|
||||
continue;
|
||||
}
|
||||
if (!noDealPx) {
|
||||
// generate 3 new declarations and put them in the new rules which has [data-dpr]
|
||||
for (var dpr = 1; dpr <= 3; dpr++) {
|
||||
var newDeclaration = {};
|
||||
extend(true, newDeclaration, declaration);
|
||||
newDeclaration.value = self._getCalcValue('px', newDeclaration.value, dpr);
|
||||
newRules[dpr - 1].declarations.push(newDeclaration);
|
||||
}
|
||||
declarations.splice(j, 2); // delete this rule and corresponding comment
|
||||
j--;
|
||||
} else { // FIXME: keyframes do not support `force px` comment
|
||||
declaration.value = self._getCalcValue('rem', declaration.value); // common transform
|
||||
declarations.splice(j + 1, 1); // delete corresponding comment
|
||||
}
|
||||
} else if (nextDeclaration.comment.trim() === config.keepComment) { // no transform
|
||||
declarations.splice(j + 1, 1); // delete corresponding comment
|
||||
} else {
|
||||
declaration.value = self._getCalcValue('rem', declaration.value); // common transform
|
||||
}
|
||||
} else {
|
||||
declaration.value = self._getCalcValue('rem', declaration.value); // common transform
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the origin rule has no declarations, delete it
|
||||
if (!rules[i].declarations.length) {
|
||||
rules.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
|
||||
if (!noDealPx) {
|
||||
// add the new rules which contain declarations that are forced to use px
|
||||
if (newRules[0].declarations.length) {
|
||||
rules.splice(i + 1, 0, newRules[0], newRules[1], newRules[2]);
|
||||
i += 3; // skip the added new rules
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processRules(astObj.stylesheet.rules);
|
||||
|
||||
return css.stringify(astObj);
|
||||
};
|
||||
|
||||
// get calculated value of px or rem
|
||||
Px2rem.prototype._getCalcValue = function (type, value, dpr) {
|
||||
var config = this.config;
|
||||
var pxGlobalRegExp = new RegExp(pxRegExp.source, 'g');
|
||||
|
||||
function getValue(val) {
|
||||
val = parseFloat(val.toFixed(config.remPrecision)); // control decimal precision of the calculated value
|
||||
return val == 0 ? val : val + type;
|
||||
}
|
||||
|
||||
return value.replace(pxGlobalRegExp, function ($0, $1) {
|
||||
return type === 'px' ? getValue($1 * dpr / config.baseDpr) : getValue($1 / config.remUnit);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Px2rem;
|
||||
Reference in New Issue
Block a user