Skip to content

Commit abe035d

Browse files
authored
Merge pull request #36 from tomasrudh/Eliminate-Moment.js
Eliminate Moment.js
2 parents a2f948b + 764da3a commit abe035d

File tree

3 files changed

+210
-42
lines changed

3 files changed

+210
-42
lines changed

Formats.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
The code for formatting dates and times are borrowed from https://blog.stevenlevithan.com/archives/javascript-date-format
2+
3+
| Mask | Description |
4+
| --- | --- |
5+
| d | Day of the month as digits; no leading zero for single-digit days. |
6+
| dd | Day of the month as digits; leading zero for single-digit days. |
7+
| ddd | Day of the week as a three-letter abbreviation. |
8+
| dddd | Day of the week as its full name. |
9+
| m | Month as digits; no leading zero for single-digit months. |
10+
| mm | Month as digits; leading zero for single-digit months. |
11+
| mmm | Month as a three-letter abbreviation. |
12+
| mmmm | Month as its full name. |
13+
| yy | Year as last two digits; leading zero for years less than 10. |
14+
| yyyy | Year represented by four digits. |
15+
| h | Hours; no leading zero for single-digit hours (12-hour clock). |
16+
|hh | Hours; leading zero for single-digit hours (12-hour clock). |
17+
| H | Hours; no leading zero for single-digit hours (24-hour clock). |
18+
| HH | Hours; leading zero for single-digit hours (24-hour clock). |
19+
| M | Minutes; no leading zero for single-digit minutes. Uppercase M unlike CF timeFormat's m to avoid conflict with months. |
20+
| MM | Minutes; leading zero for single-digit minutes. Uppercase MM unlike CF timeFormat's mm to avoid conflict with months. |
21+
| s | Seconds; no leading zero for single-digit seconds. |
22+
| ss | Seconds; leading zero for single-digit seconds. |
23+
| l or L | Milliseconds. l gives 3 digits. L gives 2 digits. |
24+
| t | Lowercase, single-character time marker string: a or p. No equivalent in CF. |
25+
| tt | Lowercase, two-character time marker string: am or pm. No equivalent in CF. |
26+
| T | Uppercase, single-character time marker string: A or P. Uppercase T unlike CF's t to allow for user-specified casing. |
27+
| TT | Uppercase, two-character time marker string: AM or PM. Uppercase TT unlike CF's tt to allow for user-specified casing. |
28+
| Z | US timezone abbreviation, e.g. EST or MDT. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. GMT-0500. No equivalent in CF. |
29+
| o | GMT/UTC timezone offset, e.g. -0500 or +0230. No equivalent in CF. |
30+
| S | The date's ordinal suffix (st, nd, rd, or th). Works well with d. No equivalent in CF. |
31+
| '…' or "…" | Literal character sequence. Surrounding quotes are removed. No equivalent in CF. |
32+
| UTC: | Must be the first four characters of the mask. Converts the date from local time to UTC/GMT/Zulu time before applying the mask. The "UTC:" prefix is removed. No equivalent in CF. |
33+
34+
There are some predefined masks
35+
36+
| Name | Mask | Example |
37+
| --- | --- | --- |
38+
| default | ddd mmm dd yyyy HH:MM:ss | Sat Jun 09 2007 17:46:21 |
39+
| shortDate | m/d/yy | 6/9/07 |
40+
| mediumDate | mmm d, yyyy | Jun 9, 2007 |
41+
| longDate | mmmm d, yyyy | June 9, 2007 |
42+
| fullDate | dddd, mmmm d, yyyy | Saturday, June 9, 2007
43+
| shortTime | h:MM TT | 5:46 PM |
44+
| mediumTime | h:MM:ss TT | 5:46:21 PM |
45+
| longTime | h:MM:ss TT Z | 5:46:21 PM EST |
46+
| isoDate | yyyy-mm-dd | 2007-06-09 |
47+
| isoTime | HH:MM:ss | 17:46:21 |
48+
| isoDateTime | yyyy-mm-dd'T'HH:MM:ss | 2007-06-09T17:46:21 |
49+
| isoUtcDateTime | UTC:yyyy-mm-dd'T'HH:MM:ss'Z' | 2007-06-09T22:46:21Z |

README.md

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
# Lovelace Analog Clock
44
An analog clock card for Home Assistant Lovelace. Colors are fully customizable, weekday names and date formats are localizable.
55

6+
```diff
7+
- Breaking changes
8+
Some of the masks for 'dateformat' and 'timeformat' have changed text. Please see Formats for the new masks.
9+
```
10+
611
## Installation
712

813
Install using HACS, search for 'Analog Clock'.
@@ -13,18 +18,9 @@ type: "custom:analog-clock"
1318
```
1419
You might have to add a character and remove it again, before the Save button becomes active.
1520

16-
In addition to the js file is moment.js needed, but only if you plan to use dateformat or timeformat. To install moment.js add these lines in the section 'resources' in ui-lovelace.yaml:
17-
```
18-
- url: https://unpkg.com/moment@2.30.1/min/moment-with-locales.js
19-
type: js
20-
```
21-
22-
If you use the dateformat or timeformat and date or digital time are not shown, that probably means moment.js is not properly loaded. Refresh the cache in your browser.
23-
2421
## Configuration
2522

26-
For a list of available options for dateformat and timeformat, see this:
27-
https://momentjs.com/docs/#/displaying/format/
23+
For a list of available options for dateformat and timeformat, see Formats.
2824

2925
![Analog clock2](https://github.com/tomasrudh/analogclock/blob/main/Images/AnalogClock2.png?raw=true)
3026

@@ -54,8 +50,8 @@ https://momentjs.com/docs/#/displaying/format/
5450
| style_hourhand | Integer | 1 | Style for the hour hand |
5551
| style_minutehand | Integer | 1 | Style for the minute hand |
5652
| style_secondhand | Integer | 3 | Style for the second hand |
57-
| dateformat | String | HA setting | Format for the date (Require moment.js) |
58-
| timeformat | String | HA setting | Format for the time (Require moment.js) |
53+
| dateformat | String | HA setting | Format for the date |
54+
| timeformat | String | HA setting | Format for the time |
5955

6056
Themes are settings that are applied during a time interval. Any setting except timezone and diameter can be set in themes. There can be multiple 'time' sections.
6157

@@ -82,10 +78,10 @@ All colors can be entered in one of four different ways:
8278
hide_secondHand: true
8379
locale: sv-SE
8480
diameter: 200
85-
color_hourHand: "#326ba8"
86-
color_minuteHand: "#3273a8"
87-
color_digitalTime: "#CCCCCC"
88-
color_faceDigits: "#a83832"
81+
color_hourhand: "#326ba8"
82+
color_minutehand: "#3273a8"
83+
color_digitaltime: "#CCCCCC"
84+
color_facedigits: "#a83832"
8985
color_ticks: "Silver"
9086
themes:
9187
- time: 23:00-08:00
@@ -94,11 +90,11 @@ All colors can be entered in one of four different ways:
9490
![Analog clock4](https://github.com/tomasrudh/analogclock/blob/main/Images/AnalogClock4.png?raw=true)
9591
```
9692
- type: "custom:analog-clock"
97-
hide_secondHand: true
98-
color_hourHand: "#326ba8"
99-
color_minuteHand: "#3273a8"
100-
color_digitalTime: "#CCCCCC"
101-
color_faceDigits: "#a83832"
93+
hide_secondhand: true
94+
color_hourhand: "#326ba8"
95+
color_minutehand: "#3273a8"
96+
color_digitaltime: "#CCCCCC"
97+
color_facedigits: "#a83832"
10298
hide_minorticks: true
10399
timezone: America/Fortaleza
104100
timezonedisplayname: "UTC-3"
@@ -140,11 +136,11 @@ elements:
140136
hide_facedigits: true
141137
dateformat: "YYYY-MM-DD"
142138
color_background: rgba(0,0,0,0)
143-
color_hourHand: "#326ba8"
144-
color_minuteHand: "#3293a8"
139+
color_hourhand: "#326ba8"
140+
color_minutehand: "#3293a8"
145141
color_secondhand: red
146-
color_digitalTime: "#CCCCCC"
147-
color_faceDigits: "#a83832"
142+
color_digitaltime: "#CCCCCC"
143+
color_facedigits: "#a83832"
148144
card_mod:
149145
style: |
150146
ha-card {

dist/analogclock.js

Lines changed: 140 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
class AnalogClock extends HTMLElement {
22
set hass(hass) {
3-
if (!this.content) {
4-
console.info(`%c ANALOG-CLOCK v2.0 `, 'color: white; font-weight: bold; background: black');
53

4+
const formatStackTrace = (stack) => {
5+
return stack.split("\n").map(line => line.trim());
6+
};
7+
8+
if (!this.content) {
9+
console.info(`%c ANALOG-CLOCK v3.0 `, 'color: white; font-weight: bold; background: black');
610
var config = this.config;
711
const card = document.createElement('ha-card');
812
this.content = document.createElement('div');
@@ -21,7 +25,6 @@ class AnalogClock extends HTMLElement {
2125
//ctx.textBaseline = 'middle';
2226
var radius = (canvas.width < canvas.height) ? canvas.width / 2.1 : canvas.height / 2.1;
2327
//ctx.translate(canvas.width / 2, canvas.height / 2);
24-
2528
var canvasHourEl = document.createElement('canvas');
2629
canvasHourEl.width = canvas.width
2730
canvasHourEl.height = canvas.height
@@ -45,6 +48,131 @@ class AnalogClock extends HTMLElement {
4548
var layerCachedForMinute = -1;
4649
getConfig();
4750

51+
/*
52+
* Date Format 1.2.3
53+
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
54+
* MIT license
55+
*
56+
* Includes enhancements by Scott Trenda <scott.trenda.net>
57+
* and Kris Kowal <cixar.com/~kris.kowal/>
58+
*
59+
* Accepts a date, a mask, or a date and a mask.
60+
* Returns a formatted version of the given date.
61+
* The date defaults to the current date/time.
62+
* The mask defaults to dateFormat.masks.default.
63+
*/
64+
var dateFormat = function () {
65+
var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
66+
timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
67+
timezoneClip = /[^-+\dA-Z]/g,
68+
pad = function (val, len) {
69+
val = String(val);
70+
len = len || 2;
71+
while (val.length < len) val = "0" + val;
72+
return val;
73+
};
74+
75+
// Regexes and supporting functions are cached through closure
76+
return function (date, mask, utc) {
77+
var dF = dateFormat;
78+
79+
// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
80+
if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
81+
mask = date;
82+
date = undefined;
83+
}
84+
85+
// Passing date through Date applies Date.parse, if necessary
86+
date = date ? new Date(date) : new Date;
87+
if (isNaN(date)) throw SyntaxError("invalid date");
88+
89+
mask = String(dF.masks[mask] || mask || dF.masks["default"]);
90+
91+
// Allow setting the utc argument via the mask
92+
if (mask.slice(0, 4) == "UTC:") {
93+
mask = mask.slice(4);
94+
utc = true;
95+
}
96+
97+
var _ = utc ? "getUTC" : "get",
98+
d = date[_ + "Date"](),
99+
D = date[_ + "Day"](),
100+
m = date[_ + "Month"](),
101+
y = date[_ + "FullYear"](),
102+
H = date[_ + "Hours"](),
103+
M = date[_ + "Minutes"](),
104+
s = date[_ + "Seconds"](),
105+
L = date[_ + "Milliseconds"](),
106+
o = utc ? 0 : date.getTimezoneOffset(),
107+
flags = {
108+
d: d,
109+
dd: pad(d),
110+
ddd: intlDay('short'),
111+
dddd: intlDay('long'),
112+
m: m + 1,
113+
mm: pad(m + 1),
114+
mmm: intlMonth('short'),
115+
mmmm: intlMonth('long'),
116+
yy: String(y).slice(2),
117+
yyyy: y,
118+
h: H % 12 || 12,
119+
hh: pad(H % 12 || 12),
120+
H: H,
121+
HH: pad(H),
122+
M: M,
123+
MM: pad(M),
124+
s: s,
125+
ss: pad(s),
126+
l: pad(L, 3),
127+
L: pad(L > 99 ? Math.round(L / 10) : L),
128+
t: H < 12 ? "a" : "p",
129+
tt: H < 12 ? "am" : "pm",
130+
T: H < 12 ? "A" : "P",
131+
TT: H < 12 ? "AM" : "PM",
132+
Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
133+
o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
134+
S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
135+
};
136+
137+
return mask.replace(token, function ($0) {
138+
return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
139+
});
140+
};
141+
}();
142+
143+
// Some common format strings
144+
dateFormat.masks = {
145+
"default": "ddd mmm dd yyyy HH:MM:ss",
146+
shortDate: "m/d/yy",
147+
mediumDate: "mmm d, yyyy",
148+
longDate: "mmmm d, yyyy",
149+
fullDate: "dddd, mmmm d, yyyy",
150+
shortTime: "h:MM TT",
151+
mediumTime: "h:MM:ss TT",
152+
longTime: "h:MM:ss TT Z",
153+
isoDate: "yyyy-mm-dd",
154+
isoTime: "HH:MM:ss",
155+
isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
156+
isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
157+
};
158+
159+
// For convenience...
160+
Date.prototype.format = function (mask, utc) {
161+
return dateFormat(this, mask, utc);
162+
};
163+
164+
function intlMonth(length) {
165+
var now = new Date();
166+
var options = { month: length };
167+
return now.toLocaleDateString(locale, options);
168+
}
169+
170+
function intlDay(length) {
171+
var now = new Date();
172+
var options = { weekday: length };
173+
return now.toLocaleDateString(locale, options);
174+
}
175+
48176
drawClock();
49177
if (this.hide_SecondHand) {
50178
setInterval(drawClock, 10000);
@@ -280,8 +408,7 @@ class AnalogClock extends HTMLElement {
280408
var timeString = now.toLocaleTimeString(locale, options);
281409
if (timeFormat) {
282410
try {
283-
var nowmoment = moment(now);
284-
timeString = nowmoment.format(timeFormat);
411+
timeString = dateFormat(now, timeFormat)
285412
}
286413
catch (err) {
287414
showerror(err, ctx, radius)
@@ -300,13 +427,12 @@ class AnalogClock extends HTMLElement {
300427
function drawDate(ctx, now, locale, radius, color) {
301428
ctx.font = Math.round(radius / 7) + 'px Sans-Serif';
302429
ctx.fillStyle = color
303-
if (dateFormat) {
430+
if (dateMask) {
304431
//"20111010T1020"
305432
var datestring = now.toLocaleString('sv-SE');
306433
//var datestring = '2021-01-10 10:08';
307434
try {
308-
var nowmoment = moment(datestring);
309-
ctx.fillText(nowmoment.format(dateFormat), 0, radius * 0.5);
435+
ctx.fillText(dateFormat(now, dateMask), 0, radius * 0.5)
310436
}
311437
catch (err) {
312438
showerror(err, ctx, radius)
@@ -445,8 +571,8 @@ class AnalogClock extends HTMLElement {
445571
globalThis.style_SecondHand = 3;
446572
if (config.style_secondhand) style_SecondHand = config.style_secondhand;
447573

448-
globalThis.dateFormat = "";
449-
if (config.dateformat) dateFormat = config.dateformat;
574+
globalThis.dateMask = "";
575+
if (config.dateformat) dateMask = config.dateformat;
450576

451577
globalThis.timeFormat = "";
452578
if (config.timeformat) timeFormat = config.timeformat;
@@ -502,7 +628,7 @@ class AnalogClock extends HTMLElement {
502628
if (themes[i].style_hourhand) { style_HourHand = themes[i].style_hourhand };
503629
if (themes[i].style_minutehand) { style_MinuteHand = themes[i].style_minutehand };
504630
if (themes[i].style_secondhand) { style_SecondHand = themes[i].style_secondhand };
505-
if (themes[i].dateformat) { dateFormat = themes[i].dateformat };
631+
if (themes[i].dateformat) { dateMask = themes[i].dateFormat };
506632
if (themes[i].timeformat) { timeFormat = themes[i].timeformat };
507633
}
508634
}
@@ -514,12 +640,9 @@ class AnalogClock extends HTMLElement {
514640
}
515641

516642
function showerror(err, ctx, radius) {
517-
console.error("ANALOG-CLOCK Error: " + err.message);
518-
if (err.message = 'moment is not defined') {
519-
console.info('Have you added moment.js as a resource in Lovelace.yaml?')
520-
console.info('Also clear your browser cache, to make moment.js load.')
521-
console.info('Find documentation here: https://github.com/tomasrudh/analogclock')
522-
}
643+
console.error("ANALOG-CLOCK Error: " + err.message)
644+
const stackTraceArr = formatStackTrace(err.stack)
645+
console.info(stackTraceArr[1])
523646
var img = new Image();
524647
img.src = 'https://cdn.jsdelivr.net/gh/tomasrudh/analogclock/Images/errorsign.png';
525648
img.onload = function (e) {

0 commit comments

Comments
 (0)