MOBILE-3664 siteplugins: Implement directives

main
Dani Palou 2021-03-04 08:15:44 +01:00
parent a4046f5678
commit f5a7da148f
8 changed files with 651 additions and 26 deletions

View File

@ -64,7 +64,7 @@ import { CORE_SITEHOME_SERVICES } from '@features/sitehome/sitehome.module';
import { CORE_TAG_SERVICES } from '@features/tag/tag.module';
import { CORE_USER_SERVICES } from '@features/user/user.module';
import { CORE_XAPI_SERVICES } from '@features/xapi/xapi.module';
// @todo import { CoreSitePluginsProvider } from '@features/siteplugins/services/siteplugins';
import { CoreSitePluginsProvider } from '@features/siteplugins/services/siteplugins';
// Import other libraries and providers.
import { DomSanitizer } from '@angular/platform-browser';
@ -93,7 +93,7 @@ import { CoreSharedModule } from '@/core/shared.module';
import { CoreCourseComponentsModule } from '@features/course/components/components.module';
import { CoreCourseDirectivesModule } from '@features/course/directives/directives.module';
import { CoreCoursesComponentsModule } from '@features/courses/components/components.module';
// @todo import { CoreSitePluginsDirectivesModule } from '@features/siteplugins/directives/directives.module';
import { CoreSitePluginsDirectivesModule } from '@features/siteplugins/directives/directives.module';
import { CoreUserComponentsModule } from '@features/user/components/components.module';
import { CoreQuestionComponentsModule } from '@features/question/components/components.module';
import { CoreBlockComponentsModule } from '@features/block/components/components.module';
@ -103,17 +103,15 @@ import { CoreSearchComponentsModule } from '@features/search/components/componen
// Import some components so they can be injected dynamically.
import { CoreCourseUnsupportedModuleComponent } from '@features/course/components/unsupported-module/unsupported-module';
import { CoreCourseFormatSingleActivityComponent } from '@features/course/format/singleactivity/components/singleactivity';
// @todo
// import { CoreSitePluginsModuleIndexComponent } from '@features/siteplugins/components/module-index/module-index';
// import { CoreSitePluginsBlockComponent } from '@features/siteplugins/components/block/block';
// import { CoreSitePluginsCourseOptionComponent } from '@features/siteplugins/components/course-option/course-option';
// import { CoreSitePluginsCourseFormatComponent } from '@features/siteplugins/components/course-format/course-format';
// import { CoreSitePluginsQuestionComponent } from '@features/siteplugins/components/question/question';
// import { CoreSitePluginsQuestionBehaviourComponent } from '@features/siteplugins/components/question-behaviour/question-behaviour';
// import { CoreSitePluginsUserProfileFieldComponent } from '@features/siteplugins/components/user-profile-field/user-profile-field';
// import { CoreSitePluginsQuizAccessRuleComponent } from '@features/siteplugins/components/quiz-access-rule/quiz-access-rule';
// import { CoreSitePluginsAssignFeedbackComponent } from '@features/siteplugins/components/assign-feedback/assign-feedback';
// import { CoreSitePluginsAssignSubmissionComponent } from '@features/siteplugins/components/assign-submission/assign-submission';
import { CoreSitePluginsModuleIndexComponent } from '@features/siteplugins/components/module-index/module-index';
import { CoreSitePluginsBlockComponent } from '@features/siteplugins/components/block/block';
import { CoreSitePluginsCourseFormatComponent } from '@features/siteplugins/components/course-format/course-format';
import { CoreSitePluginsQuestionComponent } from '@features/siteplugins/components/question/question';
import { CoreSitePluginsQuestionBehaviourComponent } from '@features/siteplugins/components/question-behaviour/question-behaviour';
import { CoreSitePluginsUserProfileFieldComponent } from '@features/siteplugins/components/user-profile-field/user-profile-field';
import { CoreSitePluginsQuizAccessRuleComponent } from '@features/siteplugins/components/quiz-access-rule/quiz-access-rule';
import { CoreSitePluginsAssignFeedbackComponent } from '@features/siteplugins/components/assign-feedback/assign-feedback';
import { CoreSitePluginsAssignSubmissionComponent } from '@features/siteplugins/components/assign-submission/assign-submission';
// Import addon providers. Do not import database module because it causes circular dependencies.
import { ADDON_BADGES_SERVICES } from '@addons/badges/badges.module';
@ -169,8 +167,8 @@ export class CoreCompileProvider {
protected readonly IMPORTS = [
CoreSharedModule, CoreCourseComponentsModule, CoreCoursesComponentsModule, CoreUserComponentsModule,
CoreCourseDirectivesModule, CoreQuestionComponentsModule, AddonModAssignComponentsModule,
CoreBlockComponentsModule, CoreEditorComponentsModule, CoreSearchComponentsModule,
// @todo AddonModWorkshopComponentsModule, CoreSitePluginsDirectivesModule,
CoreBlockComponentsModule, CoreEditorComponentsModule, CoreSearchComponentsModule, CoreSitePluginsDirectivesModule,
// @todo AddonModWorkshopComponentsModule,
];
constructor(protected injector: Injector, compilerFactory: JitCompilerFactory) {
@ -272,7 +270,7 @@ export class CoreCompileProvider {
...CORE_SETTINGS_SERVICES,
// @todo ...CORE_SHAREDFILES_SERVICES,
...CORE_SITEHOME_SERVICES,
// @todo ...CoreSitePluginsProvider,
CoreSitePluginsProvider,
...CORE_TAG_SERVICES,
...CORE_USER_SERVICES,
...CORE_XAPI_SERVICES,
@ -348,16 +346,15 @@ export class CoreCompileProvider {
instance['CoreCourseResourcePrefetchHandlerBase'] = CoreCourseResourcePrefetchHandlerBase;
instance['CoreCourseUnsupportedModuleComponent'] = CoreCourseUnsupportedModuleComponent;
instance['CoreCourseFormatSingleActivityComponent'] = CoreCourseFormatSingleActivityComponent;
// @todo instance['CoreSitePluginsModuleIndexComponent'] = CoreSitePluginsModuleIndexComponent;
// instance['CoreSitePluginsBlockComponent'] = CoreSitePluginsBlockComponent;
// instance['CoreSitePluginsCourseOptionComponent'] = CoreSitePluginsCourseOptionComponent;
// instance['CoreSitePluginsCourseFormatComponent'] = CoreSitePluginsCourseFormatComponent;
// instance['CoreSitePluginsQuestionComponent'] = CoreSitePluginsQuestionComponent;
// instance['CoreSitePluginsQuestionBehaviourComponent'] = CoreSitePluginsQuestionBehaviourComponent;
// instance['CoreSitePluginsUserProfileFieldComponent'] = CoreSitePluginsUserProfileFieldComponent;
// instance['CoreSitePluginsQuizAccessRuleComponent'] = CoreSitePluginsQuizAccessRuleComponent;
// instance['CoreSitePluginsAssignFeedbackComponent'] = CoreSitePluginsAssignFeedbackComponent;
// instance['CoreSitePluginsAssignSubmissionComponent'] = CoreSitePluginsAssignSubmissionComponent;
instance['CoreSitePluginsModuleIndexComponent'] = CoreSitePluginsModuleIndexComponent;
instance['CoreSitePluginsBlockComponent'] = CoreSitePluginsBlockComponent;
instance['CoreSitePluginsCourseFormatComponent'] = CoreSitePluginsCourseFormatComponent;
instance['CoreSitePluginsQuestionComponent'] = CoreSitePluginsQuestionComponent;
instance['CoreSitePluginsQuestionBehaviourComponent'] = CoreSitePluginsQuestionBehaviourComponent;
instance['CoreSitePluginsUserProfileFieldComponent'] = CoreSitePluginsUserProfileFieldComponent;
instance['CoreSitePluginsQuizAccessRuleComponent'] = CoreSitePluginsQuizAccessRuleComponent;
instance['CoreSitePluginsAssignFeedbackComponent'] = CoreSitePluginsAssignFeedbackComponent;
instance['CoreSitePluginsAssignSubmissionComponent'] = CoreSitePluginsAssignSubmissionComponent;
instance['CoreGeolocationError'] = CoreGeolocationError;
instance['CoreGeolocationErrorReason'] = CoreGeolocationErrorReason;
}

View File

@ -0,0 +1,82 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { Input, OnInit, ElementRef, Directive } from '@angular/core';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { Translate } from '@singletons';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';
import { CoreSitePluginsCallWSBaseDirective } from './call-ws-directive';
/**
* Base class for directives to call a WS when the element is clicked.
*
* The directives that inherit from this class will call a WS method when the element is clicked.
*/
@Directive()
export class CoreSitePluginsCallWSOnClickBaseDirective extends CoreSitePluginsCallWSBaseDirective implements OnInit {
@Input() confirmMessage?: string; // Message to confirm the action. If not supplied, no confirmation. If empty, default message.
@Input() showError?: boolean | string; // Whether to show an error message if the WS call fails. Defaults to true.
constructor(
element: ElementRef,
parentContent: CoreSitePluginsPluginContentComponent | null,
) {
super(element, parentContent);
}
/**
* @inheritdoc
*/
ngOnInit(): void {
super.ngOnInit();
this.element.addEventListener('click', async (ev: Event) => {
ev.preventDefault();
ev.stopPropagation();
if (typeof this.confirmMessage != 'undefined') {
// Ask for confirm.
try {
await CoreDomUtils.showConfirm(this.confirmMessage || Translate.instant('core.areyousure'));
} catch {
// User cancelled, stop.
return;
}
}
this.callWS();
});
}
/**
* @inheritdoc
*/
protected async callWS(): Promise<void> {
const modal = await CoreDomUtils.showModalLoading();
try {
await super.callWS();
} catch (error) {
if (typeof this.showError == 'undefined' || CoreUtils.isTrueOrOne(this.showError)) {
CoreDomUtils.showErrorModalDefault(error, 'core.serverconnection', true);
}
} finally {
modal.dismiss();
}
}
}

View File

@ -0,0 +1,135 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { Input, OnInit, OnDestroy, ElementRef, Output, EventEmitter, Directive } from '@angular/core';
import { Subscription } from 'rxjs';
import { CoreSiteWSPreSets } from '@classes/site';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';
import { CoreSitePlugins } from '../services/siteplugins';
import { CoreLogger } from '@singletons/logger';
/**
* Base class for directives that need to call a WS.
*/
@Directive()
export class CoreSitePluginsCallWSBaseDirective implements OnInit, OnDestroy {
@Input() name!: string; // The name of the WS to call.
@Input() params?: Record<string, unknown>; // The params for the WS call.
@Input() preSets?: CoreSiteWSPreSets; // The preSets for the WS call.
@Input() useOtherDataForWS?: string[] | unknown; // Whether to include other data in the params for the WS.
@Input() form?: string; // ID or name to identify a form. The form data will be retrieved and sent to the WS.
@Output() onSuccess = new EventEmitter<unknown>(); // Sends the result when the WS call succeeds.
@Output() onError = new EventEmitter<unknown>(); // Sends the error when the WS call fails.
@Output() onDone = new EventEmitter<void>(); // Notifies when the WS call is done (either success or fail).
protected logger: CoreLogger;
protected element: HTMLElement;
protected invalidateObserver?: Subscription;
constructor(
element: ElementRef,
protected parentContent: CoreSitePluginsPluginContentComponent | null,
) {
this.element = element.nativeElement || element;
this.logger = CoreLogger.getInstance('CoreSitePluginsCallWS');
}
/**
* @inheritdoc
*/
ngOnInit(): void {
if (!this.parentContent?.invalidateObservable) {
return;
}
this.invalidateObserver = this.parentContent.invalidateObservable.subscribe(() => {
this.invalidate();
});
}
/**
* Call a WS.
*
* @return Promise resolved when done.
*/
protected async callWS(): Promise<void> {
try {
const params = this.getParamsForWS();
const result = await CoreSitePlugins.callWS(this.name, params, this.preSets);
this.onSuccess.emit(result);
return this.wsCallSuccess(result);
} catch (error) {
this.onError.emit(error);
this.logger.error(`Error calling WS ${this.name}`, error);
throw error;
} finally {
this.onDone.emit();
}
}
/**
* Get the params for the WS call.
*
* @return Params.
*/
protected getParamsForWS(): Record<string, unknown> {
let params = this.params || {};
if (this.parentContent) {
params = CoreSitePlugins.loadOtherDataInArgs(params, this.parentContent.otherData, this.useOtherDataForWS);
}
if (this.form && document.forms[this.form]) {
params = Object.assign(params, CoreDomUtils.getDataFromForm(document.forms[this.form]));
}
return params;
}
/**
* Function called when the WS call is successful.
*
* @param result Result of the WS call.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected wsCallSuccess(result: unknown): void {
// Function to be overridden.
}
/**
* Invalidate the WS call.
*
* @return Promise resolved when done.
*/
invalidate(): Promise<void> {
const params = this.getParamsForWS();
return CoreSitePlugins.instance.invalidateCallWS(this.name, params, this.preSets);
}
/**
* Directive destroyed.
*/
ngOnDestroy(): void {
this.invalidateObserver?.unsubscribe();
}
}

View File

@ -0,0 +1,119 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, ElementRef, Optional } from '@angular/core';
import { CoreSiteWSPreSets } from '@classes/site';
import { CoreNavigator } from '@services/navigator';
import { CoreUtils } from '@services/utils/utils';
import { Md5 } from 'ts-md5';
import { CoreSitePluginsCallWSOnClickBaseDirective } from '../classes/call-ws-click-directive';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';
import { CoreSitePlugins } from '../services/siteplugins';
/**
* Directive to call a WS when the element is clicked and load a new content passing the WS result as args. This new content
* can be displayed in a new page or in the same page (only if current page is already displaying a site plugin content).
*
* If you don't need to load some new content when done, @see CoreSitePluginsCallWSDirective.
*
* @see CoreSitePluginsCallWSOnClickBaseDirective.
*
* Example usages:
*
* A button to get some data from the server without using cache, showing default confirm and displaying a new page:
*
* <ion-button core-site-plugins-call-ws-new-content name="mod_certificate_get_issued_certificates"
* [params]="{certificateid: <% certificate.id %>}" [preSets]="{getFromCache: 0, saveToCache: 0}" confirmMessage
* title="<% certificate.name %>" component="mod_certificate" method="mobile_issues_view"
* [args]="{cmid: <% cmid %>, courseid: <% courseid %>}">
* {{ 'plugin.mod_certificate_coursecertificate.getissued' | translate }}
* </ion-button>
*
* A button to get some data from the server using cache, without confirm, displaying new content in same page and using
* userid from otherdata:
*
* <ion-button core-site-plugins-call-ws-new-content name="mod_certificate_get_issued_certificates"
* [params]="{certificateid: <% certificate.id %>}" component="mod_certificate" method="mobile_issues_view"
* [args]="{cmid: <% cmid %>, courseid: <% courseid %>}" samePage="true" [useOtherData]="['userid']">
* {{ 'plugin.mod_certificate_coursecertificate.getissued' | translate }}
* </ion-button>
*/
@Directive({
selector: '[core-site-plugins-call-ws-new-content]',
})
export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCallWSOnClickBaseDirective {
@Input() component?: string; // The component of the new content. If not provided, use the same component as current page.
@Input() method?: string; // The method to get the new content. If not provided, use the same method as current page.
@Input() args?: Record<string, unknown>; // The params to get the new content.
@Input() title?: string; // The title to display with the new content. Only if samePage=false.
@Input() samePage?: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
@Input() useOtherData?: string[] | unknown; // Whether to include other data in the args.
@Input() form?: string; // ID or name to identify a form. The form data will be retrieved and sent to the WS.
// JS variables to pass to the new page so they can be used in the template or JS.
// If true is supplied instead of an object, all initial variables from current page will be copied.
@Input() jsData?: Record<string, unknown> | boolean;
@Input() newContentPreSets?: CoreSiteWSPreSets; // The preSets for the WS call of the new content.
@Input() ptrEnabled?: boolean | string; // Whether PTR should be enabled in the new page. Defaults to true.
constructor(
element: ElementRef,
@Optional() parentContent: CoreSitePluginsPluginContentComponent,
) {
super(element, parentContent);
}
/**
* Function called when the WS call is successful.
*
* @param result Result of the WS call.
*/
protected wsCallSuccess(result: unknown): void {
let args = this.args || {};
if (this.parentContent) {
args = CoreSitePlugins.loadOtherDataInArgs(this.args, this.parentContent.otherData, this.useOtherData);
}
// Add the properties from the WS call result to the args.
args = Object.assign(args, result);
let jsData = this.jsData || {};
if (jsData === true) {
jsData = this.parentContent?.data || {};
}
if (CoreUtils.isTrueOrOne(this.samePage)) {
// Update the parent content (if it exists).
this.parentContent?.updateContent(args, this.component, this.method, jsData, this.newContentPreSets);
} else {
const component = this.component || this.parentContent?.component;
const method = this.method || this.parentContent?.method;
const hash = <string> Md5.hashAsciiStr(JSON.stringify(args));
CoreNavigator.navigateToSitePath(`siteplugins/${component}/${method}/${hash}`, {
params: {
title: this.title || this.parentContent?.pageTitle,
args,
initResult: this.parentContent?.initResult,
jsData,
preSets: this.newContentPreSets,
ptrEnabled: this.ptrEnabled,
},
});
}
}
}

View File

@ -0,0 +1,57 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, OnInit, ElementRef, Optional } from '@angular/core';
import { CoreSitePluginsCallWSBaseDirective } from '../classes/call-ws-directive';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';
/**
* Directive to call a WS as soon as its loaded.
* This directive is meant for actions to do in the background, like calling logging WebServices.
*
* If you want to call a WS when the user clicks on a certain element, @see CoreSitePluginsCallWSDirective.
*
* @see CoreSitePluginsCallWSBaseDirective.
*
* Example usage:
*
* <span core-site-plugins-call-ws-on-load name="mod_certificate_view_certificate" [params]="{certificateid: <% certificate.id %>}"
* [preSets]="{getFromCache: 0, saveToCache: 0}"></span>
*/
@Directive({
selector: '[core-site-plugins-call-ws-on-load]',
})
export class CoreSitePluginsCallWSOnLoadDirective extends CoreSitePluginsCallWSBaseDirective implements OnInit {
constructor(
element: ElementRef,
@Optional() parentContent: CoreSitePluginsPluginContentComponent,
) {
super(element, parentContent);
}
/**
* @inheritdoc
*/
ngOnInit(): void {
super.ngOnInit();
// Call the WS immediately.
this.callWS().catch(() => {
// Ignore errors.
});
}
}

View File

@ -0,0 +1,81 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, ElementRef, Optional } from '@angular/core';
import { Translate } from '@singletons';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreNavigator } from '@services/navigator';
import { CoreSitePluginsCallWSOnClickBaseDirective } from '../classes/call-ws-click-directive';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';
/**
* Directive to call a WS when the element is clicked. The action to do when the WS call is successful depends on the input data:
* display a message, go back or refresh current view.
*
* If you want to load a new content when the WS call is done, @see CoreSitePluginsCallWSNewContentDirective.
*
* @see CoreSitePluginsCallWSOnClickBaseDirective.
*
* Example usages:
*
* A button to send some data to the server without using cache, displaying default messages and refreshing on success:
*
* <ion-button core-site-plugins-call-ws name="mod_certificate_view_certificate"
* [params]="{certificateid: <% certificate.id %>}" [preSets]="{getFromCache: 0, saveToCache: 0}" confirmMessage
* successMessage refreshOnSuccess="true">
* {{ 'plugin.mod_certificate_coursecertificate.senddata' | translate }}
* </ion-button>
*
* A button to send some data to the server using cache, without confirm, going back on success and using userid from otherdata:
*
* <ion-button core-site-plugins-call-ws name="mod_certificate_view_certificate"
* [params]="{certificateid: <% certificate.id %>}" goBackOnSuccess="true" [useOtherData]="['userid']">
* {{ 'plugin.mod_certificate_coursecertificate.senddata' | translate }}
* </ion-button>
*/
@Directive({
selector: '[core-site-plugins-call-ws]',
})
export class CoreSitePluginsCallWSDirective extends CoreSitePluginsCallWSOnClickBaseDirective {
@Input() successMessage?: string; // Message to show on success. If not supplied, no message. If empty, default message.
@Input() goBackOnSuccess?: boolean | string; // Whether to go back if the WS call is successful.
@Input() refreshOnSuccess?: boolean | string; // Whether to refresh the current view if the WS call is successful.
constructor(
element: ElementRef,
@Optional() parentContent: CoreSitePluginsPluginContentComponent,
) {
super(element, parentContent);
}
/**
* @inheritdoc
*/
protected wsCallSuccess(): void {
if (typeof this.successMessage != 'undefined') {
// Display the success message.
CoreDomUtils.showToast(this.successMessage || Translate.instant('core.success'));
}
if (CoreUtils.isTrueOrOne(this.goBackOnSuccess)) {
CoreNavigator.back();
} else if (CoreUtils.isTrueOrOne(this.refreshOnSuccess) && this.parentContent) {
this.parentContent.refreshContent(true);
}
}
}

View File

@ -0,0 +1,37 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { CoreSitePluginsCallWSDirective } from './call-ws';
import { CoreSitePluginsCallWSNewContentDirective } from './call-ws-new-content';
import { CoreSitePluginsCallWSOnLoadDirective } from './call-ws-on-load';
import { CoreSitePluginsNewContentDirective } from './new-content';
@NgModule({
declarations: [
CoreSitePluginsCallWSDirective,
CoreSitePluginsCallWSNewContentDirective,
CoreSitePluginsCallWSOnLoadDirective,
CoreSitePluginsNewContentDirective,
],
imports: [],
exports: [
CoreSitePluginsCallWSDirective,
CoreSitePluginsCallWSNewContentDirective,
CoreSitePluginsCallWSOnLoadDirective,
CoreSitePluginsNewContentDirective,
],
})
export class CoreSitePluginsDirectivesModule {}

View File

@ -0,0 +1,117 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, Optional } from '@angular/core';
import { Md5 } from 'ts-md5';
import { CoreSiteWSPreSets } from '@classes/site';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';
import { CoreSitePlugins } from '../services/siteplugins';
/**
* Directive to display a new site plugin content when clicked. This new content can be displayed in a new page or in the
* current page (only if the current page is already displaying a site plugin content).
*
* Example usages:
*
* A button to go to a new content page:
*
* <ion-button core-site-plugins-new-content title="<% certificate.name %>" component="mod_certificate"
* method="mobile_issues_view" [args]="{cmid: <% cmid %>, courseid: <% courseid %>}">
* {{ 'plugin.mod_certificate_coursecertificate.viewissued' | translate }}
* </ion-button>
*
* A button to load new content in current page using a param from otherdata:
*
* <ion-button core-site-plugins-new-content component="mod_certificate" method="mobile_issues_view"
* [args]="{cmid: <% cmid %>, courseid: <% courseid %>}" samePage="true" [useOtherData]="['userid']">
* {{ 'plugin.mod_certificate_coursecertificate.viewissued' | translate }}
* </ion-button>
*/
@Directive({
selector: '[core-site-plugins-new-content]',
})
export class CoreSitePluginsNewContentDirective implements OnInit {
@Input() component?: string; // The component of the new content. If not provided, use the same component as current page.
@Input() method?: string; // The method to get the new content. If not provided, use the same method as current page.
@Input() args?: Record<string, unknown>; // The params to get the new content.
@Input() title?: string; // The title to display with the new content. Only if samePage=false.
@Input() samePage?: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
@Input() useOtherData?: string[] | unknown; // Whether to include other data in the args.
@Input() form?: string; // ID or name to identify a form. The form data will be retrieved and sent to the WS.
// JS variables to pass to the new page so they can be used in the template or JS.
// If true is supplied instead of an object, all initial variables from current page will be copied.
@Input() jsData?: Record<string, unknown> | boolean;
@Input() preSets?: CoreSiteWSPreSets; // The preSets for the WS call of the new content.
@Input() ptrEnabled?: boolean | string; // Whether PTR should be enabled in the new page. Defaults to true.
protected element: HTMLElement;
constructor(
element: ElementRef,
@Optional() protected parentContent: CoreSitePluginsPluginContentComponent,
) {
this.element = element.nativeElement || element;
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.element.addEventListener('click', (ev: Event): void => {
ev.preventDefault();
ev.stopPropagation();
let args = this.args || {};
if (this.parentContent) {
args = CoreSitePlugins.loadOtherDataInArgs(this.args, this.parentContent.otherData, this.useOtherData);
}
if (this.form && document.forms[this.form]) {
args = Object.assign(args, CoreDomUtils.getDataFromForm(document.forms[this.form]));
}
let jsData = this.jsData || {};
if (jsData === true) {
jsData = this.parentContent?.data || {};
}
if (CoreUtils.isTrueOrOne(this.samePage)) {
// Update the parent content (if it exists).
this.parentContent?.updateContent(args, this.component, this.method, jsData, this.preSets);
} else {
const component = this.component || this.parentContent?.component;
const method = this.method || this.parentContent?.method;
const hash = <string> Md5.hashAsciiStr(JSON.stringify(args));
CoreNavigator.navigateToSitePath(`siteplugins/${component}/${method}/${hash}`, {
params: {
title: this.title || this.parentContent?.pageTitle,
args,
initResult: this.parentContent?.initResult,
jsData,
preSets: this.preSets,
ptrEnabled: this.ptrEnabled,
},
});
}
});
}
}