2017-07-01 17:36:52 -07:00

270 lines
9.0 KiB
HTML

---
layout: page
title: "Components"
description: "List of the built-in components of Home Assistant."
date: 2014-12-21 13:35
sidebar: false
comments: false
sharing: true
footer: true
is_homepage: true
hide_github_edit: true
body_id: components-page
regenerate: false
---
{% assign count = site.components | size %}
{% assign nocat = site.components | where: 'ha_category', null | size %}
{% assign tot = count | minus: nocat %}
{% assign components = site.components | sort: 'title' %}
{% assign categories = components | sort: 'ha_category' | map: 'ha_category' | uniq %}
{% capture current_version %}{{ site.current_major_version }}.{{ site.current_minor_version }}{% endcapture %}
{% assign added_one_ago_minor_version = site.current_minor_version|minus: 1 %}
{% capture added_one_ago_version %}{{ site.current_major_version }}.{{ added_one_ago_minor_version }}{% endcapture %}
{% assign added_two_ago_minor_version = site.current_minor_version|minus: 2 %}
{% capture added_two_ago_version %}{{ site.current_major_version }}.{{ added_two_ago_minor_version }}{% endcapture %}
{% assign current_version_components_count = site.components | where: 'ha_release', current_version | size %}
{% assign one_ago_version_components_count = site.components | where: 'ha_release', added_one_ago_version | size %}
{% assign two_ago_version_components_count = site.components | where: 'ha_release', added_two_ago_version | size %}
<p class='note'>
Support for these components is provided by the Home Assistant community.
</p>
<div class="grid">
<div class="grid__item one-sixth lap-one-whole palm-one-whole">
<div class="filter-button-group">
<a href='#all' class="btn">All ({{tot}})</a>
<a href='#featured' class="btn featured">Featured</a>
<a href='#version/{{ current_version }}' class="btn added_in_current_version">Added in {{ current_version }} ({{ current_version_components_count }})</a>
<a href='#version/{{ added_one_ago_version }}' class="btn added_one_version_ago">Added in {{ added_one_ago_version }} ({{ one_ago_version_components_count }})</a>
<a href='#version/{{ added_two_ago_version }}' class="btn added_two_versions_ago">Added in {{ added_two_ago_version }} ({{ two_ago_version_components_count }})</a>
{% for category in categories %}
{% if category and category != 'Other' %}
<a href='#{{ category | slugify }}' class="btn">{{ category }} ({{ components | where: 'ha_category', category | size }})</a>
{% endif %}
{% endfor %}
<a href='#other' class="btn">Other</a>
</div>
</div>
<div class="grid__item five-sixths lap-one-whole palm-one-whole">
<div class="component-search">
<form onsubmit="event.preventDefault(); return false">
<input type="text" name="search" id="search" class="search" placeholder="Search components...">
</form>
</div>
<div class="hass-option-cards" id="componentContainer"> </div>
</div>
</div>
{% comment %}
## Pages without categories
{% for component in components %}
{% unless component.ha_category %}
<p>{{ component.title }}</p>
{% endunless %}
{% endfor %}
{% endcomment %}
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
{% raw %}
<script id="component-template" type="text/x-custom-template">
{{#components}}
<a href="{{url}}" class="option-card">
<div class="img-container">{{{image}}}</div>
<div class='title'>{{title}}</div>
<div class='category'>{{cat}}</div>
</a>
{{/components}}
{{^components}}
<p class='note'>Nothing found!</p>
{{/components}}
</script>
{% endraw %}
<script type="text/javascript">
// This object contains all components we have
var allComponents = [
{% for component in components %}
{% if component.ha_category %}
{% assign sliced_version = component.ha_release | split: '.' %}
{% assign minor_version = sliced_version[1]|plus: 0 %}
{% assign major_version = sliced_version[0]|plus: 0 %}
{url:"{{ component.url }}", title:"{{component.title}}", cat:"{{component.ha_category | slugify}}", featured: {% if component.featured %}true{% else %}false{% endif %}, v: "{{major_version}}.{{minor_version}}", logo: "{{component.logo}}"},
{% endif %}
{% endfor %}
false
];
allComponents.pop(); // remove placeholder element at the end
</script>
<script type="text/javascript">
(function(){
var template = $('#component-template').html();
Mustache.parse(template); // make future calls to render faster
function init() {
// do the lowerCase transformation once
for (i=0; i < (allComponents.length); i++) {
allComponents[i].titleLC = allComponents[i].title.toLowerCase();
allComponents[i].catLC = allComponents[i].cat.toLowerCase();
}
// sort the components alphabetically
allComponents.sort(function(a, b){
return a.titleLC.localeCompare(b.titleLC);
});
if (location.hash !== '' && location.hash.indexOf('#search/') === 0) {
// set default value in search from URL
jQuery('.component-search input').val(decodeURIComponent(location.hash).substring(8));
}
// add focus to the search field - even on IE
setTimeout(function () {
jQuery('.component-search input').focus();
}, 1);
}
init();
/**
* filter all components, based on the location's hash and render them into the component box
*/
function applyFilter() {
var rendered, i, filter, search;
var hash = location.hash || '';
var data = {
components: [],
image: function () {
if(this.logo === '') {
return '';
} else {
return '<img src="/images/supported_brands/' + this.logo + '">';
}
}
};
// fade-out css effect on the old elements. This is actually not visible on fast browsers
$('#componentContainer').addClass('remove-items');
if (hash.indexOf('#search/') === -1) {
// reset search box when not searching
jQuery('.component-search input').val(null);
}
if (hash === '#all') {
// shortcut: no need to filter
data.components = allComponents;
} else {
if (hash.indexOf('#search/') === 0) {
// search through title and category
search = decodeURIComponent(hash).substring(8).toLowerCase();
filter = function(comp) {
return (comp.titleLC.indexOf(search) !== -1) ||
(comp.catLC.indexOf(search) !== -1);
};
} else if(hash === '#featured' || hash === '') {
// only show those with featured = true
filter = function(comp) {
return comp.featured;
};
} else if(hash.indexOf('#version/') === 0) {
// compare against a version
search = decodeURIComponent(hash).substring(9).toLowerCase();
filter = function(comp) {
// compare version string against version js
return comp.v === search;
};
} else {
// regular filter categories
search = hash.substring(1);
filter = function(comp) {
return comp.catLC === search;
};
}
// filter all components using the filter function
for (i=0; i < (allComponents.length); i++) {
if (filter(allComponents[i])) {
data.components.push(allComponents[i]);
}
}
}
rendered = Mustache.render(template, data);
// remove previous elements and css classes, add the new stuff and then trigger the fade-in css animation
$('#componentContainer').html('').removeClass('show-items remove-items').html(rendered).addClass('show-items');
}
/**
* update the browser location hash. This enables users to use the browser-history
*/
function updateHash(newHash) {
if ('replaceState' in history) {
history.replaceState('', '', newHash);
} else {
location.hash = newHash;
}
}
// update view by filter selection
jQuery('.filter-button-group a').click(function() {
updateHash(this.getAttribute('href'));
applyFilter();
return false;
});
/**
* Simple debounce implementation, based on http://davidwalsh.name/javascript-debounce-function
*/
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
};
// update view by search text
$('.component-search input').keyup(debounce(function() {
var text = $(this).val();
// sanitize input
text = text.replace(/[(\?|\&\{\}\(\))]/gi, '');
updateHash('#search/' + text);
applyFilter();
}, 500));
window.addEventListener('hashchange', applyFilter);
applyFilter();
})();
</script>
<noscript>
<ul>
{% for component in components %}
{% if component.ha_category %}
<li><a href='{{ component.url }}'>{{ component.title }}</a></li>
{% endif %}
{% endfor %}
</ul>
</noscript>