370 lines
9.0 KiB
HTML

<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/polymer/lib/utils/debounce.html">
<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="./ha-demo-badge.html">
<link rel="import" href="../cards/ha-badges-card.html">
<link rel="import" href="../cards/ha-card-chooser.html">
<link rel="import" href="../util/hass-util.html">
<dom-module id="ha-cards">
<template>
<style is="custom-style" include="iron-flex iron-flex-factors"></style>
<style>
:host {
display: block;
padding-top: 8px;
padding-right: 8px;
}
.badges {
font-size: 85%;
text-align: center;
}
.column {
max-width: 500px;
overflow-x: hidden;
}
ha-card-chooser {
display: block;
margin-left: 8px;
margin-bottom: 8px;
}
@media (max-width: 500px) {
:host {
padding-right: 0;
}
ha-card-chooser {
margin-left: 0;
}
}
@media (max-width: 599px) {
.column {
max-width: 600px;
}
}
</style>
<div id='main'>
<template is='dom-if' if='[[cards.badges]]'>
<div class='badges'>
<template is='dom-if' if='[[cards.demo]]'>
<ha-demo-badge></ha-demo-badge>
</template>
<ha-badges-card states='[[cards.badges]]' hass='[[hass]]'></ha-badges-card>
</div>
</template>
<div class='horizontal layout center-justified'>
<template is='dom-repeat' items='[[cards.columns]]' as='column'>
<div class='column flex-1'>
<template is='dom-repeat' items='[[column]]' as='card'>
<ha-card-chooser card-data='[[card]]' hass='[[hass]]'
></ha-card-chooser>
</template>
</div>
</template>
</div>
</template>
</dom-module>
<script>
{
// mapping domain to size of the card.
const DOMAINS_WITH_CARD = {
camera: 4,
history_graph: 4,
media_player: 3,
persistent_notification: 0,
plant: 3,
weather: 4,
};
// 4 types:
// badges: 0 .. 10
// before groups < 0
// groups: X
// rest: 100
const PRIORITY = {
// before groups < 0
configurator: -20,
persistent_notification: -15,
// badges have priority >= 0
updater: 0,
sun: 1,
device_tracker: 2,
alarm_control_panel: 3,
timer: 4,
sensor: 5,
binary_sensor: 6,
mailbox: 7,
};
const getPriority = domain =>
((domain in PRIORITY) ? PRIORITY[domain] : 100);
const sortPriority = (domainA, domainB) =>
domainA.priority - domainB.priority;
const entitySortBy = (entityA, entityB) => {
const nameA = (entityA.attributes.friendly_name ||
entityA.entity_id).toLowerCase();
const nameB = (entityB.attributes.friendly_name ||
entityB.entity_id).toLowerCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
};
const iterateDomainSorted = (collection, func) => {
Object.keys(collection)
.map(key => collection[key])
.sort(sortPriority)
.forEach((domain) => {
domain.states.sort(entitySortBy);
func(domain);
});
};
const computeDomain = window.hassUtil.computeDomain;
class HaCards extends Polymer.Element {
static get is() { return 'ha-cards'; }
static get properties() {
return {
hass: Object,
columns: {
type: Number,
value: 2,
},
states: Object,
panelVisible: Boolean,
viewVisible: {
type: Boolean,
value: false,
},
orderedGroupEntities: Array,
cards: Object,
};
}
static get observers() {
return [
'updateCards(columns, states, panelVisible, viewVisible, orderedGroupEntities)',
];
}
updateCards(
columns,
states,
panelVisible,
viewVisible,
orderedGroupEntities
) {
if (!panelVisible || !viewVisible) {
if (this.$.main.parentNode) {
this.$.main._parentNode = this.$.main.parentNode;
this.$.main.parentNode.removeChild(this.$.main);
}
return;
} else if (!this.$.main.parentNode && this.$.main._parentNode) {
this.$.main._parentNode.appendChild(this.$.main);
}
this._debouncer = Polymer.Debouncer.debounce(
this._debouncer,
Polymer.Async.timeOut.after(10),
() => {
// Things might have changed since it got scheduled.
if (this.panelVisible && this.viewVisible) {
this.cards = this.computeCards(columns, states, orderedGroupEntities);
}
}
);
}
emptyCards() {
return {
demo: false,
badges: [],
columns: [],
};
}
computeCards(columns, states, orderedGroupEntities) {
const hass = this.hass;
const cards = this.emptyCards();
const entityCount = [];
for (let i = 0; i < columns; i++) {
cards.columns.push([]);
entityCount.push(0);
}
// Find column with < 5 entities, else column with lowest count
function getIndex(size) {
let minIndex = 0;
for (let i = 0; i < entityCount.length; i++) {
if (entityCount[i] < 5) {
minIndex = i;
break;
}
if (entityCount[i] < entityCount[minIndex]) {
minIndex = i;
}
}
entityCount[minIndex] += size;
return minIndex;
}
function addEntitiesCard(name, entities, groupEntity) {
if (entities.length === 0) return;
const owncard = [];
const other = [];
let size = 0;
entities.forEach((entity) => {
const domain = computeDomain(entity);
if (domain in DOMAINS_WITH_CARD) {
owncard.push(entity);
size += DOMAINS_WITH_CARD[domain];
} else {
other.push(entity);
size++;
}
});
// Add 1 to the size if we're rendering entities card
size += other.length > 0;
const curIndex = getIndex(size);
if (other.length > 0) {
cards.columns[curIndex].push({
hass: hass,
cardType: 'entities',
states: other,
groupEntity: groupEntity || false,
});
}
owncard.forEach((entity) => {
cards.columns[curIndex].push({
hass: hass,
cardType: computeDomain(entity),
stateObj: entity,
});
});
}
const splitted = window.HAWS.splitByGroups(states);
if (orderedGroupEntities) {
splitted.groups.sort((gr1, gr2) => orderedGroupEntities[gr1.entity_id] -
orderedGroupEntities[gr2.entity_id]);
} else {
splitted.groups.sort((gr1, gr2) => gr1.attributes.order - gr2.attributes.order);
}
const badgesColl = {};
const beforeGroupColl = {};
const afterGroupedColl = {};
Object.keys(splitted.ungrouped).forEach((key) => {
const state = splitted.ungrouped[key];
const domain = computeDomain(state);
if (domain === 'a') {
cards.demo = true;
return;
}
const priority = getPriority(domain);
let coll;
if (priority < 0) {
coll = beforeGroupColl;
} else if (priority < 10) {
coll = badgesColl;
} else {
coll = afterGroupedColl;
}
if (!(domain in coll)) {
coll[domain] = {
domain: domain,
priority: priority,
states: [],
};
}
coll[domain].states.push(state);
});
if (orderedGroupEntities) {
Object.keys(badgesColl)
.map(key => badgesColl[key])
.forEach((domain) => {
cards.badges.push.apply(cards.badges, domain.states);
});
cards.badges.sort((e1, e2) => orderedGroupEntities[e1.entity_id] -
orderedGroupEntities[e2.entity_id]);
} else {
iterateDomainSorted(badgesColl, (domain) => {
cards.badges.push.apply(cards.badges, domain.states);
});
}
iterateDomainSorted(beforeGroupColl, (domain) => {
addEntitiesCard(domain.domain, domain.states);
});
splitted.groups.forEach((groupState) => {
const entities = window.HAWS.getGroupEntities(states, groupState);
addEntitiesCard(
groupState.entity_id,
Object.keys(entities).map(key => entities[key]),
groupState
);
});
iterateDomainSorted(afterGroupedColl, (domain) => {
addEntitiesCard(domain.domain, domain.states);
});
// Remove empty columns
cards.columns = cards.columns.filter(val => val.length > 0);
return cards;
}
}
customElements.define(HaCards.is, HaCards);
}
</script>