Compare commits

...
32 Commits
Author SHA1 Message Date
Gaël Métais e67a0e0bc0 Merge pull request #81 from gmetais/develop
v1.6.0
2015-05-25 16:38:14 +02:00
Gaël Métais f553d45396 v1.6.0 2015-05-25 16:01:24 +02:00
Gaël Métais 090a53b95a Killing a Phantomas process will not kill YLT anymore 2015-05-25 15:57:01 +02:00
Gaël Métais 22ab7515fb Redirect www. to non-www (for SEO) 2015-05-25 15:01:21 +02:00
Gaël Métais a97dcc5efb Change the tweet-this message 2015-05-25 14:35:39 +02:00
Gaël Métais 4b098aef69 Fix timeline bug, not being displayed 2015-05-25 14:04:27 +02:00
Gaël Métais cb46274288 New rule: jQuery calls on empty objects 2015-05-25 13:33:26 +02:00
Gaël Métais 1e60a43075 Don't count duplicated queries on elements not attached to DOM 2015-05-25 11:42:47 +02:00
Gaël Métais 1aa9cd032f Update dependencies 2015-05-25 09:22:45 +02:00
Gaël Métais 5e3748315c Remove jQueryNotDelegatedEvents offenders and send user to filtered timeline 2015-05-25 09:22:25 +02:00
Gaël Métais 7f67c032d1 fix tests 2015-05-25 08:30:02 +02:00
Gaël Métais 33621af3ad Replaced DOMqueriesWithoutResults by queriesWithoutResults to include jQuery queries 2015-05-22 18:54:32 +02:00
Gaël Métais 2fb4a7bd6a Replace rules DOMinserts, DOMqueries & eventsBound by DOMaccesses 2015-05-22 17:47:13 +02:00
Gaël Métais 1ff983a03b Add specific sub-filters on warnings in the timeline 2015-05-22 17:44:54 +02:00
Gaël Métais 701530ef04 Be cooler on global variables 2015-05-22 11:16:18 +02:00
Gaël Métais 719e624ddf Fix icons showing a background grid on IE 2015-05-22 11:09:29 +02:00
Gaël Métais 03a25df367 One webfont is ok 2015-05-22 10:57:39 +02:00
Gaël Métais c93ce684a8 Old jQuery major versions didn't have the trailing .0 in number 2015-05-22 10:52:12 +02:00
Gaël Métais 090708f38b Merge branch 'HipsterBrown-url-input' into develop 2015-05-22 10:06:27 +02:00
Gaël Métais 49f93e660e User agent sniffing 2015-05-22 10:05:41 +02:00
Nick Hehr 867680f4e9 Updates LaunchTest() form text input to be of type "url".
Making this change not only adds automatic url validation from modern
browsers but enabled special keyboards on mobile devices to make
inputing urls much easier.
2015-05-20 10:31:34 -04:00
Gaël Métais 36ac529cc8 Improve doc 2015-05-13 19:29:26 +02:00
Gaël Métais 0ae388f0f6 Improve doc 2015-05-13 19:23:12 +02:00
Gaël Métais b53ace765c Improve doc 2015-05-13 19:13:38 +02:00
Gaël Métais f256299a0c Improve doc 2015-05-13 18:48:33 +02:00
Gaël Métais 4fb05e406a New doc test 2015-05-13 18:21:31 +02:00
Gaël Métais 035639c68a Improve doc 2015-05-13 09:12:21 +02:00
Gaël Métais 09f53cac92 Add ngrok in README 2015-05-12 13:57:45 +02:00
Gaël Métais 05a27d9003 v1.5.1 2015-05-12 11:43:09 +02:00
Gaël Métais 5d4d1807ba v1.5.1 2015-05-12 11:42:50 +02:00
Gaël Métais 836e465414 Fix bug with DOMaccessesOnScroll offenders 2015-05-12 11:38:05 +02:00
Gaël Métais 94457b24cd Small wording adjustment 2015-05-12 10:30:28 +02:00
43 changed files with 365 additions and 439 deletions
+59 -27
View File
@@ -1,39 +1,73 @@
# Yellow Lab Tools
<img src="./doc/img/logo.png" alt="Yellow Lab Tools"></img>
Online tool that lets you test a webpage and detects **performance** and **front-end code quality** issues.
[![Dependency Status](https://gemnasium.com/gmetais/YellowLabTools.svg)](https://gemnasium.com/gmetais/YellowLabTools) [![Build Status](https://travis-ci.org/gmetais/YellowLabTools.svg?branch=master)](https://travis-ci.org/gmetais/YellowLabTools)
Analyzes a webpage and detects **performance** or **front-end code quality** issues. Easy to launch, easy to understand, in-depth details.
### Access the tool here: [http://yellowlab.tools](http://yellowlab.tools)
#
<img src="./doc/img/commandment.png" alt="No website should go live without being tested with Yellow Lab Tools"></img>
<table>
<tr>
<td width="70%">
The <b>online tool</b> (recommended):
<a href="http://yellowlab.tools" target="_blank">http://yellowlab.tools</a>
</td>
<td width="30%">
<img src="./doc/img/YLT-animated.gif"></img>
</td>
</tr>
<tr>
<td width="70%">
The <b>CLI</b> (Command Line Interface) - <a href="https://github.com/gmetais/YellowLabTools/wiki/Command-Line-Interface" target="_blank">Doc here</a>
</td>
<td width="30%">
<img src="./doc/img/YLT-cli-animated.gif"></img>
</td>
</tr>
<tr>
<td width="70%">
The <b>Grunt task</b>: <a href="https://github.com/gmetais/grunt-yellowlabtools" traget="_blank">gmetais/grunt-yellowlabtools</a>
<br>For developers or Continuous Integration
</td>
<td width="30%">
<img src="./doc/img/grunt-logo.png"></img>
</td>
</tr>
<tr>
<td width="70%">
The <b>NodeJS</b> package - <a href="https://github.com/gmetais/YellowLabTools/wiki/NodeJS-module" target="_blank">Doc here</a>
</td>
<td width="30%">
<img src="./doc/img/npm-logo.png"></img>
</td>
</tr>
<tr>
<td width="70%">
The <b>public API</b> - <a href="https://github.com/gmetais/YellowLabTools/wiki/Public-API" target="_blank">Doc here</a>
<br>
Allows you to launch runs from any language
</td>
<td width="30%">
<img src="./doc/img/api-logo.png"></img>
</td>
</tr>
</table>
![example dashboard screenshot](screenshot.png)
## How it works
The tool loads the given URL via [PhantomJS](http://phantomjs.org/) (a headless browser) and collects various metrics and statistics with the help of [Phantomas](https://github.com/macbre/phantomas). These metrics are categorized and transformed into scores. It also gives in-depth details so developpers can correct the detected issues.
The tool loads the given URL via [PhantomJS](http://phantomjs.org/) (a headless browser) and collects various metrics and statistics with the help of [Phantomas](https://github.com/macbre/phantomas). These metrics are then categorized and transformed into scores. It also gives in-depth details so developpers can fix the detected issues.
By the way, it's free because we are geeks, not businessmen. All we want is a ★ on GitHub, it will boost our motivation to add more awesome features!!!
![example dashboard screenshot](./doc/img/screenshot.png)
## Different ways to use YLT
#### The web interface:
This is the best way to discover the tool: [http://yellowlab.tools](http://yellowlab.tools).
Please note the server is hosted in Baltimore, USA.
## Test your localhost
#### The Command Line Client:
Might be useful if you want to build an automation tool. The documentation is [here](https://github.com/gmetais/YellowLabTools/wiki/Command-Line-Interface).
#### The NPM module:
Can be used to build automation tools in NodeJS. The documentation is [here](https://github.com/gmetais/YellowLabTools/wiki/NodeJS-module).
#### The Public API:
Hosted on our http://yellowlab.tools server, it is a RESTful API that allows you to launch distant tests. The documentation is [here](https://github.com/gmetais/YellowLabTools/wiki/Public-API).
#### The Grunt task:
If you have a Continuous Integration platform, may I suggest you to use [grunt-yellowlabtools](https://github.com/gmetais/grunt-yellowlabtools)? You set it up once, then the task fails if the front-end quality conditions you defined are not met.
You can use [ngrok](https://ngrok.com/), a tool that creates a secure tunnel between your localhost and the online tool (or the public API). You can also use the CLI or the Grunt tasks as they run on your machine.
## Install your own private instance
@@ -41,18 +75,16 @@ If you have a Continuous Integration platform, may I suggest you to use [grunt-y
If your project is not accessible from outside, or if you want to fork and improve the tool, you can build your own instance. The documentation is [here](https://github.com/gmetais/YellowLabTools/wiki/Install-your-private-server).
## Help needed
## Help needed!
There are so many things left to do, **your help would be greatly appreciated**! Please report bugs, ask for evolutions and come code with me.
## License
Please read the [license](LICENSE).
Icons are the property of [IcoMoon.io](https://icomoon.io/)
Please read the [license](LICENSE). Icons are the property of [IcoMoon.io](https://icomoon.io/)
## Author
Gaël Métais. I'm a webperf freelance based in Paris. If you understand french, you can visit [my website](http://www.gaelmetais.com).
Gaël Métais. I'm a webperf freelance based in Paris. If you understand French, you can visit [my website](http://www.gaelmetais.com).
## Contributors
+2
View File
@@ -7,12 +7,14 @@ var cors = require('cors');
var authMiddleware = require('../lib/server/middlewares/authMiddleware');
var apiLimitsMiddleware = require('../lib/server/middlewares/apiLimitsMiddleware');
var wwwRedirectMiddleware = require('../lib/server/middlewares/wwwRedirectMiddleware');
// Middlewares
app.use(compress());
app.use(bodyParser.json());
app.use(cors());
app.use(wwwRedirectMiddleware);
app.use(authMiddleware);
app.use(apiLimitsMiddleware);
Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+24 -2
View File
@@ -143,6 +143,10 @@
border: 1px dotted #aaa;
text-align: left;
}
.subFilters {
margin-left: 3em;
font-size: 0.9em;
}
.table {
display: table;
width: 100%;
@@ -306,9 +310,27 @@
color: #e74c3c;
cursor: pointer;
}
.warningsFilterOn > div {
.queryWithoutResultsFilterOn > div {
display: none;
}
.warningsFilterOn > div.warning {
.queryWithoutResultsFilterOn > div.queryWithoutResults {
display: table-row;
}
.jQueryCallOnEmptyObjectFilterOn > div {
display: none;
}
.jQueryCallOnEmptyObjectFilterOn > div.jQueryCallOnEmptyObject {
display: table-row;
}
.eventNotDelegatedFilterOn > div {
display: none;
}
.eventNotDelegatedFilterOn > div.eventNotDelegated {
display: table-row;
}
.jsErrorFilterOn > div {
display: none;
}
.jsErrorFilterOn > div.jsError {
display: table-row;
}
+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 256.00,0.00C 397.385,0.00, 512.00,114.615, 512.00,256.00s -114.615,256.00, -256.00,256.00s -256.00-114.615, -256.00-256.00S 114.615,0.00, 256.00,0.00z M 256.00,464.00 c 114.875,0.00 208.00-93.125 208.00-208.00S 370.875,48.00, 256.00,48.00s -208.00,93.125, -208.00,208.00S 141.125,464.00, 256.00,464.00zM 105.372,233.373l 128.001-128.00c 12.496-12.497 32.757-12.497 45.254,0.00c 12.497,12.497 12.497,32.758,0.00,45.255L 205.255,224.00 L 384.00,224.00 c 17.673,0.00 32.00,14.327 32.00,32.00c0.00,17.673, -14.327,32.00, -32.00,32.00l-178.745,0.00 l 73.373,73.372c 12.497,12.497 12.497,32.759,0.00,45.256 C 272.379,412.876, 264.189,416.00, 256.00,416.00s -16.379-3.124, -22.627-9.372l -128.001-128.00C 92.876,266.131, 92.876,245.869, 105.372,233.373z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 256.00,0.00C 397.385,0.00, 512.00,114.615, 512.00,256.00s -114.615,256.00, -256.00,256.00s -256.00-114.615, -256.00-256.00S 114.615,0.00, 256.00,0.00z M 256.00,464.00 c 114.875,0.00 208.00-93.125 208.00-208.00S 370.875,48.00, 256.00,48.00s -208.00,93.125, -208.00,208.00S 141.125,464.00, 256.00,464.00zM 105.372,233.373l 128.001-128.00c 12.496-12.497 32.757-12.497 45.254,0.00c 12.497,12.497 12.497,32.758,0.00,45.255L 205.255,224.00 L 384.00,224.00 c 17.673,0.00 32.00,14.327 32.00,32.00c0.00,17.673, -14.327,32.00, -32.00,32.00l-178.745,0.00 l 73.373,73.372c 12.497,12.497 12.497,32.759,0.00,45.256 C 272.379,412.876, 264.189,416.00, 256.00,416.00s -16.379-3.124, -22.627-9.372l -128.001-128.00C 92.876,266.131, 92.876,245.869, 105.372,233.373z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M0.00,416.00L 512.00,416.00L 512.00,480.00L0.00,480.00zM 64.00,288.00L 128.00,288.00L 128.00,384.00L 64.00,384.00zM 160.00,160.00L 224.00,160.00L 224.00,384.00L 160.00,384.00zM 256.00,256.00L 320.00,256.00L 320.00,384.00L 256.00,384.00zM 352.00,64.00L 416.00,64.00L 416.00,384.00L 352.00,384.00z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M0.00,416.00L 512.00,416.00L 512.00,480.00L0.00,480.00zM 64.00,288.00L 128.00,288.00L 128.00,384.00L 64.00,384.00zM 160.00,160.00L 224.00,160.00L 224.00,384.00L 160.00,384.00zM 256.00,256.00L 320.00,256.00L 320.00,384.00L 256.00,384.00zM 352.00,64.00L 416.00,64.00L 416.00,384.00L 352.00,384.00z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 634 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 478.145,402.241L 320.00,138.729L 320.00,32.00 l 16.00,0.00 c 8.80,0.00, 16.00-7.20, 16.00-16.00s-7.20-16.00-16.00-16.00L 176.00,0.00 c-8.80,0.00-16.00,7.20-16.00,16.00s 7.20,16.00, 16.00,16.00l 16.00,0.00 l0.00,106.729 L 33.856,402.241C-2.365,462.608, 25.60,512.00, 96.00,512.00l 320.00,0.00 C 486.40,512.00, 514.365,462.608, 478.145,402.241z M 120.519,320.00L 224.00,147.531L 224.00,32.00 l 64.00,0.00 l0.00,115.531 L 391.482,320.00L 120.519,320.00 z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 478.145,402.241L 320.00,138.729L 320.00,32.00 l 16.00,0.00 c 8.80,0.00, 16.00-7.20, 16.00-16.00s-7.20-16.00-16.00-16.00L 176.00,0.00 c-8.80,0.00-16.00,7.20-16.00,16.00s 7.20,16.00, 16.00,16.00l 16.00,0.00 l0.00,106.729 L 33.856,402.241C-2.365,462.608, 25.60,512.00, 96.00,512.00l 320.00,0.00 C 486.40,512.00, 514.365,462.608, 478.145,402.241z M 120.519,320.00L 224.00,147.531L 224.00,32.00 l 64.00,0.00 l0.00,115.531 L 391.482,320.00L 120.519,320.00 z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 792 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M0.00,0.00L 128.00,0.00L 128.00,128.00L0.00,128.00zM 192.00,32.00L 512.00,32.00L 512.00,96.00L 192.00,96.00zM0.00,192.00L 128.00,192.00L 128.00,320.00L0.00,320.00zM 192.00,224.00L 512.00,224.00L 512.00,288.00L 192.00,288.00zM0.00,384.00L 128.00,384.00L 128.00,512.00L0.00,512.00zM 192.00,416.00L 512.00,416.00L 512.00,480.00L 192.00,480.00z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M0.00,0.00L 128.00,0.00L 128.00,128.00L0.00,128.00zM 192.00,32.00L 512.00,32.00L 512.00,96.00L 192.00,96.00zM0.00,192.00L 128.00,192.00L 128.00,320.00L0.00,320.00zM 192.00,224.00L 512.00,224.00L 512.00,288.00L 192.00,288.00zM0.00,384.00L 128.00,384.00L 128.00,512.00L0.00,512.00zM 192.00,416.00L 512.00,416.00L 512.00,480.00L 192.00,480.00z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 679 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 437.011,74.99C 390.685,28.662, 326.693,0.00, 256.00,0.00C 146.256,0.00, 52.655,69.064, 16.251,166.094l 59.938,22.477 C 103.491,115.798, 173.692,64.00, 256.00,64.00c 53.02,0.00, 101.01,21.50, 135.753,56.247L 320.00,192.00l 192.00,0.00 L 512.00,0.00 L 437.011,74.99zM 256.00,448.00c-53.02,0.00-101.013-21.496-135.756-56.244L 192.00,320.00L0.00,320.00 l0.00,192.00 l 74.997-74.997C 121.32,483.334, 185.306,512.00, 256.00,512.00 c 109.745,0.00, 203.346-69.064, 239.75-166.094l-59.938-22.477C 408.51,396.202, 338.309,448.00, 256.00,448.00z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 437.011,74.99C 390.685,28.662, 326.693,0.00, 256.00,0.00C 146.256,0.00, 52.655,69.064, 16.251,166.094l 59.938,22.477 C 103.491,115.798, 173.692,64.00, 256.00,64.00c 53.02,0.00, 101.01,21.50, 135.753,56.247L 320.00,192.00l 192.00,0.00 L 512.00,0.00 L 437.011,74.99zM 256.00,448.00c-53.02,0.00-101.013-21.496-135.756-56.244L 192.00,320.00L0.00,320.00 l0.00,192.00 l 74.997-74.997C 121.32,483.334, 185.306,512.00, 256.00,512.00 c 109.745,0.00, 203.346-69.064, 239.75-166.094l-59.938-22.477C 408.51,396.202, 338.309,448.00, 256.00,448.00z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 875 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 368.00,0.00L 144.00,0.00 c-26.40,0.00-48.00,21.60-48.00,48.00l0.00,416.00 c0.00,26.40, 21.60,48.00, 48.00,48.00l 224.00,0.00 c 26.40,0.00, 48.00-21.60, 48.00-48.00L 416.00,48.00 C 416.00,21.60, 394.40,0.00, 368.00,0.00z M 192.00,24.00 l 128.00,0.00 l0.00,16.00 L 192.00,40.00 L 192.00,24.00 z M 256.00,480.00c-17.673,0.00-32.00-14.327-32.00-32.00s 14.327-32.00, 32.00-32.00s 32.00,14.327, 32.00,32.00S 273.673,480.00, 256.00,480.00z M 384.00,384.00L 128.00,384.00 L 128.00,64.00 l 256.00,0.00 L 384.00,384.00 z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 368.00,0.00L 144.00,0.00 c-26.40,0.00-48.00,21.60-48.00,48.00l0.00,416.00 c0.00,26.40, 21.60,48.00, 48.00,48.00l 224.00,0.00 c 26.40,0.00, 48.00-21.60, 48.00-48.00L 416.00,48.00 C 416.00,21.60, 394.40,0.00, 368.00,0.00z M 192.00,24.00 l 128.00,0.00 l0.00,16.00 L 192.00,40.00 L 192.00,24.00 z M 256.00,480.00c-17.673,0.00-32.00-14.327-32.00-32.00s 14.327-32.00, 32.00-32.00s 32.00,14.327, 32.00,32.00S 273.673,480.00, 256.00,480.00z M 384.00,384.00L 128.00,384.00 L 128.00,64.00 l 256.00,0.00 L 384.00,384.00 z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 851 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 224.00,352.00L 288.00,352.00L 288.00,416.00L 224.00,416.00zM 352.00,128.00 C 369.673,128.00 384.00,142.327 384.00,160.00 L 384.00,256.00 L 288.00,320.00 L 224.00,320.00 L 224.00,288.00 L 320.00,224.00 L 320.00,192.00 L 160.00,192.00 L 160.00,128.00 L 352.00,128.00 ZM 256.00,48.00 C 200.441,48.00 148.208,69.636 108.922,108.922 C 69.636,148.208 48.00,200.441 48.00,256.00 C 48.00,311.559 69.636,363.792 108.922,403.078 C 148.208,442.364 200.441,464.00 256.00,464.00 C 311.559,464.00 363.792,442.364 403.078,403.078 C 442.364,363.792 464.00,311.559 464.00,256.00 C 464.00,200.441 442.364,148.208 403.078,108.922 C 363.792,69.636 311.559,48.00 256.00,48.00 Z M 256.00,0.00 L 256.00,0.00 C 397.385,0.00 512.00,114.615 512.00,256.00 C 512.00,397.385 397.385,512.00 256.00,512.00 C 114.615,512.00 0.00,397.385 0.00,256.00 C 0.00,114.615 114.615,0.00 256.00,0.00 Z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 224.00,352.00L 288.00,352.00L 288.00,416.00L 224.00,416.00zM 352.00,128.00 C 369.673,128.00 384.00,142.327 384.00,160.00 L 384.00,256.00 L 288.00,320.00 L 224.00,320.00 L 224.00,288.00 L 320.00,224.00 L 320.00,192.00 L 160.00,192.00 L 160.00,128.00 L 352.00,128.00 ZM 256.00,48.00 C 200.441,48.00 148.208,69.636 108.922,108.922 C 69.636,148.208 48.00,200.441 48.00,256.00 C 48.00,311.559 69.636,363.792 108.922,403.078 C 148.208,442.364 200.441,464.00 256.00,464.00 C 311.559,464.00 363.792,442.364 403.078,403.078 C 442.364,363.792 464.00,311.559 464.00,256.00 C 464.00,200.441 442.364,148.208 403.078,108.922 C 363.792,69.636 311.559,48.00 256.00,48.00 Z M 256.00,0.00 L 256.00,0.00 C 397.385,0.00 512.00,114.615 512.00,256.00 C 512.00,397.385 397.385,512.00 256.00,512.00 C 114.615,512.00 0.00,397.385 0.00,256.00 C 0.00,114.615 114.615,0.00 256.00,0.00 Z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 512.00,416.00L 512.00,32.00 L0.00,32.00 l0.00,384.00 l 224.00,0.00 l0.00,32.00 l-96.00,0.00 l0.00,32.00 l 256.00,0.00 l0.00-32.00 l-96.00,0.00 l0.00-32.00 L 512.00,416.00 z M 64.00,96.00l 384.00,0.00 l0.00,256.00 L 64.00,352.00 L 64.00,96.00 z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 512.00,416.00L 512.00,32.00 L0.00,32.00 l0.00,384.00 l 224.00,0.00 l0.00,32.00 l-96.00,0.00 l0.00,32.00 l 256.00,0.00 l0.00-32.00 l-96.00,0.00 l0.00-32.00 L 512.00,416.00 z M 64.00,96.00l 384.00,0.00 l0.00,256.00 L 64.00,352.00 L 64.00,96.00 z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 584 B

+1 -1
View File
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 400.00,0.00L 80.00,0.00 C 53.60,0.00, 32.00,21.60, 32.00,48.00l0.00,416.00 c0.00,26.40, 21.60,48.00, 48.00,48.00l 320.00,0.00 c 26.40,0.00, 48.00-21.60, 48.00-48.00L 448.00,48.00 C 448.00,21.60, 426.40,0.00, 400.00,0.00z M 240.00,496.00 c-8.836,0.00-16.00-7.163-16.00-16.00s 7.164-16.00, 16.00-16.00s 16.00,7.163, 16.00,16.00S 248.836,496.00, 240.00,496.00z M 384.00,448.00L 96.00,448.00 L 96.00,64.00 l 288.00,0.00 L 384.00,448.00 z" ></path></svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 400.00,0.00L 80.00,0.00 C 53.60,0.00, 32.00,21.60, 32.00,48.00l0.00,416.00 c0.00,26.40, 21.60,48.00, 48.00,48.00l 320.00,0.00 c 26.40,0.00, 48.00-21.60, 48.00-48.00L 448.00,48.00 C 448.00,21.60, 426.40,0.00, 400.00,0.00z M 240.00,496.00 c-8.836,0.00-16.00-7.163-16.00-16.00s 7.164-16.00, 16.00-16.00s 16.00,7.163, 16.00,16.00S 248.836,496.00, 240.00,496.00z M 384.00,448.00L 96.00,448.00 L 96.00,64.00 l 288.00,0.00 L 384.00,448.00 z" ></path></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 774 B

+1 -3
View File
@@ -1,3 +1 @@
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g class="svgGrid" id="svgGrid"><line stroke-width="1" stroke="#B35047" x1="32" x2="32" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="64" x2="64" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="96" x2="96" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="128" x2="128" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="160" x2="160" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="192" x2="192" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="224" x2="224" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="256" x2="256" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="288" x2="288" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="320" x2="320" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="352" x2="352" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="384" x2="384" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="416" x2="416" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="448" x2="448" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="480" x2="480" y1="0" y2="512"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="32" y2="32"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="64" y2="64"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="96" y2="96"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="128" y2="128"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="160" y2="160"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="192" y2="192"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="224" y2="224"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="256" y2="256"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="288" y2="288"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="320" y2="320"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="352" y2="352"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="384" y2="384"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="416" y2="416"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="448" y2="448"></line><line stroke-width="1" stroke="#B35047" x1="0" x2="512" y1="480" y2="480"></line></g><path d="M 256.00,79.362 L 83.583,448.00 L 428.417,448.00 L 256.00,79.362 Z M 256.00,0.00 L 256.00,0.00 C 267.035,0.00 278.07,7.441 286.442,22.324 L 504.978,457.88 C 521.723,487.646 507.478,512.00 473.327,512.00 L 38.673,512.00 C 4.521,512.00 -9.722,487.646 7.021,457.88 L 225.558,22.324 C 233.93,7.441 244.965,0.00 256.00,0.00 ZM 256.00,192.00 C 273.673,192.00 288.00,206.327 288.00,224.00 L 278.00,320.00 L 234.00,320.00 L 224.00,224.00 C 224.00,206.327 238.327,192.00 256.00,192.00 Z" ></path>
<circle cx="256" cy="384" r="31" style="stroke:#000000; fill:#000000"/>
</svg>
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><path d="M 256.00,79.362 L 83.583,448.00 L 428.417,448.00 L 256.00,79.362 Z M 256.00,0.00 L 256.00,0.00 C 267.035,0.00 278.07,7.441 286.442,22.324 L 504.978,457.88 C 521.723,487.646 507.478,512.00 473.327,512.00 L 38.673,512.00 C 4.521,512.00 -9.722,487.646 7.021,457.88 L 225.558,22.324 C 233.93,7.441 244.965,0.00 256.00,0.00 ZM 256.00,192.00 C 273.673,192.00 288.00,206.327 288.00,224.00 L 278.00,320.00 L 234.00,320.00 L 224.00,224.00 C 224.00,206.327 238.327,192.00 256.00,192.00 Z" ></path><circle cx="256" cy="384" r="31" style="stroke:#000000; fill:#000000"/></svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 887 B

+12
View File
@@ -19,8 +19,20 @@ var yltApp = angular.module('YellowLabTools', [
]);
yltApp.run(['$rootScope', '$location', function($rootScope, $location) {
$rootScope.isTouchDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(window.navigator.userAgent);
$rootScope.loadedRunId = null;
var oldHash;
// We don't want the hash to be kept between two pages
$rootScope.$on('$locationChangeStart', function(param1, param2, param3, param4){
var newHash = $location.hash();
if (newHash === oldHash) {
$location.hash(null);
}
oldHash = newHash;
});
// Google Analytics
$rootScope.$on('$routeChangeSuccess', function(){
ga('send', 'pageview', {'page': $location.path()});
+4 -5
View File
@@ -25,8 +25,7 @@ dashboardCtrl.controller('DashboardCtrl', ['$scope', '$rootScope', '$routeParams
// By default, Angular sorts object's attributes alphabetically. Countering this problem by retrieving the keys order here.
$scope.categoriesOrder = Object.keys($scope.result.scoreProfiles.generic.categories);
$scope.globalScore = Math.max($scope.result.scoreProfiles.generic.globalScore, 0);
$scope.tweetText = 'My website\'s score is ' + $scope.globalScore + '/100 on #YellowLabTools!';
$scope.tweetText = 'I\'ve discovered this cool open-source tool that audits the front-end quality of a web page: ';
}
$scope.showRulePage = function(ruleName) {
@@ -37,18 +36,18 @@ dashboardCtrl.controller('DashboardCtrl', ['$scope', '$rootScope', '$routeParams
API.relaunchTest($scope.result);
};
/// When comming from a social shared link, the user needs to click on "See full report" button to display the full dashboard.
// When comming from a social shared link, the user needs to click on "See full report" button to display the full dashboard.
$scope.seeFullReport = function() {
$scope.fromSocialShare = false;
$location.search({});
};
$scope.shareOnTwitter = function(message) {
openSocialPopup('https://twitter.com/intent/tweet?url=' + document.URL + '%3Fshare&text=' + encodeURIComponent(message));
openSocialPopup('https://twitter.com/intent/tweet?text=' + encodeURIComponent(message + 'http://yellowlab.tools'));
};
$scope.shareOnLinkedin = function(message) {
openSocialPopup('https://www.linkedin.com/shareArticle?mini=true&url=' + document.URL + '%3Fshare&title=' + encodeURIComponent(message) + '&summary=' + encodeURIComponent('YellowLabTools is a free online tool that analyzes performance and front-end quality of a webpage.'));
openSocialPopup('https://www.linkedin.com/shareArticle?mini=true&url=http://yellowlab.tools&title=' + encodeURIComponent(message) + '&summary=' + encodeURIComponent('YellowLabTools is a free online tool that analyzes performance and front-end quality of a webpage.'));
};
function openSocialPopup(url) {
+18
View File
@@ -19,12 +19,30 @@ timelineCtrl.controller('TimelineCtrl', ['$scope', '$rootScope', '$routeParams',
}
function render() {
initFilters();
initScriptFiltering();
initExecutionTree();
initTimeline();
$timeout(initProfiler, 100);
}
function initFilters() {
var hash = $location.hash();
var filter = null;
if (hash.indexOf('filter=') === 0) {
filter = hash.substr(7);
}
$scope.warningsFilterOn = (filter !== null);
$scope.warningsFilters = {
queryWithoutResults: (filter === null || filter === 'queryWithoutResults'),
jQueryCallOnEmptyObject: (filter === null || filter === 'jQueryCallOnEmptyObject'),
eventNotDelegated: (filter === null || filter === 'eventNotDelegated'),
jsError: (filter === null || filter === 'jsError')
};
}
function initScriptFiltering() {
var offenders = $scope.result.rules.jsCount.offendersObj.list;
$scope.scripts = [];
+14 -1
View File
@@ -766,10 +766,23 @@
element.append(getProfilerLineHTML(scope.index, scope.node));
element[0].id = 'line_' + scope.index;
if (scope.node.warning || scope.node.error) {
if (scope.node.warning) {
element[0].classList.add('warning');
if (scope.node.queryWithoutResults) {
element[0].classList.add('queryWithoutResults');
}
if (scope.node.jQueryCallOnEmptyObject) {
element[0].classList.add('jQueryCallOnEmptyObject');
}
if (scope.node.eventNotDelegated) {
element[0].classList.add('eventNotDelegated');
}
}
// Bind click on the details icon
var detailsIcon = element[0].querySelector('.details div');
if (detailsIcon) {
File diff suppressed because one or more lines are too long
+31 -2
View File
@@ -162,6 +162,11 @@
text-align: left;
}
.subFilters {
margin-left: 3em;
font-size: 0.9em;
}
.table {
display: table;
width: 100%;
@@ -346,10 +351,34 @@
color: #e74c3c;
cursor: pointer;
}
.warningsFilterOn {
.queryWithoutResultsFilterOn {
> div {
display: none;
&.warning {
&.queryWithoutResults {
display: table-row;
}
}
}
.jQueryCallOnEmptyObjectFilterOn {
> div {
display: none;
&.jQueryCallOnEmptyObject {
display: table-row;
}
}
}
.eventNotDelegatedFilterOn {
> div {
display: none;
&.eventNotDelegated {
display: table-row;
}
}
}
.jsErrorFilterOn {
> div {
display: none;
&.jsError {
display: table-row;
}
}
+2 -2
View File
@@ -2,7 +2,7 @@
<p class="price">Free and open source!</p>
<form ng-submit="launchTest()" >
<input type="text" name="url" ng-model="url" placeholder="http://www.mysite.com" class="url" />
<input type="{{$root.isTouchDevice? 'url' : 'text'}}" name="url" ng-model="url" placeholder="http://www.mysite.com" class="url" />
<input type="submit" value="Launch test" class="launchBtn" ng-class="{disabled: !url}" />
<div class="settings">
<div class="device">
@@ -90,4 +90,4 @@
<h3>JS Profiling</h3>
<p>Untangles the JavaScript spaghetti code</p>
</div>
</div>
</div>
+22 -30
View File
@@ -31,22 +31,10 @@
<b>{{offender.id}}</b>: {{offender.occurrences}} occurrences
</div>
<div ng-if="policyName === 'DOMinserts'">
<dom-element-button obj="offender.insertedElement"></dom-element-button> appended to <dom-element-button obj="offender.receiverElement"></dom-element-button>
</div>
<div ng-if="policyName === 'DOMqueriesWithoutResults'">
<b>{{offender.query}}</b> (in <dom-element-button obj="offender.context"></dom-element-button>) using {{offender.fn}}
</div>
<div ng-if="policyName === 'DOMqueriesAvoidable'">
<b>{{offender.query}}</b> (in <dom-element-button obj="offender.context"></dom-element-button>) using {{offender.fn}}: <b>{{offender.count}} queries</b>
</div>
<div ng-if="policyName === 'eventsBound'">
<b>{{offender.eventName}}</b> bound to <dom-element-button obj="offender.element"></dom-element-button>
</div>
<div ng-if="policyName === 'eventsScrollBound'">
<span ng-if="offender.target == 'window'">Scroll event bound on <b>window</b></span>
<span ng-if="offender.target == '#document'">Scroll event bound on <b>document</b></span>
@@ -80,22 +68,7 @@
</div>
<div ng-if="policyName === 'jQueryFunctionsUsed'">
Function <b>{{offender.functionName}}</b> used {{offender.count}} times
</div>
<div ng-if="policyName === 'jQueryNotDelegatedEvents'">
function <b>{{offender.functionName}}</b> used on {{offender.contextLength}} DOM elements without event delegation
<div class="offenderButton" ng-if="offender.backtrace.length == 0">no backtrace</div>
<div class="offenderButton opens" ng-if="offender.backtrace.length > 0">
backtrace
<div class="backtrace">
<div ng-repeat="obj in offender.backtrace track by $index">
<span ng-if="obj.functionName">{{obj.functionName}}()</span>
<url-link url="obj.file" max-length="60"></url-link>
line {{obj.line}}
</div>
</div>
</div>
function <b>{{offender.functionName}}</b> used {{offender.count}} times
</div>
<div ng-if="policyName === 'documentWriteCalls'">
@@ -218,10 +191,29 @@
<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>
<div ng-if="policyName === 'DOMaccesses'">
<h3>{{rule.value}} offenders</h3>
Please open the <a href="/result/{{runId}}/timeline">JS timeline</a>
</div>
<div ng-if="policyName === 'queriesWithoutResults'">
<h3>{{rule.value}} offenders</h3>
Please open the <a href="/result/{{runId}}/timeline#filter=queryWithoutResults">JS timeline, filtered by "Queries without results"</a>
</div>
<div ng-if="policyName === 'jQueryCallsOnEmptyObject'">
<h3>{{rule.value}} offenders</h3>
Please open the <a href="/result/{{runId}}/timeline#filter=jQueryCallOnEmptyObject">JS timeline, filtered by "jQuery calls on empty object"</a>
</div>
<div ng-if="policyName === 'jQueryNotDelegatedEvents'">
<h3>{{rule.value}} offenders</h3>
Please open the <a href="/result/{{runId}}/timeline#filter=eventNotDelegated">JS timeline, filtered by "Events not delegated"</a>
</div>
<div ng-if="!rule && rule !== null" class="notFound">
<h2>404</h2>
Rule "{{policyName}}"" not found
+30 -11
View File
@@ -16,14 +16,14 @@
<div ng-repeat="duration in timeline track by $index"
class="interval"
ng-class="{
domCreation: $index * timelineIntervalDuration < result.toolsResults.phantomas.metrics.domInteractive,
domInteractive: $index * timelineIntervalDuration >= result.toolsResults.phantomas.metrics.domInteractive
&& $index * timelineIntervalDuration < result.toolsResults.phantomas.metrics.domContentLoaded,
domContentLoaded: $index * timelineIntervalDuration >= result.toolsResults.phantomas.metrics.domContentLoaded
&& $index * timelineIntervalDuration < result.toolsResults.phantomas.metrics.domContentLoadedEnd,
domContentLoadedEnd: $index * timelineIntervalDuration >= result.toolsResults.phantomas.metrics.domContentLoadedEnd
&& $index * timelineIntervalDuration < result.toolsResults.phantomas.metrics.domComplete,
domComplete: $index * timelineIntervalDuration >= result.toolsResults.phantomas.metrics.domComplete
domCreation: $index * timelineIntervalDuration < result.javascriptExecutionTree.data.domInteractive,
domInteractive: $index * timelineIntervalDuration >= result.javascriptExecutionTree.data.domInteractive
&& $index * timelineIntervalDuration < result.javascriptExecutionTree.data.domContentLoaded,
domContentLoaded: $index * timelineIntervalDuration >= result.javascriptExecutionTree.data.domContentLoaded
&& $index * timelineIntervalDuration < result.javascriptExecutionTree.data.domContentLoadedEnd,
domContentLoadedEnd: $index * timelineIntervalDuration >= result.javascriptExecutionTree.data.domContentLoadedEnd
&& $index * timelineIntervalDuration < result.javascriptExecutionTree.data.domComplete,
domComplete: $index * timelineIntervalDuration >= result.javascriptExecutionTree.data.domComplete
}">
<div style="height: {{100 * duration / timelineMax | number: 0}}px" class="color" ng-class="{clickable: duration > 0}" scroll-on-click="{{$index * timelineIntervalDuration}}"></div>
<div class="tooltip detailsOverlay">
@@ -60,11 +60,30 @@
</p>
<div class="filters">
<div>
<input type="checkbox" ng-model="warningsFilterOn" id="warningsFilterOn" />
<label for="warningsFilterOn">Show warnings only</label>
<input type="checkbox" name="warningsFilter" ng-model="warningsFilterOn" id="warningsFilterOn" />
<label for="warningsFilterOn">Filter on warnings and errors</label>
<div class="subFilters" ng-if="warningsFilterOn">
<div>
<input type="checkbox" name="filters" ng-model="warningsFilters.queryWithoutResults" id="queryWithoutResultsFilterOn"/>
<label for="queryWithoutResultsFilterOn">Queries without results</label>
</div>
<div>
<input type="checkbox" name="filters" ng-model="warningsFilters.jQueryCallOnEmptyObject" id="jQueryCallOnEmptyObjectFilterOn" />
<label for="jQueryCallOnEmptyObjectFilterOn">jQuery calls on empty object</label>
</div>
<div>
<input type="checkbox" name="filters" ng-model="warningsFilters.eventNotDelegated" id="eventNotDelegatedFilterOn" />
<label for="eventNotDelegatedFilterOn">Events not delegated</label>
</div>
<div>
<input type="checkbox" name="filters" ng-model="warningsFilters.jsError" id="jsErrorFilterOn" />
<label for="jsErrorFilterOn">Errors</label>
</div>
</div>
</div>
{{queryWithoutResultsFilterOn}}
</div>
<div class="table" ng-class="{warningsFilterOn: warningsFilterOn}">
<div class="table" ng-class="{queryWithoutResultsFilterOn: warningsFilterOn && warningsFilters.queryWithoutResults, jQueryCallOnEmptyObjectFilterOn: warningsFilterOn && warningsFilters.jQueryCallOnEmptyObject, eventNotDelegatedFilterOn: warningsFilterOn && warningsFilters.eventNotDelegated, jsErrorFilterOn: warningsFilterOn && warningsFilters.jsError}">
<div class="headers">
<div><!-- index --></div>
<div>Type</div>
+29 -108
View File
@@ -66,82 +66,23 @@ var policies = {
};
}
},
/*"DOMaccesses": {
"DOMaccesses": {
"tool": "jsExecutionTransformer",
"label": "DOM access",
"message": "<p>TODO</p><p>TODO</p>",
"message": "<p>This metric counts the number of calls to DOM related functions (both native DOM functions and jQuery functions) on page load.</p><p>The more your JavaScript code accesses the DOM, the slower the page will load.</p><p>Try, as much as possible, to have an HTML page fully generated by the server instead of making changes with JS.</p><p>Try to reduce the number of queries by refactoring your JavaScript code.</p><p>Binding too many events also has a cost. Try to use <a href=\"https://learn.jquery.com/events/event-delegation/\" target=\"_blank\">event delegation</a> as much as possible.</p>",
"isOkThreshold": 50,
"isBadThreshold": 2000,
"isBadThreshold": 1500,
"isAbnormalThreshold": 3000,
"hasOffenders": false
},*/
"DOMinserts": {
"tool": "phantomas",
"label": "DOM inserts",
"message": "<p>Working with the DOM in JavaScript triggers layout calculations and slows down the page.</p><p>Try, as much as possible, to have an HTML page fully generated by the server instead of making changes with JS.</p>",
"isOkThreshold": 10,
"isBadThreshold": 400,
"isAbnormalThreshold": 1000,
"hasOffenders": true,
"offendersTransformFn": function(offenders) {
return {
count: offenders.length,
list: offenders.map(function(offender) {
var parts = /^"(.*)" ?appended ?to ?"(.*)"$/.exec(offender);
if (!parts) {
debug('DOMinserts offenders transform function error with "%s"', offender);
return {
parseError: offender
};
}
return {
insertedElement: offendersHelpers.domPathToDomElementObj(parts[1]),
receiverElement: offendersHelpers.domPathToDomElementObj(parts[2])
};
})
};
}
},
"DOMqueries": {
"tool": "phantomas",
"label": "DOM queries",
"message": "<p>DOM queries are like looking in a large catalog of items. Even if the browsers made progress on the performances of queries, websites often make hundreds of them.</p><p>Try to reduce the number of queries by refactoring your JavaScript code.</p><p>Avoid also to have a read query between two write queries. To be able to reduce the number repaints and optimize performances, browsers buffer the DOM writing operations and treat them in bulk. But each time a DOM reading is asked, the browser needs to empty the buffer. This can be particularly slow inside a loop.</p>",
"isOkThreshold": 50,
"isBadThreshold": 1000,
"isAbnormalThreshold": 2000,
"hasOffenders": false
},
"DOMqueriesWithoutResults": {
"tool": "phantomas",
"label": "DOM queries without result",
"message": "<p>Number of queries that return no result.</p><p>It suggests the query is not used on the page, probably because it is some dead code.</p><p>Or maybe the code is trying to find an HTML block that is not always here. Look at the JS Timeline to see if the scripts correctly figures out the HTML block is not here and immediatly stops interacting further with the DOM.</p>",
"queriesWithoutResults": {
"tool": "jsExecutionTransformer",
"label": "Queries without result",
"message": "<p>Number of queries that return no result. Both native and jQuery DOM requests are counted.</p><p>It suggests the query is not used on the page, probably because it is some dead code.</p><p>Or maybe the code is trying to find an HTML block that is not always here. Look at the JS Timeline to see if the scripts correctly figures out the HTML block is not here and immediatly stops interacting further with the DOM.</p>",
"isOkThreshold": 0,
"isBadThreshold": 100,
"isAbnormalThreshold": 200,
"hasOffenders": true,
"offendersTransformFn": function(offenders) {
return {
count: offenders.length,
list: offenders.map(function(offender) {
var parts = /^(.*) ?\(in ?(.*)\) ?using ?(.*)$/.exec(offender);
if (!parts) {
debug('DOMqueriesWithoutResults offenders transform function error with "%s"', offender);
return {
parseError: offender
};
}
return {
query: parts[1],
context: offendersHelpers.domPathToDomElementObj(parts[2]),
fn: parts[3]
};
})
};
}
"hasOffenders": false
},
"DOMqueriesAvoidable": {
"tool": "phantomas",
@@ -175,35 +116,6 @@ var policies = {
};
}
},
"eventsBound": {
"tool": "phantomas",
"label": "Events bound",
"message": "<p>Binding too many events has a cost.</p><p>It can be avoided by using \"event delegation\". Instead of binding events on each element one by one, events delegation binds them on the top level document element and uses the bubbling principle. It will imperceptibly slow down the event when it occurs, but the loading of the page will speed-up.</p>",
"isOkThreshold": 100,
"isBadThreshold": 800,
"isAbnormalThreshold": 1500,
"hasOffenders": true,
"offendersTransformFn": function(offenders) {
return {
count: offenders.length,
list: offenders.map(function(offender) {
var parts = /^"(.*)" ?bound ?to ?"(.*)"$/.exec(offender);
if (!parts) {
debug('eventsBound offenders transform function error with "%s"', offender);
return {
parseError: offender
};
}
return {
eventName: parts[1],
element: offendersHelpers.domPathToDomElementObj(parts[2])
};
})
};
}
},
"eventsScrollBound": {
"tool": "phantomas",
"label": "Scroll events bound",
@@ -351,9 +263,9 @@ var policies = {
"tool": "phantomas",
"label": "Global variables",
"message": "<p>It is a bad practice because they clutter up the global namespace. If two scripts use the same variable name in the global scope, it can cause conflicts and it is generally hard to debug.</p><p>Global variables also take a (very) little bit longer to be accessed than variables in the local scope of a function.</p>",
"isOkThreshold": 10,
"isBadThreshold": 50,
"isAbnormalThreshold": 200,
"isOkThreshold": 30,
"isBadThreshold": 100,
"isAbnormalThreshold": 400,
"hasOffenders": true,
"offendersTransformFn": function(offenders) {
return {
@@ -389,17 +301,17 @@ var policies = {
score = 70;
} else if (value.indexOf('1.8.') === 0) {
score = 50;
} else if (value.indexOf('1.7.') === 0) {
} else if (value.indexOf('1.7') === 0) {
score = 40;
} else if (value.indexOf('1.6.') === 0) {
} else if (value.indexOf('1.6') === 0) {
score = 30;
} else if (value.indexOf('1.5.') === 0) {
} else if (value.indexOf('1.5') === 0) {
score = 20;
} else if (value.indexOf('1.4.') === 0) {
} else if (value.indexOf('1.4') === 0) {
score = 10;
} else if (value.indexOf('1.3.') === 0) {
} else if (value.indexOf('1.3') === 0) {
score = 0;
} else if (value.indexOf('1.2.') === 0) {
} else if (value.indexOf('1.2') === 0) {
score = 0;
} else {
debug('Unknown jQuery version "%s"', value);
@@ -433,12 +345,21 @@ var policies = {
"jQueryFunctionsUsed": {
"tool": "jsExecutionTransformer",
"label": "jQuery usage",
"message": "<p>This is the number of different jQuery functions called on load. This rule is not trying to blame you for using jQuery too much, but the opposite.</p><p>If only a few functions are used, why not trying to get rid of jQuery? Have a look at <a href=\"http://youmightnotneedjquery.com/\" target=\"_blank\">http://youmightnotneedjquery.com</a>.</p>",
"message": "<p>This is the number of different core jQuery functions called on load. This rule is not trying to blame you for using jQuery too much, but the opposite.</p><p>If only a few functions are used, why not trying to get rid of jQuery? Have a look at <a href=\"http://youmightnotneedjquery.com/\" target=\"_blank\">http://youmightnotneedjquery.com</a>.</p>",
"isOkThreshold": 15,
"isBadThreshold": 6,
"isAbnormalThreshold": 0,
"hasOffenders": true
},
"jQueryCallsOnEmptyObject": {
"tool": "jsExecutionTransformer",
"label": "Calls on empty objects",
"message": "<p>This metric counts the number of jQuery functions called on an empty jQuery object. The call was useless.</p><p>This can be helpful to detect dead or unused code.</p>",
"isOkThreshold": 1,
"isBadThreshold": 100,
"isAbnormalThreshold": 180,
"hasOffenders": false
},
"jQueryNotDelegatedEvents": {
"tool": "jsExecutionTransformer",
"label": "Events not delegated",
@@ -446,7 +367,7 @@ var policies = {
"isOkThreshold": 1,
"isBadThreshold": 100,
"isAbnormalThreshold": 180,
"hasOffenders": true
"hasOffenders": false
},
"cssParsingErrors": {
"tool": "phantomas",
@@ -1024,7 +945,7 @@ var policies = {
"tool": "phantomas",
"label": "Font count",
"message": "<p>Fonts are loaded on the critical path of the head. Load as few as possible.</p>",
"isOkThreshold": 0,
"isOkThreshold": 1,
"isBadThreshold": 3,
"isAbnormalThreshold": 5,
"hasOffenders": true,
+6 -7
View File
@@ -12,11 +12,9 @@
"domManipulations": {
"label": "DOM manipulations",
"policies": {
"DOMinserts": 2,
"DOMqueries": 1,
"DOMqueriesWithoutResults": 2,
"DOMqueriesAvoidable": 2,
"eventsBound": 1
"DOMaccesses": 3,
"queriesWithoutResults": 1,
"DOMqueriesAvoidable": 1
}
},
"scroll": {
@@ -38,9 +36,10 @@
"jQuery": {
"label": "jQuery",
"policies": {
"jQueryVersion": 1,
"jQueryVersionsLoaded": 1,
"jQueryVersion": 2,
"jQueryVersionsLoaded": 2,
"jQueryFunctionsUsed": 1,
"jQueryCallsOnEmptyObject": 1,
"jQueryNotDelegatedEvents": 1
}
},
+6
View File
@@ -58,6 +58,9 @@ function RunsDatastore() {
var errorMessage;
switch(err) {
case '1':
errorMessage = "Error 1: unknown error";
break;
case '252':
errorMessage = "Error 252: page timeout in Phantomas";
break;
@@ -76,6 +79,9 @@ function RunsDatastore() {
case '1002':
errorMessage = "Error 1002: missing Phantomas metrics";
break;
case '1003':
errorMessage = "Error 1003: Phantomas not returning";
break;
default:
errorMessage = err;
}
@@ -0,0 +1,12 @@
var wwwRedirectMiddleware = function(req, res, next) {
'use strict';
// Redirect www.yellowlab.tools to yellowlab.tools without "www" (for SEO purpose)
if(/^www\.yellowlab\.tools/.test(req.headers.host)) {
res.redirect(301, req.protocol + '://' + req.headers.host.replace(/^www\./, '') + req.url);
} else {
next();
}
};
module.exports = wwwRedirectMiddleware;
+26 -28
View File
@@ -7,18 +7,20 @@ var jsExecutionTransformer = function() {
this.transform = function(data) {
var javascriptExecutionTree = {};
var scrollExecutionTree = {};
var jQueryFunctionsCollection = new Collection();
var metrics = {
domInteractive: 0,
domContentLoaded: 0,
domContentLoadedEnd: 0,
domComplete: 0,
DOMaccesses: 0,
DOMaccessesOnScroll: 0,
queriesWithoutResults: 0
};
var offenders = {
};
var offenders = {};
var hasjQuery = (data.toolsResults.phantomas.metrics.jQueryVersionsLoaded > 0);
if (hasjQuery) {
@@ -28,7 +30,6 @@ var jsExecutionTransformer = function() {
metrics.jQueryNotDelegatedEvents = 0;
offenders.jQueryFunctionsUsed = [];
offenders.jQueryNotDelegatedEvents = [];
}
try {
@@ -43,22 +44,19 @@ var jsExecutionTransformer = function() {
if (isABindWithoutEventDelegation(node, contextLength)) {
metrics.jQueryNotDelegatedEvents += contextLength;
offenders.jQueryNotDelegatedEvents.push({
functionName: node.data.type.substring(9),
contextLength: contextLength,
backtrace: offendersHelpers.backtraceToArray(node.data.backtrace)
});
node.warning = true;
node.eventNotDelegated = true;
}
if (node.data.resultsNumber === 0) {
metrics.queriesWithoutResults ++;
node.queryWithoutResults = true;
node.warning = true;
}
if (contextLength === 0) {
metrics.jQueryCallsOnEmptyObject ++;
node.jQueryCallOnEmptyObject = true;
node.warning = true;
}
@@ -75,22 +73,22 @@ var jsExecutionTransformer = function() {
// Mark a performance flag
if (['domInteractive', 'domContentLoaded', 'domContentLoadedEnd', 'domComplete'].indexOf(node.data.type) >= 0) {
node.windowPerformance = true;
}
// Read the execution tree and adjust the navigation timings (cause their not very well synchronised)
switch(node.data.type) {
case 'domInteractive':
data.toolsResults.phantomas.metrics.domInteractive = node.data.timestamp;
break;
case 'domContentLoaded':
data.toolsResults.phantomas.metrics.domContentLoaded = node.data.timestamp;
break;
case 'domContentLoadedEnd':
data.toolsResults.phantomas.metrics.domContentLoadedEnd = node.data.timestamp;
break;
case 'domComplete':
data.toolsResults.phantomas.metrics.domComplete = node.data.timestamp;
break;
// Adjust the navigation timings (cause their not very well synchronised)
switch(node.data.type) {
case 'domInteractive':
javascriptExecutionTree.data.domInteractive = node.data.timestamp;
break;
case 'domContentLoaded':
javascriptExecutionTree.data.domContentLoaded = node.data.timestamp;
break;
case 'domContentLoadedEnd':
javascriptExecutionTree.data.domContentLoadedEnd = node.data.timestamp;
break;
case 'domComplete':
javascriptExecutionTree.data.domComplete = node.data.timestamp;
break;
}
}
// Transform domPaths into objects
@@ -120,9 +118,9 @@ var jsExecutionTransformer = function() {
debug('Starting scroll execution transformation');
offenders.scrollExecutionTree = JSON.parse(data.toolsResults.phantomas.offenders.scrollExecutionTree[0]);
if (offenders.scrollExecutionTree.children) {
offenders.scrollExecutionTree.children.forEach(function(node) {
offenders.DOMaccessesOnScroll = JSON.parse(data.toolsResults.phantomas.offenders.scrollExecutionTree[0]);
if (offenders.DOMaccessesOnScroll.children) {
offenders.DOMaccessesOnScroll.children.forEach(function(node) {
// Mark a event flag
if (['documentScroll', 'windowScroll', 'window.onscroll'].indexOf(node.data.type) >= 0) {
@@ -365,7 +365,12 @@ exports.module = function(phantomas) {
phantomas.log('DOM query: by %s - "%s" (using %s) in %s', type, query, fnName, context);
phantomas.incrMetric('DOMqueries');
if (context && context.indexOf('DocumentFragment') === -1) {
if (context && (
context.indexOf('html') === 0 ||
context.indexOf('body') === 0 ||
context.indexOf('head') === 0 ||
context.indexOf('#document') === 0
)) {
DOMqueries.push(type + ' "' + query + '" with ' + fnName + ' (in context ' + context + ')');
}
});
+28 -9
View File
@@ -19,6 +19,7 @@ var PhantomasWrapper = function() {
var options = {
// Cusomizable options
'timeout': task.options.timeout || 45,
'js-deep-analysis': task.options.jsDeepAnalysis || false,
@@ -75,34 +76,52 @@ var PhantomasWrapper = function() {
}
debug('node node_modules/phantomas/bin/phantomas.js --url=' + task.url + optionsString + ' --verbose');
// Kill the application if nothing happens
var phantomasPid;
var isKilled = false;
// Kill phantomas if nothing happens
var killer = setTimeout(function() {
debug('Killing the app because the test on %s was launched %d seconds ago', task.url, 5*options.timeout);
// If in server mode, forever will restart the server
console.log('Killing phantomas because the test on ' + task.url + ' was launched ' + 5*options.timeout + ' seconds ago');
// Kill the Phantomas process first
if (phantomasPid) {
ps.kill(phantomasPid, function(err) {
if (err) {
debug('Could not kill Phantomas process %s', phantomasPid);
}
else {
debug('Phantomas process %s was correctly killed', phantomasPid);
// Suicide
process.exit(1);
// If in server mode, forever will restart the server
}
// Then suicide.
process.exit(1);
debug('Phantomas process %s was correctly killed', phantomasPid);
// Then mark the test as failed
// Error 1003 = Phantomas not answering
deferred.reject(1003);
isKilled = true;
});
} else {
// Suicide
process.exit(1);
}
}, 5*options.timeout*1000);
// It's time to launch the test!!!
var triesNumber = 2;
async.retry(triesNumber, function(cb) {
var process = phantomas(task.url, options, function(err, json, results) {
if (isKilled) {
debug('Process was killed, too late Phantomas, sorry...');
return;
}
debug('Returning from Phantomas');
// Adding some YellowLabTools errors here
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "yellowlabtools",
"version": "1.5.0",
"version": "1.6.1",
"description": "Online tool to audit a webpage for performance and front-end quality issues",
"repository": {
"type": "git",
@@ -11,18 +11,18 @@
},
"main": "./lib/index.js",
"dependencies": {
"async": "~0.9.0",
"async": "~1.0.0",
"body-parser": "~1.12.4",
"compression": "~1.4.3",
"compression": "~1.4.4",
"cors": "^2.6.0",
"debug": "~2.2.0",
"express": "~4.12.3",
"express": "~4.12.4",
"lwip": "0.0.6",
"meow": "^3.1.0",
"phantomas": "1.10.2",
"ps-node": "0.0.4",
"q": "~1.4.0",
"rimraf": "~2.3.3",
"q": "~1.4.1",
"rimraf": "~2.3.4",
"temporary": "0.0.8"
},
"devDependencies": {
@@ -47,7 +47,7 @@
"grunt-usemin": "^3.0.0",
"grunt-webfont": "^0.5.3",
"matchdep": "^0.3.0",
"mocha": "^2.2.4",
"mocha": "^2.2.5",
"request": "^2.55.0",
"sinon": "^1.14.1",
"sinon-chai": "^2.7.0"
+1 -181
View File
@@ -1,7 +1,7 @@
var should = require('chai').should();
var rulesChecker = require('../../lib/rulesChecker');
describe('rulesChecker', function() {
describe('customPolicies', function() {
var policies = require('../../lib/metadata/policies.js');
var results;
@@ -70,131 +70,6 @@ describe('rulesChecker', function() {
});
});
it('should transform DOMinserts offenders', function() {
results = rulesChecker.check({
"toolsResults": {
"phantomas": {
"metrics": {
"DOMinserts": 4
},
"offenders": {
"DOMinserts": [
"\"div\" appended to \"html\"",
"\"DocumentFragment > link[0]\" appended to \"head\"",
"\"div#Netaff-yh1XbS0vK3NaRGu\" appended to \"body > div#Global\"",
"\"img\" appended to \"body\""
]
}
}
}
}, policies);
results.should.have.a.property('DOMinserts');
results.DOMinserts.should.have.a.property('offendersObj').that.deep.equals({
"count": 4,
"list": [
{
"insertedElement": {
"type": "createdElement",
"element": "div"
},
"receiverElement": {
"type": "html"
}
},
{
"insertedElement": {
"type": "fragmentElement",
"element": "link[0]",
"tree": {
"DocumentFragment": {
"link[0]": 1
}
}
},
"receiverElement": {
"type": "head"
}
},
{
"insertedElement": {
"type": "createdElement",
"element": "div#Netaff-yh1XbS0vK3NaRGu"
},
"receiverElement": {
"type": "domElement",
"element": "div#Global",
"tree": {
"body": {
"div#Global": 1
}
}
}
},
{
"insertedElement": {
"type": "createdElement",
"element": "img"
},
"receiverElement": {
"type": "body"
}
}
]
});
});
it('should transform DOMqueriesWithoutResults offenders', function() {
results = rulesChecker.check({
"toolsResults": {
"phantomas": {
"metrics": {
"DOMqueriesWithoutResults": 2
},
"offenders": {
"DOMqueriesWithoutResults": [
"#SearchMenu (in #document) using getElementById",
".partnership-link (in body > div#Global > div#Header > ul#MainMenu) using getElementsByClassName"
]
}
}
}
}, policies);
results.should.have.a.property('DOMqueriesWithoutResults');
results.DOMqueriesWithoutResults.should.have.a.property('offendersObj').that.deep.equals({
"count": 2,
"list": [
{
"context": {
"type": "document"
},
"fn": "getElementById",
"query": "#SearchMenu "
},
{
"context": {
"element": "ul#MainMenu",
"tree": {
"body": {
"div#Global": {
"div#Header": {
"ul#MainMenu": 1
}
}
}
},
"type": "domElement"
},
"fn": "getElementsByClassName",
"query": ".partnership-link "
}
]
});
});
it('should transform DOMqueriesAvoidable offenders', function() {
results = rulesChecker.check({
@@ -246,61 +121,6 @@ describe('rulesChecker', function() {
});
it('should transform eventsBound offenders', function() {
results = rulesChecker.check({
"toolsResults": {
"phantomas": {
"metrics": {
"eventsBound": 2
},
"offenders": {
"eventsBound": [
"\"DOMContentLoaded\" bound to \"#document\"",
"\"unload\" bound to \"window\"",
"\"submit\" bound to \"body > div#Global > div#Header > form#search_mini_form\""
]
}
}
}
}, policies);
results.should.have.a.property('eventsBound');
results.eventsBound.should.have.a.property('offendersObj').that.deep.equals({
"count": 3,
"list": [
{
"element": {
"type": "document"
},
"eventName": "DOMContentLoaded"
},
{
"element": {
"type": "window"
},
"eventName": "unload"
},
{
"element": {
"element": "form#search_mini_form",
"tree": {
"body": {
"div#Global": {
"div#Header": {
"form#search_mini_form": 1
}
}
}
},
"type": "domElement"
},
"eventName": "submit"
}
]
});
});
it('should transform jsErrors offenders', function() {
results = rulesChecker.check({
"toolsResults": {
+9 -3
View File
@@ -53,8 +53,9 @@ describe('index.js', function() {
data.toolsResults.phantomas.metrics.should.have.a.property('requests').that.equals(1);
data.toolsResults.phantomas.should.have.a.property('offenders').that.is.an('object');
data.toolsResults.phantomas.offenders.should.have.a.property('DOMelementMaxDepth');
data.toolsResults.phantomas.offenders.DOMelementMaxDepth.should.have.length(1);
data.toolsResults.phantomas.offenders.DOMelementMaxDepth.should.have.length(2);
data.toolsResults.phantomas.offenders.DOMelementMaxDepth[0].should.equal('body > h1[0]');
data.toolsResults.phantomas.offenders.DOMelementMaxDepth[1].should.equal('body > script[1]');
// Test rules
data.should.have.a.property('rules').that.is.an('object');
@@ -76,10 +77,11 @@ describe('index.js', function() {
"score": 100,
"abnormalityScore": 0,
"offendersObj": {
"count": 1,
"count": 2,
"tree": {
"body": {
"h1[0]": 1
"h1[0]": 1,
"script[1]": 1
}
}
}
@@ -91,6 +93,10 @@ describe('index.js', function() {
data.should.have.a.property('javascriptExecutionTree').that.is.an('object');
data.javascriptExecutionTree.should.have.a.property('data');
data.javascriptExecutionTree.data.should.have.a.property('type').that.equals('main');
data.javascriptExecutionTree.data.should.have.a.property('domInteractive').that.is.a('number');
data.javascriptExecutionTree.data.should.have.a.property('domContentLoaded').that.is.a('number');
data.javascriptExecutionTree.data.should.have.a.property('domContentLoadedEnd').that.is.a('number');
data.javascriptExecutionTree.data.should.have.a.property('domComplete').that.is.a('number');
/*jshint expr: true*/
console.log.should.not.have.been.called;
+4
View File
@@ -4,5 +4,9 @@
</head>
<body>
<h1>Simple page</h1>
<script>
document.getElementById('foo');
</script>
</body>
</html>