Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
227
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/base/base.css
vendored
Normal file
227
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/base/base.css
vendored
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
|
||||
/** Variables
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:root {
|
||||
--dim-micro: 6px;
|
||||
--dim-small: 12px;
|
||||
--dim-medium: 24px;
|
||||
--dim-mega: 48px;
|
||||
|
||||
--base-xs: 6px;
|
||||
--base-s: 18px;
|
||||
--base-m: 24px;
|
||||
--base-l: 30px;
|
||||
--base-xl: 42px;
|
||||
--base-xxl: 60px;
|
||||
|
||||
--base-font-xs: 10px;
|
||||
--base-font-s: 14px;
|
||||
--base-font-m: 17px;
|
||||
--base-font-l: 23px;
|
||||
--base-font-xl: 60px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Apply a natural box layout
|
||||
* model to all elements
|
||||
*/
|
||||
|
||||
*,
|
||||
*:after,
|
||||
*:before {
|
||||
box-sizing: border-box; /* 1 */
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Document
|
||||
---------------------------------------------------------*/
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Body
|
||||
---------------------------------------------------------*/
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
font: 300 17px/21px 'FiraSans';
|
||||
background-color: var(--background);
|
||||
color: var(--text-color);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/** Tags
|
||||
---------------------------------------------------------*/
|
||||
|
||||
a {
|
||||
color: var(--highlight-color, inherit);
|
||||
text-decoration: none;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
margin: var(--dim-small) 0 var(--dim-small) 0;
|
||||
border: 0;
|
||||
background:
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
rgba(0,0,0,0.2)));
|
||||
}
|
||||
|
||||
em {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5 {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.alpha {
|
||||
font-size: 23px;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
line-height: 26px;
|
||||
margin: 6px 0 24px 0;
|
||||
}
|
||||
|
||||
.beta {
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
margin: 32px 0 16px 0;
|
||||
}
|
||||
|
||||
.gamma {
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
font-weight: normal;
|
||||
margin: 32px 0 16px 0;
|
||||
}
|
||||
|
||||
.milli {
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 23px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.mega {
|
||||
font-size: 60px;
|
||||
line-height: 60px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.giga {}
|
||||
.kilo {}
|
||||
|
||||
/* alignment */
|
||||
.l-align-right { float: right; }
|
||||
.l-align-left { float: left; }
|
||||
.l-align-center { text-align: center; }
|
||||
.l-text-align-left { text-align: left; }
|
||||
.l-text-align-right { text-align: right; }
|
||||
.l-text-valign-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.l-width-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/** Flexbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.l-flex { display: flex; }
|
||||
.l-flex-col { display: flex; flex-direction: column; }
|
||||
|
||||
.l-flex-col-v-align {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.l-flex-v-align { align-items: center; }
|
||||
.l-flex-h-align { justify-content: center; }
|
||||
.l-flex-grow { flex: 1; }
|
||||
|
||||
/** Margin
|
||||
---------------------------------------------------------*/
|
||||
|
||||
/* Top */
|
||||
|
||||
.l-mt-small { margin-top: var(--dim-small); }
|
||||
.l-mt-med { margin-top: var(--dim-medium); }
|
||||
|
||||
/* Bottom */
|
||||
|
||||
.l-mb-small { margin-bottom: var(--dim-small); }
|
||||
.l-mb-med { margin-bottom: var(--dim-medium); }
|
||||
.l-mb-large {}
|
||||
.l-mb-mega { margin-bottom: var(--dim-mega); }
|
||||
|
||||
/* Left */
|
||||
|
||||
.l-ml-small { margin-left: var(--dim-small); }
|
||||
|
||||
/* Right */
|
||||
|
||||
.l-mr-small { margin-right: var(--dim-small); }
|
||||
|
||||
/* Auto */
|
||||
|
||||
.l-mlr-auto { margin-left: auto; margin-right: auto; }
|
||||
.l-m-auto { margin: auto }
|
||||
|
||||
/* Margin */
|
||||
|
||||
.l-m-small { margin: var(--dim-small) }
|
||||
.l-m-med { margin: var(--dim-medium) }
|
||||
.l-m-0 { margin: 0 }
|
||||
|
||||
/** Padding
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.l-p-small { padding: var(--dim-small); }
|
||||
.l-pl-small { padding-left: var(--dim-small); }
|
||||
.l-pr-small { padding-right: var(--dim-small); }
|
||||
.l-plr-small {
|
||||
padding-right: var(--dim-small);
|
||||
padding-left: var(--dim-small);
|
||||
}
|
||||
.l-pb-small { padding-bottom: var(--dim-small); }
|
||||
.l-pt-small { padding-top: var(--dim-small); }
|
||||
.l-pt-mega { padding-top: var(--dim-mega); }
|
||||
.l-pt-micro { padding-top: var(--dim-micro); }
|
||||
.l-pb-micro { padding-bottom: var(--dim-micro); }
|
||||
.l-p-0 { padding: 0 ;}
|
||||
|
||||
/** Helpers
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.l-clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.l-inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.is-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.is-invisible {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
16
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/base/bower.json
vendored
Normal file
16
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/base/bower.json
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "base",
|
||||
"version": "0.0.0",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "base.css",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "fast-list",
|
||||
"version": "0.1.2",
|
||||
"homepage": "https://github.com/gaia-components/fast-list",
|
||||
"authors": [
|
||||
"Etienne Segonzac <etienne@segonzac.info>",
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"description": "No, really.",
|
||||
"main": "fast-list.js",
|
||||
"keywords": [
|
||||
"web",
|
||||
"performance",
|
||||
"virtual",
|
||||
"list"
|
||||
],
|
||||
"license": "MPL",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "fast-list/examples/sections",
|
||||
"version": "0.1.0",
|
||||
"homepage": "https://github.com/gaia-components/fast-list",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "index.html",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"dom-scheduler": "etiennesegonzac/dom-scheduler"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
font-family: sans-serif;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#h1-after {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
left: 0;
|
||||
top: 46px;
|
||||
|
||||
pointer-events: none;
|
||||
background-color: #ff9500;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
animation-duration: 0.25s;
|
||||
animation-timing-function: ease-in;
|
||||
animation-fill-mode: both;
|
||||
|
||||
-webkit-animation-duration: 0.25s;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
-webkit-animation-fill-mode: both;
|
||||
}
|
||||
|
||||
[data-anim='reveal'] {
|
||||
animation-name: reveal;
|
||||
-webkit-animation-name: reveal;
|
||||
}
|
||||
|
||||
@keyframes reveal {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes reveal {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
[data-anim='hide'] {
|
||||
animation-name: hide;
|
||||
-webkit-animation-name: hide;
|
||||
}
|
||||
|
||||
@keyframes hide {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes hide {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 50px;
|
||||
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
outline: 0;
|
||||
background: none;
|
||||
padding: 0 15px;
|
||||
|
||||
text-align: center;
|
||||
text-decoration: underline;
|
||||
font-size: 14px;
|
||||
color: #ffffff;
|
||||
-moz-appearance: none;
|
||||
|
||||
opacity: 1;
|
||||
transition: transform 0.1s linear,
|
||||
opacity 0.1s linear;
|
||||
-webkit-transition: -webkit-transform 0.1s linear,
|
||||
opacity 0.1s linear;
|
||||
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
button.transitioning {
|
||||
opacity: 0.5;
|
||||
transform: scale(0.6, 0.6);
|
||||
-webkit-transform: scale(0.6, 0.6);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body > section {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
h1 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #27c8c2;
|
||||
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-size: 24px;
|
||||
color: #ffffff;
|
||||
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
ul {
|
||||
list-style: none;
|
||||
padding: 0 0 0 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul section {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul h2 {
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
top: 0px;
|
||||
height: 32px;
|
||||
|
||||
margin: 0;
|
||||
padding: 0 6px;
|
||||
box-sizing: border-box;
|
||||
|
||||
font-size: 0.9em;
|
||||
line-height: 32px;
|
||||
|
||||
background: #efefef;
|
||||
border-bottom: 1px #bcbcbc solid;
|
||||
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
ul .background {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
background: linear-gradient(to bottom, transparent 0px, transparent 45px, #EDEDED 45px, #EDEDED 70px, transparent 20px),
|
||||
linear-gradient(to bottom, transparent 0px, transparent 15px, #EDEDED 15px, #EDEDED 25px, transparent 20px),
|
||||
linear-gradient(to top, #bcbcbc, #bcbcbc 1px, white 1px, white);
|
||||
background-position: 20% 88px, 5% -88px, 0 -88px;
|
||||
background-size: 90% 88px, 60% 88px, 100% 88px;
|
||||
background-repeat: repeat-y;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
ul.reordering .background {
|
||||
background: linear-gradient(to top, #bcbcbc, #bcbcbc 1px, white 1px, white);
|
||||
background-position: 0 -88px;
|
||||
background-size: 100% 88px;
|
||||
}
|
||||
|
||||
ul li {
|
||||
width: 100%;
|
||||
height: 88px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
-moz-user-select: none;
|
||||
|
||||
background: white;
|
||||
border-bottom: 1px #bcbcbc solid;
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
ul li h3 {
|
||||
margin: 0;
|
||||
padding: 9px 6px 3px 6px;
|
||||
background: white;
|
||||
|
||||
color: #424242;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
ul li p {
|
||||
margin: 0;
|
||||
padding: 3px 6px 10px 6px;
|
||||
background: white;
|
||||
|
||||
color: #797979;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
li.new {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
li .overlay {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% - 2px);
|
||||
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
|
||||
opacity: 0;
|
||||
animation-duration: 0.2s;
|
||||
animation-timing-function: ease-in;
|
||||
animation-fill-mode: both;
|
||||
|
||||
-webkit-animation-duration: 0.2s;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
-webkit-animation-fill-mode: both;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
li.edit .overlay {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.overlay .cursor {
|
||||
margin: 17px auto;
|
||||
padding: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-size: 25px;
|
||||
color: #0b0b0b;
|
||||
|
||||
border-radius: 8px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
li.dragging {
|
||||
transition: transform 0s linear;
|
||||
-webkit-transition: -webkit-transform 0s linear;
|
||||
}
|
||||
|
||||
li.dragging .overlay {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
li[data-populated=false] {
|
||||
opacity: 0;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
|
||||
|
||||
<link rel="stylesheet" href="css/h1.css">
|
||||
<link rel="stylesheet" href="css/ul.css">
|
||||
<link rel="stylesheet" href="css/app.css">
|
||||
|
||||
<script src="bower_components/dom-scheduler/lib/dom-scheduler.js" defer></script>
|
||||
<script src="fast-list.js" async></script>
|
||||
|
||||
<script src="js/bacon-source.js" async></script>
|
||||
<script src="js/page.js" async></script>
|
||||
|
||||
<title>Dom Scheduler Demo</title>
|
||||
</head>
|
||||
|
||||
<body class="theme-communications">
|
||||
<h1>
|
||||
Main List
|
||||
</h1>
|
||||
<div id="h1-after"></div>
|
||||
<button>
|
||||
Edit
|
||||
</button>
|
||||
<section>
|
||||
<ul>
|
||||
<section
|
||||
><h2> </h2
|
||||
><div class="background"
|
||||
></div
|
||||
></section>
|
||||
<li
|
||||
><h3> </h3
|
||||
><p> </p
|
||||
><div class="overlay"
|
||||
><div class="cursor">↕︎</div></div
|
||||
></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
(function() {
|
||||
var debug = false;
|
||||
var headerHeight = 50;
|
||||
var maxItemCount = 28;
|
||||
|
||||
var endEvent = ('ontouchstart' in window) ? 'touchend' : 'mouseup';
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
var listContainer = document.querySelector('section');
|
||||
|
||||
var source = new BaconSource();
|
||||
var list = new FastList(listContainer, source, scheduler);
|
||||
var dialog = document.querySelector('gaia-dialog-alert');
|
||||
|
||||
function updateHeader() {
|
||||
return scheduler.mutation(function() {
|
||||
var h1 = document.querySelector('h1');
|
||||
h1.textContent = 'Main List (' + source.fullLength() + ')';
|
||||
h1.scrollTop; // flush
|
||||
});
|
||||
}
|
||||
updateHeader();
|
||||
|
||||
function clearNewIndicator() {
|
||||
var h1After = document.querySelector('#h1-after');
|
||||
|
||||
if (h1After.dataset.anim == 'reveal') {
|
||||
scheduler.transition(function() {
|
||||
h1After.dataset.anim = 'hide';
|
||||
}, h1After, 'animationend');
|
||||
}
|
||||
}
|
||||
listContainer.addEventListener('top-reached', clearNewIndicator);
|
||||
|
||||
function updateNewIndicator() {
|
||||
var h1After = document.querySelector('#h1-after');
|
||||
if (h1After.dataset.anim == 'reveal') {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.transition(function() {
|
||||
h1After.dataset.anim = 'reveal';
|
||||
}, h1After, 'animationend');
|
||||
}
|
||||
listContainer.addEventListener('hidden-new-content', updateNewIndicator);
|
||||
|
||||
function openGaiaDialog(evt) {
|
||||
scheduler.mutation(function() {
|
||||
var detail = evt.detail;
|
||||
var li = source.getRecordAt(detail.index);
|
||||
dialog.textContent = li.title + ' item clicked!';
|
||||
dialog.open(detail.clickEvt);
|
||||
});
|
||||
}
|
||||
list.list.addEventListener('item-selected', openGaiaDialog);
|
||||
|
||||
function newContentHandler() {
|
||||
var newContent = {
|
||||
title: 'NEW Bacon ' + Date.now().toString().slice(7, -1),
|
||||
body: 'Turkey BLT please.'
|
||||
};
|
||||
|
||||
source.insertAtIndex(0, newContent);
|
||||
list.insertedAtIndex(0);
|
||||
|
||||
updateHeader();
|
||||
}
|
||||
|
||||
setInterval(newContentHandler, 15000);
|
||||
window.addEventListener('new-content', newContentHandler);
|
||||
|
||||
window.pushNewContent = function() {
|
||||
window.dispatchEvent(new CustomEvent('new-content'));
|
||||
};
|
||||
|
||||
var button = document.querySelector('button');
|
||||
button.addEventListener(endEvent, function() {
|
||||
Promise.all([toggleTransitioning(), list.toggleEditMode()])
|
||||
.then(updateText)
|
||||
.then(toggleTransitioning);
|
||||
});
|
||||
|
||||
function updateText(text) {
|
||||
return scheduler.mutation(function() {
|
||||
button.textContent = list.editing ? 'Exit' : 'Edit';
|
||||
});
|
||||
}
|
||||
|
||||
function toggleTransitioning() {
|
||||
return scheduler.feedback(function() {
|
||||
button.classList.toggle('transitioning');
|
||||
}, button, 'transitionend');
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
(function(exports) {
|
||||
var listSize = 1042;
|
||||
var sectionCount = 25;
|
||||
|
||||
var headerHeight = 32;
|
||||
var itemHeight = 88;
|
||||
|
||||
function makeContent(prefix, name) {
|
||||
return {
|
||||
title: prefix + ' Bacon ipsum dolor ' +
|
||||
Date.now().toString().slice(7, -1),
|
||||
body: 'Turkey pig boudin ' + name.toLowerCase() +
|
||||
' de mignon drums and all ' + prefix + '.'
|
||||
}
|
||||
}
|
||||
|
||||
exports.BaconSource = function BaconSource() {
|
||||
this.sections = [];
|
||||
this.contentMap = new Map();
|
||||
this._cachedLength = null;
|
||||
|
||||
for (var i = 0; i < sectionCount; i++) {
|
||||
this.sections.push('Section ' + i);
|
||||
}
|
||||
|
||||
this.sections.forEach(function(name) {
|
||||
var content = [];
|
||||
for (var i = 0; i < (Math.random() * listSize); i++) {
|
||||
content.push(makeContent(i, name));
|
||||
}
|
||||
this.contentMap.set(name, content);
|
||||
}, this);
|
||||
};
|
||||
|
||||
exports.BaconSource.prototype = {
|
||||
populateItem: function(item, i) {
|
||||
// Simulates the data source not being ready to populate
|
||||
/*if (parseInt(Date.now() / 10) % 8 === 0) {*/
|
||||
/*return new Promise(function(resolve, reject) {*/
|
||||
/*setTimeout(resolve, Math.random() * 1000);*/
|
||||
/*});*/
|
||||
/*}*/
|
||||
|
||||
var title = item.firstChild;
|
||||
var body = title.nextSibling;
|
||||
var record = this.getRecordAt(i);
|
||||
|
||||
title.firstChild.data = record.title;
|
||||
body.firstChild.data = record.body;
|
||||
},
|
||||
|
||||
getSections: function() {
|
||||
return this.contentMap.keys();
|
||||
},
|
||||
|
||||
sectionHeaderHeight: function() {
|
||||
return headerHeight;
|
||||
},
|
||||
|
||||
fullSectionHeight: function(key) {
|
||||
return this.contentMap.get(key).length * itemHeight;
|
||||
},
|
||||
|
||||
fullSectionLength: function(key) {
|
||||
return this.contentMap(key).length;
|
||||
},
|
||||
|
||||
getRecordAt: function(index) {
|
||||
for (var section of this.contentMap.values()) {
|
||||
if (index < section.length) {
|
||||
return section[index];
|
||||
}
|
||||
index -= section.length;
|
||||
}
|
||||
},
|
||||
|
||||
getSectionFor: function(index) {
|
||||
for (var entry of this.contentMap.entries()) {
|
||||
if (index < entry[1].length) {
|
||||
return entry[0];
|
||||
}
|
||||
index -= entry[1].length;
|
||||
}
|
||||
},
|
||||
|
||||
indexAtPosition: function(pos) {
|
||||
var index = 0;
|
||||
for (var section of this.contentMap.values()) {
|
||||
pos -= headerHeight;
|
||||
var sectionHeight = section.length * itemHeight;
|
||||
if (pos > sectionHeight) {
|
||||
pos -= sectionHeight;
|
||||
index += section.length;
|
||||
continue;
|
||||
}
|
||||
for (var item of section) {
|
||||
pos -= itemHeight;
|
||||
index++;
|
||||
if (pos <= 0 || index === this.fullLength() - 1) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
positionForIndex: function(index) {
|
||||
var top = 0;
|
||||
for (var section of this.contentMap.values()) {
|
||||
top += headerHeight;
|
||||
if (index < section.length) {
|
||||
top += index * itemHeight;
|
||||
return top;
|
||||
}
|
||||
index -= section.length;
|
||||
top += section.length * itemHeight;
|
||||
}
|
||||
},
|
||||
|
||||
fullLength: function() {
|
||||
if (this._cachedLength) {
|
||||
return this._cachedLength;
|
||||
}
|
||||
|
||||
var length = 0;
|
||||
for (var section of this.contentMap.values()) {
|
||||
length += section.length;
|
||||
}
|
||||
this._cachedLength = length;
|
||||
return length;
|
||||
},
|
||||
|
||||
itemHeight: function() {
|
||||
return itemHeight;
|
||||
},
|
||||
|
||||
fullHeight: function() {
|
||||
var height = 0;
|
||||
for (var section of this.contentMap.values()) {
|
||||
height += headerHeight + section.length * itemHeight;
|
||||
}
|
||||
return height;
|
||||
},
|
||||
|
||||
insertAtIndex: function(index, record, toSection) {
|
||||
this._cachedLength = null;
|
||||
for (var entry of this.contentMap.entries()) {
|
||||
if (index < entry[1].length || entry[0] === toSection) {
|
||||
return entry[1].splice(index, 0, record);
|
||||
}
|
||||
index -= entry[1].length;
|
||||
}
|
||||
},
|
||||
|
||||
replaceAtIndex: function(index, record) {
|
||||
for (var section of this.contentMap.values()) {
|
||||
if (index < section.length) {
|
||||
return section.splice(index, 1, record);
|
||||
}
|
||||
index -= section.length;
|
||||
}
|
||||
},
|
||||
|
||||
removeAtIndex: function(index) {
|
||||
this._cachedLength = null;
|
||||
|
||||
for (var section of this.contentMap.values()) {
|
||||
if (index < section.length) {
|
||||
return section.splice(index, 1)[0];
|
||||
}
|
||||
index -= section.length;
|
||||
}
|
||||
}
|
||||
};
|
||||
})(window);
|
||||
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
(function() {
|
||||
/*global BaconSource, FastList*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var endEvent = ('ontouchstart' in window) ? 'touchend' : 'mouseup';
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
var listContainer = document.querySelector('section');
|
||||
|
||||
var source = new BaconSource();
|
||||
var list = new FastList(listContainer, source);
|
||||
var scheduler = FastList.scheduler;
|
||||
|
||||
function updateHeader() {
|
||||
return scheduler.mutation(function() {
|
||||
var h1 = document.querySelector('h1');
|
||||
h1.textContent = 'Main List (' + source.fullLength() + ')';
|
||||
h1.scrollTop; // flush
|
||||
});
|
||||
}
|
||||
updateHeader();
|
||||
|
||||
function openAlert(evt) {
|
||||
scheduler.mutation(function() {
|
||||
var detail = evt.detail;
|
||||
var li = source.getRecordAt(detail.index);
|
||||
alert(li.title + ' item clicked!');
|
||||
});
|
||||
}
|
||||
list.list.addEventListener('item-selected', openAlert);
|
||||
|
||||
function clearNewIndicator() {
|
||||
var h1After = document.querySelector('#h1-after');
|
||||
|
||||
if (h1After.dataset.anim == 'reveal') {
|
||||
scheduler.transition(function() {
|
||||
h1After.dataset.anim = 'hide';
|
||||
}, h1After, 'animationend');
|
||||
}
|
||||
}
|
||||
listContainer.addEventListener('top-reached', clearNewIndicator);
|
||||
|
||||
function updateNewIndicator() {
|
||||
var h1After = document.querySelector('#h1-after');
|
||||
if (h1After.dataset.anim == 'reveal') {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.transition(function() {
|
||||
h1After.dataset.anim = 'reveal';
|
||||
}, h1After, 'animationend');
|
||||
}
|
||||
listContainer.addEventListener('hidden-new-content', updateNewIndicator);
|
||||
|
||||
function newContentHandler() {
|
||||
var newContent = {
|
||||
title: 'NEW Bacon ' + Date.now().toString().slice(7, -1),
|
||||
body: 'Turkey BLT please.'
|
||||
};
|
||||
|
||||
source.insertAtIndex(0, newContent);
|
||||
list.insertedAtIndex(0);
|
||||
|
||||
updateHeader();
|
||||
}
|
||||
|
||||
setInterval(newContentHandler, 15000);
|
||||
window.addEventListener('new-content', newContentHandler);
|
||||
|
||||
window.pushNewContent = function() {
|
||||
window.dispatchEvent(new CustomEvent('new-content'));
|
||||
};
|
||||
|
||||
var button = document.querySelector('button');
|
||||
button.addEventListener(endEvent, function() {
|
||||
Promise.all([toggleTransitioning(), list.toggleEditMode()])
|
||||
.then(updateText)
|
||||
.then(toggleTransitioning);
|
||||
});
|
||||
|
||||
function updateText(text) {
|
||||
return scheduler.mutation(function() {
|
||||
button.textContent = list.editing ? 'Exit' : 'Edit';
|
||||
});
|
||||
}
|
||||
|
||||
function toggleTransitioning() {
|
||||
return scheduler.feedback(function() {
|
||||
button.classList.toggle('transitioning');
|
||||
}, button, 'transitionend');
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "fast-list-demo",
|
||||
"description": "Faaaaasssst",
|
||||
"launch_path": "/index.html",
|
||||
"icons": {
|
||||
"16": "/icons/icon16x16.png",
|
||||
"48": "/icons/icon48x48.png",
|
||||
"60": "/icons/icon60x60.png",
|
||||
"128": "/icons/icon128x128.png"
|
||||
},
|
||||
"type": "certified",
|
||||
"orientation": "default",
|
||||
"permissions": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
/* mini reset */
|
||||
* { margin: 0; padding: 0; }
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header,
|
||||
footer {
|
||||
height: 50px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
#content {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0 0 0 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul section {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul h2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
background: linear-gradient(to top, #bcbcbc, #bcbcbc 1px, white 1px, white);
|
||||
background-position: 0 -88px;
|
||||
background-size: 100% 88px;
|
||||
background-repeat: repeat-y;
|
||||
}
|
||||
|
||||
|
||||
ul li {
|
||||
width: 100%;
|
||||
height: 88px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
-moz-user-select: none;
|
||||
|
||||
background: white;
|
||||
border-bottom: 1px #bcbcbc solid;
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
ul li h3 {
|
||||
margin: 0;
|
||||
padding: 9px 6px 3px 6px;
|
||||
background: white;
|
||||
|
||||
color: #424242;
|
||||
}
|
||||
|
||||
ul li p {
|
||||
margin: 0;
|
||||
padding: 3px 6px 10px 6px;
|
||||
background: white;
|
||||
|
||||
color: #797979;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*global DataSource, FastList*/
|
||||
|
||||
var content = document.getElementById('content');
|
||||
var data = createDummyData(1000);
|
||||
var dataSource = new DataSource(data);
|
||||
var list = new FastList(content, dataSource);
|
||||
|
||||
function createDummyData(count) {
|
||||
var result = [];
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
result.push({
|
||||
name: 'Song ' + i,
|
||||
metadata: {
|
||||
title: 'Song title ' + i,
|
||||
artist: 'Song artist ' + i
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
(function(exports) {
|
||||
var itemHeight = 88;
|
||||
|
||||
var debug = 0 ? (...args) => console.log('[DataSource]', ...args) : ()=>{};
|
||||
|
||||
exports.DataSource = function DataSource(items) {
|
||||
this.items = items;
|
||||
debug('initialized', items);
|
||||
};
|
||||
|
||||
exports.DataSource.prototype = {
|
||||
populateItem: function(item, i) {
|
||||
debug('populate item', item);
|
||||
var title = item.firstChild;
|
||||
var body = title.nextSibling;
|
||||
var record = this.getRecordAt(i);
|
||||
|
||||
title.firstChild.data = record.name;
|
||||
body.firstChild.data = record.metadata.artist;
|
||||
},
|
||||
|
||||
getSections() {
|
||||
debug('get sections');
|
||||
return [''];
|
||||
},
|
||||
|
||||
sectionHeaderHeight() {
|
||||
return 0;
|
||||
},
|
||||
|
||||
fullSectionHeight() {
|
||||
var result = this.items.length * itemHeight;
|
||||
debug('full section height', result);
|
||||
return result;
|
||||
},
|
||||
|
||||
fullSectionLength() {
|
||||
var result = this.items.length;
|
||||
debug('full section length', result);
|
||||
return result;
|
||||
},
|
||||
|
||||
getSectionFor() {
|
||||
return '';
|
||||
},
|
||||
|
||||
getRecordAt: function(index) {
|
||||
return this.items[index];
|
||||
},
|
||||
|
||||
indexAtPosition: function(pos) {
|
||||
return Math.floor(pos / itemHeight);
|
||||
},
|
||||
|
||||
positionForIndex: function(index) {
|
||||
return index * itemHeight;
|
||||
},
|
||||
|
||||
fullLength: function() {
|
||||
return this.items.length;
|
||||
},
|
||||
|
||||
itemHeight: function() {
|
||||
return itemHeight;
|
||||
},
|
||||
|
||||
fullHeight: function() {
|
||||
this.items.length * itemHeight;
|
||||
},
|
||||
|
||||
insertAtIndex: function(index, record, toSection) {
|
||||
return this.items.splice(index, 0, record);
|
||||
},
|
||||
|
||||
replaceAtIndex: function(index, record) {
|
||||
return this.items.splice(index, 1)[0];
|
||||
}
|
||||
};
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
|
||||
<link rel="stylesheet" href="app.css">
|
||||
<title>fast-list: simple</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>Header</header>
|
||||
<section id="content" style="height:100%;">
|
||||
<ul>
|
||||
<section
|
||||
><h2> </h2
|
||||
><div class="background"
|
||||
></div
|
||||
></section>
|
||||
<li
|
||||
><h3> </h3
|
||||
><p> </p
|
||||
></li>
|
||||
</ul>
|
||||
</section>
|
||||
<footer>Footer</footer>
|
||||
<!-- <script src="bower_components/dom-scheduler/lib/dom-scheduler.js"></script> -->
|
||||
<script src="fast-list.js"></script>
|
||||
<script src="data-source.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "simple-list-demo",
|
||||
"description": "Sweet",
|
||||
"launch_path": "/index.html",
|
||||
"icons": {
|
||||
"16": "/icons/icon16x16.png",
|
||||
"48": "/icons/icon48x48.png",
|
||||
"60": "/icons/icon60x60.png",
|
||||
"128": "/icons/icon128x128.png"
|
||||
},
|
||||
"orientation": "default",
|
||||
"permissions": {}
|
||||
}
|
||||
935
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/fast-list/fast-list.js
vendored
Normal file
935
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/fast-list/fast-list.js
vendored
Normal file
|
|
@ -0,0 +1,935 @@
|
|||
!(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
var debug = 0 ? console.log.bind(console, '[FastList]') : function() {};
|
||||
|
||||
var startEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';
|
||||
var moveEvent = ('ontouchstart' in window) ? 'touchmove' : 'mousemove';
|
||||
var endEvent = ('ontouchstart' in window) ? 'touchend' : 'mouseup';
|
||||
|
||||
/**
|
||||
* Use the dom-scheduler if it's around,
|
||||
* else fallback to fake shim.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var schedule = (window.scheduler && typeof window.scheduler.mutation === "function" ? window.scheduler : schedulerShim());
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
exports = module.exports = FastList;
|
||||
exports.scheduler = schedule;
|
||||
|
||||
function FastList(container, source, scheduler) {
|
||||
this.editing = false;
|
||||
|
||||
container.style.overflowX = 'hidden';
|
||||
container.style.overflowY = 'scroll';
|
||||
this.container = container;
|
||||
this.list = container.querySelector('ul');
|
||||
this.source = source;
|
||||
|
||||
this.geometry = {
|
||||
topPosition: 0,
|
||||
forward: true,
|
||||
|
||||
viewportHeight: 0,
|
||||
itemHeight: 0,
|
||||
headerHeight: 0,
|
||||
maxItemCount: 0,
|
||||
switchWindow: 0
|
||||
};
|
||||
|
||||
this._templateSection = this.list.querySelector('section');
|
||||
this.geometry.headerHeight = source.sectionHeaderHeight();
|
||||
this._templateSection.remove();
|
||||
|
||||
var template = this.list.querySelector('li');
|
||||
template.style.position = 'absolute';
|
||||
template.style.left = template.style.top = 0;
|
||||
template.style.overflow = 'hidden';
|
||||
template.style.willChange = 'transform';
|
||||
|
||||
this.geometry.itemHeight = template.offsetHeight;
|
||||
template.remove();
|
||||
|
||||
this._template = template;
|
||||
|
||||
this.updateContainerGeometry();
|
||||
|
||||
if (debug.name) {
|
||||
if (this.geometry.itemHeight !== source.itemHeight()) {
|
||||
debug('Template height and source height are not the same.');
|
||||
}
|
||||
}
|
||||
|
||||
this._rendered = false;
|
||||
this._previousTop = -1;
|
||||
this._previousFast = false;
|
||||
this._items = [];
|
||||
this._itemsInDOM = [];
|
||||
|
||||
this.reorderingContext = {
|
||||
item: null,
|
||||
initialY: null,
|
||||
identifier: null,
|
||||
moveUp: null,
|
||||
moveDown: null,
|
||||
};
|
||||
|
||||
this.updateListHeight();
|
||||
|
||||
schedule.attachDirect(
|
||||
this.container,
|
||||
'scroll',
|
||||
this.handleScroll.bind(this)
|
||||
);
|
||||
|
||||
on(this.container, 'click', this);
|
||||
on(window, 'resize', this);
|
||||
|
||||
schedule.mutation(function() {
|
||||
this.updateSections();
|
||||
this.render();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
FastList.prototype = {
|
||||
|
||||
/* Rendering
|
||||
========= */
|
||||
updateContainerGeometry: function() {
|
||||
var geo = this.geometry;
|
||||
|
||||
geo.viewportHeight = this.container.offsetHeight;
|
||||
var itemPerScreen = geo.viewportHeight / geo.itemHeight;
|
||||
// Taking into account the will-change budget multiplier from
|
||||
// layout/base/nsDisplayList.cpp#1193
|
||||
geo.maxItemCount = Math.floor(itemPerScreen * 2.4);
|
||||
geo.switchWindow = Math.floor(itemPerScreen / 2);
|
||||
|
||||
debug('maxItemCount: ' + geo.maxItemCount);
|
||||
},
|
||||
|
||||
// Returns true if we're fast scrolling
|
||||
updateViewportGeometry: function() {
|
||||
var geo = this.geometry;
|
||||
|
||||
var position = this.container.scrollTop;
|
||||
|
||||
// Don't compute velocity on first load
|
||||
if (this._previousTop === -1) {
|
||||
geo.topPosition = position;
|
||||
}
|
||||
|
||||
this._previousTop = geo.topPosition;
|
||||
geo.topPosition = position;
|
||||
|
||||
var distanceSinceLast = geo.topPosition - this._previousTop;
|
||||
|
||||
if ((distanceSinceLast > 0) && !geo.forward) {
|
||||
geo.forward = true;
|
||||
}
|
||||
|
||||
if ((distanceSinceLast < 0) && geo.forward) {
|
||||
geo.forward = false;
|
||||
}
|
||||
|
||||
if (geo.topPosition === 0 && this._previousTop !== 0) {
|
||||
this.container.dispatchEvent(new CustomEvent('top-reached'));
|
||||
}
|
||||
|
||||
var moved = Math.abs(distanceSinceLast);
|
||||
var fastScrolling = this._previousFast;
|
||||
if (!fastScrolling && moved > geo.viewportHeight * 2) {
|
||||
fastScrolling = true;
|
||||
}
|
||||
if (fastScrolling && moved > 0 && moved < geo.viewportHeight * 0.5) {
|
||||
fastScrolling = false;
|
||||
}
|
||||
this._previousFast = fastScrolling;
|
||||
|
||||
var onTop = position === 0;
|
||||
var atBottom = position === this.source.fullHeight() - geo.viewportHeight;
|
||||
|
||||
return fastScrolling && !onTop && !atBottom;
|
||||
},
|
||||
|
||||
render: function(reload, changedIndex) {
|
||||
var source = this.source;
|
||||
var items = this._items;
|
||||
var itemsInDOM = this._itemsInDOM;
|
||||
var geo = this.geometry;
|
||||
var template = this._template;
|
||||
var list = this.list;
|
||||
|
||||
var indices = computeIndices(this.source, this.geometry);
|
||||
var criticalStart = indices.cStart;
|
||||
var criticalEnd = indices.cEnd;
|
||||
var startIndex = indices.start;
|
||||
var endIndex = indices.end;
|
||||
|
||||
// Initial render generating all dom nodes
|
||||
if (!this._rendered) {
|
||||
this._rendered = true;
|
||||
endIndex = Math.min(source.fullLength() - 1,
|
||||
startIndex + this.geometry.maxItemCount - 1);
|
||||
}
|
||||
|
||||
var recyclableItems = recycle(items, criticalStart, criticalEnd,
|
||||
geo.forward ? endIndex : startIndex);
|
||||
|
||||
var findItemFor = function(index) {
|
||||
var item;
|
||||
|
||||
if (recyclableItems.length > 0) {
|
||||
var recycleIndex = recyclableItems.pop();
|
||||
item = items[recycleIndex];
|
||||
delete items[recycleIndex];
|
||||
} else if (itemsInDOM.length < geo.maxItemCount){
|
||||
item = template.cloneNode(true);
|
||||
list.appendChild(item);
|
||||
itemsInDOM.push(item);
|
||||
} else {
|
||||
console.warn('missing a cell');
|
||||
return;
|
||||
}
|
||||
|
||||
items[index] = item;
|
||||
return item;
|
||||
};
|
||||
|
||||
var renderItem = function(i) {
|
||||
var item = items[i];
|
||||
if (!item) {
|
||||
item = findItemFor(i);
|
||||
tryToPopulate(item, i, source, true);
|
||||
item.classList.toggle('new', i === changedIndex);
|
||||
} else if (reload) {
|
||||
source.populateItem(item, i);
|
||||
}
|
||||
|
||||
var section = source.getSectionFor(i);
|
||||
placeItem(item, i, section, geo, source, reload);
|
||||
};
|
||||
|
||||
if (geo.forward) {
|
||||
for (var i = startIndex; i <= endIndex; ++i) {
|
||||
renderItem(i);
|
||||
}
|
||||
} else {
|
||||
for (var j = endIndex; j >= startIndex; --j) {
|
||||
renderItem(j);
|
||||
}
|
||||
}
|
||||
|
||||
debugViewport(items, geo.forward, criticalStart, criticalEnd,
|
||||
startIndex, endIndex);
|
||||
},
|
||||
|
||||
/* Scrolling
|
||||
========= */
|
||||
handleScroll: function(evt) {
|
||||
var fast = this.updateViewportGeometry();
|
||||
if (fast) {
|
||||
debug('[x] ---------- faaaaassssstttt');
|
||||
} else {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
updateListHeight: function() {
|
||||
return schedule.mutation((function() {
|
||||
this.list.style.height = this.source.fullHeight() + 'px';
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
get scrollTop() {
|
||||
return this.geometry.topPosition;
|
||||
},
|
||||
|
||||
scrollInstantly: function(by) {
|
||||
this.container.scrollTop += by;
|
||||
this.updateViewportGeometry();
|
||||
this.render();
|
||||
},
|
||||
|
||||
reloadData: function() {
|
||||
return schedule.mutation((function() {
|
||||
this.updateSections();
|
||||
this.render(true);
|
||||
this.updateListHeight();
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
updateSections: function() {
|
||||
var list = this.list;
|
||||
var source = this.source;
|
||||
var template = this._templateSection;
|
||||
|
||||
return schedule.mutation(function() {
|
||||
var nodes = list.querySelectorAll('section');
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var toRemove = nodes[i];
|
||||
toRemove.remove();
|
||||
}
|
||||
|
||||
var headerHeight = source.sectionHeaderHeight();
|
||||
for (var section of source.getSections()) {
|
||||
var height = source.fullSectionHeight(section);
|
||||
|
||||
var sectionNode = template.cloneNode(true);
|
||||
sectionNode.style.height = headerHeight + height + 'px';
|
||||
|
||||
var title = sectionNode.firstChild;
|
||||
title.firstChild.data = section;
|
||||
|
||||
var background = title.nextSibling;
|
||||
background.style.height = height + 'px';
|
||||
|
||||
list.appendChild(sectionNode);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/* Edit mode
|
||||
========= */
|
||||
toggleEditMode: function() {
|
||||
this.editing = !this.editing;
|
||||
|
||||
if (this.editing) {
|
||||
this._startTouchListeners();
|
||||
} else {
|
||||
this._stopTouchListeners();
|
||||
}
|
||||
|
||||
return toggleEditClass(this.list,
|
||||
this._itemsInDOM, this.editing);
|
||||
},
|
||||
|
||||
_startTouchListeners: function() {
|
||||
on(this.list, startEvent, this);
|
||||
on(this.list, endEvent, this);
|
||||
},
|
||||
|
||||
_stopTouchListeners: function() {
|
||||
off(this.list, startEvent, this);
|
||||
off(this.list, endEvent, this);
|
||||
},
|
||||
|
||||
/* Reordering
|
||||
---------- */
|
||||
_reorderStart: function(evt) {
|
||||
debug('reorder start');
|
||||
var ctx = this.reorderingContext;
|
||||
|
||||
// Already tracking an item, bailing out
|
||||
if (ctx.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
var li = evt.target.parentNode.parentNode;
|
||||
var touch = evt.touches && evt.touches[0] || evt;
|
||||
|
||||
ctx.item = li;
|
||||
ctx.initialY = touch.pageY;
|
||||
ctx.identifier = touch.identifier;
|
||||
ctx.moveUp = new Set();
|
||||
ctx.moveDown = new Set();
|
||||
ctx.moveHandler = this._reorderMove.bind(this);
|
||||
|
||||
var listenToMove = (function() {
|
||||
schedule.attachDirect(this.list, moveEvent, ctx.moveHandler);
|
||||
}).bind(this);
|
||||
|
||||
setupForDragging(this.scheduler, li, true)
|
||||
.then(listenToMove)
|
||||
.then(toggleDraggingClass.bind(null, this.scheduler, li, true));
|
||||
},
|
||||
|
||||
_reorderMove: function(evt) {
|
||||
debug('reorder move');
|
||||
var ctx = this.reorderingContext;
|
||||
if (!ctx.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Multi touch
|
||||
if (evt.touches && evt.touches.length > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var li = ctx.item;
|
||||
var touch = evt.touches && evt.touches[0] || evt;
|
||||
var position = touch.pageY;
|
||||
|
||||
var delta = position - ctx.initialY;
|
||||
|
||||
this._rearrange(delta);
|
||||
tweakTransform(li, delta);
|
||||
|
||||
// TODO: scroll when close to the beginning/end of the viewport
|
||||
},
|
||||
|
||||
_reorderEnd: function(evt) {
|
||||
debug('reorder end');
|
||||
|
||||
var ctx = this.reorderingContext;
|
||||
if (!ctx.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
var li = ctx.item;
|
||||
schedule.detachDirect(this.list, moveEvent, ctx.moveHandler);
|
||||
|
||||
var touch = evt.touches && evt.touches[0] || evt;
|
||||
if (touch.identifier == ctx.identifier) {
|
||||
var position = touch.pageY;
|
||||
var delta = position - ctx.initialY;
|
||||
computeChanges(ctx, this.geometry, this._itemsInDOM, delta);
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
applyChanges(ctx, this.geometry, this._itemsInDOM),
|
||||
moveInPlace(ctx, this.geometry)
|
||||
]).then(this._reorderFinish.bind(this, li))
|
||||
.then(toggleDraggingClass.bind(null, schedule, li, false));
|
||||
},
|
||||
|
||||
_reorderFinish: function(li) {
|
||||
var scheduler = this.scheduler;
|
||||
return Promise.all([this._commitToDocument(),
|
||||
setupForDragging(scheduler, li, false)]);
|
||||
},
|
||||
|
||||
_rearrange: function(delta) {
|
||||
var ctx = this.reorderingContext;
|
||||
var upCount = ctx.moveUp.size;
|
||||
var downCount = ctx.moveDown.size;
|
||||
|
||||
computeChanges(this.reorderingContext, this.geometry,
|
||||
this._itemsInDOM, delta);
|
||||
|
||||
if (ctx.moveUp.size === upCount &&
|
||||
ctx.moveDown.size === downCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyChanges(this.reorderingContext,
|
||||
this.geometry, this._itemsInDOM);
|
||||
},
|
||||
|
||||
_commitToDocument: function() {
|
||||
var ctx = this.reorderingContext;
|
||||
var li = ctx.item;
|
||||
var itemsInDOM = this._itemsInDOM;
|
||||
var items = this._items;
|
||||
var source = this.source;
|
||||
|
||||
return schedule.mutation((function() {
|
||||
// Nothing to do
|
||||
if (!ctx.moveUp && !ctx.moveDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = items.indexOf(li);
|
||||
var section = li.dataset.section;
|
||||
var newIndex = index + ctx.moveUp.size - ctx.moveDown.size;
|
||||
|
||||
items.splice(index, 1);
|
||||
items.splice(newIndex, 0, li);
|
||||
var c = source.removeAtIndex(index);
|
||||
source.insertAtIndex(newIndex, c, section);
|
||||
|
||||
itemsInDOM.forEach(function(item) {
|
||||
resetTransition(item);
|
||||
resetTransform(item);
|
||||
});
|
||||
|
||||
this.updateSections();
|
||||
this.render();
|
||||
|
||||
ctx.item = null;
|
||||
ctx.initialY = null;
|
||||
ctx.identifier = null;
|
||||
ctx.moveUp = null;
|
||||
ctx.moveDown = null;
|
||||
ctx.moveHandler = null;
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
/* External content changes
|
||||
======================== */
|
||||
insertedAtIndex: function(index) {
|
||||
if (index !== 0) {
|
||||
//TODO: support any point of insertion
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.geometry.topPosition > this.geometry.itemHeight ||
|
||||
this.editing) {
|
||||
// No transition needed, just keep the scroll position
|
||||
this._insertOnTop(true);
|
||||
return;
|
||||
}
|
||||
|
||||
var domItems = this._itemsInDOM;
|
||||
var list = this.list;
|
||||
|
||||
list.classList.add('reordering');
|
||||
pushDown(this.scheduler, domItems, this.geometry)
|
||||
.then(this._insertOnTop.bind(this, false))
|
||||
.then(cleanInlineStyles.bind(null, domItems))
|
||||
.then(reveal.bind(null, this.list))
|
||||
.then(function() {
|
||||
list.classList.remove('reordering');
|
||||
});
|
||||
},
|
||||
|
||||
_insertOnTop: function(keepScrollPosition) {
|
||||
return schedule.mutation((function() {
|
||||
this._items.unshift(null);
|
||||
delete this._items[0]; // keeping it sparse
|
||||
|
||||
this.updateSections();
|
||||
|
||||
if (keepScrollPosition) {
|
||||
this.scrollInstantly(this.geometry.itemHeight);
|
||||
this.container.dispatchEvent(new CustomEvent('hidden-new-content'));
|
||||
} else {
|
||||
this.render(false, 0);
|
||||
}
|
||||
|
||||
this.updateListHeight();
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
handleEvent: function(evt) {
|
||||
switch (evt.type) {
|
||||
case 'resize':
|
||||
this.geometry.viewportHeight = this.container.offsetHeight;
|
||||
this.updateContainerGeometry();
|
||||
break;
|
||||
case startEvent:
|
||||
if (!evt.target.classList.contains('cursor')) {
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
this._reorderStart(evt);
|
||||
break;
|
||||
case endEvent:
|
||||
if (!evt.target.classList.contains('cursor') &&
|
||||
endEvent === 'touchend') {
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
this._reorderEnd(evt);
|
||||
break;
|
||||
case 'click':
|
||||
if (this.editing) {
|
||||
break;
|
||||
}
|
||||
|
||||
var li = evt.target;
|
||||
var index = this._items.indexOf(li);
|
||||
|
||||
this.list.dispatchEvent(new CustomEvent('item-selected', {detail: {
|
||||
index: index,
|
||||
clickEvt: evt
|
||||
}}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Internals
|
||||
========= */
|
||||
|
||||
/* ASCII Art viewport debugging
|
||||
---------------------------- */
|
||||
function debugViewport(items, forward, cStart, cEnd, start, end) {
|
||||
if (!debug.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var str = '[' + (forward ? 'v' : '^') + ']';
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (i == start) {
|
||||
str += '|';
|
||||
}
|
||||
if (i == cStart) {
|
||||
str += '[';
|
||||
}
|
||||
if (items[i]) {
|
||||
str += 'x';
|
||||
} else {
|
||||
str += '-';
|
||||
}
|
||||
if (i == cEnd) {
|
||||
str += ']';
|
||||
}
|
||||
if (i == end) {
|
||||
str += '|';
|
||||
}
|
||||
}
|
||||
|
||||
debug(str);
|
||||
}
|
||||
|
||||
function computeIndices(source, geometry) {
|
||||
var criticalStart = source.indexAtPosition(geometry.topPosition);
|
||||
var criticalEnd = source.indexAtPosition(geometry.topPosition +
|
||||
geometry.viewportHeight);
|
||||
|
||||
var canPrerender = geometry.maxItemCount -
|
||||
(criticalEnd - criticalStart) - 1;
|
||||
var before = geometry.switchWindow;
|
||||
var after = canPrerender - before;
|
||||
var lastIndex = source.fullLength() - 1;
|
||||
|
||||
var startIndex;
|
||||
var endIndex;
|
||||
|
||||
if (geometry.forward) {
|
||||
startIndex = Math.max(0, criticalStart - before);
|
||||
endIndex = Math.min(lastIndex,
|
||||
criticalEnd + after);
|
||||
} else {
|
||||
startIndex = Math.max(0, criticalStart - after);
|
||||
endIndex = Math.min(lastIndex,
|
||||
criticalEnd + before);
|
||||
}
|
||||
|
||||
return {
|
||||
cStart: criticalStart,
|
||||
cEnd: criticalEnd,
|
||||
start: startIndex,
|
||||
end: endIndex
|
||||
};
|
||||
}
|
||||
|
||||
function recycle(items, start, end, action) {
|
||||
var recyclableItems = [];
|
||||
for (var i in items) {
|
||||
if ((i < start) || (i > end)) {
|
||||
recyclableItems.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Put the items that are furthest away from the displayport edge
|
||||
// at the end of the array.
|
||||
recyclableItems.sort(function(a, b) {
|
||||
return Math.abs(a - action) - Math.abs(b - action);
|
||||
});
|
||||
|
||||
return recyclableItems;
|
||||
}
|
||||
|
||||
function tryToPopulate(item, index, source, first) {
|
||||
if (parseInt(item.dataset.index) !== index && !first) {
|
||||
// The item was probably reused
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: should be in a mutation block when !first
|
||||
var populateResult = source.populateItem(item, index);
|
||||
|
||||
if (populateResult instanceof Promise) {
|
||||
item.dataset.populated = false;
|
||||
populateResult.then(tryToPopulate.bind(null, item, index,
|
||||
source));
|
||||
return;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
item.dataset.populated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Revealing the populated item
|
||||
item.style.transition = 'opacity 0.2s linear';
|
||||
schedule.transition(function() {
|
||||
item.dataset.populated = true;
|
||||
}, item, 'transitionend').then(function() {
|
||||
item.style.transition = '';
|
||||
});
|
||||
}
|
||||
|
||||
function placeItem(item, index, section, geometry, source, reload) {
|
||||
if (parseInt(item.dataset.index) === index && !reload) {
|
||||
// The item was probably reused
|
||||
return;
|
||||
}
|
||||
|
||||
item.dataset.position = source.positionForIndex(index);
|
||||
item.dataset.index = index;
|
||||
item.dataset.section = section;
|
||||
|
||||
var tweakedBy = parseInt(item.dataset.tweakDelta);
|
||||
if (tweakedBy) {
|
||||
tweakTransform(item, tweakedBy);
|
||||
} else {
|
||||
resetTransform(item);
|
||||
}
|
||||
}
|
||||
|
||||
function resetTransform(item) {
|
||||
var position = parseInt(item.dataset.position);
|
||||
item.style.webkitTransform =
|
||||
item.style.transform = 'translate3d(0, ' + position + 'px, 0)';
|
||||
item.dataset.tweakDelta = '';
|
||||
}
|
||||
|
||||
function tweakTransform(item, delta) {
|
||||
var position = parseInt(item.dataset.position) + delta;
|
||||
item.style.webkitTransform =
|
||||
item.style.transform = 'translate3d(0, ' + position + 'px, 0)';
|
||||
item.dataset.tweakDelta = delta;
|
||||
}
|
||||
|
||||
function resetTransition(item) {
|
||||
item.style.transition = '';
|
||||
item.style.webkitTransition = '';
|
||||
}
|
||||
|
||||
function tweakAndTransition(item, tweak) {
|
||||
return schedule.feedback(function() {
|
||||
item.style.transition = 'transform 0.15s ease';
|
||||
item.style.webkitTransition = '-webkit-transform 0.15s ease';
|
||||
if (tweak === 0) {
|
||||
setTimeout(resetTransform.bind(null, item));
|
||||
return;
|
||||
}
|
||||
setTimeout(tweakTransform.bind(null, item, tweak));
|
||||
}, item, 'transitionend')
|
||||
.then(resetTransition.bind(null, item));
|
||||
}
|
||||
|
||||
function pushDown(domItems, geometry) {
|
||||
if (!domItems.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return schedule.transition(function() {
|
||||
for (var i = 0; i < domItems.length; i++) {
|
||||
var item = domItems[i];
|
||||
item.style.transition = 'transform 0.15s ease-in';
|
||||
item.style.webkitTransition = '-webkit-transform 0.15s ease-in';
|
||||
tweakTransform(item, geometry.itemHeight);
|
||||
}
|
||||
}, domItems[0], 'transitionend');
|
||||
}
|
||||
|
||||
function reveal(list) {
|
||||
var newEl = list.querySelector('li.new');
|
||||
|
||||
return schedule.transition(function() {
|
||||
newEl.style.transition = 'opacity 0.25s ease-out';
|
||||
newEl.style.webkitTransition = 'opacity 0.25s ease-out';
|
||||
setTimeout(function() {
|
||||
newEl.classList.remove('new');
|
||||
});
|
||||
}, newEl, 'transitionend').then(function() {
|
||||
newEl.style.transition = '';
|
||||
newEl.style.webkitTransition = '';
|
||||
});
|
||||
}
|
||||
|
||||
function cleanInlineStyles(domItems) {
|
||||
return schedule.mutation(function() {
|
||||
for (var i = 0; i < domItems.length; i++) {
|
||||
var item = domItems[i];
|
||||
item.style.transition = '';
|
||||
item.style.webkitTransition = '';
|
||||
resetTransform(item);
|
||||
}
|
||||
domItems[0] && domItems[0].scrollTop; // flushing
|
||||
});
|
||||
}
|
||||
|
||||
function toggleEditClass(list, domItems, editing) {
|
||||
if (!domItems.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return schedule.feedback(function() {
|
||||
for (var i = 0; i < domItems.length; i++) {
|
||||
var item = domItems[i];
|
||||
var overlay = item.querySelector('.overlay');
|
||||
overlay.dataset.anim = editing ? 'reveal' : 'hide';
|
||||
item.classList.toggle('edit', editing);
|
||||
}
|
||||
}, list, 'animationend');
|
||||
}
|
||||
|
||||
function setupForDragging(scheduler, item, on) {
|
||||
return schedule.mutation(function() {
|
||||
item.parentNode.classList.toggle('reordering', on);
|
||||
item.style.zIndex = on ? '1000' : '';
|
||||
item.style.boxShadow = on ? '0 0 3px 1px #bcbcbc' : '';
|
||||
});
|
||||
}
|
||||
|
||||
function toggleDraggingClass(scheduler, item, on) {
|
||||
return schedule.feedback(function() {
|
||||
var overlay = item.querySelector('.overlay');
|
||||
overlay.dataset.anim = on ? 'hide' : 'reveal';
|
||||
}, item, 'animationend');
|
||||
}
|
||||
|
||||
function computeChanges(context, geometry, domItems, delta) {
|
||||
if (!context.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
var draggedItem = context.item;
|
||||
var draggedOriginal = parseInt(draggedItem.dataset.position);
|
||||
var draggedTweaked = draggedOriginal + delta;
|
||||
|
||||
for (var i = 0; i < domItems.length; i++) {
|
||||
var item = domItems[i];
|
||||
if (item === draggedItem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: support re-ordering accross sections
|
||||
if (item.dataset.section !== draggedItem.dataset.section) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var itemOriginal = parseInt(item.dataset.position);
|
||||
var itemTweaked = itemOriginal + parseInt(item.dataset.tweakDelta);
|
||||
|
||||
if ((itemOriginal < draggedOriginal) && (draggedTweaked < itemOriginal)) {
|
||||
context.moveDown.add(item);
|
||||
} else {
|
||||
if (draggedTweaked > itemTweaked) {
|
||||
context.moveDown.delete(item);
|
||||
}
|
||||
}
|
||||
|
||||
if ((itemOriginal > draggedOriginal) && (draggedTweaked > itemOriginal)) {
|
||||
context.moveUp.add(item);
|
||||
} else {
|
||||
if (draggedTweaked < itemTweaked) {
|
||||
context.moveUp.delete(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyChanges(context, geometry, domItems) {
|
||||
if (!context.item) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var itemHeight = geometry.itemHeight;
|
||||
var draggedItem = context.item;
|
||||
var promises = [];
|
||||
|
||||
for (var i = 0; i < domItems.length; i++) {
|
||||
var item = domItems[i];
|
||||
if (item === draggedItem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reset
|
||||
if (item.dataset.tweakDelta &&
|
||||
!context.moveUp.has(item) && !context.moveDown.has(item)) {
|
||||
|
||||
promises.push(tweakAndTransition(item, 0));
|
||||
}
|
||||
|
||||
// Moving down
|
||||
if (context.moveDown.has(item)) {
|
||||
if (parseInt(item.dataset.tweakDelta) !== itemHeight) {
|
||||
promises.push(tweakAndTransition(item, itemHeight));
|
||||
}
|
||||
}
|
||||
|
||||
// Moving up
|
||||
if (context.moveUp.has(item)) {
|
||||
if (parseInt(item.dataset.tweakDelta) !== itemHeight * -1) {
|
||||
promises.push(tweakAndTransition(item, itemHeight * -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function moveInPlace(context, geometry) {
|
||||
var li = context.item;
|
||||
|
||||
// We're already in place
|
||||
if (!li.dataset.tweakDelta) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var position = parseInt(li.dataset.position);
|
||||
var taintedPosition = position + parseInt(li.dataset.tweakDelta);
|
||||
var itemHeight = geometry.itemHeight;
|
||||
var newPosition = position + context.moveUp.size * itemHeight -
|
||||
context.moveDown.size * itemHeight;
|
||||
|
||||
var duration = (Math.abs(taintedPosition - newPosition) / itemHeight) * 150;
|
||||
|
||||
return schedule.feedback(function() {
|
||||
li.style.transition = 'transform ' + duration + 'ms linear';
|
||||
li.style.webkitTransition = '-webkit-transform ' + duration + 'ms linear';
|
||||
setTimeout(tweakTransform.bind(null, li, (newPosition - position)));
|
||||
}, li, 'transitionend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
function schedulerShim() {
|
||||
var raf = window.requestAnimationFrame;
|
||||
|
||||
return {
|
||||
mutation: function(block) { return Promise.resolve(block()); },
|
||||
transition: function(block, el, event, timeout) {
|
||||
block();
|
||||
return after(el, event, timeout || 500);
|
||||
},
|
||||
|
||||
// Not sure if this should be different from .transition()
|
||||
feedback: function(block, el, event, timeout) {
|
||||
block();
|
||||
return after(el, event, timeout || 500);
|
||||
},
|
||||
|
||||
attachDirect: function(el, event, fn) {
|
||||
fn._raffed = function(e) { raf(function() { fn(e); } ); };
|
||||
on(el, event, fn._raffed);
|
||||
},
|
||||
|
||||
detachDirect: function(el, event, fn) {
|
||||
off(el, event, fn._raffed);
|
||||
}
|
||||
};
|
||||
|
||||
function after(target, event, timeout) {
|
||||
return new Promise(function(resolve) {
|
||||
var timer = timeout && setTimeout(cb, timeout);
|
||||
on(target, event, cb);
|
||||
function cb() {
|
||||
off(target, event, cb);
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Shorthand
|
||||
function on(el, name, fn) { el.addEventListener(name, fn); }
|
||||
function off(el, name, fn) { el.removeEventListener(name, fn); }
|
||||
|
||||
});})((typeof define)[0]=='f'&&define.amd?define:(function(n,w){'use strict';
|
||||
return(typeof module)[0]=='o'?function(c){c(require,exports,module);}:
|
||||
function(c){var m={exports:{}};c(function(n){w[n];},m.exports,m);
|
||||
w[n]=m.exports;};})('FastList',this));
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "gaia-component",
|
||||
"version": "0.3.8",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-component.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"README.md",
|
||||
"package.json",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,420 @@
|
|||
/* globals define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
var textContent = Object.getOwnPropertyDescriptor(Node.prototype,
|
||||
'textContent');
|
||||
var innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
|
||||
var removeAttribute = Element.prototype.removeAttribute;
|
||||
var setAttribute = Element.prototype.setAttribute;
|
||||
var noop = function() {};
|
||||
|
||||
/**
|
||||
* Register a new component.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} props
|
||||
* @return {constructor}
|
||||
* @public
|
||||
*/
|
||||
exports.register = function(name, props) {
|
||||
var baseProto = getBaseProto(props.extends);
|
||||
var template = props.template || baseProto.templateString;
|
||||
|
||||
// Components are extensible by default but can be declared
|
||||
// as non extensible as an optimization to avoid
|
||||
// storing the template strings
|
||||
var extensible = props.extensible = props.hasOwnProperty('extensible')?
|
||||
props.extensible : true;
|
||||
|
||||
// Clean up
|
||||
delete props.extends;
|
||||
|
||||
// Pull out CSS that needs to be in the light-dom
|
||||
if (template) {
|
||||
// Stores the string to be reprocessed when
|
||||
// a new component extends this one
|
||||
if (extensible && props.template) {
|
||||
props.templateString = props.template;
|
||||
}
|
||||
|
||||
var output = processCss(template, name);
|
||||
|
||||
props.template = document.createElement('template');
|
||||
props.template.innerHTML = output.template;
|
||||
props.lightCss = output.lightCss;
|
||||
|
||||
props.globalCss = props.globalCss || '';
|
||||
props.globalCss += output.globalCss;
|
||||
}
|
||||
|
||||
// Inject global CSS into the document,
|
||||
// and delete as no longer needed
|
||||
injectGlobalCss(props.globalCss);
|
||||
delete props.globalCss;
|
||||
|
||||
// Merge base getter/setter attributes with the user's,
|
||||
// then define the property descriptors on the prototype.
|
||||
var descriptors = mixin(props.attrs || {}, base.descriptors);
|
||||
|
||||
// Store the orginal descriptors somewhere
|
||||
// a little more private and delete the original
|
||||
props._attrs = props.attrs;
|
||||
delete props.attrs;
|
||||
|
||||
// Create the prototype, extended from base and
|
||||
// define the descriptors directly on the prototype
|
||||
var proto = createProto(baseProto, props);
|
||||
Object.defineProperties(proto, descriptors);
|
||||
|
||||
// Register the custom-element and return the constructor
|
||||
try {
|
||||
return document.registerElement(name, { prototype: proto });
|
||||
} catch (e) {
|
||||
if (e.name !== 'NotSupportedError') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var base = {
|
||||
properties: {
|
||||
GaiaComponent: true,
|
||||
attributeChanged: noop,
|
||||
attached: noop,
|
||||
detached: noop,
|
||||
created: noop,
|
||||
|
||||
createdCallback: function() {
|
||||
if (this.rtl) { addDirObserver(); }
|
||||
injectLightCss(this);
|
||||
this.created();
|
||||
},
|
||||
|
||||
/**
|
||||
* It is very common to want to keep object
|
||||
* properties in-sync with attributes,
|
||||
* for example:
|
||||
*
|
||||
* el.value = 'foo';
|
||||
* el.setAttribute('value', 'foo');
|
||||
*
|
||||
* So we support an object on the prototype
|
||||
* named 'attrs' to provide a consistent
|
||||
* way for component authors to define
|
||||
* these properties. When an attribute
|
||||
* changes we keep the attr[name]
|
||||
* up-to-date.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String||null} from
|
||||
* @param {String||null} to
|
||||
*/
|
||||
attributeChangedCallback: function(name, from, to) {
|
||||
var prop = toCamelCase(name);
|
||||
if (this._attrs && this._attrs[prop]) { this[prop] = to; }
|
||||
this.attributeChanged(name, from, to);
|
||||
},
|
||||
|
||||
attachedCallback: function() { this.attached(); },
|
||||
detachedCallback: function() { this.detached(); },
|
||||
|
||||
/**
|
||||
* A convenient method for setting up
|
||||
* a shadow-root using the defined template.
|
||||
*
|
||||
* @return {ShadowRoot}
|
||||
*/
|
||||
setupShadowRoot: function() {
|
||||
if (!this.template) { return; }
|
||||
var node = document.importNode(this.template.content, true);
|
||||
this.createShadowRoot().appendChild(node);
|
||||
return this.shadowRoot;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
setAttr: function(name, value) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
setAttribute.call(internal, name, value);
|
||||
setAttribute.call(this, name, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
removeAttr: function(name) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
removeAttribute.call(internal, name);
|
||||
removeAttribute.call(this, name);
|
||||
}
|
||||
},
|
||||
|
||||
descriptors: {
|
||||
textContent: {
|
||||
set: function(value) {
|
||||
textContent.set.call(this, value);
|
||||
if (this.lightStyle) { this.appendChild(this.lightStyle); }
|
||||
},
|
||||
|
||||
get: function() {
|
||||
return textContent.get();
|
||||
}
|
||||
},
|
||||
|
||||
innerHTML: {
|
||||
set: function(value) {
|
||||
innerHTML.set.call(this, value);
|
||||
if (this.lightStyle) { this.appendChild(this.lightStyle); }
|
||||
},
|
||||
|
||||
get: innerHTML.get
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The default base prototype to use
|
||||
* when `extends` is undefined.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var defaultPrototype = createProto(HTMLElement.prototype, base.properties);
|
||||
|
||||
/**
|
||||
* Returns a suitable prototype based
|
||||
* on the object passed.
|
||||
*
|
||||
* @private
|
||||
* @param {HTMLElementPrototype|undefined} proto
|
||||
* @return {HTMLElementPrototype}
|
||||
*/
|
||||
function getBaseProto(proto) {
|
||||
if (!proto) { return defaultPrototype; }
|
||||
proto = proto.prototype || proto;
|
||||
return !proto.GaiaComponent ?
|
||||
createProto(proto, base.properties) : proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the given proto and mixes
|
||||
* in the given properties.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} proto
|
||||
* @param {Object} props
|
||||
* @return {Object}
|
||||
*/
|
||||
function createProto(proto, props) {
|
||||
return mixin(Object.create(proto), props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects presence of shadow-dom
|
||||
* CSS selectors.
|
||||
*
|
||||
* @private
|
||||
* @return {Boolean}
|
||||
*/
|
||||
var hasShadowCSS = (function() {
|
||||
var div = document.createElement('div');
|
||||
try { div.querySelector(':host'); div.querySelector('::content'); return true; }
|
||||
catch (e) { return false; }
|
||||
})();
|
||||
|
||||
/**
|
||||
* Regexs used to extract shadow-css
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var regex = {
|
||||
shadowCss: /(?:\:host|\:\:content)[^{]*\{[^}]*\}/g,
|
||||
':host': /(?:\:host)/g,
|
||||
':host()': /\:host\((.+)\)(?: \:\:content)?/g,
|
||||
':host-context': /\:host-context\((.+)\)([^{,]+)?/g,
|
||||
'::content': /(?:\:\:content)/g
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the :host and ::content rules
|
||||
* from the shadow-dom CSS and rewrites
|
||||
* them to work from the <style scoped>
|
||||
* injected at the root of the component.
|
||||
*
|
||||
* @private
|
||||
* @return {String}
|
||||
*/
|
||||
function processCss(template, name) {
|
||||
var globalCss = '';
|
||||
var lightCss = '';
|
||||
|
||||
if (!hasShadowCSS) {
|
||||
template = template.replace(regex.shadowCss, function(match) {
|
||||
var hostContext = regex[':host-context'].exec(match);
|
||||
|
||||
if (hostContext) {
|
||||
globalCss += match
|
||||
.replace(regex['::content'], '')
|
||||
.replace(regex[':host-context'], '$1 ' + name + '$2')
|
||||
.replace(/ +/g, ' '); // excess whitespace
|
||||
} else {
|
||||
lightCss += match
|
||||
.replace(regex[':host()'], name + '$1')
|
||||
.replace(regex[':host'], name)
|
||||
.replace(regex['::content'], name);
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
template: template,
|
||||
lightCss: lightCss,
|
||||
globalCss: globalCss
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Some CSS rules, such as @keyframes
|
||||
* and @font-face don't work inside
|
||||
* scoped or shadow <style>. So we
|
||||
* have to put them into 'global'
|
||||
* <style> in the head of the
|
||||
* document.
|
||||
*
|
||||
* @private
|
||||
* @param {String} css
|
||||
*/
|
||||
function injectGlobalCss(css) {
|
||||
if (!css) {return;}
|
||||
var style = document.createElement('style');
|
||||
style.innerHTML = css.trim();
|
||||
headReady().then(function() {
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves a promise once document.head is ready.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function headReady() {
|
||||
return new Promise(function(resolve) {
|
||||
if (document.head) { return resolve(); }
|
||||
window.addEventListener('load', function fn() {
|
||||
window.removeEventListener('load', fn);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The Gecko platform doesn't yet have
|
||||
* `::content` or `:host`, selectors,
|
||||
* without these we are unable to style
|
||||
* user-content in the light-dom from
|
||||
* within our shadow-dom style-sheet.
|
||||
*
|
||||
* To workaround this, we clone the <style>
|
||||
* node into the root of the component,
|
||||
* so our selectors are able to target
|
||||
* light-dom content.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function injectLightCss(el) {
|
||||
if (hasShadowCSS) { return; }
|
||||
el.lightStyle = document.createElement('style');
|
||||
el.lightStyle.setAttribute('scoped', '');
|
||||
el.lightStyle.innerHTML = el.lightCss;
|
||||
el.appendChild(el.lightStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hyphen separated
|
||||
* string to camel-case.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* toCamelCase('foo-bar'); //=> 'fooBar'
|
||||
*
|
||||
* @private
|
||||
* @param {Sring} string
|
||||
* @return {String}
|
||||
*/
|
||||
function toCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function replacer(string, p1) {
|
||||
return p1.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer (singleton)
|
||||
*
|
||||
* @type {MutationObserver|undefined}
|
||||
*/
|
||||
var dirObserver;
|
||||
|
||||
/**
|
||||
* Observes the document `dir` (direction)
|
||||
* attribute and dispatches a global event
|
||||
* when it changes.
|
||||
*
|
||||
* Components can listen to this event and
|
||||
* make internal changes if need be.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addDirObserver() {
|
||||
if (dirObserver) { return; }
|
||||
|
||||
dirObserver = new MutationObserver(onChanged);
|
||||
dirObserver.observe(document.documentElement, {
|
||||
attributeFilter: ['dir'],
|
||||
attributes: true
|
||||
});
|
||||
|
||||
function onChanged(mutations) {
|
||||
document.dispatchEvent(new Event('dirchanged'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the values of all properties from
|
||||
* source object `target` to a target object `source`.
|
||||
* It will return the target object.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} target
|
||||
* @param {Object} source
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mixin(target, source) {
|
||||
for (var key in source) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-component',this));
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "gaia-dialog",
|
||||
"version": "0.2.3",
|
||||
"homepage": "https://github.com/gaia-components/gaia-dialog",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-dialog.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"examples",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"base": "gaia-components/base",
|
||||
"pressed": "gaia-components/pressed",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"gaia-theme": "gaia-components/gaia-theme",
|
||||
"gaia-button": "gaia-components/gaia-button"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-text-input": "gaia-components/gaia-text-input",
|
||||
"gaia-icons": "gaia-components/gaia-icons#^0.8.0",
|
||||
"gaia-component": "gaia-components/gaia-component#^0.3.7"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-action', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel')
|
||||
};
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<section>
|
||||
<content select="h1"></content>
|
||||
</section>
|
||||
<content select="button"></content>
|
||||
<button on-click="close" class="cancel">Cancel</button>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host[opened],
|
||||
:host.animating {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content section {
|
||||
padding: 33px 16px;
|
||||
}
|
||||
|
||||
::content button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0rem 25px;
|
||||
font: inherit;
|
||||
background: var(--color-beta);
|
||||
color: var(--color-epsilon);
|
||||
transition: all 200ms;
|
||||
transition-delay: 300ms;
|
||||
}
|
||||
|
||||
::content button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 49px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content button:last-child:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::content button:active {
|
||||
background-color: var(--highlight-color);
|
||||
color: #fff;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
::content button:active:after {
|
||||
background: var(--highlight-color);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-action',this));
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-alert', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog')
|
||||
};
|
||||
this.els.dialog.addEventListener('closed',
|
||||
GaiaDialogProto.hide.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return this.els.dialog.close()
|
||||
.then(GaiaDialogProto.hide.bind(this));
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<section>
|
||||
<p><content></content></p>
|
||||
</section>
|
||||
<div>
|
||||
<button class="submit primary" on-click="close">Ok</button>
|
||||
</div>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-alert',this));
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-confirm', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel')
|
||||
};
|
||||
|
||||
this.els.cancel.addEventListener('click', this.close.bind(this));
|
||||
this.els.submit.addEventListener('click', this.close.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<section>
|
||||
<p><content></content></p>
|
||||
</section>
|
||||
<fieldset>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="submit danger">Confirm</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host[opened],
|
||||
:host.animating {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-confirm',this));
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-menu', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog')
|
||||
};
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<div class="items"><content select="button"></content></div>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
::content > button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 51px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0rem 16px;
|
||||
font: inherit;
|
||||
font-style: italic;
|
||||
text-align: start;
|
||||
background: var(--color-beta);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
::content > button[data-icon]:before {
|
||||
width: 50px;
|
||||
font-size: 22px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/** Button Divider Line
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 49px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content > button:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-menu',this));
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
require('gaia-text-input');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-prompt', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
input: this.shadowRoot.querySelector('gaia-text-input'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel')
|
||||
};
|
||||
|
||||
this.els.dialog.addEventListener('opened', () => {
|
||||
this.setAttribute('opened', '');
|
||||
});
|
||||
|
||||
this.els.dialog.addEventListener('closed', () => {
|
||||
this.removeAttribute('opened');
|
||||
});
|
||||
|
||||
this.els.input.placeholder = this.firstChild.textContent;
|
||||
this.els.cancel.addEventListener('click', this.close.bind(this));
|
||||
this.els.submit.addEventListener('click', this.close.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<div><gaia-text-input></gaia-text-input></div>
|
||||
<fieldset>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="submit primary">Ok</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host[opened],
|
||||
:host.animating {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
gaia-text-input {
|
||||
margin: 16px !important;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-prompt',this));
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-select', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel'),
|
||||
list: this.shadowRoot.querySelector('ul')
|
||||
};
|
||||
|
||||
this.multiple = this.hasAttribute('multiple');
|
||||
this.els.list.addEventListener('click', this.onListClick.bind(this));
|
||||
this.els.submit.addEventListener('click', this.close.bind(this));
|
||||
this.els.cancel.addEventListener('click', this.close.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
onListClick: function(e) {
|
||||
var el = e.target.closest('li');
|
||||
var selected = el.getAttribute('aria-selected') === 'true';
|
||||
|
||||
if (this.multiple) { this.onChangeMultiple(el, selected); }
|
||||
else { this.onChange(el, selected); }
|
||||
},
|
||||
|
||||
onChange: function(el, selected) {
|
||||
this.clearSelected();
|
||||
if (!selected) { el.setAttribute('aria-selected', !selected); }
|
||||
this.fireChange();
|
||||
this.close();
|
||||
},
|
||||
|
||||
onChangeMultiple: function(el, selected) {
|
||||
el.setAttribute('aria-selected', !selected);
|
||||
this.fireChange();
|
||||
},
|
||||
|
||||
clearSelected: function() {
|
||||
[].forEach.call(this.selectedOptions, function(option) {
|
||||
option.removeAttribute('aria-selected');
|
||||
});
|
||||
},
|
||||
|
||||
fireChange: function() {
|
||||
var e = new CustomEvent('change', { detail: { value: this.valueString }});
|
||||
this.dispatchEvent(e);
|
||||
},
|
||||
|
||||
attrs: {
|
||||
multiple: {
|
||||
get: function() { return !!this._multiple; },
|
||||
set: function(value) {
|
||||
value = value === '' ? true : value;
|
||||
if (value === this._multiple) { return; }
|
||||
if (!value) {
|
||||
this._multiple = false;
|
||||
this.removeAttribute('multiple');
|
||||
} else {
|
||||
this._multiple = true;
|
||||
this.setAttribute('multiple', '');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
options: {
|
||||
get: function() { return this.querySelectorAll('li'); }
|
||||
},
|
||||
|
||||
selectedOptions: {
|
||||
get: function() {
|
||||
return this.querySelectorAll('li[aria-selected="true"]');
|
||||
}
|
||||
},
|
||||
|
||||
selected: {
|
||||
get: function() { return this.selectedOptions[0]; }
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() {
|
||||
var selected = this.selectedOptions[0];
|
||||
return selected && selected.getAttribute('value');
|
||||
}
|
||||
},
|
||||
|
||||
valueString: {
|
||||
get: function() {
|
||||
var selected = this.selected;
|
||||
return selected && selected.textContent;
|
||||
}
|
||||
},
|
||||
|
||||
length: {
|
||||
get: function() { return this.options.length; }
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<content select="h1"></content>
|
||||
<ul><content select="li"></content></ul>
|
||||
<fieldset>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="submit primary">Select</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Title (duplicate from gaia-dialog)
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content h1 {
|
||||
padding: 16px;
|
||||
font-size: 23px;
|
||||
line-height: 26px;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
/** List
|
||||
---------------------------------------------------------*/
|
||||
|
||||
ul {
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Options
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content li {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 16px;
|
||||
text-align: start;
|
||||
-moz-user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::content li[aria-selected='true'] {
|
||||
color: #00CAF2;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
::content li:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
bottom: 1px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content li:last-of-type:after {
|
||||
display: none
|
||||
}
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::host:not([multiple]) .submit {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
::host:not([multiple]) .cancel {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
::host:not([multiple]) .cancel:after {
|
||||
display: none% !important;
|
||||
}
|
||||
|
||||
/** Tick Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content li[aria-selected='true']:before {
|
||||
content: 'tick';
|
||||
position: absolute;
|
||||
top: 50%; right: 20px;
|
||||
display: block;
|
||||
margin-top: -12px;
|
||||
font-family: 'gaia-icons';
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-select',this));
|
||||
|
|
@ -0,0 +1,475 @@
|
|||
;(function(define){'use strict';define((require,exports,module) => {
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Simple logger (toggle 0)
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var debug = 0 ? console.log.bind(console) : () => {};
|
||||
|
||||
/**
|
||||
* Use the dom-scheduler if it's around,
|
||||
* else fallback to fake shim.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var schedule = (window.scheduler && typeof window.scheduler.mutation === "function" ? window.scheduler : null) || {
|
||||
mutation: block => Promise.resolve(block()),
|
||||
transition: (block, el, event, timeout) => {
|
||||
block();
|
||||
return after(el, event, timeout || 500);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-dialog', {
|
||||
created() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.dialog-inner'),
|
||||
background: this.shadowRoot.querySelector('.background'),
|
||||
window: this.shadowRoot.querySelector('.window')
|
||||
};
|
||||
|
||||
this.shadowRoot.addEventListener('click', e => this.onClick(e));
|
||||
},
|
||||
|
||||
onClick(e) {
|
||||
var el = e.target.closest('[on-click]');
|
||||
if (!el) { return; }
|
||||
debug('onClick');
|
||||
var method = el.getAttribute('on-click');
|
||||
if (typeof this[method] == 'function') { this[method](); }
|
||||
},
|
||||
|
||||
open(options) {
|
||||
if (this.isOpen) { return; }
|
||||
debug('open dialog');
|
||||
this.isOpen = true;
|
||||
|
||||
this.show()
|
||||
.then(() => this.animateBackgroundIn(options))
|
||||
.then(() => this.animateWindowIn())
|
||||
.then(() => this.dispatch('opened'));
|
||||
},
|
||||
|
||||
close(options) {
|
||||
if (!this.isOpen) { return; }
|
||||
debug('close dialog');
|
||||
this.isOpen = false;
|
||||
|
||||
this.animateWindowOut()
|
||||
.then(() => this.animateBackgroundOut())
|
||||
.then(() => this.hide())
|
||||
.then(() => this.dispatch('closed'));
|
||||
},
|
||||
|
||||
animateBackgroundIn(options) {
|
||||
if (options) { return this.animateBackgroundInFrom(options); }
|
||||
|
||||
var el = this.els.background;
|
||||
return schedule.transition(() => {
|
||||
debug('animate background in');
|
||||
el.classList.remove('animate-out');
|
||||
el.classList.add('animate-in');
|
||||
}, el, 'animationend');
|
||||
},
|
||||
|
||||
animateBackgroundOut() {
|
||||
var el = this.els.background;
|
||||
return schedule.transition(() => {
|
||||
debug('animate background out');
|
||||
el.classList.add('animate-out');
|
||||
el.classList.remove('animate-in');
|
||||
}, el, 'animationend')
|
||||
.then(() => el.style = '');
|
||||
},
|
||||
|
||||
animateBackgroundInFrom(pos) {
|
||||
var el = this.els.background;
|
||||
var scale = Math.sqrt(window.innerWidth * window.innerHeight) / 15;
|
||||
var duration = scale * 9;
|
||||
|
||||
return schedule.mutation(() => {
|
||||
el.classList.add('circular');
|
||||
el.classList.remove('animate-out');
|
||||
el.style.transform = `translate(${pos.clientX}px, ${pos.clientY}px)`;
|
||||
el.style.transitionDuration = duration + 'ms';
|
||||
el.offsetTop; // Hack, any ideas?
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
return schedule.transition(() => {
|
||||
debug('animate background in from', pos);
|
||||
el.style.transform += ` scale(${scale})`;
|
||||
el.style.opacity = 1;
|
||||
}, el, 'transitionend', duration * 1.5);
|
||||
});
|
||||
},
|
||||
|
||||
show() {
|
||||
return schedule.mutation(() => {
|
||||
debug('show');
|
||||
this.style.display = 'block';
|
||||
});
|
||||
},
|
||||
|
||||
hide() {
|
||||
return schedule.mutation(() => {
|
||||
debug('hide');
|
||||
this.style.display = 'none';
|
||||
});
|
||||
},
|
||||
|
||||
animateWindowIn() {
|
||||
var el = this.els.window;
|
||||
return schedule.transition(() => {
|
||||
debug('animate window in');
|
||||
el.classList.add('animate-in');
|
||||
el.classList.remove('animate-out');
|
||||
}, el, 'animationend');
|
||||
},
|
||||
|
||||
animateWindowOut() {
|
||||
var el = this.els.window;
|
||||
return schedule.transition(() => {
|
||||
debug('animate window out');
|
||||
el.classList.add('animate-out');
|
||||
el.classList.remove('animate-in');
|
||||
}, el, 'animationend');
|
||||
},
|
||||
|
||||
dispatch(name) {
|
||||
this.dispatchEvent(new CustomEvent(name));
|
||||
},
|
||||
|
||||
attrs: {
|
||||
opened: {
|
||||
get: function() { return !!this.isOpen; },
|
||||
set: function(value) {
|
||||
value = value === '' || value;
|
||||
if (!value) { this.close(); }
|
||||
else { this.open(); }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="dialog-inner">
|
||||
<div class="background" on-click="close"></div>
|
||||
<div class="window"><content></content></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
::content * {
|
||||
box-sizing: border-box;
|
||||
font-weight: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
::content p,
|
||||
::content h1,
|
||||
::content h2,
|
||||
::content h3,
|
||||
::content h4,
|
||||
::content button,
|
||||
::content fieldset {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0px; left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 200;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.dialog-inner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
background: rgba(199,199,199,0.85);
|
||||
}
|
||||
|
||||
/**
|
||||
* .circular
|
||||
*/
|
||||
|
||||
.background.circular {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: -20px;
|
||||
border-radius: 50%;
|
||||
will-change: transform, opacity;
|
||||
transition-property: opacity, transform;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
/**
|
||||
* .animate-in
|
||||
*/
|
||||
|
||||
.background.animate-in {
|
||||
animation-name: gaia-dialog-fade-in;
|
||||
animation-duration: 260ms;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
/**
|
||||
* .animate-out
|
||||
*/
|
||||
|
||||
.background.animate-out {
|
||||
animation-name: gaia-dialog-fade-out;
|
||||
animation-duration: 260ms;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** Window
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.window {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 350px;
|
||||
margin: auto;
|
||||
box-shadow: 0 1px 0 0px rgba(0,0,0,0.15);
|
||||
background: var(--color-iota);
|
||||
transition: opacity 300ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.window.animate-in {
|
||||
animation-name: gaia-dialog-entrance;
|
||||
animation-duration: 300ms;
|
||||
animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.275);
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.window.animate-out {
|
||||
animation-name: gaia-dialog-fade-out;
|
||||
animation-duration: 150ms;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** Title
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content h1 {
|
||||
padding: 16px;
|
||||
font-size: 23px;
|
||||
line-height: 26px;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
::content strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
::content small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
/** Section
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content section {
|
||||
padding: 33px 18px;
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
::content section > *:not(:last-child) {
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
/** Paragraphs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content p {
|
||||
text-align: -moz-start;
|
||||
}
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0rem 16px;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
background: var(--color-beta);
|
||||
color: var(--color-epsilon);
|
||||
transition: all 200ms;
|
||||
transition-delay: 300ms;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* .primary
|
||||
*/
|
||||
|
||||
::content button.primary {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* .danger
|
||||
*/
|
||||
|
||||
::content button.danger {
|
||||
color: var(--color-destructive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled buttons
|
||||
*/
|
||||
|
||||
::content button[disabled] {
|
||||
color: var(--color-zeta);
|
||||
}
|
||||
|
||||
/** Button Divider Line
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 49px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content button:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::content button:active {
|
||||
background-color: var(--highlight-color);
|
||||
color: #fff;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
::content button:active:after {
|
||||
background: var(--highlight-color);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
::content button[data-icon]:before {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/** Fieldset (button group)
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content fieldset {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::content fieldset button {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
::content fieldset button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
bottom: 6px;
|
||||
right: 0px;
|
||||
left: auto;
|
||||
width: 1px;
|
||||
height: calc(100% - 12px);
|
||||
background: #e7e7e7;
|
||||
transition: all 200ms;
|
||||
transition-delay: 200ms;
|
||||
}
|
||||
|
||||
</style>`,
|
||||
|
||||
globalCss: `
|
||||
@keyframes gaia-dialog-entrance {
|
||||
0% { transform: translateY(100px); }
|
||||
100% { transform: translateY(0px); }
|
||||
}
|
||||
|
||||
@keyframes gaia-dialog-fade-in {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
|
||||
@keyframes gaia-dialog-fade-out {
|
||||
0% { opacity: 1 }
|
||||
100% { opacity: 0 }
|
||||
}`
|
||||
});
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
function after(target, event, timeout) {
|
||||
return new Promise(resolve => {
|
||||
var timer = timeout && setTimeout(cb, timeout);
|
||||
target.addEventListener(event, cb);
|
||||
function cb() {
|
||||
target.removeEventListener(event, cb);
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog',this));
|
||||
124
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/gaia-dialog/index.html
vendored
Normal file
124
assets/webapps/music.gaiamobile.org/components/dom-scheduler/bower_components/gaia-dialog/index.html
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-dialog></title>
|
||||
<meta name="description" content="gaia-dialog demo" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/gaia-icons.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/pressed/pressed.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="bower_components/gaia-button/gaia-button.js"></script>
|
||||
<script src="bower_components/gaia-text-input/gaia-text-input.js"></script>
|
||||
<!-- <script src="bower_components/dom-scheduler/lib/dom-scheduler.js"></script> -->
|
||||
<script src="gaia-dialog.js"></script>
|
||||
<script src="gaia-dialog-alert.js"></script>
|
||||
<script src="gaia-dialog-confirm.js"></script>
|
||||
<script src="gaia-dialog-prompt.js"></script>
|
||||
<script src="gaia-dialog-action.js"></script>
|
||||
<script src="gaia-dialog-select.js"></script>
|
||||
<script src="gaia-dialog-menu.js"></script>
|
||||
<style>
|
||||
body {
|
||||
padding: 48px var(--base-m) 0 var(--base-m);
|
||||
background-color: var(--background);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="l-align-center">
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
|
||||
<div id="buttons">
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-alert">Alert</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-confirm">Confirm</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-prompt">Prompt</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-action">Action</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-select">Select</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-select[multiple]">Select Multiple</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-menu">Menu</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="#custom-dialog-1">Custom</gaia-button></div>
|
||||
</div>
|
||||
|
||||
<div id="dialogs">
|
||||
<gaia-dialog-alert>No SIM card is present</gaia-dialog-alert>
|
||||
<gaia-dialog-confirm>Are you sure you want to delete this contact?</gaia-dialog-confirm>
|
||||
<gaia-dialog-prompt>Device name</gaia-dialog-prompt>
|
||||
|
||||
<gaia-dialog-action>
|
||||
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eu mollis tortor.</h1>
|
||||
<button on-click="close">Action 1</button>
|
||||
<button on-click="close">Action 2</button>
|
||||
</gaia-dialog-action>
|
||||
|
||||
<gaia-dialog-select>
|
||||
<h1>Ring tone</h1>
|
||||
<li>Classic prism</li>
|
||||
<li>Wallphone</li>
|
||||
<li>Disco drive</li>
|
||||
<li>Touchmatic</li>
|
||||
<li>Classic courier</li>
|
||||
<li>Hacker</li>
|
||||
</gaia-dialog-select>
|
||||
|
||||
<gaia-dialog-select multiple>
|
||||
<h1>Ring tone</h1>
|
||||
<li>Classic prism</li>
|
||||
<li>Wallphone</li>
|
||||
<li>Disco drive</li>
|
||||
<li>Touchmatic</li>
|
||||
<li>Classic courier</li>
|
||||
<li>Hacker</li>
|
||||
</gaia-dialog-select>
|
||||
|
||||
<gaia-dialog-menu>
|
||||
<button on-click="close" data-icon="firefox">Open in new window</button>
|
||||
<button on-click="close" data-icon="firefox">Add to Home Screen</button>
|
||||
<button on-click="close" data-icon="firefox">Share link</button>
|
||||
<button on-click="close" data-icon="firefox">Settings</button>
|
||||
</gaia-dialog-menu>
|
||||
|
||||
<gaia-dialog id="custom-dialog-1">
|
||||
<section>
|
||||
<h1>Application Download</h1>
|
||||
<p>Do you want to download and install this application?</p>
|
||||
</section>
|
||||
<fieldset>
|
||||
<button on-click="close">Cancel</button>
|
||||
<button on-click="close">Action</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<gaia-dialog>
|
||||
<h1>Main Heading</h1>
|
||||
<h2>Sub Heading</h2>
|
||||
<hr></hr>
|
||||
<p>Lorem ipsum dolor sit amet, consecutor adipisicing elit, sed do eiusod tempor incidenti ut la et dolore magna...</p>
|
||||
<button on-click="close">Action</button>
|
||||
<button on-click="close">Cancel</button>
|
||||
</gaia-dialog>
|
||||
|
||||
<gaia-dialog>
|
||||
<h1>Confirmation</h1>
|
||||
<p>Lorem ipsum dolor sit amet, consecutor adipisicing elit, sed do eiusod tempor incidenti ut la et dolore magna...</p>
|
||||
<hr>
|
||||
<p>Lorem ipsum dolor sit amet, consecutor adipisicing elit, sed do eiusod tempor incidenti ut la et dolore magna...</p>
|
||||
<button on-click="close">Action</button>
|
||||
<button on-click="close">Action</button>
|
||||
<button on-click="close">Cancel</button>
|
||||
</gaia-dialog>
|
||||
</div>
|
||||
<script>
|
||||
var buttons = document.querySelectorAll('gaia-button');
|
||||
[].forEach.call(buttons, function(button) {
|
||||
button.addEventListener('click', function(e) {
|
||||
var dialog = document.querySelector(button.dataset.for);
|
||||
dialog.open(e);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "gaia-fonts",
|
||||
"version": "0.2.1",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "style.css",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Light.woff") format("woff");
|
||||
font-weight: 300; /* lighter */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-LightItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 300; /* lighter */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: normal; /* 400 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-RegularItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: normal; /* 400 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Medium.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: bold; /* 700 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-MediumItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: bold; /* 700 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Bold.woff") format("woff");
|
||||
font-weight: 800; /* bolder */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-BoldItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 800; /* bolder */
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
// Create a report about unused icons in a project.
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
var optimist = require('optimist');
|
||||
|
||||
var cli = optimist
|
||||
.usage('Create a report about unused icons in a project.' + '\n' +
|
||||
'Usage: $0 path/to/your/project/');
|
||||
var projectDir = cli.argv._[0];
|
||||
|
||||
// No folder passed? Show help message then.
|
||||
if (!projectDir) {
|
||||
cli.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check if the directory exist.
|
||||
var stats = fs.lstatSync(projectDir);
|
||||
if (!stats.isDirectory()) {
|
||||
console.log('\x1b[31mPlease provide a valid folder.\x1b[0m\n');
|
||||
cli.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all the icons in the font.
|
||||
* @returns {Array}
|
||||
*/
|
||||
function getIcons() {
|
||||
var icons = fs.readdirSync('./images/');
|
||||
|
||||
icons = icons.map(function(icon) {
|
||||
return path.basename(icon, '.svg');
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a grep pattern to extract used icons from files.
|
||||
* @param {string} grep
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function getUsedIcons(grep, callback) {
|
||||
exec(grep, function(err, stdout, stderr) {
|
||||
var usedIcons = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(function(icon) {
|
||||
// Take only the icon name.
|
||||
return icon.split(/["']/)[1];
|
||||
})
|
||||
.filter(function(icon) {
|
||||
// Remove non string items.
|
||||
return icon && icon.match(/^[a-z0-9-]+$/);
|
||||
});
|
||||
|
||||
callback(usedIcons);
|
||||
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of unused icons in a folder. The patterns of extraction are:
|
||||
* * data-icon="[^"]+"
|
||||
* * .dataset.icon ?= ?.+
|
||||
*/
|
||||
function getUnusedIcons() {
|
||||
var usedIcons = [];
|
||||
var length = 2;
|
||||
|
||||
var cb = function(icons) {
|
||||
usedIcons = usedIcons.concat(icons);
|
||||
length--;
|
||||
|
||||
if (length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var allIcons = getIcons();
|
||||
var unusedIcons = [];
|
||||
|
||||
allIcons.forEach(function(icon) {
|
||||
if (usedIcons.indexOf(icon) === -1) {
|
||||
unusedIcons.push(icon);
|
||||
}
|
||||
});
|
||||
|
||||
outputUnusedIcons(allIcons, unusedIcons);
|
||||
};
|
||||
|
||||
getUsedIcons('grep -rhoP \'data-icon="[^"]+"\' ' + projectDir, cb);
|
||||
getUsedIcons('grep -rhoP \'.dataset.icon ?= ?.+\' ' + projectDir, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of unused icons to the screen.
|
||||
* @param {Array.<string>} icons
|
||||
* @param {Array.<string>} unusedIcons
|
||||
*/
|
||||
function outputUnusedIcons(icons, unusedIcons) {
|
||||
console.log('\x1b[36mList of unused icons in %s (%d/%d):\x1b[0m',
|
||||
projectDir, unusedIcons.length, icons.length);
|
||||
|
||||
unusedIcons.forEach(function(icon) {
|
||||
console.log('* ' + icon);
|
||||
});
|
||||
}
|
||||
|
||||
getUnusedIcons();
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "gaia-icons",
|
||||
"version": "0.8.0",
|
||||
"homepage": "https://github.com/wilsonpage/gaia-icons",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": [
|
||||
"gaia-icons.js",
|
||||
"gaia-icons.css",
|
||||
"fonts/gaia-icons.ttf",
|
||||
"gaia-icons-embedded.css"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"templates",
|
||||
"images",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"create-svg-icon-set-file.py",
|
||||
"Gruntfile.js",
|
||||
"README.md",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,25 @@
|
|||
/* Generated by grunt-webfont */
|
||||
/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "gaia-icons";
|
||||
src: url("fonts/gaia-icons.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
[data-icon]:before,
|
||||
.ligature-icons {
|
||||
font-family: "gaia-icons";
|
||||
content: attr(data-icon);
|
||||
display: inline-block;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
text-decoration: inherit;
|
||||
text-transform: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-size: 30px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint laxbreak:true*/
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
var base = window.GAIA_ICONS_BASE_URL
|
||||
|| window.COMPONENTS_BASE_URL
|
||||
|| 'bower_components/';
|
||||
|
||||
if (!document.documentElement) {
|
||||
window.addEventListener('load', load);
|
||||
} else {
|
||||
load();
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (isLoaded()) { return; }
|
||||
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = base + 'gaia-icons/gaia-icons.css';
|
||||
document.head.appendChild(link);
|
||||
exports.loaded = true;
|
||||
}
|
||||
|
||||
function isLoaded() {
|
||||
return exports.loaded ||
|
||||
document.querySelector('link[href*=gaia-icons]') ||
|
||||
document.documentElement.classList.contains('gaia-icons-loaded');
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-icons',this));
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "gaia-text-input",
|
||||
"version": "0.1.2",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-text-input.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.8.0",
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
|
||||
"gaia-theme": "gaia-components/gaia-theme#~0.4.3",
|
||||
"base": "gaia-components/base",
|
||||
"gaia-icons": "gaia-components/gaia-icons#master"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-text-input-multiline', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
field: this.shadowRoot.querySelector('textarea')
|
||||
};
|
||||
|
||||
this.type = this.getAttribute('type');
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.placeholder = this.getAttribute('placeholder');
|
||||
this.required = this.getAttribute('required');
|
||||
this.value = this.getAttribute('value');
|
||||
},
|
||||
|
||||
clear: function(e) {
|
||||
this.value = '';
|
||||
},
|
||||
|
||||
attrs: {
|
||||
placeholder: {
|
||||
get: function() { return this.els.field.placeholder; },
|
||||
set: function(value) { this.els.field.placeholder = value || ''; }
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() { return this.els.field.value; },
|
||||
set: function(value) { this.els.field.value = value; }
|
||||
},
|
||||
|
||||
required: {
|
||||
get: function() { return this.els.field.required; },
|
||||
set: function(value) { this.els.field.required = value; }
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.els.field.disabled; },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
this.els.field.disabled = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `<div class="inner">
|
||||
<content select="label"></content>
|
||||
<div class="fields">
|
||||
<textarea></textarea>
|
||||
<div class="focus focus-1"></div>
|
||||
<div class="focus focus-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
textarea {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
margin-top: var(--base-m, 18px);
|
||||
margin-bottom: var(--base-m, 18px);
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Label
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin: 0 0 4px 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] label {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/** Fields
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.fields {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--gi-border-color:
|
||||
var(--input-border-color,
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
#e7e7e7)));
|
||||
|
||||
border-color:
|
||||
var(--gi-border-color);
|
||||
|
||||
border:
|
||||
var(--input-border,
|
||||
var(--border,
|
||||
1px solid var(--gi-border-color)));
|
||||
}
|
||||
|
||||
/** Textarea
|
||||
---------------------------------------------------------*/
|
||||
|
||||
textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 86px;
|
||||
padding: 10px 16px;
|
||||
font-size: inherit;
|
||||
border: none;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
resize: none;
|
||||
|
||||
/* dynamic */
|
||||
|
||||
color:
|
||||
var(--text-color, #000);
|
||||
|
||||
background:
|
||||
var(--text-input-background,
|
||||
var(--input-background,
|
||||
var(--background-minus,
|
||||
#fff)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [disabled]
|
||||
*/
|
||||
|
||||
textarea[disabled] {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/** Placeholder Text
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::-moz-placeholder {
|
||||
font-style: italic;
|
||||
|
||||
color:
|
||||
var(--input-placeholder-color, #909ca7);
|
||||
}
|
||||
|
||||
/** Focus Bar
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.focus {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
transition: all 200ms;
|
||||
transform: scaleX(0);
|
||||
visibility: hidden;
|
||||
background: var(--highlight-color, #000);
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
:focus ~ .focus {
|
||||
transform: scaleX(1);
|
||||
transition-delay: 200ms;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.focus-2 {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input-multiline',this));
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
|
||||
var DEFAULT_LENGTH = 4;
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-text-input-pin', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
fields: this.shadowRoot.querySelector('.fields'),
|
||||
input: this.shadowRoot.querySelector('input')
|
||||
};
|
||||
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.length = this.getAttribute('length') || DEFAULT_LENGTH;
|
||||
|
||||
this.addEventListener('keyup', () => this.updateCells());
|
||||
},
|
||||
|
||||
updateCells: function() {
|
||||
var l = this.els.input.value.length;
|
||||
this.els.cells.forEach((cell, i) => {
|
||||
cell.classList.toggle('populated', i < l);
|
||||
cell.classList.toggle('focused', i == l);
|
||||
});
|
||||
},
|
||||
|
||||
onBackspace: function(e) {
|
||||
var input = e.target;
|
||||
var empty = !input.value;
|
||||
var previous = input.previousElementSibling;
|
||||
|
||||
if (!empty && previous) {
|
||||
previous.clear();
|
||||
previous.focus();
|
||||
} else if (empty && previous) {
|
||||
previous.focus();
|
||||
}
|
||||
},
|
||||
|
||||
setupFields: function() {
|
||||
this.els.fields.innerHTML = '';
|
||||
this.els.cells = [];
|
||||
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
var el = document.createElement('div');
|
||||
el.className = 'cell';
|
||||
this.els.fields.appendChild(el);
|
||||
this.els.cells.push(el);
|
||||
}
|
||||
},
|
||||
|
||||
attributeChangedCallback: function(attr, from, to) {
|
||||
if (attrs[attr]) { this[attr] = to; }
|
||||
},
|
||||
|
||||
clear: function(e) {
|
||||
this.value = '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
|
||||
attrs: {
|
||||
length: {
|
||||
get: function() { return this._length; },
|
||||
set: function(value) {
|
||||
value = Number(value);
|
||||
this._length = value;
|
||||
this.els.input.setAttribute('maxlength', this.length);
|
||||
this.setupFields();
|
||||
}
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() { return this.els.input.value; },
|
||||
set: function(value) { this.els.input.value = value; }
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.els.input.disabled; },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
this.els.input.disabled = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content select="label"></content>
|
||||
<div class="container">
|
||||
<input />
|
||||
<div class="fields"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
height: 40px;
|
||||
margin-top: var(--base-m, 18px);
|
||||
margin-bottom: var(--base-m, 18px);
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Label
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin: 0 0 4px 16px;
|
||||
}
|
||||
|
||||
/** Container
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Input (hidden)
|
||||
---------------------------------------------------------*/
|
||||
|
||||
input {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/** Fields
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.fields {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] + .fields {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/** Cell
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.cell {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
margin-left: 1rem;
|
||||
flex: 1;
|
||||
|
||||
/* dynamic */
|
||||
|
||||
--gi-border-color:
|
||||
var(--input-border-color,
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
#e7e7e7)));
|
||||
|
||||
border-color:
|
||||
var(--gi-border-color);
|
||||
|
||||
border:
|
||||
var(--input-border,
|
||||
var(--border,
|
||||
1px solid var(--gi-border-color)));
|
||||
|
||||
background:
|
||||
var(--text-input-background,
|
||||
var(--input-background,
|
||||
var(--background-minus,
|
||||
#fff)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] + .fields .cell {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/** Dot
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.cell::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin: -7px;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
|
||||
/* dynamic */
|
||||
|
||||
background:
|
||||
var(--text-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* .populated
|
||||
*/
|
||||
|
||||
.cell.populated::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cell::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
visibility: hidden;
|
||||
background: var(--highlight-color, #000);
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
input:focus + .fields .cell::before {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input-pin',this));
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
require('gaia-icons'); // Load gaia-icons
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-text-input', {
|
||||
extends: HTMLInputElement,
|
||||
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
input: this.shadowRoot.querySelector('input'),
|
||||
clear: this.shadowRoot.querySelector('.clear')
|
||||
};
|
||||
|
||||
this.type = this.getAttribute('type');
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.clearable = this.hasAttribute('clearable');
|
||||
this.placeholder = this.getAttribute('placeholder');
|
||||
this.required = this.getAttribute('required');
|
||||
this.value = this.getAttribute('value');
|
||||
|
||||
// Don't take focus from the input field
|
||||
this.els.clear.addEventListener('mousedown', (e) => e.preventDefault());
|
||||
this.els.clear.addEventListener('click', e => this.clear(e));
|
||||
},
|
||||
|
||||
clear: function(e) {
|
||||
this.value = '';
|
||||
},
|
||||
|
||||
focus: function() {
|
||||
this.els.input.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
|
||||
attrs: {
|
||||
type: {
|
||||
get: function() { return this.els.input.getAttribute('type'); },
|
||||
set: function(value) {
|
||||
if (!value) { return; }
|
||||
this.els.inner.setAttribute('type', value);
|
||||
this.els.input.setAttribute('type', value);
|
||||
}
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
get: function() { return this.field.placeholder; },
|
||||
set: function(value) {
|
||||
if (!value && value !== '') { return; }
|
||||
this.els.input.placeholder = value;
|
||||
}
|
||||
},
|
||||
|
||||
clearable: {
|
||||
get: function() { return this._clearable; },
|
||||
set: function(value) {
|
||||
var clearable = !!(value === '' || value);
|
||||
if (clearable === this.clearable) { return; }
|
||||
|
||||
if (clearable) {
|
||||
this.els.inner.setAttribute('clearable', '');
|
||||
this.setAttribute('clearable', '');
|
||||
} else {
|
||||
this.els.inner.removeAttribute('clearable');
|
||||
this.removeAttribute('clearable');
|
||||
}
|
||||
|
||||
this._clearable = clearable;
|
||||
}
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() { return this.els.input.value; },
|
||||
set: function(value) { this.els.input.value = value; }
|
||||
},
|
||||
|
||||
required: {
|
||||
get: function() { return this.els.input.required; },
|
||||
set: function(value) { this.els.input.required = value; }
|
||||
},
|
||||
|
||||
maxlength: {
|
||||
get: function() { return this.els.input.getAttribute('maxlength'); },
|
||||
set: function(value) { this.els.input.setAttribute('maxlength', value); }
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.els.input.disabled; },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
this.els.input.disabled = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content select="label"></content>
|
||||
<div class="fields">
|
||||
<input type="text"/>
|
||||
<button class="clear" tabindex="-1"></button>
|
||||
<div class="focus"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
height: 40px;
|
||||
margin-top: var(--base-m, 18px);
|
||||
margin-bottom: var(--base-m, 18px);
|
||||
}
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
input,
|
||||
button {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Label
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin: 0 0 4px 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] label {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/** Fields
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.fields {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--gi-border-color:
|
||||
var(--input-border-color,
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
#e7e7e7)));
|
||||
|
||||
border-color:
|
||||
var(--gi-border-color);
|
||||
|
||||
border:
|
||||
var(--input-border,
|
||||
var(--border,
|
||||
1px solid var(--gi-border-color)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [type='search']
|
||||
*/
|
||||
|
||||
[type='search'] .fields {
|
||||
border-radius: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/** Input Field
|
||||
---------------------------------------------------------*/
|
||||
|
||||
input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
padding: 0 16px;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
resize: none;
|
||||
|
||||
/* Dynamic */
|
||||
|
||||
color:
|
||||
var(--text-color, #000);
|
||||
|
||||
background:
|
||||
var(--text-input-background,
|
||||
var(--input-background,
|
||||
var(--background-minus,
|
||||
#fff)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [disabled]
|
||||
*/
|
||||
|
||||
input[disabled] {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/** Placeholder Text
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::-moz-placeholder {
|
||||
font-style: italic;
|
||||
|
||||
color:
|
||||
var(--input-placeholder-color, #909ca7);
|
||||
}
|
||||
|
||||
/** Clear Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.clear {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 10px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
background:
|
||||
var(--input-clear-background, #999);
|
||||
}
|
||||
|
||||
/**
|
||||
* [clearable]
|
||||
*/
|
||||
|
||||
[clearable] .clear {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
input:focus ~ .clear {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** Clear Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.clear:before {
|
||||
font: normal 500 19px/16.5px 'gaia-icons';
|
||||
content: 'close';
|
||||
display: block;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/** Focus Bar
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.focus {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
transition: all 200ms;
|
||||
transform: scaleX(0);
|
||||
visibility: hidden;
|
||||
background: var(--highlight-color, #000);
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
:focus ~ .focus {
|
||||
transform: scaleX(1);
|
||||
transition-delay: 200ms;
|
||||
visibility: visible;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input',this));
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><gaia-text-input></title>
|
||||
<meta name="description" content="gaia-text-input demo">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/gaia-icons.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="gaia-text-input.js"></script>
|
||||
<script src="gaia-text-input-multiline.js"></script>
|
||||
<script src="gaia-text-input-pin.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding: 48px 24px 24px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
|
||||
<button id="btn">Focus</button>
|
||||
|
||||
|
||||
<gaia-text-input id="field" placeholder="Default"></gaia-text-input>
|
||||
<gaia-text-input placeholder="Search" type="search"></gaia-text-input>
|
||||
<gaia-text-input placeholder="Email" type="email" clearable></gaia-text-input>
|
||||
<gaia-text-input-multiline placeholder="Multiline"></gaia-text-input-multiline>
|
||||
<gaia-text-input-pin length="4"></gaia-text-input-pin>
|
||||
|
||||
<gaia-text-input placeholder="Disabled" disabled></gaia-text-input>
|
||||
<gaia-text-input placeholder="Search" type="search" disabled></gaia-text-input>
|
||||
<gaia-text-input placeholder="Email" type="email" clearable disabled></gaia-text-input>
|
||||
<gaia-text-input-multiline placeholder="Multiline" disabled></gaia-text-input-multiline>
|
||||
<gaia-text-input-pin length="4" disabled></gaia-text-input-pin>
|
||||
|
||||
<!-- <gaia-text-input-password></gaia-text-input-password> -->
|
||||
|
||||
|
||||
<script>
|
||||
btn.onclick = e => field.focus();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-theme",
|
||||
"version": "0.5.0",
|
||||
"homepage": "https://github.com/gaia-components/gaia-theme",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons",
|
||||
"gaia-header": "gaia-components/gaia-header",
|
||||
"gaia-button": "gaia-components/gaia-button",
|
||||
"gaia-switch": "gaia-components/gaia-switch",
|
||||
"gaia-checkbox": "gaia-components/gaia-checkbox"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
Gaia theme variables
|
||||
*/
|
||||
|
||||
|
||||
:root {
|
||||
|
||||
/** Grey Colors
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--color-alpha: #333333;
|
||||
--color-beta: #ffffff;
|
||||
--color-gamma: #4d4d4d;
|
||||
--color-delta: #5f5f5f;
|
||||
--color-epsilon: #858585;
|
||||
--color-zeta: #a6a6a6;
|
||||
--color-eta: #c7c7c7;
|
||||
--color-theta: #e7e7e7;
|
||||
--color-iota: #f4f4f4;
|
||||
|
||||
/** Brand Colors
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--color-darkblue: #00539f;
|
||||
--color-blue: #00caf2;
|
||||
--color-turquoise: #27c8c2;
|
||||
--color-darkorange: #e66000;
|
||||
--color-orange: #ff9500;
|
||||
--color-yellow: #ffcb00;
|
||||
--color-violet: #c40c84;
|
||||
|
||||
--color-warning: #fbbd3c;
|
||||
--color-destructive: #e2443a;
|
||||
--color-preffered: #00ba91;
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-beta);
|
||||
--background-plus: var(--color-theta);
|
||||
--background-minus: var(--color-zeta);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-theta);
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-gamma);
|
||||
--text-color-minus: var(--color-eta);
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--color-iota);
|
||||
|
||||
/** Links
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--link-color: var(--highlight-color);
|
||||
|
||||
/** Inputs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--input-background: var(--color-beta);
|
||||
--input-color: var(--color-alpha);
|
||||
--input-clear-background: #909ca7;
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-box-shadow:
|
||||
inset 0 -1px 0 #d8d8d8,
|
||||
inset 0 1px 0 #eeeeee;
|
||||
--button-box-shadow-active: var(--button-box-shadow);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-disabled-button-color: rgba(255,255,255,0.3);
|
||||
|
||||
/** Transitions
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.theme-productivity {
|
||||
|
||||
/** Brand Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-orange);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--highlight-color);
|
||||
--header-color: var(--color-beta);
|
||||
}
|
||||
|
||||
.theme-communications {
|
||||
|
||||
/** Brand Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-turquoise);
|
||||
|
||||
/** Links
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--link-color: #177874;
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--highlight-color);
|
||||
--header-color: var(--color-beta);
|
||||
--header-icon-color: var(--color-beta);
|
||||
--header-button-color: var(--color-beta);
|
||||
}
|
||||
|
||||
.theme-settings {
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-iota);
|
||||
--background-plus: var(--color-beta);
|
||||
--background-minus: var(--color-epsilon);
|
||||
--background-minus-minus: var(--color-zeta);
|
||||
|
||||
/** Highlight
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-blue);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-theta);
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-gamma);
|
||||
|
||||
/** Titles
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--title-color: var(--background-minus);
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--background-plus);
|
||||
|
||||
/** Switch
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--switch-background: var(--background-minus-minus);
|
||||
|
||||
/** Checkbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--checkbox-border-color: var(--background-minus-minus);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-color: var(--title-color);
|
||||
--header-background: var(--background);
|
||||
--header-button-color: var(--highlight-color);
|
||||
--header-disabled-button-color: var(--color-theta);
|
||||
--header-action-button-color: var(--title-color);
|
||||
}
|
||||
|
||||
.theme-media {
|
||||
|
||||
/** Highlight Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-blue);
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-alpha);
|
||||
--background-plus: var(--color-gamma);
|
||||
--background-minus: #2B2B2B;
|
||||
--background-minus-minus: #1a1a1a;
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-beta);
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--background-plus);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--background);
|
||||
--header-icon-color: var(--text-color);
|
||||
--header-button-color: var(--highlight-color);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-gamma);
|
||||
|
||||
/** Inputs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--input-background: var(--background-plus);
|
||||
|
||||
/** Text Input
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-input-background: var(--background-minus);
|
||||
|
||||
/** Switch
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--switch-head-border-color: var(--background-minus-minus);
|
||||
--switch-background: var(--background-minus-minus);
|
||||
|
||||
/** Checkbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--checkbox-border-color: var(--background-minus-minus);
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-box-shadow: none;
|
||||
--button-box-shadow-active: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
(function(define){'use strict';define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
|
||||
/**
|
||||
* Extend from the `HTMLElement` prototype
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
this.createShadowRoot().innerHTML = template;
|
||||
|
||||
this.els = {
|
||||
themes: this.shadowRoot.querySelector('.themes'),
|
||||
rtl: this.shadowRoot.querySelector('.toggle-rtl')
|
||||
};
|
||||
|
||||
this.els.rtl.addEventListener('click', this.onRtlClick.bind(this));
|
||||
this.els.themes.addEventListener('click', this.onThemeClick.bind(this));
|
||||
this.styleHack();
|
||||
this.set(localStorage.theme || 'settings');
|
||||
};
|
||||
|
||||
proto.styleHack = function() {
|
||||
var style = this.shadowRoot.querySelector('style');
|
||||
style.setAttribute('scoped', '');
|
||||
this.appendChild(style.cloneNode(true));
|
||||
};
|
||||
|
||||
proto.onThemeClick = function(e) {
|
||||
var theme = e.target.value;
|
||||
if (theme) { this.set(theme); }
|
||||
};
|
||||
|
||||
proto.onRtlClick = function() {
|
||||
document.dir = this.els.rtl.checked ? 'rtl' : 'ltr';
|
||||
};
|
||||
|
||||
proto.set = function(theme) {
|
||||
var radio = this.shadowRoot.querySelector('[value="' + theme + '"]');
|
||||
document.body.classList.remove('theme-' + this.theme);
|
||||
document.body.classList.add('theme-' + theme);
|
||||
radio.checked = true;
|
||||
this.theme = theme;
|
||||
localStorage.theme = theme;
|
||||
};
|
||||
|
||||
var template = `
|
||||
<style>
|
||||
|
||||
* { margin: 0; padding: 0; }
|
||||
|
||||
gaia-theme-selector {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
z-index: 101;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
background: rgba(255,255,255,0.8);
|
||||
color: #000;
|
||||
font-size: 9px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
form label {
|
||||
-moz-margin-start: 9px;
|
||||
}
|
||||
|
||||
form input {
|
||||
-moz-margin-end: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.rtl {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<form>
|
||||
<label class="rtl"><input type="checkbox" class="toggle-rtl" />RTL</label>
|
||||
<span class="themes">
|
||||
<label><input type="radio" name="theme" value="productivity"/>Prod</label>
|
||||
<label><input type="radio" name="theme" value="communications"/>Comms</label>
|
||||
<label><input type="radio" name="theme" value="media"/>Media</label>
|
||||
<label><input type="radio" name="theme" value="settings"/>Settings</label>
|
||||
</span>
|
||||
</form>`;
|
||||
|
||||
document.registerElement('gaia-theme-selector', { prototype: proto });
|
||||
|
||||
});})((function(n,w){'use strict';return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:
|
||||
function(c){var m={exports:{}},r=function(n){return w[n];};
|
||||
w[n]=c(r,m.exports,m)||m.exports;};})('gaia-theme-selector',this));
|
||||
Loading…
Reference in a new issue