Commit ed2487e5 authored by ojan@chromium.org's avatar ojan@chromium.org

Port first garden-o-matic component over to polymer

1. Add polymer bower json and update app.yaml appropriately.
2. Add 'unsafe-inline' to script-src so that imports work.
3. Add a load warning if you try to load the page without having
ever synced polymer.
4. Convert ui.results.Comparison over to <results-comparison> and
cleanup all code in ui.results.ResultsGrid.

Put results-comparison in it's own file. It makes sense to
put each custom element definition in it's own file and to test it
independently.

Add a top-level ui directory for all the UI related components. When we're
done, we should be able to delete a bunch of the JS files in the scripts
directory and all the CSS files in the styles directory.

NOTRY=true

Review URL: https://codereview.chromium.org/350563002

git-svn-id: svn://svn.chromium.org/blink/trunk@176805 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent e207ef01
# Pulled in via bower.
bower_components
garden-o-matic must be run from a server in order to handle polymer imports correctly.
1. cd Tools
2. python -m SimpleHTTPServer
3. Load http://localhost:8000/GardeningServer/garden-o-matic.html
Run the tests via http://localhost:8000/GardeningServer/run-unittests.html.
Polymer must be synced via bower in order for anything to work.
INSTALLING NPM/BOWER
The version of npm in apt-get is too old for bower. Instead
install it from http://nodejs.org/download/.
Install bower with:
sudo npm install -g bower
SYNCING POLYMER
1. cd Tools/GardeningServer
2. bower update
......@@ -21,3 +21,11 @@ handlers:
- url: /styles
static_dir: styles
- url: /ui
static_dir: ui
# FIXME: Write a script to do the appcfg update so that we can error out
# if there is no bower_components, or, even better just run "bower update".
- url: /bower_components
static_dir: bower_components
{
"name": "garden-o-matic",
"dependencies": {
"polymer": "Polymer/polymer#~0.3.3"
}
}
<!DOCTYPE html>
<!--
Copyright (C) 2011 Google Inc. All rights reserved.
......@@ -26,23 +25,12 @@ THE POSSIBILITY OF SUCH DAMAGE.
The favicons are from the awesome famfamfam.com, which is the website of Mark
James, a web developer from Birmingham, UK.
-->
<html>
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none';
script-src 'self' file: https://ajax.googleapis.com;
style-src 'self' 'unsafe-inline' file: https://ajax.googleapis.com http://fonts.googleapis.com;
font-src http://themes.googleusercontent.com;
img-src 'self' https://ajax.googleapis.com http://build.chromium.org https://storage.googleapis.com;
media-src 'self' http://build.chromium.org https://storage.googleapis.com;
frame-src 'self' http://build.chromium.org http://test-results.appspot.com https://storage.googleapis.com;
connect-src 'self'
http://blink.lc/
http://build.chromium.org
https://codereview.chromium.org
https://storage.googleapis.com
http://blink-status.appspot.com
http://chromium-status.appspot.com">
<title>Garden-O-Matic</title>
<meta name="viewport" content="width=device-width, user-scalable=no">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400,700">
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/themes/base/jquery-ui.css">
<link rel="stylesheet" href="styles/common.css">
......@@ -51,9 +39,7 @@ James, a web developer from Birmingham, UK.
<link rel="stylesheet" href="styles/results.css">
<link rel="stylesheet" href="styles/notifications.css">
<link rel="stylesheet" href="styles/pixelzoomer.css">
<meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js"></script>
<script src="scripts/base.js"></script>
......@@ -73,6 +59,11 @@ James, a web developer from Birmingham, UK.
<script src="scripts/ui/results.js"></script>
<script src="scripts/controllers.js"></script>
<script src="scripts/pixelzoomer.js"></script>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="polymer-load-warning.html">
<link rel="import" href="ui/ct-results-comparison.html">
<script src="scripts/garden-o-matic.js"></script>
</body>
</html>
</head>
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<script>
if (!window.Polymer)
alert('Polymer did not load correctly. Did you run "bower update" from Tools/GardeningServer?');
</script>
<!DOCTYPE html>
<!--
Copyright (C) 2011 Google Inc. All rights reserved.
......@@ -23,13 +22,15 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
-->
<html>
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="../qunit/qunit/qunit.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js"></script>
<script src="../qunit/qunit/qunit.js"></script>
</head>
<body>
<h1 id="qunit-header">TestFailures JavaScript Unit Tests</h1>
<h2 id="qunit-banner"></h2>
......@@ -71,5 +72,10 @@ THE POSSIBILITY OF SUCH DAMAGE.
<script src="scripts/ui/notifications_unittests.js"></script>
<script src="scripts/controllers_unittests.js"></script>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="polymer-load-warning.html">
<link rel="import" href="ui/ct-test-output-tests.html">
<link rel="import" href="ui/ct-results-comparison-tests.html">
</body>
</html>
......@@ -30,125 +30,47 @@ ui.results = ui.results || {};
var kResultsPrefetchDelayMS = 500;
ui.results.Comparison = base.extends('div', {
init: function()
{
this.className = 'comparison';
this.innerHTML = '<div><h2>Expected</h2><div class="results-container expected"></div></div>' +
'<div><h2>Actual</h2><div class="results-container actual"></div></div>' +
'<div><h2>Diff</h2><div class="results-container diff"></div></div>';
},
_selectorForKind: function(kind)
{
switch (kind) {
case results.kExpectedKind:
return '.expected';
case results.kActualKind:
return '.actual';
case results.kDiffKind:
return '.diff';
}
return '.unknown';
},
update: function(kind, result)
{
var selector = this._selectorForKind(kind);
$(selector, this).empty().append(result);
return result;
},
});
// We'd really like TextResult and ImageResult to extend a common Result base
// class, but we can't seem to do that because they inherit from different
// HTMLElements. We could have them inherit from <div>, but that seems lame.
ui.results.TextResult = base.extends('iframe', {
init: function(url)
{
this.className = 'text-result';
this.src = url;
}
});
ui.results.ImageResult = base.extends('img', {
init: function(url)
{
this.className = 'image-result';
this.src = url;
}
});
ui.results.AudioResult = base.extends('audio', {
init: function(url)
{
this.className = 'audio-result';
this.src = url;
this.controls = 'controls';
}
});
function constructorForResultType(type)
{
if (type == results.kImageType)
return ui.results.ImageResult;
if (type == results.kAudioType)
return ui.results.AudioResult;
return ui.results.TextResult;
}
ui.results.ResultsGrid = base.extends('div', {
init: function()
{
this.className = 'results-grid';
},
_addResult: function(comparison, constructor, resultsURLsByKind, kind)
{
var url = resultsURLsByKind[kind];
if (!url)
return;
comparison.update(kind, new constructor(url));
},
addComparison: function(resultType, resultsURLsByKind)
{
var comparison = new ui.results.Comparison();
var constructor = constructorForResultType(resultType);
this._addResult(comparison, constructor, resultsURLsByKind, results.kExpectedKind);
this._addResult(comparison, constructor, resultsURLsByKind, results.kActualKind);
this._addResult(comparison, constructor, resultsURLsByKind, results.kDiffKind);
this.appendChild(comparison);
return comparison;
},
addRow: function(resultType, url)
{
var constructor = constructorForResultType(resultType);
var view = new constructor(url);
this.appendChild(view);
return view;
},
addResults: function(resultsURLs)
{
var resultsURLsByTypeAndKind = {};
resultsURLsByTypeAndKind[results.kImageType] = {};
resultsURLsByTypeAndKind[results.kAudioType] = {};
resultsURLsByTypeAndKind[results.kTextType] = {};
resultsURLs.forEach(function(url) {
resultsURLsByTypeAndKind[results.resultType(url)][results.resultKind(url)] = url;
var resultType = results.resultType(url);
if (!resultsURLsByTypeAndKind[resultType])
resultsURLsByTypeAndKind[resultType] = {};
resultsURLsByTypeAndKind[resultType][results.resultKind(url)] = url;
});
$.each(resultsURLsByTypeAndKind, function(resultType, resultsURLsByKind) {
if ($.isEmptyObject(resultsURLsByKind))
return;
if (results.kUnknownKind in resultsURLsByKind) {
// This is something like "crash" that isn't a comparison.
this.addRow(resultType, resultsURLsByKind[results.kUnknownKind]);
var result = document.createElement('iframe');
result.src = resultsURLsByKind[results.kUnknownKind];
// FIXME: Move this to a stylesheet when we polymerize this component.
result.style.border = 0;
result.style.width = '100%';
result.style.height = '400px';
this.appendChild(result);
return;
}
this.addComparison(resultType, resultsURLsByKind);
var comparison = document.createElement('ct-results-comparison');
comparison.type = resultType;
if (results.kActualKind in resultsURLsByKind)
comparison.actualUrl = resultsURLsByKind[results.kActualKind];
if (results.kExpectedKind in resultsURLsByKind)
comparison.expectedUrl = resultsURLsByKind[results.kExpectedKind];
if (results.kDiffKind in resultsURLsByKind)
comparison.diffUrl = resultsURLsByKind[results.kDiffKind];
this.appendChild(comparison);
}.bind(this));
if (!this.children.length)
this.textContent = 'No results to display.'
}
......@@ -175,8 +97,6 @@ ui.results.ResultsDetails = base.extends('div', {
new ui.actions.Previous(),
new ui.actions.Next()
])).append(resultsGrid);
}.bind(this));
},
});
......
......@@ -73,57 +73,33 @@ test("ui.onebar", 3, function() {
});
// FIXME: These three results.* tests should be moved ot ui/results_unittests.js.
test("results.ResultsGrid", 1, function() {
test("results.ResultsGrid", 8, function() {
var grid = new ui.results.ResultsGrid()
grid.addResults([
'http://example.com/layout-test-results/foo-bar-diff.txt',
'http://example.com/layout-test-results/foo-bar-expected.png',
'http://example.com/layout-test-results/foo-bar-actual.png',
'http://example.com/layout-test-results/foo-bar-diff.png',
'http://example.com/foo-bar-diff.txt',
'http://example.com/foo-bar-expected.png',
'http://example.com/foo-bar-actual.png',
'http://example.com/foo-bar-diff.png',
]);
equal(grid.innerHTML,
'<div class="comparison">' +
'<div>' +
'<h2>Expected</h2>' +
'<div class="results-container expected">' +
'<img class="image-result" src="http://example.com/layout-test-results/foo-bar-expected.png">' +
'</div>' +
'</div>' +
'<div>' +
'<h2>Actual</h2>' +
'<div class="results-container actual">' +
'<img class="image-result" src="http://example.com/layout-test-results/foo-bar-actual.png">' +
'</div>' +
'</div>' +
'<div>' +
'<h2>Diff</h2>' +
'<div class="results-container diff">' +
'<img class="image-result" src="http://example.com/layout-test-results/foo-bar-diff.png">' +
'</div>' +
'</div>' +
'</div>' +
'<div class="comparison">' +
'<div>' +
'<h2>Expected</h2>' +
'<div class="results-container expected"></div>' +
'</div>' +
'<div>' +
'<h2>Actual</h2>' +
'<div class="results-container actual"></div>' +
'</div>' +
'<div>' +
'<h2>Diff</h2>' +
'<div class="results-container diff">' +
'<iframe class="text-result" src="http://example.com/layout-test-results/foo-bar-diff.txt"></iframe>' +
'</div>' +
'</div>' +
'</div>');
var comparisons = grid.querySelectorAll("ct-results-comparison");
equal(comparisons[0].type, "text");
equal(comparisons[0].actualUrl, "");
equal(comparisons[0].expectedUrl, "");
equal(comparisons[0].diffUrl, "http://example.com/foo-bar-diff.txt");
equal(comparisons[1].type, "image");
equal(comparisons[1].actualUrl, "http://example.com/foo-bar-actual.png");
equal(comparisons[1].expectedUrl, "http://example.com/foo-bar-expected.png");
equal(comparisons[1].diffUrl, "http://example.com/foo-bar-diff.png");
});
test("results.ResultsGrid (crashlog)", 1, function() {
var grid = new ui.results.ResultsGrid()
grid.addResults(['http://example.com/layout-test-results/foo-bar-crash-log.txt']);
equal(grid.innerHTML, '<iframe class="text-result" src="http://example.com/layout-test-results/foo-bar-crash-log.txt"></iframe>');
equal(grid.innerHTML, '<iframe src="http://example.com/layout-test-results/foo-bar-crash-log.txt" '+
'style="border: 0px; width: 100%; height: 400px;"></iframe>');
});
test("results.ResultsGrid (empty)", 1, function() {
......
......@@ -316,17 +316,6 @@ button.default:hover {
background-color: white;
}
.text-result {
border: none;
width: 100%;
height: 400px; /* FIXME: How do we get a reasonable height here? */
}
.image-result {
width: 100%;
height: auto;
}
/*** partytime ***/
.partytime {
......
......@@ -22,22 +22,6 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
.comparison {
display: flex;
flex-wrap: wrap;
width: 100%;
}
.comparison > div {
flex: 1;
min-width: 300px;
}
.results-container {
border: 1px solid gray;
}
.non-action-button, .results-view ul.actions, .ui-dialog ul.actions {
float: right;
margin: 0;
......@@ -95,17 +79,6 @@
border-bottom: 1px solid #DDD;
}
.results-grid .text-result {
border: none;
width: 100%;
height: 400px; /* FIXME: How do we get a reasonable height here? */
}
.results-grid .image-result {
width: 100%;
height: auto;
}
.results-view .top-panel {
max-height: 20%;
overflow: auto;
......
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="ct-results-comparison.html">
<script>
(function () {
module("ct-results-comparison");
asyncTest("basic", 7, function() {
var comparison = document.createElement('ct-results-comparison');
comparison.type = results.kImageType;
var expected = "http://domain.com/dummy-expected";
var actual = "http://domain.com/dummy-actual";
var diff = "http://domain.com/dummy-diff";
comparison.expectedUrl = expected;
comparison.actualUrl = actual;
comparison.diffUrl = diff;
Platform.endOfMicrotask(function() {
var outputs = comparison.shadowRoot.querySelectorAll('ct-test-output');
equal(outputs.length, 3);
// Verify we didn't typo any of the bindings.
equal(outputs[0].type, results.kImageType);
equal(outputs[0].url, expected);
equal(outputs[1].type, results.kImageType);
equal(outputs[1].url, actual);
equal(outputs[2].type, results.kImageType);
equal(outputs[2].url, diff);
start();
});
});
})()
</script>
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="ct-test-output.html">
<polymer-element name="ct-results-comparison" attributes="type expectedUrl actualUrl diffUrl" noscript>
<template>
<style>
:host {
display: flex;
flex-wrap: wrap;
width: 100%;
}
.container {
flex: 1;
min-width: 300px;
}
</style>
<div class="container">
<h2>Expected</h2>
<ct-test-output type="{{type}}" url="{{expectedUrl}}"></ct-test-output>
</div>
<div class="container">
<h2>Actual</h2>
<ct-test-output type="{{type}}" url="{{actualUrl}}"></ct-test-output>
</div>
<div class="container">
<h2>Diff</h2>
<ct-test-output type="{{type}}" url="{{diffUrl}}"></ct-test-output>
</div>
</template>
</polymer-element>
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="ct-test-output.html">
<script>
(function () {
module("ct-test-output");
asyncTest("image", 4, function() {
var output = document.createElement('ct-test-output');
output.type = results.kImageType;
var url = "http://domain.com/dummy-expected";
output.url = url;
Platform.endOfMicrotask(function() {
equal(output.shadowRoot.querySelectorAll('iframe').length, 0);
equal(output.shadowRoot.querySelectorAll('audio').length, 0);
var images = output.shadowRoot.querySelectorAll('img');
equal(images.length, 1);
equal(images[0].src, url);
start();
});
});
asyncTest("text", 4, function() {
var output = document.createElement('ct-test-output');
output.type = results.kTextType;
var url = "http://domain.com/dummy-expected";
output.url = url;
Platform.endOfMicrotask(function() {
equal(output.shadowRoot.querySelectorAll('img').length, 0);
equal(output.shadowRoot.querySelectorAll('audio').length, 0);
var images = output.shadowRoot.querySelectorAll('iframe');
equal(images.length, 1);
equal(images[0].src, url);
start();
});
});
asyncTest("audio", 4, function() {
var output = document.createElement('ct-test-output');
output.type = results.kAudioType;
var url = "http://domain.com/dummy-expected";
output.url = url;
Platform.endOfMicrotask(function() {
equal(output.shadowRoot.querySelectorAll('iframe').length, 0);
equal(output.shadowRoot.querySelectorAll('img').length, 0);
var images = output.shadowRoot.querySelectorAll('audio');
equal(images.length, 1);
equal(images[0].src, url);
start();
});
});
asyncTest("unknown-type", 3, function() {
var output = document.createElement('ct-test-output');
output.type = 'garbage';
var url = "http://domain.com/dummy-expected";
output.url = url;
Platform.endOfMicrotask(function() {
equal(output.shadowRoot.querySelectorAll('iframe').length, 0);
equal(output.shadowRoot.querySelectorAll('audio').length, 0);
equal(output.shadowRoot.querySelectorAll('img').length, 0);
start();
});
});
asyncTest("no-url", 3, function() {
var output = document.createElement('ct-test-output');
output.type = results.kImageType;
Platform.endOfMicrotask(function() {
equal(output.shadowRoot.querySelectorAll('iframe').length, 0);
equal(output.shadowRoot.querySelectorAll('audio').length, 0);
equal(output.shadowRoot.querySelectorAll('img').length, 0);
start();
});
});
})()
</script>
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<polymer-element name="ct-test-output" attributes="type url">
<template>
<style>
.result {
border: 1px solid gray;
}
iframe {
border: none;
width: 100%;
height: 400px;
}
img {
width: 100%;
}
</style>
<div class="result">
<template if="{{url}}">
<template if="{{type == _kImageType}}">
<img src="{{url}}">
</template>
<template if="{{type == _kTextType}}">
<iframe src="{{url}}"></iframe>
</template>
<template if="{{type == _kAudioType}}">
<audio controls src="{{url}}"></audio>
</template>
</template>
</div>
</template>
<script>
Polymer({
type: '',
url: '',
_kAudioType: results.kAudioType,
_kImageType: results.kImageType,
_kTextType: results.kTextType,
});
</script>
</polymer-element>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment