MOBILE-3814 ddwtos: Use dom Promises to know if element is ready
parent
505891fa11
commit
dbc91004e4
|
@ -12,9 +12,11 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { CoreFormatTextDirective } from '@directives/format-text';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||||
import { CoreEventObserver } from '@singletons/events';
|
import { CoreEventObserver } from '@singletons/events';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
import { AddonModQuizDdwtosQuestionData } from '../component/ddwtos';
|
import { AddonModQuizDdwtosQuestionData } from '../component/ddwtos';
|
||||||
|
@ -26,7 +28,7 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
|
|
||||||
protected logger: CoreLogger;
|
protected logger: CoreLogger;
|
||||||
protected nextDragItemNo = 1;
|
protected nextDragItemNo = 1;
|
||||||
protected selectors!: AddonQtypeDdwtosQuestionCSSSelectors; // Result of cssSelectors.
|
protected selectors = new AddonQtypeDdwtosQuestionCSSSelectors(); // Result of cssSelectors.
|
||||||
protected placed: {[no: number]: number} = {}; // Map that relates drag elements numbers with drop zones numbers.
|
protected placed: {[no: number]: number} = {}; // Map that relates drag elements numbers with drop zones numbers.
|
||||||
protected selected?: HTMLElement; // Selected element (being "dragged").
|
protected selected?: HTMLElement; // Selected element (being "dragged").
|
||||||
protected resizeListener?: CoreEventObserver;
|
protected resizeListener?: CoreEventObserver;
|
||||||
|
@ -80,8 +82,8 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
* Invisible 'drag homes' are output in the question. These have the same properties as the drag items but are invisible.
|
* Invisible 'drag homes' are output in the question. These have the same properties as the drag items but are invisible.
|
||||||
* We clone these invisible elements to make the actual drag items.
|
* We clone these invisible elements to make the actual drag items.
|
||||||
*/
|
*/
|
||||||
cloneDragItems(): void {
|
async cloneDragItems(): Promise<void> {
|
||||||
const dragHomes = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.dragHomes()));
|
const dragHomes = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.dragHomes()));
|
||||||
for (let x = 0; x < dragHomes.length; x++) {
|
for (let x = 0; x < dragHomes.length; x++) {
|
||||||
this.cloneDragItemsForOneChoice(dragHomes[x]);
|
this.cloneDragItemsForOneChoice(dragHomes[x]);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +112,7 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
*/
|
*/
|
||||||
deselectDrags(): void {
|
deselectDrags(): void {
|
||||||
// Remove the selected class from all drags.
|
// Remove the selected class from all drags.
|
||||||
const drags = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.drags()));
|
const drags = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.drags()));
|
||||||
drags.forEach((drag) => {
|
drags.forEach((drag) => {
|
||||||
drag.classList.remove('selected');
|
drag.classList.remove('selected');
|
||||||
});
|
});
|
||||||
|
@ -192,19 +194,13 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
* Initialize the question.
|
* Initialize the question.
|
||||||
*/
|
*/
|
||||||
async initializer(): Promise<void> {
|
async initializer(): Promise<void> {
|
||||||
this.selectors = new AddonQtypeDdwtosQuestionCSSSelectors();
|
const container = this.container.querySelector<HTMLElement>(this.selectors.topNode());
|
||||||
|
container?.classList.add(this.readOnly ? 'readonly' : 'notreadonly');
|
||||||
const container = <HTMLElement> this.container.querySelector(this.selectors.topNode());
|
|
||||||
if (this.readOnly) {
|
|
||||||
container.classList.add('readonly');
|
|
||||||
} else {
|
|
||||||
container.classList.add('notreadonly');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the elements to be ready.
|
// Wait for the elements to be ready.
|
||||||
await this.waitForReady();
|
await this.waitForReady();
|
||||||
|
|
||||||
this.setPaddingSizesAll();
|
await this.setPaddingSizesAll();
|
||||||
this.cloneDragItems();
|
this.cloneDragItems();
|
||||||
this.initialPlaceOfDragItems();
|
this.initialPlaceOfDragItems();
|
||||||
this.makeDropZones();
|
this.makeDropZones();
|
||||||
|
@ -220,7 +216,7 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
* Initialize drag items, putting them in their initial place.
|
* Initialize drag items, putting them in their initial place.
|
||||||
*/
|
*/
|
||||||
initialPlaceOfDragItems(): void {
|
initialPlaceOfDragItems(): void {
|
||||||
const drags = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.drags()));
|
const drags = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.drags()));
|
||||||
|
|
||||||
// Add the class 'unplaced' to all elements.
|
// Add the class 'unplaced' to all elements.
|
||||||
drags.forEach((drag) => {
|
drags.forEach((drag) => {
|
||||||
|
@ -292,15 +288,15 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create all the drop zones.
|
// Create all the drop zones.
|
||||||
const drops = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.drops()));
|
const drops = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.drops()));
|
||||||
drops.forEach((drop) => {
|
drops.forEach((drop) => {
|
||||||
this.makeDropZone(drop);
|
this.makeDropZone(drop);
|
||||||
});
|
});
|
||||||
|
|
||||||
// If home answer zone is clicked, return drag home.
|
// If home answer zone is clicked, return drag home.
|
||||||
const home = <HTMLElement> this.container.querySelector(this.selectors.topNode() + ' .answercontainer');
|
const home = this.container.querySelector<HTMLElement>(this.selectors.topNode() + ' .answercontainer');
|
||||||
|
|
||||||
home.addEventListener('click', () => {
|
home?.addEventListener('click', () => {
|
||||||
const drag = this.selected;
|
const drag = this.selected;
|
||||||
if (!drag) {
|
if (!drag) {
|
||||||
// No element selected, nothing to do.
|
// No element selected, nothing to do.
|
||||||
|
@ -413,36 +409,25 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
* Postition, or reposition, all the drag items. They're placed in the right drop zone or in the home zone.
|
* Postition, or reposition, all the drag items. They're placed in the right drop zone or in the home zone.
|
||||||
*/
|
*/
|
||||||
positionDragItems(): void {
|
positionDragItems(): void {
|
||||||
const drags = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.drags()));
|
const drags = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.drags()));
|
||||||
drags.forEach((drag) => {
|
drags.forEach((drag) => {
|
||||||
this.positionDragItem(drag);
|
this.positionDragItem(drag);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for the drag items to have an offsetParent. For some reason it takes a while.
|
* Wait for the drag home items to be in DOM.
|
||||||
*
|
*
|
||||||
* @param retries Number of times this has been retried.
|
* @return Promise resolved when ready in the DOM.
|
||||||
* @return Promise resolved when ready or if it took too long to load.
|
|
||||||
*/
|
*/
|
||||||
protected async waitForReady(retries: number = 0): Promise<void> {
|
protected async waitForReady(): Promise<void> {
|
||||||
const drag = <HTMLElement | null> Array.from(this.container.querySelectorAll(this.selectors.drags()))[0];
|
await CoreDomUtils.waitToBeInDOM(this.container);
|
||||||
if (drag?.offsetParent || retries >= 10) {
|
|
||||||
// Ready or too many retries, stop.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const deferred = CoreUtils.promiseDefer<void>();
|
await CoreComponentsRegistry.waitComponentsReady(this.container, 'core-format-text', CoreFormatTextDirective);
|
||||||
|
|
||||||
setTimeout(async () => {
|
const drag = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.dragHomes()))[0];
|
||||||
try {
|
|
||||||
await this.waitForReady(retries + 1);
|
|
||||||
} finally {
|
|
||||||
deferred.resolve();
|
|
||||||
}
|
|
||||||
}, 20);
|
|
||||||
|
|
||||||
return deferred.promise;
|
await CoreDomUtils.waitToBeInDOM(drag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -452,7 +437,7 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
*/
|
*/
|
||||||
removeDragFromDrop(drag: HTMLElement): void {
|
removeDragFromDrop(drag: HTMLElement): void {
|
||||||
const placeNo = this.placed[this.getNo(drag) ?? -1];
|
const placeNo = this.placed[this.getNo(drag) ?? -1];
|
||||||
const drop = <HTMLElement> this.container.querySelector(this.selectors.dropForPlace(placeNo));
|
const drop = this.container.querySelector<HTMLElement>(this.selectors.dropForPlace(placeNo));
|
||||||
|
|
||||||
this.placeDragInDrop(null, drop);
|
this.placeDragInDrop(null, drop);
|
||||||
}
|
}
|
||||||
|
@ -473,9 +458,9 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
/**
|
/**
|
||||||
* Set the padding size for all groups.
|
* Set the padding size for all groups.
|
||||||
*/
|
*/
|
||||||
setPaddingSizesAll(): void {
|
async setPaddingSizesAll(): Promise<void> {
|
||||||
for (let groupNo = 1; groupNo <= 8; groupNo++) {
|
for (let groupNo = 1; groupNo <= 8; groupNo++) {
|
||||||
this.setPaddingSizeForGroup(groupNo);
|
await this.setPaddingSizeForGroup(groupNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,19 +469,25 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
*
|
*
|
||||||
* @param groupNo Group number.
|
* @param groupNo Group number.
|
||||||
*/
|
*/
|
||||||
setPaddingSizeForGroup(groupNo: number): void {
|
async setPaddingSizeForGroup(groupNo: number): Promise<void> {
|
||||||
const groupItems = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.dragHomesGroup(groupNo)));
|
const groupItems = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.dragHomesGroup(groupNo)));
|
||||||
|
|
||||||
if (!groupItems.length) {
|
if (!groupItems.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await CoreDomUtils.waitToBeInDOM(groupItems[0]);
|
||||||
|
|
||||||
let maxWidth = 0;
|
let maxWidth = 0;
|
||||||
let maxHeight = 0;
|
let maxHeight = 0;
|
||||||
|
|
||||||
// Find max height and width.
|
// Find max height and width.
|
||||||
groupItems.forEach((item) => {
|
groupItems.forEach((item) => {
|
||||||
item.innerHTML = CoreTextUtils.decodeHTML(item.innerHTML);
|
item.innerHTML = CoreTextUtils.decodeHTML(item.innerHTML);
|
||||||
|
});
|
||||||
|
// Wait to render in order to calculate size.
|
||||||
|
await CoreUtils.nextTick();
|
||||||
|
|
||||||
|
groupItems.forEach((item) => {
|
||||||
maxWidth = Math.max(maxWidth, Math.ceil(item.offsetWidth));
|
maxWidth = Math.max(maxWidth, Math.ceil(item.offsetWidth));
|
||||||
maxHeight = Math.max(maxHeight, Math.ceil(item.offsetHeight));
|
maxHeight = Math.max(maxHeight, Math.ceil(item.offsetHeight));
|
||||||
});
|
});
|
||||||
|
@ -507,7 +498,7 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
this.padToWidthHeight(item, maxWidth, maxHeight);
|
this.padToWidthHeight(item, maxWidth, maxHeight);
|
||||||
});
|
});
|
||||||
|
|
||||||
const dropsGroup = <HTMLElement[]> Array.from(this.container.querySelectorAll(this.selectors.dropsGroup(groupNo)));
|
const dropsGroup = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.dropsGroup(groupNo)));
|
||||||
dropsGroup.forEach((item) => {
|
dropsGroup.forEach((item) => {
|
||||||
this.padToWidthHeight(item, maxWidth + 2, maxHeight + 2);
|
this.padToWidthHeight(item, maxWidth + 2, maxHeight + 2);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue