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

//
// 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');
}
}
});
}
}