diff --git a/src/core/courses/components/overview-events/overview-events.ts b/src/core/courses/components/overview-events/overview-events.ts
index fd566c4fa..df8db57cb 100644
--- a/src/core/courses/components/overview-events/overview-events.ts
+++ b/src/core/courses/components/overview-events/overview-events.ts
@@ -17,6 +17,7 @@ import { CoreSitesProvider } from '../../../../providers/sites';
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
import { CoreUtilsProvider } from '../../../../providers/utils/utils';
+import { CoreCourseProvider } from '../../../course/providers/course';
import * as moment from 'moment';
/**
@@ -41,7 +42,8 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
future: any[] = [];
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();
}
@@ -73,7 +75,7 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
return start <= event.timesort;
}).map((event) => {
- // @todo: event.iconUrl = this.courseProvider.getModuleIconSrc(event.icon.component);
+ event.iconUrl = this.courseProvider.getModuleIconSrc(event.icon.component);
return event;
});
}
diff --git a/src/core/viewer/pages/image/image.html b/src/core/viewer/pages/image/image.html
new file mode 100644
index 000000000..3783c5d38
--- /dev/null
+++ b/src/core/viewer/pages/image/image.html
@@ -0,0 +1,14 @@
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
diff --git a/src/core/viewer/pages/image/image.module.ts b/src/core/viewer/pages/image/image.module.ts
new file mode 100644
index 000000000..62cd6dff0
--- /dev/null
+++ b/src/core/viewer/pages/image/image.module.ts
@@ -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 {}
diff --git a/src/core/viewer/pages/image/image.ts b/src/core/viewer/pages/image/image.ts
new file mode 100644
index 000000000..6253ddbba
--- /dev/null
+++ b/src/core/viewer/pages/image/image.ts
@@ -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();
+ }
+}
\ No newline at end of file
diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts
index 119985bd8..289bfb23e 100644
--- a/src/directives/format-text.ts
+++ b/src/directives/format-text.ts
@@ -125,15 +125,35 @@ export class CoreFormatTextDirective implements OnChanges {
if (imgWidth > elWidth) {
// The image has been adapted, add an anchor to view it in full size.
- let imgSrc = this.textUtils.escapeHTML(img.getAttribute('src')),
- label = this.textUtils.escapeHTML(this.translate.instant('core.openfullimage'));
-
- // @todo: Implement image viewer. Maybe we can add the listener here directly?
- container.innerHTML += '';
+ this.addMagnifyingGlass(container, img);
}
}
+ /**
+ * 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 = '';
+
+ 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.
*/
diff --git a/src/providers/utils/dom.ts b/src/providers/utils/dom.ts
index 92b860324..3a3edbbb6 100644
--- a/src/providers/utils/dom.ts
+++ b/src/providers/utils/dom.ts
@@ -13,7 +13,8 @@
// limitations under the License.
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 { CoreTextUtilsProvider } from './text';
import { CoreAppProvider } from '../app';
@@ -33,7 +34,8 @@ export class CoreDomUtilsProvider {
constructor(private translate: TranslateService, private loadingCtrl: LoadingController, private toastCtrl: ToastController,
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.
@@ -840,6 +842,40 @@ export class CoreDomUtilsProvider {
(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.
*