MOBILE-2310 course: Style changes

main
Pau Ferrer Ocaña 2018-01-23 13:00:00 +01:00 committed by Dani Palou
parent 46ad0912ea
commit ba60f2a7e3
28 changed files with 287 additions and 126 deletions

View File

@ -27,7 +27,7 @@
<p><core-format-text [text]="courseName"></core-format-text></p> <p><core-format-text [text]="courseName"></core-format-text></p>
</ion-item> </ion-item>
<ion-item text-wrap *ngIf="event.moduleIcon"> <ion-item text-wrap *ngIf="event.moduleIcon">
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start> {{event.moduleName}} <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start alt="" role="presentation" class="core-module-icon"> {{event.moduleName}}
</ion-item> </ion-item>
<ion-item> <ion-item>
<p text-wrap *ngIf="event.description"> <p text-wrap *ngIf="event.description">

View File

@ -22,7 +22,7 @@
<ion-list *ngIf="filteredEvents && filteredEvents.length"> <ion-list *ngIf="filteredEvents && filteredEvents.length">
<a ion-item text-wrap *ngFor="let event of filteredEvents" [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId"> <a ion-item text-wrap *ngFor="let event of filteredEvents" [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId">
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start> <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
<ion-icon *ngIf="!event.moduleIcon" name="{{event.icon}}" item-start></ion-icon> <ion-icon *ngIf="!event.moduleIcon" name="{{event.icon}}" item-start></ion-icon>
<h2><core-format-text [text]="event.name"></core-format-text></h2> <h2><core-format-text [text]="event.name"></core-format-text></h2>
<p>{{ event.timestart | coreToLocaleString }}</p> <p>{{ event.timestart | coreToLocaleString }}</p>

View File

@ -31,6 +31,9 @@
} }
} }
.opacity-hide { opacity: 0; }
.core-big { font-size: 115%; }
@media only screen and (min-width: 430px) { @media only screen and (min-width: 430px) {
.core-center-view .scroll-content { .core-center-view .scroll-content {
display: flex!important; display: flex!important;
@ -63,6 +66,10 @@
margin: 0; margin: 0;
} }
.item-dimmed {
opacity: 0.6;
}
.core-oauth-icon, .item.core-oauth-icon, .list .item.core-oauth-icon { .core-oauth-icon, .item.core-oauth-icon, .list .item.core-oauth-icon {
min-height: 32px; min-height: 32px;
img, .label { img, .label {
@ -82,6 +89,20 @@
font-weight: bold; font-weight: bold;
} }
.core-module-icon {
width: auto;
}
.core-button-spinner {
min-height: 44px;
min-width: 50px;
text-align: center;
.spinner {
margin-top: 8px;
}
}
// Avatar // Avatar
// ------------------------- // -------------------------
// Large centered avatar // Large centered avatar
@ -133,7 +154,8 @@ ion-avatar ion-img, ion-avatar img {
} }
/** Format Text */ /** Format Text */
core-format-text[maxHeight], *[core-format-text][maxHeight] { core-format-text[maxHeight], *[core-format-text][maxHeight],
core-format-text[ng-reflect-max-height], *[core-format-text][ng-reflect-max-height] {
display: block; display: block;
position: relative; position: relative;
width: 100%; width: 100%;
@ -148,6 +170,7 @@ core-format-text[maxHeight], *[core-format-text][maxHeight] {
// This is to allow clicks in radio/checkbox content. // This is to allow clicks in radio/checkbox content.
&.core-text-formatted { &.core-text-formatted {
cursor: pointer; cursor: pointer;
pointer-events: auto;
.core-show-more { .core-show-more {
display: none; display: none;
@ -173,19 +196,6 @@ core-format-text[maxHeight], *[core-format-text][maxHeight] {
z-index: 1001; z-index: 1001;
background-color: $white; background-color: $white;
padding-left: 10px; padding-left: 10px;
/* @todo
&:after {
@extend .ion;
content: $ionicon-var-chevron-down;
margin-left: 10px;
color: $item-icon-accessory-color;
}
*/
}
&.core-expand-in-fullview .core-show-more:after {
// content: $ionicon-var-chevron-right; @todo
} }
&:before { &:before {
@ -205,6 +215,49 @@ core-format-text[maxHeight], *[core-format-text][maxHeight] {
} }
} }
} }
&.core-expand-in-fullview {
.core-show-more {
@include svg-background-image($item-md-detail-push-svg, true);
@include padding-horizontal(null, 18px);
@include background-position(end, 0, center);
background-repeat: no-repeat;
background-size: 14px 14px;
}
}
}
.core-media-adapt-width {
max-width: 100%;
}
audio.core-media-adapt-width {
width: 100%;
}
.core-adapted-img-container {
position: relative;
display: inline-block;
}
.core-image-viewer-icon {
position: absolute;
right: 10px;
bottom: 10px;
color: $black;
border-radius: 5px;
background: rgba(255, 255, 255, .5);
text-align: center;
width: 32px;
height: 32px;
max-width: 32px;
line-height: 32px;
font-size: 24px;
ion-icon {
font-size: 24px;
}
} }
core-format-text, *[core-format-text] { core-format-text, *[core-format-text] {
@ -232,6 +285,15 @@ core-format-text, *[core-format-text] {
width: initial; width: initial;
display: inline; display: inline;
} }
.core-disable-media-adapt,
.core-disable-media-adapt .core-media-adapt-width {
max-width: none !important;
max-height: none !important;
width: initial !important;
height: initial !important;
display: inline-block !important;
}
} }
// Message item. // Message item.
@ -273,3 +335,76 @@ ion-select {
cursor: pointer; cursor: pointer;
} }
} }
// Atto styles
// -------------------------
.atto_image_preview {
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
}
.atto_image_preview_box {
max-height: 200px;
margin-bottom: 1em;
overflow: auto;
}
.editor_atto_content img {
cursor: pointer;
}
.atto_image_size {
display: inline-block;
}
.atto_image_size input[type=checkbox] {
margin-left: 1em;
margin-right: 1em;
}
.atto_image_size input[type=text] {
width: 3em;
}
.atto_image_size label {
display: inline-block;
}
.atto_image_button_text-top {
vertical-align: text-top;
margin: 0 0.5em;
}
.atto_image_button_middle {
vertical-align: middle;
margin: 0 0.5em;
}
.atto_image_button_text-bottom {
vertical-align: text-bottom;
margin: 0 0.5em;
}
.atto_image_button_text-top.img-responsive,
.atto_image_button_middle.img-responsive,
.atto_image_button_text-bottom.img-responsive {
/* If the image is display: block then linking the image to URLs won't work. */
display: inline-block;
max-width: calc(100% - 1em);
}
/*rtl:begin:ignore*/
.atto_image_button_left {
float: left;
margin: 0 0.5em 0 0;
max-width: calc(100% - 1em);
}
.atto_image_button_right {
float: right;
margin: 0 0 0 0.5em;
max-width: calc(100% - 1em);
}
/*rtl:end:ignore*/

View File

@ -27,6 +27,7 @@ core-empty-box {
left: initial; left: initial;
right: initial; right: initial;
z-index: initial; z-index: initial;
height: auto;
} }
.icon { .icon {

View File

@ -86,7 +86,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
/** /**
* List of download promises to prevent downloading the module twice at the same time. * List of download promises to prevent downloading the module twice at the same time.
* @type {Object} * @type {{[s: string]: {[s: string]: Promise<any>}}}
*/ */
protected downloadPromises: {[s: string]: {[s: string]: Promise<any>}} = {}; protected downloadPromises: {[s: string]: {[s: string]: Promise<any>}} = {};
@ -260,9 +260,9 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
/** /**
* Returns module intro files. * Returns module intro files.
* *
* @param {Object} module The module object returned by WS. * @param {any} module The module object returned by WS.
* @param {Number} courseId Course ID. * @param {number} courseId Course ID.
* @return {Promise} Promise resolved with list of intro files. * @return {Promise<any[]>} Promise resolved with list of intro files.
*/ */
getIntroFiles(module: any, courseId: number) : Promise<any[]> { getIntroFiles(module: any, courseId: number) : Promise<any[]> {
return Promise.resolve(this.getIntroFilesFromInstance(module)); return Promise.resolve(this.getIntroFilesFromInstance(module));

View File

@ -2,7 +2,7 @@
<div *ngIf="!componentInstances.courseFormat"> <div *ngIf="!componentInstances.courseFormat">
<!-- Course summary. By default we only display the course progress. --> <!-- Course summary. By default we only display the course progress. -->
<ion-list no-lines *ngIf="!componentInstances.courseSummary"> <ion-list no-lines *ngIf="!componentInstances.courseSummary">
<ion-item *ngIf="course.progress !== false"> <ion-item *ngIf="course.progress != null && course.progress >= 0">
<core-progress-bar [progress]="course.progress"></core-progress-bar> <core-progress-bar [progress]="course.progress"></core-progress-bar>
</ion-item> </ion-item>
</ion-list> </ion-list>
@ -52,7 +52,7 @@
</ion-item-divider> </ion-item-divider>
<ion-item text-wrap *ngIf="section.summary"> <ion-item text-wrap *ngIf="section.summary">
<core-format-text [text]="section.summary" maxHeight="60"></core-format-text> <core-format-text [text]="section.summary"></core-format-text>
</ion-item> </ion-item>
<ng-container *ngFor="let module of section.modules"> <ng-container *ngFor="let module of section.modules">

View File

@ -1,3 +1,3 @@
<a *ngIf="completion" class="core-completion-container" (click)="completionClicked($event)"> <a *ngIf="completion" (click)="completionClicked($event)">
<img [src]="completionImage" [alt]="completionDescription" [title]="completionDescription"> <img [src]="completionImage" [alt]="completionDescription" [title]="completionDescription">
</a> </a>

View File

@ -0,0 +1,7 @@
core-course-module-completion a {
img {
padding: 5px;
width: 30px;
vertical-align: middle;
}
}

View File

@ -1,13 +1,13 @@
<a *ngIf="module && module.visibleoncoursepage !== 0" ion-item text-wrap id="core-course-module-{{module.id}}" class="core-course-module-handler {{module.handlerData.class}}" (click)="moduleClicked($event)" [ngClass]="{'item-media': module.handlerData.icon, 'core-not-clickable': !module.handlerData.action || !module.uservisible === false, 'item-dimmed': module.visible === 0 || module.uservisible === false}" title="{{ module.handlerData.title }}"> <a *ngIf="module && module.visibleoncoursepage !== 0" ion-item text-wrap id="core-course-module-{{module.id}}" class="core-course-module-handler {{module.handlerData.class}}" (click)="moduleClicked($event)" [ngClass]="{'item-media': module.handlerData.icon, 'core-not-clickable': !module.handlerData.action || !module.uservisible === false, 'item-dimmed': module.visible === 0 || module.uservisible === false}" title="{{ module.handlerData.title }}" detail-none>
<img item-start *ngIf="module.handlerData.icon" [src]="module.handlerData.icon" alt="" role="presentation"> <img item-start *ngIf="module.handlerData.icon" [src]="module.handlerData.icon" alt="" role="presentation" class="core-module-icon">
<core-format-text [text]="module.handlerData.title"></core-format-text> <core-format-text [text]="module.handlerData.title"></core-format-text>
<div item-end *ngIf="module.uservisible !== false && ((module.handlerData.buttons && module.handlerData.buttons.length > 0) || spinner || module.completionstatus)" class="buttons core-module-buttons" [ngClass]="{'core-button-completion': module.completionstatus}"> <div float-end *ngIf="module.uservisible !== false && ((module.handlerData.buttons && module.handlerData.buttons.length > 0) || spinner || module.completionstatus)" class="buttons core-module-buttons" [ngClass]="{'core-button-completion': module.completionstatus}">
<core-course-module-completion *ngIf="module.completionstatus" [completion]="module.completionstatus" [moduleName]="module.name" (completionChanged)="completionChanged.emit()"></core-course-module-completion> <core-course-module-completion *ngIf="module.completionstatus" [completion]="module.completionstatus" [moduleName]="module.name" (completionChanged)="completionChanged.emit()"></core-course-module-completion>
<button ion-button icon-only clear *ngFor="let button of module.handlerData.buttons" [hidden]="button.hidden" (click)="buttonClicked($event, button)" class="core-animate-show-hide" [attr.aria-label]="button.label | translate"> <button ion-button icon-only clear *ngFor="let button of module.handlerData.buttons" [hidden]="button.hidden" (click)="buttonClicked($event, button)" color="dark" class="core-animate-show-hide" [attr.aria-label]="button.label | translate">
<ion-icon [name]="button.icon" [ios]="button.iosIcon || ''" [md]="button.mdIcon || ''"></ion-icon> <ion-icon [name]="button.icon" [ios]="button.iosIcon || ''" [md]="button.mdIcon || ''"></ion-icon>
</button> </button>

View File

@ -0,0 +1,30 @@
core-course-module {
a.core-course-module-handler {
align-items: flex-start;
item-inner {
padding-right: 0;
}
}
.core-module-icon {
align-items: flex-start;
}
.core-module-buttons {
display: flex;
flex-flow: row;
align-items: center;
z-index: 1;
cursor: pointer;
pointer-events: auto;
position: absolute;
right: 0;
top: 4px;
.spinner {
right: 7px;
position: absolute;
}
}
}

View File

@ -37,7 +37,6 @@ export class CoreCourseUnsupportedModulePage {
* Expand the description. * Expand the description.
*/ */
expandDescription() { expandDescription() {
this.textUtils.expandText(this.translate.instant('core.description'), this.module.description, false, this.textUtils.expandText(this.translate.instant('core.description'), this.module.description);
undefined, undefined, this.navCtrl);
} }
} }

View File

@ -293,9 +293,9 @@ export class CoreCourseHelperProvider {
/** /**
* Confirm and prefetches a list of courses. * Confirm and prefetches a list of courses.
* *
* @param {Object[]} courses List of courses to download. * @param {any[]} courses List of courses to download.
* @return {Promise} Promise resolved with true when downloaded, resolved with false if user cancels, rejected if error. * @param {Function} [onProgress] Function to call everytime a course is downloaded.
* It will send a "progress" everytime a course is downloaded or fails to download. * @return {Promise<boolean>} Resolved with true when downloaded, resolved with false if user cancels, rejected if error.
*/ */
confirmAndPrefetchCourses(courses: any[], onProgress?: (data: CoreCourseCoursesProgress) => void) : Promise<boolean> { confirmAndPrefetchCourses(courses: any[], onProgress?: (data: CoreCourseCoursesProgress) => void) : Promise<boolean> {
const siteId = this.sitesProvider.getCurrentSiteId(); const siteId = this.sitesProvider.getCurrentSiteId();

View File

@ -1224,10 +1224,9 @@ export class CoreCourseModulePrefetchDelegate {
/** /**
* Update the enabled handlers for the current site. * Update the enabled handlers for the current site.
* *
* @param {string} handles The module this handler handles, e.g. forum, label. * @param {CoreCourseModulePrefetchHandler} handler The handler to treat.
* @param {Object} handlerInfo The handler details. * @param {number} time Time this update process started.
* @param {Number} time Time this update process started. * @return {Promise<void>} Resolved when done.
* @return {Promise} Resolved when enabled, rejected when not.
*/ */
updateHandler(handler: CoreCourseModulePrefetchHandler, time: number) : Promise<void> { updateHandler(handler: CoreCourseModulePrefetchHandler, time: number) : Promise<void> {
let promise, let promise,

View File

@ -1,13 +1,18 @@
<ion-card> <ion-card>
<a ion-item text-wrap detail-none (click)="openCourse(course)" [title]="course.fullname"> <ion-item tappable text-wrap detail-none (click)="openCourse(course)" [title]="course.fullname">
<h2 float-start><core-format-text [text]="course.fullname"></core-format-text></h2> <div class="core-course-link">
<!-- Download course. --> <h2><core-format-text [text]="course.fullname"></core-format-text></h2>
<button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" float-end (click)="prefetchCourse($event)">
<ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon> <div class="core-button-spinner">
</button> <!-- Download course. -->
<!-- Download course spinner. --> <button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourse($event)">
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" class="core-course-download-spinner" float-end></ion-spinner> <ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon>
</a> </button>
<!-- Download course spinner. -->
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'"></ion-spinner>
</div>
</div>
</ion-item>
<ion-item text-wrap *ngIf="course.summary && course.summary.length"> <ion-item text-wrap *ngIf="course.summary && course.summary.length">
<p> <p>
<summary> <summary>

View File

@ -1,12 +1,34 @@
core-courses-course-progress.core-courseoverview { core-courses-course-progress {
@media (max-width: 576px) { &.core-courseoverview {
@media (max-width: 576px) {
ion-card.card {
margin: 0;
border-radius: 0;
box-shadow: none;
border-bottom: 1px solid $list-border-color;
width: 100%;
height: 100% !important;
}
}
ion-card.card { ion-card.card {
margin: 0; display: flex;
border-radius: 0; flex-direction: column;
box-shadow: none; justify-content: space-between;
border-bottom: 1px solid $list-border-color; }
width: 100%; }
height: 100% !important;
button {
z-index: 1;
}
.core-course-link {
display: flex;
align-items: center;
justify-content: space-between;
h2 {
flex-grow: 1;
} }
} }
} }

View File

@ -1,7 +1,7 @@
<ng-template #eventTemplate let-event="event"> <ng-template #eventTemplate let-event="event">
<a ion-item core-link text-wrap detail-none captureLink="true" class="core-course-module-handler item-media" [href]="event.url" [title]="event.name" [class.item-badge-right-phone]="event.action && event.action.showitemcount"> <a ion-item core-link text-wrap detail-none captureLink="true" class="core-course-module-handler item-media" [href]="event.url" [title]="event.name" [class.item-badge-right-phone]="event.action && event.action.showitemcount">
<img [src]="event.iconUrl" core-external-content alt="" role="presentation" *ngIf="event.iconUrl"> <img item-start [src]="event.iconUrl" core-external-content alt="" role="presentation" *ngIf="event.iconUrl" class="core-module-icon">
<p class="item-heading"><core-format-text [text]="event.name"></core-format-text></p> <h2><core-format-text [text]="event.name"></core-format-text></h2>
<p>{{event.timesort * 1000 | coreFormatDate:"dfmediumdate" }} <core-format-text *ngIf="showCourse" [text]="event.course.fullnamedisplay"></core-format-text></p> <p>{{event.timesort * 1000 | coreFormatDate:"dfmediumdate" }} <core-format-text *ngIf="showCourse" [text]="event.course.fullnamedisplay"></core-format-text></p>
<button ion-button clear item-end class="hidden-phone" (click)="action($event, event.action.url)" [title]="event.action.name" [disabled]="!event.action.actionable" *ngIf="event.action"> <button ion-button clear item-end class="hidden-phone" (click)="action($event, event.action.url)" [title]="event.action.name" [disabled]="!event.action.actionable" *ngIf="event.action">
{{event.action.name}} {{event.action.name}}

View File

@ -54,11 +54,11 @@
<ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option> <ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option>
</ion-select> </ion-select>
<!-- Download all courses. --> <!-- Download all courses. -->
<div *ngIf="courses[courses.selected] && courses[courses.selected].length > 1"> <div *ngIf="courses[courses.selected] && courses[courses.selected].length > 1" class="core-button-spinner" float-end>
<button *ngIf="prefetchCoursesData[courses.selected].icon && prefetchCoursesData[courses.selected].icon != 'spinner'" ion-button icon-only clear color="dark" float-end (click)="prefetchCourses()"> <button *ngIf="prefetchCoursesData[courses.selected].icon && prefetchCoursesData[courses.selected].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
<ion-icon [name]="prefetchCoursesData[courses.selected].icon"></ion-icon> <ion-icon [name]="prefetchCoursesData[courses.selected].icon"></ion-icon>
</button> </button>
<ion-spinner *ngIf="!prefetchCoursesData[courses.selected].icon || prefetchCoursesData[courses.selected].icon == 'spinner'" float-end></ion-spinner> <ion-spinner *ngIf="!prefetchCoursesData[courses.selected].icon || prefetchCoursesData[courses.selected].icon == 'spinner'"></ion-spinner>
<span float-end *ngIf="prefetchCoursesData[courses.selected].badge">{{prefetchCoursesData[courses.selected].badge}}</span> <span float-end *ngIf="prefetchCoursesData[courses.selected].badge">{{prefetchCoursesData[courses.selected].badge}}</span>
</div> </div>
</div> </div>

View File

@ -44,11 +44,9 @@ export class CoreEmulatorCaptureHelperProvider {
/** /**
* Capture media (image, audio, video). * Capture media (image, audio, video).
* *
* @param {String} type Type of media: image, audio, video. * @param {string} type Type of media: image, audio, video.
* @param {Function} successCallback Function called when media taken. * @param {any} [options] Optional options.
* @param {Function} errorCallback Function called when error or cancel. * @return {Promise<any>} Promise resolved when captured, rejected if error.
* @param {Object} [options] Optional options.
* @return {Void}
*/ */
captureMedia(type: string, options: any) : Promise<any> { captureMedia(type: string, options: any) : Promise<any> {
options = options || {}; options = options || {};

View File

@ -263,6 +263,6 @@ export class CoreLoginEmailSignupPage {
* Show authentication instructions. * Show authentication instructions.
*/ */
protected showAuthInstructions() { protected showAuthInstructions() {
this.textUtils.expandText(this.translate.instant('core.login.instructions'), this.authInstructions, true); this.textUtils.expandText(this.translate.instant('core.login.instructions'), this.authInstructions);
} }
} }

View File

@ -2,7 +2,7 @@
<ion-navbar> <ion-navbar>
<ion-title>{{ title }}</ion-title> <ion-title>{{ title }}</ion-title>
<ion-buttons end *ngIf="isModal"> <ion-buttons end>
<button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="close"></ion-icon> <ion-icon name="close"></ion-icon>
</button> </button>

View File

@ -27,14 +27,12 @@ import { IonicPage, ViewController, NavParams } from 'ionic-angular';
export class CoreViewerImagePage { export class CoreViewerImagePage {
title: string; // Page title. title: string; // Page title.
image: string; // Image URL. 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. component: string; // Component to use in external-content.
componentId: string|number; // Component ID to use in external-content. componentId: string|number; // Component ID to use in external-content.
constructor(private viewCtrl: ViewController, params: NavParams, translate: TranslateService) { constructor(private viewCtrl: ViewController, params: NavParams, translate: TranslateService) {
this.title = params.get('title') || translate.instant('core.imageviewer'); this.title = params.get('title') || translate.instant('core.imageviewer');
this.image = params.get('image'); this.image = params.get('image');
this.isModal = params.get('isModal');
this.component = params.get('component'); this.component = params.get('component');
this.componentId = params.get('componentId'); this.componentId = params.get('componentId');
} }

View File

@ -2,7 +2,7 @@
<ion-navbar> <ion-navbar>
<ion-title>{{ title }}</ion-title> <ion-title>{{ title }}</ion-title>
<ion-buttons end *ngIf="isModal"> <ion-buttons end>
<button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="close"></ion-icon> <ion-icon name="close"></ion-icon>
</button> </button>

View File

@ -27,17 +27,14 @@ import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
export class CoreViewerTextPage { export class CoreViewerTextPage {
title: string; // Page title. title: string; // Page title.
content: string; // Page content. content: string; // Page content.
isModal: boolean; // Whether it should be opened in a modal or in a page.
component: string; // Component to use in format-text. component: string; // Component to use in format-text.
componentId: string|number; // Component ID to use in format-text. componentId: string|number; // Component ID to use in format-text.
constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) { constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) {
this.title = params.get('title'); this.title = params.get('title');
this.content = params.get('content'); this.content = params.get('content');
this.isModal = params.get('isModal');
this.component = params.get('component'); this.component = params.get('component');
this.componentId = params.get('componentId'); this.componentId = params.get('componentId');
// @todo: Use replacelinebreaks param like in Ionic 1? format-text should do it by default.
} }
/** /**

View File

@ -51,7 +51,6 @@ export class CoreFormatTextDirective implements OnChanges {
// avoid this use class="inline" at the same time to use display: inline-block. // avoid this use class="inline" at the same time to use display: inline-block.
@Input() fullOnClick?: boolean|string; // Whether it should open a new page with the full contents on click. Only if @Input() fullOnClick?: boolean|string; // Whether it should open a new page with the full contents on click. Only if
// "max-height" is set and the content has been collapsed. // "max-height" is set and the content has been collapsed.
@Input() brOnFull?: boolean|string; // Whether new lines should be replaced by <br> on full view.
@Input() fullTitle?: string; // Title to use in full view. Defaults to "Description". @Input() fullTitle?: string; // Title to use in full view. Defaults to "Description".
@Output() afterRender?: EventEmitter<any>; // Called when the data is rendered. @Output() afterRender?: EventEmitter<any>; // Called when the data is rendered.
@ -148,7 +147,7 @@ export class CoreFormatTextDirective implements OnChanges {
anchor.addEventListener('click', (e: Event) => { anchor.addEventListener('click', (e: Event) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.domUtils.viewImage(imgSrc, img.getAttribute('alt'), true, this.component, this.componentId); this.domUtils.viewImage(imgSrc, img.getAttribute('alt'), this.component, this.componentId);
}); });
container.appendChild(anchor); container.appendChild(anchor);
@ -177,8 +176,10 @@ export class CoreFormatTextDirective implements OnChanges {
this.text = this.text.trim(); this.text = this.text.trim();
this.formatContents().then((div: HTMLElement) => { this.formatContents().then((div: HTMLElement) => {
this.element.innerHTML = ''; // Remove current contents. // Disable media adapt to correctly calculate the height.
this.element.classList.add('core-disable-media-adapt');
this.element.innerHTML = ''; // Remove current contents.
if (this.maxHeight && div.innerHTML != "") { if (this.maxHeight && div.innerHTML != "") {
// Move the children to the current element to be able to calculate the height. // Move the children to the current element to be able to calculate the height.
// @todo: Display the element? // @todo: Display the element?
@ -221,17 +222,15 @@ export class CoreFormatTextDirective implements OnChanges {
} }
// Open a new state with the contents. // Open a new state with the contents.
// @todo: brOnFull is needed?
this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text, this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text,
false, this.component, this.componentId); this.component, this.componentId);
}); });
} }
} else { } else {
this.domUtils.moveChildren(div, this.element); this.domUtils.moveChildren(div, this.element);
} }
this.element.classList.add('core-enabled-media-adapt'); this.element.classList.remove('core-disable-media-adapt');
this.finishRender(); this.finishRender();
}); });
} }
@ -363,16 +362,7 @@ export class CoreFormatTextDirective implements OnChanges {
* @return {number} The height of the element in pixels. When 0 is returned it means the element is not visible. * @return {number} The height of the element in pixels. When 0 is returned it means the element is not visible.
*/ */
protected getElementHeight(element: HTMLElement) : number { protected getElementHeight(element: HTMLElement) : number {
let height; return this.domUtils.getElementHeight(element) || 0;
// Disable media adapt to correctly calculate the height.
element.classList.remove('core-enabled-media-adapt');
height = this.domUtils.getElementHeight(element);
element.classList.add('core-enabled-media-adapt');
return height || 0;
} }
/** /**

View File

@ -532,7 +532,7 @@ export class CoreFilepoolProvider {
* *
* @param {string} siteId The site ID. * @param {string} siteId The site ID.
* @param {string} fileId The file ID. * @param {string} fileId The file ID.
* @param {Object} data Additional information to store about the file (timemodified, url, ...). See mmFilepoolStore schema. * @param {any} data Additional information to store about the file (timemodified, url, ...). See FILES_TABLE schema.
* @return {Promise<any>} Promise resolved on success. * @return {Promise<any>} Promise resolved on success.
*/ */
protected addFileToPool(siteId: string, fileId: string, data: any) : Promise<any> { protected addFileToPool(siteId: string, fileId: string, data: any) : Promise<any> {
@ -714,7 +714,7 @@ export class CoreFilepoolProvider {
* @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise. * @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise.
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise. * @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
* Ignored if checkSize=false. * Ignored if checkSize=false.
* @param {Object} [options] Extra options (isexternalfile, repositorytype). * @param {any} [options] Extra options (isexternalfile, repositorytype).
* @return {Promise<any>} Promise resolved when the file is downloaded. * @return {Promise<any>} Promise resolved when the file is downloaded.
*/ */
protected addToQueueIfNeeded(siteId: string, fileUrl: string, component: string, componentId?: string|number, timemodified = 0, protected addToQueueIfNeeded(siteId: string, fileUrl: string, component: string, componentId?: string|number, timemodified = 0,
@ -1571,7 +1571,7 @@ export class CoreFilepoolProvider {
* @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise. * @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise.
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise. * @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
* Ignored if checkSize=false. * Ignored if checkSize=false.
* @param {Object} [options] Extra options (isexternalfile, repositorytype). * @param {any} [options] Extra options (isexternalfile, repositorytype).
* @return {Promise<string>} Resolved with the URL to use. * @return {Promise<string>} Resolved with the URL to use.
* @description * @description
* This will return a URL pointing to the content of the requested URL. * This will return a URL pointing to the content of the requested URL.
@ -2003,7 +2003,7 @@ export class CoreFilepoolProvider {
* @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise. * @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise.
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise. * @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
* Ignored if checkSize=false. * Ignored if checkSize=false.
* @param {Object} [options] Extra options (isexternalfile, repositorytype). * @param {any} [options] Extra options (isexternalfile, repositorytype).
* @return {Promise<string>} Resolved with the URL to use. * @return {Promise<string>} Resolved with the URL to use.
* @description * @description
* This will return a URL pointing to the content of the requested URL. * This will return a URL pointing to the content of the requested URL.
@ -2045,7 +2045,7 @@ export class CoreFilepoolProvider {
* @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise. * @param {boolean} [checkSize=true] True if we shouldn't download files if their size is big, false otherwise.
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise. * @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
* Ignored if checkSize=false. * Ignored if checkSize=false.
* @param {Object} [options] Extra options (isexternalfile, repositorytype). * @param {any} [options] Extra options (isexternalfile, repositorytype).
* @return {Promise<string>} Resolved with the URL to use. * @return {Promise<string>} Resolved with the URL to use.
* @description * @description
* This will return a URL pointing to the content of the requested URL. * This will return a URL pointing to the content of the requested URL.
@ -2608,7 +2608,7 @@ export class CoreFilepoolProvider {
* Convenience function to check if a file should be downloaded before opening it. * Convenience function to check if a file should be downloaded before opening it.
* *
* The default behaviour in the app is to download first and then open the local file in the following cases: * The default behaviour in the app is to download first and then open the local file in the following cases:
* - The file is small (less than mmFilepoolDownloadThreshold). * - The file is small (less than DOWNLOAD_THRESHOLD).
* - The file cannot be streamed. * - The file cannot be streamed.
* If the file is big and can be streamed, the promise returned by this function will be rejected. * If the file is big and can be streamed, the promise returned by this function will be rejected.
*/ */

View File

@ -269,7 +269,7 @@ export class CoreDomUtilsProvider {
* Returns height or width of an element. * Returns height or width of an element.
* *
* @param {any} element DOM element to measure. * @param {any} element DOM element to measure.
* @param {boolean} [isWidth] Whether to get width or height. * @param {boolean} [getWidth] Whether to get width or height.
* @param {boolean} [usePadding] Whether to use padding to calculate the measure. * @param {boolean} [usePadding] Whether to use padding to calculate the measure.
* @param {boolean} [useMargin] Whether to use margin to calculate the measure. * @param {boolean} [useMargin] Whether to use margin to calculate the measure.
* @param {boolean} [useBorder] Whether to use borders to calculate the measure. * @param {boolean} [useBorder] Whether to use borders to calculate the measure.
@ -852,13 +852,10 @@ export class CoreDomUtilsProvider {
* *
* @param {string} image URL of the image. * @param {string} image URL of the image.
* @param {string} title Title of the page or modal. * @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} [component] Component to link the image to if needed.
* @param {string|number} [componentId] An ID to use in conjunction with the component. * @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, viewImage(image: string, title?: string, component?: string, componentId?: string|number) : void {
navCtrl?: NavController) : void {
if (image) { if (image) {
let params: any = { let params: any = {
title: title, title: title,
@ -867,16 +864,8 @@ export class CoreDomUtilsProvider {
componentId: componentId componentId: componentId
}; };
if (isModal) { let modal = this.modalCtrl.create('CoreViewerImagePage', params);
// Open a modal with the contents. modal.present();
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);
}
} }
} }

View File

@ -248,13 +248,10 @@ export class CoreTextUtilsProvider {
* *
* @param {string} title Title of the new state. * @param {string} title Title of the new state.
* @param {string} text Content of the text to be expanded. * @param {string} text Content of the text to be expanded.
* @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 embedded files to. * @param {string} [component] Component to link the embedded files to.
* @param {string|number} [componentId] An ID to use in conjunction with the component. * @param {string|number} [componentId] An ID to use in conjunction with the component.
* @param {NavController} [navCtrl] The NavController instance to use. Required if isModal is false.
*/ */
expandText(title: string, text: string, isModal?: boolean, component?: string, componentId?: string|number, expandText(title: string, text: string, component?: string, componentId?: string|number) : void {
navCtrl?: NavController) : void {
if (text.length > 0) { if (text.length > 0) {
let params: any = { let params: any = {
title: title, title: title,
@ -263,18 +260,12 @@ export class CoreTextUtilsProvider {
componentId: componentId componentId: componentId
}; };
if (isModal) { // Open a modal with the contents.
// Open a modal with the contents. params.isModal = true;
params.isModal = true;
let modal = this.modalCtrl.create('CoreViewerTextPage', params); let modal = this.modalCtrl.create('CoreViewerTextPage', params);
modal.present(); modal.present();
} else if (navCtrl) {
// Open a new page with the contents.
navCtrl.push('CoreViewerTextPage', params);
}
} }
} }
/** /**

View File

@ -170,11 +170,11 @@ export class CoreUtilsProvider {
* Blocks leaving a view. This function should be used in views that want to perform a certain action before * Blocks leaving a view. This function should be used in views that want to perform a certain action before
* leaving (usually, ask the user if he wants to leave because some data isn't saved). * leaving (usually, ask the user if he wants to leave because some data isn't saved).
* *
* @param {Object} scope View's scope. * @param {object} scope View's scope.
* @param {Function} canLeaveFn Function called when the user wants to leave the view. Must return a promise * @param {Function} canLeaveFn Function called when the user wants to leave the view. Must return a promise
* resolved if the view should be left, rejected if the user should stay in the view. * resolved if the view should be left, rejected if the user should stay in the view.
* @param {Object} [currentView] Current view. Defaults to $ionicHistory.currentView(). * @param {object} [currentView] Current view. Defaults to $ionicHistory.currentView().
* @return {Object} Object with: * @return {object} Object with:
* -back: Original back function. * -back: Original back function.
* -unblock: Function to unblock. It is called automatically when scope is destroyed. * -unblock: Function to unblock. It is called automatically when scope is destroyed.
*/ */