فهرست منبع

Merge pull request #54 from gmetais/scriptfilter

Introduce a script selector to filter the timeline and the profiler.
Gaël Métais 10 سال پیش
والد
کامیت
f304e5efb7
4فایلهای تغییر یافته به همراه99 افزوده شده و 18 حذف شده
  1. 14 0
      front/src/css/timeline.css
  2. 59 17
      front/src/js/controllers/timelineCtrl.js
  3. 18 0
      front/src/less/timeline.less
  4. 8 1
      front/src/views/timeline.html

+ 14 - 0
front/src/css/timeline.css

@@ -2,6 +2,19 @@
 .execution {
   text-align: center;
 }
+.selectScript {
+  padding-bottom: 2em;
+  font-size: 0.9em;
+}
+.selectScript select {
+  max-width: 30em;
+}
+.selectScript.empty {
+  font-size: 0.8em;
+}
+.selectScript.empty select {
+  width: 10em;
+}
 .timeline {
   margin: 2em 0 5em;
 }
@@ -173,6 +186,7 @@ input.textFilter {
 }
 .table > div > .index {
   color: #bbb;
+  word-break: normal;
 }
 .table > div > .type {
   white-space: nowrap;

+ 59 - 17
front/src/js/controllers/timelineCtrl.js

@@ -19,16 +19,52 @@ timelineCtrl.controller('TimelineCtrl', ['$scope', '$rootScope', '$routeParams',
     }
 
     function render() {
+        initScriptFiltering();
         initExecutionTree();
         initTimeline();
         $timeout(initProfiler, 100);
     }
 
+    function initScriptFiltering() {
+        var offenders = $scope.result.rules.jsCount.offendersObj.list;
+        $scope.scripts = [];
+
+        offenders.forEach(function(script) {
+            var filePath = script.file;
+
+            if (filePath.length > 100) {
+                filePath = filePath.substr(0, 98) + '...';
+            }
+
+            var scriptObj = {
+                fullPath: script.file, 
+                shortPath: filePath
+            };
+
+            $scope.scripts.push(scriptObj);
+        });
+    }
+
     function initExecutionTree() {
         var originalExecutions = $scope.result.javascriptExecutionTree.children || [];
-        $scope.executionTree = [];
+        
+        // Detect the last event of all (before filtering) and read time
+        var lastEvent = originalExecutions[originalExecutions.length - 1];
+        $scope.endTime =  lastEvent.data.timestamp + (lastEvent.data.time || 0);
 
+        // Filter and calculate the search index
+        $scope.executionTree = [];
         originalExecutions.forEach(function(node) {
+            
+            // Filter by script (if enabled)
+            if ($scope.selectedScript) {
+                if (node.data.backtrace && node.data.backtrace.indexOf($scope.selectedScript.fullPath + ':') === -1) {
+                    return;
+                }
+                if (node.data.type === "jQuery loaded" || node.data.type === "jQuery version change") {
+                    return;
+                }
+            }
 
             // Prepare a faster angular search by creating a kind of search index
             node.searchIndex = (node.data.callDetails) ? [node.data.type].concat(node.data.callDetails.arguments).join('°°') : node.data.type;
@@ -41,8 +77,6 @@ timelineCtrl.controller('TimelineCtrl', ['$scope', '$rootScope', '$routeParams',
 
         // Split the timeline into 200 intervals
         var numberOfIntervals = 199;
-        var lastEvent = $scope.executionTree[$scope.executionTree.length - 1];
-        $scope.endTime =  lastEvent.data.timestamp + (lastEvent.data.time || 0);
         $scope.timelineIntervalDuration = $scope.endTime / numberOfIntervals;
         
         // Pre-fill array of as many elements as there are milleseconds
@@ -89,25 +123,33 @@ timelineCtrl.controller('TimelineCtrl', ['$scope', '$rootScope', '$routeParams',
         var out = [];
         var splited = str.split(' / ');
         splited.forEach(function(trace) {
-            var result = /^(\S*)\s?\(?(https?:\/\/\S+):(\d+)\)?$/g.exec(trace);
-            if (result && result[2].length > 0) {
-                var filePath = result[2];
-                var chunks = filePath.split('/');
-                var fileName = chunks[chunks.length - 1];
-
-                out.push({
-                    fnName: result[1],
-                    fileName: fileName,
-                    filePath: filePath,
-                    line: result[3]
-                });
+            var fnName = null, fileAndLine;
+
+            var withFnResult = /^([^\s\(]+) \((.+:\d+)\)$/.exec(trace);
+            if (withFnResult === null) {
+                fileAndLine = trace;
+            } else {
+                fnName = withFnResult[1];
+                fileAndLine = withFnResult[2];
             }
+
+            var fileAndLineSplit = /^(.*):(\d+)$/.exec(fileAndLine);
+            var filePath = fileAndLineSplit[1];
+            var line = fileAndLineSplit[2];
+
+            out.push({
+                fnName: fnName,
+                filePath: filePath,
+                line: line
+            });
         });
         return out;
     }
 
-    $scope.filter = function(textFilter, scriptName) {
-
+    $scope.changeScript = function() {
+        initExecutionTree();
+        initTimeline();
+        initProfiler();
     };
 
     $scope.onNodeDetailsClick = function(node) {

+ 18 - 0
front/src/less/timeline.less

@@ -14,6 +14,23 @@
     text-align: center;
 }
 
+.selectScript {
+    padding-bottom: 2em;
+    font-size: 0.9em;
+
+    select {
+        max-width: 30em;
+    }
+
+    &.empty {
+        font-size: 0.8em;
+
+        select {
+            width: 10em;
+        }
+    }
+}
+
 .timeline {
     margin: 2em 0 5em;
 }
@@ -191,6 +208,7 @@ input.textFilter {
 
 .table > div > .index {
     color: #bbb;
+    word-break: normal;
 }
 
 .table > div > .type {

+ 8 - 1
front/src/views/timeline.html

@@ -1,5 +1,12 @@
 <div ng-include="'views/resultSubHeader.html'"></div>
 <div class="execution board">
+    <div class="selectScript" ng-class="{empty:!selectedScript}">
+        Filter timeline and profiler by script:
+        <select ng-model="selectedScript" ng-options="script.shortPath for script in scripts" ng-change="changeScript()">
+            <option value="">All (no filter)</option>
+        </select>
+    </div>
+
     <h2>Javascript Timeline</h2>
     <p>This graph gives a quick view of when the Javascript interactions with the DOM occur during the loading of the page.</p>
 
@@ -130,7 +137,7 @@
                         <div class="table">
                             <div ng-repeat="trace in node.parsedBacktrace track by $index">
                                 <div>{{trace.fnName || '(anonymous)'}}</div>
-                                <div class="trace"><a href="{{trace.filePath}}" title="{{trace.filePath}}" target="_blank">{{trace.fileName || 'HTML'}}</a>:{{trace.line}}</div>
+                                <div class="trace"><url-link url="trace.filePath" max-length="40"></url-link>:{{trace.line}}</div>
                             </div>
                             <div ng-if="node.parsedBacktrace.length == 0 && node.data.type != 'script loaded'">
                                 <div>can't find any backtrace :/</div>