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:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

1
gaia/shared/elements/config.js Executable file
View file

@ -0,0 +1 @@
window.COMPONENTS_BASE_URL = '/shared/elements/';

View file

@ -0,0 +1,14 @@
<element name="confirmation-message" extends="form">
<template>
<section>
<h1>Confirmation title</h1>
<p>Confirmation message</p>
</section>
<menu>
<button>Action 1</button>
<button>Action 2</button>
</menu>
</template>
</element>

View file

@ -0,0 +1,12 @@
<element name="contact-in-overlay" extends="button">
<template>
<div class="js-name ci__name ellipsis" dir="auto"></div>
<div class="ci__details">
<span class="js-tel-type ci__tel-type ellipsis" dir="auto"></span>
<span class="js-separator"></span>
<span class="js-tel ellipsis" dir="ltr"></span>
</div>
</template>
</element>

View file

@ -0,0 +1,10 @@
<element name="contact-list-overlay" extends="form">
<template>
<header></header>
<menu id="contact-list">
<button id="contact-list-overlay-cancel" data-l10n-id="cancel">Cancel</button>
</menu>
</template>
</element>

View file

@ -0,0 +1,28 @@
{
"name": "font-fit",
"main": "font-fit.js",
"version": "0.3.1",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"README.md",
"index.html",
"package.json"
],
"homepage": "https://github.com/gaia-components/font-fit",
"_release": "0.3.1",
"_resolution": {
"type": "version",
"tag": "v0.3.1",
"commit": "07a497519b335a3d86a66268f990d8844b83d517"
},
"_source": "git://github.com/gaia-components/font-fit.git",
"_target": "~0.3.0",
"_originalSource": "gaia-components/font-fit"
}

View file

@ -0,0 +1,18 @@
{
"name": "font-fit",
"main": "font-fit.js",
"version": "0.3.1",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"README.md",
"index.html",
"package.json"
]
}

View file

@ -0,0 +1,132 @@
;(function(define){define(function(require,exports,module){
'use strict';
/**
* Simple logger.
*
* @return {Function}
*/
var debug = 0 ? console.log.bind(console) : function(){};
/**
* Global canvas cache.
*
* @type {Object}
*/
var cache = {};
/**
* Default min/max font-size.
*
* @type {Number}
*/
var MIN = 16;
var MAX = 24;
/**
* The number of pixels to subtract from
* the given `config.space` to ensure
* HTML text doesn't overflow container.
*
* Ideally we would use 1px, but in some
* cases italicised text in canvas is ~2px
* longer than the same text in HTML.
*
* http://bugzil.la/1126391
*
* @type {Number}
*/
var BUFFER = 3;
/**
* Get the font-size that closest fits
* the given space with the given font.
*
* Config:
*
* - {String} `text` The text string
* - {String} `font` Font shorthand string
* - {Number} `space` Width (px) to fit the text into
* - {Number} `min` Min font-size (px) (optional)
* - {Number} `max` Max font-size (px) (optional)
*
* @param {Object} config
* @return {Object} {fontSize,overflowing,textWidth}
*/
module.exports = function(config) {
debug('font fit', config);
var space = config.space - BUFFER;
var min = config.min || MIN;
var max = config.max || MAX;
var text = trim(config.text);
var fontSize = max;
var textWidth;
var font;
do {
font = config.font.replace(/\d+px/, fontSize + 'px');
textWidth = getTextWidth(text, font);
} while (textWidth > space && fontSize !== min && fontSize--);
return {
textWidth: textWidth,
fontSize: fontSize,
overflowing: textWidth > space
};
};
/**
* Get the width of the given text
* with the given font style.
*
* @param {String} text
* @param {String} font (CSS shorthand)
* @return {Number} (px)
*/
function getTextWidth(text, font) {
var ctx = getCanvasContext(font);
var width = ctx.measureText(text).width;
debug('got text width', width);
return width;
}
/**
* Get a canvas context configured
* to the given font style.
*
* @param {String} font
* @return {CanvasRenderingContext2D}
*/
function getCanvasContext(font) {
debug('get canvas context', font);
var cached = cache[font];
if (cached) { return cached; }
var canvas = document.createElement('canvas');
canvas.setAttribute('moz-opaque', 'true');
canvas.setAttribute('width', '1px');
canvas.setAttribute('height', '1px');
debug('created canvas', canvas);
var ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.font = font;
return cache[font] = ctx;
}
/**
* Trim leading, trailing
* and excess whitespace.
*
* @param {String} text
* @return {String}
*/
function trim(text) {
return text.replace(/\s+/g, ' ').trim();
}
});})(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;};})('font-fit',this));

View file

@ -0,0 +1,41 @@
{
"name": "gaia-button",
"version": "0.1.0",
"main": "gaia-button.js",
"homepage": "https://github.com/gaia-components/gaia-button",
"authors": [
"cyee@mozilla.com"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests",
"index.html",
"package.json",
"README.md"
],
"devDependencies": {
"base": "gaia-components/base",
"gaia-fonts": "gaia-components/gaia-fonts",
"gaia-icons": "gaia-components/gaia-icons",
"gaia-theme": "gaia-components/gaia-theme"
},
"dependencies": {
"gaia-component": "gaia-components/gaia-component#~0.4.0"
},
"resolutions": {
"gaia-component": "~0.4.0"
},
"_release": "0.1.0",
"_resolution": {
"type": "version",
"tag": "v0.1.0",
"commit": "f6ab06010343da9f69cad963fc817d1e8e663c1e"
},
"_source": "git://github.com/gaia-components/gaia-button.git",
"_target": "*",
"_originalSource": "gaia-components/gaia-button"
}

View file

@ -0,0 +1,32 @@
{
"name": "gaia-button",
"version": "0.0.5",
"main": "gaia-button.js",
"homepage": "https://github.com/gaia-components/gaia-button",
"authors": [
"cyee@mozilla.com"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests",
"index.html",
"package.json",
"README.md"
],
"devDependencies": {
"base": "gaia-components/base",
"gaia-fonts": "gaia-components/gaia-fonts",
"gaia-icons": "gaia-components/gaia-icons",
"gaia-theme": "gaia-components/gaia-theme"
},
"dependencies": {
"gaia-component": "gaia-components/gaia-component#~0.4.0"
},
"resolutions": {
"gaia-component": "~0.4.0"
}
}

View file

@ -0,0 +1,234 @@
/* globals define */
(function(define){'use strict';define(function(require,exports,module){
/**
* Dependencies
*/
var component = require('gaia-component');
/**
* Simple logger
* @type {Function}
*/
var debug = 0 ? console.log.bind(console) : function() {};
/**
* Exports
*/
module.exports = component.register('gaia-button', {
extends: HTMLButtonElement.prototype,
created: function() {
this.setupShadowRoot();
// Configure
this.disabled = this.getAttribute('disabled');
// process everything that doesn't affect user interaction
// after the component is created
setTimeout(() => this.makeAccessible());
},
/**
* Accessibility enhancements.
* Read gaia-button as button.
* make it tabable
* read its disabled state
*/
makeAccessible: function() {
this.setAttribute('role', 'button');
// Make tabable
this.tabIndex = 0;
if (this.disabled) {
this.setAttribute('aria-disabled', true);
}
},
attrs: {
circular: {
get: function() { return this.getAttribute('circular'); },
set: function(value) {
value = !!(value === '' || value);
if (value) {
this.setAttribute('circular', '');
} else {
this.removeAttribute('circular');
}
}
},
disabled: {
get: function() { return this._disabled; },
set: function(value) {
value = !!(value || value === '');
if (this._disabled === value) { return; }
debug('set disabled', value);
this._disabled = value;
if (value) {
this.setAttr('disabled', '');
this.setAttribute('aria-disabled', true);
} else {
this.removeAttr('disabled');
this.removeAttribute('aria-disabled');
}
}
}
},
template: `
<div class="inner">
<div class="background"></div>
<div class="content"><content></content></div>
</div>
<style>
:host {
display: block;
box-sizing: border-box;
overflow: hidden;
height: 50px;
min-width: 50%;
border-radius: 50px;
margin: var(--base-m, 18px) 0;
outline: 0;
font-style: italic;
font-size: 17px;
cursor: pointer;
-moz-user-select: none;
line-height: 1;
background:
var(--button-background,
var(--input-background,
var(--background-plus,
#fff)));
color:
var(--button-color,
var(--text-color,
inherit));
box-shadow:
var(--button-box-shadow,
var(--box-shadow,
none));
transition: color 0ms 300ms;
}
@media(min-width:500px) {
:host { min-width: 140px; }
}
/**
* :active
*/
:host(:active) {
color: var(--button-color-active, #fff);
box-shadow: var(--button-box-shadow-active, none);
transition: none;
}
/**
* [circular]
*/
:host([circular]) {
width: 50px;
min-width: 0;
max-width: 50px;
border-radius: 50%;
}
:host([disabled]) {
pointer-events: none;
opacity: 0.5;
}
/** Inner
---------------------------------------------------------*/
.inner {
position: relative;
height: 100%;
}
/** Background
---------------------------------------------------------*/
.background {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 500ms 200ms;
background:
var(--button-background-active,
var(--highlight-color,
#333));
}
:active .background {
transition: none;
opacity: 1;
}
/** Content
---------------------------------------------------------*/
/**
* 1. In some cases events seems to be getting
* swallowed by text-nodes. Ignoring pointer-
* events means we can listen on parent nodes
* instead.
*/
.content {
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 2;
height: 100%;
padding: 0 18px;
pointer-events: none; /* 1 */
}
[circular] .content {
padding: 0;
}
::content i:before {
font-size: 22px;
}
::content i {
margin-left: -2px;
margin-right: -2px;
}
::content i + span,
::content span + i {
-moz-margin-start: 8px;
}
</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-button',this));

View file

@ -0,0 +1,28 @@
{
"name": "gaia-component",
"version": "0.4.0",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "gaia-component.js",
"license": "MIT",
"ignore": [
"**/.*",
"README.md",
"package.json",
"node_modules",
"bower_components",
"test",
"tests"
],
"homepage": "https://github.com/gaia-components/gaia-component",
"_release": "0.4.0",
"_resolution": {
"type": "version",
"tag": "v0.3.5",
"commit": "e29dfbd8e07a96cbe521df8067120b78c306b584"
},
"_source": "git://github.com/gaia-components/gaia-component.git",
"_target": "~0.4.0",
"_originalSource": "gaia-components/gaia-component"
}

View file

@ -0,0 +1,18 @@
{
"name": "gaia-component",
"version": "0.4.0",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "gaia-component.js",
"license": "MIT",
"ignore": [
"**/.*",
"README.md",
"package.json",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View file

@ -0,0 +1,460 @@
/* 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.dirObserver) { 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() {
if (this.dirObserver) {
this.setInnerDirAttributes = setInnerDirAttributes.bind(null, this);
document.addEventListener('dirchanged', this.setInnerDirAttributes);
}
this.attached();
},
detachedCallback: function() {
if (this.dirObserver) {
document.removeEventListener('dirchanged', this.setInnerDirAttributes);
}
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);
if (this.dirObserver) { setInnerDirAttributes(this); }
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; }
var stylesheet = el.querySelector('style');
if (!stylesheet) {
stylesheet = document.createElement('style');
stylesheet.setAttribute('scoped', '');
stylesheet.appendChild(document.createTextNode(el.lightCss));
el.appendChild(stylesheet);
}
el.lightStyle = stylesheet;
}
/**
* Convert hyphen separated
* string to camel-case.
*
* Example:
*
* toCamelCase('foo-bar'); //=> 'fooBar'
*
* @private
* @param {String} string
* @return {String}
*/
function toCamelCase(string) {
return string.replace(/-(.)/g, function replacer(string, p1) {
return p1.toUpperCase();
});
}
/**
* Observer (singleton)
*
* @type {MutationObserver|undefined}
*/
var dirObserver;
/**
* Workaround for bug 1100912: applies a `dir` attribute to all shadowRoot
* children so that :-moz-dir() selectors work on shadow DOM elements.
*
* In order to keep decent performances, the `dir` is the component dir if
* defined, or the document dir otherwise. This won't work if the component's
* direction is defined by CSS or inherited from a parent container.
*
* This method should be removed when bug 1100912 is fixed.
*
* @private
* @param {WebComponent}
*/
function setInnerDirAttributes(component) {
var dir = component.dir || document.dir;
Array.from(component.shadowRoot.children).forEach(element => {
if (element.nodeName !== 'STYLE') {
element.dir = dir;
}
});
}
/**
* Observes the document `dir` (direction) attribute and when it changes:
* - dispatches a global `dirchanged` event;
* - forces the `dir` attribute of all shadowRoot children.
*
* Components can listen to this event and make internal changes if needed.
*
* @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));

View file

@ -0,0 +1,41 @@
{
"name": "gaia-dialog",
"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",
"test",
"tests",
"index.html",
"package.json",
"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#^1.0.0",
"gaia-component": "gaia-components/gaia-component#^0.3.9"
},
"version": "0.2.4",
"_release": "0.2.4",
"_resolution": {
"type": "version",
"tag": "v0.2.4",
"commit": "ddaea4f4ca5e5fe0fbb71816fb04d30052cfc10e"
},
"_source": "git://github.com/gaia-components/gaia-dialog.git",
"_target": "*",
"_originalSource": "gaia-components/gaia-dialog"
}

View file

@ -0,0 +1,31 @@
{
"name": "gaia-dialog",
"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",
"test",
"tests",
"index.html",
"package.json",
"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#^1.0.0",
"gaia-component": "gaia-components/gaia-component#^0.3.9"
}
}

View file

@ -0,0 +1,116 @@
/* 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')
};
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() {
// First close (hide) inner dialog and then the container.
return this.els.dialog.close()
.then(GaiaDialogProto.hide.bind(this));
},
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 {
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
display: none;
}
gaia-dialog section {
max-width: 320px;
}
/** 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));

View file

@ -0,0 +1,67 @@
/* 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;
left: 0;
top: 0;
z-index: 999;
width: 100%;
height: 100%;
}
gaia-dialog section {
max-width: 320px;
}
</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));

View file

@ -0,0 +1,72 @@
/* 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() {
// First close (hide) inner dialog and then the container.
return this.els.dialog.close()
.then(GaiaDialogProto.hide.bind(this));
},
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: block;
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
display: none;
}
gaia-dialog section {
max-width: 320px;
}
</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));

View file

@ -0,0 +1,105 @@
/* 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'),
items: this.shadowRoot.querySelector('.items')
};
this.els.dialog.addEventListener('closed',
GaiaDialogProto.hide.bind(this));
setTimeout(() => this.makeAccessible());
},
makeAccessible() {
this.els.items.setAttribute('role', 'menu');
[].forEach.call(this.querySelectorAll('button'),
menuitem => menuitem.setAttribute('role', 'menuitem'));
},
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>
<div class="items"><content select="button"></content></div>
</gaia-dialog>
<style>
:host {
display: none;
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
}
::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));

View file

@ -0,0 +1,80 @@
/* 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 this.els.dialog.close()
.then(GaiaDialogProto.hide.bind(this));
},
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 {
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
display: none;
}
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));

View file

@ -0,0 +1,248 @@
/* 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));
setTimeout(() => this.makeAccessible());
},
makeAccessible() {
this.els.list.setAttribute('role', 'listbox');
if (this.multiple) {
this.els.list.setAttribute('aria-multiselectable', true);
}
[].forEach.call(this.options, option => {
option.setAttribute('role', 'option');
option.setAttribute('tabindex', '0');
});
},
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));
},
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');
this.els.list.removeAttribute('aria-multiselectable');
} else {
this._multiple = true;
this.setAttribute('multiple', '');
this.els.list.setAttribute('aria-multiselectable', true);
}
}
},
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%;
z-index: 999;
}
/** 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;
outline: 0;
}
::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));

View file

@ -0,0 +1,495 @@
/* global define */
;(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));
setTimeout(() => this.makeAccessible());
},
makeAccessible() {
this.setAttribute('role', 'dialog');
},
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;
return 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;
return 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;
z-index: 200;
width: 100%;
height: 100%;
overflow: hidden;
font-size: 17px;
font-style: italic;
text-align: center;
color: var(--text-color);
}
/** Inner
---------------------------------------------------------*/
.dialog-inner {
display: flex;
width: 100%;
height: 100%;
padding: 20px;
box-sizing: border-box;
align-items: center;
justify-content: center;
}
/** Background
---------------------------------------------------------*/
.background {
position: absolute;
top: 0; left: 0;
width: 100%;
height: 100%;
opacity: 0;
background: var(--overlay-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: 100%;
margin: auto;
box-shadow: 0 1px 0 0px rgba(0,0,0,0.15);
background: var(--background);
transition: opacity 300ms;
opacity: 0;
}
@media (min-width: 360px) {
.window {
width: auto;
min-width: 320px;
}
}
.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: var(--title-color);
}
::content strong {
font-weight: 700;
}
::content small {
font-size: 0.8em;
}
/** Section
---------------------------------------------------------*/
::content section {
padding: 33px 18px;
}
::content section > *:not(:last-child) {
margin-bottom: 13px;
}
/** Paragraphs
---------------------------------------------------------*/
::content p {
text-align: start;
line-height: 1.3em;
}
/** Buttons
---------------------------------------------------------*/
::content button {
position: relative;
display: block;
width: 100%;
height: 50px;
border: 0;
padding: 0 16px;
cursor: pointer;
font: inherit;
background: var(--background-plus);
color: var(--text-color);
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(--text-color-minus);
}
/** Button Divider Line
---------------------------------------------------------*/
::content button:after {
content: '';
display: block;
position: absolute;
height: 1px;
left: 6px;
right: 6px;
top: 49px;
background: var(--background);
}
::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: var(--background);
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));

View file

@ -0,0 +1,39 @@
{
"name": "gaia-header",
"version": "0.9.5",
"homepage": "https://github.com/gaia-components/gaia-header",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "gaia-header.js",
"license": "MIT",
"ignore": [
"**/.*",
"!.jshintrc",
"node_modules",
"bower_components",
"test",
"index.html",
"package.json",
"README.md"
],
"dependencies": {
"gaia-icons": "gaia-components/gaia-icons#~0.10.3",
"gaia-component": "gaia-components/gaia-component#~0.4.0",
"font-fit": "gaia-components/font-fit#~0.3.0"
},
"devDependencies": {
"gaia-theme": "gaia-components/gaia-theme",
"gaia-fonts": "gaia-components/gaia-fonts",
"base": "gaia-components/base"
},
"_release": "0.9.5",
"_resolution": {
"type": "version",
"tag": "v0.9.5",
"commit": "aa4c9c5cb83ce8813c8472860671ea514f07274f"
},
"_source": "git://github.com/gaia-components/gaia-header.git",
"_target": "~0.9.5",
"_originalSource": "gaia-components/gaia-header"
}

View file

@ -0,0 +1,33 @@
{
"camelcase": false,
"curly": true,
"forin": false,
"latedef": "nofunc",
"newcap": false,
"noarg": true,
"node": true,
"nonew": true,
"quotmark": "single",
"undef": true,
"unused": "vars",
"strict": true,
"trailing": true,
"maxlen": 80,
"eqnull": true,
"esnext": true,
"expr": true,
"globalstrict": true,
"maxerr": 1000,
"regexdash": true,
"laxcomma": true,
"proto": true,
"browser": true,
"devel": true,
"nonstandard": true,
"worker": true,
"-W078": true
}

View file

@ -0,0 +1,30 @@
{
"name": "gaia-header",
"version": "0.9.5",
"homepage": "https://github.com/gaia-components/gaia-header",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "gaia-header.js",
"license": "MIT",
"ignore": [
"**/.*",
"!.jshintrc",
"node_modules",
"bower_components",
"test",
"index.html",
"package.json",
"README.md"
],
"dependencies": {
"gaia-icons": "gaia-components/gaia-icons#~0.10.3",
"gaia-component": "gaia-components/gaia-component#~0.4.0",
"font-fit": "gaia-components/font-fit#~0.3.0"
},
"devDependencies": {
"gaia-theme": "gaia-components/gaia-theme",
"gaia-fonts": "gaia-components/gaia-fonts",
"base": "gaia-components/base"
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
{
"name": "gaia-icons",
"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",
"bidi-helper.css"
],
"license": "MIT",
"ignore": [
"**/.*",
"!.jshintrc",
"node_modules",
"bower_components",
"templates",
"images",
"test",
"tests",
"index.html",
"create-svg-icon-set-file.py",
"Gruntfile.js",
"Dockerfile",
"bin",
"README.md",
"package.json"
],
"version": "1.0.2",
"_release": "1.0.2",
"_resolution": {
"type": "version",
"tag": "v1.0.2",
"commit": "42dfa3ed9a9ffa09733dc8db08a06d3dd9d0a081"
},
"_source": "git://github.com/gaia-components/gaia-icons.git",
"_target": "~1.0.2",
"_originalSource": "gaia-components/gaia-icons"
}

View file

@ -0,0 +1,33 @@
{
"camelcase": false,
"curly": true,
"forin": false,
"latedef": "nofunc",
"newcap": false,
"noarg": true,
"node": true,
"nonew": true,
"quotmark": "single",
"undef": true,
"unused": "vars",
"strict": true,
"trailing": true,
"maxlen": 80,
"eqnull": true,
"esnext": true,
"expr": true,
"globalstrict": true,
"maxerr": 1000,
"regexdash": true,
"laxcomma": true,
"proto": true,
"browser": true,
"devel": true,
"nonstandard": true,
"worker": true,
"-W078": true
}

View file

@ -0,0 +1,74 @@
/* Some BiDi-proof icons
* In the future, we might handle this at the font level, see
* https://bugzilla.mozilla.org/show_bug.cgi?id=1214127
*/
[data-icon="back"]:-moz-dir(ltr):before {
content: 'left';
}
[data-icon="back"]:-moz-dir(rtl):before {
content: 'right';
}
[data-icon="forward"]:-moz-dir(ltr):before {
content: 'right';
}
[data-icon="forward"]:-moz-dir(rtl):before {
content: 'left';
}
[data-icon="back-light"]:-moz-dir(ltr):before {
content: 'left-light';
}
[data-icon="back-light"]:-moz-dir(rtl):before {
content: 'right-light';
}
[data-icon="forward-light"]:-moz-dir(ltr):before {
content: 'right-light';
}
[data-icon="forward-light"]:-moz-dir(rtl):before {
content: 'left-light';
}
[data-icon="arrow-back"]:-moz-dir(ltr):before {
content: 'arrow-left';
}
[data-icon="arrow-back"]:-moz-dir(rtl):before {
content: 'arrow-right';
}
[data-icon="arrow-forward"]:-moz-dir(ltr):before {
content: 'arrow-right';
}
[data-icon="arrow-forward"]:-moz-dir(rtl):before {
content: 'arrow-left';
}
[data-icon="clear-input"]:-moz-dir(ltr):before {
content: 'clear-input-left';
}
[data-icon="clear-input"]:-moz-dir(rtl):before {
content: 'clear-input-right';
}
[data-icon="expand"]:-moz-dir(ltr):before {
content: 'expand-left';
}
[data-icon="expand"]:-moz-dir(rtl):before {
content: 'expand-right';
}
[data-icon="send"]:-moz-dir(ltr):before {
content: 'send-right';
}
[data-icon="send"]:-moz-dir(rtl):before {
content: 'send-left';
}
[data-icon="edit"]:-moz-dir(ltr):before {
content: 'edit-left';
}
[data-icon="edit"]:-moz-dir(rtl):before {
content: 'edit-right';
}

View file

@ -0,0 +1,32 @@
{
"name": "gaia-icons",
"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",
"bidi-helper.css"
],
"license": "MIT",
"ignore": [
"**/.*",
"!.jshintrc",
"node_modules",
"bower_components",
"templates",
"images",
"test",
"tests",
"index.html",
"create-svg-icon-set-file.py",
"Gruntfile.js",
"Dockerfile",
"bin",
"README.md",
"package.json"
]
}

Binary file not shown.

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,40 @@
/* 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;
}
[data-icon]:not([data-l10n-id]):not([aria-label]):not([aria-hidden="true"]):before {
/* Highlight cases where icons are not localized and still visible to screen
reader */
background: rgba(255, 0, 0, 0.4);
}
[data-icon]:not([data-l10n-id]):not([aria-label]):not([aria-hidden="true"]):after {
background: #333;
color: #fff;
position: absolute;
width: 20rem;
border-radius: 0.5rem;
padding: 0.5rem;
content: "Icon is not localized and is still visible to screen reader. Please add data-l10n-id or aria-label for localization or use aria-hidden to hide the icon from screen reader.";
z-index: 9999;
}

View file

@ -0,0 +1,38 @@
/* global define */
(function(define){'use strict';define(function(require,exports,module){
/**
* 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){'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-icons',this));

View file

@ -0,0 +1,33 @@
{
"name": "gaia-site-icon",
"description": "A web component to show an icon for an application or site.",
"authors": [
"Chris Lord <chrislord.net@gmail.com>"
],
"main": "script.js",
"keywords": [
"app",
"icon",
"homescreen",
"B2G",
"Firefox OS"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"homepage": "https://github.com/fxos-components/gaia-site-icon",
"_release": "dd873b7f7d",
"_resolution": {
"type": "branch",
"branch": "master",
"commit": "dd873b7f7d0d8be737566276f3188e68931a9584"
},
"_source": "git://github.com/fxos-components/gaia-site-icon.git",
"_target": "*",
"_originalSource": "fxos-components/gaia-site-icon"
}

View file

@ -0,0 +1,24 @@
{
"name": "gaia-site-icon",
"version": "0.0.0",
"description": "A web component to show an icon for an application or site.",
"authors": [
"Chris Lord <chrislord.net@gmail.com>"
],
"main": "script.js",
"keywords": [
"app",
"icon",
"homescreen",
"B2G",
"Firefox OS"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>GaiaAppIcon demo</title>
<script src="../script.js"></script>
<style>
gaia-app-icon {
width: 256px;
}
</style>
</head>
<body>
<gaia-app-icon id="icon"></gaia-app-icon>
</body>
<script>
// TODO: This example doesn't work anymore, icon takes an app and uses
// app.manifest, app.launch and navigator.mozApps.mgmt.getIcon.
var icon = document.getElementById('icon');
icon.manifest = {
name: 'GaiaAppIcon test',
origin: '',
icons: {
'284': 'icon.png'
}
};
</script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -0,0 +1,7 @@
/* XXX Bug 1018269
* animation keyframes have to be specified outside of the shadow DOM.
*/
@keyframes rotate {
from { transform: rotate(1deg); }
to { transform: rotate(360deg); }
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84"><path opacity=".85" fill="#5F5F5F" d="M42 0c23.3 0 42 18.7 42 42S65.3 84 42 84 0 65.3 0 42 18.7 0 42 0z"/><path fill="#FFF" d="M60.7 40.1c-.9-9.3-9.3-16.8-18.7-16.8-10.3 0-18.7 8.4-18.7 18.7S31.7 60.7 42 60.7c3.7 0 7.5-.9 10.3-2.8l-2.8-3.7C46.7 56.1 44.8 57 42 57c-8.4 0-14.9-6.5-14.9-14.9s6.5-15 14.9-15c7.5 0 13.1 5.6 14 13.1h-6.5l7.5 7.5c.9.9 2.8.9 3.7 0l7.5-7.5h-7.5z"/></svg>

After

Width:  |  Height:  |  Size: 443 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84"><path opacity=".85" fill="#E51E1E" d="M42 0c23.3 0 42 18.7 42 42S65.3 84 42 84 0 65.3 0 42 18.7 0 42 0z"/><path fill="#FFF" d="M60.7 40.1c-.9-9.3-9.3-16.8-18.7-16.8-10.3 0-18.7 8.4-18.7 18.7S31.7 60.7 42 60.7c3.7 0 7.5-.9 10.3-2.8l-2.8-3.7C46.7 56.1 44.8 57 42 57c-8.4 0-14.9-6.5-14.9-14.9s6.5-15 14.9-15c7.5 0 13.1 5.6 14 13.1h-6.5l7.5 7.5c.9.9 2.8.9 3.7 0l7.5-7.5h-7.5z"/></svg>

After

Width:  |  Height:  |  Size: 443 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="24.134" y1="31.414" x2="81.176" y2="46.699"><stop offset="0" stop-color="#00B4CF"/><stop offset=".979" stop-color="#00B4CF" stop-opacity="0"/></linearGradient><path fill-rule="evenodd" clip-rule="evenodd" fill="url(#a)" d="M83.9 39.5v2.6h-3.3c0 21.3-17.3 38.6-38.7 38.6C20.6 80.7 3.3 63.4 3.3 42 3.3 20.6 20.6 3.3 42 3.3V0C18.8 0 0 18.8 0 42s18.8 42 42 42 42-18.8 42-42c0-.8 0-1.7-.1-2.5z"/></svg>

After

Width:  |  Height:  |  Size: 518 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84"><path opacity=".85" fill="#E51E1E" d="M42 0c23.3 0 42 18.8 42 42 0 23.3-18.8 42-42 42-23.1.1-42-18.7-42-42C0 18.8 18.9 0 42 0z"/><path fill="#FFF" d="M42 25.4c-.9 0-2.5 2.5-3.4 5.5 1.1-.2 2.3-.3 3.5-.3s2.3.1 3.3.3c-.9-3-2.5-5.5-3.4-5.5M27.1 39.1l5.7-5.7c1.7-8.3 6.7-16.7 9.2-16.7s7.5 8.4 9.2 16.7l5.7 5.7V54h-4l-5.6-5.6c-.6.6-1.2 1.1-1.9 1.5h-7c-.7-.4-1.3-.9-1.9-1.5L31.1 54h-4V39.1M16.6 59.2c.4.9 1.3 1.5 2.4 1.5h46c1 0 1.9-.6 2.4-1.5H16.6z"/></svg>

After

Width:  |  Height:  |  Size: 513 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84"><path opacity=".85" fill="#333" d="M42 0c23.3 0 42 18.8 42 42 0 23.3-18.8 42-42 42-23.1.1-42-18.7-42-42C0 18.8 18.9 0 42 0z"/><path fill="#FFF" d="M29.9 50c.4.9 1.3 1.5 2.4 1.5h19.3c1 0 1.9-.6 2.4-1.5H29.9zm22.3-17.8L51 33.4v.1L42.4 42c-.3.3-.7.3-1 0l-8.6-8.6v-.1l-1.2-1.2c-1.6.3-3.1.6-4.6.9.2.5.4 1 .9 1.5l11.3 11.3c1.5 1.5 3.8 1.5 5.3 0l11.3-11.3c.4-.4.7-.9.9-1.5-1.4-.3-2.9-.6-4.5-.8z"/></svg>

After

Width:  |  Height:  |  Size: 459 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="42" x2="42" y2="84"><stop offset="0" stop-color="#E5EBEF"/><stop offset="1" stop-color="#EDF1F4"/></linearGradient><path fill="url(#a)" d="M42 0c23.3 0 42 18.8 42 42 0 23.3-18.8 42-42 42-23.1.1-42-18.7-42-42C0 18.8 18.9 0 42 0z"/><path fill="#9AB0C0" d="M41.5 25.9c-.9 0-2.5 2.6-3.5 5.7 1.1-.2 2.3-.3 3.6-.3 1.2 0 2.4.1 3.4.3-1-3.1-2.6-5.7-3.5-5.7M43 53.3h2.2c.3.9.4 2 .4 3.1 0 4-3.1 7.2-4.1 7.2s-4.1-3.2-4.1-7.2c0-1.1.1-2.2.4-3.1H40c-.2.5-.3 1.2-.3 1.9 0 1.8 1.4 3.3 1.9 3.3s1.9-1.5 1.9-3.3c-.2-.7-.3-1.4-.5-1.9M26.1 40l5.9-5.9c1.7-8.6 6.9-17.2 9.5-17.2s7.8 8.7 9.5 17.2l5.9 5.9v15.4h-4.1l-5.7-5.7c-.6.6-1.2 1.1-1.9 1.5h-7.3c-.7-.4-1.3-.9-1.9-1.5l-5.7 5.7h-4.1L26.1 40"/></svg>

After

Width:  |  Height:  |  Size: 799 B

View file

@ -0,0 +1,39 @@
{
"name": "gaia-site-icon",
"version": "0.0.1",
"description": "A web component to show an icon for an application or site.",
"author": [
{
"name": "Chris Lord",
"email": "chrislord.net@gmail.com"
}
],
"main": "script.js",
"directories": {
"example": "examples"
},
"scripts": {
"test": "./node_modules/karma/bin/karma start test/karma.conf.js --single-run",
"test-dev": "./node_modules/karma/bin/karma start test/karma.conf.js"
},
"repository": {
"type": "git",
"url": "git@github.com:gaia-components/gaia-site-icon.git"
},
"devDependencies": {
"karma": "^0.12.37",
"karma-firefox-launcher": "^0.1.6",
"karma-mocha": "^0.2.0",
"karma-sinon-chai": "^1.0.0",
"mocha": "^2.2.5",
"mozilla-download": "^1.1.1"
},
"keywords": [
"app",
"icon",
"homescreen",
"B2G",
"Firefox OS"
],
"license": "MIT"
}

View file

@ -0,0 +1,607 @@
'use strict';
window.GaiaAppIcon = (function(exports) {
const LAUNCH_TIMEOUT = 500;
const PREDEFINED_ICONS = {
default: 'default_icon.svg',
unrecoverable: 'app_install_unrecoverable.svg',
installing: 'app_installing.svg',
paused: 'app_install_canceled.svg',
failed: 'app_install_failed.svg'
};
const SHADOW_BLUR = 1;
const SHADOW_OFFSET = { x: 1, y: 1 };
const SHADOW_COLOR = 'rgba(0, 0, 0, 0.2)';
const DEFAULT_BACKGROUND_COLOR = 'rgb(228, 234, 238)';
const CANVAS_PADDING = 2 * window.devicePixelRatio;
const FAVICON_SCALE = 0.55;
var proto = Object.create(HTMLElement.prototype);
// Allow the base URL to be overridden
var base = window.GAIA_ICONS_BASE_URL ||
window.COMPONENTS_BASE_URL ||
'bower_components/';
var baseurl = window.GaiaAppIconBaseurl || base + 'gaia-site-icon/';
proto.createdCallback = function() {
this._template = template.content.cloneNode(true);
var shadow = this.createShadowRoot();
shadow.appendChild(this._template);
this._container = shadow.getElementById('image-container');
this._titleContainer = shadow.getElementById('title-container');
this._subtitle = shadow.getElementById('subtitle');
this._showName = true;
this._image = null;
this._app = null;
this._bookmark = null;
this._entryPoint = '';
this._size = -1;
this._hasIcon = false;
this._hasUserSetIcon = false;
this._hasPredefinedIcon = false;
this._iconUrl = null;
this._pendingIconUrl = null;
this._pendingIconRefresh = false;
this._lastState = null;
this._predefinedIcons = {};
for (var key in PREDEFINED_ICONS) {
this._predefinedIcons[key] = baseurl + 'images/' + PREDEFINED_ICONS[key];
}
// Make the icon accessible/allow activation
this.tabIndex = 0;
this.setAttribute('role', 'link');
var activate = () => {
if (!this.dispatchEvent(new CustomEvent('activated',
{ cancelable: true }))) {
return;
}
this.launch();
};
this.addEventListener('keydown', (e) => {
switch (e.keyCode) {
case 32: // Space
case 13: // Enter
activate();
}
});
this.addEventListener('click', activate);
// Refresh now we've created the DOM
this.refresh();
};
Object.defineProperty(proto, 'app', {
get: function() {
return this._app;
},
set: function(app) {
if (this._app) {
this._app.removeEventListener('progress', this);
this._app.removeEventListener('downloaderror', this);
this._app.removeEventListener('downloadsuccess', this);
this._app.removeEventListener('downloadapplied', this);
}
delete this.dataset.testIconUrl;
this._cancelIconLoad();
this._removeOldIcon();
this._hasIcon = false;
this._app = app;
if (!app) {
return;
}
this._bookmark = null;
this._app.addEventListener('progress', this);
this._app.addEventListener('downloaderror', this);
this._app.addEventListener('downloadsuccess', this);
this._app.addEventListener('downloadapplied', this);
this._container.classList.add('initial-load');
},
enumerable: true
});
Object.defineProperty(proto, 'entryPoint', {
get: function() {
return this._entryPoint;
},
set: function(entryPoint) {
this._entryPoint = entryPoint ? entryPoint : '';
this.refresh();
},
enumerable: true
});
Object.defineProperty(proto, 'state', {
get: function() {
if (!this.app) {
return 'unavailable';
}
if (this.app.installState === 'pending' &&
!this.app.downloadAvailable &&
!this.app.readyToApplyDownload) {
return 'unrecoverable';
}
if (this.app.downloading) {
return 'installing';
}
if (this.app.downloadError) {
if (this.app.downloadError.name === 'DOWNLOAD_CANCELED') {
return 'paused';
} else {
return 'error';
}
}
if (this.app.installState === 'pending') {
return 'paused';
}
return 'installed';
},
enumberable: true
});
Object.defineProperty(proto, 'name', {
get: function() {
return this._subtitle ? this._subtitle.textContent : '';
},
enumberable: true
});
Object.defineProperty(proto, 'size', {
get: function() {
return (this._size === -1) ? this.clientWidth : this._size;
},
set: function(size) {
this._size = size >= 0 ? size : -1;
},
enumerable: true
});
Object.defineProperty(proto, 'bookmark', {
get: function() {
return this._bookmark;
},
set: function(bookmark) {
if (!this._bookmark || this._bookmark.id !== bookmark.id) {
this.app = null;
}
this._bookmark = bookmark;
},
enumerable: true
});
Object.defineProperty(proto, 'icon', {
get: function() {
if (window.VulpesCompat && this.app && this._vulpesSourceIcon) return Promise.resolve(this._vulpesSourceIcon);
return new Promise((resolve, reject) => {
if (!this._hasIcon || this._hasPredefinedIcon) {
return reject();
}
var image = this._container.querySelector('img');
if (!image) {
return reject();
}
var canvas = document.createElement('canvas');
var size = this.size * window.devicePixelRatio;
canvas.width = canvas.height = size;
var ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.drawImage(image, 0, 0, size, size);
try {
canvas.toBlob((blob) => {
resolve(blob);
});
} catch(e) {
console.error('Failed to get canvas data for icon');
reject(e);
}
});
},
set: function(blob) {
if (blob) {
this._prepareIconLoader();
this._hasUserSetIcon = true;
this._pendingIconUrl = 'user-set';
this._image.src = URL.createObjectURL(blob);
} else {
this._pendingIconUrl = null;
delete this.dataset.testIconUrl;
this._cancelIconLoad();
this._removeOldIcon();
}
},
enumerable: true
});
Object.defineProperty(proto, 'showName', {
get: function() {
return this._showName;
},
set: function(show) {
show = show ? true : false;
if (this._showName !== show) {
this._showName = show;
this._titleContainer.classList.toggle('hidden', !show);
}
},
enumerable: true
});
Object.defineProperty(proto, 'isUserSet', {
get: function() {
return this._iconUrl === 'user-set';
},
enumerable: true
});
proto._cancelIconLoad = function() {
if (!this._image) {
return;
}
this._pendingIconUrl = null;
this._image.onload = null;
this._image.src = '';
this._image = null;
};
proto._removeOldIcon = function() {
while (this._container.children.length > 1) {
this._container.removeChild(this._container.lastChild);
}
};
proto.launch = function() {
if (!this.app && !this.bookmark) {
return;
}
this.classList.add('launching');
setTimeout(() => { this.classList.remove('launching'); }, LAUNCH_TIMEOUT);
if (this.app) {
window.performance.mark('appLaunch@' + this.app.origin);
this.app.launch(this.entryPoint);
} else {
var features = {
name: this.bookmark.name,
remote: true
};
if (this.bookmark.scope) {
features.scope = this.bookmark.scope;
}
window.open(this.bookmark.url, '_samescope', Object.keys(features)
.map(function eachFeature(key) {
return encodeURIComponent(key) + '=' +
encodeURIComponent(features[key]);
}).join(','));
}
};
proto._prepareIconLoader = function() {
// Create new image element to load icon
this._cancelIconLoad();
this._hasPredefinedIcon = false;
this._hasUserSetIcon = false;
this._image = document.createElement('img');
this._image.setAttribute('role', 'presentation');
this._image.onload = () => {
this._image.onload = () => {
// Add new icon
this._removeOldIcon();
this._container.appendChild(this._image);
this._container.classList.remove('initial-load');
this._image = null;
this._hasIcon = true;
// Set icon URL on dataset, for testing.
if (this._pendingIconUrl) {
this._iconUrl = this.dataset.testIconUrl = this._pendingIconUrl;
this._pendingIconUrl = null;
}
if (!this._hasPredefinedIcon) {
this.dispatchEvent(new CustomEvent('icon-loaded'));
}
if (this._pendingIconRefresh) {
this._image = null;
this._pendingIconRefresh = false;
this.refresh();
}
};
if (!this._hasUserSetIcon) {
// Process the image
var canvas = document.createElement('canvas');
var size = this.size * window.devicePixelRatio;
canvas.width = canvas.height = size;
var ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.shadowColor = SHADOW_COLOR;
ctx.shadowBlur = SHADOW_BLUR;
ctx.shadowOffsetX = SHADOW_OFFSET.x;
ctx.shadowOffsetY = SHADOW_OFFSET.y;
if (this.bookmark && !this._hasPredefinedIcon) {
if (this._image.width <= size / 2) {
// Draw filled background circle
ctx.beginPath();
ctx.arc(size / 2, size / 2,
size / 2 - CANVAS_PADDING, 0, 2 * Math.PI);
ctx.fillStyle = DEFAULT_BACKGROUND_COLOR;
ctx.fill();
// Disable shadow drawing and image smoothing
ctx.shadowBlur = 0;
ctx.shadowOffsetY = 0;
ctx.mozImageSmoothingEnabled = false;
var iconSize = size * FAVICON_SCALE;
ctx.drawImage(this._image,
(size - iconSize) / 2,
(size - iconSize) / 2,
iconSize, iconSize);
} else {
// Clip the favicon in a circle. We do this in a new canvas so
// the shadow-rendering on the main canvas works correctly.
var clipCanvas = document.createElement('canvas');
clipCanvas.width = clipCanvas.height = size;
var clipCtx =
clipCanvas.getContext('2d', { willReadFrequently: true });
clipCtx.beginPath();
clipCtx.arc(size / 2, size / 2,
size / 2 - CANVAS_PADDING, 0, 2 * Math.PI);
clipCtx.clip();
clipCtx.drawImage(this._image,
CANVAS_PADDING, CANVAS_PADDING,
size - CANVAS_PADDING * 2,
size - CANVAS_PADDING * 2);
ctx.drawImage(clipCanvas, 0, 0);
}
} else {
// Just draw the icon straight (without padding if it was set
// explicitly rather than loaded via manifest/bookmark)
ctx.drawImage(this._image,
CANVAS_PADDING, CANVAS_PADDING,
size - CANVAS_PADDING * 2,
size - CANVAS_PADDING * 2);
}
canvas.toBlob(function(image, blob) {
if (image.onload) {
image.src = URL.createObjectURL(blob);
}
}.bind(this, this._image));
}
if (this._hasUserSetIcon) {
this._image.onload();
}
};
this._image.onerror = (e) => {
console.error('Failed to load icon', e);
this._pendingIconUrl = null;
if (this._pendingIconRefresh) {
this._pendingIconRefresh = false;
this._image = null;
this.refresh();
} else if (!this._hasIcon) {
this._image.onerror = null;
this._setPredefinedIcon('default');
} else {
this._image = null;
}
};
};
proto._setPredefinedIcon = function(name) {
this._hasPredefinedIcon = true;
this._image.src = this._pendingIconUrl = this._predefinedIcons[name];
};
proto._localizeString = function(str) {
var userLang = document.documentElement.lang;
// We want to make sure that we tranlsate only if we're using
// a runtime pseudolocale.
// mozL10n.ctx.qps contains only runtime pseudolocales
if (navigator.mozL10n &&
navigator.mozL10n.ctx.qps.indexOf(userLang) !== -1) {
return navigator.mozL10n.qps[userLang].translate(str);
}
return str;
};
proto.updateName = function() {
if (this.app) {
var userLang = document.documentElement.lang;
var ep = this.entryPoint || undefined;
this.app.getLocalizedValue('short_name', userLang, ep).then(
(shortName) => {
this._subtitle.textContent = this._localizeString(shortName);
},
() => {
this.app.getLocalizedValue('name', userLang, ep).then(
(name) => {
this._subtitle.textContent = this._localizeString(name);
},
(e) => {
// Try to fall back to manifest app name
var manifest = this.app.manifest || this.app.updateManifest;
if (manifest) {
var nameObject = (manifest.entry_points && this.entryPoint) ?
manifest.entry_points[this.entryPoint] : manifest;
this._subtitle.textContent =
this._localizeString(nameObject.short_name || nameObject.name);
} else {
console.error('Error retrieving app name', e);
this._subtitle.textContent = '';
}
});
});
} else if (this.bookmark) {
this._subtitle.textContent = this.bookmark.name;
} else {
this._subtitle.textContent = '';
}
};
proto.refresh = function() {
if (!this._template) {
return;
}
this.updateName();
this._container.classList.remove('downloading');
// Set an identifier on the icon to help with automated testing.
if (this.app) {
this.dataset.identifier = this.app.manifestURL +
(this.entryPoint ? '/' + this.entryPoint : '');
} else if (this.bookmark) {
this.dataset.identifier = this.bookmark.id;
} else {
delete this.dataset.identifier;
}
// If we're already loading an icon, let that finish first.
if (this._image) {
this._pendingIconRefresh = true;
return;
}
// If the icon won't be visible, don't bother fetching and processing it.
var size = this.size * window.devicePixelRatio;
if (size < 1) {
return;
}
this._prepareIconLoader();
// Handle icon loading for bookmarks, app icon loading is more involved
// and handled below this block.
if (this.bookmark) {
// Fallback to the default icon
if (!this._hasIcon) {
this._setPredefinedIcon('default');
}
return;
}
// If the app is downloading/paused/failed to download, use a predefined
// icon.
var state = this._lastState = this.state;
switch (state) {
case 'unrecoverable':
this._setPredefinedIcon('unrecoverable');
break;
case 'installing':
this._setPredefinedIcon('installing');
this._container.classList.add('downloading');
break;
case 'paused':
this._setPredefinedIcon('paused');
break;
case 'error':
this._setPredefinedIcon('failed');
break;
case 'installed':
var handleError = function(image, e) {
if (e.message !== 'NO_ICON' && e.name !== 'NO_ICON') {
console.error('Failed to retrieve icon', e);
}
if (image.onload && !this._hasIcon) {
this._setPredefinedIcon('default');
} else {
this._image = null;
}
};
var getImage = () => {
navigator.mozApps.mgmt.getIcon(this.app, size, this.entryPoint).
then(function(image, blob) {
this._pendingIconUrl = 'app-icon';
if (window.VulpesCompat) { this._vulpesSourceIcon = blob; this._hasUserSetIcon = true; } // Keep original app pixels; skip the legacy canvas pass.
if (image.onload) {
image.src = URL.createObjectURL(blob);
}
}.bind(this, this._image),
handleError.bind(this, this._image));
};
getImage();
break;
}
};
proto.handleEvent = function(e) {
switch(e.type) {
case 'progress':
case 'downloadsuccess':
if (this.state !== this._lastState) {
this.refresh();
}
break;
case 'downloaderror':
case 'downloadapplied':
this.refresh();
break;
}
};
var template = document.createElement('template');
var stylesheet = baseurl + 'style.css';
template.innerHTML =
`<style>@import url(${stylesheet});</style>
<div id="image-container"><div id="spinner"></div></div>
<div id="title-container"><div dir="auto" id="subtitle"></div></div>`;
return document.registerElement('gaia-app-icon', { prototype: proto });
})(window);

View file

@ -0,0 +1,54 @@
gaia-app-icon {
display: flex;
flex-direction: column;
font-size: 0;
}
#image-container {
position: relative;
transition: visibility 0.2s, opacity 0.2s;
}
#image-container.initial-load {
opacity: 0;
visibility: hidden;
}
#image-container > #spinner {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#image-container.downloading > #spinner {
display: block;
background: no-repeat center center url('images/app_install_spinner.svg');
background-size: contain;
animation: rotate 2s infinite linear;
}
#image-container,
#image-container > * {
width: 100%;
}
#subtitle {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-top: 0.3rem;
}
#title-container {
transition: opacity 0.2s, visibility 0.2s;
}
#title-container.hidden {
opacity: 0;
visibility: hidden;
height: 0;
}

View file

@ -0,0 +1,38 @@
{
"name": "gaia-text-input",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "gaia-text-input.js",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests",
"index.html",
"manifest.webapp",
"README.md"
],
"dependencies": {
"gaia-icons": "fxos-components/gaia-icons#~1.0.0",
"gaia-component": "fxos-components/gaia-component#~0.6.0"
},
"devDependencies": {
"gaia-fonts": "fxos-components/gaia-fonts",
"gaia-theme": "fxos-components/gaia-theme",
"base": "fxos-components/base"
},
"homepage": "https://github.com/gaia-components/gaia-text-input",
"version": "0.3.0",
"_release": "0.3.0",
"_resolution": {
"type": "version",
"tag": "v0.3.0",
"commit": "6a520d865fe541853f88ca74c098565da28bff41"
},
"_source": "git://github.com/gaia-components/gaia-text-input.git",
"_target": "*",
"_originalSource": "gaia-components/gaia-text-input"
}

View file

@ -0,0 +1,30 @@
{
"name": "gaia-text-input",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "gaia-text-input.js",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests",
"index.html",
"manifest.webapp",
"README.md"
],
"dependencies": {
"gaia-icons": "fxos-components/gaia-icons#~1.0.0",
"gaia-component": "fxos-components/gaia-component#~0.6.0"
},
"devDependencies": {
"gaia-fonts": "fxos-components/gaia-fonts",
"gaia-theme": "fxos-components/gaia-theme",
"base": "fxos-components/base"
}
}

View file

@ -0,0 +1,214 @@
(define=>{define((require,exports,module)=>{
'use strict';
/**
* Dependencies
*/
var component = require('gaia-component');
/**
* Exports
*/
module.exports = component.register('gaia-text-input-multiline', {
created() {
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(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);
font-size: 17px;
}
/** 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>`
});
})})(((n,w)=>{return(typeof define)[0]=='f'&&define.amd?define:(typeof module)[0]=='o'?c =>{c(require,exports,module)}:c=>{var m={exports:{}},r=n=>w[n];w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input-multiline',this));/*jshint ignore:line*/

View file

@ -0,0 +1,278 @@
(define=>{define((require,exports,module)=>{
'use strict';
/**
* Dependencies
*/
var component = require('gaia-component');
/**
* Locals
*/
var DEFAULT_LENGTH = 4;
/**
* Exports
*/
module.exports = component.register('gaia-text-input-pin', {
created() {
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() {
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(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() {
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);
}
},
clear(e) {
this.value = '';
this.updateCells();
},
focus(e) {
this.els.input.focus();
},
/**
* 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 x-inputmode="digit"/>
<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;
left: 0;
bottom: 0;
width: 100%;
height: 3px;
visibility: hidden;
background: var(--highlight-color, #000);
}
/**
* input:focus
*/
input:focus + .fields .cell::before {
visibility: visible;
}
</style>
`
});
})})(((n,w)=>{return(typeof define)[0]=='f'&&define.amd?define:(typeof module)[0]=='o'?c =>{c(require,exports,module)}:c=>{var m={exports:{}},r=n=>w[n];w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input-pin',this));/*jshint ignore:line*/

View file

@ -0,0 +1,378 @@
(define=>{define((require,exports,module)=>{
'use strict';
/**
* Dependencies
*/
var component = require('gaia-component');
require('gaia-icons'); // Load gaia-icons
/**
* Mini logger
*
* @type {Function}
*/
var debug = 0 ? (...args) => console.log('[GaiaTextInput]', ...args) : () => {};
/**
* Exports
*/
module.exports = component.register('gaia-text-input', {
created() {
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.inputmode = this.getAttribute('x-inputmode');
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));
this.els.input.addEventListener('input', e => this.onInput(e));
this.els.input.addEventListener('focus', e => this.onFocus(e));
this.els.input.addEventListener('blur', e => this.onBlur(e));
},
/**
* Clear the field.
*
* @public
*/
clear() {
debug('clear');
this.value = '';
this.emit('clear');
},
/**
* Focus the field.
*
* @public
*/
focus() {
debug('focus');
this.els.input.focus();
},
/**
* Unfocus the field.
*
* @public
*/
blur() {
debug('blur');
this.els.input.blur();
},
/**
* Runs when the field is focused.
*
* @private
*/
onFocus() {
debug('on focus');
this.els.inner.classList.add('focused');
this.emit('focus');
},
/**
* Runs when the field is unfocused.
*
* @private
*/
onBlur() {
debug('on blur');
this.els.inner.classList.remove('focused');
this.emit('blur');
},
/**
* Runs when the value of the
* input is manually changed.
*
* @private
*/
onInput() {
debug('on input');
this.onValueChanged();
},
/**
* Runs when the values changes
* programatically or via keystrokes.
*
* @private
*/
onValueChanged() {
debug('value changed');
var hasValue = !!this.value.length;
this.els.inner.classList.toggle('has-value', hasValue);
this.emit('input');
},
/**
* Emit a DOM event on the component.
*
* @param {String} name
* @param {*} detail
* @private
*/
emit(name, detail) {
var e = new CustomEvent(name, { detail: detail });
this.dispatchEvent(e);
},
/**
* 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);
}
},
inputmode: {
get: function() { return this.els.input.getAttribute('x-inputmode'); },
set: function(value) {
if (!value) {
this.els.input.removeAttribute('x-inputmode');
return;
}
this.els.input.setAttribute('x-inputmode', 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.setAttr('clearable', '');
else this.removeAttr('clearable');
this._clearable = clearable;
}
},
value: {
get: function() { return this.els.input.value; },
set: function(value) {
debug('set value', value);
this.els.input.value = value;
this.onValueChanged();
}
},
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);
font-size: 17px;
overflow: hidden;
--this-background:
var(--text-input-background,
var(--input-background,
var(--background-minus,
#fff)));
--this-border-color:
var(--input-border-color,
var(--border-color,
var(--background-plus,
#e7e7e7)));
}
.inner {
height: 100%;
}
label {
font-size: 14px;
display: block;
margin: 0 0 4px 16px;
}
[disabled] label {
opacity: 0.3;
}
.fields {
position: relative;
width: 100%;
height: 100%;
box-sizing: border-box;
border-color:
var(--this-border-color);
border:
var(--input-border,
var(--border,
1px solid var(--this-border-color)));
}
[type='search'] .fields {
border-radius: 30px;
overflow: hidden;
}
input {
display: block;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 0 16px;
margin: 0;
border: 0;
font: inherit;
resize: none;
/* Dynamic */
color: var(--text-color, #000);
background: var(--this-background);
}
input[disabled] {
background: var(--background);
}
::-moz-placeholder {
font-style: italic;
color:
var(--input-placeholder-color, #909ca7);
}
.clear {
position: absolute;
offset-inline-end: 0;
top: 0;
display: none;
width: 18px;
height: 18px;
padding: 0;
margin: 0;
border: solid 10px transparent;
box-sizing: content-box;
border-radius: 50%;
color: var(--background);
cursor: pointer;
background: var(--input-clear-background, #999);
background-clip: padding-box;
opacity: 0;
pointer-events: none;
}
[clearable] .clear {
display: block;
}
[clearable].has-value.focused .clear {
pointer-events: all;
transition: opacity 200ms;
opacity: 1;
}
.clear:before {
content: 'close';
display: block;
font: normal 500 19px/17px 'gaia-icons';
text-rendering: optimizeLegibility;
}
.focus {
position: absolute;
left: 0;
bottom: 0px;
width: 100%;
height: 3px;
transition: transform 200ms;
transform: scaleX(0);
visibility: hidden;
background: var(--highlight-color, #000);
}
[type='search'] .focus {
border-radius: 0 0 60px 60px;
left: 10px;
width: calc(100% - 20px);
}
/**
* .focused
*/
.focused .focus {
transform: scaleX(1);
transition-delay: 200ms;
visibility: visible;
}
</style>`
});
})})(((n,w)=>{return(typeof define)[0]=='f'&&define.amd?define:(typeof module)[0]=='o'?c =>{c(require,exports,module)}:c=>{var m={exports:{}},r=n=>w[n];w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input',this));/*jshint ignore:line*/

View file

@ -0,0 +1,34 @@
{
"name": "gaia-text-input",
"version": "0.3.0",
"homepage": "https://github.com/fxos-components/gaia-text-input",
"license": "ISC",
"main": "gaia-text-input.js",
"directories": {
"test": "test"
},
"devDependencies": {
"bower": "^1.6.5",
"jshint": "^2.8.0",
"karma": "^0.13.15",
"karma-firefox-launcher": "^0.1.6",
"karma-mocha": "^0.2.0",
"karma-sinon-chai": "^0.3.0",
"mocha": "^2.3.3"
},
"scripts": {
"postinstall": "bower install",
"test": "npm run --silent test-unit && npm run --silent test-lint",
"test-lint": "./node_modules/jshint/bin/jshint *.js",
"test-unit": "./node_modules/karma/bin/karma start test/karma.conf.js --single-run",
"test-unit-dev": "./node_modules/karma/bin/karma start test/karma.conf.js",
"gh-pages": "git co gh-pages; git merge master; git push upstrea gh-pages; git co -"
},
"repository": {
"type": "git",
"url": "git://github.com/fxos-components/gaia-text-input.git"
},
"bugs": {
"url": "https://github.com/fxos-components/gaia-text-input/issues"
}
}

View file

@ -0,0 +1,35 @@
{
"name": "gaia-theme",
"version": "0.4.7",
"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"
},
"_release": "0.4.7",
"_resolution": {
"type": "version",
"tag": "v0.4.7",
"commit": "a1b3220e6ae53503b0809eb04de22f28bc701612"
},
"_source": "git://github.com/gaia-components/gaia-theme.git",
"_target": "~0.4.6",
"_originalSource": "gaia-components/gaia-theme"
}

View file

@ -0,0 +1,4 @@
{
"strict": false,
"node": true
}

View file

@ -0,0 +1,26 @@
{
"name": "gaia-theme",
"version": "0.4.7",
"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"
}
}

View file

@ -0,0 +1,246 @@
/*
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);
--label-color: #000;
/** 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(--link-color);
}
.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);
--label-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;
}

View file

@ -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));

View file

@ -0,0 +1,38 @@
{
"name": "gaia-toast",
"homepage": "https://github.com/gaia-components/gaia-toast",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "script.js",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"index.html",
"test",
"tests",
"examples",
"README.md"
],
"devDependencies": {
"base": "gaia-components/base",
"gaia-theme": "gaia-components/gaia-theme#~0.4.1",
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
"gaia-button": "gaia-components/gaia-button#master"
},
"dependencies": {
"gaia-component": "gaia-components/gaia-component#~0.2.0"
},
"_release": "fd000de635",
"_resolution": {
"type": "branch",
"branch": "master",
"commit": "fd000de635edc3298cf78c387a1bcb7667fd7382"
},
"_source": "git://github.com/gaia-components/gaia-toast.git",
"_target": "*",
"_originalSource": "gaia-components/gaia-toast",
"_direct": true
}

View file

@ -0,0 +1,29 @@
{
"name": "gaia-toast",
"version": "0.0.0",
"homepage": "https://github.com/gaia-components/gaia-toast",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"main": "script.js",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"index.html",
"test",
"tests",
"examples",
"README.md"
],
"devDependencies": {
"base": "gaia-components/base",
"gaia-theme": "gaia-components/gaia-theme#~0.4.1",
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
"gaia-button": "gaia-components/gaia-button#master"
},
"dependencies": {
"gaia-component": "gaia-components/gaia-component#~0.2.0"
}
}

View file

@ -0,0 +1,170 @@
;(function(define){define(function(require,exports,module){
/*jshint esnext:true*/
'use strict';
/**
* Dependencies
*/
var component = require('gaia-component');
/**
* Exports
*/
module.exports = component.register('gaia-toast', {
created: function() {
this.setupShadowRoot();
this.els = {
inner: this.shadowRoot.querySelector('.inner'),
bread: this.shadowRoot.querySelector('.bread')
};
this.timeout = this.getAttribute('timeout');
},
show: function() {
this.els.bread.removeEventListener('animationend', this.onAnimateOutEnd);
clearTimeout(this.hideTimeout);
this.els.inner.classList.add('visible');
var reflow = this.els.inner.offsetTop;
this.els.bread.classList.remove('animate-out');
this.els.bread.classList.add('animate-in');
this.hideTimeout = setTimeout(this.hide.bind(this), this.timeout);
},
hide: function() {
var self = this;
clearTimeout(this.hideTimeout);
this.els.bread.classList.remove('animate-in');
this.els.bread.classList.add('animate-out');
this.els.bread.removeEventListener('animationend', this.onAnimateOutEnd);
this.onAnimateOutEnd = function() {
self.els.bread.removeEventListener('animationend', self.onAnimateOutEnd);
self.els.bread.classList.remove('animate-out');
self.els.inner.classList.remove('visible');
};
this.els.bread.addEventListener('animationend', this.onAnimateOutEnd);
},
animateOut: function() {},
attrs: {
timeout: {
get: function() { return this.getAttribute('timeout') || 1000; },
set: function(value) {
var current = this.getAttribute('timeout');
if (current == value) { return; }
else if (!value) { this.removeAttribute('timeout'); }
else { this.setAttribute('timeout', value); }
}
}
},
template: `
<div class="inner">
<div class="bread">
<content></content>
</div>
</div>
<style>
/** Host
---------------------------------------------------------*/
:host {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
font-style: italic;
text-align: center;
z-index: 100;
color:
var(--highlight-color);
}
/** Inner
---------------------------------------------------------*/
.inner {
display: none;
padding: 16px;
}
.inner.visible {
display: block;
}
/**
---------------------------------------------------------*/
.bread {
max-width: 600px;
margin: 0 auto;
padding: 16px;
box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 0.15);
transform: translateY(100%);
background:
var(--background-plus,
white);
}
.bread.animate-in {
animation-name: gaia-toast-enter;
animation-fill-mode: forwards;
animation-duration: 300ms;
}
.bread.animate-out {
animation-name: gaia-toast-leave;
animation-duration: 600ms;
transform: translateY(0%);
}
</style>
`,
globalCss: `
@keyframes gaia-toast-enter {
0% {
transform: translateY(100%);
opacity: 0;
}
40% {
opacity: 0;
}
100% {
transform: translateY(0%);
opacity: 1;
}
}
@keyframes gaia-toast-leave {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
`
});
});})(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-toast',this));

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="utf-8" />
<title>GaiaButtons Demo</title>
<meta name="description" content="Demo app for gaia-buttons" />
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
font-size: 10px;
background-color: #fff;
}
</style>
<script>
window.onload = function() {
var dirInput = document.getElementById('dir');
dirInput.checked = false;
dirInput.onchange= function() {
document.documentElement.dir = this.checked ? "rtl" : "ltr";
}
};
</script>
<script>window.GaiaButtonsBaseurl = '../';</script>
<script src="../../../js/component_utils.js"></script>
<script src="../script.js" type="text/javascript"></script>
</head>
<body role="application">
<p dir="ltr">
<label class="bb-docs">
<input id="dir" type="checkbox"> RTL mode
</label>
</p>
<gaia-buttons class="inline">
<button class="full" dir="auto">With class="inline"</button>
</gaia-buttons>
<gaia-buttons skin="dark">
<button class="recommend icon icon-previous">Button 1</button>
<button disabled>Button 2</button>
<a href="#" class="danger">Anchor 1</a>
</gaia-buttons>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="utf-8" />
<title>GaiaButtons Demo</title>
<meta name="description" content="Demo app for gaia-buttons" />
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
font-size: 10px;
background-color: #fff;
}
</style>
<script>
window.onload = function() {
var dirInput = document.getElementById('dir');
dirInput.checked = false;
dirInput.onchange = function() {
document.documentElement.dir = this.checked ? "rtl" : "ltr";
};
};
</script>
<script>window.GaiaButtonsBaseurl = '../';</script>
<script src="../../../js/component_utils.js"></script>
<script src="../script.js" type="text/javascript"></script>
</head>
<body role="application">
<p dir="ltr">
<label class="bb-docs">
<input id="dir" type="checkbox"> RTL mode
</label>
</p>
<section id="stress-test">
</section>
<script>
// add a thousand buttons
var stressSection = document.getElementById('stress-test');
var innerSectionHtml = '';
for (var i = 0; i < 1000; i++) {
innerSectionHtml +=
'<gaia-buttons class="inline">' +
' <button class="icon icon-next">next</button>' +
'</gaia-buttons>';
}
stressSection.innerHTML = innerSectionHtml;
</script>
</body>
</html>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"><path fill="#667174" fill-opacity=".7" d="m 18.2995,19.66 -5.056,-5.057 5.056,-5.056 c -0.31,-0.516 -0.62,-1.032 -0.93,-1.34 l -5.672,5.673 v 1.652 l 5.675,5.676 c 0.31,-0.515 0.722,-0.928 0.93,-1.547 z"/></svg>

After

Width:  |  Height:  |  Size: 294 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path fill="#667174" fill-opacity=".7" d="M11.8,19.9l4.9-4.9l-4.9-4.9c0.3-0.5,0.6-1,0.9-1.3l5.5,5.5c0,0.3,0,0.5,0,0.8c0,0.3,0,0.5,0,0.8l-5.5,5.5 C12.4,20.9,12,20.5,11.8,19.9z"/></svg>

After

Width:  |  Height:  |  Size: 243 B

View file

@ -0,0 +1,18 @@
'use strict';
/* global ComponentUtils */
window.GaiaButtons = (function(win) {
// Extend from the HTMLElement prototype
var proto = Object.create(HTMLElement.prototype);
// Allow baseurl to be overridden (used for demo page)
var baseurl = window.GaiaButtonsBaseurl ||
'/shared/elements/gaia_buttons/';
proto.createdCallback = function() {
ComponentUtils.style.call(this, baseurl);
};
// Register and return the constructor
return document.registerElement('gaia-buttons', { prototype: proto });
})(window);

View file

@ -0,0 +1,281 @@
/* ---------------------------------------
* gaia-buttons:
* Container for buttons e.g:
* action menu, confirm, edit mode, FTU
* --------------------------------------- */
gaia-buttons {
display: flex;
justify-content: center;
align-items: center;
height: 7rem;
box-sizing: border-box;
pointer-events: auto;
}
gaia-buttons:not(.inline) {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 10;
border-top: 0.1rem solid #e7e7e7;
padding: 0;
background-color: #f4f4f4;
}
/* this 'end' padding must match the buttons 'start' margin */
gaia-buttons:not(.inline):-moz-dir(ltr) { padding-right: 1.5rem; }
gaia-buttons:not(.inline):-moz-dir(rtl) { padding-left: 1.5rem; }
gaia-buttons.inline a,
gaia-buttons.inline button {
margin: 0;
}
button::-moz-focus-inner {
border: none;
outline: none;
}
a,
button {
position: relative;
font-family: sans-serif;
font-style: italic;
width: 100%;
height: 4rem;
margin: 0;
padding: 0 0.2rem;
box-sizing: border-box;
display: inline-block;
vertical-align: middle;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
background: #d8d8d8;
border: none;
border-radius: 2rem;
font-weight: normal;
font-size: 1.6rem;
line-height: 4rem;
color: #333;
text-align: center;
text-decoration: none;
outline: none;
}
:-moz-dir(ltr) a,
:-moz-dir(ltr) button {
margin-left: 1.5rem;
}
:-moz-dir(rtl) a,
:-moz-dir(rtl) button {
margin-right: 1.5rem;
}
/* Recommend */
a.recommend,
button.recommend {
background-color: #00caf2;
color: #fff;
}
/* Danger */
a.danger,
button.danger {
background-color: #e51e1e;
color: #fff;
}
/* Pressed */
a:active,
button:active {
background-color: #b2f2ff;
color: #fff;
}
a::-moz-selection,
button::-moz-selection {
background-color: transparent;
}
/* Disabled */
a[aria-disabled="true"],
button[disabled] {
background-color: rgba(0,0,0,0.05);
color: #c7c7c7;
pointer-events: auto;
}
a[aria-disabled="true"].recommend,
button[disabled].recommend {
background-color: #97cbd5;
color: rgba(255,255,255,0.5);
}
a[aria-disabled="true"].danger,
button[disabled].danger {
background-color: #eb7474;
color: rgba(255,255,255,0.5);
}
a[aria-disabled="true"]::-moz-selection,
button[disabled]::-moz-selection {
-moz-user-select: none;
}
/* Hidden */
[hidden] {
visibility: hidden;
}
/* Icons */
a.icon,
button.icon {
position: relative;
}
a.icon:before,
button.icon:before {
content: "";
width: 3rem;
height: 3rem;
position: absolute;
top: 50%;
margin-top: -1.5rem;
background: transparent no-repeat center center / 100% auto;
}
:-moz-dir(ltr) a.icon:before,
:-moz-dir(ltr) button.icon:before { right: 0.5rem; }
:-moz-dir(rtl) a.icon:before,
:-moz-dir(rtl) button.icon:before { left: 0.5rem; }
a.icon-next:before,
button.icon-next:before {
background-size: 3rem;
}
:-moz-dir(ltr) a.icon-next:before,
:-moz-dir(ltr) button.icon-next:before {
background-image: url(images/right-light.svg);
}
:-moz-dir(rtl) a.icon-next:before,
:-moz-dir(rtl) button.icon-next:before {
background-image: url(images/left-light.svg);
}
a.icon-previous:before,
button.icon-previous:before {
background-size: 3rem;
}
:-moz-dir(ltr) a.icon-previous:before,
:-moz-dir(ltr) button.icon-previous:before {
left: 0.5rem;
background-image: url(images/left-light.svg);
}
:-moz-dir(rtl) a.icon-previous:before,
:-moz-dir(rtl) button.icon-previous:before {
right: 0.5rem;
background-image: url(images/right-light.svg);
}
/* -----------------------------------------------------------------
SKIN: dark
----------------------------------------------------------------- */
gaia-buttons[skin="dark"] {
background: #4d4d4d;
border: none;
}
/* Pressed */
[skin="dark"] a:active,
[skin="dark"] button:active {
background-color: #00aacc;
}
/* Disabled */
[skin="dark"] a[aria-disabled="true"],
[skin="dark"] button[disabled] {
background-color: #565656;
color: rgba(255,255,255,0.4);
}
[skin="dark"] a[aria-disabled="true"].recommend,
[skin="dark"] button[disabled].recommend {
background-color: #006579;
}
[skin="dark"] a[aria-disabled="true"].danger,
[skin="dark"] button[disabled].danger {
background-color: #730f0f;
}
/* -----------------------------------------------------------------
Transitions
----------------------------------------------------------------- */
[transition] {
display: flex;
transition: visibility var(--transition-duration);
}
[transition][hidden] {
pointer-events: none;
}
[transition="slide"] {
transform: translateY(0);
transition: transform var(--transition-duration) ease,
visibility var(--transition-duration);
}
[transition="slide"][hidden] {
transform: translateY(100%);
}
[transition="fade"] {
opacity: 1;
transition: opacity var(--transition-duration) ease,
visibility var(--transition-duration);
}
[transition="fade"][hidden] {
opacity: 0;
}
/* -----------------------------------------------------------------
RESPONSIVE: tablet
----------------------------------------------------------------- */
@media (min-width: 768px) {
gaia-buttons {
height: 10rem;
}
gaia-buttons:not(.inline) {
border-top-width: 0.2rem;
}
/* this 'end' padding must match the buttons 'start' margin */
gaia-buttons:not(.inline):-moz-dir(ltr) { padding-right: 3rem; }
gaia-buttons:not(.inline):-moz-dir(rtl) { padding-left: 3rem; }
a,
button {
font-size: 2rem;
height: 5rem;
line-height: 5rem;
border-radius: 2.5rem;
max-width: 40rem;
}
:-moz-dir(ltr) a,
:-moz-dir(ltr) button {
margin-left: 3rem;
}
:-moz-dir(rtl) a,
:-moz-dir(rtl) button {
margin-right: 3rem;
}
}

View file

@ -0,0 +1,13 @@
'use strict';
var result = document.getElementById('result');
var elements = document.querySelectorAll('gaia-checkbox');
[].forEach.call(elements, function(element, index) {
element.addEventListener('click', function(e) {
result.textContent = 'Click event for: ' + (index + 1) + ' value: ' +
e.target.checked;
});
});

View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="utf-8" />
<title>GaiaCheckbox Demo</title>
<meta name="description" content="Demo app for gaia-checkbox" />
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
font-size: 10px;
background-color: #fff;
width: 100%;
}
section {
margin: 2rem;
border-bottom: 1px solid #000;
}
</style>
<script>
window.onload = function() {
var dirInput = document.getElementById('dir');
dirInput.checked = false;
dirInput.onchange= function() {
document.documentElement.dir = this.checked ? 'rtl' : 'ltr';
}
};
</script>
<script src="../../../js/component_utils.js"></script>
<script>window.GaiaCheckboxBaseurl = '../';</script>
<script src="../script.js"></script>
<script defer src="example.js"></script>
</head>
<body role="application">
<p dir="ltr">
<label class="bb-docs">
<input id="dir" type="checkbox"> RTL mode
</label>
</p>
<section>
<gaia-checkbox></gaia-checkbox>
</section>
<section>
<gaia-checkbox checked style="width: 100%;">
<label>With a label</label>
</gaia-checkbox>
</section>
<section>
<gaia-checkbox class="danger"></gaia-checkbox>
</section>
<section>
<gaia-checkbox class="danger" checked>
<label>Class = danger</label>
</gaia-checkbox>
</section>
<section>
<gaia-checkbox class="inline" checked>
<label>Class = inline</label>
</gaia-checkbox>
</section>
<div id="result"></div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,129 @@
'use strict';
/* global ComponentUtils */
window.GaiaCheckbox = (function(win) {
// Extend from the HTMLElement prototype
var proto = Object.create(HTMLElement.prototype);
// Allow baseurl to be overridden (used for demo page)
var baseurl = window.GaiaCheckboxBaseurl ||
'/shared/elements/gaia_checkbox/';
proto.createdCallback = function() {
// A timestamp of the last click on the checkbox.
// We use this to throttle click events to the control.
// This is a temporary workaround for bug 1221886.
this.lastClick = 0;
this.throttleTime = 250;
var shadow = this.createShadowRoot();
this._template = template.content.cloneNode(true);
this._wrapper = this._template.getElementById('checkbox');
this._wrapper.addEventListener('click', this.handleClick.bind(this));
this.configureClass();
this.checked = this.hasAttribute('checked');
this._wrapper.setAttribute('aria-checked', this.checked);
this.setAttribute('role', 'presentation');
shadow.appendChild(this._template);
ComponentUtils.style.call(this, baseurl);
};
/**
* Handles a click event on the shadow dom.
* We handle checking/unchecking of the checkbox and proxy the click
* event to any click listeners on the gaia-radio. This is a nice transition
* that preserves backwards behavior and should make it easier to port apps.
*/
proto.handleClick = function(e) {
// We add this event listener twice (see above) on both the content and
// custom element nodes. We need to stop the event propagation to prevent
// this event from firing against both nodes.
e.preventDefault();
e.stopImmediatePropagation();
// Workaround for bug 1221886 - throttle clicks if needed.
if (this.lastClick + this.throttleTime > Date.now()) {
return;
}
this.lastClick = Date.now();
// Dispatch a click event to any listeners to the app.
// We should be able to remove this when bug 887541 lands.
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
this.dispatchEvent(event);
if (!event.defaultPrevented) {
this.checked = !this.checked;
this._wrapper.setAttribute('aria-checked', this.checked);
}
// Dispatch a change event for the gaia-switch.
this.dispatchEvent(new CustomEvent('change', {
bubbles: true,
cancelable: false
}));
};
/**
* Configures the class for the element.
*/
proto.configureClass = function() {
this._wrapper.className = this.className;
};
/**
* Proxy className property to the wrapper.
*/
proto.attributeChangedCallback = function(name, from, to) {
if (name === 'class') {
this._wrapper.className = to;
}
};
/**
* Proxy the checked property to the input element.
*/
Object.defineProperty(proto, 'checked', {
get: function() {
return this._checked || false;
},
set: function(value) {
this._wrapper.classList.toggle('checked', value);
this._checked = value;
}
});
/**
* Proxy the name property to the input element.
*/
Object.defineProperty(proto, 'name', {
get: function() {
return this.getAttribute('name');
},
set: function(value) {
this.setAttribute('name', value);
}
});
var template = document.createElement('template');
template.innerHTML =
`<span id="checkbox" role="checkbox">
<span role="presentation"><content select="label"></content></span>
</span>`;
// Register and return the constructor
return document.registerElement('gaia-checkbox', { prototype: proto });
})(window);

View file

@ -0,0 +1,71 @@
gaia-checkbox {
display: inline-block;
width: 100%;
}
#checkbox {
display: block;
width: 100%;
/* Normal gaia-checkboxes are the heights of their parents. */
height: 100%;
position: relative;
background: none;
}
#checkbox span {
font-size: 1.9rem;
font-weight: normal;
color: var(--label-color);
line-height: 3rem;
box-sizing: border-box;
display: block;
min-width: 2.2rem;
min-height: 2.2rem;
width: 100%;
padding-inline-end: 2.2rem;
/* Override inheriting nowrap from legacy lists building blocks. */
white-space: normal;
}
/* Inline gaia-checkboxes are the heights of their parents. */
#checkbox.inline {
display: inline-block;
vertical-align: middle;
}
#checkbox:not(.invisible) span:after {
content: '';
position: absolute;
offset-inline-end: 0;
top: 50%;
margin: -1.2rem 0 0;
margin-inline-start: -1.2rem;
width: 2.2rem;
height: 2.2rem;
}
#checkbox.inline span {
padding-inline-start: 3rem;
padding-inline-end: 0;
height: auto;
}
#checkbox.inline span:after {
offset-inline-start: 1.2rem;
offset-inline-end: unset;
margin: -1.2rem 0 0;
margin-inline-start: -1.2rem;
}
#checkbox:not(.invisible) span:after {
background: url(images/default.png) no-repeat center top / 2.2rem auto;
}
#checkbox.checked span:after {
background-position: center bottom;
}
/* 'Dangerous' checkboxes */
#checkbox.danger span:after {
background-image: url(images/danger.png);
}

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html dir="ltr" >
<head>
<meta charset="utf-8" />
<title>GaiaConfirm Demo</title>
<meta name="description" content="Demo app for gaia-confirm" />
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
font-size: 10px;
}
</style>
<script>window.GaiaConfirmBaseurl = '../';</script>
<script>window.GaiaButtonsBaseurl = '../../gaia_buttons/';</script>
<script src="../../../js/component_utils.js"></script>
<script src="../../gaia_buttons/script.js"></script>
<script src="../script.js"></script>
<script>
document.documentElement.addEventListener("keypress", function(e) {
var dir = document.documentElement.dir;
document.documentElement.dir = dir == "ltr" ? "rtl" : "ltr";
});
</script>
</head>
<body role="application">
<gaia-confirm>
<h1>You are about to do a thing. Are you sure you want to do this thing?</h1>
<p>Some additional description here.</p>
<gaia-buttons skin="dark">
<button class="cancel">Cancel</button>
<button class="confirm recommend">Submit</button>
</gaia-buttons>
</gaia-confirm>
<script type="text/javascript" charset="utf-8">
/**
In addition to showing a nice confirm dialog we have some additional events which
are emitted on the dialog itself (but not bubbled!) they require the use of
the special .cancel and .confirm class names on the buttons inside the confirm.
*/
var confirm = document.querySelector('gaia-confirm');
confirm.addEventListener('confirm', function() {
console.log('confirm was pressed');
});
confirm.addEventListener('cancel', function() {
console.log('cancel was pressed');
});
</script>
</body>
</html>

View file

@ -0,0 +1,72 @@
'use strict';
/* global ComponentUtils */
/**
* The gaia-confirm component displays a dialog in which the user has a
* choice to confirm or cancel the action. It may be displayed along with a
* title, description, and image. Buttons may also be configured.
* @requires GaiaButtons
*/
window.GaiaConfirm = (function(win) {
// Extend from the HTMLElement prototype
var proto = Object.create(HTMLElement.prototype);
// Allow baseurl to be overridden (used for demo page)
var baseurl = window.GaiaConfirmBaseurl ||
'/shared/elements/gaia_confirm/';
/**
preventDefault and prevent other listeners from hearing abut changes to a
particular event object.
@param {Array[Element]|Null} unless a list of elements to allow events to hit.
@param {Event} event triggered by addEventListener, etc...
*/
function eatEvent(unless, event) {
// prevent handlers from everything else unless the target is on the list.
if (unless && unless.indexOf(event.target) !== -1) {
return;
}
event.preventDefault();
event.stopImmediatePropagation();
}
proto.createdCallback = function() {
var shadow = this.createShadowRoot();
this._template = template.content.cloneNode(true);
shadow.appendChild(this._template);
ComponentUtils.style.call(this, baseurl);
var confirm = this.querySelector('gaia-buttons .confirm');
var cancel = this.querySelector('gaia-buttons .cancel');
if (confirm) {
confirm.addEventListener('click', (e) => {
eatEvent(null, e);
this.dispatchEvent(new CustomEvent('confirm'));
});
}
if (cancel) {
cancel.addEventListener('click', (e) => {
eatEvent(null, e);
this.dispatchEvent(new CustomEvent('cancel'));
});
}
};
var template = document.createElement('template');
template.innerHTML = `<form role="dialog" class="confirm">
<section>
<content select="h1"></content>
<content select="p"></content>
</section>
<content select="gaia-buttons">
</content>
</form>`;
// Register and return the constructor
return document.registerElement('gaia-confirm', { prototype: proto });
})(window);

View file

@ -0,0 +1,155 @@
/* ----------------------------------
* Confirm
* ---------------------------------- */
/* Main dialog setup */
gaia-confirm {
background: #2d2d2d;
overflow: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding-bottom: 7rem;
font-size: 0;
text-align: start;
/* Using font-size: 0; we avoid the unwanted visual space (about 3px)
created by white-spaces and break lines in the code betewen inline-block elements */
color: #fff;
display: flex;
align-items: stretch;
flex-direction: column;
justify-content: center;
transition: transform ease-in-out 0.3s, visibility 0.3s;
/**
magic number ideally to place confirm dialogs on top.
*/
z-index: 2147483646;
}
gaia-confirm[hidden] {
transform: translateY(100%);
visibility: hidden;
pointer-events: none;
}
.confirm section {
height: 100%;
font-weight: 300;
font-size: 2.2rem;
color: #FAFAFA;
padding: 0 1.5rem;
box-sizing: padding-box;
width: 100%;
display: inline-block;
max-height: 100%;
vertical-align: middle;
white-space: normal;
}
h1 {
font-weight: normal;
font-size: 1.6rem;
line-height: 1.5em;
color: #fff;
margin: 0;
padding: 1rem 1.5rem 0;
overflow: hidden;
max-height: 7rem;
word-wrap: break-word;
}
/* Specific component code */
p {
word-wrap: break-word;
margin: 1rem 0 0;
padding: 1rem 1.5rem;
border-top: 0.1rem solid #686868;
line-height: 3rem;
}
p img {
margin-inline-end: 2rem;
}
p img:-moz-dir(ltr) { float: left; }
p img:-moz-dir(rtl) { float: right; }
p strong {
font-weight: 300;
}
p small {
font-size: 1.4rem;
font-weight: normal;
color: #cbcbcb;
display: block;
}
dl {
border-top: 0.1rem solid #686868;
margin: 1rem 0 0;
overflow: hidden;
padding-top: 1rem;
font-size: 1.6rem;
line-height: 2.2rem;
}
dl > dt {
clear: both;
width: 7rem;
padding-inline-start: 1.5rem;
font-weight: 500;
text-align: start;
}
dl > dt:-moz-dir(ltr) { float: left; }
dl > dt:-moz-dir(rtl) { float: right; }
dl > dd {
padding-inline-end: 1.5rem;
font-weight: 300;
text-overflow: ellipsis;
vertical-align: top;
overflow: hidden;
}
figure {
margin: 1.5rem;
display: flex;
align-items: center;
}
figure img {
padding-inline-end: 1.5rem;
flex-shrink: 0;
}
figure figcaption {
font-size: 2.1rem;
font-weight: 300;
}
ul {
margin: 0;
padding: 2rem 1.5rem;
border-top: 0.1rem solid #686868;
list-style: none;
font-size: 1.6rem;
font-weight: normal;
}
ul li {
word-wrap: break-word;
line-height: 2rem;
padding-bottom: 1.5rem;
}
ul li:last-child {
padding-bottom: 0;
}
ul li ul {
border: none;
margin: 0;
padding: 0;
}

View file

@ -0,0 +1,118 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>GaiaDrawer Demo</title>
<meta name="description" content="Demo app for gaia-drawer" />
<style type="text/css">
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
font-size: 10px;
background-color: #fff;
}
body {
font: 16px sans-serif;
}
div {
display: flex;
flex-direction: column;
position: relative;
float: left;
height: 400px;
border: solid 1px #eee;
overflow: hidden;
}
.half {
width: 50%;
}
.third {
width: 33.33%;
}
gaia-drawer {
flex: 1;
}
</style>
<!-- Demo Dependencies -->
<link rel="stylesheet" type="text/css" href="../../../style/lists.css">
<script>window.GaiaHeaderBaseurl = '../../gaia_header/';</script>
<script src="../../gaia_header/script.js"></script>
<!-- Component -->
<script src="../../../js/component_utils.js"></script>
<script>window.GaiaDrawerBaseurl = '../';</script>
<script src="../script.js"></script>
</head>
<body role="application">
<div class="slot third">
<gaia-header action="menu"><h1>Title</h1></gaia-header>
<gaia-drawer open>
<section data-type="list">
<ul>
<li><p>List Item 1</p></li>
<li><p>List Item 2</p></li>
<li><p>List Item 3</p></li>
</ul>
</section>
</gaia-drawer>
</div>
<div class="slot third">
<gaia-header action="menu"><h1>Title</h1></gaia-header>
<gaia-drawer>
<section data-type="list">
<ul>
<li><p>List Item 1</p></li>
<li><p>List Item 2</p></li>
<li><p>List Item 3</p></li>
</ul>
</section>
</gaia-drawer>
</div>
<div class="slot third">
<gaia-header action="menu"><h1>Title</h1></gaia-header>
<gaia-drawer>
<section data-type="list">
<ul>
<li><p>List Item 1</p></li>
<li><p>List Item 2</p></li>
<li><p>List Item 3</p></li>
<li><p>List Item 1</p></li>
<li><p>List Item 2</p></li>
<li><p>List Item 3</p></li>
<li><p>List Item 1</p></li>
<li><p>List Item 2</p></li>
<li><p>List Item 3</p></li>
</ul>
</section>
</gaia-drawer>
</div>
<div class="half"></div>
<div class="half"></div>
<script>
[].forEach.call(document.querySelectorAll('.slot'), function(slot) {
var header = slot.querySelector('gaia-header');
var drawer = slot.querySelector('gaia-drawer');
header.addEventListener('action', function() {
drawer.toggle();
});
});
window.addEventListener('WebComponentsReady', function() {
console.log('WebComponentsReady');
});
</script>
</body>
</html>

View file

@ -0,0 +1,138 @@
window.GaiaDrawer = (function(win) {
/*global ComponentUtils*/
/*jshint maxlen:false*/
'use strict';
// Extend from the HTMLElement prototype
var proto = Object.create(HTMLElement.prototype);
// Allow baseurl to be overridden (used for demo page)
var baseurl = window.GaiaDrawerBaseurl ||
'/shared/elements/gaia_drawer/';
/**
* Runs when an instance of the
* element is first created.
*
* When use this moment to create the
* shadow-dom, inject our template
* content, setup event listeners
* and set the draw state to match
* the initial `open` attribute.
*
* @private
*/
proto.createdCallback = function() {
var shadow = this.createShadowRoot();
this._template = template.content.cloneNode(true);
// Fetch some els
this._els = {};
this._els.background = this._template.getElementById('background');
this._els.content = this._template.getElementById('content');
this._els.inner = this._template.getElementById('inner');
this._attachEvents();
this.toggle(this.hasAttribute('open'));
// Put content in the shadow-dom
shadow.appendChild(this._template);
ComponentUtils.style.call(this, baseurl);
};
/**
* Runs when any attribute changes
* on the element.
*
* We only support the `open` attribute,
* so we ignore all others. We then toggle,
* opening the drawer for all values other
* than `null` (which means the attribute
* was removed).
*
* @param {String} attr
* @param {String|null} oldVal
* @param {String|null} newVal
* @private
*/
proto.attributeChangedCallback = function(attr, oldVal, newVal) {
if (attr !== 'open') { return; }
this.toggle(newVal !== null);
};
proto._attachEvents = function() {
this._els.background.addEventListener('click', this.close.bind(this));
this._els.content.addEventListener('click', function(e) {
e.stopPropagation();
});
};
/**
* Toggle the drawer open/closed.
*
* If a value is passed, we ignore the
* current `open` value and just derive
* the state from the value given (similar
* to how `classList.toggle` works).
*
* @param {Boolean} value
* @public
*/
proto.toggle = function(value) {
value = arguments.length ? value : !this.hasAttribute('open');
if (value) { this.open(); }
else { this.close(); }
};
/**
* Open the drawer.
*
* We have to also duplicate the
* attribute on the `.inner` element
* inside the shadow-root as we are
* currently missing the `:host`
* selector from the platform.
*
* @public
*/
proto.open = function() {
this.setAttribute('open', '');
this._els.inner.setAttribute('open', '');
};
/**
* Close the drawer.
*
* We have to also duplicate the
* attribute on the `.inner` element
* inside the shadow-root as we are
* currently missing the `:host`
* selector from the platform.
*
* @public
*/
proto.close = function() {
this.removeAttribute('open');
this._els.inner.removeAttribute('open');
};
// HACK: Create a <template> in memory at runtime.
// When the custom-element is created we clone
// this template and inject into the shadow-root.
// Prior to this we would have had to copy/paste
// the template into the <head> of every app that
// wanted to use <gaia-switch>, this would make
// markup changes complicated, and could lead to
// things getting out of sync. This is a short-term
// hack until we can import entire custom-elements
// using HTML Imports (bug 877072).
// var stylesheet = baseurl + 'style.css';
var template = document.createElement('template');
template.innerHTML = `<div class="inner" id="inner">
<div class="background" id="background"></div>
<div class="content" id="content"><content></content></div>
</div>`;
// Register and return the constructor
return document.registerElement('gaia-drawer', { prototype: proto });
})(window);

View file

@ -0,0 +1,69 @@
/** Gaia Drawer
---------------------------------------------------------*/
gaia-drawer {
display: block;
position: relative;
overflow: hidden;
}
/** Inner
---------------------------------------------------------*/
.inner {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%
}
/** Content
---------------------------------------------------------*/
.content {
position: relative;
min-height: calc(100% - 200px);
max-height: calc(100% - 95px);
overflow: auto;
color: #5F5F5F;
background-color: #F4F4F4;
transform: translateY(-100%);
transition: transform 300ms ease, visibility 300ms;
will-change: transform;
visibility: hidden;
}
/**
* open
*/
[open] .content {
transform: translateY(0);
visibility: visible;
}
/** Background
---------------------------------------------------------*/
.background {
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.6);
transition: opacity 240ms ease;
will-change: opacity;
opacity: 0;
}
/**
* open
*/
[open] .background {
opacity: 1;
}

View file

@ -0,0 +1,65 @@
'use strict';
/* global GaiaGrid */
var grid = document.getElementById('grid');
var icon = 'mozilla.png';
var whitePixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///' +
'wAAACwAAAAAAQABAAACAkQBADs=';
var items = [
new GaiaGrid.Bookmark({
id: 1,
name: 'Mozilla',
icon: icon,
url: 'http://mozilla.org'
}),
new GaiaGrid.Bookmark({
id: 2,
name: 'Two',
icon: icon,
url: 'http://2'
}),
new GaiaGrid.Bookmark({
id: 3,
name: 'Three',
icon: icon,
url: 'http://3'
}),
new GaiaGrid.Bookmark({
id: 4,
name: 'Four',
icon: icon,
url: 'http://4'
}),
new GaiaGrid.Mozapp({
id: 5,
icon: icon,
manifest: {
name: 'A Webapp',
icons: {
64: whitePixel
}
}
}),
new GaiaGrid.Divider(),
new GaiaGrid.Mozapp({
id: 6,
manifestURL: 'app://xfoobar',
manifest: {
name: 'Another Webapp',
icons: {
64: whitePixel
}
}
}),
];
items.forEach(grid.add.bind(grid));
grid.render();
document.getElementById('clear').addEventListener('click', function() {
grid.clear();
});

View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>GaiaGrid Demo</title>
<meta name="description" content="Demo app for gaia-grid" />
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
font-size: 10px;
background-color: #48036f;
font-family: Verdana, sans-serif;
width: 600px;
}
gaia-grid {
display: block;
height: 100%;
width: 100%;
}
</style>
<script>window.GaiaConfirmBaseurl = '../';</script>
<script>window.GaiaButtonsBaseurl = '../../gaia_buttons/';</script>
<script src="../../../js/component_utils.js"></script>
<script src="../../gaia_buttons/script.js"></script>
<script src="../../gaia_confirm/script.js"></script>
<script>window.GaiaGridBaseurl = '../';</script>
<script src="../../../js/url_helper.js"></script>
<script src="../../../js/l10n.js"></script>
<script src="../script.js"></script>
<script src="../js/grid_icon_renderer.js"></script>
<script src="../js/dialog.js"></script>
<script src="../js/grid_view.js"></script>
<script src="../js/grid_icon_renderer.js"></script>
<script src="../js/items/grid_item.js"></script>
<script src="../js/items/placeholder.js"></script>
<script src="../js/items/bookmark.js"></script>
<script src="../js/items/divider.js"></script>
<script src="../js/items/mozapp.js"></script>
<script src="../js/grid_layout.js"></script>
<script src="../js/grid_dragdrop.js"></script>
<script src="../js/grid_zoom.js"></script>
</head>
<body role="application">
<button id="clear">Clear Grid</button>
<gaia-grid id="grid" dragdrop></gaia-grid>
<script defer src="example.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Some files were not shown because too many files have changed in this diff Show more