mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Clean up examples directory
This CL removes a bunch of examples that don't actually work in the current engine. I've also renamed example-element to custom-element and example-scrollable to scrolling because the word "example" in the name is redundant with the name of the directory. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/980323003
This commit is contained in:
parent
383ea84244
commit
b15263b453
@ -1,3 +0,0 @@
|
||||
Some of these examples are examples of what sky supports now.
|
||||
Others are examples of what sky hopes to one day support.
|
||||
Therefore not all these examples actually work today.
|
||||
@ -1,46 +0,0 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
<import src="../data/cities.sky" as="cities" />
|
||||
<script>
|
||||
function CityDataService(cities) {
|
||||
this.cities = cities;
|
||||
|
||||
// sort by state, city name.
|
||||
this.cities.sort(function(a, b) {
|
||||
if (a.state != b.state) {
|
||||
return a.state < b.state ? -1 : 1;
|
||||
}
|
||||
|
||||
return a.name < b.name ? -1 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
CityDataService.prototype.get = function(index, count) {
|
||||
var self = this;
|
||||
|
||||
return new Promise(function(fulfill) {
|
||||
var result = [];
|
||||
while (count-- > 0) {
|
||||
while (index < 0) {
|
||||
index += self.cities.length;
|
||||
}
|
||||
if (index >= self.cities.length)
|
||||
index = index % self.cities.length;
|
||||
|
||||
result.push(self.cities[index]);
|
||||
index++;
|
||||
}
|
||||
|
||||
fulfill(result);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
service: new Promise(function(fulfill) {
|
||||
fulfill(new CityDataService(cities));
|
||||
})
|
||||
};
|
||||
</script>
|
||||
@ -1,532 +0,0 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
<import src="city-data-service.sky" as="CityDataService" />
|
||||
<import src="city-sequence.sky" as="CitySequence" />
|
||||
|
||||
<sky-element name="state-header">
|
||||
<template>
|
||||
<style>
|
||||
div {
|
||||
font-size: 16px;
|
||||
color: #FFF;
|
||||
background-color: #333;
|
||||
padding: 4px 4px 4px 12px;
|
||||
display: paragraph;
|
||||
}
|
||||
</style>
|
||||
<div>{{ state }}</div>
|
||||
</template>
|
||||
<script>
|
||||
module.exports.StateHeaderElement = class extends SkyElement {
|
||||
created() {
|
||||
this.state = "";
|
||||
}
|
||||
set datum(datum) {
|
||||
this.state = datum.state;
|
||||
}
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
|
||||
<sky-element name="letter-header">
|
||||
<template>
|
||||
<style>
|
||||
div {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 2px 4px 4px 12px;
|
||||
background-color: #DDD;
|
||||
display: paragraph;
|
||||
}
|
||||
</style>
|
||||
<div>{{ letter }}</div>
|
||||
</template>
|
||||
<script>
|
||||
module.exports.LetterHeaderElement = class extends SkyElement {
|
||||
created() {
|
||||
this.letter = "";
|
||||
}
|
||||
set datum(datum) {
|
||||
this.letter = datum.letter;
|
||||
}
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
|
||||
<sky-element name="city-item">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
font-size: 13px;
|
||||
padding: 8px 4px 4px 12px;
|
||||
border-bottom: 1px solid #EEE;
|
||||
line-height: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div {
|
||||
display: paragraph;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#name {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
#population {
|
||||
color: #AAA;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<span id="name">{{ name }}</span>
|
||||
<t>, </t>
|
||||
<span id="population">population {{ population }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
module.exports.CityItemElement = class extends SkyElement {
|
||||
created() {
|
||||
this.name = "";
|
||||
this.population = "";
|
||||
}
|
||||
set datum(datum) {
|
||||
this.name = datum.name;
|
||||
this.population = datum.population;
|
||||
}
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
|
||||
<sky-element name="city-list">
|
||||
<template>
|
||||
<style>
|
||||
|
||||
:host {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#contentarea {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.position {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="contentarea">
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
(function(global) {
|
||||
"use strict";
|
||||
|
||||
var LOAD_LENGTH = 20;
|
||||
var LOAD_BUFFER_PRE = LOAD_LENGTH * 4;
|
||||
var LOAD_BUFFER_POST = LOAD_LENGTH * 4;
|
||||
|
||||
function Loader(cityList) {
|
||||
this.cityList = cityList;
|
||||
this.loadingData = false;
|
||||
this.data = null;
|
||||
this.zeroIndex = 0;
|
||||
this.loadIndex = 0;
|
||||
}
|
||||
|
||||
Loader.prototype.localIndex = function(externalIndex) {
|
||||
return externalIndex + this.zeroIndex;
|
||||
}
|
||||
|
||||
Loader.prototype.externalIndex = function(localIndex) {
|
||||
return localIndex - this.zeroIndex;
|
||||
}
|
||||
|
||||
Loader.prototype.getItems = function() {
|
||||
return this.data ? this.data.items : [];
|
||||
}
|
||||
|
||||
Loader.prototype.maybeLoadMoreData =
|
||||
function(dataloadedCallback, firstVisible) {
|
||||
if (this.loadingData)
|
||||
return;
|
||||
|
||||
if (firstVisible) {
|
||||
this.loadIndex = this.externalIndex(
|
||||
this.data.items.indexOf(firstVisible));
|
||||
}
|
||||
|
||||
var localIndex = this.localIndex(this.loadIndex);
|
||||
var loadedPre = 0;
|
||||
var loadedPost = 0;
|
||||
|
||||
if (this.data) {
|
||||
loadedPre = localIndex;
|
||||
loadedPost = this.data.items.length - loadedPre;
|
||||
}
|
||||
|
||||
var loadTime;
|
||||
if (loadedPre >= LOAD_BUFFER_PRE &&
|
||||
loadedPost >= LOAD_BUFFER_POST) {
|
||||
|
||||
var cityList = this.cityList;
|
||||
setTimeout(function() {
|
||||
cityList.dispatchEvent(new Event('load'));
|
||||
});
|
||||
|
||||
if (window.startLoad) {
|
||||
loadTime = new Date().getTime() - window.startLoad;
|
||||
console.log('Load: ' + loadTime + 'ms');
|
||||
window.startLoad = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadingData = true;
|
||||
|
||||
var loadIndex;
|
||||
|
||||
if (!this.data) {
|
||||
// Initial batch
|
||||
loadIndex = 0;
|
||||
} else if (loadedPost < LOAD_BUFFER_POST) {
|
||||
// Load forward first
|
||||
loadIndex = this.data.items.length;
|
||||
} else {
|
||||
// Then load backward
|
||||
loadIndex = -LOAD_LENGTH;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var externalIndex = this.externalIndex(loadIndex);
|
||||
|
||||
try {
|
||||
CityDataService.service.then(function(cityService) {
|
||||
return cityService.get(externalIndex, LOAD_LENGTH)
|
||||
.then(function(cities) {
|
||||
var indexOffset = 0;
|
||||
var newData = new CitySequence(cities);
|
||||
if (!self.data) {
|
||||
self.data = newData;
|
||||
} else if (loadIndex > 0) {
|
||||
self.data.append(newData);
|
||||
} else {
|
||||
self.zeroIndex += LOAD_LENGTH;
|
||||
indexOffset = LOAD_LENGTH;
|
||||
newData.append(self.data);
|
||||
self.data = newData;
|
||||
}
|
||||
|
||||
self.loadingData = false;
|
||||
dataloadedCallback(self.data, indexOffset);
|
||||
});
|
||||
}).catch(function(ex) {
|
||||
console.log(ex.stack);
|
||||
});
|
||||
} catch (ex) {
|
||||
console.log(ex.stack);
|
||||
}
|
||||
}
|
||||
|
||||
function Scroller() {
|
||||
this.contentarea = null;
|
||||
this.scrollTop = 0;
|
||||
this.scrollHeight = -1;
|
||||
}
|
||||
|
||||
Scroller.prototype.setup = function(scrollHeight, contentarea) {
|
||||
this.scrollHeight = scrollHeight;
|
||||
this.contentarea = contentarea;
|
||||
}
|
||||
|
||||
Scroller.prototype.scrollBy = function(amount) {
|
||||
this.scrollTop += amount;
|
||||
this.scrollTo();
|
||||
}
|
||||
|
||||
Scroller.prototype.scrollTo = function() {
|
||||
var transform = 'translateY(' + -this.scrollTop.toFixed(2) + 'px)';
|
||||
this.contentarea.style.transform = transform;
|
||||
}
|
||||
|
||||
// Current position and height of the scroller, that could
|
||||
// be used (by Tiler, for example) to reason about where to
|
||||
// place visible things.
|
||||
Scroller.prototype.getCurrentFrame = function() {
|
||||
return { top: this.scrollTop, height: this.scrollHeight };
|
||||
}
|
||||
|
||||
Scroller.prototype.hasFrame = function() {
|
||||
return this.scrollHeight != -1;
|
||||
}
|
||||
|
||||
function Tile(datum, element, viewType, index) {
|
||||
this.datum = datum;
|
||||
this.element = element;
|
||||
this.viewType = viewType;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
function Tiler(contentArea, views, viewHeights) {
|
||||
this.contentArea = contentArea;
|
||||
this.drawTop = 0;
|
||||
this.drawBottom = 0;
|
||||
this.firstItem = -1;
|
||||
this.tiles = [];
|
||||
this.viewHeights = viewHeights;
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
Tiler.prototype.setupViews = function(scrollFrame) {
|
||||
for (var type in this.viewHeights) {
|
||||
this.initializeViewType(scrollFrame, type, this.viewHeights[type]);
|
||||
}
|
||||
}
|
||||
|
||||
Tiler.prototype.initializeViewType = function(scrollFrame, viewType,
|
||||
height) {
|
||||
var count = Math.ceil(scrollFrame.height / height) * 2;
|
||||
var viewCache = this.views[viewType] = {
|
||||
indices: [],
|
||||
elements: []
|
||||
};
|
||||
|
||||
var protoElement;
|
||||
switch (viewType) {
|
||||
case 'stateHeader':
|
||||
protoElement = document.createElement('state-header');
|
||||
break;
|
||||
case 'letterHeader':
|
||||
protoElement = document.createElement('letter-header');
|
||||
break;
|
||||
case 'cityItem':
|
||||
protoElement = document.createElement('city-item');
|
||||
break;
|
||||
default:
|
||||
console.warn('Unknown viewType: ' + viewType);
|
||||
}
|
||||
protoElement.style.display = 'none';
|
||||
protoElement.style.height = height;
|
||||
protoElement.classList.add('position');
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
var clone = protoElement.cloneNode(false);
|
||||
this.contentArea.appendChild(clone);
|
||||
viewCache.elements.push(clone);
|
||||
viewCache.indices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
Tiler.prototype.checkoutTile = function(viewType, datum, top) {
|
||||
var viewCache = this.views[viewType];
|
||||
var index = viewCache.indices.pop();
|
||||
var element = viewCache.elements[index];
|
||||
element.datum = datum;
|
||||
element.style.display = '';
|
||||
element.style.top = top + 'px';
|
||||
|
||||
return new Tile(datum, element, viewType, index);
|
||||
}
|
||||
|
||||
Tiler.prototype.checkinTile = function(tile) {
|
||||
if (!tile.element)
|
||||
return;
|
||||
|
||||
tile.element.style.display = 'none';
|
||||
this.views[tile.viewType].indices.push(tile.index);
|
||||
}
|
||||
|
||||
Tiler.prototype.getFirstVisibleDatum = function(scrollFrame) {
|
||||
var tiles = this.tiles;
|
||||
var viewHeights = this.viewHeights;
|
||||
|
||||
var itemTop = this.drawTop - scrollFrame.top;
|
||||
if (itemTop >= 0 && tiles.length)
|
||||
return tiles[0].datum;
|
||||
|
||||
var tile;
|
||||
for (var i = 0; i < tiles.length && itemTop < 0; i++) {
|
||||
tile = tiles[i];
|
||||
var height = viewHeights[tile.viewType];
|
||||
itemTop += height;
|
||||
}
|
||||
|
||||
return tile ? tile.datum : null;
|
||||
}
|
||||
|
||||
Tiler.prototype.viewType = function(datum) {
|
||||
switch (datum.headerOrder) {
|
||||
case 1: return 'stateHeader';
|
||||
case 2: return 'letterHeader';
|
||||
default: return 'cityItem';
|
||||
}
|
||||
}
|
||||
|
||||
Tiler.prototype.drawTiles = function(scrollFrame, data) {
|
||||
var tiles = this.tiles;
|
||||
var viewHeights = this.viewHeights;
|
||||
|
||||
var buffer = Math.round(scrollFrame.height / 2);
|
||||
var targetTop = scrollFrame.top - buffer;
|
||||
var targetBottom = scrollFrame.top + scrollFrame.height + buffer;
|
||||
|
||||
// Collect down to targetTop
|
||||
var first = tiles[0];
|
||||
while (tiles.length &&
|
||||
targetTop > this.drawTop + viewHeights[first.viewType]) {
|
||||
|
||||
var height = viewHeights[first.viewType];
|
||||
this.drawTop += height;
|
||||
|
||||
this.firstItem++;
|
||||
this.checkinTile(tiles.shift());
|
||||
|
||||
first = tiles[0];
|
||||
}
|
||||
|
||||
// Collect up to targetBottom
|
||||
var last = tiles[tiles.length - 1];
|
||||
while(tiles.length &&
|
||||
targetBottom < this.drawBottom - viewHeights[last.viewType]) {
|
||||
|
||||
var height = viewHeights[last.viewType];
|
||||
this.drawBottom -= height;
|
||||
|
||||
this.checkinTile(tiles.pop());
|
||||
|
||||
last = tiles[tiles.length - 1];
|
||||
}
|
||||
|
||||
// Layout up to targetTop
|
||||
while (this.firstItem > 0 &&
|
||||
targetTop < this.drawTop) {
|
||||
|
||||
var datum = data[this.firstItem - 1];
|
||||
var type = this.viewType(datum);
|
||||
var height = viewHeights[type];
|
||||
|
||||
this.drawTop -= height;
|
||||
|
||||
var tile = targetBottom < this.drawTop ?
|
||||
new Tile(datum, null, datum.viewType, -1) : // off-screen
|
||||
this.checkoutTile(type, datum, this.drawTop);
|
||||
|
||||
this.firstItem--;
|
||||
tiles.unshift(tile);
|
||||
}
|
||||
|
||||
// Layout down to targetBottom
|
||||
while (this.firstItem + tiles.length < data.length - 1 &&
|
||||
targetBottom > this.drawBottom) {
|
||||
|
||||
var datum = data[this.firstItem + tiles.length];
|
||||
var type = this.viewType(datum);
|
||||
var height = viewHeights[type];
|
||||
|
||||
this.drawBottom += height;
|
||||
|
||||
var tile = targetTop > this.drawBottom ?
|
||||
new Tile(datum, null, datum.viewType, -1) : // off-screen
|
||||
this.checkoutTile(type, datum, this.drawBottom - height);
|
||||
|
||||
tiles.push(tile);
|
||||
}
|
||||
|
||||
// Debug validate:
|
||||
// for (var i = 0; i < tiles.length; i++) {
|
||||
// if (tiles[i].datum !== data[this.firstItem + i])
|
||||
// throw Error('Invalid')
|
||||
// }
|
||||
}
|
||||
|
||||
// FIXME: Needs better name.
|
||||
Tiler.prototype.updateFirstItem = function(offset) {
|
||||
var tiles = this.tiles;
|
||||
|
||||
if (!tiles.length) {
|
||||
this.firstItem = 0;
|
||||
} else {
|
||||
this.firstItem += offset;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.CityListElement = class extends SkyElement {
|
||||
|
||||
created() {
|
||||
this.loader = null;
|
||||
this.scroller = null;
|
||||
this.tiler = null;
|
||||
this.date = null;
|
||||
this.month = null;
|
||||
this.views = null;
|
||||
}
|
||||
|
||||
attached() {
|
||||
this.views = {};
|
||||
this.loader = new Loader(this);
|
||||
this.scroller = new Scroller();
|
||||
this.tiler = new Tiler(
|
||||
this.shadowRoot.getElementById('contentarea'), this.views, {
|
||||
stateHeader: 27,
|
||||
letterHeader: 18,
|
||||
cityItem: 30
|
||||
});
|
||||
|
||||
var self = this;
|
||||
this.addEventListener('wheel', function(event) {
|
||||
self.scrollBy(-event.offsetY)
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
self.domReady();
|
||||
self.loader.maybeLoadMoreData(self.dataLoaded.bind(self));
|
||||
});
|
||||
}
|
||||
|
||||
domReady() {
|
||||
this.scroller.setup(this.clientHeight,
|
||||
this.shadowRoot.getElementById('contentarea'));
|
||||
var scrollFrame = this.scroller.getCurrentFrame();
|
||||
this.tiler.setupViews(scrollFrame);
|
||||
}
|
||||
|
||||
updateView(data, scrollChanged) {
|
||||
var scrollFrame = this.scroller.getCurrentFrame();
|
||||
this.tiler.drawTiles(scrollFrame, data);
|
||||
var datum = scrollChanged ?
|
||||
this.tiler.getFirstVisibleDatum(scrollFrame) : null;
|
||||
this.loader.maybeLoadMoreData(this.dataLoaded.bind(this), datum);
|
||||
}
|
||||
|
||||
dataLoaded(data, indexOffset) {
|
||||
var scrollFrame = this.scroller.getCurrentFrame();
|
||||
this.tiler.updateFirstItem(indexOffset);
|
||||
this.updateView(data.items, false);
|
||||
}
|
||||
|
||||
scrollBy(amount) {
|
||||
this.scroller.scrollBy(amount);
|
||||
this.updateView(this.loader.getItems(), true);
|
||||
}
|
||||
}.register();
|
||||
|
||||
})(this);
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,64 +0,0 @@
|
||||
<!--
|
||||
// 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>
|
||||
function StateHeader(state) {
|
||||
this.state = state;
|
||||
this.headerOrder = 1;
|
||||
};
|
||||
|
||||
function LetterHeader(letter) {
|
||||
this.letter = letter;
|
||||
this.headerOrder = 2;
|
||||
}
|
||||
|
||||
function CitySequence(cities)
|
||||
{
|
||||
this.items = [];
|
||||
this.cursor = 0;
|
||||
|
||||
var lastState;
|
||||
var lastLetter;
|
||||
|
||||
for (var i = 0; i < cities.length; i++) {
|
||||
var city = cities[i];
|
||||
if (!lastState || lastState.state != city.state) {
|
||||
lastState = new StateHeader(city.state);
|
||||
this.items.push(lastState);
|
||||
lastLetter = undefined;
|
||||
}
|
||||
if (!lastLetter || lastLetter.letter != city.name[0]) {
|
||||
lastLetter = new LetterHeader(city.name[0]);
|
||||
this.items.push(lastLetter);
|
||||
}
|
||||
this.items.push(city);
|
||||
}
|
||||
};
|
||||
|
||||
CitySequence.prototype = {
|
||||
append: function(other) {
|
||||
var lastCity = this.items[this.items.length - 1];
|
||||
var firstOtherCity = other.items[2];
|
||||
|
||||
var index = 0;
|
||||
if (firstOtherCity.state == lastCity.state) {
|
||||
// skip StateHeader
|
||||
if (firstOtherCity.name[0] == lastCity.name[0]) {
|
||||
// skip LetterHeader
|
||||
index = 2;
|
||||
} else {
|
||||
index = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (; index < other.items.length; index++) {
|
||||
this.items.push(other.items[index]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CitySequence;
|
||||
|
||||
</script>
|
||||
@ -1,52 +0,0 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport"
|
||||
content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes, width=device-width">
|
||||
<import src="city-list.sky" />
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Roboto", "HelveticaNeue",sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 13px;
|
||||
color: #222;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script>
|
||||
window.startLoad = new Date().getTime();
|
||||
</script>
|
||||
<body>
|
||||
<city-list></city-list>
|
||||
<script>
|
||||
var cityList = document.querySelector('city-list');
|
||||
var scrollBy = 0;
|
||||
var toks = location.search.match(/auto=([0-9]+)/);
|
||||
if (toks) {
|
||||
scrollBy = Number(toks[1]);
|
||||
}
|
||||
|
||||
function autoScroll() {
|
||||
cityList.scrollBy(scrollBy);
|
||||
requestAnimationFrame(autoScroll);
|
||||
}
|
||||
|
||||
if (scrollBy) {
|
||||
setTimeout(function() {
|
||||
requestAnimationFrame(autoScroll);
|
||||
}, 200)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,82 +0,0 @@
|
||||
#!mojo mojo:sky_viewer
|
||||
<sky>
|
||||
<import src="dart-library.sky" as="library" />
|
||||
<script>
|
||||
import 'dart:async';
|
||||
import '/mojo/public/dart/application.dart';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:sky.internals' as internals;
|
||||
import 'mojo:bindings';
|
||||
import 'mojo:core';
|
||||
|
||||
import 'package:mojo/services/network/public/interfaces/network_service.mojom.dart';
|
||||
import 'package:mojo/services/network/public/interfaces/url_loader.mojom.dart';
|
||||
import 'package:mojo/public/interfaces/application/shell.mojom.dart' as shell_mojom;
|
||||
|
||||
class WGet extends Application {
|
||||
NetworkServiceProxy _networkService;
|
||||
UrlLoaderProxy _urlLoaderProxy;
|
||||
|
||||
WGet.fromHandle(MojoHandle handle) : super.fromHandle(handle);
|
||||
WGet(MojoMessagePipeEndpoint endpoint) : super(endpoint);
|
||||
|
||||
void initialize(List<String> args, String url) {
|
||||
run(args);
|
||||
}
|
||||
|
||||
run(List<String> args) async {
|
||||
if (args == null || args.length != 2) {
|
||||
throw "Expected URL argument";
|
||||
}
|
||||
|
||||
ByteData bodyData = await _getUrl(args[1]);
|
||||
print("read ${bodyData.lengthInBytes} bytes");
|
||||
|
||||
_closeProxies();
|
||||
close();
|
||||
}
|
||||
|
||||
Future<ByteData> _getUrl(String url) async {
|
||||
_initProxiesIfNeeded();
|
||||
|
||||
var urlRequest = new UrlRequest()
|
||||
..url = url
|
||||
..autoFollowRedirects = true;
|
||||
|
||||
var urlResponse = await _urlLoaderProxy.start(urlRequest);
|
||||
print("url => ${urlResponse.response.url}");
|
||||
print("status_line => ${urlResponse.response.statusLine}");
|
||||
print("mime_type => ${urlResponse.response.mimeType}");
|
||||
|
||||
return DataPipeDrainer.drainHandle(urlResponse.response.body);
|
||||
}
|
||||
|
||||
void _initProxiesIfNeeded() {
|
||||
if (_networkService == null) {
|
||||
_networkService = new NetworkServiceProxy.unbound();
|
||||
connectToService("mojo:network_service", _networkService);
|
||||
}
|
||||
if (_urlLoaderProxy == null) {
|
||||
_urlLoaderProxy = new UrlLoaderProxy.unbound();
|
||||
_networkService.createUrlLoader(_urlLoaderProxy);
|
||||
}
|
||||
}
|
||||
|
||||
void _closeProxies() {
|
||||
_urlLoaderProxy.close();
|
||||
_networkService.close();
|
||||
_urlLoaderProxy = null;
|
||||
_networkService = null;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
var messagePipe = new MojoMessagePipe();
|
||||
var wget = new WGet(messagePipe.endpoints[1]);
|
||||
wget.listen();
|
||||
var shellProxy = new shell_mojom.ShellProxy.fromHandle(new MojoHandle(internals.takeShellProxyHandle()));
|
||||
wget.initializeFromShellProxy(shellProxy, ["mojo:wget", "http://www.google.com"], "mojo:wget");
|
||||
}
|
||||
|
||||
</script>
|
||||
</sky>
|
||||
@ -1,20 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-header">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
background: linear-gradient(#3E77B7, #6C98C4);
|
||||
padding: 8px;
|
||||
color: white;
|
||||
border-bottom: 1px solid #3E77B7;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,21 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-menu-button">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
border-radius: 4px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,16 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-panel-content">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,19 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-panel-header">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
background-color: #DEDEDE;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,18 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-panel">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,18 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-scrollable">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
flex: 1;
|
||||
box-shadow: inset 0px 0px 22px 2px rgba(22, 22, 22, 0.63);
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,32 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-search-input">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
background-color: #F6F6F6;
|
||||
padding: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.input-text {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
<span class="input-icon">
|
||||
<img src="/sky/examples/flights/images/magnifying-glass.png" style="width: 16px">
|
||||
</span>
|
||||
<span class="input-text"><t>flights today to dc by price</t></span>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
attached() {
|
||||
var sel = window.getSelection();
|
||||
var input = this.shadowRoot.querySelector('t');
|
||||
sel.selectAllChildren(input);
|
||||
}
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,20 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-title">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 22px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,51 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-toast">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
position: absolute;
|
||||
bottom: 32px;
|
||||
right: 32px;
|
||||
max-width: 55%;
|
||||
box-shadow: 0px 0px 12px 2px rgba(22, 22, 22, 0.4);
|
||||
background-image: linear-gradient(#E5D658, #DFCF43);
|
||||
border: 1px solid #AEA477;
|
||||
padding: 6px;
|
||||
border-radius: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.8em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex-shrink: 0;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.close-box {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
width: 1em;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
outline: 1px solid #AEA477;
|
||||
}
|
||||
</style>
|
||||
<div class="header">
|
||||
<content select=".toast-icon" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<content select=".toast-content" />
|
||||
</div>
|
||||
<div class="close-box">
|
||||
X
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,17 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="app-toolbar">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
background-color: #F6F6F6;
|
||||
padding: 0 8px;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,208 +0,0 @@
|
||||
<import src="../../framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
<import src="app-header.sky" />
|
||||
<import src="app-title.sky" />
|
||||
<import src="app-menu-button.sky" />
|
||||
<import src="app-panel.sky" />
|
||||
<import src="app-panel-header.sky" />
|
||||
<import src="app-panel-content.sky" />
|
||||
<import src="app-toolbar.sky" />
|
||||
<import src="app-search-input.sky" />
|
||||
<import src="app-scrollable.sky" />
|
||||
<import src="app-toast.sky" />
|
||||
|
||||
<sky-element name="flights-app">
|
||||
<template>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
t, span {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background-color: #494949;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
font-size: 16px;
|
||||
color: #2B2B2B;
|
||||
}
|
||||
|
||||
.toast-icon {
|
||||
font-weight: bold;
|
||||
font-size: 24px;
|
||||
border-radius: 16px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 2px solid black;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tip-price {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.route-result {
|
||||
margin: 16px 16px 0 16px;
|
||||
outline: 1px solid black;
|
||||
}
|
||||
|
||||
.route-title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.airline {
|
||||
border-radius: 2px;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.airline-name {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.airline-logo-image {
|
||||
width: 50px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.airline-best-price {
|
||||
color: #ABB4B6;
|
||||
}
|
||||
|
||||
.airline-name,
|
||||
.airline-best-price {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #1155CC;
|
||||
}
|
||||
</style>
|
||||
<app-header>
|
||||
<app-title>
|
||||
<t>Search</t>
|
||||
</app-title>
|
||||
<app-menu-button>
|
||||
<img src="/sky/examples/flights/images/menu-white.png" style="width: 18px" />
|
||||
</app-menu-button>
|
||||
</app-header>
|
||||
<app-toolbar>
|
||||
<app-search-input />
|
||||
</app-toolbar>
|
||||
<app-scrollable>
|
||||
<app-panel class="route-result">
|
||||
<app-panel-header>
|
||||
<div class="route-title">
|
||||
<t>SFO to DCA</t>
|
||||
</div>
|
||||
<app-menu-button>
|
||||
<img src="/sky/examples/flights/images/menu-enabled.png" style="width: 14px" />
|
||||
</app-menu-button>
|
||||
</app-panel-header>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/virgin-america.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>Virgin America</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$800</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/ba.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>British Airways</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$700</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/united.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>United</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$667</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/delta.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>Delta</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$450</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
</app-panel>
|
||||
<app-panel class="route-result">
|
||||
<app-panel-header>
|
||||
<div class="route-title">
|
||||
<t>SJC to DCA</t>
|
||||
</div>
|
||||
<app-menu-button>
|
||||
<img src="/sky/examples/flights/images/menu-enabled.png" style="width: 14px" />
|
||||
</app-menu-button>
|
||||
</app-panel-header>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/virgin-america.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>Virgin America</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$1500</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/jetblue.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>jetBlue</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$650</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
<app-panel-content class="airline">
|
||||
<div class="airline-logo">
|
||||
<img class="airline-logo-image" src="/sky/examples/flights/images/united.jpg" />
|
||||
</div>
|
||||
<div class="airline-name">
|
||||
<t>United</t>
|
||||
</div>
|
||||
<div class="airline-best-price">
|
||||
<t><a>$367</a></t>
|
||||
</div>
|
||||
</app-panel-content>
|
||||
</app-panel>
|
||||
</app-scrollable>
|
||||
<app-toast>
|
||||
<div class="toast-icon">
|
||||
<t>?</t>
|
||||
</div>
|
||||
<div class="toast-content">
|
||||
<t>Flights are <span class="tip-price">$200</span> cheaper tomorrow.</t>
|
||||
</div>
|
||||
</app-toast>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = class extends SkyElement {
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,10 +0,0 @@
|
||||
#!mojo mojo:sky_viewer
|
||||
<sky>
|
||||
<import src="flights-app.sky" as="FlightsAppElement"/>
|
||||
<style>
|
||||
sky {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<flights-app />
|
||||
</sky>
|
||||
@ -1,68 +0,0 @@
|
||||
#!mojo mojo:sky_viewer
|
||||
<!--
|
||||
// Copyright 2015 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.
|
||||
-->
|
||||
<import src="/sky/framework/sky-element/sky-element.sky" as="SkyElement" />
|
||||
|
||||
<sky-element name="fps-counter" attributes="showHistory:boolean">
|
||||
<template>
|
||||
<template if="{{ showHistory }}">
|
||||
<template repeat="{{ deltas }}">
|
||||
<div>{{ roundedValue }} ms</div>
|
||||
</template>
|
||||
<div>max = {{ max }} ms</div>
|
||||
</template>
|
||||
<div>fps = {{ frameRate }} Hz</div>
|
||||
</template>
|
||||
<script>
|
||||
const kMaxDeltaLength = 10;
|
||||
|
||||
class Delta {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
this.roundedValue = value.toFixed(2);
|
||||
Object.preventExtensions(this);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class extends SkyElement {
|
||||
created() {
|
||||
this.frameRate = "...";
|
||||
this.max = 0;
|
||||
this.sum = 0;
|
||||
this.lastTimeStamp = 0;
|
||||
this.rafId = 0;
|
||||
this.deltas = [];
|
||||
for (var i = 0; i < kMaxDeltaLength; ++i)
|
||||
this.deltas[i] = new Delta(0);
|
||||
}
|
||||
attached() {
|
||||
this.scheduleTick();
|
||||
}
|
||||
detached() {
|
||||
cancelAnimationFrame(this.rafId);
|
||||
this.rafId = 0;
|
||||
}
|
||||
scheduleTick() {
|
||||
this.rafId = requestAnimationFrame(this.tick.bind(this));
|
||||
}
|
||||
tick(timeStamp) {
|
||||
this.scheduleTick();
|
||||
var lastTimeStamp = this.lastTimeStamp;
|
||||
this.lastTimeStamp = timeStamp;
|
||||
if (!lastTimeStamp)
|
||||
return;
|
||||
var delta = new Delta(timeStamp - lastTimeStamp);
|
||||
var removedDelta = this.deltas.shift();
|
||||
this.deltas.push(delta);
|
||||
this.sum -= removedDelta.value;
|
||||
this.sum += delta.value;
|
||||
var avg = this.sum / this.deltas.length;
|
||||
this.frameRate = (1000 / avg).toFixed(2);
|
||||
this.max = Math.max(delta.value, this.max).toFixed(2);
|
||||
}
|
||||
}.register();
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,70 +0,0 @@
|
||||
SKY MODULE - defines an <element> element
|
||||
<import src="sky:core" as="sky"/>
|
||||
|
||||
<!-- usage:
|
||||
|
||||
<element name="tagname">
|
||||
<style> style here (optional) </style>
|
||||
<template> shadow tree here (optional) </template>
|
||||
<script> // optional
|
||||
module.currentScript.parentNode.setPrototype({
|
||||
init: function () {
|
||||
// constructor here
|
||||
},
|
||||
// rest of api here
|
||||
});
|
||||
</script>
|
||||
</element>
|
||||
|
||||
-->
|
||||
|
||||
<script>
|
||||
module.exports.Element = sky.registerElement(
|
||||
class extends Element {
|
||||
static get tagName() { return 'element'; }
|
||||
constructor (hostModule) {
|
||||
super(hostModule);
|
||||
this.state = 'loading';
|
||||
this.module = hostModule;
|
||||
this.definedPrototype = sky.Element;
|
||||
}
|
||||
setPrototype(prototype) {
|
||||
this.definedPrototype = prototype;
|
||||
}
|
||||
endTagParsedCallback() {
|
||||
let style = null;
|
||||
let template = null;
|
||||
let child = this.firstChild;
|
||||
while (child && !(style && template)) {
|
||||
if ((!style) && (child instanceof sky.StyleElement))
|
||||
style = child;
|
||||
if ((!template) && (template instanceof sky.TemplateElement))
|
||||
template = child;
|
||||
child = child.nextSibling;
|
||||
}
|
||||
let tagName = this.getAttribute('name');
|
||||
let constructorName = tagName.charAt(0).toUpperCase() + tagName.slice(1) + 'Element';
|
||||
let constructor = function (hostModule) {
|
||||
super(hostModule);
|
||||
if (this.init)
|
||||
this.init();
|
||||
if (style)
|
||||
this.shadowRoot.append(style.cloneNode(true));
|
||||
if (template)
|
||||
this.shadowRoot.append(template.cloneNode(true));
|
||||
}
|
||||
};
|
||||
if (this.definedPrototype)
|
||||
constructor.prototype = this.definedPrototype;
|
||||
else
|
||||
constructor.prototype = sky.Element;
|
||||
constructor.tagName = this.getAttribute('name');
|
||||
constructor.shadow = style || template;
|
||||
this.module.exports[constructorName] = this.registerElement(constructor);
|
||||
delete this.definedPrototype;
|
||||
delete this.module;
|
||||
this.state = 'loaded';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
@ -1,112 +0,0 @@
|
||||
SKY MODULE - exports some basic HTML-like elements
|
||||
<import src="element.sky"/>
|
||||
|
||||
<!-- note: accessibility handling is not implemented yet, because the
|
||||
mojo ax service isn't yet ready -->
|
||||
|
||||
<import src="scrollable-block.sky">
|
||||
<element name=html>
|
||||
<style>
|
||||
:host { display: scrollable-block; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=head />
|
||||
<element name=body />
|
||||
<element name=p />
|
||||
|
||||
<element name=h1>
|
||||
<style>
|
||||
:host { margin-top: 0.67em; margin-bottom: 0.67em; font-size: 2.00em; font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=h2>
|
||||
<style>
|
||||
:host { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=h3>
|
||||
<style>
|
||||
:host { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=h4>
|
||||
<style>
|
||||
:host { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=h5>
|
||||
<style>
|
||||
:host { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=h6>
|
||||
<style>
|
||||
:host { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=b>
|
||||
<style>
|
||||
:host { font-weight: bold; }
|
||||
</style>
|
||||
</element>
|
||||
|
||||
<element name=data>
|
||||
<script>
|
||||
module.currentScript.parentNode.setPrototype({
|
||||
get value () {
|
||||
return this.getAttribute('value');
|
||||
},
|
||||
set value (newValue) {
|
||||
this.setAttribute('value', newValue);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</element>
|
||||
|
||||
<element name=progress>
|
||||
<template>
|
||||
<div> ... </div>
|
||||
</template>
|
||||
<script>
|
||||
module.currentScript.parentNode.setPrototype({
|
||||
...
|
||||
});
|
||||
</script>
|
||||
</element>
|
||||
|
||||
<element name=details>
|
||||
<style>
|
||||
:host { display: block; }
|
||||
.outer { border: solid; }
|
||||
.header { display: inline; }
|
||||
.summary { display: inline; }
|
||||
</style>
|
||||
<template>
|
||||
<div class="outer">
|
||||
<div class="header">
|
||||
<div class="button">OPEN</div>
|
||||
<div class="summary"><content select="summary"/></div>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<content/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
module.currentScript.parentNode.setPrototype({
|
||||
init: function () {
|
||||
|
||||
},
|
||||
open() {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</element>
|
||||
@ -1,11 +0,0 @@
|
||||
#!mojo mojo:sky
|
||||
<import src="../framework/htmlish.sky"/>
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to Sky</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Introduction</h1>
|
||||
<p>Hello world.</p>
|
||||
</body>
|
||||
</html>
|
||||
@ -5,6 +5,6 @@
|
||||
// found in the LICENSE file.
|
||||
-->
|
||||
<sky>
|
||||
<import src="example-scrollable.sky" />
|
||||
<example-scrollable />
|
||||
<import src="scrolling.sky" />
|
||||
<scrolling />
|
||||
</sky>
|
||||
@ -7,7 +7,7 @@
|
||||
<import src="/sky/framework/sky-scrollable.sky" />
|
||||
<import src="../data/cities.sky" as="cities" />
|
||||
|
||||
<sky-element name="example-scrollable">
|
||||
<sky-element>
|
||||
<template>
|
||||
<style>
|
||||
sky-scrollable {
|
||||
@ -21,8 +21,8 @@
|
||||
<script>
|
||||
import "dart:sky";
|
||||
|
||||
@Tagname('example-scrollable')
|
||||
class ExampleScrollable extends SkyElement {
|
||||
@Tagname('scrolling')
|
||||
class Scrolling extends SkyElement {
|
||||
void shadowRootReady() {
|
||||
Element parent = shadowRoot.querySelector('sky-scrollable');
|
||||
for (Map city in cities.kData.getRange(0, 300)) {
|
||||
@ -33,6 +33,6 @@ class ExampleScrollable extends SkyElement {
|
||||
}
|
||||
}
|
||||
|
||||
_init(script) => register(script, ExampleScrollable);
|
||||
_init(script) => register(script, Scrolling);
|
||||
</script>
|
||||
</sky-element>
|
||||
@ -1,38 +0,0 @@
|
||||
<script>
|
||||
import '/sky/framework/shell.dart' as shell;
|
||||
import 'dart:sky';
|
||||
import 'package:sky/services/sensors/sensors.mojom.dart';
|
||||
|
||||
class MyListener extends SensorListener {
|
||||
int count = 0;
|
||||
|
||||
void onAccuracyChanged(int accuracy) {
|
||||
print("onAccuracyChanged $accuracy");
|
||||
}
|
||||
|
||||
void onSensorChanged(SensorData data) {
|
||||
double value = data.values[0] + data.values[1] + data.values[2];
|
||||
if (value > 40.0) {
|
||||
document.querySelector('div').textContent =
|
||||
"Shake count " + (count++).toString();
|
||||
}
|
||||
}
|
||||
|
||||
MyListener.unbound() {
|
||||
stub = new SensorListenerStub.unbound()
|
||||
..delegate = this;
|
||||
}
|
||||
|
||||
SensorListenerStub stub;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var sensorService = new SensorServiceProxy.unbound();
|
||||
shell.requestService(sensorService);
|
||||
|
||||
var listener = new MyListener.unbound();
|
||||
sensorService.ptr.addListener(SensorType_ACCELEROMETER, listener.stub);
|
||||
listener.stub.listen();
|
||||
}
|
||||
</script>
|
||||
<div>Shake me.</div>
|
||||
@ -1,78 +0,0 @@
|
||||
SKY MODULE
|
||||
<import src="sky:core" as="sky"/>
|
||||
<!--
|
||||
! this module provides trivial vertical block layout
|
||||
! no margins, padding, borders, etc
|
||||
!-->
|
||||
<script>
|
||||
module.exports.BlockLayoutManager = class BlockLayoutManager extends sky.LayoutManager {
|
||||
function layout(width, height) {
|
||||
if (width == null)
|
||||
width = this.getIntrinsicWidth().value;
|
||||
let autoHeight = false;
|
||||
if (height == null) {
|
||||
height = 0;
|
||||
autoHeight = true;
|
||||
}
|
||||
this.assumeDimensions(width, height);
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
let y = 0;
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
if (child.needsLayout || child.descendantNeedsLayout) {
|
||||
let dims = child.layoutManager.layout(width, null);
|
||||
this.setChildSize(child, dims.width, dims.height);
|
||||
}
|
||||
this.setChildPosition(child, 0, y);
|
||||
y += child.height;
|
||||
loop = children.next();
|
||||
}
|
||||
if (autoHeight)
|
||||
height = y;
|
||||
this.markAsLaidOut();
|
||||
return {
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
function layoutDescendants() {
|
||||
this.layout(node.width, node.height);
|
||||
}
|
||||
function getIntrinsicWidth() {
|
||||
let width = this.node.getProperty('width');
|
||||
if (typeof width != 'number') {
|
||||
// e.g. width: auto
|
||||
width = 0;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
let childWidth = child.layoutManager.getIntrinsicWidth();
|
||||
if (width < childWidth.value)
|
||||
width = childWidth.value;
|
||||
loop = children.next();
|
||||
}
|
||||
}
|
||||
return super(width); // applies and provides our own min-width/max-width rules
|
||||
}
|
||||
function getIntrinsicHeight() {
|
||||
let height = this.node.getProperty('height');
|
||||
if (typeof height != 'number') {
|
||||
// e.g. height: auto
|
||||
height = 0;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
let childHeight = child.layoutManager.getIntrinsicHeight();
|
||||
if (height < childHeight.value)
|
||||
height = childHeight.value;
|
||||
loop = children.next();
|
||||
}
|
||||
}
|
||||
return super(height); // applies and provides our own min-height/max-height rules
|
||||
}
|
||||
}
|
||||
sky.registerLayoutManager('block', module.exports.BlockLayoutManager);
|
||||
</script>
|
||||
@ -1,152 +0,0 @@
|
||||
#!mojo mojo:sky
|
||||
<import src="sky:core" as="sky"/>
|
||||
<script>
|
||||
class BeehiveLayoutManager extends sky.LayoutManager {
|
||||
function layout(width, height) {
|
||||
if (width == null)
|
||||
width = this.getIntrinsicWidth().value;
|
||||
let autoHeight = false;
|
||||
if (height == null) {
|
||||
height = 0;
|
||||
autoHeight = true;
|
||||
}
|
||||
this.assumeDimensions(width, height);
|
||||
let cellCount = this.node.getProperty('beehive-count');
|
||||
let cellDim = width / cellCount;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
if (child.needsLayout) {
|
||||
child.layoutManager.layout(cellDim, cellDim);
|
||||
// we ignore the size the child reported from layout(), and force it to the cell dimensions
|
||||
this.setChildSize(child, cellDim, cellDim);
|
||||
} else if (child.descendantNeedsLayout) {
|
||||
child.layoutManager.layoutDescendants();
|
||||
this.setChildSize(child, cellDim, cellDim);
|
||||
}
|
||||
this.setChildPosition(child, x * cellDim + (y % 2) * cellDim/2, y * 3/4 * cellDim);
|
||||
x += 1;
|
||||
if (x > cellCount) {
|
||||
y += 1;
|
||||
x = 0;
|
||||
}
|
||||
loop = children.next();
|
||||
}
|
||||
if (height == 0)
|
||||
height = (1 + y * 3/4) * cellDim;
|
||||
this.markAsLaidOut();
|
||||
return {
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
function getIntrinsicHeight() {
|
||||
let height = this.node.getProperty('height');
|
||||
if (typeof height != 'number') {
|
||||
// e.g. height: auto
|
||||
width = this.getIntrinsicWidth().value;
|
||||
let cellCount = this.node.getProperty('beehive-count');
|
||||
let cellDim = width / cellCount;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
let childCount = 0;
|
||||
while (!loop.done) {
|
||||
childCount += 1;
|
||||
loop.next();
|
||||
}
|
||||
if (childCount > 0)
|
||||
height = cellDim * (1/4 + Math.ceil(childCount / cellCount) * 3/4);
|
||||
else
|
||||
height = 0;
|
||||
}
|
||||
return super(height); // does the equivalent of getIntrinsicWidth() above, applying min-height etc
|
||||
}
|
||||
function paintChildren(canvas) {
|
||||
let width = this.node.width;
|
||||
let cellCount = this.node.getProperty('beehive-count');
|
||||
let cellDim = width / cellCount;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
canvas.save();
|
||||
try {
|
||||
canvas.beginPath();
|
||||
canvas.moveTo(child.x, child.y + cellDim/4);
|
||||
canvas.lineTo(child.x + cellDim/2, child.y);
|
||||
canvas.lineTo(child.x + cellDim, child.y + cellDim/4);
|
||||
canvas.lineTo(child.x + cellDim, child.y + 3*cellDim/4);
|
||||
canvas.lineTo(child.x + cellDim/2, child.y + cellDim);
|
||||
canvas.moveTo(child.x, child.y + 3*cellDim/4);
|
||||
canvas.closePath();
|
||||
canvas.clip();
|
||||
canvas.paintChild(child);
|
||||
} finally {
|
||||
canvas.restore();
|
||||
}
|
||||
loop = children.next();
|
||||
}
|
||||
}
|
||||
function inHex(topLeftX, topLeftY, width, height, hitX, hitY) {
|
||||
let centerX = topLeftX - width/2;
|
||||
let absCenteredHitX = Math.abs(hitX - centerX);
|
||||
if (absCenteredHitX > width/2)
|
||||
return false;
|
||||
let centerY = topLeftY - height/2;
|
||||
let absCenteredHitY = Math.abs(hitY - centerY);
|
||||
if (absCenteredHitY > height/2)
|
||||
return false;
|
||||
if (absCenteredHitY < height * absCenteredHitX / (2 * width) + height / 2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
function hitTest(x, y) {
|
||||
let cellCount = this.node.getProperty('beehive-count');
|
||||
let cellDim = width / cellCount;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
if (this.inHex(child.x, child.y, child.width, child.height, x, y))
|
||||
return child.layoutManager.hitTest(x-child.x, y-child.y);
|
||||
loop = children.next();
|
||||
}
|
||||
return this.node;
|
||||
}
|
||||
}
|
||||
sky.registerLayoutManager('beehive', BeehiveLayoutManager);
|
||||
let BeehiveCountStyleGrammar = new StyleGrammar();
|
||||
BeehiveCountStyleGrammar.addParser((tokens) => {
|
||||
let token = tokens.next();
|
||||
if (token.done)
|
||||
throw new Error();
|
||||
if (token.value.kind != 'number')
|
||||
throw new Error();
|
||||
if (token.value.value <= 0)
|
||||
throw new Error();
|
||||
if (Math.trunc(token.value.value) != token.value.value) // is integer
|
||||
throw new Error();
|
||||
return new NumericStyleValue(token.value.value);
|
||||
});
|
||||
sky.registerProperty({
|
||||
name: 'beehive-count',
|
||||
type: BeehiveCountStyleGrammar,
|
||||
inherits: true,
|
||||
initialValue: 5,
|
||||
needsLayout: true,
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
div { display: beehive; beehive-count: 3; }
|
||||
</style>
|
||||
<div>
|
||||
<t>Hello</t>
|
||||
<t>World</t>
|
||||
<t>How</t>
|
||||
<t>Are</t>
|
||||
<t>You</t>
|
||||
<t>Today?</t>
|
||||
</div>
|
||||
@ -1,143 +0,0 @@
|
||||
SKY MODULE
|
||||
<!-- this is part of sky:core -->
|
||||
<script>
|
||||
// "internals" is an object only made visible to this module that exports stuff implemented in C++
|
||||
module.exports.registerProperty = internals.registerProperty;
|
||||
internals.registerLayoutManager('none', null);
|
||||
module.exports.LayoutManager = internals.LayoutManager;
|
||||
module.exports.InlineLayoutManager = internals.InlineLayoutManager;
|
||||
internals.registerLayoutManager('inline', internals.InlineLayoutManager);
|
||||
module.exports.ParagraphLayoutManager = internals.ParagraphLayoutManager;
|
||||
internals.registerLayoutManager('paragraph', internals.ParagraphLayoutManager);
|
||||
module.exports.BlockLayoutManager = internals.BlockLayoutManager;
|
||||
internals.registerLayoutManager('block', internals.BlockLayoutManager);
|
||||
|
||||
let displayTypes = new Map();
|
||||
module.exports.registerLayoutManager = function registerLayoutManager(displayValue, layoutManagerConstructor) {
|
||||
// TODO(ianh): apply rules for type-checking displayValue is a String
|
||||
// TODO(ianh): apply rules for type-checking layoutManagerConstructor implements the LayoutManagerConstructor interface (or is null)
|
||||
if (displayTypes.has(displayValue))
|
||||
throw new Error();
|
||||
displayTypes.set(displayValue, layoutManagerConstructor);
|
||||
};
|
||||
|
||||
module.exports.DisplayStyleGrammar = new StyleGrammar(); // value is null or a LayoutManagerConstructor
|
||||
module.exports.DisplayStyleGrammar.addParser((tokens) => {
|
||||
let token = tokens.next();
|
||||
if (token.done)
|
||||
throw new Error();
|
||||
if (token.value.kind != 'identifier')
|
||||
throw new Error();
|
||||
if (!displayTypes.has(token.value.value))
|
||||
throw new Error();
|
||||
return {
|
||||
value: displayTypes.get(token.value.value),
|
||||
}
|
||||
});
|
||||
|
||||
internals.registerProperty({
|
||||
name: 'display',
|
||||
type: module.exports.DisplayStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: internals.BlockLayoutManager,
|
||||
needsLayout: true,
|
||||
});
|
||||
|
||||
module.exports.PositiveLengthStyleGrammar = new StyleGrammar(); // value is a ParsedValue whose value (once resolved) is a number in 96dpi pixels, >=0
|
||||
module.exports.PositiveLengthStyleGrammar.addParser((tokens) => {
|
||||
// just handle "<number>px"
|
||||
let token = tokens.next();
|
||||
if (token.done)
|
||||
throw new Error();
|
||||
if (token.value.kind != 'dimension')
|
||||
throw new Error();
|
||||
if (token.value.unit != 'px')
|
||||
throw new Error();
|
||||
if (token.value.value < 0)
|
||||
throw new Error();
|
||||
return {
|
||||
value: token.value.value;
|
||||
};
|
||||
});
|
||||
|
||||
internals.registerProperty({
|
||||
name: 'min-width',
|
||||
type: module.exports.PositiveLengthStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: 0,
|
||||
needsLayout: true,
|
||||
});
|
||||
internals.registerProperty({
|
||||
name: 'min-height',
|
||||
type: module.exports.PositiveLengthStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: 0,
|
||||
needsLayout: true,
|
||||
});
|
||||
|
||||
module.exports.PositiveLengthOrAutoStyleGrammar = new StyleGrammar(); // value is a ParsedValue whose value (once resolved) is either a number in 96dpi pixels (>=0) or null (meaning 'auto')
|
||||
module.exports.PositiveLengthOrAutoStyleGrammar.addParser((tokens) => {
|
||||
// handle 'auto'
|
||||
let token = tokens.next();
|
||||
if (token.done)
|
||||
throw new Error();
|
||||
if (token.value.kind != 'identifier')
|
||||
throw new Error();
|
||||
if (token.value.value != 'auto')
|
||||
throw new Error();
|
||||
return {
|
||||
value: null,
|
||||
};
|
||||
});
|
||||
module.exports.PositiveLengthOrAutoStyleGrammar.addParser((tokens) => {
|
||||
return module.exports.PositiveLengthStyleGrammar.parse(tokens);
|
||||
});
|
||||
|
||||
internals.registerProperty({
|
||||
name: 'width',
|
||||
type: module.exports.PositiveLengthOrAutoStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: null,
|
||||
needsLayout: true,
|
||||
});
|
||||
internals.registerProperty({
|
||||
name: 'height',
|
||||
type: module.exporets.PositiveLengthOrAutoStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: null,
|
||||
needsLayout: true,
|
||||
});
|
||||
|
||||
module.exports.PositiveLengthOrInfinityStyleGrammar = new StyleGrammar(); // value is a ParsedValue whose value (once resolved) is either a number in 96dpi pixels (>=0) or Infinity
|
||||
module.exports.PositiveLengthOrInfinityStyleGrammar.addParser((tokens) => {
|
||||
// handle 'infinity'
|
||||
let token = tokens.next();
|
||||
if (token.done)
|
||||
throw new Error();
|
||||
if (token.value.kind != 'identifier')
|
||||
throw new Error();
|
||||
if (token.value.value != 'infinity')
|
||||
throw new Error();
|
||||
return {
|
||||
value: Infinity,
|
||||
};
|
||||
});
|
||||
module.exports.PositiveLengthOrInfinityStyleGrammar.addParser((tokens) => {
|
||||
return module.exports.PositiveLengthStyleGrammar.parse(tokens);
|
||||
});
|
||||
|
||||
internals.registerProperty({
|
||||
name: 'width',
|
||||
type: module.exports.PositiveLengthOrInfinityStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: Infinity,
|
||||
needsLayout: true,
|
||||
});
|
||||
internals.registerProperty({
|
||||
name: 'height',
|
||||
type: module.exporets.PositiveLengthOrInfinityStyleGrammar,
|
||||
inherits: false,
|
||||
initialValue: Infinity,
|
||||
needsLayout: true,
|
||||
});
|
||||
</script>
|
||||
@ -1,214 +0,0 @@
|
||||
SKY MODULE
|
||||
<import src="sky:core" as="sky"/>
|
||||
<script>
|
||||
// display: toolbar;
|
||||
// toolbar-spacing: <length>
|
||||
// display: spring; // remaining space is split equally amongst the springs
|
||||
// children are vertically centered, layout out left-to-right with toolbar-spacing space between them
|
||||
// last child is hidden by default unless there's not enough room for the others, then it's shown last, right-aligned
|
||||
module.exports.SpringLayoutManager = class SpringLayoutManager extends sky.LayoutManager { }
|
||||
sky.registerLayoutManager('spring', module.exports.SpringLayoutManager);
|
||||
sky.registerProperty({
|
||||
name: 'toolbar-spacing',
|
||||
type: sky.PositiveLengthStyleGrammar,
|
||||
inherits: true,
|
||||
initialValue: 8,
|
||||
needsLayout: true,
|
||||
});
|
||||
module.exports.ToolbarLayoutManager = class ToolbarLayoutManager extends sky.LayoutManager {
|
||||
constructor (styleNode) {
|
||||
super(styleNode);
|
||||
this.showingOverflow = false;
|
||||
this.firstSkippedChild = null;
|
||||
this.overflowChild = null;
|
||||
}
|
||||
function layout(width, height) {
|
||||
let children = null;
|
||||
let loop = null;
|
||||
if (height == null)
|
||||
height = this.getIntrinsicHeight().value;
|
||||
if (width == null)
|
||||
this.assumeDimensions(0, height);
|
||||
else
|
||||
this.assumeDimensions(width, height);
|
||||
let spacing = this.node.getProperty('toolbar-spacing');
|
||||
if (typeof spacing != 'number')
|
||||
spacing = 0;
|
||||
this.overflowChild = null;
|
||||
this.firstSkippedChild = null;
|
||||
|
||||
// layout children and figure out whether we need to truncate the child list and show the overflow child
|
||||
let springCount = 0;
|
||||
let minX = 0;
|
||||
let overflowChildWidth = 0;
|
||||
let pendingSpacing = 0;
|
||||
children = this.walkChildren();
|
||||
loop = children.next();
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
let dims = null;
|
||||
if (child.layoutManager instanceof module.exports.SpringLayoutManager) {
|
||||
springCount += 1;
|
||||
pendingSpacing = spacing; // not +=, because we only have one extra spacing per batch of springs
|
||||
} else {
|
||||
if (child.needsLayout || child.descendantNeedsLayout) {
|
||||
childHeight = child.layoutManager.getIntrinsicHeight();
|
||||
if (childHeight.value < height)
|
||||
childHeight = childHeight.value;
|
||||
else
|
||||
childHeight = height;
|
||||
dims = child.layoutManager.layout(null, height);
|
||||
this.setChildSize(child, dims.width, dims.height);
|
||||
} else {
|
||||
dims = {
|
||||
width: child.width,
|
||||
height: child.height,
|
||||
};
|
||||
}
|
||||
loop = children.next();
|
||||
if (!loop.done) {
|
||||
if (minX > 0)
|
||||
minX += spacing + pendingSpacing;
|
||||
minX += dims.width;
|
||||
pendingSpacing = 0;
|
||||
} else {
|
||||
overflowChildWidth = spacing + dims.width;
|
||||
this.overflowChild = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// figure out the spacing
|
||||
this.showingOverflow = false;
|
||||
let springSize = 0;
|
||||
if (width != null) {
|
||||
if (minX <= width) {
|
||||
if (springCount > 0)
|
||||
springSize = (width - minX) / sprintCount;
|
||||
} else {
|
||||
this.showingOverflow = true;
|
||||
}
|
||||
} else {
|
||||
width = minX;
|
||||
}
|
||||
|
||||
// position the children
|
||||
// TODO(ianh): support rtl toolbars
|
||||
let x = 0;
|
||||
let lastWasNonSpring = false;
|
||||
children = this.walkChildren();
|
||||
loop = children.next();
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
if (child.layoutManager instanceof module.exports.SpringLayoutManager) {
|
||||
x += springSize;
|
||||
if (lastWasNonSpring)
|
||||
x += spacing;
|
||||
lastWasNonSpring = false;
|
||||
} else {
|
||||
if (!loop.done) {
|
||||
if (x + child.width + overflowChildWidth > width) {
|
||||
this.firstSkippedChild = child;
|
||||
break; // don't display any more children
|
||||
}
|
||||
this.setChildPosition(child, x, (height - child.height)/2);
|
||||
x += child.width + spacing;
|
||||
lastWasNonSpring = true;
|
||||
} else {
|
||||
// assert: this.showingOverflow == false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.showingOverflow)
|
||||
this.setChildPosition(this.overflowChild, width-this.overflowChild.width, (height - this.overflowChild.height)/2);
|
||||
else
|
||||
this.firstSkippedChild = this.overflowChild;
|
||||
|
||||
this.markAsLaidOut();
|
||||
return {
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
function layoutDescendants() {
|
||||
this.layout(node.width, node.height);
|
||||
}
|
||||
function getIntrinsicWidth() {
|
||||
let width = this.node.getProperty('width');
|
||||
if (typeof width != 'number') {
|
||||
let spacing = this.node.getProperty('toolbar-spacing');
|
||||
if (typeof spacing != 'number')
|
||||
spacing = 0;
|
||||
width = 0;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
// we exclude the last child because at our ideal width we wouldn't need it
|
||||
let last1 = null; // last one
|
||||
let last2 = null; // one before the last one
|
||||
while (!loop.done) {
|
||||
if (last1)
|
||||
width += last1.layoutManager.getIntrinsicWidth().value;
|
||||
if (last2)
|
||||
width += spacing;
|
||||
last2 = last1;
|
||||
last1 = loop.value;
|
||||
loop = children.next();
|
||||
}
|
||||
}
|
||||
return super(width); // applies and provides our own min-width/max-width rules
|
||||
}
|
||||
function getIntrinsicHeight() {
|
||||
// we grow our minimum height to be no smaller than the children's
|
||||
let result = super();
|
||||
let determineHeight = false;
|
||||
let heightProperty = this.node.getProperty('height');
|
||||
if (typeof heightProperty != 'number')
|
||||
determineHeight = true;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
// here we include the last child so that if it pops in our height doesn't change
|
||||
while (!loop.done) {
|
||||
let child = loop.value;
|
||||
let childHeight = child.layoutManager.getIntrinsicHeight();
|
||||
if (determineHeight) {
|
||||
if (result.value < childHeight.value)
|
||||
result.value = childHeight.value;
|
||||
}
|
||||
if (result.minimum < childHeight.minimum)
|
||||
result.minimum = childHeight.minimum;
|
||||
loop = children.next();
|
||||
}
|
||||
if (result.minimum > result.maximum)
|
||||
result.maximum = result.minimum;
|
||||
if (result.value > result.maximum)
|
||||
result.value = result.maximum;
|
||||
if (result.value < result.minimum)
|
||||
result.value = result.minimum;
|
||||
return result;
|
||||
}
|
||||
function paintChildren(canvas) {
|
||||
let width = this.node.width;
|
||||
let children = this.walkChildren();
|
||||
let loop = children.next();
|
||||
while ((!loop.done) && (loop.value != this.firstSkippedChild))
|
||||
canvas.paintChild(loop.value);
|
||||
if (this.showingOverflow)
|
||||
canvas.paintChild(this.overflowChild);
|
||||
}
|
||||
function inChild(child, x, y) {
|
||||
return (x >= child.x) && (y >= child.y) && (x < child.x+child.width) && (y < child.y+child.height);
|
||||
}
|
||||
function hitTest(x, y) {
|
||||
let children = this.walkChildrenBackwards();
|
||||
let loop = children.next();
|
||||
while ((!loop.done) && (loop.value != this.firstSkippedChild))
|
||||
if (this.inChild(loop.value, x, y))
|
||||
return loop.value;
|
||||
if (this.showingOverflow)
|
||||
if (this.inChild(this.overflowChild, x, y))
|
||||
return this.overflowChild;
|
||||
return this.node;
|
||||
}
|
||||
}
|
||||
sky.registerLayoutManager('toolbar', module.exports.ToolbarLayoutManager);
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user