Recording - fix error end of message animation

This commit is contained in:
Francis McKenzie 2021-02-15 17:25:31 +01:00
parent 914b1a1c19
commit 9dfdadbc63

View file

@ -21,7 +21,7 @@ class PromiseBuilder {
}).finally(() => { if (this.completions) { this.completions.forEach((completion) => { completion(); }); } }) }).finally(() => { if (this.completions) { this.completions.forEach((completion) => { completion(); }); } })
]); ]);
} }
async _tryHandler(handler, name, ...args) { async _tryHandler(handler, name, ...args) {
try { try {
await handler(...args); await handler(...args);
@ -30,32 +30,32 @@ class PromiseBuilder {
this.reject(e); this.reject(e);
} }
} }
promise(handler) { promise(handler) {
if (handler) { this._tryHandler(handler, "promise", this); } if (handler) { this._tryHandler(handler, "promise", this); }
return this._promise; return this._promise;
} }
onCompletion(completion) { onCompletion(completion) {
if (!this.completions) { this.completions = []; } if (!this.completions) { this.completions = []; }
this.completions.push(completion); this.completions.push(completion);
return this; return this;
} }
onTimeout(delay, timeoutHandler) { onTimeout(delay, timeoutHandler) {
const timer = () => { this._tryHandler(timeoutHandler, "timeout", this.resolve, this.reject); }; const timer = () => { this._tryHandler(timeoutHandler, "timeout", this.resolve, this.reject); };
let timeoutId = setTimeout(() => { timeoutId = null; timer(); }, delay); let timeoutId = setTimeout(() => { timeoutId = null; timer(); }, delay);
this.onCompletion(() => { clearTimeout(timeoutId); }); this.onCompletion(() => { clearTimeout(timeoutId); });
return this; return this;
} }
onFutureEvent(target, eventName, eventHandler) { onFutureEvent(target, eventName, eventHandler) {
const listener = (event) => { this._tryHandler(eventHandler, eventName, this.resolve, this.reject, event); }; const listener = (event) => { this._tryHandler(eventHandler, eventName, this.resolve, this.reject, event); };
target.addEventListener(eventName, listener, {once: true}); target.addEventListener(eventName, listener, {once: true});
this.onCompletion(() => { target.removeEventListener(eventName, listener); }); this.onCompletion(() => { target.removeEventListener(eventName, listener); });
return this; return this;
} }
onEvent(target, eventName, eventHandler) { onEvent(target, eventName, eventHandler) {
if (target === window) { if (target === window) {
eventName = eventName.toLowerCase(); eventName = eventName.toLowerCase();
@ -68,7 +68,7 @@ class PromiseBuilder {
case "complete": case "complete":
// Event already fired - run immediately // Event already fired - run immediately
this._tryHandler(eventHandler, eventName, this.resolve, this.reject); this._tryHandler(eventHandler, eventName, this.resolve, this.reject);
return this; return this;
} }
} }
} }
@ -92,22 +92,22 @@ class Animation {
element.classList.add("show"); element.classList.add("show");
} }
} else { } else {
element.classList.remove("show"); element.classList.remove("show");
} }
}; };
return new PromiseBuilder() return new PromiseBuilder()
.onTimeout(timeoutDelay, resolves()) .onTimeout(timeoutDelay, resolves())
.onEvent(element, "transitionend", resolves()) .onEvent(element, "transitionend", resolves())
.promise((promise) => { .promise((promise) => {
// Delay until element has been rendered // Delay until element has been rendered
requestAnimationFrame(() => { requestAnimationFrame(() => {
setTimeout(() => { setTimeout(() => {
animate(); animate();
}, 10); }, 10);
}); });
// Ensure animation always reaches final state // Ensure animation always reaches final state
promise.onCompletion(animate); promise.onCompletion(animate);
}); });
@ -132,13 +132,11 @@ class UIResponse {
} }
} }
let requests;
class UIRequestManager { class UIRequestManager {
static request(component, action, options) { static request(component, action, options) {
// Try for quick return // Try for quick return
if (component.unique) { if (component.unique) {
const previous = requests && requests[component.name]; const previous = this.requests && this.requests[component.name];
// Quick return if request already enqueued // Quick return if request already enqueued
if (previous && previous.action === action) { if (previous && previous.action === action) {
@ -153,7 +151,7 @@ class UIRequestManager {
return previous.response; return previous.response;
} }
} }
// Quick return if no request pending and element already added/removed // Quick return if no request pending and element already added/removed
if (!previous) { if (!previous) {
const element = this._get(component); const element = this._get(component);
@ -164,19 +162,19 @@ class UIRequestManager {
} }
} }
} }
// New request // New request
const response = new UIResponse(); const response = new UIResponse();
const request = new UIRequest(component, action, options, response); const request = new UIRequest(component, action, options, response);
// Enqueue // Enqueue
let previous; let previous;
if (component.unique) { if (component.unique) {
if (!requests) { requests = {}; } if (!this.requests) { this.requests = {}; }
previous = requests[component.name]; previous = this.requests[component.name];
requests[component.name] = request; this.requests[component.name] = request;
} }
// Execute // Execute
response.modifyingDOM = new Promise((resolve,reject) => { response.modifyingDOM = new Promise((resolve,reject) => {
const modifiedDOM = {resolve,reject}; const modifiedDOM = {resolve,reject};
@ -185,10 +183,10 @@ class UIRequestManager {
this._execute(request, previous, modifiedDOM, animated); this._execute(request, previous, modifiedDOM, animated);
}); });
}); });
return response; return response;
} }
static _get(component) { static _get(component) {
const unique = component.unique; const unique = component.unique;
if (!unique) { return null; } if (!unique) { return null; }
@ -207,16 +205,16 @@ class UIRequestManager {
} }
} }
} }
static async _execute(request, previous, modifiedDOM, animated) { static async _execute(request, previous, modifiedDOM, animated) {
try { try {
if (previous) { if (previous) {
try { await previous.response.animating; } catch (e) { /* Ignore previous success/failure */ } try { await previous.response.animating; } catch (e) { /* Ignore previous success/failure */ }
} }
const component = request.component; const component = request.component;
const options = request.options; const options = request.options;
// Get parent // Get parent
let parentElement; let parentElement;
if ("querySelector" in component.parent) { if ("querySelector" in component.parent) {
@ -228,24 +226,24 @@ class UIRequestManager {
parentElement = this._get(component.parent); parentElement = this._get(component.parent);
} }
} }
let element; let element;
// Add // Add
if (request.action === "add") { if (request.action === "add") {
element = await component.create(options); element = await component.create(options);
if (component.onUpdate) { await component.onUpdate(element, options); } if (component.onUpdate) { await component.onUpdate(element, options); }
if (component.prepend) { if (component.prepend) {
parentElement.prepend(element); parentElement.prepend(element);
} else { } else {
parentElement.appendChild(element); parentElement.appendChild(element);
} }
modifiedDOM.resolve(element); modifiedDOM.resolve(element);
if (component.onAdd) { await component.onAdd(element, options); } if (component.onAdd) { await component.onAdd(element, options); }
// Remove // Remove
} else { } else {
if (parentElement) { if (parentElement) {
@ -257,14 +255,16 @@ class UIRequestManager {
modifiedDOM.resolve(element); modifiedDOM.resolve(element);
} }
} }
animated.resolve(element); animated.resolve(element);
} catch (e) { } catch (e) {
modifiedDOM.reject(e); modifiedDOM.reject(e);
animated.reject(e); animated.reject(e);
} finally { } finally {
if (requests[request.component.name] === request) { requests[request.component.name] = null; } if (this.requests && this.requests[request.component.name] === request) {
this.requests[request.component.name] = null;
}
} }
} }
} }
@ -318,7 +318,7 @@ class Recording {
text: "Sites will be automatically added to this container as you browse in this tab" text: "Sites will be automatically added to this container as you browse in this tab"
}); });
elem.classList.add("recording"); elem.classList.add("recording");
return elem; return elem;
} }
static onAdd(elem) { return Animation.toggle(elem, true); } static onAdd(elem) { return Animation.toggle(elem, true); }
static onRemove(elem) { return Animation.toggle(elem, false); } static onRemove(elem) { return Animation.toggle(elem, false); }
@ -329,7 +329,7 @@ class Message {
static async create(options) { static async create(options) {
// Message // Message
const msgElem = document.createElement("div"); const msgElem = document.createElement("div");
// Text // Text
// Ideally we would use https://bugzilla.mozilla.org/show_bug.cgi?id=1340930 when this is available // Ideally we would use https://bugzilla.mozilla.org/show_bug.cgi?id=1340930 when this is available
msgElem.innerText = options.text; msgElem.innerText = options.text;