CSSSelectorProfileView.js [plain text]
WebInspector.CSSSelectorDataGridNode = function(profileView, data)
{
WebInspector.DataGridNode.call(this, data, false);
this._profileView = profileView;
}
WebInspector.CSSSelectorDataGridNode.prototype = {
get data()
{
var data = {};
data.selector = this._data.selector;
data.matches = this._data.matchCount;
if (this._profileView.showTimeAsPercent.get())
data.time = Number(this._data.timePercent).toFixed(1) + "%";
else
data.time = Number.secondsToString(this._data.time / 1000, true);
return data;
},
get rawData()
{
return this._data;
},
createCell: function(columnIdentifier)
{
var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
if (columnIdentifier === "selector" && cell.firstChild) {
cell.firstChild.title = this.rawData.selector;
return cell;
}
if (columnIdentifier !== "source")
return cell;
cell.removeChildren();
if (this.rawData.url) {
var wrapperDiv = cell.createChild("div");
wrapperDiv.appendChild(WebInspector.linkifyResourceAsNode(this.rawData.url, this.rawData.lineNumber));
}
return cell;
}
}
WebInspector.CSSSelectorDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
WebInspector.CSSSelectorProfileView = function(profile)
{
WebInspector.View.call(this);
this.element.addStyleClass("profile-view");
this.showTimeAsPercent = WebInspector.settings.createSetting("selectorProfilerShowTimeAsPercent", true);
var columns = { "selector": { title: WebInspector.UIString("Selector"), width: "550px", sortable: true },
"source": { title: WebInspector.UIString("Source"), width: "100px", sortable: true },
"time": { title: WebInspector.UIString("Total"), width: "72px", sort: "descending", sortable: true },
"matches": { title: WebInspector.UIString("Matches"), width: "72px", sortable: true } };
this.dataGrid = new WebInspector.DataGrid(columns);
this.dataGrid.element.addStyleClass("selector-profile-view");
this.dataGrid.addEventListener("sorting changed", this._sortProfile, this);
this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
this.dataGrid.show(this.element);
this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item");
this.percentButton.addEventListener("click", this._percentClicked, this);
this.profile = profile;
this._createProfileNodes();
this._sortProfile();
this._updatePercentButton();
}
WebInspector.CSSSelectorProfileView.prototype = {
get statusBarItems()
{
return [this.percentButton.element];
},
get profile()
{
return this._profile;
},
set profile(profile)
{
this._profile = profile;
},
_createProfileNodes: function()
{
var data = this.profile.data;
if (!data) {
return;
}
this.profile.children = [];
for (var i = 0; i < data.length; ++i) {
data[i].timePercent = data[i].time * 100 / this.profile.totalTime;
var node = new WebInspector.CSSSelectorDataGridNode(this, data[i]);
this.profile.children.push(node);
}
},
rebuildGridItems: function()
{
this.dataGrid.rootNode().removeChildren();
var children = this.profile.children;
var count = children.length;
for (var index = 0; index < count; ++index)
this.dataGrid.rootNode().appendChild(children[index]);
},
refreshData: function()
{
var child = this.dataGrid.rootNode().children[0];
while (child) {
child.refresh();
child = child.traverseNextNode(false, null, true);
}
},
refreshShowAsPercents: function()
{
this._updatePercentButton();
this.refreshData();
},
_percentClicked: function(event)
{
this.showTimeAsPercent.set(!this.showTimeAsPercent.get());
this.refreshShowAsPercents();
},
_updatePercentButton: function()
{
if (this.showTimeAsPercent.get()) {
this.percentButton.title = WebInspector.UIString("Show absolute times.");
this.percentButton.toggled = true;
} else {
this.percentButton.title = WebInspector.UIString("Show times as percentages.");
this.percentButton.toggled = false;
}
},
_sortProfile: function()
{
var sortAscending = this.dataGrid.sortOrder === "ascending";
var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
function selectorComparator(a, b)
{
var result = b.rawData.selector.localeCompare(a.rawData.selector);
return sortAscending ? -result : result;
}
function sourceComparator(a, b)
{
var aRawData = a.rawData;
var bRawData = b.rawData;
var result = bRawData.url.localeCompare(aRawData.url);
if (!result)
result = bRawData.lineNumber - aRawData.lineNumber;
return sortAscending ? -result : result;
}
function timeComparator(a, b)
{
const result = b.rawData.time - a.rawData.time;
return sortAscending ? -result : result;
}
function matchesComparator(a, b)
{
const result = b.rawData.matchCount - a.rawData.matchCount;
return sortAscending ? -result : result;
}
var comparator;
switch (sortColumnIdentifier) {
case "time":
comparator = timeComparator;
break;
case "matches":
comparator = matchesComparator;
break;
case "selector":
comparator = selectorComparator;
break;
case "source":
comparator = sourceComparator;
break;
}
this.profile.children.sort(comparator);
this.rebuildGridItems();
},
_mouseDownInDataGrid: function(event)
{
if (event.detail < 2)
return;
var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
if (!cell)
return;
if (cell.hasStyleClass("time-column"))
this.showTimeAsPercent.set(!this.showTimeAsPercent.get());
else
return;
this.refreshShowAsPercents();
event.consume(true);
}
}
WebInspector.CSSSelectorProfileView.prototype.__proto__ = WebInspector.View.prototype;
WebInspector.CSSSelectorProfileType = function()
{
WebInspector.ProfileType.call(this, WebInspector.CSSSelectorProfileType.TypeId, WebInspector.UIString("Collect CSS Selector Profile"));
this._recording = false;
this._profileUid = 1;
WebInspector.CSSSelectorProfileType.instance = this;
}
WebInspector.CSSSelectorProfileType.TypeId = "SELECTOR";
WebInspector.CSSSelectorProfileType.prototype = {
get buttonTooltip()
{
return this._recording ? WebInspector.UIString("Stop CSS selector profiling.") : WebInspector.UIString("Start CSS selector profiling.");
},
buttonClicked: function()
{
if (this._recording)
this.stopRecordingProfile();
else
this.startRecordingProfile();
},
get treeItemTitle()
{
return WebInspector.UIString("CSS SELECTOR PROFILES");
},
get description()
{
return WebInspector.UIString("CSS selector profiles show how long the selector matching has taken in total and how many times a certain selector has matched DOM elements (the results are approximate due to matching algorithm optimizations.)");
},
reset: function()
{
this._profileUid = 1;
},
isRecordingProfile: function()
{
return this._recording;
},
setRecordingProfile: function(isProfiling)
{
this._recording = isProfiling;
},
startRecordingProfile: function()
{
this._recording = true;
CSSAgent.startSelectorProfiler();
WebInspector.panels.profiles.setRecordingProfile(WebInspector.CSSSelectorProfileType.TypeId, true);
},
stopRecordingProfile: function()
{
function callback(error, profile)
{
if (error)
return;
profile.uid = this._profileUid++;
profile.title = WebInspector.UIString("Profile %d", profile.uid) + String.sprintf(" (%s)", Number.secondsToString(profile.totalTime / 1000));
profile.typeId = WebInspector.CSSSelectorProfileType.TypeId;
WebInspector.panels.profiles.addProfileHeader(profile);
WebInspector.panels.profiles.setRecordingProfile(WebInspector.CSSSelectorProfileType.TypeId, false);
}
this._recording = false;
CSSAgent.stopSelectorProfiler(callback.bind(this));
},
createSidebarTreeElementForProfile: function(profile)
{
return new WebInspector.ProfileSidebarTreeElement(profile, profile.title, "profile-sidebar-tree-item");
},
createView: function(profile)
{
return new WebInspector.CSSSelectorProfileView(profile);
},
createTemporaryProfile: function()
{
return new WebInspector.ProfileHeader(WebInspector.CSSSelectorProfileType.TypeId, WebInspector.UIString("Recording\u2026"));
},
createProfile: function(profile)
{
return new WebInspector.ProfileHeader(profile.typeId, profile.title, profile.uid);
}
}
WebInspector.CSSSelectorProfileType.prototype.__proto__ = WebInspector.ProfileType.prototype;