diff --git a/src/core/classes/delegate.ts b/src/core/classes/delegate.ts index c9d0183b4..41aac25c5 100644 --- a/src/core/classes/delegate.ts +++ b/src/core/classes/delegate.ts @@ -86,7 +86,7 @@ export class CoreDelegate { * @param delegateName Delegate name used for logging purposes. * @param listenSiteEvents Whether to update the handler when a site event occurs (login, site updated, ...). */ - constructor(delegateName: string, listenSiteEvents?: boolean) { + constructor(delegateName: string, listenSiteEvents: boolean = true) { this.logger = CoreLogger.getInstance(delegateName); this.handlersInitPromise = new Promise((resolve): void => { diff --git a/src/core/features/tag/pages/index-area/index-area.page.ts b/src/core/features/tag/pages/index-area/index-area.page.ts index cdaead47a..46ea0ed39 100644 --- a/src/core/features/tag/pages/index-area/index-area.page.ts +++ b/src/core/features/tag/pages/index-area/index-area.page.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Type } from '@angular/core'; import { IonInfiniteScroll, IonRefresher } from '@ionic/angular'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTag } from '@features/tag/services/tag'; @@ -20,6 +20,7 @@ import { CoreTagFeedElement } from '../../services/tag-helper'; import { ActivatedRoute } from '@angular/router'; import { CoreTagAreaDelegate } from '../../services/tag-area-delegate'; import { Translate } from '@singletons'; +import { CoreUtils } from '@services/utils/utils'; /** * Page that displays the tag index area. @@ -47,7 +48,7 @@ export class CoreTagIndexAreaPage implements OnInit { items: CoreTagFeedElement[] = []; nextPage = 0; canLoadMore = false; - areaComponent: any; // @todo + areaComponent?: Type; loadMoreError = false; constructor( @@ -59,7 +60,7 @@ export class CoreTagIndexAreaPage implements OnInit { */ async ngOnInit(): Promise { - const navParams = this.route.snapshot.queryParamMap; + const navParams = this.route.snapshot.queryParams; this.tagId = navParams['tagId'] ? parseInt(navParams['tagId'], 10) : this.tagId; this.tagName = navParams['tagName'] || this.tagName; @@ -74,8 +75,8 @@ export class CoreTagIndexAreaPage implements OnInit { this.componentName = navParams['componentName']; this.itemType = navParams['itemType']; this.items = []; // @todo navParams['items'] || []; - this.nextPage = navParams.has('nextPage') ? parseInt(navParams['nextPage']!, 10) : 0; - this.canLoadMore = !!navParams['canLoadMore']; + this.nextPage = typeof navParams['nextPage'] != 'undefined' ? parseInt(navParams['nextPage'], 10) : 0; + this.canLoadMore = CoreUtils.instance.isTrueOrOne(navParams['canLoadMore']); try { if (!this.componentName || !this.itemType || !this.items.length || this.nextPage == 0) { diff --git a/src/core/features/tag/pages/index/index.page.ts b/src/core/features/tag/pages/index/index.page.ts index 394d1c416..9366303b1 100644 --- a/src/core/features/tag/pages/index/index.page.ts +++ b/src/core/features/tag/pages/index/index.page.ts @@ -168,8 +168,11 @@ export class CoreTagIndexPage implements OnInit { canLoadMore: area.canLoadMore, nextPage: 1, }; - // this.splitviewCtrl.push('core-tag-index-area', params); - this.router.navigate(['core-tag-index-area'], { queryParams: params }); + // this.splitviewCtrl.push('index-area', params); + this.router.navigate(['../index-area'], { + queryParams: params, + relativeTo: this.route, + }); } diff --git a/src/core/features/tag/services/tag-area-delegate.ts b/src/core/features/tag/services/tag-area-delegate.ts index 8ef4cca71..a0daaf087 100644 --- a/src/core/features/tag/services/tag-area-delegate.ts +++ b/src/core/features/tag/services/tag-area-delegate.ts @@ -52,7 +52,7 @@ export class CoreTagAreaDelegateService extends CoreDelegate protected handlerNameProperty = 'type'; constructor() { - super('CoreTagAreaDelegate'); + super('CoreTagAreaDelegate', true); } /** diff --git a/src/core/features/user/classes/base-profilefield-component.ts b/src/core/features/user/classes/base-profilefield-component.ts index 4d3a6d830..88f390862 100644 --- a/src/core/features/user/classes/base-profilefield-component.ts +++ b/src/core/features/user/classes/base-profilefield-component.ts @@ -24,7 +24,7 @@ import { CoreUserProfileField } from '@features/user/services/user'; @Component({ template: '', }) -export class CoreUserProfileFieldBaseComponent implements OnInit { +export abstract class CoreUserProfileFieldBaseComponent implements OnInit { @Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered. @Input() edit = false; // True if editing the field. Defaults to false. diff --git a/src/core/features/user/components/components.module.ts b/src/core/features/user/components/components.module.ts index cd7b1d33f..00837117a 100644 --- a/src/core/features/user/components/components.module.ts +++ b/src/core/features/user/components/components.module.ts @@ -21,10 +21,12 @@ import { CoreComponentsModule } from '@components/components.module'; import { CoreDirectivesModule } from '@directives/directives.module'; import { CorePipesModule } from '@pipes/pipes.module'; import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile-field'; +import { CoreUserTagAreaComponent } from './tag-area/tag-area'; @NgModule({ declarations: [ CoreUserProfileFieldComponent, + CoreUserTagAreaComponent, ], imports: [ CommonModule, @@ -38,6 +40,7 @@ import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile ], exports: [ CoreUserProfileFieldComponent, + CoreUserTagAreaComponent, ], }) export class CoreUserComponentsModule {} diff --git a/src/core/features/user/components/tag-area/core-user-tag-area.html b/src/core/features/user/components/tag-area/core-user-tag-area.html new file mode 100644 index 000000000..e2bd39803 --- /dev/null +++ b/src/core/features/user/components/tag-area/core-user-tag-area.html @@ -0,0 +1,6 @@ + + + +

{{ item.heading }}

+
+
\ No newline at end of file diff --git a/src/core/features/user/components/tag-area/tag-area.ts b/src/core/features/user/components/tag-area/tag-area.ts new file mode 100644 index 000000000..116ecb0dc --- /dev/null +++ b/src/core/features/user/components/tag-area/tag-area.ts @@ -0,0 +1,30 @@ +// (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 { Component, Input } from '@angular/core'; + +import { CoreUserTagFeedElement } from '@features/user/services/handlers/tag-area-handler'; + +/** + * Component to render the user tag area. + */ +@Component({ + selector: 'core-user-tag-area', + templateUrl: 'core-user-tag-area.html', +}) +export class CoreUserTagAreaComponent { + + @Input() items?: CoreUserTagFeedElement[]; // Area items to render. + +} diff --git a/src/core/features/user/services/handlers/tag-area-handler.ts b/src/core/features/user/services/handlers/tag-area-handler.ts new file mode 100644 index 000000000..384466574 --- /dev/null +++ b/src/core/features/user/services/handlers/tag-area-handler.ts @@ -0,0 +1,98 @@ +// (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 { Injectable, Type } from '@angular/core'; + +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate'; +import { CoreUserTagAreaComponent } from '@features/user/components/tag-area/tag-area'; +import { CoreTagFeedElement } from '@features/tag/services/tag-helper'; +import { CoreUserBasicData } from '../user'; +import { makeSingleton } from '@singletons'; + +/** + * Handler to support tags. + */ +@Injectable({ providedIn: 'root' }) +export class CoreUserTagAreaHandlerService implements CoreTagAreaHandler { + + name = 'CoreUserTagAreaHandler'; + type = 'core/user'; + + /** + * Whether or not the handler is enabled on a site level. + * + * @return Whether or not the handler is enabled on a site level. + */ + async isEnabled(): Promise { + return true; + } + + /** + * Parses the rendered content of a tag index and returns the items. + * + * @param content Rendered content. + * @return Area items (or promise resolved with the items). + */ + parseContent(content: string): CoreUserTagFeedElement[] { + const items: CoreUserTagFeedElement[] = []; + const element = CoreDomUtils.instance.convertToElement(content); + + Array.from(element.querySelectorAll('div.user-box')).forEach((userbox: HTMLElement) => { + const avatarLink = userbox.querySelector('a:first-child'); + if (!avatarLink) { + return; + } + + const profileUrl = avatarLink.getAttribute('href') || ''; + const match = profileUrl.match(/.*\/user\/(?:profile|view)\.php\?id=(\d+)/); + if (!match) { + return; + } + + const avatarImg = avatarLink.querySelector('img.userpicture'); + const avatarUrl = avatarImg ? avatarImg.getAttribute('src') : ''; + + items.push({ + avatarUrl, + heading: userbox.innerText, + details: [], + user: { + id: Number(match[1]), + profileimageurl: avatarUrl || '', + fullname: userbox.innerText, + }, + }); + }); + + return items; + } + + /** + * Get the component to use to display items. + * + * @param injector Injector. + * @return The component (or promise resolved with component) to use, undefined if not found. + */ + getComponent(): Type | Promise> { + return CoreUserTagAreaComponent; + } + +} + +export class CoreUserTagAreaHandler extends makeSingleton(CoreUserTagAreaHandlerService) {} + +export type CoreUserTagFeedElement = CoreTagFeedElement & { + user: CoreUserBasicData; +}; diff --git a/src/core/features/user/user.module.ts b/src/core/features/user/user.module.ts index 572a89da7..8ffbebe6c 100644 --- a/src/core/features/user/user.module.ts +++ b/src/core/features/user/user.module.ts @@ -25,6 +25,8 @@ import { CoreContentLinksDelegate } from '@features/contentlinks/services/conten import { CoreUserProfileLinkHandler } from './services/handlers/profile-link'; import { CoreCronDelegate } from '@services/cron'; import { CoreUserSyncCronHandler } from './services/handlers/sync-cron'; +import { CoreUserTagAreaHandler } from './services/handlers/tag-area-handler'; +import { CoreTagAreaDelegate } from '@features/tag/services/tag-area-delegate'; const routes: Routes = [ { @@ -55,6 +57,7 @@ const routes: Routes = [ CoreUserDelegate.instance.registerHandler(CoreUserProfileMailHandler.instance); CoreContentLinksDelegate.instance.registerHandler(CoreUserProfileLinkHandler.instance); CoreCronDelegate.instance.register(CoreUserSyncCronHandler.instance); + CoreTagAreaDelegate.instance.registerHandler(CoreUserTagAreaHandler.instance); }, }, ],