Skip to content

Commit baf4f46

Browse files
committed
Alarm card updated to 0.4.0 (ciotlosm#192)
* Get rid of memory leak * Add requested changes for labels and hide/show buttons * Remove console.log messages * Add label method * Handle translations * Fix labels documentation. * Address PR comments. * Added changelog and version updates
1 parent a5e11e3 commit baf4f46

File tree

4 files changed

+96
-68
lines changed

4 files changed

+96
-68
lines changed

alarm_control_panel-card/README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Alarm control panel card allows you to control [alarm_control_panel](https://www
1616
| states | list | optional | A list of possible arm buttons. Supports `arm_home`, `arm_away`, `arm_night`, `arm_custom_bypass`.
1717
| style | string | optional | Allows to override some default styles. Example `--alarm-color-disarmed: var(--label-badge-blue);`
1818
| auto_enter | object | optional | Options to auto arm and disarm. See `auto_enter` options.
19+
| labels | object | optional | Labels that augment/override defaults.
20+
| show_label_ids | boolean | optional | Allow displaying label constants (when setting to `true`) to be able to map your own translations under `labels`. Defaults to `false`.
1921

2022
`auto_enter` options:
2123

@@ -24,6 +26,9 @@ Alarm control panel card allows you to control [alarm_control_panel](https://www
2426
| code_length | integer | Required | When number of digits entered system will arm/disarm
2527
| arm_action | string | Required | Action to invoke when after digits entered. Can be any of the same values as `states` above.
2628

29+
`labels`:
30+
The labels to display. Label name and value. See example.
31+
2732
**Example**
2833

2934
```yaml
@@ -35,8 +40,12 @@ Alarm control panel card allows you to control [alarm_control_panel](https://www
3540
states:
3641
- arm_home
3742
- arm_away
43+
labels:
44+
ui.card.alarm_control_panel.code: Inserire un codice a 4 cifre
45+
state.alarm_control_panel.arm_away: Away!!
3846
```
3947
4048
**Credits**
49+
- [@gwww](https://github.com/gwww) Added translations
4150
- [@gwww](https://github.com/gwww) Awesome refactoring
42-
- [@ciotlosm](https://github.com/ciotlosm)
51+
- [@ciotlosm](https://github.com/ciotlosm)

alarm_control_panel-card/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.3.2
1+
0.4.0

alarm_control_panel-card/alarm_control_panel-card.js

+80-66
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,6 @@ class AlarmControlPanelCard extends HTMLElement {
22
constructor() {
33
super();
44
this.attachShadow({ mode: 'open' });
5-
this._stateStrings = {
6-
'arm_away': 'Arm away',
7-
'arm_custom_bypass': 'Custom',
8-
'arm_home': 'Arm home',
9-
'arming': 'Arming',
10-
'arm_night': 'Arm night',
11-
'armed_away': 'Armed away',
12-
'armed_custom_bypass': 'Armed custom',
13-
'armed_home': 'Armed home',
14-
'armed_night': 'Armed night',
15-
'disarm': 'Disarm',
16-
'disarmed': 'Disarmed',
17-
'pending': 'Pending',
18-
'triggered': 'Triggered',
19-
}
205
this._icons = {
216
'armed_away': 'mdi:security-lock',
227
'armed_custom_bypass': 'mdi:security',
@@ -29,14 +14,47 @@ class AlarmControlPanelCard extends HTMLElement {
2914
}
3015

3116
set hass(hass) {
32-
this.myhass = hass;
3317
const entity = hass.states[this._config.entity];
34-
if (entity && entity.state != this._state) {
35-
this._state = entity.state;
36-
this._updateCardContent(entity);
18+
19+
if (entity) {
20+
this.myhass = hass;
21+
if(!this.shadowRoot.lastChild) {
22+
this._createCard(entity);
23+
}
24+
if (entity.state != this._state) {
25+
this._state = entity.state;
26+
this._updateCardContent(entity);
27+
}
3728
}
3829
}
3930

31+
_createCard(entity) {
32+
const config = this._config;
33+
34+
const card = document.createElement('ha-card');
35+
const content = document.createElement('div');
36+
content.id = "content";
37+
content.innerHTML = `
38+
${config.title ? '<div id="state-text"></div>' : ''}
39+
<ha-icon id="state-icon"></ha-icon>
40+
${this._actionButtons()}
41+
${entity.attributes.code_format ?
42+
`<paper-input label='${this._label("ui.card.alarm_control_panel.code")}'
43+
type="password"></paper-input>` : ''}
44+
${this._keypad(entity)}
45+
`;
46+
card.appendChild(this._style(config.style));
47+
card.appendChild(content);
48+
this.shadowRoot.appendChild(card);
49+
50+
this._setupInput();
51+
this._setupKeypad();
52+
this._setupActions();
53+
}
54+
55+
connectedCallback() {
56+
}
57+
4058
setConfig(config) {
4159
if (!config.entity || config.entity.split(".")[0] !== "alarm_control_panel") {
4260
throw new Error('Please specify an entity from alarm_control_panel domain.');
@@ -48,70 +66,54 @@ class AlarmControlPanelCard extends HTMLElement {
4866
}
4967
this._arm_action = config.auto_enter.arm_action;
5068
}
69+
if (!config.states) config.states = ['arm_away', 'arm_home'];
70+
if (!config.scale) config.scale = '15px';
71+
this._config = Object.assign({}, config);
5172

5273
const root = this.shadowRoot;
5374
if (root.lastChild) root.removeChild(root.lastChild);
54-
if (!config.states) config.states = ['arm_home', 'arm_away'];
55-
if (!config.scale) config.scale = '15px';
56-
57-
this._card = document.createElement('ha-card');
58-
const content = document.createElement('div');
59-
content.id = "content";
60-
this._config = Object.assign({}, config);
61-
this._card.appendChild(this._style(config.style));
62-
this._card.appendChild(content);
63-
root.appendChild(this._card);
64-
this._config = Object.assign({}, config);
6575
}
6676

6777
_updateCardContent(entity) {
6878
const root = this.shadowRoot;
6979
const card = root.lastChild;
7080
const config = this._config;
7181

72-
if (!config.title) {
73-
card.header = this._stateToText(this._state);
74-
} else {
82+
const state_str = "state.alarm_control_panel." + this._state;
83+
if (config.title) {
7584
card.header = config.title;
85+
root.getElementById("state-text").innerHTML = this._label(state_str);
86+
root.getElementById("state-text").className = `state ${this._state}`;
87+
} else {
88+
card.header = this._label(state_str);
7689
}
7790

78-
root.getElementById("content").innerHTML = `
79-
${this._icon()}
80-
${config.title ? `<div class='state ${this._state}'>
81-
${this._stateToText(this._state)}</div>` : ''}
82-
${this._actionButtons()}
83-
${entity.attributes.code_format ? '<paper-input label="Alarm code" type="password"></paper-input>' : ''}
84-
${this._keypad(entity)}
85-
`;
86-
87-
this._setupActions();
88-
this._setupInput();
89-
this._setupKeypad();
90-
}
91+
root.getElementById("state-icon").setAttribute("icon",
92+
this._icons[this._state] || 'mdi:shield-outline');
93+
root.getElementById("state-icon").className = this._state;
9194

92-
_icon() {
93-
return `<ha-icon icon='${this._stateToIcon(this._state)}'
94-
class='${this._state}'></ha-icon>`
95+
const armVisible = (this._state === 'disarmed');
96+
root.getElementById("arm-actions").style.display = armVisible ? "" : "none";
97+
root.getElementById("disarm-actions").style.display = armVisible ? "none" : "";
9598
}
9699

97100
_actionButtons() {
98101
const armVisible = (this._state === 'disarmed');
99102
return `
100-
<div class="actions">
101-
${armVisible
102-
? `${this._config.states.map(el => `${this._actionButton(el)}`).join('')}`
103-
: `${this._actionButton('disarm')}`}
104-
</div>`
103+
<div id="arm-actions" class="actions">
104+
${this._config.states.map(el => `${this._actionButton(el)}`).join('')}
105+
</div>
106+
<div id="disarm-actions" class="actions">
107+
${this._actionButton('disarm')}
108+
</div>`;
105109
}
106110

107111
_actionButton(state) {
108-
return `<paper-button noink raised id="${state}">${this._stateToText(state)}
109-
</paper-button>`;
112+
return `<paper-button noink raised id="${state}">
113+
${this._label("ui.card.alarm_control_panel." + state)}</paper-button>`;
110114
}
111115

112116
_setupActions() {
113-
// TODO: fix memory leak for reattaching handlers every time
114-
// Need a way to avoid doing innerHTML, at least without detaching handlers first
115117
const card = this.shadowRoot.lastChild;
116118
const config = this._config;
117119

@@ -161,7 +163,8 @@ class AlarmControlPanelCard extends HTMLElement {
161163

162164
const input = root.lastChild.querySelector('paper-input');
163165
root.querySelectorAll(".pad paper-button").forEach(element => {
164-
if (element.getAttribute('value') === 'Clear') {
166+
if (element.getAttribute('value') ===
167+
this._label("ui.card.alarm_control_panel.clear_code")) {
165168
element.addEventListener('click', event => {
166169
input.value = '';
167170
})
@@ -207,7 +210,7 @@ class AlarmControlPanelCard extends HTMLElement {
207210
${this._keypadButton("3", "DEF")}
208211
${this._keypadButton("6", "MNO")}
209212
${this._keypadButton("9", "WXYZ")}
210-
${this._keypadButton("Clear", "")}
213+
${this._keypadButton(this._label("ui.card.alarm_control_panel.clear_code"), "")}
211214
</div>
212215
</div>`
213216
}
@@ -324,17 +327,28 @@ class AlarmControlPanelCard extends HTMLElement {
324327
return style;
325328
}
326329

327-
_stateToIcon(state) {
328-
return this._icons[state] || 'mdi:shield-outline'
329-
}
330+
_label(label, default_label=undefined) {
331+
// Just show "raw" label; useful when want to see underlying const
332+
// so you can define your own label.
333+
if (this._config.show_label_ids) return label;
334+
335+
if (this._config.labels && this._config.labels[label])
336+
return this._config.labels[label];
337+
338+
const lang = this.myhass.selectedLanguage || this.myhass.language;
339+
const translations = this.myhass.resources[lang];
340+
if (translations && translations[label]) return translations[label];
341+
342+
if (default_label) return default_label;
330343

331-
_stateToText(state) {
332-
return this._stateStrings[state] || 'Unknown'
344+
// If all else fails then pretify the passed in label const
345+
const last_bit = label.split('.').pop();
346+
return last_bit.split('_').join(' ').replace(/^\w/, c => c.toUpperCase());
333347
}
334348

335349
getCardSize() {
336350
return 1;
337351
}
338352
}
339353

340-
customElements.define('alarm_control_panel-card', AlarmControlPanelCard);
354+
customElements.define('alarm_control_panel-card', AlarmControlPanelCard);

alarm_control_panel-card/changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.4.0
2+
- Major refactoring from @gwww
3+
- Add translation support
4+
- Fixes some memory leaks
5+
16
## 0.3.2
27
- Fixed javascript error on code clear when no code was used
38

0 commit comments

Comments
 (0)