CSSStyleDeclaration.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*********************************************************************
  2. * This is a fork from the CSS Style Declaration part of
  3. * https://github.com/NV/CSSOM
  4. ********************************************************************/
  5. "use strict";
  6. var CSSOM = require('cssom');
  7. var validProperties = require('./validProperties');
  8. /**
  9. * @constructor
  10. * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration
  11. */
  12. var CSSStyleDeclaration = function CSSStyleDeclaration(onChangeCallback) {
  13. this._values = {};
  14. this._importants = {};
  15. this._length = 0;
  16. this._onChange = onChangeCallback || function () { return; };
  17. };
  18. CSSStyleDeclaration.prototype = {
  19. constructor: CSSStyleDeclaration,
  20. /**
  21. *
  22. * @param {string} name
  23. * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-getPropertyValue
  24. * @return {string} the value of the property if it has been explicitly set for this declaration block.
  25. * Returns the empty string if the property has not been set.
  26. */
  27. getPropertyValue: function (name) {
  28. if (!this._values.hasOwnProperty(name)) {
  29. return "";
  30. }
  31. return this._values[name].toString();
  32. },
  33. /**
  34. *
  35. * @param {string} name
  36. * @param {string} value
  37. * @param {string} [priority=null] "important" or null
  38. * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
  39. */
  40. setProperty: function (name, value, priority) {
  41. if (value === undefined) {
  42. return;
  43. }
  44. if (value === null || value === '') {
  45. this.removeProperty(name);
  46. return;
  47. }
  48. var lowercaseName = name.toLowerCase();
  49. if (!validProperties.has(lowercaseName)) {
  50. return;
  51. }
  52. this[lowercaseName] = value;
  53. this._importants[lowercaseName] = priority;
  54. },
  55. _setProperty: function (name, value, priority) {
  56. if (value === undefined) {
  57. return;
  58. }
  59. if (value === null || value === '') {
  60. this.removeProperty(name);
  61. return;
  62. }
  63. if (this._values[name]) {
  64. // Property already exist. Overwrite it.
  65. var index = Array.prototype.indexOf.call(this, name);
  66. if (index < 0) {
  67. this[this._length] = name;
  68. this._length++;
  69. }
  70. } else {
  71. // New property.
  72. this[this._length] = name;
  73. this._length++;
  74. }
  75. this._values[name] = value;
  76. this._importants[name] = priority;
  77. this._onChange(this.cssText);
  78. },
  79. /**
  80. *
  81. * @param {string} name
  82. * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-removeProperty
  83. * @return {string} the value of the property if it has been explicitly set for this declaration block.
  84. * Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property.
  85. */
  86. removeProperty: function (name) {
  87. if (!this._values.hasOwnProperty(name)) {
  88. return "";
  89. }
  90. var prevValue = this._values[name];
  91. delete this._values[name];
  92. delete this._importants[name];
  93. var index = Array.prototype.indexOf.call(this, name);
  94. if (index < 0) {
  95. return prevValue;
  96. }
  97. // That's what WebKit and Opera do
  98. Array.prototype.splice.call(this, index, 1);
  99. // That's what Firefox does
  100. //this[index] = ""
  101. this._onChange(this.cssText);
  102. return prevValue;
  103. },
  104. /**
  105. *
  106. * @param {String} name
  107. */
  108. getPropertyPriority: function (name) {
  109. return this._importants[name] || "";
  110. },
  111. getPropertyCSSValue: function () {
  112. //FIXME
  113. return;
  114. },
  115. /**
  116. * element.style.overflow = "auto"
  117. * element.style.getPropertyShorthand("overflow-x")
  118. * -> "overflow"
  119. */
  120. getPropertyShorthand: function () {
  121. //FIXME
  122. return;
  123. },
  124. isPropertyImplicit: function () {
  125. //FIXME
  126. return;
  127. },
  128. /**
  129. * http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-item
  130. */
  131. item: function (index) {
  132. index = parseInt(index, 10);
  133. if (index < 0 || index >= this._length) {
  134. return '';
  135. }
  136. return this[index];
  137. }
  138. };
  139. Object.defineProperties(CSSStyleDeclaration.prototype, {
  140. cssText: {
  141. get: function () {
  142. var properties = [];
  143. var i;
  144. var name;
  145. var value;
  146. var priority;
  147. for (i = 0; i < this._length; i++) {
  148. name = this[i];
  149. value = this.getPropertyValue(name);
  150. priority = this.getPropertyPriority(name);
  151. if (priority !== '') {
  152. priority = " !" + priority;
  153. }
  154. properties.push([name, ': ', value, priority, ';'].join(''));
  155. }
  156. return properties.join(' ');
  157. },
  158. set: function (value) {
  159. var i;
  160. this._values = {};
  161. Array.prototype.splice.call(this, 0, this._length);
  162. this._importants = {};
  163. var dummyRule;
  164. try {
  165. dummyRule = CSSOM.parse('#bogus{' + value + '}').cssRules[0].style;
  166. } catch (err) {
  167. // malformed css, just return
  168. return;
  169. }
  170. var rule_length = dummyRule.length;
  171. var name;
  172. for (i = 0; i < rule_length; ++i) {
  173. name = dummyRule[i];
  174. this.setProperty(dummyRule[i], dummyRule.getPropertyValue(name), dummyRule.getPropertyPriority(name));
  175. }
  176. this._onChange(this.cssText);
  177. },
  178. enumerable: true,
  179. configurable: true
  180. },
  181. parentRule: {
  182. get: function () { return null; },
  183. enumerable: true,
  184. configurable: true
  185. },
  186. length: {
  187. get: function () { return this._length; },
  188. /**
  189. * This deletes indices if the new length is less then the current
  190. * length. If the new length is more, it does nothing, the new indices
  191. * will be undefined until set.
  192. **/
  193. set: function (value) {
  194. var i;
  195. for (i = value; i < this._length; i++) {
  196. delete this[i];
  197. }
  198. this._length = value;
  199. },
  200. enumerable: true,
  201. configurable: true
  202. },
  203. 'float': {
  204. get: function () { return this.cssFloat; },
  205. set: function (value) {
  206. this.cssFloat = value;
  207. },
  208. enumerable: true,
  209. configurable: true
  210. }
  211. });
  212. require('./properties')(CSSStyleDeclaration.prototype);
  213. exports.CSSStyleDeclaration = CSSStyleDeclaration;