Merge branch 'visual-console-refactor' of https://brutus.artica.lan:8081/artica/pandorafms into visual-console-refactor

Former-commit-id: 50ffdbe852fe3dc88ba1705ce769f8ec70bc7506
This commit is contained in:
Daniel Maya 2019-04-24 13:40:46 +02:00
commit 56fef21bc6
12 changed files with 125 additions and 81 deletions

View File

@ -18,10 +18,10 @@
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;
-webkit-user-select: none; -webkit-user-select: text;
-moz-user-select: none; -moz-user-select: text;
-ms-user-select: none; -ms-user-select: text;
user-select: none; user-select: text;
} }
@font-face { @font-face {
@ -86,4 +86,4 @@
animation: rotate-second 60s infinite linear; animation: rotate-second 60s infinite linear;
} }
/*# sourceMappingURL=vc.main.ba23d758.css.map*/ /*# sourceMappingURL=vc.main.402dd2b3.css.map*/

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///main.css","webpack:///styles.css"],"names":[],"mappings":"AAAA;EACE,gBAAgB;EAChB,kBAAkB;EAClB,4BAA4B;EAC5B,wBAAwB;AAC1B;;AAEA;EACE,kBAAkB;EAClB,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,2BAAuB;EAAvB,8BAAuB;MAAvB,2BAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;EACnB,yBAAiB;KAAjB,sBAAiB;MAAjB,qBAAiB;UAAjB,iBAAiB;AACnB;;ACdA;EACE,wBAAwB;EACxB,kCAA2B;AAC7B;;AAEA,kBAAkB;;AAElB;EACE,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,4BAAsB;EAAtB,6BAAsB;MAAtB,0BAAsB;UAAtB,sBAAsB;EACtB,wBAAuB;MAAvB,qBAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,0BAAqB;MAArB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;AACrB;;AAEA;EACE,6DAA6D;EAC7D,eAAe;;EAEf,0BAA0B;EAC1B,mCAAmC;EACnC,kCAAkC;EAClC,kCAAkC;EAClC,wCAAwC;AAC1C;;AAEA;EACE,eAAe;AACjB;;AAEA;EACE,eAAe;AACjB;;AAEA,iBAAiB;;AAEjB;EACE,qDAA6C;UAA7C,6CAA6C;AAC/C;;AAEA;EACE,sDAA8C;UAA9C,8CAA8C;AAChD;;AAEA;EACE,oDAA4C;UAA5C,4CAA4C;AAC9C","file":"vc.main.ba23d758.css","sourcesContent":["#visual-console-container {\n margin: 0px auto;\n position: relative;\n background-repeat: no-repeat;\n background-size: contain;\n}\n\n.visual-console-item {\n position: absolute;\n display: flex;\n flex-direction: initial;\n justify-items: center;\n align-items: center;\n user-select: none;\n}\n","@font-face {\n font-family: Alarm Clock;\n src: url(./alarm-clock.ttf);\n}\n\n/* Digital clock */\n\n.visual-console-item .digital-clock {\n display: flex;\n flex-direction: column;\n justify-content: center;\n justify-items: center;\n align-content: center;\n align-items: center;\n}\n\n.visual-console-item .digital-clock > span {\n font-family: \"Alarm Clock\", \"Courier New\", Courier, monospace;\n font-size: 50px;\n\n /* To improve legibility */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;\n}\n\n.visual-console-item .digital-clock > span.date {\n font-size: 25px;\n}\n\n.visual-console-item .digital-clock > span.timezone {\n font-size: 25px;\n}\n\n/* Analog clock */\n\n.visual-console-item .analogic-clock .hour-hand {\n animation: rotate-hour 43200s infinite linear;\n}\n\n.visual-console-item .analogic-clock .minute-hand {\n animation: rotate-minute 3600s infinite linear;\n}\n\n.visual-console-item .analogic-clock .second-hand {\n animation: rotate-second 60s infinite linear;\n}\n"],"sourceRoot":""} {"version":3,"sources":["webpack:///main.css","webpack:///styles.css"],"names":[],"mappings":"AAAA;EACE,gBAAgB;EAChB,kBAAkB;EAClB,4BAA4B;EAC5B,wBAAwB;AAC1B;;AAEA;EACE,kBAAkB;EAClB,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,2BAAuB;EAAvB,8BAAuB;MAAvB,2BAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;EACnB,yBAAiB;KAAjB,sBAAiB;MAAjB,qBAAiB;UAAjB,iBAAiB;AACnB;;ACdA;EACE,wBAAwB;EACxB,kCAA2B;AAC7B;;AAEA,kBAAkB;;AAElB;EACE,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,4BAAsB;EAAtB,6BAAsB;MAAtB,0BAAsB;UAAtB,sBAAsB;EACtB,wBAAuB;MAAvB,qBAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,0BAAqB;MAArB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;AACrB;;AAEA;EACE,6DAA6D;EAC7D,eAAe;;EAEf,0BAA0B;EAC1B,mCAAmC;EACnC,kCAAkC;EAClC,kCAAkC;EAClC,wCAAwC;AAC1C;;AAEA;EACE,eAAe;AACjB;;AAEA;EACE,eAAe;AACjB;;AAEA,iBAAiB;;AAEjB;EACE,qDAA6C;UAA7C,6CAA6C;AAC/C;;AAEA;EACE,sDAA8C;UAA9C,8CAA8C;AAChD;;AAEA;EACE,oDAA4C;UAA5C,4CAA4C;AAC9C","file":"vc.main.402dd2b3.css","sourcesContent":["#visual-console-container {\n margin: 0px auto;\n position: relative;\n background-repeat: no-repeat;\n background-size: contain;\n}\n\n.visual-console-item {\n position: absolute;\n display: flex;\n flex-direction: initial;\n justify-items: center;\n align-items: center;\n user-select: text;\n}\n","@font-face {\n font-family: Alarm Clock;\n src: url(./alarm-clock.ttf);\n}\n\n/* Digital clock */\n\n.visual-console-item .digital-clock {\n display: flex;\n flex-direction: column;\n justify-content: center;\n justify-items: center;\n align-content: center;\n align-items: center;\n}\n\n.visual-console-item .digital-clock > span {\n font-family: \"Alarm Clock\", \"Courier New\", Courier, monospace;\n font-size: 50px;\n\n /* To improve legibility */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;\n}\n\n.visual-console-item .digital-clock > span.date {\n font-size: 25px;\n}\n\n.visual-console-item .digital-clock > span.timezone {\n font-size: 25px;\n}\n\n/* Analog clock */\n\n.visual-console-item .analogic-clock .hour-hand {\n animation: rotate-hour 43200s infinite linear;\n}\n\n.visual-console-item .analogic-clock .minute-hand {\n animation: rotate-minute 3600s infinite linear;\n}\n\n.visual-console-item .analogic-clock .second-hand {\n animation: rotate-second 60s infinite linear;\n}\n"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -197,7 +197,34 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
element.className = "visual-console-item-label"; element.className = "visual-console-item-label";
// Add the label if it exists. // Add the label if it exists.
if (this.props.label && this.props.label.length) { if (this.props.label && this.props.label.length) {
element.innerHTML = this.props.label; // Ugly table we need to use to replicate the legacy style.
const table = document.createElement("table");
const row = document.createElement("tr");
const emptyRow1 = document.createElement("tr");
const emptyRow2 = document.createElement("tr");
const cell = document.createElement("td");
cell.innerHTML = this.props.label;
row.append(cell);
table.append(emptyRow1, row, emptyRow2);
switch (this.props.labelPosition) {
case "up":
case "down":
if (this.props.width > 0) {
table.style.width = `${this.props.width}px`;
}
break;
case "left":
case "right":
if (this.props.height > 0) {
table.style.height = `${this.props.height}px`;
}
break;
}
// element.innerHTML = this.props.label;
element.append(table);
} }
return element; return element;

View File

@ -4,10 +4,11 @@ import { LinkedVisualConsoleProps, UnknownObject, Size } from "../../types";
import { import {
linkedVCPropsDecoder, linkedVCPropsDecoder,
parseIntOr, parseIntOr,
padLeft,
parseBoolean, parseBoolean,
prefixedCssRules, prefixedCssRules,
notEmptyStringOr notEmptyStringOr,
humanDate,
humanTime
} from "../../lib"; } from "../../lib";
import Item, { ItemProps, itemBasePropsDecoder, ItemType } from "../../Item"; import Item, { ItemProps, itemBasePropsDecoder, ItemType } from "../../Item";
@ -388,7 +389,7 @@ export default class Clock extends Item<ClockProps> {
pin.setAttribute("fill", colors.handDark); pin.setAttribute("fill", colors.handDark);
// Get the hand angles. // Get the hand angles.
const date = this.getDate(); const date = this.getOriginDate();
const seconds = date.getSeconds(); const seconds = date.getSeconds();
const minutes = date.getMinutes(); const minutes = date.getMinutes();
const hours = date.getHours(); const hours = date.getHours();
@ -492,11 +493,14 @@ export default class Clock extends Item<ClockProps> {
(width / 100) * 10 (width / 100) * 10
); );
// Date calculated using the original timezone.
const date = this.getOriginDate();
// Date. // Date.
if (this.props.clockFormat === "datetime") { if (this.props.clockFormat === "datetime") {
const dateElem: HTMLSpanElement = document.createElement("span"); const dateElem: HTMLSpanElement = document.createElement("span");
dateElem.className = "date"; dateElem.className = "date";
dateElem.textContent = this.getDigitalDate(); dateElem.textContent = humanDate(date, "default");
dateElem.style.fontSize = `${dateFontSize}px`; dateElem.style.fontSize = `${dateFontSize}px`;
if (this.props.color) dateElem.style.color = this.props.color; if (this.props.color) dateElem.style.color = this.props.color;
element.append(dateElem); element.append(dateElem);
@ -505,7 +509,7 @@ export default class Clock extends Item<ClockProps> {
// Time. // Time.
const timeElem: HTMLSpanElement = document.createElement("span"); const timeElem: HTMLSpanElement = document.createElement("span");
timeElem.className = "time"; timeElem.className = "time";
timeElem.textContent = this.getDigitalTime(); timeElem.textContent = humanTime(date);
timeElem.style.fontSize = `${timeFontSize}px`; timeElem.style.fontSize = `${timeFontSize}px`;
if (this.props.color) timeElem.style.color = this.props.color; if (this.props.color) timeElem.style.color = this.props.color;
element.append(timeElem); element.append(timeElem);
@ -528,8 +532,8 @@ export default class Clock extends Item<ClockProps> {
* Generate the current date using the timezone offset stored into the properties. * Generate the current date using the timezone offset stored into the properties.
* @return The current date. * @return The current date.
*/ */
private getDate(): Date { private getOriginDate(initialDate: Date | null = null): Date {
const d = new Date(); const d = initialDate ? initialDate : new Date();
const targetTZOffset = this.props.clockTimezoneOffset * 1000; // In ms. const targetTZOffset = this.props.clockTimezoneOffset * 1000; // In ms.
const localTZOffset = d.getTimezoneOffset() * 60 * 1000; // In ms. const localTZOffset = d.getTimezoneOffset() * 60 * 1000; // In ms.
const utimestamp = d.getTime() + targetTZOffset + localTZOffset; const utimestamp = d.getTime() + targetTZOffset + localTZOffset;
@ -537,37 +541,6 @@ export default class Clock extends Item<ClockProps> {
return new Date(utimestamp); return new Date(utimestamp);
} }
/**
* Generate a date representation with the format 'd/m/Y'.
* @example 24/02/2020.
* @return Date representation.
*/
public getDigitalDate(initialDate: Date | null = null): string {
const date = initialDate || this.getDate();
// Use getDate, getDay returns the week day.
const day = padLeft(date.getDate(), 2, 0);
// The getMonth function returns the month starting by 0.
const month = padLeft(date.getMonth() + 1, 2, 0);
const year = padLeft(date.getFullYear(), 4, 0);
// Format: 'd/m/Y'.
return `${day}/${month}/${year}`;
}
/**
* Generate a time representation with the format 'hh:mm:ss'.
* @example 01:34:09.
* @return Time representation.
*/
public getDigitalTime(initialDate: Date | null = null): string {
const date = initialDate || this.getDate();
const hours = padLeft(date.getHours(), 2, 0);
const minutes = padLeft(date.getMinutes(), 2, 0);
const seconds = padLeft(date.getSeconds(), 2, 0);
return `${hours}:${minutes}:${seconds}`;
}
/** /**
* Extract a human readable city name from the timezone text. * Extract a human readable city name from the timezone text.
* @param timezone Timezone text. * @param timezone Timezone text.

View File

@ -55,24 +55,6 @@ describe("Clock item", () => {
).toBeGreaterThan(0); ).toBeGreaterThan(0);
}); });
describe("getDate function", () => {
it("should return the date with padded 0's", () => {
const expected = "01/02/0123";
const date = new Date(`02/01/0123 12:00:00`);
const digitalDate = clockInstance.getDigitalDate(date);
expect(digitalDate).toBe(expected);
});
});
describe("getTime function", () => {
it("should return the time with padded 0's when hours/minutes/seconds are less than 10", () => {
const expected = "01:02:03";
const date = new Date(`01/01/1970 ${expected}`);
const digitalTime = clockInstance.getDigitalTime(date);
expect(digitalTime).toBe(expected);
});
});
describe("getHumanTimezone function", () => { describe("getHumanTimezone function", () => {
it("should return a better timezone", () => { it("should return a better timezone", () => {
expect(clockInstance.getHumanTimezone("America/New_York")).toBe( expect(clockInstance.getHumanTimezone("America/New_York")).toBe(

View File

@ -2,9 +2,11 @@ import {
parseIntOr, parseIntOr,
stringIsEmpty, stringIsEmpty,
notEmptyStringOr, notEmptyStringOr,
padLeft, leftPad,
prefixedCssRules, prefixedCssRules,
decodeBase64 decodeBase64,
humanDate,
humanTime
} from "./lib"; } from "./lib";
describe("function parseIntOr", () => { describe("function parseIntOr", () => {
@ -40,18 +42,18 @@ describe("function notEmptyStringOr", () => {
}); });
}); });
describe("function padLeft", () => { describe("function leftPad", () => {
it("should pad properly", () => { it("should pad properly", () => {
expect(padLeft(1, 2, 0)).toBe("01"); expect(leftPad(1, 2, 0)).toBe("01");
expect(padLeft(1, 4, 0)).toBe("0001"); expect(leftPad(1, 4, 0)).toBe("0001");
expect(padLeft(1, 4, "0")).toBe("0001"); expect(leftPad(1, 4, "0")).toBe("0001");
expect(padLeft("1", 4, "0")).toBe("0001"); expect(leftPad("1", 4, "0")).toBe("0001");
expect(padLeft(10, 4, 0)).toBe("0010"); expect(leftPad(10, 4, 0)).toBe("0010");
expect(padLeft("bar", 6, "foo")).toBe("foobar"); expect(leftPad("bar", 6, "foo")).toBe("foobar");
expect(padLeft("bar", 11, "foo")).toBe("foofoofobar"); expect(leftPad("bar", 11, "foo")).toBe("foofoofobar");
expect(padLeft("bar", 4, "foo")).toBe("fbar"); expect(leftPad("bar", 4, "foo")).toBe("fbar");
expect(padLeft("bar", 2, "foo")).toBe("ar"); expect(leftPad("bar", 2, "foo")).toBe("ar");
expect(padLeft("bar", 3, "foo")).toBe("bar"); expect(leftPad("bar", 3, "foo")).toBe("bar");
}); });
}); });
@ -79,3 +81,21 @@ describe("function decodeBase64", () => {
).toEqual("<div>Box <p>Paragraph</p><hr /></div>"); ).toEqual("<div>Box <p>Paragraph</p><hr /></div>");
}); });
}); });
describe("humanDate function", () => {
it("should return the date with padded 0's", () => {
const expected = "01/02/0123";
const date = new Date(`02/01/0123 12:00:00`);
const digitalDate = humanDate(date);
expect(digitalDate).toBe(expected);
});
});
describe("humanTime function", () => {
it("should return the time with padded 0's when hours/minutes/seconds are less than 10", () => {
const expected = "01:02:03";
const date = new Date(`01/01/1970 ${expected}`);
const digitalTime = humanTime(date);
expect(digitalTime).toBe(expected);
});
});

View File

@ -82,7 +82,7 @@ export function parseBoolean(value: any): boolean {
* @param pad Text to add. * @param pad Text to add.
* @return Padded text. * @return Padded text.
*/ */
export function padLeft( export function leftPad(
value: string | number, value: string | number,
length: number, length: number,
pad: string | number = " " pad: string | number = " "
@ -277,3 +277,45 @@ export function prefixedCssRules(
export function decodeBase64(input: string): string { export function decodeBase64(input: string): string {
return decodeURIComponent(escape(window.atob(input))); return decodeURIComponent(escape(window.atob(input)));
} }
/**
* Generate a date representation with the format 'd/m/Y'.
* @param initialDate Date to be used instead of a generated one.
* @param locale Locale to use if localization is required and available.
* @example 24/02/2020.
* @return Date representation.
*/
export function humanDate(date: Date, locale: string | null = null): string {
if (locale && Intl && Intl.DateTimeFormat) {
// Format using the user locale.
const options: Intl.DateTimeFormatOptions = {
day: "2-digit",
month: "2-digit",
year: "numeric"
};
return Intl.DateTimeFormat(locale, options).format(date);
} else {
// Use getDate, getDay returns the week day.
const day = leftPad(date.getDate(), 2, 0);
// The getMonth function returns the month starting by 0.
const month = leftPad(date.getMonth() + 1, 2, 0);
const year = leftPad(date.getFullYear(), 4, 0);
// Format: 'd/m/Y'.
return `${day}/${month}/${year}`;
}
}
/**
* Generate a time representation with the format 'hh:mm:ss'.
* @param initialDate Date to be used instead of a generated one.
* @example 01:34:09.
* @return Time representation.
*/
export function humanTime(date: Date): string {
const hours = leftPad(date.getHours(), 2, 0);
const minutes = leftPad(date.getMinutes(), 2, 0);
const seconds = leftPad(date.getSeconds(), 2, 0);
return `${hours}:${minutes}:${seconds}`;
}

View File

@ -11,5 +11,5 @@
flex-direction: initial; flex-direction: initial;
justify-items: center; justify-items: center;
align-items: center; align-items: center;
user-select: none; user-select: text;
} }