| (function(root){ |
| |
| /* |
| * General Value Types definition |
| * they return an object of arrays of type { <name>: [<start-value>, <end-value>], ... } |
| */ |
| var values = { |
| 'length' : function() { |
| // http://www.w3.org/TR/css3-values/#lengths |
| return { |
| // CSS Values and Module Level 3 |
| // ch: ['1ch', '10ch'], |
| // rem: ['1rem', '10rem'], |
| // vw: ['1vw', '10vw'], |
| // vh: ['1vh', '10vh'], |
| // vmin: ['1vmin', '10vmin'], |
| // vmax: ['1vmax', '10vmax'], |
| // CSS Values and Module Level 2 |
| pt: ['1pt', '10pt'], |
| pc: ['1pc', '10pc'], |
| px: ['1px', '10px'], |
| // CSS Values and Module Level 1 |
| em: ['1em', '10em'], |
| ex: ['1ex', '10ex'], |
| mm: ['1mm', '10mm'], |
| cm: ['1cm', '10cm'], |
| 'in': ['1in', '10in'] |
| }; |
| }, |
| 'length-em': function() { |
| return { |
| em: ['1.1em', '1.5em'] |
| }; |
| }, |
| 'percentage': function() { |
| // http://www.w3.org/TR/css3-values/#percentages |
| return { |
| '%': ['33%', '80%'] |
| }; |
| }, |
| 'color': function() { |
| // http://www.w3.org/TR/css3-values/#colors |
| // http://www.w3.org/TR/css3-color/ |
| return { |
| rgba: ['rgba(100,100,100,1)', 'rgba(10,10,10,0.4)'] |
| }; |
| }, |
| 'rectangle': function() { |
| // http://www.w3.org/TR/CSS2/visufx.html#value-def-shape |
| return { |
| rectangle: ['rect(10px,10px,10px,10px)', 'rect(15px,15px,5px,5px)'] |
| }; |
| }, |
| 'font-weight': function() { |
| // http://www.w3.org/TR/css3-fonts/#font-weight-prop |
| return { |
| keyword: ["normal", "bold"], |
| numeric: ["100", "900"] |
| }; |
| }, |
| 'number': function() { |
| // http://www.w3.org/TR/css3-values/#number |
| return { |
| integer: ["1", "10"], |
| decimal: ["1.1", "9.55"] |
| }; |
| }, |
| 'number[0,1]': function() { |
| // http://www.w3.org/TR/css3-values/#number |
| // applies to [0,1]-ranged properties like opacity |
| return { |
| "zero-to-one": ["0.2", "0.9"] |
| }; |
| }, |
| 'integer': function() { |
| // http://www.w3.org/TR/css3-values/#integer |
| return { |
| integer: ["1", "10"] |
| }; |
| }, |
| 'shadow': function() { |
| // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property |
| return { |
| shadow: ['rgba(0,0,0,0.1) 5px 6px 7px', 'rgba(10,10,10,0.9) 5px 6px 7px'] |
| }; |
| }, |
| 'visibility': function() { |
| // http://www.w3.org/TR/CSS2/visufx.html#visibility |
| return { |
| keyword: ['visible', 'hidden', {discrete: true}] |
| }; |
| }, |
| 'auto': function(property) { |
| var types = properties[property] || unspecified_properties[property]; |
| var val = values[types[0]](property); |
| var key = Object.keys(val).shift(); |
| return { |
| to: [val[key][1], 'auto'], |
| from: ['auto', val[key][1]] |
| }; |
| }, |
| // types reqired for non-specified properties |
| 'border-radius': function() { |
| return { |
| px: ['1px', '10px'], |
| "px-px": ['1px 3px', '10px 13px'] |
| }; |
| }, |
| 'image' : function() { |
| var prefix = getValueVendorPrefix('background-image', 'linear-gradient(top, hsl(0, 80%, 70%), #bada55)'); |
| return { |
| // Chrome implements this |
| url: ['url(support/one.gif)', 'url(support/two.gif)'], |
| data: ['url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=)', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==)'], |
| // A hunch, as from the spec: |
| // http://www.w3.org/TR/css3-transitions/#animatable-types |
| // gradient: interpolated via the positions and colors of each stop. They must have the same type (radial or linear) and same number of stops in order to be animated. Note: [CSS3-IMAGES] may extend this definition. |
| gradient: [prefix + 'linear-gradient(top, hsl(0, 80%, 70%), #bada55)', prefix + 'linear-gradient(top, #bada55, hsl(0, 80%, 70%))'] |
| }; |
| }, |
| 'background-size': function() { |
| return { |
| keyword: ['cover', 'contain'] |
| }; |
| }, |
| 'box-shadow': function() { |
| // http://www.w3.org/TR/css3-background/#ltshadowgt |
| return { |
| shadow: ['60px -16px teal', '60px -16px red'] |
| }; |
| }, |
| 'vertical': function() { |
| return { |
| keyword: ['top', 'bottom'] |
| }; |
| }, |
| 'horizontal': function() { |
| return { |
| keyword: ['left', 'right'] |
| }; |
| }, |
| 'font-stretch': function() { |
| return { |
| keyword: ['condensed', 'expanded'] |
| }; |
| }, |
| 'transform': function() { |
| return { |
| rotate: ['rotate(10deg)', 'rotate(20deg)'] |
| }; |
| }, |
| 'position': function() { |
| return { |
| 'static to absolute': ['static', 'absolute', {discrete: true}], |
| 'relative to absolute': ['relative', 'absolute', {discrete: true}], |
| 'absolute to fixed': ['absolute', 'fixed', {discrete: true}] |
| }; |
| }, |
| 'display': function() { |
| return { |
| 'static to absolute': ['none', 'block', {discrete: true}], |
| 'block to inline-block': ['block', 'inline-block', {discrete: true}] |
| }; |
| } |
| }; |
| |
| /* |
| * Property to Type table |
| * (as stated in specification) |
| */ |
| var properties = { |
| 'background-color': ['color'], |
| 'background-position': ['length', 'percentage'], |
| |
| 'border-top-width': ['length'], |
| 'border-right-width': ['length'], |
| 'border-bottom-width': ['length'], |
| 'border-left-width': ['length'], |
| |
| 'border-top-color': ['color'], |
| 'border-right-color': ['color'], |
| 'border-bottom-color': ['color'], |
| 'border-left-color': ['color'], |
| |
| 'padding-bottom': ['length'], |
| 'padding-left': ['length'], |
| 'padding-right': ['length'], |
| 'padding-top': ['length'], |
| |
| 'margin-bottom': ['length'], |
| 'margin-left': ['length'], |
| 'margin-right': ['length'], |
| 'margin-top': ['length'], |
| |
| 'height': ['length', 'percentage'], |
| 'width': ['length', 'percentage'], |
| 'min-height': ['length', 'percentage'], |
| 'min-width': ['length', 'percentage'], |
| 'max-height': ['length', 'percentage'], |
| 'max-width': ['length', 'percentage'], |
| |
| 'top': ['length', 'percentage'], |
| 'right': ['length', 'percentage'], |
| 'bottom': ['length', 'percentage'], |
| 'left': ['length', 'percentage'], |
| |
| 'color': ['color'], |
| 'font-size': ['length', 'percentage'], |
| 'font-weight': ['font-weight'], |
| 'line-height': ['number', 'length', 'percentage'], |
| 'letter-spacing': ['length'], |
| // Note: percentage is Level3 and not implemented anywhere yet |
| // https://drafts.csswg.org/css3-text/#word-spacing |
| 'word-spacing': ['length', 'percentage'], |
| 'text-indent': ['length', 'percentage'], |
| 'text-shadow': ['shadow'], |
| |
| 'outline-color': ['color'], |
| // outline-offset <integer> used to be an error in the spec |
| 'outline-offset': ['length'], |
| 'outline-width': ['length'], |
| |
| 'clip': ['rectangle'], |
| // Note: doesn't seem implemented anywhere |
| 'crop': ['rectangle'], |
| |
| 'vertical-align': ['length', 'percentage'], |
| 'opacity': ['number[0,1]'], |
| 'visibility': ['visibility'], |
| 'z-index': ['integer'] |
| }; |
| |
| /* |
| * Property to auto-value mapping |
| * (lazily taken from http://www.siliconbaytraining.com/pages/csspv.html) |
| */ |
| var properties_auto = [ |
| 'margin-top', |
| 'margin-right', |
| 'margin-bottom', |
| 'margin-left', |
| 'height', |
| 'width', |
| 'clip', |
| 'marker-offset', |
| 'top', |
| 'right', |
| 'left', |
| 'bottom', |
| 'z-index' |
| ]; |
| |
| /* |
| * Property to Type table |
| * (missing value-types of specified properties) |
| */ |
| var missing_properties = { |
| 'margin-bottom': ['percentage'], |
| 'margin-left': ['percentage'], |
| 'margin-right': ['percentage'], |
| 'margin-top': ['percentage'], |
| 'padding-bottom': ['percentage'], |
| 'padding-left': ['percentage'], |
| 'padding-right': ['percentage'], |
| 'padding-top': ['percentage'], |
| 'vertical-align': ['vertical'] |
| }; |
| |
| /* |
| * Property to Type table |
| * (properties that haven't been specified but implemented) |
| */ |
| var unspecified_properties = { |
| // http://oli.jp/2010/css-animatable-properties/ |
| 'border-top-left-radius': ['border-radius'], |
| 'border-top-right-radius': ['border-radius'], |
| 'border-bottom-left-radius': ['border-radius'], |
| 'border-bottom-right-radius': ['border-radius'], |
| 'background-image': ['image'], |
| 'background-size': ['background-size'], |
| // https://drafts.csswg.org/css3-background/#the-box-shadow |
| // Animatable: yes, except between inner and outer shadows (Transition to/from an absent shadow is a transition to/from ‘0 0 transparent’ or ‘0 0 transparent inset’, as appropriate.) |
| 'box-shadow': ['box-shadow'], |
| 'font-size-adjust': ['number'], |
| 'font-stretch': ['font-stretch'], |
| 'marker-offset': ['length'], |
| 'text-decoration-color': ['color'], |
| 'column-count': ['integer'], |
| 'column-gap': ['length'], |
| 'column-rule-color': ['color'], |
| 'column-rule-width': ['length'], |
| 'column-width': ['length'], |
| 'transform': ['transform'], |
| 'transform-origin': ['horizontal'], |
| 'zoom': ['number'], |
| 'outline-radius-topleft': ['length', 'percentage'], |
| 'outline-radius-topright': ['length', 'percentage'], |
| 'outline-radius-bottomright': ['length', 'percentage'], |
| 'outline-radius-bottomleft': ['length', 'percentage'], |
| 'display': ['display'], |
| 'position': ['position'] |
| }; |
| |
| /* |
| * additional styles required to actually render |
| * (different browsers expect different environment) |
| */ |
| var additional_styles = { |
| // all browsers |
| 'border-top-width': {'border-top-style' : 'solid'}, |
| 'border-right-width': {'border-right-style' : 'solid'}, |
| 'border-bottom-width': {'border-bottom-style' : 'solid'}, |
| 'border-left-width': {'border-left-style' : 'solid'}, |
| 'top': {'position': 'absolute'}, |
| 'right': {'position': 'absolute'}, |
| 'bottom': {'position': 'absolute'}, |
| 'left': {'position': 'absolute'}, |
| 'z-index': {'position': 'absolute'}, |
| 'outline-offset': {'outline-style': 'solid'}, |
| 'outline-width': {'outline-style': 'solid'}, |
| 'word-spacing': {'width': '100px', 'height': '100px'}, |
| // unspecified properties |
| 'column-rule-width': {'column-rule-style': 'solid'}, |
| 'position': {'width': '50px', 'height': '50px', top: '10px', left: '50px'} |
| }; |
| |
| /* |
| * additional styles required *on the parent* to actually render |
| * (different browsers expect different environment) |
| */ |
| var parent_styles = { |
| 'border-top-width': {'border-top-style' : 'solid'}, |
| 'border-right-width': {'border-right-style' : 'solid'}, |
| 'border-bottom-width': {'border-bottom-style' : 'solid'}, |
| 'border-left-width': {'border-left-style' : 'solid'}, |
| 'height': {'width': '100px', 'height': '100px'}, |
| 'min-height': {'width': '100px', 'height': '100px'}, |
| 'max-height': {'width': '100px', 'height': '100px'}, |
| 'width': {'width': '100px', 'height': '100px'}, |
| 'min-width': {'width': '100px', 'height': '100px'}, |
| 'max-width': {'width': '100px', 'height': '100px'}, |
| // unspecified properties |
| 'position': {'position': 'relative', 'width': '100px', 'height': '100px'}, |
| // inheritance tests |
| 'top': {'width': '100px', 'height': '100px', 'position': 'relative'}, |
| 'right': {'width': '100px', 'height': '100px', 'position': 'relative'}, |
| 'bottom': {'width': '100px', 'height': '100px', 'position': 'relative'}, |
| 'left': {'width': '100px', 'height': '100px', 'position': 'relative'} |
| }; |
| |
| |
| function assemble(props) { |
| var tests = []; |
| |
| // assemble tests |
| for (var property in props) { |
| props[property].forEach(function(type) { |
| var _values = values[type](property); |
| Object.keys(_values).forEach(function(unit) { |
| var data = { |
| name: property + ' ' + type + '(' + unit + ')', |
| property: property, |
| valueType : type, |
| unit : unit, |
| parentStyle: extend({}, parent_styles[property] || {}), |
| from: extend({}, additional_styles[property] || {}), |
| to: {} |
| }; |
| |
| data.from[property] = _values[unit][0]; |
| data.to[property] = _values[unit][1]; |
| data.flags = _values[unit][2] || {}; |
| |
| tests.push(data); |
| }); |
| }); |
| } |
| |
| return tests; |
| } |
| |
| root.getPropertyTests = function() { |
| return assemble(properties); |
| }; |
| |
| root.getMissingPropertyTests = function() { |
| return assemble(missing_properties); |
| }; |
| |
| root.getUnspecifiedPropertyTests = function() { |
| return assemble(unspecified_properties); |
| }; |
| |
| root.getFontSizeRelativePropertyTests = function() { |
| var accepted = {}; |
| |
| for (var key in properties) { |
| if (!Object.prototype.hasOwnProperty.call(properties, key) || key === "font-size") { |
| continue; |
| } |
| |
| if (properties[key].indexOf('length') > -1) { |
| accepted[key] = ['length-em']; |
| } |
| } |
| |
| return assemble(accepted); |
| }; |
| |
| root.getAutoPropertyTests = function() { |
| var accepted = {}; |
| |
| for (var i = 0, key; key = properties_auto[i]; i++) { |
| accepted[key] = ['auto']; |
| } |
| |
| return assemble(accepted); |
| }; |
| |
| root.filterPropertyTests = function(tests, names) { |
| var allowed = {}; |
| var accepted = []; |
| |
| if (typeof names === "string") { |
| names = [names]; |
| } |
| |
| if (!(names instanceof RegExp)) { |
| names.forEach(function(name) { |
| allowed[name] = true; |
| }); |
| } |
| |
| tests.forEach(function(test) { |
| if (names instanceof RegExp) { |
| if (!test.name.match(names)) { |
| return; |
| } |
| } else if (!allowed[test.name]) { |
| return; |
| } |
| |
| accepted.push(test); |
| }); |
| |
| return accepted; |
| }; |
| |
| })(window); |