CSSStyleDeclaration.js 6.8 KB

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