MOBILE-2309 contentlinks: Implement some handlers and handle links

main
Dani Palou 2018-01-23 11:26:21 +01:00
parent b3d0457540
commit 3cb62c748c
19 changed files with 551 additions and 54 deletions

View File

@ -58,6 +58,7 @@ import { CoreFileUploaderModule } from '../core/fileuploader/fileuploader.module
import { CoreSharedFilesModule } from '../core/sharedfiles/sharedfiles.module';
import { CoreCourseModule } from '../core/course/course.module';
import { CoreSiteHomeModule } from '../core/sitehome/sitehome.module';
import { CoreContentLinksModule } from '../core/contentlinks/contentlinks.module';
// Addon modules.
import { AddonCalendarModule } from '../addon/calendar/calendar.module';
@ -94,6 +95,7 @@ export function createTranslateLoader(http: HttpClient) {
CoreSharedFilesModule,
CoreCourseModule,
CoreSiteHomeModule,
CoreContentLinksModule,
AddonCalendarModule
],
bootstrap: [IonicApp],

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { NavController } from 'ionic-angular';
import { CoreContentLinksAction } from '../providers/delegate';
import { CoreContentLinksHandlerBase } from './base-handler';
import { CoreSitesProvider } from '../../../providers/sites';
@ -64,7 +65,7 @@ export class CoreContentLinksModuleGradeHandler extends CoreContentLinksHandlerB
courseId = courseId || params.courseid || params.cid;
return [{
action: (siteId) : void => {
action: (siteId, navCtrl?) : void => {
// Check if userid is the site's current user.
const modal = this.domUtils.showModalLoading();
this.sitesProvider.getSite(siteId).then((site) => {
@ -73,7 +74,7 @@ export class CoreContentLinksModuleGradeHandler extends CoreContentLinksHandlerB
this.courseHelper.navigateToModule(parseInt(params.id, 10), siteId, courseId);
} else if (this.canReview) {
// Use the goToReview function.
this.goToReview(url, params, courseId, siteId);
this.goToReview(url, params, courseId, siteId, navCtrl);
} else {
// Not current user and cannot review it in the app, open it in browser.
site.openInBrowserWithAutoLogin(url);
@ -91,10 +92,11 @@ export class CoreContentLinksModuleGradeHandler extends CoreContentLinksHandlerB
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} courseId Course ID related to the URL.
* @param {string} siteId List of sites the URL belongs to.
* @param {string} siteId Site to use.
* @param {NavController} [navCtrl] Nav Controller to use to navigate.
* @return {Promise<any>} Promise resolved when done.
*/
protected goToReview(url: string, params: any, courseId: number, siteId: string) : Promise<any> {
protected goToReview(url: string, params: any, courseId: number, siteId: string, navCtrl?: NavController) : Promise<any> {
// This function should be overridden.
return Promise.resolve();
}

View File

@ -55,7 +55,7 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB
courseId = courseId || params.courseid || params.cid;
return [{
action: (siteId) => {
action: (siteId, navCtrl?) => {
this.courseHelper.navigateToModule(parseInt(params.id, 10), siteId, courseId);
}
}];

View File

@ -80,7 +80,7 @@ export class CoreContentLinksChooseSitePage implements OnInit {
* @param {string} siteId Site ID.
*/
siteClicked(siteId: string) : void {
this.action.action(siteId);
this.action.action(siteId, this.navCtrl);
}
/**

View File

@ -13,6 +13,7 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreLoggerProvider } from '../../../providers/logger';
import { CoreSitesProvider } from '../../../providers/sites';
import { CoreUrlUtilsProvider } from '../../../providers/utils/url';
@ -115,8 +116,9 @@ export interface CoreContentLinksAction {
* Action to perform when the link is clicked.
*
* @param {string} siteId The site ID.
* @param {NavController} [navCtrl] Nav Controller to use to navigate.
*/
action(siteId: string) : void;
action(siteId: string, navCtrl?: NavController) : void;
};
/**

View File

@ -202,9 +202,10 @@ export class CoreContentLinksHelperProvider {
* @param {string} url URL to handle.
* @param {string} [username] Username related with the URL. E.g. in 'http://myuser@m.com', url would be 'http://m.com' and
* the username 'myuser'. Don't use it if you don't want to filter by username.
* @param {NavController} [navCtrl] Nav Controller to use to navigate.
* @return {Promise<boolean>} Promise resolved with a boolean: true if URL was treated, false otherwise.
*/
handleLink(url: string, username?: string) : Promise<boolean> {
handleLink(url: string, username?: string, navCtrl?: NavController) : Promise<boolean> {
// Check if the link should be treated by some component/addon.
return this.contentLinksDelegate.getActionsFor(url, undefined, username).then((actions) => {
const action = this.getFirstValidAction(actions);
@ -212,18 +213,18 @@ export class CoreContentLinksHelperProvider {
if (!this.sitesProvider.isLoggedIn()) {
// No current site. Perform the action if only 1 site found, choose the site otherwise.
if (action.sites.length == 1) {
action.action(action.sites[0]);
action.action(action.sites[0], navCtrl);
} else {
this.goToChooseSite(url);
}
} else if (action.sites.length == 1 && action.sites[0] == this.sitesProvider.getCurrentSiteId()) {
// Current site.
action.action(action.sites[0]);
action.action(action.sites[0], navCtrl);
} else {
// Not current site or more than one site. Ask for confirmation.
this.domUtils.showConfirm(this.translate.instant('core.contentlinks.confirmurlothersite')).then(() => {
if (action.sites.length == 1) {
action.action(action.sites[0]);
action.action(action.sites[0], navCtrl);
} else {
this.goToChooseSite(url);
}

View File

@ -42,7 +42,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
@Input() course: any; // The course to render.
@Input() sections: any[]; // List of course sections.
@Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
@Input() initialSectionId: number; // The section to load first.
@Input() initialSectionId?: number; // The section to load first (by ID).
@Input() initialSectionNumber?: number; // The section to load first (by number).
@Output() completionChanged?: EventEmitter<void>; // Will emit an event when any module completion changes.
// Get the containers where to inject dynamic components. We use a setter because they might be inside a *ngIf.
@ -144,11 +145,11 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
if (changes.sections && this.sections) {
if (!this.selectedSection) {
// There is no selected section yet, calculate which one to load.
if (this.initialSectionId) {
if (this.initialSectionId || this.initialSectionNumber) {
// We have an input indicating the section ID to load. Search the section.
for (let i = 0; i < this.sections.length; i++) {
let section = this.sections[i];
if (section.id == this.initialSectionId) {
if (section.id == this.initialSectionId || section.section == this.initialSectionNumber) {
this.loaded = true;
this.sectionChanged(section);
break;
@ -229,6 +230,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
this.componentInstances[type].course = this.course;
this.componentInstances[type].sections = this.sections;
this.componentInstances[type].initialSectionId = this.initialSectionId;
this.componentInstances[type].initialSectionNumber = this.initialSectionNumber;
this.componentInstances[type].downloadEnabled = this.downloadEnabled;
this.cdr.detectChanges(); // The instances are used in ngIf, tell Angular that something has changed.

View File

@ -21,6 +21,6 @@
<a aria-selected="true">{{ 'core.course.contents' | translate }}</a>
<a *ngFor="let handler of courseHandlers">{{ handler.data.title || translate }}</a>
</div>
<core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
<core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
</core-loading>
</ion-content>

View File

@ -40,6 +40,7 @@ export class CoreCourseSectionPage implements OnDestroy {
course: any;
sections: any[];
sectionId: number;
sectionNumber: number;
courseHandlers: CoreCoursesHandlerToDisplay[];
dataLoaded: boolean;
downloadEnabled: boolean;
@ -59,6 +60,7 @@ export class CoreCourseSectionPage implements OnDestroy {
sitesProvider: CoreSitesProvider, private navCtrl: NavController) {
this.course = navParams.get('course');
this.sectionId = navParams.get('sectionId');
this.sectionNumber = navParams.get('sectionNumber');
// Get the title to display. We dont't have sections yet.
this.title = courseFormatDelegate.getCourseTitle(this.course);

View File

@ -13,11 +13,13 @@
// limitations under the License.
import { Component, Input, Output, OnChanges, EventEmitter, SimpleChange } from '@angular/core';
import { NavController } from 'ionic-angular';
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 { CoreContentLinksHelperProvider } from '../../../contentlinks/providers/helper';
import * as moment from 'moment';
/**
@ -41,9 +43,9 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
next30Days: any[] = [];
future: any[] = [];
constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider,
constructor(private navCtrl: NavController, private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider,
private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider,
private courseProvider: CoreCourseProvider) {
private courseProvider: CoreCourseProvider, private contentLinksHelper: CoreContentLinksHelperProvider) {
this.loadMore = new EventEmitter();
}
@ -100,9 +102,6 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
loadMoreEvents() {
this.loadingMore = true;
this.loadMore.emit();
// this.loadMore().finally(function() {
// scope.loadingMore = false;
// });
}
/**
@ -119,19 +118,14 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
url = this.textUtils.decodeHTMLEntities(url);
let modal = this.domUtils.showModalLoading();
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url).finally(() => {
this.contentLinksHelper.handleLink(url, undefined, this.navCtrl).then((treated) => {
if (!treated) {
return this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url);
}
}).finally(() => {
modal.dismiss();
});
// @todo
// $mmContentLinksHelper.handleLink(url).then((treated) => {
// if (!treated) {
// return this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url);
// }
// }).finally(() => {
// modal.dismiss();
// });
return false;
}
}

View File

@ -17,7 +17,11 @@ import { CoreCoursesProvider } from './providers/courses';
import { CoreCoursesMainMenuHandler } from './providers/mainmenu-handler';
import { CoreCoursesMyOverviewProvider } from './providers/my-overview';
import { CoreCoursesDelegate } from './providers/delegate';
import { CoreCoursesCourseLinkHandler } from './providers/course-link-handler';
import { CoreCoursesIndexLinkHandler } from './providers/courses-index-link-handler';
import { CoreCoursesMyOverviewLinkHandler } from './providers/my-overview-link-handler';
import { CoreMainMenuDelegate } from '../mainmenu/providers/delegate';
import { CoreContentLinksDelegate } from '../contentlinks/providers/delegate';
@NgModule({
declarations: [],
@ -27,12 +31,21 @@ import { CoreMainMenuDelegate } from '../mainmenu/providers/delegate';
CoreCoursesProvider,
CoreCoursesMainMenuHandler,
CoreCoursesMyOverviewProvider,
CoreCoursesDelegate
CoreCoursesDelegate,
CoreCoursesCourseLinkHandler,
CoreCoursesIndexLinkHandler,
CoreCoursesMyOverviewLinkHandler
],
exports: []
})
export class CoreCoursesModule {
constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: CoreCoursesMainMenuHandler) {
constructor(mainMenuDelegate: CoreMainMenuDelegate, contentLinksDelegate: CoreContentLinksDelegate,
mainMenuHandler: CoreCoursesMainMenuHandler, courseLinkHandler: CoreCoursesCourseLinkHandler,
indexLinkHandler: CoreCoursesIndexLinkHandler, myOverviewLinkHandler: CoreCoursesMyOverviewLinkHandler) {
mainMenuDelegate.registerHandler(mainMenuHandler);
contentLinksDelegate.registerHandler(courseLinkHandler);
contentLinksDelegate.registerHandler(indexLinkHandler);
contentLinksDelegate.registerHandler(myOverviewLinkHandler);
}
}

View File

@ -0,0 +1,267 @@
// (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 { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreSitesProvider } from '../../../providers/sites';
import { CoreDomUtilsProvider } from '../../../providers/utils/dom';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '../../contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreCourseProvider } from '../../course/providers/course';
import { CoreCoursesProvider } from './courses';
/**
* Handler to treat links to course view or enrol (except site home).
*/
@Injectable()
export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
name = 'CoreCoursesCourseLinkHandler';
pattern = /((\/enrol\/index\.php)|(\/course\/enrol\.php)|(\/course\/view\.php)).*([\?\&]id=\d+)/;
protected waitStart = 0;
constructor(private sitesProvider: CoreSitesProvider, private coursesProvider: CoreCoursesProvider,
private loginHelper: CoreLoginHelperProvider, private domUtils: CoreDomUtilsProvider,
private translate: TranslateService, private courseProvider: CoreCourseProvider) {
super();
}
/**
* Get the list of actions for a link (url).
*
* @param {string[]} siteIds List of sites the URL belongs to.
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
*/
getActions(siteIds: string[], url: string, params: any, courseId?: number) :
CoreContentLinksAction[]|Promise<CoreContentLinksAction[]> {
courseId = parseInt(params.id, 10);
let sectionId = params.sectionid ? parseInt(params.sectionid, 10) : null,
sectionNumber = typeof params.section != 'undefined' ? parseInt(params.section, 10) : NaN,
pageParams: any = {
course: {id: courseId},
sectionId: sectionId || null
};
if (!isNaN(sectionNumber)) {
pageParams.sectionNumber = sectionNumber;
}
return [{
action: (siteId, navCtrl?) => {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (siteId == this.sitesProvider.getCurrentSiteId()) {
this.actionEnrol(courseId, url, pageParams).catch(() => {
// Ignore errors.
});
} else {
// Use redirect to make the course the new history root (to avoid "loops" in history).
this.loginHelper.redirect('CoreCourseSectionPage', pageParams, siteId);
}
}
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
* If not defined, defaults to true.
*
* @param {string} siteId The site ID.
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
*/
isEnabled(siteId: string, url: string, params: any, courseId?: number) : boolean|Promise<boolean> {
courseId = parseInt(params.id, 10);
if (!courseId) {
return false;
}
// Get the course id of Site Home.
return this.sitesProvider.getSiteHomeId(siteId).then((siteHomeId) => {
return courseId != siteHomeId;
});
}
/**
* Action to perform when an enrol link is clicked.
*
* @param {number} courseId Course ID.
* @param {string} url Treated URL.
* @param {any} pageParams Params to send to the new page.
* @return {Promise<any>} Promise resolved when done.
*/
protected actionEnrol(courseId: number, url: string, pageParams: any) : Promise<any> {
let modal = this.domUtils.showModalLoading(),
isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/);
// Check if user is enrolled in the course.
return this.coursesProvider.getUserCourse(courseId).catch(() => {
// User is not enrolled in the course. Check if can self enrol.
return this.canSelfEnrol(courseId).then(() => {
modal.dismiss();
// The user can self enrol. If it's not a enrolment URL we'll ask for confirmation.
let promise = isEnrolUrl ? Promise.resolve() :
this.domUtils.showConfirm(this.translate.instant('core.courses.confirmselfenrol'));
return promise.then(() => {
// Enrol URL or user confirmed.
return this.selfEnrol(courseId).catch((error) => {
if (error) {
this.domUtils.showErrorModal(error);
}
return Promise.reject(null);
});
}, () => {
// User cancelled. Check if the user can view the course contents (guest access or similar).
return this.courseProvider.getSections(courseId, false, true);
});
}, (error) => {
// Can't self enrol. Check if the user can view the course contents (guest access or similar).
return this.courseProvider.getSections(courseId, false, true).catch(() => {
// Error. Show error message and allow the user to open the link in browser.
modal.dismiss();
if (error) {
error = error.message || error.error || error.content || error.body || error;
}
if (!error) {
error = this.translate.instant('core.courses.notenroled');
}
let body = this.translate.instant('core.twoparagraphs',
{p1: error, p2: this.translate.instant('core.confirmopeninbrowser')});
this.domUtils.showConfirm(body).then(() => {
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLogin(url);
}).catch(() => {
// User cancelled.
});
return Promise.reject(null);
});
});
}).then(() => {
modal.dismiss();
// Use redirect to make the course the new history root (to avoid "loops" in history).
this.loginHelper.redirect('CoreCourseSectionPage', pageParams, this.sitesProvider.getCurrentSiteId());
});
}
/**
* Check if a user can be "automatically" self enrolled in a course.
*
* @param {number} courseId Course ID.
* @return {Promise<any>} Promise resolved if user can be enrolled in a course, rejected otherwise.
*/
protected canSelfEnrol(courseId: number) : Promise<any> {
// Check that the course has self enrolment enabled.
return this.coursesProvider.getCourseEnrolmentMethods(courseId).then((methods) => {
let isSelfEnrolEnabled = false,
instances = 0;
methods.forEach((method) => {
if (method.type == 'self' && method.status) {
isSelfEnrolEnabled = true;
instances++;
}
});
if (!isSelfEnrolEnabled || instances != 1) {
// Self enrol not enabled or more than one instance.
return Promise.reject(null);
}
});
}
/**
* Try to self enrol a user in a course.
*
* @param {number} courseId Course ID.
* @param {string} [password] Password.
* @return {Promise<any>} Promise resolved when the user is enrolled, rejected otherwise.
*/
protected selfEnrol(courseId: number, password?: string) : Promise<any> {
const modal = this.domUtils.showModalLoading();
return this.coursesProvider.selfEnrol(courseId, password).then(() => {
// Success self enrolling the user, invalidate the courses list.
return this.coursesProvider.invalidateUserCourses().catch(() => {
// Ignore errors.
}).then(() => {
// Sometimes the list of enrolled courses takes a while to be updated. Wait for it.
return this.waitForEnrolled(courseId, true).finally(() => {
modal.dismiss();
});
});
}).catch((error) => {
modal.dismiss();
if (error && error.code === CoreCoursesProvider.ENROL_INVALID_KEY) {
// Invalid password. Allow the user to input password.
let title = this.translate.instant('core.courses.selfenrolment'),
body = ' ', // Empty message.
placeholder = this.translate.instant('core.courses.password');
if (typeof password != 'undefined') {
// The user attempted a password. Show an error message.
this.domUtils.showErrorModal(error.message);
}
return this.domUtils.showPrompt(body, title, placeholder).then((password) => {
return this.selfEnrol(courseId, password);
});
} else {
return Promise.reject(error);
}
});
}
/**
* Wait for the user to be enrolled in a course.
*
* @param {number} courseId The course ID.
* @param {boolean} first If it's the first call (true) or it's a recursive call (false).
* @return {Promise<any>} Promise resolved when enrolled or timeout.
*/
protected waitForEnrolled(courseId: number, first?: boolean) : Promise<any> {
if (first) {
this.waitStart = Date.now();
}
// Check if user is enrolled in the course.
return this.coursesProvider.invalidateUserCourses().catch(() => {
// Ignore errors.
}).then(() => {
return this.coursesProvider.getUserCourse(courseId);
}).catch(() => {
// Not enrolled, wait a bit and try again.
if (Date.now() - this.waitStart > 60000) {
// Max time reached, stop.
return;
}
return new Promise((resolve, reject) => {
setTimeout(() => {
this.waitForEnrolled(courseId).then(resolve);
}, 5000);
});
});
}
}

View File

@ -0,0 +1,64 @@
// (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 { Injectable } from '@angular/core';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '../../contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreCoursesProvider } from './courses';
/**
* Handler to treat links to course index (list of courses).
*/
@Injectable()
export class CoreCoursesIndexLinkHandler extends CoreContentLinksHandlerBase {
name = 'CoreCoursesIndexLinkHandler';
featureName = '$mmSideMenuDelegate_mmCourses';
pattern = /\/course\/?(index\.php.*)?$/;
constructor(private coursesProvider: CoreCoursesProvider, private loginHelper: CoreLoginHelperProvider) {
super();
}
/**
* Get the list of actions for a link (url).
*
* @param {string[]} siteIds List of sites the URL belongs to.
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
*/
getActions(siteIds: string[], url: string, params: any, courseId?: number) :
CoreContentLinksAction[]|Promise<CoreContentLinksAction[]> {
return [{
action: (siteId, navCtrl?) => {
var page = 'CoreCoursesMyCoursesPage', // By default, go to My Courses.
pageParams: any = {};
if (this.coursesProvider.isGetCoursesByFieldAvailable()) {
if (params.categoryid) {
page = 'CoreCoursesCategoriesPage';
pageParams.categoryId = parseInt(params.categoryid, 10);
} else {
page = 'CoreCoursesAvailableCoursesPage';
}
}
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.loginHelper.redirect(page, pageParams, siteId);
}
}];
}
}

View File

@ -0,0 +1,52 @@
// (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 { Injectable } from '@angular/core';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '../../contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreCoursesProvider } from './courses';
/**
* Handler to treat links to my overview.
*/
@Injectable()
export class CoreCoursesMyOverviewLinkHandler extends CoreContentLinksHandlerBase {
name = 'CoreCoursesMyOverviewLinkHandler';
featureName = '$mmSideMenuDelegate_mmCourses';
pattern = /\/my\/?$/;
constructor(private coursesProvider: CoreCoursesProvider, private loginHelper: CoreLoginHelperProvider) {
super();
}
/**
* Get the list of actions for a link (url).
*
* @param {string[]} siteIds List of sites the URL belongs to.
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
*/
getActions(siteIds: string[], url: string, params: any, courseId?: number) :
CoreContentLinksAction[]|Promise<CoreContentLinksAction[]> {
return [{
action: (siteId, navCtrl?) => {
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.loginHelper.redirect('CoreCoursesMyOverviewPage', undefined, siteId);
}
}];
}
}

View File

@ -21,6 +21,8 @@ import { CoreSitesProvider } from '../../../../providers/sites';
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
import { CoreUtilsProvider } from '../../../../providers/utils/utils';
import { CoreLoginHelperProvider } from '../../providers/helper';
import { CoreContentLinksDelegate } from '../../../contentlinks/providers/delegate';
import { CoreContentLinksHelperProvider } from '../../../contentlinks/providers/helper';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
/**
@ -52,7 +54,8 @@ export class CoreLoginCredentialsPage {
constructor(private navCtrl: NavController, navParams: NavParams, fb: FormBuilder, private appProvider: CoreAppProvider,
private sitesProvider: CoreSitesProvider, private loginHelper: CoreLoginHelperProvider,
private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private utils: CoreUtilsProvider,
private eventsProvider: CoreEventsProvider) {
private eventsProvider: CoreEventsProvider, private contentLinksDelegate: CoreContentLinksDelegate,
private contentLinksHelper: CoreContentLinksHelperProvider) {
this.siteUrl = navParams.get('siteUrl');
this.siteConfig = navParams.get('siteConfig');
@ -203,16 +206,15 @@ export class CoreLoginCredentialsPage {
if (this.urlToOpen) {
// There's a content link to open.
// @todo: Implement this once content links delegate is implemented.
// return $mmContentLinksDelegate.getActionsFor(urlToOpen, undefined, username).then((actions) => {
// action = $mmContentLinksHelper.getFirstValidAction(actions);
// if (action && action.sites.length) {
// // Action should only have 1 site because we're filtering by username.
// action.action(action.sites[0]);
// } else {
// return $mmLoginHelper.goToSiteInitialPage();
// }
// });
return this.contentLinksDelegate.getActionsFor(this.urlToOpen, undefined, username).then((actions) => {
const action = this.contentLinksHelper.getFirstValidAction(actions);
if (action && action.sites.length) {
// Action should only have 1 site because we're filtering by username.
action.action(action.sites[0]);
} else {
return this.loginHelper.goToSiteInitialPage();
}
});
} else {
return this.loginHelper.goToSiteInitialPage();
}

View File

@ -0,0 +1,84 @@
// (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 { Injectable } from '@angular/core';
import { CoreSitesProvider } from '../../../providers/sites';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '../../contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreSiteHomeProvider } from './sitehome';
/**
* Handler to treat links to site home index.
*/
@Injectable()
export class CoreSiteHomeIndexLinkHandler extends CoreContentLinksHandlerBase {
name = 'CoreSiteHomeIndexLinkHandler';
featureName = '$mmSideMenuDelegate_mmaFrontpage';
pattern = /\/course\/view\.php.*([\?\&]id=\d+)/;
constructor(private sitesProvider: CoreSitesProvider, private siteHomeProvider: CoreSiteHomeProvider,
private loginHelper: CoreLoginHelperProvider) {
super();
}
/**
* Get the list of actions for a link (url).
*
* @param {string[]} siteIds List of sites the URL belongs to.
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
*/
getActions(siteIds: string[], url: string, params: any, courseId?: number) :
CoreContentLinksAction[]|Promise<CoreContentLinksAction[]> {
return [{
action: (siteId, navCtrl?) => {
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.loginHelper.redirect('CoreSiteHomeIndexPage', undefined, siteId);
}
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
* If not defined, defaults to true.
*
* @param {string} siteId The site ID.
* @param {string} url The URL to treat.
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
*/
isEnabled(siteId: string, url: string, params: any, courseId?: number) : boolean|Promise<boolean> {
courseId = parseInt(params.id, 10);
if (!courseId) {
return false;
}
return this.sitesProvider.getSite(siteId).then((site) => {
if (courseId != site.getSiteHomeId()) {
// The course is not site home.
return false;
}
return this.siteHomeProvider.isAvailable(siteId).then(() => {
return true;
}).catch(() => {
return false;
});
});
}
}

View File

@ -15,7 +15,9 @@
import { NgModule } from '@angular/core';
import { CoreSiteHomeProvider } from './providers/sitehome';
import { CoreSiteHomeMainMenuHandler } from './providers/mainmenu-handler';
import { CoreSiteHomeIndexLinkHandler } from './providers/index-link-handler';
import { CoreMainMenuDelegate } from '../mainmenu/providers/delegate';
import { CoreContentLinksDelegate } from '../contentlinks/providers/delegate';
@NgModule({
declarations: [],
@ -23,12 +25,15 @@ import { CoreMainMenuDelegate } from '../mainmenu/providers/delegate';
],
providers: [
CoreSiteHomeProvider,
CoreSiteHomeMainMenuHandler
CoreSiteHomeMainMenuHandler,
CoreSiteHomeIndexLinkHandler
],
exports: []
})
export class CoreSiteHomeModule {
constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: CoreSiteHomeMainMenuHandler) {
constructor(mainMenuDelegate: CoreMainMenuDelegate, contentLinksDelegate: CoreContentLinksDelegate,
mainMenuHandler: CoreSiteHomeMainMenuHandler, indexLinkHandler: CoreSiteHomeIndexLinkHandler) {
mainMenuDelegate.registerHandler(mainMenuHandler);
contentLinksDelegate.registerHandler(indexLinkHandler);
}
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Directive, ElementRef, Input, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Platform, NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '../providers/app';
import { CoreFilepoolProvider } from '../providers/filepool';
@ -26,6 +26,7 @@ import { CoreUtilsProvider } from '../providers/utils/utils';
import { CoreSite } from '../classes/site';
import { CoreLinkDirective } from '../directives/link';
import { CoreExternalContentDirective } from '../directives/external-content';
import { CoreContentLinksHelperProvider } from '../core/contentlinks/providers/helper';
/**
* Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
@ -60,7 +61,8 @@ export class CoreFormatTextDirective implements OnChanges {
constructor(element: ElementRef, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
private textUtils: CoreTextUtilsProvider, private translate: TranslateService, private platform: Platform,
private utils: CoreUtilsProvider, private urlUtils: CoreUrlUtilsProvider, private loggerProvider: CoreLoggerProvider,
private filepoolProvider: CoreFilepoolProvider, private appProvider: CoreAppProvider) {
private filepoolProvider: CoreFilepoolProvider, private appProvider: CoreAppProvider,
private contentLinksHelper: CoreContentLinksHelperProvider, private navCtrl: NavController) {
this.element = element.nativeElement;
this.element.classList.add('opacity-hide'); // Hide contents until they're treated.
this.afterRender = new EventEmitter();
@ -274,7 +276,8 @@ export class CoreFormatTextDirective implements OnChanges {
// Important: We need to look for links first because in 'img' we add new links without core-link.
anchors.forEach((anchor) => {
// Angular 2 doesn't let adding directives dynamically. Create the CoreLinkDirective manually.
let linkDir = new CoreLinkDirective(anchor, this.domUtils, this.utils, this.sitesProvider, this.urlUtils);
let linkDir = new CoreLinkDirective(anchor, this.domUtils, this.utils, this.sitesProvider, this.urlUtils,
this.contentLinksHelper, this.navCtrl);
linkDir.capture = true;
linkDir.ngOnInit();

View File

@ -13,10 +13,12 @@
// limitations under the License.
import { Directive, Input, OnInit, ElementRef } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreSitesProvider } from '../providers/sites';
import { CoreDomUtilsProvider } from '../providers/utils/dom';
import { CoreUrlUtilsProvider } from '../providers/utils/url';
import { CoreUtilsProvider } from '../providers/utils/utils';
import { CoreContentLinksHelperProvider } from '../core/contentlinks/providers/helper';
import { CoreConfigConstants } from '../configconstants';
/**
@ -36,7 +38,8 @@ export class CoreLinkDirective implements OnInit {
protected element: HTMLElement;
constructor(element: ElementRef, private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider,
private sitesProvider: CoreSitesProvider, private urlUtils: CoreUrlUtilsProvider) {
private sitesProvider: CoreSitesProvider, private urlUtils: CoreUrlUtilsProvider,
private contentLinksHelper: CoreContentLinksHelperProvider, private navCtrl: NavController) {
// This directive can be added dynamically. In that case, the first param is the anchor HTMLElement.
this.element = element.nativeElement || element;
}
@ -56,12 +59,11 @@ export class CoreLinkDirective implements OnInit {
event.stopPropagation();
if (this.utils.isTrueOrOne(this.capture)) {
// @todo: Handle link using content links helper.
// $mmContentLinksHelper.handleLink(href).then((treated) => {
// if (!treated) {
this.contentLinksHelper.handleLink(href, undefined, this.navCtrl).then((treated) => {
if (!treated) {
this.navigate(href);
// }
// });
}
});
} else {
this.navigate(href);
}