You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
7.2 KiB
249 lines
7.2 KiB
//
|
|
// We need to load cssstyle's parsers.js, but its location differs
|
|
// between node 4 and node 5, so check which one we have.
|
|
//
|
|
|
|
var PARSERS = 'jsdom/node_modules/cssstyle/lib/parsers.js'; // node 4 hierarchy
|
|
try {require(PARSERS)} catch (e) {PARSERS = 'cssstyle/lib/parsers.js'} // node 5 heirarchy
|
|
|
|
//
|
|
// Companion to implicitSetter, but for the individual parts.
|
|
// This sets the individual value, and checks to see if all four
|
|
// sub-parts are set. If so, it sets the shorthand version and removes
|
|
// the individual parts from the cssText.
|
|
//
|
|
var subImplicitSetter = function (prefix, part, isValid, parser) {
|
|
var property = prefix + '-' + part;
|
|
var subparts = [prefix+"-top", prefix+"-right", prefix+"-bottom", prefix+"-left"];
|
|
|
|
return function (v) {
|
|
if (typeof v === 'number') v = v.toString();
|
|
if (typeof v !== 'string') return undefined;
|
|
if (!isValid(v)) return undefined;
|
|
v = parser(v);
|
|
this._setProperty(property,v);
|
|
var parts = [];
|
|
for (var i = 0; i < 4; i++) {
|
|
if (this._values[subparts[i]] == null || this._values[subparts[i]] === '') break;
|
|
parts.push(this._values[subparts[i]]);
|
|
}
|
|
if (parts.length === 4) {
|
|
for (i = 0; i < 4; i++) {
|
|
this.removeProperty(subparts[i]);
|
|
this._values[subparts[i]] = parts[i];
|
|
}
|
|
this._setProperty(prefix,parts.join(" "));
|
|
}
|
|
return v;
|
|
};
|
|
};
|
|
|
|
//
|
|
// Patch for CSSStyleDeclaration padding property so that it sets/clears
|
|
// the Top, Right, Bottom, and Left properties (and also validates the
|
|
// padding value)
|
|
//
|
|
var PADDING = (function () {
|
|
var parsers = require(PARSERS);
|
|
var TYPES = parsers.TYPES;
|
|
|
|
var isValid = function (v) {
|
|
var type = parsers.valueType(v);
|
|
return type === TYPES.LENGTH || type === TYPES.PERCENT;
|
|
};
|
|
|
|
var parser = function (v) {
|
|
return parsers.parseMeasurement(v);
|
|
};
|
|
|
|
var mySetter = parsers.implicitSetter('padding', '', isValid, parser);
|
|
var myGlobal = parsers.implicitSetter('padding', '', function () {return true}, function (v) {return v});
|
|
|
|
return {
|
|
definition: {
|
|
set: function (v) {
|
|
if (typeof v === "number") v = String(v);
|
|
if (typeof v !== "string") return;
|
|
var V = v.toLowerCase();
|
|
switch (V) {
|
|
case 'inherit':
|
|
case 'initial':
|
|
case 'unset':
|
|
case '':
|
|
myGlobal.call(this, V);
|
|
break;
|
|
|
|
default:
|
|
mySetter.call(this, v);
|
|
break;
|
|
}
|
|
},
|
|
get: function () {
|
|
return this.getPropertyValue('padding');
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
},
|
|
isValid: isValid,
|
|
parser: parser
|
|
};
|
|
})();
|
|
|
|
//
|
|
// Patch for CSSStyleDeclaration margin property so that it sets/clears
|
|
// the Top, Right, Bottom, and Left properties (and also validates the
|
|
// margin value)
|
|
//
|
|
var MARGIN = (function () {
|
|
var parsers = require(PARSERS);
|
|
var TYPES = parsers.TYPES;
|
|
|
|
var isValid = function (v) {
|
|
if (v.toLowerCase() === "auto") return true;
|
|
var type = parsers.valueType(v);
|
|
return type === TYPES.LENGTH || type === TYPES.PERCENT;
|
|
};
|
|
|
|
var parser = function (v) {
|
|
var V = v.toLowerCase();
|
|
if (V === "auto") return V;
|
|
return parsers.parseMeasurement(v);
|
|
};
|
|
|
|
var mySetter = parsers.implicitSetter('margin', '', isValid, parser);
|
|
var myGlobal = parsers.implicitSetter('margin', '', function () {return true}, function (v) {return v});
|
|
|
|
return {
|
|
definition: {
|
|
set: function (v) {
|
|
if (typeof v === "number") v = String(v);
|
|
if (typeof v !== "string") return;
|
|
var V = v.toLowerCase();
|
|
switch (V) {
|
|
case 'inherit':
|
|
case 'initial':
|
|
case 'unset':
|
|
case '':
|
|
myGlobal.call(this, V);
|
|
break;
|
|
|
|
default:
|
|
mySetter.call(this, v);
|
|
break;
|
|
}
|
|
},
|
|
get: function () {
|
|
return this.getPropertyValue('margin');
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
},
|
|
isValid: isValid,
|
|
parser: parser
|
|
};
|
|
})();
|
|
|
|
|
|
//
|
|
// Patch jsdom functions
|
|
//
|
|
exports.patch = function (jsdom) {
|
|
var document = jsdom('');
|
|
var window = document.defaultView;
|
|
//
|
|
// Fix setting of style attributes so shorthands work properly.
|
|
//
|
|
var div = document.createElement("div");
|
|
div.style.border = "1px solid black";
|
|
if (div.style.border !== "1px solid black") {
|
|
var INIT = window.HTMLElement._init;
|
|
window.HTMLElement._init = function () {
|
|
INIT.apply(this,arguments);
|
|
var that = this;
|
|
this.style._onChange = function (csstext) {
|
|
if (!that._settingCssText) {
|
|
that._settingCssText = true;
|
|
that.setAttribute('style', csstext);
|
|
that._settingCssText = false;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
//
|
|
// Add missing nodeName to Attr (after jsdom 7.1.0, it is no longer defined)
|
|
// since this is used in mml2jax.
|
|
//
|
|
if (!("nodeName" in window.Attr.prototype)) {
|
|
Object.defineProperties(window.Attr.prototype,{
|
|
nodeName: {get: function() {return this.name}}
|
|
});
|
|
}
|
|
//
|
|
// Fix CSSStyleDeclaration properties that are broken (padding, margin)
|
|
//
|
|
div.style.paddingTop = "10px";
|
|
div.style.padding = "1px";
|
|
if (div.style.paddingTop !== "1px") {
|
|
var core = require("jsdom/lib/jsdom/level1/core");
|
|
Object.defineProperties(core.CSSStyleDeclaration.prototype,{
|
|
padding: PADDING.definition,
|
|
margin: MARGIN.definition
|
|
});
|
|
}
|
|
div.style.padding = "1px 2px 3px 4px";
|
|
div.style.paddingTop = "10px";
|
|
if (div.style.padding !== "10px 2px 3px 4px") {
|
|
var core = require("jsdom/lib/jsdom/level1/core");
|
|
Object.defineProperties(core.CSSStyleDeclaration.prototype,{
|
|
marginTop: {
|
|
set: subImplicitSetter('margin', 'top', MARGIN.isValid, MARGIN.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('margin-top');
|
|
}
|
|
},
|
|
marginRight: {
|
|
set: subImplicitSetter('margin', 'right', MARGIN.isValid, MARGIN.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('margin-right');
|
|
}
|
|
},
|
|
marginBottom: {
|
|
set: subImplicitSetter('margin', 'bottom', MARGIN.isValid, MARGIN.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('margin-bottom');
|
|
}
|
|
},
|
|
marginLeft: {
|
|
set: subImplicitSetter('margin', 'left', MARGIN.isValid, MARGIN.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('margin-left');
|
|
}
|
|
},
|
|
paddingTop: {
|
|
set: subImplicitSetter('padding', 'top', PADDING.isValid, PADDING.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('padding-top');
|
|
}
|
|
},
|
|
paddingRight: {
|
|
set: subImplicitSetter('padding', 'right', PADDING.isValid, PADDING.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('padding-right');
|
|
}
|
|
},
|
|
paddingBottom: {
|
|
set: subImplicitSetter('padding', 'bottom', PADDING.isValid, PADDING.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('padding-bottom');
|
|
}
|
|
},
|
|
paddingLeft: {
|
|
set: subImplicitSetter('padding', 'left', PADDING.isValid, PADDING.parser),
|
|
get: function () {
|
|
return this.getPropertyValue('padding-left');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|