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.
13
gaia/shared/elements/gaia_radio/examples/example.js
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
var result = document.getElementById('result');
|
||||
|
||||
var elements = document.querySelectorAll('gaia-radio');
|
||||
|
||||
[].forEach.call(elements, function(radio, index) {
|
||||
radio.addEventListener('click', function(e) {
|
||||
result.textContent = 'Click event for: ' + (index + 1) + ' value: ' +
|
||||
e.target.checked;
|
||||
});
|
||||
|
||||
});
|
||||
94
gaia/shared/elements/gaia_radio/examples/index.html
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>GaiaRadio Demo</title>
|
||||
<meta name="description" content="Demo app for gaia-radio" />
|
||||
<style type="text/css">
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 10px;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
}
|
||||
html[dir="ltr"] header[dir] { text-align: left; }
|
||||
html[dir="rtl"] header[dir] { text-align: right; }
|
||||
</style>
|
||||
<script src="../../../js/component_utils.js"></script>
|
||||
<script>window.GaiaRadioBaseurl = '../';</script>
|
||||
<script src="../script.js"></script>
|
||||
<script defer src="example.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
document.getElementById('dir').checked = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- List styling -->
|
||||
<link href="../../../style/lists.css" rel="stylesheet">
|
||||
</head>
|
||||
<body role="application">
|
||||
<p dir="ltr">
|
||||
<label>
|
||||
<input id="dir" type="checkbox"
|
||||
onchange="document.documentElement.dir = this.checked ? 'rtl' : 'ltr'">
|
||||
RTL mode
|
||||
</label>
|
||||
</p>
|
||||
<section data-type="list">
|
||||
<header dir="auto">With class="inline":</header>
|
||||
<ul>
|
||||
<li>
|
||||
<gaia-radio name="first" class="inline"></gaia-radio>
|
||||
<gaia-radio name="first" checked class="inline"></gaia-radio>
|
||||
</li>
|
||||
<li>
|
||||
<gaia-radio name="second" class="danger inline"></gaia-radio>
|
||||
<gaia-radio name="second" checked class="danger inline"></gaia-radio>
|
||||
</li>
|
||||
</ul>
|
||||
<header dir="auto">With an inner label:</header>
|
||||
<ul role="menu">
|
||||
<li role="presentation">
|
||||
<gaia-radio name="third" checked>
|
||||
<label>Here is the first option</label>
|
||||
</gaia-radio>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<gaia-radio name="third">
|
||||
<label>Here is the second option</label>
|
||||
</gaia-radio>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<gaia-radio name="third" class="truncate">
|
||||
<p>Here is a truncated option. Here is a truncated option. Here is a truncated option. Here is a truncated option. Here is a truncated option.</p>
|
||||
</gaia-radio>
|
||||
</li>
|
||||
</ul>
|
||||
<header dir="auto">With class="checkone":</header>
|
||||
<ul role="menu">
|
||||
<li role="presentation">
|
||||
<gaia-radio name="fourth" class="checkone" checked>
|
||||
<label>Here is the first option</label>
|
||||
</gaia-radio>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<gaia-radio name="fourth" class="checkone">
|
||||
<label>Here is the second option</label>
|
||||
</gaia-radio>
|
||||
</li>
|
||||
</ul>
|
||||
<header dir="auto">With class="split"</header>
|
||||
<ul role="menu">
|
||||
<li role="presentation">
|
||||
<gaia-radio name="fourth" class="split" checked>
|
||||
<label class="split">A split label.</label>
|
||||
</gaia-radio>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<div id="result"></div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
gaia/shared/elements/gaia_radio/images/checked.png
Executable file
|
After Width: | Height: | Size: 292 B |
BIN
gaia/shared/elements/gaia_radio/images/checked@1.5x.png
Executable file
|
After Width: | Height: | Size: 397 B |
BIN
gaia/shared/elements/gaia_radio/images/checked@2.25x.png
Executable file
|
After Width: | Height: | Size: 522 B |
BIN
gaia/shared/elements/gaia_radio/images/checked@2x.png
Executable file
|
After Width: | Height: | Size: 650 B |
BIN
gaia/shared/elements/gaia_radio/images/danger.png
Executable file
|
After Width: | Height: | Size: 578 B |
BIN
gaia/shared/elements/gaia_radio/images/danger@1.5x.png
Executable file
|
After Width: | Height: | Size: 893 B |
BIN
gaia/shared/elements/gaia_radio/images/danger@2.25x.png
Executable file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
gaia/shared/elements/gaia_radio/images/danger@2x.png
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
gaia/shared/elements/gaia_radio/images/default.png
Executable file
|
After Width: | Height: | Size: 575 B |
BIN
gaia/shared/elements/gaia_radio/images/default@1.5x.png
Executable file
|
After Width: | Height: | Size: 889 B |
BIN
gaia/shared/elements/gaia_radio/images/default@2.25x.png
Executable file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
gaia/shared/elements/gaia_radio/images/default@2x.png
Executable file
|
After Width: | Height: | Size: 1.2 KiB |
205
gaia/shared/elements/gaia_radio/script.js
Executable file
|
|
@ -0,0 +1,205 @@
|
|||
'use strict';
|
||||
/* global ComponentUtils */
|
||||
|
||||
window.GaiaRadio = (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.GaiaRadioBaseurl ||
|
||||
'/shared/elements/gaia_radio/';
|
||||
|
||||
proto.createdCallback = function() {
|
||||
var shadow = this.createShadowRoot();
|
||||
this._template = template.content.cloneNode(true);
|
||||
|
||||
this._wrapper = this._template.getElementById('radio');
|
||||
this._wrapper.addEventListener('click', this.handleClick.bind(this));
|
||||
|
||||
// The default 'radio' accessibility role could be overridden.
|
||||
if (this.dataset.role) {
|
||||
this._wrapper.setAttribute('role', this.dataset.role);
|
||||
}
|
||||
|
||||
if (!this.hasAttribute('role')) {
|
||||
// The root element has no accessibility use, purge it from the tree.
|
||||
this.setAttribute('role', 'presentation');
|
||||
}
|
||||
|
||||
this.configureClass();
|
||||
|
||||
shadow.appendChild(this._template);
|
||||
|
||||
this.checked = this.hasAttribute('checked');
|
||||
this._wrapper.setAttribute('aria-checked', this.checked);
|
||||
|
||||
// When events are triggered on content nodes, they do not bubble to
|
||||
// our custom element. We add an event listener on our children so we can
|
||||
// intercept the click and, process the state change, and notify listeners.
|
||||
// Platform bug 887541.
|
||||
setTimeout(function nextTick() {
|
||||
var label = this.querySelector('label, p');
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
label.addEventListener('click', this.handleClick.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
ComponentUtils.style.call(this, baseurl);
|
||||
|
||||
// Proxy RTL changes to the shadow root so we can style for RTL.
|
||||
var dirObserver = new MutationObserver(this.updateInternalDir.bind(this));
|
||||
dirObserver.observe(document.documentElement, {
|
||||
attributeFilter: ['dir'],
|
||||
attributes: true
|
||||
});
|
||||
this.updateInternalDir();
|
||||
};
|
||||
|
||||
proto.updateInternalDir = function() {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
if (document.documentElement.dir === 'rtl') {
|
||||
internal.setAttribute('dir', 'rtl');
|
||||
} else {
|
||||
internal.removeAttribute('dir');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a click event on the shadow dom.
|
||||
* We handle checking/unchecking of radio elements 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.stopImmediatePropagation();
|
||||
|
||||
// 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 this radio component is already checked, don't do anything.
|
||||
if (this.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event.defaultPrevented) {
|
||||
this.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;
|
||||
this._wrapper.classList.toggle('checked', this._checked);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method to remove the component details.
|
||||
*/
|
||||
proto.hideDetails = function() {
|
||||
this.shadowRoot.querySelector('.details').style.display = 'none';
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy className property to the wrapper.
|
||||
*/
|
||||
proto.attributeChangedCallback = function(name, from, to) {
|
||||
if (name === 'class') {
|
||||
this._wrapper.className = to;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle setting/getting of the checked property.
|
||||
*/
|
||||
Object.defineProperty(proto, 'checked', {
|
||||
get: function() {
|
||||
return this._checked;
|
||||
},
|
||||
set: function(value) {
|
||||
// Return early if we have not initialized.
|
||||
// In some cases a radio of the same name might try to toggle this one
|
||||
// before we've run the createdCallback.
|
||||
if (!this._template) {
|
||||
return;
|
||||
}
|
||||
if (value) {
|
||||
// Uncheck other radio elements with the same name and check this one.
|
||||
var relevant = document.querySelectorAll(
|
||||
'gaia-radio[name="' + this.getAttribute('name') + '"]');
|
||||
for (var i = 0, iLen = relevant.length; i < iLen; i++) {
|
||||
relevant[i].checked = false;
|
||||
}
|
||||
this.setAttribute('checked', true);
|
||||
} else {
|
||||
this.removeAttribute('checked');
|
||||
}
|
||||
this._wrapper.classList.toggle('checked', value);
|
||||
this._wrapper.setAttribute('aria-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);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Proxy the value property to the input element.
|
||||
*/
|
||||
Object.defineProperty( proto, 'value', {
|
||||
get: function() {
|
||||
return this.getAttribute('value');
|
||||
},
|
||||
set: function(value) {
|
||||
this.setAttribute('value', value);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Proxy the input type.
|
||||
*/
|
||||
Object.defineProperty( proto, 'type', {
|
||||
get: function() {
|
||||
return 'gaia-radio';
|
||||
}
|
||||
});
|
||||
|
||||
// Handle both p and label elements for now to support existing
|
||||
// building blocks. Mainly radio labels and inputs inside a list
|
||||
// as this is a rather common use case.
|
||||
var template = document.createElement('template');
|
||||
template.innerHTML = '<span role="radio" id="radio">' +
|
||||
'<span><content select="p,label"></content></span>' +
|
||||
'<div class="details"><content select="details"></content></div>' +
|
||||
'<div class="divider"></div>' +
|
||||
'</span>';
|
||||
|
||||
// Register and return the constructor
|
||||
return document.registerElement('gaia-radio', { prototype: proto });
|
||||
})(window);
|
||||
107
gaia/shared/elements/gaia_radio/style.css
Executable file
|
|
@ -0,0 +1,107 @@
|
|||
gaia-radio {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#radio {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background: none;
|
||||
}
|
||||
|
||||
gaia-radio.inline,
|
||||
#radio.inline {
|
||||
width: 5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#radio span {
|
||||
font-size: 1.9rem;
|
||||
color: var(--label-color);
|
||||
padding: 1rem 0;
|
||||
padding-inline-end: 2.4rem;
|
||||
line-height: 3rem;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
/* Override inheriting nowrap from legacy lists building blocks. */
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Users may choose to truncate text instead of it wrapping by adding the "truncate" className */
|
||||
#radio.truncate span {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#radio span:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
offset-inline-end: 0;
|
||||
top: 50%;
|
||||
margin: -1.1rem 0 0;
|
||||
margin-inline-start: -1.1rem;
|
||||
width: 2.2rem;
|
||||
height: 2.2rem;
|
||||
background: url(images/default.png) no-repeat center top / 2.2rem auto;
|
||||
}
|
||||
|
||||
#radio.checked span:after {
|
||||
background-position: center bottom;
|
||||
}
|
||||
|
||||
/* 'Dangerous' radio */
|
||||
#radio.danger span:after {
|
||||
background-image: url(images/danger.png);
|
||||
}
|
||||
|
||||
/* 'checkone' radio */
|
||||
#radio.checkone span:after {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#radio.checkone.checked span:after {
|
||||
background: url(images/checked.png) no-repeat right center / 100%;
|
||||
}
|
||||
|
||||
#radio.checkone.checked span {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 'split' radio label */
|
||||
#radio.split .divider {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: #E6E6E3;
|
||||
offset-inline-end: 3.5rem;
|
||||
width: 0.1rem;
|
||||
height: calc(100% - 1rem);
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
gaia-radio.split label {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* A <details> slot may be specified in addition the the <label>.
|
||||
* When provided, it appears under the <label> and can provide additional context.
|
||||
*/
|
||||
#radio div.details {
|
||||
position: relative;
|
||||
top: -1.5rem;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding-top: 0.5rem;
|
||||
-moz-padding-start: 0;
|
||||
-moz-padding-end: 8rem;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.6rem;
|
||||
color: #505859;
|
||||
font-style: normal;
|
||||
white-space: normal;
|
||||
}
|
||||