浏览代码

Add CSS colors count and a palette as offender

Gaël Métais 10 年之前
父节点
当前提交
ed4ddc0a43

+ 42 - 0
front/src/css/rule.css

@@ -148,3 +148,45 @@
   font-style: italic;
   font-weight: normal;
 }
+.colorPalette {
+  width: 30em;
+  border: 2px solid #000;
+  text-align: left;
+  /* Checkerboard background */
+  background-color: #ddd;
+  background-image: linear-gradient(45deg, #aaaaaa 25%, transparent 25%, transparent 75%, #aaaaaa 75%, #aaaaaa), linear-gradient(45deg, #aaaaaa 25%, transparent 25%, transparent 75%, #aaaaaa 75%, #aaaaaa);
+  background-size: 1em 1em;
+  background-position: 0 0, 0.5em 0.5em;
+}
+.colorPalette > div {
+  display: inline-block;
+  height: 2em;
+  position: relative;
+}
+.colorPalette > div div {
+  display: none;
+  position: absolute;
+  left: 100%;
+  top: 100%;
+  background: #FFF;
+  padding: 0.5em;
+  border: 2px solid #f1c40f;
+  border-radius: 0.5em;
+  white-space: nowrap;
+  z-index: 3;
+  font-weight: bold;
+}
+.colorPalette > div:hover div {
+  display: block;
+}
+.colorPalette > div:hover:after {
+  content: " ";
+  position: absolute;
+  background-color: inherit;
+  left: -0.2em;
+  top: -0.2em;
+  width: 100%;
+  height: 100%;
+  z-index: 2;
+  border: 0.2em solid #f1c40f;
+}

+ 48 - 0
front/src/less/rule.less

@@ -168,4 +168,52 @@
             font-weight: normal;
         }
     }
+}
+
+.colorPalette {
+    width: 30em;
+    border: 2px solid #000;
+    text-align: left;
+
+    /* Checkerboard background */
+    background-color: #ddd;
+    background-image: linear-gradient(45deg, #AAA 25%, transparent 25%, transparent 75%, #AAA 75%, #AAA), linear-gradient(45deg, #AAA 25%, transparent 25%, transparent 75%, #AAA 75%, #AAA);
+    background-size:1em 1em;
+    background-position:0 0, 0.5em 0.5em;
+
+    > div {
+        display: inline-block;
+        height: 2em;
+        position: relative;
+
+        div {
+            display: none;
+            position: absolute;
+            left: 100%;
+            top: 100%;
+            background: #FFF;
+            padding: 0.5em;
+            border: 2px solid #f1c40f;
+            border-radius: 0.5em;
+            white-space: nowrap;
+            z-index: 3;
+            font-weight: bold;
+        }
+
+        &:hover div {
+            display: block;
+        }
+
+        &:hover:after {
+            content: " ";
+            position: absolute;
+            background-color: inherit;
+            left: -0.2em;
+            top: -0.2em;
+            width: 100%;
+            height: 100%;
+            z-index: 2;
+            border: 0.2em solid #f1c40f;
+        }
+    }
 }

+ 7 - 0
front/src/views/rule.html

@@ -143,6 +143,13 @@
                 <dom-tree tree="rule.offendersObj.tree"></dom-tree>
             </div>
 
+            <div ng-if="policyName === 'cssColors' && rule.offendersObj.count > 0">
+                <p>This is the color palette, sized by total occurrences:</p>
+                <div class="colorPalette">
+                    <div ng-repeat="offender in rule.offendersObj.palette" style="background-color: {{offender.color}}; width: {{offender.occurrences * 100 / rule.offendersObj.palette[0].occurrences}}%"><div>{{offender.color}} ({{offender.occurrences}} times)</div></div>
+                </div>
+            </div>
+
         </div>
 
     </div>

+ 46 - 0
lib/metadata/policies.js

@@ -410,6 +410,52 @@ var policies = {
             };
         }
     },
+    "cssColors": {
+        "tool": "phantomas",
+        "label": "Different colors",
+        "message": "<p>This is the number of different colors defined in CSS.</p><p>Your CSS project will be easier to maintain if you keep a small color set.</p>",
+        "isOkThreshold": 30,
+        "isBadThreshold": 150,
+        "isAbnormalThreshold": 300,
+        "hasOffenders": true,
+        "offendersTransformFn": function(offenders, ruleObject) {
+            var deduplicatedObj = {};
+
+            offenders.map(function(offender) {
+                var parts = /^([^ ]*) \((\d+) times\)$/.exec(offender);
+
+                if (!parts) {
+                    debug('cssColors offenders transform function error with "%s"', offender);
+                    return;
+                }
+
+                var color = parts[1];
+                var count = parseInt(parts[2], 10);
+
+                deduplicatedObj[color] = (deduplicatedObj[color] || 0) + count;
+            });
+
+            var deduplicatedTable = [];
+            for (var color in deduplicatedObj) {
+                deduplicatedTable.push({
+                    color: color,
+                    occurrences: deduplicatedObj[color]
+                });
+            }
+
+            deduplicatedTable.sort(function(a, b) {
+                return b.occurrences - a.occurrences;
+            });
+
+            // Override rules.value
+            ruleObject.value = deduplicatedTable.length;
+
+            return {
+                count: deduplicatedTable.length,
+                palette: deduplicatedTable
+            };
+        }
+    },
     "cssImports": {
         "tool": "phantomas",
         "label": "Uses of @import",

+ 2 - 1
lib/metadata/scoreProfileGeneric.json

@@ -46,7 +46,8 @@
             "policies": {
                 "cssRules": 2,
                 "cssComplexSelectors": 2,
-                "cssComplexSelectorsByAttribute": 1.5
+                "cssComplexSelectorsByAttribute": 1.5,
+                "cssColors": 0.5
             }
         },
         "badCSS": {

+ 1 - 1
lib/rulesChecker.js

@@ -65,7 +65,7 @@ var RulesChecker = function() {
                         if (policy.offendersTransformFn) {
 
                             try {
-                                offendersObj = policy.offendersTransformFn(offenders);
+                                offendersObj = policy.offendersTransformFn(offenders, rule);
                             } catch(err) {
                                 debug('Error while transforming offenders for %s', metricName);
                                 debug(err);

+ 8 - 8
test/core/customPoliciesTest.js

@@ -404,20 +404,20 @@ describe('rulesChecker', function() {
         results.should.deep.equals({});
 
 
-        // If jQueryDifferentVersions is 0
+        // If jQueryVersionsLoaded is 0
         results = rulesChecker.check({
             "toolsResults": {
                 "phantomas": {
                     "metrics": {
                         "jQueryVersion": "1.6.0",
-                        "jQueryDifferentVersions": 0
+                        "jQueryVersionsLoaded": 0
                     }
                 }
             }
         }, policies);
         results.should.not.have.a.property('jQueryVersion');
-        results.should.have.a.property('jQueryDifferentVersions');
-        results.jQueryDifferentVersions.should.have.a.property('score').that.equals(100);
+        results.should.have.a.property('jQueryVersionsLoaded');
+        results.jQueryVersionsLoaded.should.have.a.property('score').that.equals(100);
 
 
         // If there are more than 1 jQuery version
@@ -426,15 +426,15 @@ describe('rulesChecker', function() {
                 "phantomas": {
                     "metrics": {
                         "jQueryVersion": "1.6.0",
-                        "jQueryDifferentVersions": 2
+                        "jQueryVersionsLoaded": 2
                     }
                 }
             }
         }, policies);
         results.should.not.have.a.property('jQueryVersion');
-        results.should.have.a.property('jQueryDifferentVersions');
-        results.jQueryDifferentVersions.should.have.a.property('score').that.equals(0);
-        results.jQueryDifferentVersions.should.have.a.property('abnormal').that.equals(true);
+        results.should.have.a.property('jQueryVersionsLoaded');
+        results.jQueryVersionsLoaded.should.have.a.property('score').that.equals(0);
+        results.jQueryVersionsLoaded.should.have.a.property('abnormal').that.equals(true);
     });