La hora en México es (JS)
¿Que hora es en México en este mismo momento? Para eso aquí un gadget por si publicas en otros paises y quieres te contacten y deseas sepan de mera casualidad la hora en México.
El resultado será:
<script id="rendered-js" type="module">
class Mexico extends HTMLElement {
static tagName = "hr-mx";
static prefix = "hr-mx--";
static attr = {
template: "data-Mexico",
ready: "ready",
defer: "defer-hydration"
};
static onceCache = new Map();
static onReady = new Map();
static fallback = {
":not(hr-mx,:defined,[defer-hydration])": (readyPromise, node, prefix) => {
// remove from document to prevent web component init
let cloned = document.createElement(prefix + node.localName);
for (let attr of node.getAttributeNames()) {
cloned.setAttribute(attr, node.getAttribute(attr));
}
// Declarative Shadow DOM (with polyfill)
let shadowroot = node.shadowRoot;
if (!shadowroot) {
let tmpl = node.querySelector(
":scope > template:is([shadowrootmode], [shadowroot])"
);
if (tmpl) {
let mode =
tmpl.getAttribute("shadowrootmode") ||
tmpl.getAttribute("shadowroot") ||
"closed";
shadowroot = node.attachShadow({ mode }); // default is closed
shadowroot.appendChild(tmpl.content.cloneNode(true));
}
}
// Cheers to https://gist.github.com/developit/45c85e9be01e8c3f1a0ec073d600d01e
if (shadowroot) {
cloned
.attachShadow({ mode: shadowroot.mode })
.append(...shadowroot.childNodes);
}
// Keep *same* child nodes to preserve state of children (e.g. details->summary)
cloned.append(...node.childNodes);
node.replaceWith(cloned);
return readyPromise.then(() => {
// Restore original children and shadow DOM
if (cloned.shadowRoot) {
node.shadowRoot.append(...cloned.shadowRoot.childNodes);
}
node.append(...cloned.childNodes);
cloned.replaceWith(node);
});
}
};
constructor() {
super();
// Internal promises
this.ready = new Promise((resolve) => {
this.readyResolve = resolve;
});
}
// any parents of `el` that are <hr-mx> (with conditions)
static getParents(el, stopAt = false) {
let nodes = [];
while (el) {
if (el.matches && el.matches(Mexico.tagName)) {
if (stopAt && el === stopAt) {
break;
}
if (Conditions.hasConditions(el)) {
nodes.push(el);
}
}
el = el.parentNode;
}
return nodes;
}
static async ready(el, parents) {
if (!parents) {
parents = Mexico.getParents(el);
}
if (parents.length === 0) {
return;
}
let imports = await Promise.all(parents.map((p) => p.wait()));
// return innermost module import
if (imports.length) {
return imports[0];
}
}
forceFallback() {
if (window.Mexico) {
Object.assign(Mexico.fallback, window.Mexico.fallback);
}
for (let selector in Mexico.fallback) {
// Reverse here as a cheap way to get the deepest nodes first
let components = Array.from(this.querySelectorAll(selector)).reverse();
// with thanks to https://gist.github.com/cowboy/938767
for (let node of components) {
if (!node.isConnected) {
continue;
}
let parents = Mexico.getParents(node);
// must be in a leaf Mexico (not nested deep)
if (parents.length === 1) {
let p = Mexico.ready(node, parents);
Mexico.fallback[selector](p, node, Mexico.prefix);
}
}
}
}
wait() {
return this.ready;
}
async connectedCallback() {
// Only use fallback content with loading conditions
if (Conditions.hasConditions(this)) {
// Keep fallback content without initializing the components
this.forceFallback();
}
await this.hydrate();
}
getTemplates() {
return this.querySelectorAll(`template[${Mexico.attr.template}]`);
}
replaceTemplates(templates) {
// replace <template> with the live content
for (let node of templates) {
// if the template is nested inside another child <hr-mx> inside, skip
if (Mexico.getParents(node, this).length > 0) {
continue;
}
let value = node.getAttribute(Mexico.attr.template);
// get rid of the rest of the content on the Mexico
if (value === "replace") {
let children = Array.from(this.childNodes);
for (let child of children) {
this.removeChild(child);
}
this.appendChild(node.content);
break;
} else {
let html = node.innerHTML;
if (value === "once" && html) {
if (Mexico.onceCache.has(html)) {
node.remove();
return;
}
Mexico.onceCache.set(html, true);
}
node.replaceWith(node.content);
}
}
}
async hydrate() {
let conditions = [];
if (this.parentNode) {
// wait for all parents before hydrating
conditions.push(Mexico.ready(this.parentNode));
}
let attrs = Conditions.getConditions(this);
for (let condition in attrs) {
if (Conditions.map[condition]) {
conditions.push(Conditions.map[condition](attrs[condition], this));
}
}
// Loading conditions must finish before dependencies are loaded
await Promise.all(conditions);
this.replaceTemplates(this.getTemplates());
for (let fn of Mexico.onReady.values()) {
await fn.call(this, Mexico);
}
this.readyResolve();
this.setAttribute(Mexico.attr.ready, "");
// Remove [defer-hydration]
this.querySelectorAll(`[${Mexico.attr.defer}]`).forEach((node) =>
node.removeAttribute(Mexico.attr.defer)
);
}
}
class Conditions {
static map = {
visible: Conditions.visible,
idle: Conditions.idle,
interaction: Conditions.interaction,
media: Conditions.media,
"save-data": Conditions.saveData
};
static hasConditions(node) {
return Object.keys(Conditions.getConditions(node)).length > 0;
}
static getConditions(node) {
let map = {};
for (let key of Object.keys(Conditions.map)) {
if (node.hasAttribute(`on:${key}`)) {
map[key] = node.getAttribute(`on:${key}`);
}
}
return map;
}
static visible(noop, el) {
if (!("IntersectionObserver" in window)) {
// runs immediately
return;
}
return new Promise((resolve) => {
let observer = new IntersectionObserver((entries) => {
let [entry] = entries;
if (entry.isIntersecting) {
observer.unobserve(entry.target);
resolve();
}
});
observer.observe(el);
});
}
// Warning: on:idle is not very useful with other conditions as it may resolve long before.
static idle() {
let onload = new Promise((resolve) => {
if (document.readyState !== "complete") {
window.addEventListener("load", () => resolve(), { once: true });
} else {
resolve();
}
});
if (!("requestIdleCallback" in window)) {
// run immediately
return onload;
}
// both idle and onload
return Promise.all([
new Promise((resolve) => {
requestIdleCallback(() => {
resolve();
});
}),
onload
]);
}
static interaction(eventOverrides, el) {
let events = ["click", "touchstart"];
// event overrides e.g. on:interaction="mouseenter"
if (eventOverrides) {
events = (eventOverrides || "").split(",").map((entry) => entry.trim());
}
return new Promise((resolve) => {
function resolveFn(e) {
resolve();
// cleanup the other event handlers
for (let name of events) {
el.removeEventListener(name, resolveFn);
}
}
for (let name of events) {
el.addEventListener(name, resolveFn, { once: true });
}
});
}
static media(query) {
let mm = {
matches: true
};
if (query && "matchMedia" in window) {
mm = window.matchMedia(query);
}
if (mm.matches) {
return;
}
return new Promise((resolve) => {
mm.addListener((e) => {
if (e.matches) {
resolve();
}
});
});
}
static saveData(expects) {
// return early if API does not exist
if (
!("connection" in navigator) ||
navigator.connection.saveData === (expects !== "false")
) {
return;
}
// dangly promise
return new Promise(() => {});
}
}
// Should this auto define? Folks can redefine later using { component } export
if ("customElements" in window) {
window.customElements.define(Mexico.tagName, Mexico);
window.Mexico = Mexico;
}
export {
Mexico,
Mexico as component // Backwards compat only: recommend `Mexico` export
};
// TODO remove in 4.0
export const ready = Mexico.ready; // Backwards compat only: recommend `Mexico` export
</script>
<hr-mx on:visible="">
<template data-Mexico="">
<local-time><span lang="en">Time in Mexico City:</span> <span id="current-live-time"></span>
</local-time>
<script>
let options = {
timeZone: 'America/Mexico_City',
hour: 'numeric',
minute: 'numeric',
}
function updateTime() {
document.getElementById('current-live-time').textContent = (new Date()).toLocaleString([], options);
}
updateTime();
window.setInterval(updateTime, 1000);
</script>
<script></script>
</template>
</hr-mx>
Por cierto, sabias que en español es correcto escribir dos mil (separado, no junto) y es correcto veintidós (con tilde).
View on Instagram View on Flickr View on Twitter