Merge pull request #1261 from dpalou/MOBILE-2333

Mobile 2333
main
Juan Leyva 2018-03-13 11:36:47 +01:00 committed by GitHub
commit bb524a384d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
195 changed files with 4919 additions and 697 deletions

View File

@ -6,12 +6,13 @@ const customConfig = {
resolve: {
alias: {
'@addon': resolve('./src/addon'),
'@app': resolve('./src/app'),
'@classes': resolve('./src/classes'),
'@core': resolve('./src/core'),
'@providers': resolve('./src/providers'),
'@components': resolve('./src/components'),
'@directives': resolve('./src/directives/directives.module'),
'@pipes': resolve('./src/pipes/pipes.module')
'@directives': resolve('./src/directives'),
'@pipes': resolve('./src/pipes')
}
}
};

View File

@ -16,8 +16,8 @@ import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCalendarEventPage } from './event';
@NgModule({

View File

@ -16,8 +16,8 @@ import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCalendarListPage } from './list';
@NgModule({

View File

@ -16,7 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonCalendarSettingsPage } from './settings';
import { CorePipesModule } from '@pipes';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [

View File

@ -16,7 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonFilesListPage } from './list';
@NgModule({

View File

@ -17,8 +17,8 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonMessagesDiscussionsComponent } from '../components/discussions/discussions';
import { AddonMessagesContactsComponent } from '../components/contacts/contacts';

View File

@ -17,8 +17,8 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonMessagesDiscussionPage } from './discussion';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonMessagesSettingsPage } from './settings';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonMessagesComponentsModule } from '../../components/components.module';
@NgModule({

View File

@ -21,6 +21,7 @@ import { AddonMessagesOfflineProvider } from './messages-offline';
import { AddonMessagesProvider } from './messages';
import { CoreUserProvider } from '@core/user/providers/user';
import { CoreEventsProvider } from '@providers/events';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { TranslateService } from '@ngx-translate/core';
import { CoreSyncProvider } from '@providers/sync';
@ -37,8 +38,8 @@ export class AddonMessagesSyncProvider extends CoreSyncBaseProvider {
protected appProvider: CoreAppProvider, private messagesOffline: AddonMessagesOfflineProvider,
private eventsProvider: CoreEventsProvider, private messagesProvider: AddonMessagesProvider,
private userProvider: CoreUserProvider, private translate: TranslateService, private utils: CoreUtilsProvider,
syncProvider: CoreSyncProvider) {
super('AddonMessagesSync', sitesProvider, loggerProvider, appProvider, syncProvider);
syncProvider: CoreSyncProvider, protected textUtils: CoreTextUtilsProvider) {
super('AddonMessagesSync', sitesProvider, loggerProvider, appProvider, syncProvider, textUtils);
}
/**

View File

@ -17,7 +17,7 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
import { AddonModBookIndexComponent } from './index/index';
import { AddonModBookTocPopoverComponent } from './toc-popover/toc-popover';

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, Optional } from '@angular/core';
import { NavParams, NavController, Content, PopoverController } from 'ionic-angular';
import { Content, PopoverController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreDomUtilsProvider } from '@providers/utils/dom';

View File

@ -15,7 +15,7 @@
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModBookComponentsModule } from '../../components/components.module';
import { AddonModBookIndexPage } from './index';

View File

@ -288,7 +288,7 @@ export class AddonModBookProvider {
return [];
}
return JSON.parse(contents[0].content);
return this.textUtils.parseJSON(contents[0].content, []);
}
/**

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { NavController, NavOptions } from 'ionic-angular';
import { AddonModBookProvider } from './book';
import { AddonModBookIndexComponent } from '../components/index/index';
@ -60,12 +60,14 @@ export class AddonModBookModuleHandler implements CoreCourseModuleHandler {
/**
* Get the component to render the module. This is needed to support singleactivity course format.
* The component returned must implement CoreCourseModuleMainComponent.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course object.
* @param {any} module The module object.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getMainComponent(course: any, module: any): any {
getMainComponent(injector: Injector, course: any, module: any): any | Promise<any> {
return AddonModBookIndexComponent;
}
}

View File

@ -78,22 +78,6 @@ export class AddonModBookPrefetchHandler extends CoreCourseModulePrefetchHandler
return this.bookProvider.invalidateContent(moduleId, courseId);
}
/**
* Invalidate WS calls needed to determine module status.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @return {Promise<any>} Promise resolved when invalidated.
*/
invalidateModule(module: any, courseId: number): Promise<any> {
const promises = [];
promises.push(this.bookProvider.invalidateBookData(courseId));
promises.push(this.courseProvider.invalidateModule(module.id));
return Promise.all(promises);
}
/**
* Whether or not the handler is enabled on a site level.
*

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
/**
@ -58,12 +58,14 @@ export class AddonModLabelModuleHandler implements CoreCourseModuleHandler {
/**
* Get the component to render the module. This is needed to support singleactivity course format.
* The component returned must implement CoreCourseModuleMainComponent.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course object.
* @param {any} module The module object.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getMainComponent(course: any, module: any): any {
getMainComponent(injector: Injector, course: any, module: any): any | Promise<any> {
// There's no need to implement this because label cannot be used in singleactivity course format.
}
}

View File

@ -25,7 +25,7 @@ import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreConfigProvider } from '@providers/config';
import { CoreConfigConstants } from '.././../../configconstants';
import { CoreConfigConstants } from '../../../configconstants';
/**
* Service to handle push notifications.

View File

@ -12,9 +12,8 @@
// 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 { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from
'../../../../core/user/providers/user-profile-field-delegate';
import { Injectable, Injector } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldCheckboxComponent } from '../component/checkbox';
/**
@ -60,10 +59,12 @@ export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFiel
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return {any} The component to use, undefined if not found.
* @param {Injector} injector Injector.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): any {
getComponent(injector: Injector): any | Promise<any> {
return AddonUserProfileFieldCheckboxComponent;
}
}

View File

@ -19,7 +19,7 @@ import { AddonUserProfileFieldDatetimeHandler } from './providers/handler';
import { CoreUserProfileFieldDelegate } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldDatetimeComponent } from './component/datetime';
import { CoreComponentsModule } from '@components/components.module';
import { CorePipesModule } from '@pipes';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [

View File

@ -12,9 +12,8 @@
// 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 { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from
'../../../../core/user/providers/user-profile-field-delegate';
import { Injectable, Injector } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldDatetimeComponent } from '../component/datetime';
/**
@ -62,10 +61,12 @@ export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFiel
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return {any} The component to use, undefined if not found.
* @param {Injector} injector Injector.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): any {
getComponent(injector: Injector): any | Promise<any> {
return AddonUserProfileFieldDatetimeComponent;
}
}

View File

@ -19,7 +19,7 @@ import { AddonUserProfileFieldMenuHandler } from './providers/handler';
import { CoreUserProfileFieldDelegate } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldMenuComponent } from './component/menu';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -12,9 +12,8 @@
// 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 { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from
'../../../../core/user/providers/user-profile-field-delegate';
import { Injectable, Injector } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldMenuComponent } from '../component/menu';
/**
@ -60,10 +59,12 @@ export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHan
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return {any} The component to use, undefined if not found.
* @param {Injector} injector Injector.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): any {
getComponent(injector: Injector): any | Promise<any> {
return AddonUserProfileFieldMenuComponent;
}
}

View File

@ -12,9 +12,8 @@
// 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 { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from
'../../../../core/user/providers/user-profile-field-delegate';
import { Injectable, Injector } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldTextComponent } from '../component/text';
import { CoreTextUtilsProvider } from '@providers/utils/text';
@ -57,10 +56,12 @@ export class AddonUserProfileFieldTextHandler implements CoreUserProfileFieldHan
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return {any} The component to use, undefined if not found.
* @param {Injector} injector Injector.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): any {
getComponent(injector: Injector): any | Promise<any> {
return AddonUserProfileFieldTextComponent;
}
}

View File

@ -19,7 +19,7 @@ import { AddonUserProfileFieldTextHandler } from './providers/handler';
import { CoreUserProfileFieldDelegate } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldTextComponent } from './component/text';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -12,9 +12,8 @@
// 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 { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from
'../../../../core/user/providers/user-profile-field-delegate';
import { Injectable, Injector } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldTextareaComponent } from '../component/textarea';
import { CoreTextUtilsProvider } from '@providers/utils/text';
@ -66,10 +65,12 @@ export class AddonUserProfileFieldTextareaHandler implements CoreUserProfileFiel
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return {any} The component to use, undefined if not found.
* @param {Injector} injector Injector.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): any {
getComponent(injector: Injector): any | Promise<any> {
return AddonUserProfileFieldTextareaComponent;
}
}

View File

@ -19,7 +19,7 @@ import { AddonUserProfileFieldTextareaHandler } from './providers/handler';
import { CoreUserProfileFieldDelegate } from '@core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldTextareaComponent } from './component/textarea';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -49,6 +49,7 @@ import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreUpdateManagerProvider } from '@providers/update-manager';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
import { CoreSyncProvider } from '@providers/sync';
import { CoreFileHelperProvider } from '@providers/file-helper';
// Core modules.
import { CoreComponentsModule } from '@components/components.module';
@ -64,6 +65,8 @@ import { CoreContentLinksModule } from '@core/contentlinks/contentlinks.module';
import { CoreUserModule } from '@core/user/user.module';
import { CoreGradesModule } from '@core/grades/grades.module';
import { CoreSettingsModule } from '@core/settings/settings.module';
import { CoreSitePluginsModule } from '@core/siteplugins/siteplugins.module';
import { CoreCompileModule } from '@core/compile/compile.module';
// Addon modules.
import { AddonCalendarModule } from '@addon/calendar/calendar.module';
@ -79,6 +82,36 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
return new TranslateHttpLoader(http, './assets/lang/', '.json');
}
// List of providers.
export const CORE_PROVIDERS: any[] = [
CoreLoggerProvider,
CoreDbProvider,
CoreAppProvider,
CoreConfigProvider,
CoreLangProvider,
CoreTextUtilsProvider,
CoreDomUtilsProvider,
CoreTimeUtilsProvider,
CoreUrlUtilsProvider,
CoreUtilsProvider,
CoreMimetypeUtilsProvider,
CoreInitDelegate,
CoreFileProvider,
CoreWSProvider,
CoreEventsProvider,
CoreSitesFactoryProvider,
CoreSitesProvider,
CoreLocalNotificationsProvider,
CoreGroupsProvider,
CoreCronDelegate,
CoreFileSessionProvider,
CoreFilepoolProvider,
CoreUpdateManagerProvider,
CorePluginFileDelegate,
CoreSyncProvider,
CoreFileHelperProvider
];
@NgModule({
declarations: [
MoodleMobileApp
@ -111,6 +144,8 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
CoreUserModule,
CoreGradesModule,
CoreSettingsModule,
CoreSitePluginsModule,
CoreCompileModule,
AddonCalendarModule,
AddonUserProfileFieldModule,
AddonFilesModule,
@ -123,38 +158,13 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
entryComponents: [
MoodleMobileApp
],
providers: [
providers: CORE_PROVIDERS.concat([
{
provide: HTTP_INTERCEPTORS,
useClass: CoreInterceptor,
multi: true,
},
CoreLoggerProvider,
CoreDbProvider,
CoreAppProvider,
CoreConfigProvider,
CoreLangProvider,
CoreTextUtilsProvider,
CoreDomUtilsProvider,
CoreTimeUtilsProvider,
CoreUrlUtilsProvider,
CoreUtilsProvider,
CoreMimetypeUtilsProvider,
CoreInitDelegate,
CoreFileProvider,
CoreWSProvider,
CoreEventsProvider,
CoreSitesFactoryProvider,
CoreSitesProvider,
CoreLocalNotificationsProvider,
CoreGroupsProvider,
CoreCronDelegate,
CoreFileSessionProvider,
CoreFilepoolProvider,
CoreUpdateManagerProvider,
CorePluginFileDelegate,
CoreSyncProvider
]
}
])
})
export class AppModule {
constructor(platform: Platform, initDelegate: CoreInitDelegate, updateManager: CoreUpdateManagerProvider,

View File

@ -16,6 +16,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreAppProvider } from '@providers/app';
import { CoreTextUtilsProvider } from '@providers/utils/text';
/**
* Base class to create sync providers. It provides some common functions.
@ -44,7 +45,8 @@ export class CoreSyncBaseProvider {
protected syncPromises: { [siteId: string]: { [uniqueId: string]: Promise<any> } } = {};
constructor(component: string, protected sitesProvider: CoreSitesProvider, protected loggerProvider: CoreLoggerProvider,
protected appProvider: CoreAppProvider, protected syncProvider: CoreSyncProvider) {
protected appProvider: CoreAppProvider, protected syncProvider: CoreSyncProvider,
protected textUtils: CoreTextUtilsProvider) {
this.logger = this.loggerProvider.getInstance(component);
this.component = component;
}
@ -115,11 +117,7 @@ export class CoreSyncBaseProvider {
*/
getSyncWarnings(id: string | number, siteId?: string): Promise<string[]> {
return this.syncProvider.getSyncRecord(this.component, id, siteId).then((entry) => {
try {
return JSON.parse(entry.warnings);
} catch (ex) {
return [];
}
return this.textUtils.parseJSON(entry.warnings, []);
}).catch(() => {
return [];
});

View File

@ -91,7 +91,7 @@ export class CoreDelegate {
// Update handlers on this cases.
eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this));
eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this));
eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this));
eventsProvider.on(CoreEventsProvider.SITE_PLUGINS_LOADED, this.updateHandlers.bind(this));
}
}

View File

@ -734,7 +734,7 @@ export class CoreSite {
const expires = (entry.expirationTime - now) / 1000;
this.logger.info(`Cached element found, id: ${id} expires in ${expires} seconds`);
return JSON.parse(entry.data);
return this.textUtils.parseJSON(entry.data, {});
}
return Promise.reject(null);

View File

@ -15,8 +15,8 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { CoreLoadingComponent } from './loading/loading';
import { CoreMarkRequiredComponent } from './mark-required/mark-required';
import { CoreInputErrorsComponent } from './input-errors/input-errors';

View File

@ -13,9 +13,10 @@
// limitations under the License.
import {
Component, Input, ViewChild, OnInit, OnChanges, DoCheck, ViewContainerRef, ComponentFactoryResolver,
KeyValueDiffers, SimpleChange
Component, Input, ViewChild, OnInit, OnChanges, DoCheck, ViewContainerRef, ComponentFactoryResolver, ComponentRef,
KeyValueDiffers, SimpleChange, ChangeDetectorRef, Optional, ElementRef
} from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreLoggerProvider } from '@providers/logger';
/**
@ -39,6 +40,10 @@ import { CoreLoggerProvider } from '@providers/logger';
*
* Please notice that the component that you pass needs to be declared in entryComponents of the module to be created dynamically.
*
* Alternatively, you can also supply a ComponentRef instead of the class of the component. In this case, the component won't
* be instantiated because it already is, it will be attached to the view and the right data will be passed to it.
* Passing ComponentRef is meant for site plugins, so we'll inject a NavController instance to the component.
*
* The contents of this component will be displayed if no component is supplied or it cannot be created. In the example above,
* if no component is supplied then the template will show the message "Cannot render the data.".
*/
@ -62,7 +67,8 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
protected logger: any;
protected differ: any; // To detect changes in the data input.
constructor(logger: CoreLoggerProvider, private factoryResolver: ComponentFactoryResolver, differs: KeyValueDiffers) {
constructor(logger: CoreLoggerProvider, protected factoryResolver: ComponentFactoryResolver, differs: KeyValueDiffers,
@Optional() protected navCtrl: NavController, protected cdr: ChangeDetectorRef, protected element: ElementRef) {
this.logger = logger.getInstance('CoreDynamicComponent');
this.differ = differs.find([]).create();
}
@ -128,21 +134,32 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
return true;
}
try {
// Create the component and add it to the container.
const factory = this.factoryResolver.resolveComponentFactory(this.component),
componentRef = this.container.createComponent(factory);
if (this.component instanceof ComponentRef) {
// A ComponentRef was supplied instead of the component class. Add it to the view.
this.container.insert(this.component.hostView);
this.instance = this.component.instance;
this.instance = componentRef.instance;
// This feature is usually meant for site plugins. Inject some properties.
this.instance['ChangeDetectorRef'] = this.cdr;
this.instance['NavController'] = this.navCtrl;
this.instance['componentContainer'] = this.element.nativeElement;
} else {
try {
// Create the component and add it to the container.
const factory = this.factoryResolver.resolveComponentFactory(this.component),
componentRef = this.container.createComponent(factory);
this.setInputData();
this.instance = componentRef.instance;
} catch (ex) {
this.logger.error('Error creating component', ex);
return true;
} catch (ex) {
this.logger.error('Error creating component', ex);
return false;
return false;
}
}
this.setInputData();
return true;
}
/**

View File

@ -13,11 +13,10 @@
// limitations under the License.
import { Component, Input, Output, OnInit, OnDestroy, EventEmitter } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events';
import { CoreFileProvider } from '@providers/file';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreFileHelperProvider } from '@providers/file-helper';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
@ -36,7 +35,6 @@ export class CoreFileComponent implements OnInit, OnDestroy {
@Input() file: any; // The file. Must have a property 'filename' and a 'fileurl' or 'url'
@Input() component?: string; // Component the file belongs to.
@Input() componentId?: string | number; // Component ID.
@Input() timemodified?: number; // If set, the value will be used to check if the file is outdated.
@Input() canDelete?: boolean | string; // Whether file can be deleted.
@Input() alwaysDownload?: boolean | string; // Whether it should always display the refresh button when the file is downloaded.
// Use it for files that you cannot determine if they're outdated or not.
@ -52,12 +50,14 @@ export class CoreFileComponent implements OnInit, OnDestroy {
protected fileUrl: string;
protected siteId: string;
protected fileSize: number;
protected state: string;
protected timemodified: number;
protected observer;
constructor(private translate: TranslateService, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
private domUtils: CoreDomUtilsProvider, private filepoolProvider: CoreFilepoolProvider,
private fileProvider: CoreFileProvider, private appProvider: CoreAppProvider,
private mimeUtils: CoreMimetypeUtilsProvider, private eventsProvider: CoreEventsProvider) {
constructor(private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, private domUtils: CoreDomUtilsProvider,
private filepoolProvider: CoreFilepoolProvider, private appProvider: CoreAppProvider,
private fileHelper: CoreFileHelperProvider, private mimeUtils: CoreMimetypeUtilsProvider,
private eventsProvider: CoreEventsProvider) {
this.onDelete = new EventEmitter();
}
@ -68,9 +68,9 @@ export class CoreFileComponent implements OnInit, OnDestroy {
this.canDelete = this.utils.isTrueOrOne(this.canDelete);
this.alwaysDownload = this.utils.isTrueOrOne(this.alwaysDownload);
this.canDownload = this.utils.isTrueOrOne(this.canDownload);
this.timemodified = this.timemodified || 0;
this.fileUrl = this.file.fileurl || this.file.url;
this.fileUrl = this.fileHelper.getFileUrl(this.file);
this.timemodified = this.fileHelper.getFileTimemodified(this.file);
this.siteId = this.sitesProvider.getCurrentSiteId();
this.fileSize = this.file.filesize;
this.fileName = this.file.filename;
@ -102,6 +102,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
return this.filepoolProvider.getFileStateByUrl(this.siteId, this.fileUrl, this.timemodified).then((state) => {
const canDownload = this.sitesProvider.getCurrentSite().canDownloadFiles();
this.state = state;
this.isDownloaded = state === CoreConstants.DOWNLOADED || state === CoreConstants.OUTDATED;
this.isDownloading = canDownload && state === CoreConstants.DOWNLOADING;
this.showDownload = canDownload && (state === CoreConstants.NOT_DOWNLOADED || state === CoreConstants.OUTDATED ||
@ -109,123 +110,19 @@ export class CoreFileComponent implements OnInit, OnDestroy {
});
}
/**
* Download the file.
*
* @return {Promise<string>} Promise resolved when file is downloaded.
*/
protected downloadFile(): Promise<string> {
if (!this.sitesProvider.getCurrentSite().canDownloadFiles()) {
this.domUtils.showErrorModal('core.cannotdownloadfiles', true);
return Promise.reject(null);
}
this.isDownloading = true;
return this.filepoolProvider.downloadUrl(this.siteId, this.fileUrl, false, this.component, this.componentId,
this.timemodified, undefined, undefined, this.file).catch(() => {
// Call calculateState to make sure we have the right state.
return this.calculateState().then(() => {
if (this.isDownloaded) {
return this.filepoolProvider.getInternalUrlByUrl(this.siteId, this.fileUrl);
} else {
return Promise.reject(null);
}
});
});
}
/**
* Convenience function to open a file, downloading it if needed.
*
* @return {Promise<string>} Promise resolved when file is opened.
*/
protected openFile(): Promise<any> {
const fixedUrl = this.sitesProvider.getCurrentSite().fixPluginfileURL(this.fileUrl);
let promise;
if (this.fileProvider.isAvailable()) {
promise = Promise.resolve().then(() => {
// The file system is available.
const isWifi = !this.appProvider.isNetworkAccessLimited(),
isOnline = this.appProvider.isOnline();
if (this.isDownloaded && !this.showDownload) {
// File is downloaded, get the local file URL.
return this.filepoolProvider.getUrlByUrl(this.siteId, this.fileUrl,
this.component, this.componentId, this.timemodified, false, false, this.file);
} else {
if (!isOnline && !this.isDownloaded) {
// Not downloaded and user is offline, reject.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
const isDownloading = this.isDownloading;
this.isDownloading = true; // This check could take a while, show spinner.
return this.filepoolProvider.shouldDownloadBeforeOpen(fixedUrl, this.fileSize).then(() => {
if (isDownloading) {
// It's already downloading, stop.
return;
}
// Download and then return the local URL.
return this.downloadFile();
}, () => {
// Start the download if in wifi, but return the URL right away so the file is opened.
if (isWifi && isOnline) {
this.downloadFile();
}
if (isDownloading || !this.isDownloaded || isOnline) {
// Not downloaded or outdated and online, return the online URL.
return fixedUrl;
} else {
// Outdated but offline, so we return the local URL.
return this.filepoolProvider.getUrlByUrl(this.siteId, this.fileUrl,
this.component, this.componentId, this.timemodified, false, false, this.file);
}
});
}
});
} else {
// Use the online URL.
promise = Promise.resolve(fixedUrl);
}
return promise.then((url) => {
if (!url) {
return;
}
if (url.indexOf('http') === 0) {
return this.utils.openOnlineFile(url).catch((error) => {
// Error opening the file, some apps don't allow opening online files.
if (!this.fileProvider.isAvailable()) {
return Promise.reject(error);
} else if (this.isDownloading) {
return Promise.reject(this.translate.instant('core.erroropenfiledownloading'));
}
let subPromise;
if (status === CoreConstants.NOT_DOWNLOADED) {
// File is not downloaded, download and then return the local URL.
subPromise = this.downloadFile();
} else {
// File is outdated and can't be opened in online, return the local URL.
subPromise = this.filepoolProvider.getInternalUrlByUrl(this.siteId, this.fileUrl);
}
return subPromise.then((url) => {
return this.utils.openFile(url);
});
});
} else {
return this.utils.openFile(url);
return this.fileHelper.downloadAndOpenFile(this.file, this.component, this.componentId, this.state, (event) => {
if (event && event.calculating) {
// The process is calculating some data required for the download, show the spinner.
this.isDownloading = true;
}
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
});
}

View File

@ -14,7 +14,7 @@
// Code based on https://github.com/martinpritchardelevate/ionic-split-pane-demo
import { Component, ViewChild, Input, ElementRef, OnInit } from '@angular/core';
import { Component, ViewChild, Input, ElementRef, OnInit, Optional } from '@angular/core';
import { NavController, Nav } from 'ionic-angular';
/**
@ -54,7 +54,7 @@ export class CoreSplitViewComponent implements OnInit {
// Empty placeholder for the 'detail' page.
detailPage: any = null;
constructor(private masterNav: NavController, element: ElementRef) {
constructor(@Optional() private masterNav: NavController, element: ElementRef) {
this.element = element.nativeElement;
}

View File

@ -0,0 +1,27 @@
// (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 { CoreCompileProvider } from './providers/compile';
@NgModule({
declarations: [
],
imports: [
],
providers: [
CoreCompileProvider
]
})
export class CoreCompileModule { }

View File

@ -0,0 +1,30 @@
// (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 { CommonModule } from '@angular/common';
import { CoreCompileHtmlComponent } from './compile-html';
@NgModule({
declarations: [
CoreCompileHtmlComponent
],
imports: [
CommonModule
],
exports: [
CoreCompileHtmlComponent
]
})
export class CoreCompileHtmlComponentModule {}

View File

@ -0,0 +1,122 @@
// (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, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, ViewChild, ComponentRef, SimpleChange, ChangeDetectorRef,
ElementRef, Optional
} from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCompileProvider } from '../../providers/compile';
import { BehaviorSubject } from 'rxjs';
/**
* This component has a behaviour similar to $compile for AngularJS. Given an HTML code, it will compile it so all its
* components and directives are instantiated.
*
* IMPORTANT: Use this component only if it is a must. It will create and compile a new component and module everytime this
* component is used, so it can slow down the app.
*
* This component has its own module to prevent circular dependencies. If you want to use it,
* you need to import CoreCompileHtmlComponentModule.
*
* You can provide some Javascript code (as text) to be executed inside the component. The context of the javascript code (this)
* will be the component instance created to compile the template. This means your javascript code can interact with the template.
* The component instance will have most of the providers so you can use them in the javascript code. E.g. if you want to use
* CoreAppProvider, you can do it with "this.CoreAppProvider".
*/
@Component({
selector: 'core-compile-html',
template: '<ng-container #dynamicComponent></ng-container>'
})
export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
@Input() text: string; // The HTML text to display.
@Input() javascript: string; // The Javascript to execute in the component.
@Input() jsData; // Data to pass to the fake component.
// Get the container where to put the content.
@ViewChild('dynamicComponent', { read: ViewContainerRef }) container: ViewContainerRef;
protected componentRef: ComponentRef<any>;
protected element;
componentObservable: BehaviorSubject<any>; // An observable to notify observers when the component is instantiated.
constructor(protected compileProvider: CoreCompileProvider, protected cdr: ChangeDetectorRef, element: ElementRef,
@Optional() protected navCtrl: NavController) {
this.element = element.nativeElement;
this.componentObservable = new BehaviorSubject<any>(null);
}
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if ((changes.text || changes.javascript) && this.text) {
// Create a new component and a new module.
this.compileProvider.createAndCompileComponent(this.text, this.getComponentClass()).then((factory) => {
// Destroy previous components.
this.componentRef && this.componentRef.destroy();
if (factory) {
// Create the component.
this.componentRef = this.container.createComponent(factory);
this.componentObservable.next(this.componentRef.instance);
}
});
}
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.componentRef && this.componentRef.destroy();
}
/**
* Get a class that defines the dynamic component.
*
* @return {any} The component class.
*/
protected getComponentClass(): any {
// tslint:disable: no-this-assignment
const compileInstance = this;
// Create the component, using the text as the template.
return class CoreCompileHtmlFakeComponent implements OnInit {
constructor() {
// If there is some javascript to run, prepare the instance.
if (compileInstance.javascript) {
compileInstance.compileProvider.injectLibraries(this);
// Add some more components and classes.
this['ChangeDetectorRef'] = compileInstance.cdr;
this['NavController'] = compileInstance.navCtrl;
this['componentContainer'] = compileInstance.element;
}
// Add the data passed to the component.
for (const name in compileInstance.jsData) {
this[name] = compileInstance.jsData[name];
}
}
ngOnInit(): void {
// If there is some javascript to run, do it now.
if (compileInstance.javascript) {
compileInstance.compileProvider.executeJavascript(this, compileInstance.javascript);
}
}
};
}
}

View File

@ -0,0 +1,224 @@
// (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, Injector, Component, NgModule, Compiler, ComponentFactory, ComponentRef, NgModuleRef } from '@angular/core';
import {
Platform, ActionSheetController, AlertController, LoadingController, ModalController, PopoverController, ToastController,
IonicModule
} from 'ionic-angular';
import { TranslateService, TranslateModule } from '@ngx-translate/core';
import { CoreLoggerProvider } from '@providers/logger';
// Import core providers.
import { CORE_PROVIDERS } from '@app/app.module';
import { CORE_CONTENTLINKS_PROVIDERS } from '@core/contentlinks/contentlinks.module';
import { CORE_COURSE_PROVIDERS } from '@core/course/course.module';
import { CORE_COURSES_PROVIDERS } from '@core/courses/courses.module';
import { CORE_FILEUPLOADER_PROVIDERS } from '@core/fileuploader/fileuploader.module';
import { CORE_GRADES_PROVIDERS } from '@core/grades/grades.module';
import { CORE_LOGIN_PROVIDERS } from '@core/login/login.module';
import { CORE_MAINMENU_PROVIDERS } from '@core/mainmenu/mainmenu.module';
import { CORE_SHAREDFILES_PROVIDERS } from '@core/sharedfiles/sharedfiles.module';
import { CORE_SITEHOME_PROVIDERS } from '@core/sitehome/sitehome.module';
import { CORE_USER_PROVIDERS } from '@core/user/user.module';
import { IONIC_NATIVE_PROVIDERS } from '@core/emulator/emulator.module';
// Import only this provider to prevent circular dependencies.
import { CoreSitePluginsProvider } from '@core/siteplugins/providers/siteplugins';
// Import other libraries and providers.
import { DomSanitizer } from '@angular/platform-browser';
import { FormBuilder, Validators } from '@angular/forms';
import { Http } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { CoreConfigConstants } from '../../../configconstants';
import { CoreConstants } from '@core/constants';
import * as moment from 'moment';
import { Md5 } from 'ts-md5/dist/md5';
// Import core classes that can be useful for site plugins.
import { CoreSyncBaseProvider } from '@classes/base-sync';
import { CoreCache } from '@classes/cache';
import { CoreDelegate } from '@classes/delegate';
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksModuleGradeHandler } from '@core/contentlinks/classes/module-grade-handler';
import { CoreContentLinksModuleIndexHandler } from '@core/contentlinks/classes/module-index-handler';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
// Import all modules that define components, directives and pipes.
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
import { CoreCourseDirectivesModule } from '@core/course/directives/directives.module';
import { CoreCoursesComponentsModule } from '@core/courses/components/components.module';
import { CoreSitePluginsDirectivesModule } from '@core/siteplugins/directives/directives.module';
import { CoreSiteHomeComponentsModule } from '@core/sitehome/components/components.module';
import { CoreUserComponentsModule } from '@core/user/components/components.module';
// Import some components listed in entryComponents so they can be injected dynamically.
import { CoreCourseUnsupportedModuleComponent } from '@core/course/components/unsupported-module/unsupported-module';
import { CoreCourseFormatSingleActivityComponent } from '@core/course/formats/singleactivity/components/singleactivity';
import { CoreSitePluginsModuleIndexComponent } from '@core/siteplugins/components/module-index/module-index';
import { CoreSitePluginsCourseOptionComponent } from '@core/siteplugins/components/course-option/course-option';
import { CoreSitePluginsCourseFormatComponent } from '@core/siteplugins/components/course-format/course-format';
/**
* Service to provide functionalities regarding compiling dynamic HTML and Javascript.
*/
@Injectable()
export class CoreCompileProvider {
protected logger;
// Other Ionic/Angular providers that don't depend on where they are injected.
protected OTHER_PROVIDERS = [
TranslateService, Http, HttpClient, Platform, DomSanitizer, ActionSheetController, AlertController, LoadingController,
ModalController, PopoverController, ToastController, FormBuilder
];
// List of imports for dynamic module. Since the template can have any component we need to import all core components modules.
protected IMPORTS = [
IonicModule, TranslateModule.forChild(), CoreComponentsModule, CoreDirectivesModule, CorePipesModule,
CoreCourseComponentsModule, CoreCoursesComponentsModule, CoreSiteHomeComponentsModule, CoreUserComponentsModule,
CoreCourseDirectivesModule, CoreSitePluginsDirectivesModule
];
constructor(protected injector: Injector, logger: CoreLoggerProvider, protected compiler: Compiler) {
this.logger = logger.getInstance('CoreCompileProvider');
}
/**
* Create and compile a dynamic component.
*
* @param {string} template The template of the component.
* @param {any} componentClass The JS class of the component.
* @return {Promise<ComponentFactory<any>>} Promise resolved with the factory to instantiate the component.
*/
createAndCompileComponent(template: string, componentClass: any): Promise<ComponentFactory<any>> {
// Create the component using the template and the class.
const component = Component({
template: template
})
(componentClass);
// Now create the module containing the component.
const module = NgModule({imports: this.IMPORTS, declarations: [component]})(class {});
// Compile the module and the component.
return this.compiler.compileModuleAndAllComponentsAsync(module).then((factories) => {
// Search and return the factory of the component we just created.
for (const i in factories.componentFactories) {
const factory = factories.componentFactories[i];
if (factory.componentType == component) {
return factory;
}
}
});
}
/**
* Eval some javascript using the context of the function.
*
* @param {string} javascript The javascript to eval.
* @return {any} Result of the eval.
*/
protected evalInContext(javascript: string): any {
// tslint:disable: no-eval
return eval(javascript);
}
/**
* Execute some javascript code, using a certain instance as the context.
*
* @param {any} instance Instance to use as the context. In the JS code, "this" will be this instance.
* @param {string} javascript The javascript code to eval.
* @return {any} Result of the javascript execution.
*/
executeJavascript(instance: any, javascript: string): any {
try {
return this.evalInContext.call(instance, javascript);
} catch (ex) {
this.logger.error('Error evaluating javascript', ex);
}
}
/**
* Inject all the core libraries in a certain object.
*
* @param {any} instance The instance where to inject the libraries.
*/
injectLibraries(instance: any): void {
const providers = (<any[]> CORE_PROVIDERS).concat(CORE_CONTENTLINKS_PROVIDERS).concat(CORE_COURSE_PROVIDERS)
.concat(CORE_COURSES_PROVIDERS).concat(CORE_FILEUPLOADER_PROVIDERS).concat(CORE_GRADES_PROVIDERS)
.concat(CORE_LOGIN_PROVIDERS).concat(CORE_MAINMENU_PROVIDERS).concat(CORE_SHAREDFILES_PROVIDERS)
.concat(CORE_SITEHOME_PROVIDERS).concat([CoreSitePluginsProvider]).concat(CORE_USER_PROVIDERS)
.concat(IONIC_NATIVE_PROVIDERS).concat(this.OTHER_PROVIDERS);
// We cannot inject anything to this constructor. Use the Injector to inject all the providers into the instance.
for (const i in providers) {
const providerDef = providers[i];
if (typeof providerDef == 'function' && providerDef.name) {
try {
// Inject the provider to the instance. We use the class name as the property name.
instance[providerDef.name] = this.injector.get(providerDef);
} catch (ex) {
this.logger.warn('Error injecting provider', providerDef.name, ex);
}
}
}
// Inject current service.
instance['CoreCompileProvider'] = this;
// Add some final classes.
instance['injector'] = this.injector;
instance['Validators'] = Validators;
instance['CoreConfigConstants'] = CoreConfigConstants;
instance['CoreConstants'] = CoreConstants;
instance['moment'] = moment;
instance['Md5'] = Md5;
instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider;
instance['CoreCache'] = CoreCache;
instance['CoreDelegate'] = CoreDelegate;
instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase;
instance['CoreContentLinksModuleGradeHandler'] = CoreContentLinksModuleGradeHandler;
instance['CoreContentLinksModuleIndexHandler'] = CoreContentLinksModuleIndexHandler;
instance['CoreCourseModulePrefetchHandlerBase'] = CoreCourseModulePrefetchHandlerBase;
instance['CoreCourseUnsupportedModuleComponent'] = CoreCourseUnsupportedModuleComponent;
instance['CoreCourseFormatSingleActivityComponent'] = CoreCourseFormatSingleActivityComponent;
instance['CoreSitePluginsModuleIndexComponent'] = CoreSitePluginsModuleIndexComponent;
instance['CoreSitePluginsCourseOptionComponent'] = CoreSitePluginsCourseOptionComponent;
instance['CoreSitePluginsCourseFormatComponent'] = CoreSitePluginsCourseFormatComponent;
}
/**
* Instantiate a dynamic component.
*
* @param {string} template The template of the component.
* @param {any} componentClass The JS class of the component.
* @param {Injector} [injector] The injector to use. It's recommended to pass it so NavController and similar can be injected.
* @return {Promise<ComponentRef<any>>} Promise resolved with the component instance.
*/
instantiateDynamicComponent(template: string, componentClass: any, injector?: Injector): Promise<ComponentRef<any>> {
injector = injector || this.injector;
return this.createAndCompileComponent(template, componentClass).then((factory) => {
if (factory) {
// Create and return the component.
return factory.create(injector, undefined, undefined, injector.get(NgModuleRef));
}
});
}
}

View File

@ -17,7 +17,7 @@ import { CoreContentLinksAction } from '../providers/delegate';
import { CoreContentLinksHandlerBase } from './base-handler';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCourseHelperProvider } from '../../course/providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
/**
* Handler to handle URLs pointing to the grade of a module.

View File

@ -14,7 +14,7 @@
import { CoreContentLinksAction } from '../providers/delegate';
import { CoreContentLinksHandlerBase } from './base-handler';
import { CoreCourseHelperProvider } from '../../course/providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
/**
* Handler to handle URLs pointing to the index of a module.

View File

@ -16,14 +16,17 @@ import { NgModule } from '@angular/core';
import { CoreContentLinksDelegate } from './providers/delegate';
import { CoreContentLinksHelperProvider } from './providers/helper';
// List of providers.
export const CORE_CONTENTLINKS_PROVIDERS = [
CoreContentLinksDelegate,
CoreContentLinksHelperProvider
];
@NgModule({
declarations: [],
imports: [
],
providers: [
CoreContentLinksDelegate,
CoreContentLinksHelperProvider
],
providers: CORE_CONTENTLINKS_PROVIDERS,
exports: []
})
export class CoreContentLinksModule {}

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { CoreContentLinksChooseSitePage } from './choose-site';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -23,10 +23,11 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
import { CoreContentLinksDelegate, CoreContentLinksAction } from './delegate';
import { CoreConstants } from '../../constants';
import { CoreConstants } from '@core/constants';
import { CoreConfigConstants } from '../../../configconstants';
import { CoreSitePluginsProvider } from '@core/siteplugins/providers/siteplugins';
/**
* Service that provides some features regarding content links.
@ -38,7 +39,8 @@ export class CoreContentLinksHelperProvider {
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private loginHelper: CoreLoginHelperProvider,
private contentLinksDelegate: CoreContentLinksDelegate, private appProvider: CoreAppProvider,
private domUtils: CoreDomUtilsProvider, private urlUtils: CoreUrlUtilsProvider, private translate: TranslateService,
private initDelegate: CoreInitDelegate, eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider) {
private initDelegate: CoreInitDelegate, eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider,
private sitePluginsProvider: CoreSitePluginsProvider) {
this.logger = logger.getInstance('CoreContentLinksHelperProvider');
// Listen for app launched URLs. If we receive one, check if it's a content link.
@ -144,7 +146,6 @@ export class CoreContentLinksHelperProvider {
return this.sitesProvider.checkSite(siteUrl).then((result) => {
// Site exists. We'll allow to add it.
const ssoNeeded = this.loginHelper.isSSOLoginNeeded(result.code),
hasRemoteAddonsLoaded = false,
pageName = 'CoreLoginCredentialsPage',
pageParams = {
siteUrl: result.siteUrl,
@ -152,7 +153,8 @@ export class CoreContentLinksHelperProvider {
urlToOpen: url,
siteConfig: result.config
};
let promise;
let promise,
hasSitePluginsLoaded = false;
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
@ -164,8 +166,8 @@ export class CoreContentLinksHelperProvider {
const confirmMsg = this.translate.instant('core.contentlinks.confirmurlothersite');
promise = this.domUtils.showConfirm(confirmMsg).then(() => {
if (!ssoNeeded) {
// @todo hasRemoteAddonsLoaded = $mmAddonManager.hasRemoteAddonsLoaded(); @todo
if (hasRemoteAddonsLoaded) {
hasSitePluginsLoaded = this.sitePluginsProvider.hasSitePluginsLoaded;
if (hasSitePluginsLoaded) {
// Store the redirect since logout will restart the app.
this.appProvider.storeRedirect(CoreConstants.NO_SITE_ID, pageName, pageParams);
}
@ -181,7 +183,7 @@ export class CoreContentLinksHelperProvider {
if (ssoNeeded) {
this.loginHelper.confirmAndOpenBrowserForSSOLogin(
result.siteUrl, result.code, result.service, result.config && result.config.launchurl);
} else if (!hasRemoteAddonsLoaded) {
} else if (!hasSitePluginsLoaded) {
this.appProvider.getRootNavController().setRoot(pageName, pageParams);
}
});

View File

@ -133,10 +133,11 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number): Promise<any> {
return this.downloadOrPrefetch(module, courseId, false);
download(module: any, courseId: number, dirPath?: string): Promise<any> {
return this.downloadOrPrefetch(module, courseId, false, dirPath);
}
/**
@ -332,8 +333,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
}
/**
* Invalidate WS calls needed to determine module status. It doesn't need to invalidate check updates.
* It should NOT invalidate files nor all the prefetched data.
* Invalidate WS calls needed to determine module status (usually, to check if module is downloadable).
* It doesn't need to invalidate check updates. It should NOT invalidate files nor all the prefetched data.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
@ -409,10 +410,11 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean): Promise<any> {
return this.downloadOrPrefetch(module, courseId, true);
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
return this.downloadOrPrefetch(module, courseId, true, dirPath);
}
/**

View File

@ -17,7 +17,7 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreCourseFormatComponent } from './format/format';
import { CoreCourseModuleComponent } from './module/module';
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';

View File

@ -13,17 +13,17 @@
// limitations under the License.
import {
Component, Input, OnInit, OnChanges, OnDestroy, SimpleChange, Output, EventEmitter, ViewChildren, QueryList
Component, Input, OnInit, OnChanges, OnDestroy, SimpleChange, Output, EventEmitter, ViewChildren, QueryList, Injector
} from '@angular/core';
import { Content } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCourseProvider } from '../../../course/providers/course';
import { CoreCourseHelperProvider } from '../../../course/providers/helper';
import { CoreCourseFormatDelegate } from '../../../course/providers/format-delegate';
import { CoreCourseModulePrefetchDelegate } from '../../../course/providers/module-prefetch-delegate';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseFormatDelegate } from '@core/course/providers/format-delegate';
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
/**
@ -69,7 +69,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
protected sectionStatusObserver;
constructor(private cfDelegate: CoreCourseFormatDelegate, translate: TranslateService,
constructor(private cfDelegate: CoreCourseFormatDelegate, translate: TranslateService, private injector: Injector,
private courseHelper: CoreCourseHelperProvider, private domUtils: CoreDomUtilsProvider,
eventsProvider: CoreEventsProvider, private sitesProvider: CoreSitesProvider, private content: Content,
prefetchDelegate: CoreCourseModulePrefetchDelegate) {
@ -194,19 +194,29 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
protected getComponents(): void {
if (this.course) {
if (!this.courseFormatComponent) {
this.courseFormatComponent = this.cfDelegate.getCourseFormatComponent(this.course);
this.cfDelegate.getCourseFormatComponent(this.injector, this.course).then((component) => {
this.courseFormatComponent = component;
});
}
if (!this.courseSummaryComponent) {
this.courseSummaryComponent = this.cfDelegate.getCourseSummaryComponent(this.course);
this.cfDelegate.getCourseSummaryComponent(this.injector, this.course).then((component) => {
this.courseSummaryComponent = component;
});
}
if (!this.sectionSelectorComponent) {
this.sectionSelectorComponent = this.cfDelegate.getSectionSelectorComponent(this.course);
this.cfDelegate.getSectionSelectorComponent(this.injector, this.course).then((component) => {
this.sectionSelectorComponent = component;
});
}
if (!this.singleSectionComponent) {
this.singleSectionComponent = this.cfDelegate.getSingleSectionComponent(this.course);
this.cfDelegate.getSingleSectionComponent(this.injector, this.course).then((component) => {
this.singleSectionComponent = component;
});
}
if (!this.allSectionsComponent) {
this.allSectionsComponent = this.cfDelegate.getAllSectionsComponent(this.course);
this.cfDelegate.getAllSectionsComponent(this.injector, this.course).then((component) => {
this.allSectionsComponent = component;
});
}
}
}

View File

@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUserProvider } from '../../../user/providers/user';
import { CoreUserProvider } from '@core/user/providers/user';
/**
* Component to handle activity completion. It shows a checkbox with the current status, and allows manually changing

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, Optional } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
@ -67,7 +67,7 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
protected prefetchHandler: CoreCourseModulePrefetchHandler;
protected statusObserver;
constructor(protected navCtrl: NavController, protected prefetchDelegate: CoreCourseModulePrefetchDelegate,
constructor(@Optional() protected navCtrl: NavController, protected prefetchDelegate: CoreCourseModulePrefetchDelegate,
protected domUtils: CoreDomUtilsProvider, protected courseHelper: CoreCourseHelperProvider,
protected eventsProvider: CoreEventsProvider, protected sitesProvider: CoreSitesProvider) {
this.completionChanged = new EventEmitter();

View File

@ -25,6 +25,16 @@ import { CoreCourseFormatSocialModule } from './formats/social/social.module';
import { CoreCourseFormatTopicsModule } from './formats/topics/topics.module';
import { CoreCourseFormatWeeksModule } from './formats/weeks/weeks.module';
// List of providers (without handlers).
export const CORE_COURSE_PROVIDERS: any[] = [
CoreCourseProvider,
CoreCourseHelperProvider,
CoreCourseFormatDelegate,
CoreCourseModuleDelegate,
CoreCourseModulePrefetchDelegate,
CoreCourseOptionsDelegate
];
@NgModule({
declarations: [],
imports: [
@ -33,15 +43,9 @@ import { CoreCourseFormatWeeksModule } from './formats/weeks/weeks.module';
CoreCourseFormatWeeksModule,
CoreCourseFormatSocialModule
],
providers: [
CoreCourseProvider,
CoreCourseHelperProvider,
CoreCourseFormatDelegate,
CoreCourseModuleDelegate,
CoreCourseModulePrefetchDelegate,
CoreCourseOptionsDelegate,
providers: CORE_COURSE_PROVIDERS.concat([
CoreCourseFormatDefaultHandler
],
]),
exports: []
})
export class CoreCourseModule {}

View File

@ -0,0 +1,27 @@
// (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 { CoreCourseDownloadModuleMainFileDirective } from './download-module-main-file';
@NgModule({
declarations: [
CoreCourseDownloadModuleMainFileDirective
],
imports: [],
exports: [
CoreCourseDownloadModuleMainFileDirective
]
})
export class CoreCourseDirectivesModule {}

View File

@ -0,0 +1,81 @@
// (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 { Directive, Input, OnInit, ElementRef } from '@angular/core';
import { CoreCourseProvider } from '../providers/course';
import { CoreCourseHelperProvider } from '../providers/helper';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
/**
* Directive to allow downloading and open the main file of a module.
* When the item with this directive is clicked, the module will be downloaded (if needed) and opened.
* This is meant for modules like mod_resource.
*
* This directive must receive either a module or a moduleId. If no files are provided, it will use module.contents.
*/
@Directive({
selector: '[core-course-download-module-main-file]'
})
export class CoreCourseDownloadModuleMainFileDirective implements OnInit {
@Input() module: any; // The module.
@Input() moduleId: string | number; // The module ID. Required if module is not supplied.
@Input() courseId: string | number; // The course ID.
@Input() component?: string; // Component to link the file to.
@Input() componentId?: string | number; // Component ID to use in conjunction with the component. If not defined, use moduleId.
@Input() files?: any[]; // List of files of the module. If not provided, use module.contents.
protected element: HTMLElement;
constructor(element: ElementRef, protected domUtils: CoreDomUtilsProvider, protected courseHelper: CoreCourseHelperProvider,
protected courseProvider: CoreCourseProvider) {
this.element = element.nativeElement || element;
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.element.addEventListener('click', (ev: Event): void => {
if (!this.module && !this.moduleId) {
return;
}
ev.preventDefault();
ev.stopPropagation();
const modal = this.domUtils.showModalLoading(),
courseId = typeof this.courseId == 'string' ? parseInt(this.courseId, 10) : this.courseId;
let promise;
if (this.module) {
// We already have the module.
promise = Promise.resolve(module);
} else {
// Try to get the module from cache.
this.moduleId = typeof this.moduleId == 'string' ? parseInt(this.moduleId, 10) : this.moduleId;
promise = this.courseProvider.getModule(this.moduleId, courseId);
}
promise.then((module) => {
const componentId = this.componentId || module.id;
return this.courseHelper.downloadModuleAndOpenFile(module, courseId, this.component, componentId, this.files);
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
}).finally(() => {
modal.dismiss();
});
});
}
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnChanges, SimpleChange, ViewChild } from '@angular/core';
import { Component, Input, OnChanges, SimpleChange, ViewChild, Injector } from '@angular/core';
import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
import { CoreCourseUnsupportedModuleComponent } from '../../../components/unsupported-module/unsupported-module';
import { CoreDynamicComponent } from '../../../../../components/dynamic-component/dynamic-component';
@ -36,7 +36,7 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
componentClass: any; // The class of the component to render.
data: any = {}; // Data to pass to the component.
constructor(private moduleDelegate: CoreCourseModuleDelegate) { }
constructor(private moduleDelegate: CoreCourseModuleDelegate, private injector: Injector) { }
/**
* Detect changes on input properties.
@ -47,8 +47,9 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
const module = this.sections[0] && this.sections[0].modules && this.sections[0].modules[0];
if (module && !this.componentClass) {
// We haven't obtained the class yet. Get it now.
this.componentClass = this.moduleDelegate.getMainComponent(this.course, module) ||
CoreCourseUnsupportedModuleComponent;
this.moduleDelegate.getMainComponent(this.injector, this.course, module).then((component) => {
this.componentClass = component || CoreCourseUnsupportedModuleComponent;
});
}
this.data.courseId = this.course.id;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { CoreCourseFormatHandler } from '../../../providers/format-delegate';
import { CoreCourseFormatSingleActivityComponent } from '../components/singleactivity';
@ -86,11 +86,13 @@ export class CoreCourseFormatSingleActivityHandler implements CoreCourseFormatHa
* Return the Component to use to display the course format instead of using the default one.
* Use it if you want to display a format completely different from the default one.
* If you want to customize the default format there are several methods to customize parts of it.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getCourseFormatComponent(course: any): any {
getCourseFormatComponent(injector: Injector, course: any): any | Promise<any> {
return CoreCourseFormatSingleActivityComponent;
}
}

View File

@ -30,7 +30,7 @@
<!-- One tab per handler. -->
<core-tab *ngFor="let handler of courseHandlers" [title]="handler.data.title | translate" class="{{handler.data.class}}">
<ng-template>
<core-dynamic-component [component]="handler.data.component" [data]="handlerData"></core-dynamic-component>
<core-dynamic-component [component]="handler.data.component" [data]="handler.data.componentData"></core-dynamic-component>
</ng-template>
</core-tab>
</core-tabs>

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreCourseSectionPage } from './section';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreCourseComponentsModule } from '../../components/components.module';
@NgModule({

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, ViewChild, OnDestroy } from '@angular/core';
import { Component, ViewChild, OnDestroy, Injector } from '@angular/core';
import { IonicPage, NavParams, Content, NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
@ -25,7 +25,7 @@ import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
import { CoreCourseModulePrefetchDelegate } from '../../providers/module-prefetch-delegate';
import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate';
import { CoreCourseFormatComponent } from '../../components/format/format';
import { CoreCoursesProvider } from '../../../courses/providers/courses';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
/**
* Page that displays the list of courses the user is enrolled in.
@ -45,7 +45,6 @@ export class CoreCourseSectionPage implements OnDestroy {
sectionId: number;
sectionNumber: number;
courseHandlers: CoreCourseOptionsHandlerToDisplay[];
handlerData: any = {}; // Data to send to the handlers components.
dataLoaded: boolean;
downloadEnabled: boolean;
downloadEnabledIcon = 'square-outline'; // Disabled by default.
@ -64,13 +63,12 @@ export class CoreCourseSectionPage implements OnDestroy {
private courseFormatDelegate: CoreCourseFormatDelegate, private courseOptionsDelegate: CoreCourseOptionsDelegate,
private translate: TranslateService, private courseHelper: CoreCourseHelperProvider, eventsProvider: CoreEventsProvider,
private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider,
sitesProvider: CoreSitesProvider, private navCtrl: NavController,
sitesProvider: CoreSitesProvider, private navCtrl: NavController, private injector: Injector,
private prefetchDelegate: CoreCourseModulePrefetchDelegate) {
this.course = navParams.get('course');
this.sectionId = navParams.get('sectionId');
this.sectionNumber = navParams.get('sectionNumber');
this.module = navParams.get('module');
this.handlerData.courseId = this.course.id;
// Get the title to display. We dont't have sections yet.
this.title = courseFormatDelegate.getCourseTitle(this.course);
@ -193,7 +191,14 @@ export class CoreCourseSectionPage implements OnDestroy {
}));
// Load the course handlers.
promises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.course, refresh, false).then((handlers) => {
promises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.injector, this.course, refresh, false)
.then((handlers) => {
// Add the courseId to the handler component data.
handlers.forEach((handler) => {
handler.data.componentData = handler.data.componentData || {};
handler.data.componentData.courseId = this.course.id;
});
this.courseHandlers = handlers;
}));

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreCourseUnsupportedModulePage } from './unsupported-module';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreCourseComponentsModule } from '../../components/components.module';
@NgModule({

View File

@ -201,7 +201,7 @@ export class CoreCourseProvider {
* @return {Promise<any>} Promise resolved with the module.
*/
getModule(moduleId: number, courseId?: number, sectionId?: number, preferCache?: boolean, ignoreCache?: boolean,
siteId?: string): Promise<any> {
siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
let promise;

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCoursesProvider } from '../../courses/providers/courses';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCourseFormatHandler } from './format-delegate';
import { CoreCourseProvider } from './course';

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger';
@ -85,44 +85,54 @@ export interface CoreCourseFormatHandler extends CoreDelegateHandler {
* Return the Component to use to display the course format instead of using the default one.
* Use it if you want to display a format completely different from the default one.
* If you want to customize the default format there are several methods to customize parts of it.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getCourseFormatComponent?(course: any): any;
getCourseFormatComponent?(injector: Injector, course: any): any | Promise<any>;
/**
* Return the Component to use to display the course summary inside the default course format.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getCourseSummaryComponent?(course: any): any;
getCourseSummaryComponent?(injector: Injector, course: any): any | Promise<any>;
/**
* Return the Component to use to display the section selector inside the default course format.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getSectionSelectorComponent?(course: any): any;
getSectionSelectorComponent?(injector: Injector, course: any): any | Promise<any>;
/**
* Return the Component to use to display a single section. This component will only be used if the user is viewing a
* single section. If all the sections are displayed at once then it won't be used.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getSingleSectionComponent?(course: any): any;
getSingleSectionComponent?(injector: Injector, course: any): any | Promise<any>;
/**
* Return the Component to use to display all sections in a course.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getAllSectionsComponent?(course: any): any;
getAllSectionsComponent?(injector: Injector, course: any): any | Promise<any>;
/**
* Invalidate the data required to load the course format.
@ -199,31 +209,40 @@ export class CoreCourseFormatDelegate extends CoreDelegate {
/**
* Get the component to use to display all sections in a course.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {Promise<any>} Promise resolved with component to use, undefined if not found.
*/
getAllSectionsComponent(course: any): any {
return this.executeFunction(course.format, 'getAllSectionsComponent', [course]);
getAllSectionsComponent(injector: Injector, course: any): Promise<any> {
return Promise.resolve(this.executeFunction(course.format, 'getAllSectionsComponent', [injector, course])).catch((e) => {
this.logger.error('Error getting all sections component', e);
});
}
/**
* Get the component to use to display a course format.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {Promise<any>} Promise resolved with component to use, undefined if not found.
*/
getCourseFormatComponent(course: any): any {
return this.executeFunction(course.format, 'getCourseFormatComponent', [course]);
getCourseFormatComponent(injector: Injector, course: any): Promise<any> {
return Promise.resolve(this.executeFunction(course.format, 'getCourseFormatComponent', [injector, course])).catch((e) => {
this.logger.error('Error getting course format component', e);
});
}
/**
* Get the component to use to display the course summary in the default course format.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {Promise<any>} Promise resolved with component to use, undefined if not found.
*/
getCourseSummaryComponent(course: any): any {
return this.executeFunction(course.format, 'getCourseSummaryComponent', [course]);
getCourseSummaryComponent(injector: Injector, course: any): Promise<any> {
return Promise.resolve(this.executeFunction(course.format, 'getCourseSummaryComponent', [injector, course])).catch((e) => {
this.logger.error('Error getting course summary component', e);
});
}
/**
@ -259,22 +278,29 @@ export class CoreCourseFormatDelegate extends CoreDelegate {
/**
* Get the component to use to display the section selector inside the default course format.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {Promise<any>} Promise resolved with component to use, undefined if not found.
*/
getSectionSelectorComponent(course: any): any {
return this.executeFunction(course.format, 'getSectionSelectorComponent', [course]);
getSectionSelectorComponent(injector: Injector, course: any): Promise<any> {
return Promise.resolve(this.executeFunction(course.format, 'getSectionSelectorComponent', [injector, course]))
.catch((e) => {
this.logger.error('Error getting section selector component', e);
});
}
/**
* Get the component to use to display a single section. This component will only be used if the user is viewing
* a single section. If all the sections are displayed at once then it won't be used.
*
* @param {Injector} injector Injector.
* @param {any} course The course to render.
* @return {any} The component to use, undefined if not found.
* @return {Promise<any>} Promise resolved with component to use, undefined if not found.
*/
getSingleSectionComponent(course: any): any {
return this.executeFunction(course.format, 'getSingleSectionComponent', [course]);
getSingleSectionComponent(injector: Injector, course: any): Promise<any> {
return Promise.resolve(this.executeFunction(course.format, 'getSingleSectionComponent', [injector, course])).catch((e) => {
this.logger.error('Error getting single section component', e);
});
}
/**

View File

@ -12,23 +12,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events';
import { CoreFileProvider } from '@providers/file';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreFileHelperProvider } from '@providers/file-helper';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from './options-delegate';
import { CoreSiteHomeProvider } from '../../sitehome/providers/sitehome';
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
import { CoreCourseProvider } from './course';
import { CoreCourseModuleDelegate } from './module-delegate';
import { CoreCourseModulePrefetchDelegate } from './module-prefetch-delegate';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreConstants } from '../../constants';
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
import { CoreConstants } from '@core/constants';
import { CoreSite } from '@classes/site';
import * as moment from 'moment';
@ -116,7 +119,8 @@ export class CoreCourseHelperProvider {
private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider,
private utils: CoreUtilsProvider, private translate: TranslateService, private loginHelper: CoreLoginHelperProvider,
private courseOptionsDelegate: CoreCourseOptionsDelegate, private siteHomeProvider: CoreSiteHomeProvider,
private eventsProvider: CoreEventsProvider) { }
private eventsProvider: CoreEventsProvider, private fileHelper: CoreFileHelperProvider,
private appProvider: CoreAppProvider, private fileProvider: CoreFileProvider, private injector: Injector) { }
/**
* This function treats every module on the sections provided to load the handler data, treat completion
@ -271,7 +275,7 @@ export class CoreCourseHelperProvider {
if (courseHandlers) {
promise = Promise.resolve(courseHandlers);
} else {
promise = this.courseOptionsDelegate.getHandlersToDisplay(course);
promise = this.courseOptionsDelegate.getHandlersToDisplay(this.injector, course);
}
return promise.then((handlers: CoreCourseOptionsHandlerToDisplay[]) => {
@ -319,7 +323,7 @@ export class CoreCourseHelperProvider {
subPromises.push(this.courseProvider.getSections(course.id, false, true).then((courseSections) => {
sections = courseSections;
}));
subPromises.push(this.courseOptionsDelegate.getHandlersToDisplay(course).then((cHandlers) => {
subPromises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.injector, course).then((cHandlers) => {
handlers = cHandlers;
}));
@ -470,6 +474,227 @@ export class CoreCourseHelperProvider {
});
}
/**
* Convenience function to open a module main file, downloading the package if needed.
* This is meant for modules like mod_resource.
*
* @param {any} module The module to download.
* @param {number} courseId The course ID of the module.
* @param {string} [component] The component to link the files to.
* @param {string|number} [componentId] An ID to use in conjunction with the component.
* @param {any[]} [files] List of files of the module. If not provided, use module.contents.
* @param {string} [siteId] The site ID. If not defined, current site.
* @return {Promise<any>} Resolved on success.
*/
downloadModuleAndOpenFile(module: any, courseId: number, component?: string, componentId?: string | number, files?: any[],
siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
let promise;
if (files) {
promise = Promise.resolve(files);
} else {
promise = this.courseProvider.loadModuleContents(module, courseId).then(() => {
files = module.contents;
});
}
// Make sure that module contents are loaded.
return promise.then(() => {
if (!files || !files.length) {
return Promise.reject(null);
}
return this.sitesProvider.getSite(siteId);
}).then((site) => {
const mainFile = files[0],
fileUrl = this.fileHelper.getFileUrl(mainFile);
// Check if the file should be opened in browser.
if (this.fileHelper.shouldOpenInBrowser(mainFile)) {
if (this.appProvider.isOnline()) {
// Open in browser.
let fixedUrl = site.fixPluginfileURL(fileUrl).replace('&offline=1', '');
// Remove forcedownload when followed by another param.
fixedUrl = fixedUrl.replace(/forcedownload=\d+&/, '');
// Remove forcedownload when not followed by any param.
fixedUrl = fixedUrl.replace(/[\?|\&]forcedownload=\d+/, '');
this.utils.openInBrowser(fixedUrl);
if (this.fileProvider.isAvailable()) {
// Download the file if needed (file outdated or not downloaded).
// Download will be in background, don't return the promise.
this.downloadModule(module, courseId, component, componentId, files, siteId);
}
return;
} else {
// Not online, get the offline file. It will fail if not found.
return this.filepoolProvider.getInternalUrlByUrl(siteId, fileUrl).then((path) => {
return this.utils.openFile(path);
}).catch((error) => {
return Promise.reject(this.translate.instant('core.networkerrormsg'));
});
}
}
// File shouldn't be opened in browser. Download the module if it needs to be downloaded.
return this.downloadModuleWithMainFileIfNeeded(module, courseId, component, componentId, files, siteId)
.then((result) => {
if (result.path.indexOf('http') === 0) {
return this.utils.openOnlineFile(result.path).catch((error) => {
// Error opening the file, some apps don't allow opening online files.
if (!this.fileProvider.isAvailable()) {
return Promise.reject(error);
} else if (result.status === CoreConstants.DOWNLOADING) {
return Promise.reject(this.translate.instant('core.erroropenfiledownloading'));
}
let promise;
if (result.status === CoreConstants.NOT_DOWNLOADED) {
// Not downloaded, download it now and return the local file.
promise = this.downloadModule(module, courseId, component, componentId, files, siteId).then(() => {
return this.filepoolProvider.getInternalUrlByUrl(siteId, fileUrl);
});
} else {
// File is outdated or stale and can't be opened in online, return the local URL.
promise = this.filepoolProvider.getInternalUrlByUrl(siteId, fileUrl);
}
return promise.then((path) => {
return this.utils.openFile(path);
});
});
} else {
return this.utils.openFile(result.path);
}
});
});
}
/**
* Convenience function to download a module that has a main file and return the local file's path and other info.
* This is meant for modules like mod_resource.
*
* @param {any} module The module to download.
* @param {number} courseId The course ID of the module.
* @param {string} [component] The component to link the files to.
* @param {string|number} [componentId] An ID to use in conjunction with the component.
* @param {any[]} [files] List of files of the module. If not provided, use module.contents.
* @param {string} [siteId] The site ID. If not defined, current site.
* @return {Promise<{fixedUrl: string, path: string, status: string}>} Promise resolved when done.
*/
protected downloadModuleWithMainFileIfNeeded(module: any, courseId: number, component?: string, componentId?: string | number,
files?: any[], siteId?: string): Promise<{fixedUrl: string, path: string, status: string}> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (!files || !files.length) {
// Module not valid, stop.
return Promise.reject(null);
}
const mainFile = files[0],
fileUrl = this.fileHelper.getFileUrl(mainFile),
timemodified = this.fileHelper.getFileTimemodified(mainFile),
prefetchHandler = this.prefetchDelegate.getPrefetchHandlerFor(module),
result = {
fixedUrl: undefined,
path: undefined,
status: undefined
};
return this.sitesProvider.getSite(siteId).then((site) => {
const fixedUrl = site.fixPluginfileURL(fileUrl);
result.fixedUrl = fixedUrl;
if (this.fileProvider.isAvailable()) {
// The file system is available.
return this.filepoolProvider.getPackageStatus(siteId, component, componentId).then((status) => {
result.status = status;
const isWifi = !this.appProvider.isNetworkAccessLimited(),
isOnline = this.appProvider.isOnline();
if (status === CoreConstants.DOWNLOADED) {
// Get the local file URL.
return this.filepoolProvider.getInternalUrlByUrl(siteId, fileUrl);
} else if (status === CoreConstants.DOWNLOADING && !this.appProvider.isDesktop()) {
// Return the online URL.
return fixedUrl;
} else {
if (!isOnline && status === CoreConstants.NOT_DOWNLOADED) {
// Not downloaded and we're offline, reject.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
return this.filepoolProvider.shouldDownloadBeforeOpen(fixedUrl, mainFile.filesize).then(() => {
// Download and then return the local URL.
return this.downloadModule(module, courseId, component, componentId, files, siteId).then(() => {
return this.filepoolProvider.getInternalUrlByUrl(siteId, fileUrl);
});
}, () => {
// Start the download if in wifi, but return the URL right away so the file is opened.
if (isWifi && isOnline) {
this.downloadModule(module, courseId, component, componentId, files, siteId);
}
if (!this.fileHelper.isStateDownloaded(status) || isOnline) {
// Not downloaded or online, return the online URL.
return fixedUrl;
} else {
// Outdated but offline, so we return the local URL. Use getUrlByUrl so it's added to the queue.
return this.filepoolProvider.getUrlByUrl(siteId, fileUrl, component, componentId, timemodified,
false, false, mainFile);
}
});
}
}).then((path) => {
result.path = path;
return result;
});
} else {
// We use the live URL.
result.path = fixedUrl;
return result;
}
});
}
/**
* Convenience function to download a module.
*
* @param {any} module The module to download.
* @param {number} courseId The course ID of the module.
* @param {string} [component] The component to link the files to.
* @param {string|number} [componentId] An ID to use in conjunction with the component.
* @param {any[]} [files] List of files of the module. If not provided, use module.contents.
* @param {string} [siteId] The site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
downloadModule(module: any, courseId: number, component?: string, componentId?: string | number, files?: any[], siteId?: string)
: Promise<any> {
const prefetchHandler = this.prefetchDelegate.getPrefetchHandlerFor(module);
if (prefetchHandler) {
// Use the prefetch handler to download the module.
if (prefetchHandler.download) {
return prefetchHandler.download(module, courseId);
} else {
return prefetchHandler.prefetch(module, courseId, true);
}
}
// There's no prefetch handler for the module, just download the files.
files = files || module.contents;
return this.filepoolProvider.downloadOrPrefetchFiles(siteId, files, false, false, component, componentId);
}
/**
* Fill the Context Menu for a certain module.
*
@ -605,8 +830,13 @@ export class CoreCourseHelperProvider {
moduleInfo.statusIcon = 'spinner';
break;
case CoreConstants.OUTDATED:
moduleInfo.statusIcon = 'ion-android-refresh';
moduleInfo.statusIcon = 'refresh';
break;
case CoreConstants.DOWNLOADED:
if (!this.prefetchDelegate.canCheckUpdates()) {
moduleInfo.statusIcon = 'refresh';
break;
}
default:
moduleInfo.statusIcon = '';
break;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { NavController, NavOptions } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger';
@ -38,12 +38,14 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
/**
* Get the component to render the module. This is needed to support singleactivity course format.
* The component returned must implement CoreCourseModuleMainComponent.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} course The course object.
* @param {any} module The module object.
* @return {any} The component to use, undefined if not found.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getMainComponent(course: any, module: any): any;
getMainComponent(injector: Injector, course: any, module: any): any | Promise<any>;
}
/**
@ -176,17 +178,17 @@ export class CoreCourseModuleDelegate extends CoreDelegate {
/**
* Get the component to render the module.
*
* @param {Injector} injector Injector.
* @param {any} course The course object.
* @param {any} module The module object.
* @return {any} The component to use, undefined if not found.
* @return {Promise<any>} Promise resolved with component to use, undefined if not found.
*/
getMainComponent?(course: any, module: any): any {
getMainComponent(injector: Injector, course: any, module: any): Promise<any> {
const handler = this.enabledHandlers[module.modname];
if (handler && handler.getMainComponent) {
const component = handler.getMainComponent(course, module);
if (component) {
return component;
}
return Promise.resolve(handler.getMainComponent(injector, course, module)).catch((err) => {
this.logger.error('Error getting main component', err);
});
}
}

View File

@ -86,9 +86,20 @@ export interface CoreCourseModulePrefetchHandler extends CoreDelegateHandler {
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean): Promise<any>;
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any>;
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download?(module: any, courseId: number, dirPath?: string): Promise<any>;
/**
* Check if a certain module can use core_course_check_updates to check if it has updates.
@ -141,8 +152,8 @@ export interface CoreCourseModulePrefetchHandler extends CoreDelegateHandler {
hasUpdates?(module: any, courseId: number, moduleUpdates: any[]): boolean | Promise<boolean>;
/**
* Invalidate WS calls needed to determine module status. It doesn't need to invalidate check updates.
* It should NOT invalidate files nor all the prefetched data.
* Invalidate WS calls needed to determine module status (usually, to check if module is downloadable).
* It doesn't need to invalidate check updates. It should NOT invalidate files nor all the prefetched data.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.

View File

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreUtilsProvider, PromiseDefer } from '@providers/utils/utils';
import { CoreCoursesProvider } from '../../courses/providers/courses';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCourseProvider } from './course';
/**
@ -45,10 +45,11 @@ export interface CoreCourseOptionsHandler extends CoreDelegateHandler {
/**
* Returns the data needed to render the handler.
*
* @param {Injector} injector Injector.
* @param {number} courseId The course ID.
* @return {CoreCourseOptionsHandlerData} Data.
* @return {CoreCourseOptionsHandlerData|Promise<CoreCourseOptionsHandlerData>} Data or promise resolved with the data.
*/
getDisplayData?(courseId: number): CoreCourseOptionsHandlerData;
getDisplayData?(injector: Injector, courseId: number): CoreCourseOptionsHandlerData | Promise<CoreCourseOptionsHandlerData>;
/**
* Should invalidate the data to determine if the handler is enabled for a certain course.
@ -90,6 +91,12 @@ export interface CoreCourseOptionsHandlerData {
* When the component is created, it will receive the courseId as input.
*/
component: any;
/**
* Data to pass to the component. All the properties in this object will be passed to the component as inputs.
* @type {any}
*/
componentData?: any;
}
/**
@ -237,6 +244,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
* Get the list of handlers that should be displayed for a course.
* This function should be called only when the handlers need to be displayed, since it can call several WebServices.
*
* @param {Injector} injector Injector.
* @param {any} course The course object.
* @param {boolean} [refresh] True if it should refresh the list.
* @param {boolean} [isGuest] Whether it's guest.
@ -244,7 +252,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
* @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
* @return {Promise<CoreCourseOptionsHandlerToDisplay[]>} Promise resolved with array of handlers.
*/
getHandlersToDisplay(course: any, refresh?: boolean, isGuest?: boolean, navOptions?: any, admOptions?: any):
getHandlersToDisplay(injector: Injector, course: any, refresh?: boolean, isGuest?: boolean, navOptions?: any, admOptions?: any):
Promise<CoreCourseOptionsHandlerToDisplay[]> {
course.id = parseInt(course.id, 10);
@ -263,14 +271,19 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
// Call getHandlersForAccess to make sure the handlers have been loaded.
return this.getHandlersForAccess(course.id, refresh, accessData, course.navOptions, course.admOptions);
}).then(() => {
const handlersToDisplay: CoreCourseOptionsHandlerToDisplay[] = [];
const handlersToDisplay: CoreCourseOptionsHandlerToDisplay[] = [],
promises = [];
this.coursesHandlers[course.id].enabledHandlers.forEach((handler) => {
handlersToDisplay.push({
data: handler.getDisplayData(course),
priority: handler.priority,
prefetch: handler.prefetch
});
promises.push(Promise.resolve(handler.getDisplayData(injector, course)).then((data) => {
handlersToDisplay.push({
data: data,
priority: handler.priority,
prefetch: handler.prefetch
});
}).catch((err) => {
this.logger.error('Error getting data for handler', handler.name, err);
}));
});
// Sort them by priority.

View File

@ -17,8 +17,8 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { CoreCoursesCourseProgressComponent } from '../components/course-progress/course-progress';
import { CoreCoursesCourseListItemComponent } from '../components/course-list-item/course-list-item';
import { CoreCoursesOverviewEventsComponent } from '../components/overview-events/overview-events';

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, Optional } from '@angular/core';
import { NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreCoursesProvider } from '../../providers/courses';
@ -31,7 +31,8 @@ import { CoreCoursesProvider } from '../../providers/courses';
export class CoreCoursesCourseListItemComponent implements OnInit {
@Input() course: any; // The course to render.
constructor(private navCtrl: NavController, private translate: TranslateService, private coursesProvider: CoreCoursesProvider) {
constructor(@Optional() private navCtrl: NavController, private translate: TranslateService,
private coursesProvider: CoreCoursesProvider) {
}
/**

View File

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { Component, Input, OnInit, OnDestroy, Optional } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCourseFormatDelegate } from '../../../course/providers/format-delegate';
import { CoreCourseProvider } from '../../../course/providers/course';
import { CoreCourseHelperProvider } from '../../../course/providers/helper';
import { CoreCourseFormatDelegate } from '@core/course/providers/format-delegate';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
/**
* This component is meant to display a course for a list of courses with progress.
@ -44,7 +44,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
protected isDestroyed = false;
protected courseStatusObserver;
constructor(private navCtrl: NavController, private courseHelper: CoreCourseHelperProvider,
constructor(@Optional() private navCtrl: NavController, private courseHelper: CoreCourseHelperProvider,
private courseFormatDelegate: CoreCourseFormatDelegate, private domUtils: CoreDomUtilsProvider,
private courseProvider: CoreCourseProvider, eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider) {
// Listen for status change in course.

View File

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, OnChanges, EventEmitter, SimpleChange } from '@angular/core';
import { Component, Input, Output, OnChanges, EventEmitter, SimpleChange, Optional } 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 { CoreCourseProvider } from '@core/course/providers/course';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import * as moment from 'moment';
/**
@ -43,9 +43,10 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
next30Days: any[] = [];
future: any[] = [];
constructor(private navCtrl: NavController, private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider,
private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider,
private courseProvider: CoreCourseProvider, private contentLinksHelper: CoreContentLinksHelperProvider) {
constructor(@Optional() private navCtrl: NavController, private utils: CoreUtilsProvider,
private textUtils: CoreTextUtilsProvider, private domUtils: CoreDomUtilsProvider,
private sitesProvider: CoreSitesProvider, private courseProvider: CoreCourseProvider,
private contentLinksHelper: CoreContentLinksHelperProvider) {
this.loadMore = new EventEmitter();
}

View File

@ -19,21 +19,25 @@ import { CoreCoursesMyOverviewProvider } from './providers/my-overview';
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';
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
// List of providers (without handlers).
export const CORE_COURSES_PROVIDERS: any[] = [
CoreCoursesProvider,
CoreCoursesMyOverviewProvider
];
@NgModule({
declarations: [],
imports: [
],
providers: [
CoreCoursesProvider,
providers: CORE_COURSES_PROVIDERS.concat([
CoreCoursesMainMenuHandler,
CoreCoursesMyOverviewProvider,
CoreCoursesCourseLinkHandler,
CoreCoursesIndexLinkHandler,
CoreCoursesMyOverviewLinkHandler
],
]),
exports: []
})
export class CoreCoursesModule {

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreCoursesCategoriesPage } from './categories';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreCoursesComponentsModule } from '../../components/components.module';
@NgModule({

View File

@ -17,8 +17,8 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreCoursesCoursePreviewPage } from './course-preview';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [

View File

@ -21,9 +21,9 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCourseOptionsDelegate } from '../../../course/providers/options-delegate';
import { CoreCourseProvider } from '../../../course/providers/course';
import { CoreCourseHelperProvider } from '../../../course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
/**
* Page that allows "previewing" a course and enrolling in it if enabled and not enrolled.

View File

@ -18,8 +18,8 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCourseHelperProvider } from '../../../course/providers/helper';
import { CoreCourseOptionsDelegate } from '../../../course/providers/options-delegate';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
/**
* Page that displays the list of courses the user is enrolled in.

View File

@ -18,7 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreCoursesMyOverviewPage } from './my-overview';
import { CoreComponentsModule } from '@components/components.module';
import { CoreCoursesComponentsModule } from '../../components/components.module';
import { CoreSiteHomeComponentsModule } from '../../../sitehome/components/components.module';
import { CoreSiteHomeComponentsModule } from '@core/sitehome/components/components.module';
@NgModule({
declarations: [

View File

@ -18,9 +18,9 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCoursesMyOverviewProvider } from '../../providers/my-overview';
import { CoreCourseHelperProvider } from '../../../course/providers/helper';
import { CoreCourseOptionsDelegate } from '../../../course/providers/options-delegate';
import { CoreSiteHomeProvider } from '../../../sitehome/providers/sitehome';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
import * as moment from 'moment';
/**

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { CoreCoursesSelfEnrolPasswordPage } from './self-enrol-password';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -16,10 +16,10 @@ 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 { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCoursesProvider } from './courses';
/**

View File

@ -13,9 +13,9 @@
// 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 { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
import { CoreCoursesProvider } from './courses';
/**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core';
import { CoreCoursesProvider } from './courses';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../../mainmenu/providers/delegate';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
import { CoreCoursesMyOverviewProvider } from '../providers/my-overview';
/**

View File

@ -13,9 +13,9 @@
// 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 { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
/**
* Handler to treat links to my overview.

View File

@ -56,6 +56,24 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreInitDelegate } from '@providers/init';
// List of Ionic Native providers.
export const IONIC_NATIVE_PROVIDERS = [
Camera,
Clipboard,
File,
FileTransfer,
Globalization,
InAppBrowser,
Keyboard,
LocalNotifications,
MediaCapture,
Network,
SplashScreen,
StatusBar,
SQLite,
Zip
];
/**
* This module handles the emulation of Cordova plugins in browser and desktop.
*

View File

@ -17,7 +17,7 @@ import { LocalNotifications, ILocalNotification } from '@ionic-native/local-noti
import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { SQLiteDB } from '@classes/sqlitedb';
import { CoreConstants } from '../../constants';
import { CoreConstants } from '@core/constants';
import { CoreConfigConstants } from '../../../configconstants';
import * as moment from 'moment';

View File

@ -22,21 +22,25 @@ import { CoreFileUploaderCameraHandler } from './providers/camera-handler';
import { CoreFileUploaderFileHandler } from './providers/file-handler';
import { CoreFileUploaderVideoHandler } from './providers/video-handler';
// List of providers (without handlers).
export const CORE_FILEUPLOADER_PROVIDERS: any[] = [
CoreFileUploaderProvider,
CoreFileUploaderHelperProvider,
CoreFileUploaderDelegate
];
@NgModule({
declarations: [
],
imports: [
],
providers: [
CoreFileUploaderProvider,
CoreFileUploaderHelperProvider,
CoreFileUploaderDelegate,
providers: CORE_FILEUPLOADER_PROVIDERS.concat([
CoreFileUploaderAlbumHandler,
CoreFileUploaderAudioHandler,
CoreFileUploaderCameraHandler,
CoreFileUploaderFileHandler,
CoreFileUploaderVideoHandler
]
])
})
export class CoreFileUploaderModule {
constructor(delegate: CoreFileUploaderDelegate, albumHandler: CoreFileUploaderAlbumHandler,

View File

@ -18,8 +18,8 @@ import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreGradesCourseComponent } from './course/course';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [

View File

@ -39,8 +39,9 @@ export class CoreGradesCourseComponent {
gradesTable: any;
constructor(private gradesProvider: CoreGradesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams,
private gradesHelper: CoreGradesHelperProvider, private sitesProvider: CoreSitesProvider, private navCtrl: NavController,
private appProvider: CoreAppProvider, @Optional() private svComponent: CoreSplitViewComponent) {
private gradesHelper: CoreGradesHelperProvider, private sitesProvider: CoreSitesProvider,
@Optional() private navCtrl: NavController, private appProvider: CoreAppProvider,
@Optional() private svComponent: CoreSplitViewComponent) {
}
/**

View File

@ -15,19 +15,25 @@
import { NgModule } from '@angular/core';
import { CoreGradesProvider } from './providers/grades';
import { CoreGradesHelperProvider } from './providers/helper';
import { CoreMainMenuDelegate } from '../mainmenu/providers/delegate';
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
import { CoreGradesMainMenuHandler } from './providers/mainmenu-handler';
import { CoreGradesCourseOptionHandler } from './providers/course-option-handler';
import { CoreGradesComponentsModule } from './components/components.module';
import { CoreCourseOptionsDelegate } from '../course/providers/options-delegate';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { CoreGradesUserLinkHandler } from './providers/user-link-handler';
import { CoreGradesOverviewLinkHandler } from './providers/overview-link-handler';
import { CoreContentLinksDelegate } from '../contentlinks/providers/delegate';
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
import { CoreGradesUserHandler } from './providers/user-handler';
import { CoreUserDelegate } from '../user/providers/user-delegate';
import { CoreUserDelegate } from '@core/user/providers/user-delegate';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreUserProvider } from '../user/providers/user';
import { CoreUserProvider } from '@core/user/providers/user';
// List of providers (without handlers).
export const CORE_GRADES_PROVIDERS: any[] = [
CoreGradesProvider,
CoreGradesHelperProvider
];
@NgModule({
declarations: [
@ -35,15 +41,13 @@ import { CoreUserProvider } from '../user/providers/user';
imports: [
CoreGradesComponentsModule
],
providers: [
CoreGradesProvider,
CoreGradesHelperProvider,
providers: CORE_GRADES_PROVIDERS.concat([
CoreGradesMainMenuHandler,
CoreGradesCourseOptionHandler,
CoreGradesUserLinkHandler,
CoreGradesOverviewLinkHandler,
CoreGradesUserHandler
]
])
})
export class CoreGradesModule {
constructor(mainMenuDelegate: CoreMainMenuDelegate, gradesMenuHandler: CoreGradesMainMenuHandler,

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreGradesCoursesPage } from './courses';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreGradesGradePage } from './grade';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '../../course/providers/options-delegate';
import { CoreCourseProvider } from '../../course/providers/course';
import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGradesProvider } from './grades';
import { CoreCoursesProvider } from '../../courses/providers/courses';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreGradesCourseComponent } from '../components/course/course';
/**
@ -80,9 +80,11 @@ export class CoreGradesCourseOptionHandler implements CoreCourseOptionsHandler {
/**
* Returns the data needed to render the handler.
*
* @return {CoreCourseOptionsHandlerData} Data needed to render the handler.
* @param {Injector} injector Injector.
* @param {number} courseId The course ID.
* @return {CoreCourseOptionsHandlerData|Promise<CoreCourseOptionsHandlerData>} Data or promise resolved with the data.
*/
getDisplayData(): CoreCourseOptionsHandlerData {
getDisplayData(injector: Injector, courseId: number): CoreCourseOptionsHandlerData | Promise<CoreCourseOptionsHandlerData> {
return {
title: 'core.grades.grades',
class: 'core-grades-course-handler',

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSite } from '@classes/site';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '../../courses/providers/courses';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
/**
* Service to provide grade functionalities.

View File

@ -16,8 +16,8 @@ import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { TranslateService } from '@ngx-translate/core';
import { CoreCoursesProvider } from '../../courses/providers/courses';
import { CoreCourseProvider } from '../../course/providers/course';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGradesProvider } from './grades';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url';

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core';
import { CoreGradesProvider } from './grades';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../../mainmenu/providers/delegate';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
/**
* Handler to inject an option into main menu.

View File

@ -13,9 +13,9 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '../../contentlinks/providers/delegate';
import { CoreContentLinksHelperProvider } from '../../contentlinks/providers/helper';
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { CoreGradesProvider } from './grades';
/**

View File

@ -13,9 +13,9 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '../../user/providers/user-delegate';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
import { CoreSitesProvider } from '@providers/sites';
import { CoreContentLinksHelperProvider } from '../../contentlinks/providers/helper';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { CoreGradesProvider } from './grades';
/**

View File

@ -13,9 +13,9 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '../../contentlinks/providers/delegate';
import { CoreContentLinksHelperProvider } from '../../contentlinks/providers/helper';
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { CoreGradesProvider } from './grades';
/**

View File

@ -15,13 +15,16 @@
import { NgModule } from '@angular/core';
import { CoreLoginHelperProvider } from './providers/helper';
// List of providers.
export const CORE_LOGIN_PROVIDERS = [
CoreLoginHelperProvider
];
@NgModule({
declarations: [
],
imports: [
],
providers: [
CoreLoginHelperProvider
]
providers: CORE_LOGIN_PROVIDERS
})
export class CoreLoginModule {}

View File

@ -17,7 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { CoreLoginCredentialsPage } from './credentials';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [

View File

@ -21,8 +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 { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
/**

View File

@ -17,8 +17,8 @@ import { IonicPageModule } from 'ionic-angular';
import { CoreLoginEmailSignupPage } from './email-signup';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CoreUserComponentsModule } from '../../../user/components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreUserComponentsModule } from '@core/user/components/components.module';
@NgModule({
declarations: [

View File

@ -22,7 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreWSProvider } from '@providers/ws';
import { CoreLoginHelperProvider } from '../../providers/helper';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { CoreUserProfileFieldDelegate } from '../../../user/providers/user-profile-field-delegate';
import { CoreUserProfileFieldDelegate } from '@core/user/providers/user-profile-field-delegate';
/**
* Page to signup using email.

Some files were not shown because too many files have changed in this diff Show More