Merge pull request #1909 from sammarshallou/MOBILE-2935
MOBILE-2935 Support site plugins for blocks on dashboard pagemain
commit
94c8d251a9
|
@ -12,9 +12,11 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input, OnInit, Injector, ViewChild } from '@angular/core';
|
||||
import { Component, Input, OnInit, Injector, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { CoreBlockDelegate } from '../../providers/delegate';
|
||||
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
|
||||
/**
|
||||
* Component to render a block.
|
||||
|
@ -23,7 +25,7 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
|
|||
selector: 'core-block',
|
||||
templateUrl: 'core-block.html'
|
||||
})
|
||||
export class CoreBlockComponent implements OnInit {
|
||||
export class CoreBlockComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent;
|
||||
|
||||
@Input() block: any; // The block to render.
|
||||
|
@ -37,7 +39,10 @@ export class CoreBlockComponent implements OnInit {
|
|||
class: string; // CSS class to apply to the block.
|
||||
loaded = false;
|
||||
|
||||
constructor(protected injector: Injector, protected blockDelegate: CoreBlockDelegate) { }
|
||||
blockSubscription: Subscription;
|
||||
|
||||
constructor(protected injector: Injector, protected blockDelegate: CoreBlockDelegate,
|
||||
protected eventsProvider: CoreEventsProvider) { }
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
|
@ -50,9 +55,28 @@ export class CoreBlockComponent implements OnInit {
|
|||
}
|
||||
|
||||
// Get the data to render the block.
|
||||
this.initBlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block display data and initialises the block once this is available. If the block is not
|
||||
* supported at the moment, try again if the available blocks are updated (because it comes
|
||||
* from a site plugin).
|
||||
*/
|
||||
initBlock(): void {
|
||||
this.blockDelegate.getBlockDisplayData(this.injector, this.block, this.contextLevel, this.instanceId).then((data) => {
|
||||
if (!data) {
|
||||
// Block not supported, don't render it.
|
||||
// Block not supported, don't render it. But, site plugins might not have finished loading.
|
||||
// Subscribe to the observable in block delegate that will tell us if blocks are updated.
|
||||
// We can retry init later if that happens.
|
||||
this.blockSubscription = this.blockDelegate.blocksUpdateObservable.subscribe({
|
||||
next: (): void => {
|
||||
this.blockSubscription.unsubscribe();
|
||||
delete this.blockSubscription;
|
||||
this.initBlock();
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -73,6 +97,16 @@ export class CoreBlockComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* On destroy of the component, clear up any subscriptions.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
if (this.blockSubscription) {
|
||||
this.blockSubscription.unsubscribe();
|
||||
delete this.blockSubscription;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,8 @@ import { CoreSitesProvider } from '@providers/sites';
|
|||
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
|
||||
import { CoreBlockDefaultHandler } from './default-block-handler';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreSitePluginsProvider } from '@core/siteplugins/providers/siteplugins';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Interface that all blocks must implement.
|
||||
|
@ -83,9 +85,12 @@ export class CoreBlockDelegate extends CoreDelegate {
|
|||
|
||||
protected featurePrefix = 'CoreBlockDelegate_';
|
||||
|
||||
blocksUpdateObservable: Subject<void>;
|
||||
|
||||
constructor(logger: CoreLoggerProvider, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
|
||||
protected defaultHandler: CoreBlockDefaultHandler) {
|
||||
protected defaultHandler: CoreBlockDefaultHandler, protected sitePluginsProvider: CoreSitePluginsProvider) {
|
||||
super('CoreBlockDelegate', logger, sitesProvider, eventsProvider);
|
||||
this.blocksUpdateObservable = new Subject<void>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,4 +162,26 @@ export class CoreBlockDelegate extends CoreDelegate {
|
|||
protected isFeatureDisabled(handler: CoreDelegateHandler, site: CoreSite): boolean {
|
||||
return this.areBlocksDisabledInSite(site) || super.isFeatureDisabled(handler, site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the handler name for a given block name.
|
||||
*
|
||||
* @param {string} name Block name e.g. 'activity_modules'
|
||||
* @return {string} Full name of corresponding handler
|
||||
*/
|
||||
getHandlerName(name: string): string {
|
||||
if (!this.isBlockSupported(name)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return this.getHandler(name, true).name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there are new block handlers available. Informs anyone who subscribed to the
|
||||
* observable.
|
||||
*/
|
||||
updateData(): void {
|
||||
this.blocksUpdateObservable.next();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ import { CoreBlockComponentsModule } from '@core/block/components/components.mod
|
|||
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 { CoreSitePluginsBlockComponent } from '@core/siteplugins/components/block/block';
|
||||
import { CoreSitePluginsCourseOptionComponent } from '@core/siteplugins/components/course-option/course-option';
|
||||
import { CoreSitePluginsCourseFormatComponent } from '@core/siteplugins/components/course-format/course-format';
|
||||
import { CoreSitePluginsQuestionComponent } from '@core/siteplugins/components/question/question';
|
||||
|
@ -269,6 +270,7 @@ export class CoreCompileProvider {
|
|||
instance['CoreCourseUnsupportedModuleComponent'] = CoreCourseUnsupportedModuleComponent;
|
||||
instance['CoreCourseFormatSingleActivityComponent'] = CoreCourseFormatSingleActivityComponent;
|
||||
instance['CoreSitePluginsModuleIndexComponent'] = CoreSitePluginsModuleIndexComponent;
|
||||
instance['CoreSitePluginsBlockComponent'] = CoreSitePluginsBlockComponent;
|
||||
instance['CoreSitePluginsCourseOptionComponent'] = CoreSitePluginsCourseOptionComponent;
|
||||
instance['CoreSitePluginsCourseFormatComponent'] = CoreSitePluginsCourseFormatComponent;
|
||||
instance['CoreSitePluginsQuestionComponent'] = CoreSitePluginsQuestionComponent;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// (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 { Injector } from '@angular/core';
|
||||
import { CoreSitePluginsBaseHandler } from './base-handler';
|
||||
import { CoreBlockHandler, CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||
import { CoreSitePluginsBlockComponent } from '@core/siteplugins/components/block/block';
|
||||
|
||||
/**
|
||||
* Handler to support a block using a site plugin.
|
||||
*/
|
||||
export class CoreSitePluginsBlockHandler extends CoreSitePluginsBaseHandler implements CoreBlockHandler {
|
||||
|
||||
constructor(name: string, public blockName: string, protected handlerSchema: any, protected initResult: any) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets display data for this block. The class and title can be provided either by data from
|
||||
* the handler schema (mobile.php) or using default values.
|
||||
*
|
||||
* @param {Injector} injector Injector
|
||||
* @param {any} block Block data
|
||||
* @param {string} contextLevel Context level (not used)
|
||||
* @param {number} instanceId Instance if (not used)
|
||||
* @return {CoreBlockHandlerData|Promise<CoreBlockHandlerData>} Data or promise resolved with the data
|
||||
*/
|
||||
getDisplayData(injector: Injector, block: any, contextLevel: string, instanceId: number):
|
||||
CoreBlockHandlerData | Promise<CoreBlockHandlerData> {
|
||||
let title,
|
||||
className;
|
||||
if (this.handlerSchema.displaydata && this.handlerSchema.displaydata.title) {
|
||||
title = this.handlerSchema.displaydata.title;
|
||||
} else {
|
||||
title = 'plugins.block_' + block.name + '.pluginname';
|
||||
}
|
||||
if (this.handlerSchema.displaydata && this.handlerSchema.displaydata.class) {
|
||||
className = this.handlerSchema.displaydata.class;
|
||||
} else {
|
||||
className = 'block_' + block.name;
|
||||
}
|
||||
|
||||
return {
|
||||
title: title,
|
||||
class: className,
|
||||
component: CoreSitePluginsBlockComponent
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// (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, OnChanges, Input, ViewChild, Injector } from '@angular/core';
|
||||
import { CoreSitePluginsProvider } from '../../providers/siteplugins';
|
||||
import { CoreSitePluginsPluginContentComponent } from '../plugin-content/plugin-content';
|
||||
import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component';
|
||||
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||
|
||||
/**
|
||||
* Component that displays the index of a course format site plugin.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-site-plugins-block',
|
||||
templateUrl: 'core-siteplugins-block.html',
|
||||
})
|
||||
export class CoreSitePluginsBlockComponent extends CoreBlockBaseComponent implements OnChanges {
|
||||
@Input() block: any;
|
||||
@Input() contextLevel: number;
|
||||
@Input() instanceId: number;
|
||||
|
||||
@ViewChild(CoreSitePluginsPluginContentComponent) content: CoreSitePluginsPluginContentComponent;
|
||||
|
||||
component: string;
|
||||
method: string;
|
||||
args: any;
|
||||
initResult: any;
|
||||
|
||||
constructor(protected injector: Injector, protected sitePluginsProvider: CoreSitePluginsProvider,
|
||||
protected blockDelegate: CoreBlockDelegate) {
|
||||
super(injector, 'CoreSitePluginsBlockComponent');
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect changes on input properties.
|
||||
*/
|
||||
ngOnChanges(): void {
|
||||
if (!this.component) {
|
||||
// Initialize the data.
|
||||
const handlerName = this.blockDelegate.getHandlerName(this.block.name);
|
||||
const handler = this.sitePluginsProvider.getSitePluginHandler(handlerName);
|
||||
if (handler) {
|
||||
this.component = handler.plugin.component;
|
||||
this.method = handler.handlerSchema.method;
|
||||
this.args = { };
|
||||
this.initResult = handler.initResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass on content invalidation by refreshing content in the plugin content component.
|
||||
*/
|
||||
protected invalidateContent(): Promise<any> {
|
||||
return Promise.resolve(this.content.refreshContent());
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [initResult]="initResult" [data]="data"></core-site-plugins-plugin-content>
|
|
@ -29,11 +29,13 @@ import { CoreSitePluginsQuizAccessRuleComponent } from './quiz-access-rule/quiz-
|
|||
import { CoreSitePluginsAssignFeedbackComponent } from './assign-feedback/assign-feedback';
|
||||
import { CoreSitePluginsAssignSubmissionComponent } from './assign-submission/assign-submission';
|
||||
import { CoreSitePluginsWorkshopAssessmentStrategyComponent } from './workshop-assessment-strategy/workshop-assessment-strategy';
|
||||
import { CoreSitePluginsBlockComponent } from '@core/siteplugins/components/block/block';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSitePluginsPluginContentComponent,
|
||||
CoreSitePluginsModuleIndexComponent,
|
||||
CoreSitePluginsBlockComponent,
|
||||
CoreSitePluginsCourseOptionComponent,
|
||||
CoreSitePluginsCourseFormatComponent,
|
||||
CoreSitePluginsUserProfileFieldComponent,
|
||||
|
@ -56,6 +58,7 @@ import { CoreSitePluginsWorkshopAssessmentStrategyComponent } from './workshop-a
|
|||
exports: [
|
||||
CoreSitePluginsPluginContentComponent,
|
||||
CoreSitePluginsModuleIndexComponent,
|
||||
CoreSitePluginsBlockComponent,
|
||||
CoreSitePluginsCourseOptionComponent,
|
||||
CoreSitePluginsCourseFormatComponent,
|
||||
CoreSitePluginsUserProfileFieldComponent,
|
||||
|
@ -68,6 +71,7 @@ import { CoreSitePluginsWorkshopAssessmentStrategyComponent } from './workshop-a
|
|||
],
|
||||
entryComponents: [
|
||||
CoreSitePluginsModuleIndexComponent,
|
||||
CoreSitePluginsBlockComponent,
|
||||
CoreSitePluginsCourseOptionComponent,
|
||||
CoreSitePluginsCourseFormatComponent,
|
||||
CoreSitePluginsUserProfileFieldComponent,
|
||||
|
|
|
@ -64,6 +64,8 @@ import { CoreSitePluginsQuizAccessRuleHandler } from '../classes/handlers/quiz-a
|
|||
import { CoreSitePluginsAssignFeedbackHandler } from '../classes/handlers/assign-feedback-handler';
|
||||
import { CoreSitePluginsAssignSubmissionHandler } from '../classes/handlers/assign-submission-handler';
|
||||
import { CoreSitePluginsWorkshopAssessmentStrategyHandler } from '../classes/handlers/workshop-assessment-strategy-handler';
|
||||
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||
import { CoreSitePluginsBlockHandler } from '@core/siteplugins/classes/handlers/block-handler';
|
||||
|
||||
/**
|
||||
* Helper service to provide functionalities regarding site plugins. It basically has the features to load and register site
|
||||
|
@ -92,7 +94,7 @@ export class CoreSitePluginsHelperProvider {
|
|||
private assignSubmissionDelegate: AddonModAssignSubmissionDelegate, private translate: TranslateService,
|
||||
private assignFeedbackDelegate: AddonModAssignFeedbackDelegate, private appProvider: CoreAppProvider,
|
||||
private workshopAssessmentStrategyDelegate: AddonWorkshopAssessmentStrategyDelegate,
|
||||
private courseProvider: CoreCourseProvider) {
|
||||
private courseProvider: CoreCourseProvider, private blockDelegate: CoreBlockDelegate) {
|
||||
|
||||
this.logger = logger.getInstance('CoreSitePluginsHelperProvider');
|
||||
|
||||
|
@ -478,6 +480,10 @@ export class CoreSitePluginsHelperProvider {
|
|||
promise = Promise.resolve(this.registerQuestionBehaviourHandler(plugin, handlerName, handlerSchema));
|
||||
break;
|
||||
|
||||
case 'CoreBlockDelegate':
|
||||
promise = Promise.resolve(this.registerBlockHandler(plugin, handlerName, handlerSchema, result));
|
||||
break;
|
||||
|
||||
case 'AddonMessageOutputDelegate':
|
||||
promise = Promise.resolve(this.registerMessageOutputHandler(plugin, handlerName, handlerSchema, result));
|
||||
break;
|
||||
|
@ -611,6 +617,27 @@ export class CoreSitePluginsHelperProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a handler in a plugin, register it in the block delegate.
|
||||
*
|
||||
* @param {any} plugin Data of the plugin.
|
||||
* @param {string} handlerName Name of the handler in the plugin.
|
||||
* @param {any} handlerSchema Data about the handler.
|
||||
* @param {any} initResult Result of init function.
|
||||
* @return {string|Promise<string>} A string (or a promise resolved with a string) to identify the handler.
|
||||
*/
|
||||
protected registerBlockHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any):
|
||||
string | Promise<string> {
|
||||
|
||||
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||
blockName = (handlerSchema.moodlecomponent || plugin.component).replace('block_', '');
|
||||
|
||||
this.blockDelegate.registerHandler(
|
||||
new CoreSitePluginsBlockHandler(uniqueName, blockName, handlerSchema, initResult));
|
||||
|
||||
return uniqueName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a handler in a plugin, register it in the course format delegate.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue