MOBILE-2577 quiz: Fix position of drags when question contains images
parent
ab1c124713
commit
c14d7ad04a
|
@ -7,7 +7,7 @@
|
||||||
<ion-icon name="information-circle"></ion-icon>
|
<ion-icon name="information-circle"></ion-icon>
|
||||||
{{ 'core.question.howtodraganddrop' | translate }}
|
{{ 'core.question.howtodraganddrop' | translate }}
|
||||||
</p>
|
</p>
|
||||||
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
|
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text" #questiontext></core-format-text></p>
|
||||||
<core-format-text *ngIf="question.ddArea" [adaptImg]="false" [component]="component" [componentId]="componentId" [text]="question.ddArea" (afterRender)="questionRendered()"></core-format-text>
|
<core-format-text *ngIf="question.ddArea" [adaptImg]="false" [component]="component" [componentId]="componentId" [text]="question.ddArea" (afterRender)="questionRendered()"></core-format-text>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// 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 { Component, OnInit, OnDestroy, Injector, ElementRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, Injector, ElementRef, ViewChild } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreQuestionBaseComponent } from '@core/question/classes/base-question-component';
|
import { CoreQuestionBaseComponent } from '@core/question/classes/base-question-component';
|
||||||
import { AddonQtypeDdMarkerQuestion } from '../classes/ddmarker';
|
import { AddonQtypeDdMarkerQuestion } from '../classes/ddmarker';
|
||||||
|
@ -25,6 +25,7 @@ import { AddonQtypeDdMarkerQuestion } from '../classes/ddmarker';
|
||||||
templateUrl: 'addon-qtype-ddmarker.html'
|
templateUrl: 'addon-qtype-ddmarker.html'
|
||||||
})
|
})
|
||||||
export class AddonQtypeDdMarkerComponent extends CoreQuestionBaseComponent implements OnInit, OnDestroy {
|
export class AddonQtypeDdMarkerComponent extends CoreQuestionBaseComponent implements OnInit, OnDestroy {
|
||||||
|
@ViewChild('questiontext') questionTextEl: ElementRef;
|
||||||
|
|
||||||
protected element: HTMLElement;
|
protected element: HTMLElement;
|
||||||
protected questionInstance: AddonQtypeDdMarkerQuestion;
|
protected questionInstance: AddonQtypeDdMarkerQuestion;
|
||||||
|
@ -87,9 +88,11 @@ export class AddonQtypeDdMarkerComponent extends CoreQuestionBaseComponent imple
|
||||||
*/
|
*/
|
||||||
questionRendered(): void {
|
questionRendered(): void {
|
||||||
if (!this.destroyed) {
|
if (!this.destroyed) {
|
||||||
|
this.domUtils.waitForImages(this.questionTextEl.nativeElement).then(() => {
|
||||||
// Create the instance.
|
// Create the instance.
|
||||||
this.questionInstance = new AddonQtypeDdMarkerQuestion(this.loggerProvider, this.domUtils, this.textUtils, this.element,
|
this.questionInstance = new AddonQtypeDdMarkerQuestion(this.loggerProvider, this.domUtils, this.textUtils,
|
||||||
this.question, this.question.readOnly, this.dropZones);
|
this.element, this.question, this.question.readOnly, this.dropZones);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
<section ion-list *ngIf="question.text || question.text === ''">
|
<section ion-list *ngIf="question.text || question.text === ''">
|
||||||
<ion-item text-wrap class="addon-qtype-ddwtos-container">
|
<!-- Content is outside the core-loading to let the script calculate drag items position -->
|
||||||
|
<core-loading [hideUntil]="question.loaded"></core-loading>
|
||||||
|
|
||||||
|
<ion-item text-wrap class="addon-qtype-ddwtos-container" [ngClass]="{invisible: !question.loaded}">
|
||||||
<p *ngIf="!question.readOnly" class="core-info-card" icon-start>
|
<p *ngIf="!question.readOnly" class="core-info-card" icon-start>
|
||||||
<ion-icon name="information-circle"></ion-icon>
|
<ion-icon name="information-circle"></ion-icon>
|
||||||
{{ 'core.question.howtodraganddrop' | translate }}
|
{{ 'core.question.howtodraganddrop' | translate }}
|
||||||
</p>
|
</p>
|
||||||
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
|
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text" #questiontext></core-format-text></p>
|
||||||
<core-format-text *ngIf="question.answers" [component]="component" [componentId]="componentId" [text]="question.answers" (afterRender)="questionRendered()"></core-format-text>
|
<core-format-text *ngIf="question.answers" [component]="component" [componentId]="componentId" [text]="question.answers" (afterRender)="questionRendered()"></core-format-text>
|
||||||
<div class="drags"></div>
|
<div class="drags"></div>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// 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 { Component, OnInit, OnDestroy, Injector, ElementRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, Injector, ElementRef, ViewChild } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreQuestionBaseComponent } from '@core/question/classes/base-question-component';
|
import { CoreQuestionBaseComponent } from '@core/question/classes/base-question-component';
|
||||||
import { AddonQtypeDdwtosQuestion } from '../classes/ddwtos';
|
import { AddonQtypeDdwtosQuestion } from '../classes/ddwtos';
|
||||||
|
@ -25,6 +25,7 @@ import { AddonQtypeDdwtosQuestion } from '../classes/ddwtos';
|
||||||
templateUrl: 'addon-qtype-ddwtos.html'
|
templateUrl: 'addon-qtype-ddwtos.html'
|
||||||
})
|
})
|
||||||
export class AddonQtypeDdwtosComponent extends CoreQuestionBaseComponent implements OnInit, OnDestroy {
|
export class AddonQtypeDdwtosComponent extends CoreQuestionBaseComponent implements OnInit, OnDestroy {
|
||||||
|
@ViewChild('questiontext') questionTextEl: ElementRef;
|
||||||
|
|
||||||
protected element: HTMLElement;
|
protected element: HTMLElement;
|
||||||
protected questionInstance: AddonQtypeDdwtosQuestion;
|
protected questionInstance: AddonQtypeDdwtosQuestion;
|
||||||
|
@ -80,6 +81,8 @@ export class AddonQtypeDdwtosComponent extends CoreQuestionBaseComponent impleme
|
||||||
this.question.text += inputEl.outerHTML;
|
this.question.text += inputEl.outerHTML;
|
||||||
this.inputIds.push(inputEl.getAttribute('id'));
|
this.inputIds.push(inputEl.getAttribute('id'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.question.loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,11 +90,15 @@ export class AddonQtypeDdwtosComponent extends CoreQuestionBaseComponent impleme
|
||||||
*/
|
*/
|
||||||
questionRendered(): void {
|
questionRendered(): void {
|
||||||
if (!this.destroyed) {
|
if (!this.destroyed) {
|
||||||
|
this.domUtils.waitForImages(this.questionTextEl.nativeElement).then(() => {
|
||||||
// Create the instance.
|
// Create the instance.
|
||||||
this.questionInstance = new AddonQtypeDdwtosQuestion(this.loggerProvider, this.domUtils, this.element, this.question,
|
this.questionInstance = new AddonQtypeDdwtosQuestion(this.loggerProvider, this.domUtils, this.element,
|
||||||
this.question.readOnly, this.inputIds);
|
this.question, this.question.readOnly, this.inputIds);
|
||||||
|
|
||||||
this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId);
|
this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId);
|
||||||
|
|
||||||
|
this.question.loaded = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
|
||||||
import { IonicModule } from 'ionic-angular';
|
import { IonicModule } from 'ionic-angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||||
|
import { CoreComponentsModule } from '@components/components.module';
|
||||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
import { AddonQtypeDdwtosHandler } from './providers/handler';
|
import { AddonQtypeDdwtosHandler } from './providers/handler';
|
||||||
import { AddonQtypeDdwtosComponent } from './component/ddwtos';
|
import { AddonQtypeDdwtosComponent } from './component/ddwtos';
|
||||||
|
@ -27,6 +28,7 @@ import { AddonQtypeDdwtosComponent } from './component/ddwtos';
|
||||||
imports: [
|
imports: [
|
||||||
IonicModule,
|
IonicModule,
|
||||||
TranslateModule.forChild(),
|
TranslateModule.forChild(),
|
||||||
|
CoreComponentsModule,
|
||||||
CoreDirectivesModule
|
CoreDirectivesModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -296,7 +296,7 @@ export class CoreFormatTextDirective implements OnChanges {
|
||||||
this.calculateHeight();
|
this.calculateHeight();
|
||||||
|
|
||||||
// Wait for images to load and calculate the height again if needed.
|
// Wait for images to load and calculate the height again if needed.
|
||||||
this.waitForImages().then((hasImgToLoad) => {
|
this.domUtils.waitForImages(this.element).then((hasImgToLoad) => {
|
||||||
if (hasImgToLoad) {
|
if (hasImgToLoad) {
|
||||||
this.calculateHeight();
|
this.calculateHeight();
|
||||||
}
|
}
|
||||||
|
@ -628,39 +628,6 @@ export class CoreFormatTextDirective implements OnChanges {
|
||||||
this.iframeUtils.treatFrame(iframe);
|
this.iframeUtils.treatFrame(iframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for images to load.
|
|
||||||
*
|
|
||||||
* @return {Promise<boolean>} Promise resolved with a boolean: whether there was any image to load.
|
|
||||||
*/
|
|
||||||
protected waitForImages(): Promise<boolean> {
|
|
||||||
const imgs = Array.from(this.element.querySelectorAll('img')),
|
|
||||||
promises = [];
|
|
||||||
let hasImgToLoad = false;
|
|
||||||
|
|
||||||
imgs.forEach((img) => {
|
|
||||||
if (img && !img.complete) {
|
|
||||||
hasImgToLoad = true;
|
|
||||||
|
|
||||||
// Wait for image to load or fail.
|
|
||||||
promises.push(new Promise((resolve, reject): void => {
|
|
||||||
const imgLoaded = (): void => {
|
|
||||||
resolve();
|
|
||||||
img.removeEventListener('loaded', imgLoaded);
|
|
||||||
img.removeEventListener('error', imgLoaded);
|
|
||||||
};
|
|
||||||
|
|
||||||
img.addEventListener('load', imgLoaded);
|
|
||||||
img.addEventListener('error', imgLoaded);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => {
|
|
||||||
return hasImgToLoad;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function to extract YouTube Id to translate to embedded video.
|
* Convenience function to extract YouTube Id to translate to embedded video.
|
||||||
* Based on http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url
|
* Based on http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url
|
||||||
|
|
|
@ -1258,6 +1258,40 @@ export class CoreDomUtilsProvider {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for images to load.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element The element to search in.
|
||||||
|
* @return {Promise<boolean>} Promise resolved with a boolean: whether there was any image to load.
|
||||||
|
*/
|
||||||
|
waitForImages(element: HTMLElement): Promise<boolean> {
|
||||||
|
const imgs = Array.from(element.querySelectorAll('img')),
|
||||||
|
promises = [];
|
||||||
|
let hasImgToLoad = false;
|
||||||
|
|
||||||
|
imgs.forEach((img) => {
|
||||||
|
if (img && !img.complete) {
|
||||||
|
hasImgToLoad = true;
|
||||||
|
|
||||||
|
// Wait for image to load or fail.
|
||||||
|
promises.push(new Promise((resolve, reject): void => {
|
||||||
|
const imgLoaded = (): void => {
|
||||||
|
resolve();
|
||||||
|
img.removeEventListener('load', imgLoaded);
|
||||||
|
img.removeEventListener('error', imgLoaded);
|
||||||
|
};
|
||||||
|
|
||||||
|
img.addEventListener('load', imgLoaded);
|
||||||
|
img.addEventListener('error', imgLoaded);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
return hasImgToLoad;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap an HTMLElement with another element.
|
* Wrap an HTMLElement with another element.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue