reorderable.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // TODO: it'd be great to merge it with the other canReorder functionality
  2. var rulesOverlap = require('./rules-overlap');
  3. var specificitiesOverlap = require('./specificities-overlap');
  4. var FLEX_PROPERTIES = /align-items|box-align|box-pack|flex|justify/;
  5. var BORDER_PROPERTIES = /^border-(top|right|bottom|left|color|style|width|radius)/;
  6. function canReorder(left, right, cache) {
  7. for (var i = right.length - 1; i >= 0; i--) {
  8. for (var j = left.length - 1; j >= 0; j--) {
  9. if (!canReorderSingle(left[j], right[i], cache)) { return false; }
  10. }
  11. }
  12. return true;
  13. }
  14. function canReorderSingle(left, right, cache) {
  15. var leftName = left[0];
  16. var leftValue = left[1];
  17. var leftNameRoot = left[2];
  18. var leftSelector = left[5];
  19. var leftInSpecificSelector = left[6];
  20. var rightName = right[0];
  21. var rightValue = right[1];
  22. var rightNameRoot = right[2];
  23. var rightSelector = right[5];
  24. var rightInSpecificSelector = right[6];
  25. if (leftName == 'font' && rightName == 'line-height' || rightName == 'font' && leftName == 'line-height') { return false; }
  26. if (FLEX_PROPERTIES.test(leftName) && FLEX_PROPERTIES.test(rightName)) { return false; }
  27. if (leftNameRoot == rightNameRoot
  28. && unprefixed(leftName) == unprefixed(rightName)
  29. && (vendorPrefixed(leftName) ^ vendorPrefixed(rightName))) { return false; }
  30. if (leftNameRoot == 'border' && BORDER_PROPERTIES.test(rightNameRoot) && (leftName == 'border' || leftName == rightNameRoot || (leftValue != rightValue && sameBorderComponent(leftName, rightName)))) { return false; }
  31. if (rightNameRoot == 'border' && BORDER_PROPERTIES.test(leftNameRoot) && (rightName == 'border' || rightName == leftNameRoot || (leftValue != rightValue && sameBorderComponent(leftName, rightName)))) { return false; }
  32. if (leftNameRoot == 'border' && rightNameRoot == 'border' && leftName != rightName && (isSideBorder(leftName) && isStyleBorder(rightName) || isStyleBorder(leftName) && isSideBorder(rightName))) { return false; }
  33. if (leftNameRoot != rightNameRoot) { return true; }
  34. if (leftName == rightName
  35. && leftNameRoot == rightNameRoot
  36. && (leftValue == rightValue || withDifferentVendorPrefix(leftValue, rightValue))) { return true; }
  37. if (leftName != rightName
  38. && leftNameRoot == rightNameRoot
  39. && leftName != leftNameRoot
  40. && rightName != rightNameRoot) { return true; }
  41. if (leftName != rightName
  42. && leftNameRoot == rightNameRoot
  43. && leftValue == rightValue) { return true; }
  44. if (rightInSpecificSelector
  45. && leftInSpecificSelector
  46. && !inheritable(leftNameRoot)
  47. && !inheritable(rightNameRoot)
  48. && !rulesOverlap(rightSelector, leftSelector, false)) { return true; }
  49. if (!specificitiesOverlap(leftSelector, rightSelector, cache)) { return true; }
  50. return false;
  51. }
  52. function vendorPrefixed(name) {
  53. return /^-(?:moz|webkit|ms|o)-/.test(name);
  54. }
  55. function unprefixed(name) {
  56. return name.replace(/^-(?:moz|webkit|ms|o)-/, '');
  57. }
  58. function sameBorderComponent(name1, name2) {
  59. return name1.split('-').pop() == name2.split('-').pop();
  60. }
  61. function isSideBorder(name) {
  62. return name == 'border-top' || name == 'border-right' || name == 'border-bottom' || name == 'border-left';
  63. }
  64. function isStyleBorder(name) {
  65. return name == 'border-color' || name == 'border-style' || name == 'border-width';
  66. }
  67. function withDifferentVendorPrefix(value1, value2) {
  68. return vendorPrefixed(value1) && vendorPrefixed(value2) && value1.split('-')[1] != value2.split('-')[2];
  69. }
  70. function inheritable(name) {
  71. // According to http://www.w3.org/TR/CSS21/propidx.html
  72. // Others will be catched by other, preceeding rules
  73. return name == 'font' || name == 'line-height' || name == 'list-style';
  74. }
  75. module.exports = {
  76. canReorder: canReorder,
  77. canReorderSingle: canReorderSingle
  78. };