MOBILE-2310 core: Implement image viewer
parent
cbc9bc715c
commit
764309edd7
|
@ -17,6 +17,7 @@ import { CoreSitesProvider } from '../../../../providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||||
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
|
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
|
||||||
import { CoreUtilsProvider } from '../../../../providers/utils/utils';
|
import { CoreUtilsProvider } from '../../../../providers/utils/utils';
|
||||||
|
import { CoreCourseProvider } from '../../../course/providers/course';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +42,8 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
|
||||||
future: any[] = [];
|
future: any[] = [];
|
||||||
|
|
||||||
constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider,
|
constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider,
|
||||||
private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider) {
|
private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider,
|
||||||
|
private courseProvider: CoreCourseProvider) {
|
||||||
this.loadMore = new EventEmitter();
|
this.loadMore = new EventEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
|
||||||
|
|
||||||
return start <= event.timesort;
|
return start <= event.timesort;
|
||||||
}).map((event) => {
|
}).map((event) => {
|
||||||
// @todo: event.iconUrl = this.courseProvider.getModuleIconSrc(event.icon.component);
|
event.iconUrl = this.courseProvider.getModuleIconSrc(event.icon.component);
|
||||||
return event;
|
return event;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<ion-header>
|
||||||
|
<ion-navbar>
|
||||||
|
<ion-title>{{ title }}</ion-title>
|
||||||
|
|
||||||
|
<ion-buttons end *ngIf="isModal">
|
||||||
|
<button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||||
|
<ion-icon name="close"></ion-icon>
|
||||||
|
</button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-navbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content padding>
|
||||||
|
<img [src]="image" alt="{{ title }}" core-external-content [component]="component" [componentId]="componentId">
|
||||||
|
</ion-content>
|
|
@ -0,0 +1,31 @@
|
||||||
|
// (C) Copyright 2015 Martin Dougiamas
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { IonicPageModule } from 'ionic-angular';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CoreViewerImagePage } from './image';
|
||||||
|
import { CoreDirectivesModule } from '../../../../directives/directives.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CoreViewerImagePage
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CoreDirectivesModule,
|
||||||
|
IonicPageModule.forChild(CoreViewerImagePage),
|
||||||
|
TranslateModule.forChild()
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CoreViewerImagePageModule {}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// (C) Copyright 2015 Martin Dougiamas
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { IonicPage, ViewController, NavParams } from 'ionic-angular';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page to view an image. If opened as a modal, it will have a button to close the modal.
|
||||||
|
*/
|
||||||
|
@IonicPage({segment: 'core-viewer-image'})
|
||||||
|
@Component({
|
||||||
|
selector: 'page-core-viewer-image',
|
||||||
|
templateUrl: 'image.html',
|
||||||
|
})
|
||||||
|
export class CoreViewerImagePage {
|
||||||
|
title: string; // Page title.
|
||||||
|
image: string; // Image URL.
|
||||||
|
isModal: boolean; // Whether it should be opened in a modal or in a page.
|
||||||
|
component: string; // Component to use in external-content.
|
||||||
|
componentId: string|number; // Component ID to use in external-content.
|
||||||
|
|
||||||
|
constructor(private viewCtrl: ViewController, params: NavParams, translate: TranslateService) {
|
||||||
|
this.title = params.get('title') || translate.instant('core.imageviewer');
|
||||||
|
this.image = params.get('image');
|
||||||
|
this.isModal = params.get('isModal');
|
||||||
|
this.component = params.get('component');
|
||||||
|
this.componentId = params.get('componentId');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close modal.
|
||||||
|
*/
|
||||||
|
closeModal() : void {
|
||||||
|
this.viewCtrl.dismiss();
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,15 +125,35 @@ export class CoreFormatTextDirective implements OnChanges {
|
||||||
|
|
||||||
if (imgWidth > elWidth) {
|
if (imgWidth > elWidth) {
|
||||||
// The image has been adapted, add an anchor to view it in full size.
|
// The image has been adapted, add an anchor to view it in full size.
|
||||||
let imgSrc = this.textUtils.escapeHTML(img.getAttribute('src')),
|
this.addMagnifyingGlass(container, img);
|
||||||
label = this.textUtils.escapeHTML(this.translate.instant('core.openfullimage'));
|
|
||||||
|
|
||||||
// @todo: Implement image viewer. Maybe we can add the listener here directly?
|
|
||||||
container.innerHTML += '<a href="#" class="core-image-viewer-icon" core-image-viewer img="' + imgSrc +
|
|
||||||
'" aria-label="' + label + '"><ion-icon name="search"></ion-icon></a>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a magnifying glass icon to view an image at full size.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} container The container of the image.
|
||||||
|
* @param {HTMLElement} img The image.
|
||||||
|
*/
|
||||||
|
addMagnifyingGlass(container: HTMLElement, img: HTMLElement) : void {
|
||||||
|
let imgSrc = this.textUtils.escapeHTML(img.getAttribute('src')),
|
||||||
|
label = this.textUtils.escapeHTML(this.translate.instant('core.openfullimage')),
|
||||||
|
anchor = document.createElement('a');
|
||||||
|
|
||||||
|
anchor.classList.add('core-image-viewer-icon');
|
||||||
|
anchor.setAttribute('aria-label', label);
|
||||||
|
// Add an ion-icon item to apply the right styles, but the ion-icon component won't be executed.
|
||||||
|
anchor.innerHTML = '<ion-icon name="search" class="icon icon-md ion-md-search"></ion-icon>';
|
||||||
|
|
||||||
|
anchor.addEventListener('click', (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.domUtils.viewImage(imgSrc, img.getAttribute('alt'), true, this.component, this.componentId);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(anchor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the rendering, displaying the element again and calling afterRender.
|
* Finish the rendering, displaying the element again and calling afterRender.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { LoadingController, Loading, ToastController, Toast, AlertController, Alert, Platform, Content } from 'ionic-angular';
|
import { LoadingController, Loading, ToastController, Toast, AlertController, Alert, Platform, Content,
|
||||||
|
NavController, ModalController } from 'ionic-angular';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreTextUtilsProvider } from './text';
|
import { CoreTextUtilsProvider } from './text';
|
||||||
import { CoreAppProvider } from '../app';
|
import { CoreAppProvider } from '../app';
|
||||||
|
@ -33,7 +34,8 @@ export class CoreDomUtilsProvider {
|
||||||
|
|
||||||
constructor(private translate: TranslateService, private loadingCtrl: LoadingController, private toastCtrl: ToastController,
|
constructor(private translate: TranslateService, private loadingCtrl: LoadingController, private toastCtrl: ToastController,
|
||||||
private alertCtrl: AlertController, private textUtils: CoreTextUtilsProvider, private appProvider: CoreAppProvider,
|
private alertCtrl: AlertController, private textUtils: CoreTextUtilsProvider, private appProvider: CoreAppProvider,
|
||||||
private platform: Platform, private configProvider: CoreConfigProvider, private urlUtils: CoreUrlUtilsProvider) {}
|
private platform: Platform, private configProvider: CoreConfigProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||||
|
private modalCtrl: ModalController) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a message with core-format-text if the message contains HTML tags.
|
* Wraps a message with core-format-text if the message contains HTML tags.
|
||||||
|
@ -840,6 +842,40 @@ export class CoreDomUtilsProvider {
|
||||||
(el.tagName.toLowerCase() == 'input' && this.inputSupportKeyboard.indexOf(el.type) != -1));
|
(el.tagName.toLowerCase() == 'input' && this.inputSupportKeyboard.indexOf(el.type) != -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View an image in a new page or modal.
|
||||||
|
*
|
||||||
|
* @param {string} image URL of the image.
|
||||||
|
* @param {string} title Title of the page or modal.
|
||||||
|
* @param {boolean} [isModal] Whether it should be opened in a modal (true) or in a new page (false).
|
||||||
|
* @param {string} [component] Component to link the image to if needed.
|
||||||
|
* @param {string|number} [componentId] An ID to use in conjunction with the component.
|
||||||
|
* @param {NavController} [navCtrl] The NavController instance to use.
|
||||||
|
*/
|
||||||
|
viewImage(image: string, title?: string, isModal?: boolean, component?: string, componentId?: string|number,
|
||||||
|
navCtrl?: NavController) : void {
|
||||||
|
if (image) {
|
||||||
|
let params: any = {
|
||||||
|
title: title,
|
||||||
|
image: image,
|
||||||
|
component: component,
|
||||||
|
componentId: componentId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isModal) {
|
||||||
|
// Open a modal with the contents.
|
||||||
|
params.isModal = true;
|
||||||
|
|
||||||
|
let modal = this.modalCtrl.create('CoreViewerImagePage', params);
|
||||||
|
modal.present();
|
||||||
|
} else if (navCtrl) {
|
||||||
|
// Open a new page with the contents.
|
||||||
|
navCtrl.push('CoreViewerImagePage', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap an HTMLElement with another element.
|
* Wrap an HTMLElement with another element.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue