commit
						aa3e894248
					
				@ -420,6 +420,7 @@
 | 
			
		||||
  "addon.mod_assign_submission_onlinetext.wordlimitexceeded": "assignsubmission_onlinetext",
 | 
			
		||||
  "addon.mod_book.errorchapter": "book",
 | 
			
		||||
  "addon.mod_book.modulenameplural": "book",
 | 
			
		||||
  "addon.mod_book.tagarea_book_chapters": "book",
 | 
			
		||||
  "addon.mod_book.toc": "book",
 | 
			
		||||
  "addon.mod_chat.beep": "chat",
 | 
			
		||||
  "addon.mod_chat.chatreport": "chat",
 | 
			
		||||
@ -479,6 +480,7 @@
 | 
			
		||||
  "addon.mod_data.confirmdeleterecord": "data",
 | 
			
		||||
  "addon.mod_data.descending": "data",
 | 
			
		||||
  "addon.mod_data.disapprove": "data",
 | 
			
		||||
  "addon.mod_data.edittagsnotsupported": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_data.emptyaddform": "data",
 | 
			
		||||
  "addon.mod_data.entrieslefttoadd": "data",
 | 
			
		||||
  "addon.mod_data.entrieslefttoaddtoview": "data",
 | 
			
		||||
@ -503,8 +505,10 @@
 | 
			
		||||
  "addon.mod_data.recorddisapproved": "data",
 | 
			
		||||
  "addon.mod_data.resetsettings": "data",
 | 
			
		||||
  "addon.mod_data.search": "data",
 | 
			
		||||
  "addon.mod_data.searchbytagsnotsupported": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_data.selectedrequired": "data",
 | 
			
		||||
  "addon.mod_data.single": "data",
 | 
			
		||||
  "addon.mod_data.tagarea_data_records": "data",
 | 
			
		||||
  "addon.mod_data.timeadded": "data",
 | 
			
		||||
  "addon.mod_data.timemodified": "data",
 | 
			
		||||
  "addon.mod_data.usedate": "data",
 | 
			
		||||
@ -597,6 +601,7 @@
 | 
			
		||||
  "addon.mod_forum.reply": "forum",
 | 
			
		||||
  "addon.mod_forum.replyplaceholder": "forum",
 | 
			
		||||
  "addon.mod_forum.subject": "forum",
 | 
			
		||||
  "addon.mod_forum.tagarea_forum_posts": "forum",
 | 
			
		||||
  "addon.mod_forum.thisforumhasduedate": "forum",
 | 
			
		||||
  "addon.mod_forum.thisforumisdue": "forum",
 | 
			
		||||
  "addon.mod_forum.unlockdiscussion": "forum",
 | 
			
		||||
@ -631,6 +636,7 @@
 | 
			
		||||
  "addon.mod_glossary.modulenameplural": "glossary",
 | 
			
		||||
  "addon.mod_glossary.noentriesfound": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_glossary.searchquery": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_glossary.tagarea_glossary_entries": "glossary",
 | 
			
		||||
  "addon.mod_imscp.deploymenterror": "imscp",
 | 
			
		||||
  "addon.mod_imscp.modulenameplural": "imscp",
 | 
			
		||||
  "addon.mod_imscp.showmoduledescription": "local_moodlemobileapp",
 | 
			
		||||
@ -887,6 +893,7 @@
 | 
			
		||||
  "addon.mod_wiki.pageexists": "wiki",
 | 
			
		||||
  "addon.mod_wiki.pagename": "wiki",
 | 
			
		||||
  "addon.mod_wiki.subwiki": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_wiki.tagarea_wiki_pages": "wiki",
 | 
			
		||||
  "addon.mod_wiki.titleshouldnotbeempty": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_wiki.viewpage": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_wiki.wikipage": "local_moodlemobileapp",
 | 
			
		||||
@ -1868,6 +1875,20 @@
 | 
			
		||||
  "core.submit": "moodle",
 | 
			
		||||
  "core.success": "moodle",
 | 
			
		||||
  "core.tablet": "local_moodlemobileapp",
 | 
			
		||||
  "core.tag.defautltagcoll": "moodle",
 | 
			
		||||
  "core.tag.errorareanotsupported": "local_moodlemobileapp",
 | 
			
		||||
  "core.tag.inalltagcoll": "moodle",
 | 
			
		||||
  "core.tag.itemstaggedwith": "moodle",
 | 
			
		||||
  "core.tag.notagsfound": "moodle",
 | 
			
		||||
  "core.tag.searchtags": "moodle",
 | 
			
		||||
  "core.tag.showingfirsttags": "moodle",
 | 
			
		||||
  "core.tag.tag": "moodle",
 | 
			
		||||
  "core.tag.tagarea_course": "moodle",
 | 
			
		||||
  "core.tag.tagarea_course_modules": "moodle",
 | 
			
		||||
  "core.tag.tagarea_post": "moodle",
 | 
			
		||||
  "core.tag.tagarea_user": "moodle",
 | 
			
		||||
  "core.tag.tags": "moodle",
 | 
			
		||||
  "core.tag.warningareasnotsupported": "local_moodlemobileapp",
 | 
			
		||||
  "core.teachers": "moodle",
 | 
			
		||||
  "core.thereisdatatosync": "local_moodlemobileapp",
 | 
			
		||||
  "core.thisdirection": "langconfig",
 | 
			
		||||
 | 
			
		||||
@ -17,12 +17,14 @@ import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
 | 
			
		||||
import { CoreUserDelegate } from '@core/user/providers/user-delegate';
 | 
			
		||||
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { AddonBlogProvider } from './providers/blog';
 | 
			
		||||
import { AddonBlogMainMenuHandler } from './providers/mainmenu-handler';
 | 
			
		||||
import { AddonBlogUserHandler } from './providers/user-handler';
 | 
			
		||||
import { AddonBlogCourseOptionHandler } from './providers/course-option-handler';
 | 
			
		||||
import { AddonBlogComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonBlogIndexLinkHandler } from './providers/index-link-handler';
 | 
			
		||||
import { AddonBlogTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
@ -35,17 +37,20 @@ import { AddonBlogIndexLinkHandler } from './providers/index-link-handler';
 | 
			
		||||
        AddonBlogMainMenuHandler,
 | 
			
		||||
        AddonBlogUserHandler,
 | 
			
		||||
        AddonBlogCourseOptionHandler,
 | 
			
		||||
        AddonBlogIndexLinkHandler
 | 
			
		||||
        AddonBlogIndexLinkHandler,
 | 
			
		||||
        AddonBlogTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlogModule {
 | 
			
		||||
    constructor(mainMenuDelegate: CoreMainMenuDelegate, menuHandler: AddonBlogMainMenuHandler,
 | 
			
		||||
            userHandler: AddonBlogUserHandler, userDelegate: CoreUserDelegate,
 | 
			
		||||
            courseOptionHandler: AddonBlogCourseOptionHandler, courseOptionsDelegate: CoreCourseOptionsDelegate,
 | 
			
		||||
            linkHandler: AddonBlogIndexLinkHandler, contentLinksDelegate: CoreContentLinksDelegate) {
 | 
			
		||||
            linkHandler: AddonBlogIndexLinkHandler, contentLinksDelegate: CoreContentLinksDelegate,
 | 
			
		||||
            tagAreaDelegate: CoreTagAreaDelegate, tagAreaHandler: AddonBlogTagAreaHandler) {
 | 
			
		||||
        mainMenuDelegate.registerHandler(menuHandler);
 | 
			
		||||
        userDelegate.registerHandler(userHandler);
 | 
			
		||||
        courseOptionsDelegate.registerHandler(courseOptionHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(linkHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CorePipesModule } from '@pipes/pipes.module';
 | 
			
		||||
import { CoreCommentsComponentsModule } from '@core/comments/components/components.module';
 | 
			
		||||
import { CoreTagComponentsModule } from '@core/tag/components/components.module';
 | 
			
		||||
import { AddonBlogEntriesComponent } from './entries/entries';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
@ -33,7 +34,8 @@ import { AddonBlogEntriesComponent } from './entries/entries';
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CorePipesModule,
 | 
			
		||||
        CoreCommentsComponentsModule
 | 
			
		||||
        CoreCommentsComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,10 @@
 | 
			
		||||
                </ion-item>
 | 
			
		||||
                <ion-card-content>
 | 
			
		||||
                    <core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id"></core-format-text>
 | 
			
		||||
                    <ion-item text-wrap *ngIf="tagsEnabled && entry.tags && entry.tags.length > 0">
 | 
			
		||||
                        <div item-start>{{ 'core.tag.tags' | translate }}:</div>
 | 
			
		||||
                        <core-tag-list [tags]="entry.tags"></core-tag-list>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
                    <ion-item *ngIf="commentsEnabled">
 | 
			
		||||
                        <core-comments [component]="this.component" [itemId]="entry.id" area="format_blog" [instanceId]="entry.userid" contextLevel="user"></core-comments>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreUserProvider } from '@core/user/providers/user';
 | 
			
		||||
import { AddonBlogProvider } from '../../providers/blog';
 | 
			
		||||
import { CoreCommentsProvider } from '@core/comments/providers/comments';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays the blog entries.
 | 
			
		||||
@ -49,10 +50,11 @@ export class AddonBlogEntriesComponent implements OnInit {
 | 
			
		||||
    onlyMyEntries = false;
 | 
			
		||||
    component = AddonBlogProvider.COMPONENT;
 | 
			
		||||
    commentsEnabled: boolean;
 | 
			
		||||
    tagsEnabled: boolean;
 | 
			
		||||
 | 
			
		||||
    constructor(protected blogProvider: AddonBlogProvider, protected domUtils: CoreDomUtilsProvider,
 | 
			
		||||
            protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider,
 | 
			
		||||
            protected commentsProvider: CoreCommentsProvider) {
 | 
			
		||||
            protected commentsProvider: CoreCommentsProvider, private tagProvider: CoreTagProvider) {
 | 
			
		||||
        this.currentUserId = sitesProvider.getCurrentSiteUserId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -85,6 +87,7 @@ export class AddonBlogEntriesComponent implements OnInit {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.commentsEnabled = !this.commentsProvider.areCommentsDisabledInSite();
 | 
			
		||||
        this.tagsEnabled = this.tagProvider.areTagsAvailableInSite();
 | 
			
		||||
 | 
			
		||||
        this.fetchEntries().then(() => {
 | 
			
		||||
            this.blogProvider.logView(this.filter).catch(() => {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								src/addon/blog/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/addon/blog/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
import { AddonBlogProvider } from './blog';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonBlogTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'AddonBlogTagAreaHandler';
 | 
			
		||||
    type = 'core/post';
 | 
			
		||||
 | 
			
		||||
    constructor(private tagHelper: CoreTagHelperProvider, private blogProvider: AddonBlogProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return this.blogProvider.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        return this.tagHelper.parseFeedContent(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -22,6 +22,8 @@ import { AddonModBookPrefetchHandler } from './providers/prefetch-handler';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { AddonModBookTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
 | 
			
		||||
// List of providers (without handlers).
 | 
			
		||||
export const ADDON_MOD_BOOK_PROVIDERS: any[] = [
 | 
			
		||||
@ -39,18 +41,21 @@ export const ADDON_MOD_BOOK_PROVIDERS: any[] = [
 | 
			
		||||
        AddonModBookModuleHandler,
 | 
			
		||||
        AddonModBookLinkHandler,
 | 
			
		||||
        AddonModBookListLinkHandler,
 | 
			
		||||
        AddonModBookPrefetchHandler
 | 
			
		||||
        AddonModBookPrefetchHandler,
 | 
			
		||||
        AddonModBookTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookModule {
 | 
			
		||||
    constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModBookModuleHandler,
 | 
			
		||||
            contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModBookLinkHandler,
 | 
			
		||||
            prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModBookPrefetchHandler,
 | 
			
		||||
            listLinkHandler: AddonModBookListLinkHandler) {
 | 
			
		||||
            listLinkHandler: AddonModBookListLinkHandler, tagAreaDelegate: CoreTagAreaDelegate,
 | 
			
		||||
            tagAreaHandler: AddonModBookTagAreaHandler) {
 | 
			
		||||
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(linkHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(listLinkHandler);
 | 
			
		||||
        prefetchDelegate.registerHandler(prefetchHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
 | 
			
		||||
import { AddonModBookIndexComponent } from './index/index';
 | 
			
		||||
import { CoreTagComponentsModule } from '@core/tag/components/components.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
@ -31,7 +32,8 @@ import { AddonModBookIndexComponent } from './index/index';
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CoreCourseComponentsModule
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,10 @@
 | 
			
		||||
    <div padding>
 | 
			
		||||
        <core-navigation-bar [previous]="previousChapter > 0 && previousChapter" [next]="nextChapter > 0 && nextChapter" (action)="changeChapter($event)"></core-navigation-bar>
 | 
			
		||||
        <core-format-text [component]="component" [componentId]="componentId" [text]="chapterContent"></core-format-text>
 | 
			
		||||
        <div margin-top *ngIf="tagsEnabled && contentsMap && contentsMap[currentChapter] && contentsMap[currentChapter].tags && contentsMap[currentChapter].tags.length > 0">
 | 
			
		||||
            <b>{{ 'core.tag.tags' | translate }}:</b>
 | 
			
		||||
            <core-tag-list [tags]="contentsMap[currentChapter].tags"></core-tag-list>
 | 
			
		||||
        </div>
 | 
			
		||||
        <core-navigation-bar [previous]="previousChapter > 0 && previousChapter" [next]="nextChapter > 0 && nextChapter" (action)="changeChapter($event)"></core-navigation-bar>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
 | 
			
		||||
import { CoreCourseModuleMainResourceComponent } from '@core/course/classes/main-resource-component';
 | 
			
		||||
import { AddonModBookProvider, AddonModBookContentsMap, AddonModBookTocChapter } from '../../providers/book';
 | 
			
		||||
import { AddonModBookPrefetchHandler } from '../../providers/prefetch-handler';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays a book.
 | 
			
		||||
@ -34,6 +35,7 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp
 | 
			
		||||
    chapterContent: string;
 | 
			
		||||
    previousChapter: string;
 | 
			
		||||
    nextChapter: string;
 | 
			
		||||
    tagsEnabled: boolean;
 | 
			
		||||
 | 
			
		||||
    protected chapters: AddonModBookTocChapter[];
 | 
			
		||||
    protected currentChapter: string;
 | 
			
		||||
@ -41,7 +43,7 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, private bookProvider: AddonModBookProvider, private courseProvider: CoreCourseProvider,
 | 
			
		||||
            private appProvider: CoreAppProvider, private prefetchDelegate: AddonModBookPrefetchHandler,
 | 
			
		||||
            private modalCtrl: ModalController, @Optional() private content: Content) {
 | 
			
		||||
            private modalCtrl: ModalController, private tagProvider: CoreTagProvider, @Optional() private content: Content) {
 | 
			
		||||
        super(injector);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -51,6 +53,8 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
 | 
			
		||||
        this.tagsEnabled = this.tagProvider.areTagsAvailableInSite();
 | 
			
		||||
 | 
			
		||||
        this.loadContent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "errorchapter": "Error reading chapter of book.",
 | 
			
		||||
    "modulenameplural": "Books",
 | 
			
		||||
    "tagarea_book_chapters": "Book chapters",
 | 
			
		||||
    "toc": "Table of contents"
 | 
			
		||||
}
 | 
			
		||||
@ -24,6 +24,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
import { CoreCourseProvider } from '@core/course/providers/course';
 | 
			
		||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
 | 
			
		||||
import { CoreSite } from '@classes/site';
 | 
			
		||||
import { CoreTagItem } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A book chapter inside the toc list.
 | 
			
		||||
@ -52,7 +53,13 @@ export interface AddonModBookTocChapter {
 | 
			
		||||
 * Map of book contents. For each chapter it has its index URL and the list of paths of the files the chapter has. Each path
 | 
			
		||||
 * is identified by the relative path in the book, and the value is the URL of the file.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBookContentsMap = {[chapter: string]: {indexUrl?: string, paths: {[path: string]: string}}};
 | 
			
		||||
export type AddonModBookContentsMap = {
 | 
			
		||||
    [chapter: string]: {
 | 
			
		||||
        indexUrl?: string,
 | 
			
		||||
        paths: {[path: string]: string},
 | 
			
		||||
        tags?: CoreTagItem[]
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service that provides some features for books.
 | 
			
		||||
@ -203,8 +210,9 @@ export class AddonModBookProvider {
 | 
			
		||||
                    map[chapter] = map[chapter] || { paths: {} };
 | 
			
		||||
 | 
			
		||||
                    if (content.filename == 'index.html' && filepathIsChapter) {
 | 
			
		||||
                        // Index of the chapter, set indexUrl of the chapter.
 | 
			
		||||
                        // Index of the chapter, set indexUrl and tags of the chapter.
 | 
			
		||||
                        map[chapter].indexUrl = content.fileurl;
 | 
			
		||||
                        map[chapter].tags = content.tags;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (filepathIsChapter) {
 | 
			
		||||
                            // It's a file in the root folder OR the WS isn't returning the filepath as it should (MDL-53671).
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								src/addon/mod/book/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/addon/mod/book/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
import { CoreCourseProvider } from '@core/course/providers/course';
 | 
			
		||||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
 | 
			
		||||
import { AddonModBookProvider } from './book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModBookTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'AddonModBookTagAreaHandler';
 | 
			
		||||
    type = 'mod_book/book_chapters';
 | 
			
		||||
 | 
			
		||||
    constructor(private tagHelper: CoreTagHelperProvider, private bookProvider: AddonModBookProvider,
 | 
			
		||||
            private courseProvider: CoreCourseProvider,  private urlUtils: CoreUrlUtilsProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return this.bookProvider.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        const items = this.tagHelper.parseFeedContent(content);
 | 
			
		||||
 | 
			
		||||
        // Find module ids of the returned books, they are needed by the link delegate.
 | 
			
		||||
        return Promise.all(items.map((item) => {
 | 
			
		||||
            const params = this.urlUtils.extractUrlParams(item.url);
 | 
			
		||||
            if (params.b && !params.id) {
 | 
			
		||||
                const bookId = parseInt(params.b, 10);
 | 
			
		||||
 | 
			
		||||
                return this.courseProvider.getModuleBasicInfoByInstance(bookId, 'book').then((module) => {
 | 
			
		||||
                    item.url += '&id=' + module.id;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        })).then(() => {
 | 
			
		||||
            return items;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -20,6 +20,7 @@ import { AddonModDataOfflineProvider } from '../../providers/offline';
 | 
			
		||||
import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
			
		||||
import { CoreUserProvider } from '@core/user/providers/user';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays a database action.
 | 
			
		||||
@ -41,13 +42,16 @@ export class AddonModDataActionComponent implements OnInit {
 | 
			
		||||
    rootUrl: string;
 | 
			
		||||
    url: string;
 | 
			
		||||
    userPicture: string;
 | 
			
		||||
    tagsEnabled: boolean;
 | 
			
		||||
 | 
			
		||||
    constructor(protected injector: Injector, protected dataProvider: AddonModDataProvider,
 | 
			
		||||
            protected dataOffline: AddonModDataOfflineProvider, protected eventsProvider: CoreEventsProvider,
 | 
			
		||||
            sitesProvider: CoreSitesProvider, protected userProvider: CoreUserProvider, private navCtrl: NavController,
 | 
			
		||||
            protected linkHelper: CoreContentLinksHelperProvider, private dataHelper: AddonModDataHelperProvider) {
 | 
			
		||||
            protected linkHelper: CoreContentLinksHelperProvider, private dataHelper: AddonModDataHelperProvider,
 | 
			
		||||
            private tagProvider: CoreTagProvider) {
 | 
			
		||||
        this.rootUrl = sitesProvider.getCurrentSite().getURL();
 | 
			
		||||
        this.siteId = sitesProvider.getCurrentSiteId();
 | 
			
		||||
        this.tagsEnabled = this.tagProvider.areTagsAvailableInSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -32,3 +32,5 @@
 | 
			
		||||
</a>
 | 
			
		||||
 | 
			
		||||
<a *ngIf="action == 'user' && entry" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">{{entry.fullname}}</a>
 | 
			
		||||
 | 
			
		||||
<core-tag-list *ngIf="tagsEnabled && action == 'tags' && entry" [tags]="entry.tags"></core-tag-list>
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ import { AddonModDataFieldPluginComponent } from './field-plugin/field-plugin';
 | 
			
		||||
import { AddonModDataActionComponent } from './action/action';
 | 
			
		||||
import { CoreCompileHtmlComponentModule } from '@core/compile/components/compile-html/compile-html.module';
 | 
			
		||||
import { CoreCommentsComponentsModule } from '@core/comments/components/components.module';
 | 
			
		||||
import { CoreTagComponentsModule } from '@core/tag/components/components.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
@ -41,7 +42,8 @@ import { CoreCommentsComponentsModule } from '@core/comments/components/componen
 | 
			
		||||
        CorePipesModule,
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
        CoreCompileHtmlComponentModule,
 | 
			
		||||
        CoreCommentsComponentsModule
 | 
			
		||||
        CoreCommentsComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,8 @@ import { AddonModDataSyncCronHandler } from './providers/sync-cron-handler';
 | 
			
		||||
import { AddonModDataOfflineProvider } from './providers/offline';
 | 
			
		||||
import { AddonModDataFieldsDelegate } from './providers/fields-delegate';
 | 
			
		||||
import { AddonModDataDefaultFieldHandler } from './providers/default-field-handler';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { AddonModDataTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
import { AddonModDataFieldModule } from './fields/field.module';
 | 
			
		||||
import { CoreUpdateManagerProvider } from '@providers/update-manager';
 | 
			
		||||
 | 
			
		||||
@ -67,7 +69,8 @@ export const ADDON_MOD_DATA_PROVIDERS: any[] = [
 | 
			
		||||
        AddonModDataEditLinkHandler,
 | 
			
		||||
        AddonModDataListLinkHandler,
 | 
			
		||||
        AddonModDataSyncCronHandler,
 | 
			
		||||
        AddonModDataDefaultFieldHandler
 | 
			
		||||
        AddonModDataDefaultFieldHandler,
 | 
			
		||||
        AddonModDataTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModDataModule {
 | 
			
		||||
@ -77,7 +80,8 @@ export class AddonModDataModule {
 | 
			
		||||
            cronDelegate: CoreCronDelegate, syncHandler: AddonModDataSyncCronHandler, updateManager: CoreUpdateManagerProvider,
 | 
			
		||||
            approveLinkHandler: AddonModDataApproveLinkHandler, deleteLinkHandler: AddonModDataDeleteLinkHandler,
 | 
			
		||||
            showLinkHandler: AddonModDataShowLinkHandler, editLinkHandler: AddonModDataEditLinkHandler,
 | 
			
		||||
            listLinkHandler: AddonModDataListLinkHandler) {
 | 
			
		||||
            listLinkHandler: AddonModDataListLinkHandler, tagAreaDelegate: CoreTagAreaDelegate,
 | 
			
		||||
            tagAreaHandler: AddonModDataTagAreaHandler) {
 | 
			
		||||
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        prefetchDelegate.registerHandler(prefetchHandler);
 | 
			
		||||
@ -88,6 +92,7 @@ export class AddonModDataModule {
 | 
			
		||||
        contentLinksDelegate.registerHandler(editLinkHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(listLinkHandler);
 | 
			
		||||
        cronDelegate.register(syncHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
 | 
			
		||||
        // Allow migrating the tables from the old app to the new schema.
 | 
			
		||||
        updateManager.registerSiteTableMigration({
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@
 | 
			
		||||
    "confirmdeleterecord": "Are you sure you want to delete this entry?",
 | 
			
		||||
    "descending": "Descending",
 | 
			
		||||
    "disapprove": "Undo approval",
 | 
			
		||||
    "edittagsnotsupported": "Sorry, editing tags is not supported by the app.",
 | 
			
		||||
    "emptyaddform": "You did not fill out any fields!",
 | 
			
		||||
    "entrieslefttoadd": "You must add {{$a.entriesleft}} more entry/entries in order to complete this activity",
 | 
			
		||||
    "entrieslefttoaddtoview": "You must add {{$a.entrieslefttoview}} more entry/entries before you can view other participants' entries.",
 | 
			
		||||
@ -34,8 +35,10 @@
 | 
			
		||||
    "recorddisapproved": "Entry unapproved",
 | 
			
		||||
    "resetsettings": "Reset filters",
 | 
			
		||||
    "search": "Search",
 | 
			
		||||
    "searchbytagsnotsupported": "Sorry, searching by tags is not supported by the app.",
 | 
			
		||||
    "selectedrequired": "All selected required",
 | 
			
		||||
    "single": "View single",
 | 
			
		||||
    "tagarea_data_records": "Data records",
 | 
			
		||||
    "timeadded": "Time added",
 | 
			
		||||
    "timemodified": "Time modified",
 | 
			
		||||
    "usedate": "Include in search."
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ import { AddonModDataHelperProvider } from '../../providers/helper';
 | 
			
		||||
import { AddonModDataOfflineProvider } from '../../providers/offline';
 | 
			
		||||
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
 | 
			
		||||
import { AddonModDataComponentsModule } from '../../components/components.module';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays the view edit page.
 | 
			
		||||
@ -68,7 +69,8 @@ export class AddonModDataEditPage {
 | 
			
		||||
            protected courseProvider: CoreCourseProvider, protected dataProvider: AddonModDataProvider,
 | 
			
		||||
            protected dataOffline: AddonModDataOfflineProvider, protected dataHelper: AddonModDataHelperProvider,
 | 
			
		||||
            sitesProvider: CoreSitesProvider, protected navCtrl: NavController, protected translate: TranslateService,
 | 
			
		||||
            protected eventsProvider: CoreEventsProvider, protected fileUploaderProvider: CoreFileUploaderProvider) {
 | 
			
		||||
            protected eventsProvider: CoreEventsProvider, protected fileUploaderProvider: CoreFileUploaderProvider,
 | 
			
		||||
            private tagProvider: CoreTagProvider) {
 | 
			
		||||
        this.module = params.get('module') || {};
 | 
			
		||||
        this.entryId = params.get('entryId') || null;
 | 
			
		||||
        this.courseId = params.get('courseId');
 | 
			
		||||
@ -302,6 +304,11 @@ export class AddonModDataEditPage {
 | 
			
		||||
            template = template.replace(replace, 'field_' + field.id);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Editing tags is not supported.
 | 
			
		||||
        replace = new RegExp('##tags##', 'gi');
 | 
			
		||||
        const message = '<p class="item-dimmed">{{ \'addon.mod_data.edittagsnotsupported\' | translate }}</p>';
 | 
			
		||||
        template = template.replace(replace, this.tagProvider.areTagsAvailableInSite() ? message : '');
 | 
			
		||||
 | 
			
		||||
        return template;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
			
		||||
import { AddonModDataComponentsModule } from '../../components/components.module';
 | 
			
		||||
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
 | 
			
		||||
import { AddonModDataHelperProvider } from '../../providers/helper';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays the search modal.
 | 
			
		||||
@ -42,7 +43,8 @@ export class AddonModDataSearchPage {
 | 
			
		||||
 | 
			
		||||
    constructor(params: NavParams, private viewCtrl: ViewController, fb: FormBuilder, protected utils: CoreUtilsProvider,
 | 
			
		||||
            protected domUtils: CoreDomUtilsProvider, protected fieldsDelegate: AddonModDataFieldsDelegate,
 | 
			
		||||
            protected textUtils: CoreTextUtilsProvider, protected dataHelper: AddonModDataHelperProvider) {
 | 
			
		||||
            protected textUtils: CoreTextUtilsProvider, protected dataHelper: AddonModDataHelperProvider,
 | 
			
		||||
            private tagProvider: CoreTagProvider) {
 | 
			
		||||
        this.search = params.get('search');
 | 
			
		||||
        this.fields = params.get('fields');
 | 
			
		||||
        this.data = params.get('data');
 | 
			
		||||
@ -117,9 +119,10 @@ export class AddonModDataSearchPage {
 | 
			
		||||
        [placeholder]="\'addon.mod_data.authorlastname\' | translate" formControlName="lastname"></ion-input></span>';
 | 
			
		||||
        template = template.replace(replace, render);
 | 
			
		||||
 | 
			
		||||
        // Tags are unsupported right now.
 | 
			
		||||
        // Searching by tags is not supported.
 | 
			
		||||
        replace = new RegExp('##tags##', 'gi');
 | 
			
		||||
        template = template.replace(replace, '');
 | 
			
		||||
        const message = '<p class="item-dimmed">{{ \'addon.mod_data.searchbytagsnotsupported\' | translate }}</p>';
 | 
			
		||||
        template = template.replace(replace, this.tagProvider.areTagsAvailableInSite() ? message : '');
 | 
			
		||||
 | 
			
		||||
        return template;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -367,6 +367,7 @@ export class AddonModDataHelperProvider {
 | 
			
		||||
            userpicture: true,
 | 
			
		||||
            timeadded: true,
 | 
			
		||||
            timemodified: true,
 | 
			
		||||
            tags: true,
 | 
			
		||||
 | 
			
		||||
            edit: record.canmanageentry && !record.deleted, // This already checks capabilities and readonly period.
 | 
			
		||||
            delete: record.canmanageentry,
 | 
			
		||||
@ -377,7 +378,6 @@ export class AddonModDataHelperProvider {
 | 
			
		||||
            comments: database.comments,
 | 
			
		||||
 | 
			
		||||
            // Unsupported actions.
 | 
			
		||||
            tags: false,
 | 
			
		||||
            delcheck: false,
 | 
			
		||||
            export: false
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								src/addon/mod/data/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/addon/mod/data/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
import { AddonModDataProvider } from './data';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModDataTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'AddonModDataTagAreaHandler';
 | 
			
		||||
    type = 'mod_data/data_records';
 | 
			
		||||
 | 
			
		||||
    constructor(private tagHelper: CoreTagHelperProvider, private dataProvider: AddonModDataProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return this.dataProvider.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        return this.tagHelper.parseFeedContent(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -21,6 +21,7 @@ import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CorePipesModule } from '@pipes/pipes.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
 | 
			
		||||
import { CoreRatingComponentsModule } from '@core/rating/components/components.module';
 | 
			
		||||
import { CoreTagComponentsModule } from '@core/tag/components/components.module';
 | 
			
		||||
import { AddonModForumIndexComponent } from './index/index';
 | 
			
		||||
import { AddonModForumPostComponent } from './post/post';
 | 
			
		||||
 | 
			
		||||
@ -37,7 +38,8 @@ import { AddonModForumPostComponent } from './post/post';
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CorePipesModule,
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
        CoreRatingComponentsModule
 | 
			
		||||
        CoreRatingComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,10 @@
 | 
			
		||||
        </ng-container>
 | 
			
		||||
    </div>
 | 
			
		||||
</ion-card-content>
 | 
			
		||||
<ion-item text-wrap *ngIf="tagsEnabled && post.tags && post.tags.length > 0">
 | 
			
		||||
    <div item-start>{{ 'core.tag.tags' | translate }}:</div>
 | 
			
		||||
    <core-tag-list [tags]="post.tags"></core-tag-list>
 | 
			
		||||
</ion-item>
 | 
			
		||||
<core-rating-rate *ngIf="forum && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" [itemId]="post.id" [itemSetId]="discussionId" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale" [userId]="post.userid" (onUpdate)="ratingUpdated()"></core-rating-rate>
 | 
			
		||||
<core-rating-aggregate *ngIf="forum && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" [itemId]="post.id" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale"></core-rating-aggregate>
 | 
			
		||||
<ion-item no-padding text-end *ngIf="post.id && post.canreply && !post.isprivatereply" class="addon-forum-reply-button">
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ import { AddonModForumHelperProvider } from '../../providers/helper';
 | 
			
		||||
import { AddonModForumOfflineProvider } from '../../providers/offline';
 | 
			
		||||
import { AddonModForumSyncProvider } from '../../providers/sync';
 | 
			
		||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
 | 
			
		||||
@ -52,6 +53,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    uniqueId: string;
 | 
			
		||||
    advanced = false; // Display all form fields.
 | 
			
		||||
    tagsEnabled: boolean;
 | 
			
		||||
 | 
			
		||||
    protected syncId: string;
 | 
			
		||||
 | 
			
		||||
@ -65,8 +67,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy {
 | 
			
		||||
            private forumHelper: AddonModForumHelperProvider,
 | 
			
		||||
            private forumOffline: AddonModForumOfflineProvider,
 | 
			
		||||
            private forumSync: AddonModForumSyncProvider,
 | 
			
		||||
            private tagProvider: CoreTagProvider,
 | 
			
		||||
            @Optional() private content: Content) {
 | 
			
		||||
        this.onPostChange = new EventEmitter<void>();
 | 
			
		||||
        this.tagsEnabled = this.tagProvider.areTagsAvailableInSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { AddonModForumProvider } from './providers/forum';
 | 
			
		||||
import { AddonModForumOfflineProvider } from './providers/offline';
 | 
			
		||||
import { AddonModForumHelperProvider } from './providers/helper';
 | 
			
		||||
@ -30,6 +31,7 @@ import { AddonModForumDiscussionLinkHandler } from './providers/discussion-link-
 | 
			
		||||
import { AddonModForumListLinkHandler } from './providers/list-link-handler';
 | 
			
		||||
import { AddonModForumPostLinkHandler } from './providers/post-link-handler';
 | 
			
		||||
import { AddonModForumPushClickHandler } from './providers/push-click-handler';
 | 
			
		||||
import { AddonModForumTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
import { AddonModForumComponentsModule } from './components/components.module';
 | 
			
		||||
import { CoreUpdateManagerProvider } from '@providers/update-manager';
 | 
			
		||||
 | 
			
		||||
@ -59,7 +61,8 @@ export const ADDON_MOD_FORUM_PROVIDERS: any[] = [
 | 
			
		||||
        AddonModForumListLinkHandler,
 | 
			
		||||
        AddonModForumPostLinkHandler,
 | 
			
		||||
        AddonModForumDiscussionLinkHandler,
 | 
			
		||||
        AddonModForumPushClickHandler
 | 
			
		||||
        AddonModForumPushClickHandler,
 | 
			
		||||
        AddonModForumTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModForumModule {
 | 
			
		||||
@ -69,7 +72,8 @@ export class AddonModForumModule {
 | 
			
		||||
            indexHandler: AddonModForumIndexLinkHandler, discussionHandler: AddonModForumDiscussionLinkHandler,
 | 
			
		||||
            updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModForumListLinkHandler,
 | 
			
		||||
            pushNotificationsDelegate: CorePushNotificationsDelegate, pushClickHandler: AddonModForumPushClickHandler,
 | 
			
		||||
            postLinkHandler: AddonModForumPostLinkHandler) {
 | 
			
		||||
            postLinkHandler: AddonModForumPostLinkHandler, tagAreaDelegate: CoreTagAreaDelegate,
 | 
			
		||||
            tagAreaHandler: AddonModForumTagAreaHandler) {
 | 
			
		||||
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        prefetchDelegate.registerHandler(prefetchHandler);
 | 
			
		||||
@ -79,6 +83,7 @@ export class AddonModForumModule {
 | 
			
		||||
        linksDelegate.registerHandler(listLinkHandler);
 | 
			
		||||
        linksDelegate.registerHandler(postLinkHandler);
 | 
			
		||||
        pushNotificationsDelegate.registerClickHandler(pushClickHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
 | 
			
		||||
        // Allow migrating the tables from the old app to the new schema.
 | 
			
		||||
        updateManager.registerSiteTablesMigration([
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,7 @@
 | 
			
		||||
    "reply": "Reply",
 | 
			
		||||
    "replyplaceholder": "Write your reply...",
 | 
			
		||||
    "subject": "Subject",
 | 
			
		||||
    "tagarea_forum_posts": "Forum posts",
 | 
			
		||||
    "thisforumhasduedate": "The due date for posting to this forum is {{$a}}.",
 | 
			
		||||
    "thisforumisdue": "The due date for posting to this forum was {{$a}}.",
 | 
			
		||||
    "unlockdiscussion": "Unlock this discussion",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								src/addon/mod/forum/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/addon/mod/forum/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModForumTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'AddonModForumTagAreaHandler';
 | 
			
		||||
    type = 'mod_forum/forum_posts';
 | 
			
		||||
 | 
			
		||||
    constructor(private tagHelper: CoreTagHelperProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        return this.tagHelper.parseFeedContent(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -17,6 +17,7 @@ import { CoreCronDelegate } from '@providers/cron';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { AddonModGlossaryProvider } from './providers/glossary';
 | 
			
		||||
import { AddonModGlossaryOfflineProvider } from './providers/offline';
 | 
			
		||||
import { AddonModGlossaryHelperProvider } from './providers/helper';
 | 
			
		||||
@ -28,6 +29,7 @@ import { AddonModGlossaryIndexLinkHandler } from './providers/index-link-handler
 | 
			
		||||
import { AddonModGlossaryEntryLinkHandler } from './providers/entry-link-handler';
 | 
			
		||||
import { AddonModGlossaryListLinkHandler } from './providers/list-link-handler';
 | 
			
		||||
import { AddonModGlossaryEditLinkHandler } from './providers/edit-link-handler';
 | 
			
		||||
import { AddonModGlossaryTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
import { AddonModGlossaryComponentsModule } from './components/components.module';
 | 
			
		||||
import { CoreUpdateManagerProvider } from '@providers/update-manager';
 | 
			
		||||
 | 
			
		||||
@ -56,7 +58,8 @@ export const ADDON_MOD_GLOSSARY_PROVIDERS: any[] = [
 | 
			
		||||
        AddonModGlossaryIndexLinkHandler,
 | 
			
		||||
        AddonModGlossaryEntryLinkHandler,
 | 
			
		||||
        AddonModGlossaryListLinkHandler,
 | 
			
		||||
        AddonModGlossaryEditLinkHandler
 | 
			
		||||
        AddonModGlossaryEditLinkHandler,
 | 
			
		||||
        AddonModGlossaryTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModGlossaryModule {
 | 
			
		||||
@ -65,7 +68,8 @@ export class AddonModGlossaryModule {
 | 
			
		||||
            cronDelegate: CoreCronDelegate, syncHandler: AddonModGlossarySyncCronHandler, linksDelegate: CoreContentLinksDelegate,
 | 
			
		||||
            indexHandler: AddonModGlossaryIndexLinkHandler, discussionHandler: AddonModGlossaryEntryLinkHandler,
 | 
			
		||||
            updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModGlossaryListLinkHandler,
 | 
			
		||||
            editLinkHandler: AddonModGlossaryEditLinkHandler) {
 | 
			
		||||
            editLinkHandler: AddonModGlossaryEditLinkHandler, tagAreaDelegate: CoreTagAreaDelegate,
 | 
			
		||||
            tagAreaHandler: AddonModGlossaryTagAreaHandler) {
 | 
			
		||||
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        prefetchDelegate.registerHandler(prefetchHandler);
 | 
			
		||||
@ -74,6 +78,7 @@ export class AddonModGlossaryModule {
 | 
			
		||||
        linksDelegate.registerHandler(discussionHandler);
 | 
			
		||||
        linksDelegate.registerHandler(listLinkHandler);
 | 
			
		||||
        linksDelegate.registerHandler(editLinkHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
 | 
			
		||||
        // Allow migrating the tables from the old app to the new schema.
 | 
			
		||||
        updateManager.registerSiteTableMigration({
 | 
			
		||||
 | 
			
		||||
@ -26,5 +26,6 @@
 | 
			
		||||
    "linking": "Auto-linking",
 | 
			
		||||
    "modulenameplural": "Glossaries",
 | 
			
		||||
    "noentriesfound": "No entries were found.",
 | 
			
		||||
    "searchquery": "Search query"
 | 
			
		||||
    "searchquery": "Search query",
 | 
			
		||||
    "tagarea_glossary_entries": "Glossary entries"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,10 @@
 | 
			
		||||
                    <core-file *ngFor="let file of entry.attachments" [file]="file" [component]="component" [componentId]="componentId"></core-file>
 | 
			
		||||
                </div>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
            <ion-item text-wrap *ngIf="tagsEnabled && entry && entry.tags && entry.tags.length > 0">
 | 
			
		||||
                <div item-start>{{ 'core.tag.tags' | translate }}:</div>
 | 
			
		||||
                <core-tag-list [tags]="entry.tags"></core-tag-list>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
            <ion-item text-wrap *ngIf="entry.approved != 1">
 | 
			
		||||
                <p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CorePipesModule } from '@pipes/pipes.module';
 | 
			
		||||
import { CoreRatingComponentsModule } from '@core/rating/components/components.module';
 | 
			
		||||
import { CoreTagComponentsModule } from '@core/tag/components/components.module';
 | 
			
		||||
import { AddonModGlossaryEntryPage } from './entry';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
@ -31,7 +32,8 @@ import { AddonModGlossaryEntryPage } from './entry';
 | 
			
		||||
        CorePipesModule,
 | 
			
		||||
        IonicPageModule.forChild(AddonModGlossaryEntryPage),
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreRatingComponentsModule
 | 
			
		||||
        CoreRatingComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModForumDiscussionPageModule {}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ import { Component } from '@angular/core';
 | 
			
		||||
import { IonicPage, NavParams } from 'ionic-angular';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
import { AddonModGlossaryProvider } from '../../providers/glossary';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -35,15 +36,18 @@ export class AddonModGlossaryEntryPage {
 | 
			
		||||
    showAuthor = false;
 | 
			
		||||
    showDate = false;
 | 
			
		||||
    ratingInfo: CoreRatingInfo;
 | 
			
		||||
    tagsEnabled: boolean;
 | 
			
		||||
 | 
			
		||||
    protected courseId: number;
 | 
			
		||||
    protected entryId: number;
 | 
			
		||||
 | 
			
		||||
    constructor(navParams: NavParams,
 | 
			
		||||
            private domUtils: CoreDomUtilsProvider,
 | 
			
		||||
            private glossaryProvider: AddonModGlossaryProvider) {
 | 
			
		||||
            private glossaryProvider: AddonModGlossaryProvider,
 | 
			
		||||
            private tagProvider: CoreTagProvider) {
 | 
			
		||||
        this.courseId = navParams.get('courseId');
 | 
			
		||||
        this.entryId = navParams.get('entryId');
 | 
			
		||||
        this.tagsEnabled = this.tagProvider.areTagsAvailableInSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								src/addon/mod/glossary/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/addon/mod/glossary/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModGlossaryTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'AddonModGlossaryTagAreaHandler';
 | 
			
		||||
    type = 'mod_glossary/glossary_entries';
 | 
			
		||||
 | 
			
		||||
    constructor(private tagHelper: CoreTagHelperProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        return this.tagHelper.parseFeedContent(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -19,6 +19,7 @@ import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
 | 
			
		||||
import { CoreTagComponentsModule } from '@core/tag/components/components.module';
 | 
			
		||||
import { AddonModWikiIndexComponent } from './index/index';
 | 
			
		||||
import { AddonModWikiSubwikiPickerComponent } from './subwiki-picker/subwiki-picker';
 | 
			
		||||
 | 
			
		||||
@ -33,7 +34,8 @@ import { AddonModWikiSubwikiPickerComponent } from './subwiki-picker/subwiki-pic
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CoreCourseComponentsModule
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,11 @@
 | 
			
		||||
                        <core-format-text *ngIf="pageContent" [component]="component" [componentId]="componentId" [text]="pageContent"></core-format-text>
 | 
			
		||||
                        <core-empty-box *ngIf="!pageContent" icon="document" [message]="'addon.mod_wiki.nocontent' | translate" [inline]="true"></core-empty-box>
 | 
			
		||||
                    </article>
 | 
			
		||||
 | 
			
		||||
                    <div margin-top *ngIf="tagsEnabled && currentPageObj && currentPageObj.tags && currentPageObj.tags.length > 0">
 | 
			
		||||
                        <b>{{ 'core.tag.tags' | translate }}:</b>
 | 
			
		||||
                        <core-tag-list [tags]="currentPageObj.tags"></core-tag-list>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </ng-template>
 | 
			
		||||
        </core-tab>
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ import { AddonModWikiOfflineProvider } from '../../providers/wiki-offline';
 | 
			
		||||
import { AddonModWikiSyncProvider } from '../../providers/wiki-sync';
 | 
			
		||||
import { CoreTabsComponent } from '@components/tabs/tabs';
 | 
			
		||||
import { AddonModWikiSubwikiPickerComponent } from '../../components/subwiki-picker/subwiki-picker';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays a wiki entry page.
 | 
			
		||||
@ -64,6 +65,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
        subwikis: [],
 | 
			
		||||
        count: 0
 | 
			
		||||
    };
 | 
			
		||||
    tagsEnabled: boolean;
 | 
			
		||||
 | 
			
		||||
    protected syncEventName = AddonModWikiSyncProvider.AUTO_SYNCED;
 | 
			
		||||
    protected currentSubwiki: any; // Current selected subwiki.
 | 
			
		||||
@ -81,10 +83,12 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
    constructor(injector: Injector, protected wikiProvider: AddonModWikiProvider, @Optional() protected content: Content,
 | 
			
		||||
            protected wikiOffline: AddonModWikiOfflineProvider, protected wikiSync: AddonModWikiSyncProvider,
 | 
			
		||||
            protected navCtrl: NavController, protected utils: CoreUtilsProvider, protected groupsProvider: CoreGroupsProvider,
 | 
			
		||||
            protected userProvider: CoreUserProvider, private popoverCtrl: PopoverController) {
 | 
			
		||||
            protected userProvider: CoreUserProvider, private popoverCtrl: PopoverController,
 | 
			
		||||
            private tagProvider: CoreTagProvider) {
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
 | 
			
		||||
        this.pageStr = this.translate.instant('addon.mod_wiki.wikipage');
 | 
			
		||||
        this.tagsEnabled = this.tagProvider.areTagsAvailableInSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@
 | 
			
		||||
    "pageexists": "This page already exists.",
 | 
			
		||||
    "pagename": "Page name",
 | 
			
		||||
    "subwiki": "Sub-wiki",
 | 
			
		||||
    "tagarea_wiki_pages": "Wiki pages",
 | 
			
		||||
    "titleshouldnotbeempty": "The title should not be empty",
 | 
			
		||||
    "viewpage": "View page",
 | 
			
		||||
    "wikipage": "Wiki page",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								src/addon/mod/wiki/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/addon/mod/wiki/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModWikiTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'AddonModWikiTagAreaHandler';
 | 
			
		||||
    type = 'mod_wiki/wiki_pages';
 | 
			
		||||
 | 
			
		||||
    constructor(private tagHelper: CoreTagHelperProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        return this.tagHelper.parseFeedContent(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -17,6 +17,7 @@ import { CoreCronDelegate } from '@providers/cron';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { AddonModWikiComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModWikiProvider } from './providers/wiki';
 | 
			
		||||
import { AddonModWikiOfflineProvider } from './providers/wiki-offline';
 | 
			
		||||
@ -29,6 +30,7 @@ import { AddonModWikiPageOrMapLinkHandler } from './providers/page-or-map-link-h
 | 
			
		||||
import { AddonModWikiCreateLinkHandler } from './providers/create-link-handler';
 | 
			
		||||
import { AddonModWikiEditLinkHandler } from './providers/edit-link-handler';
 | 
			
		||||
import { AddonModWikiListLinkHandler } from './providers/list-link-handler';
 | 
			
		||||
import { AddonModWikiTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
import { CoreUpdateManagerProvider } from '@providers/update-manager';
 | 
			
		||||
 | 
			
		||||
// List of providers (without handlers).
 | 
			
		||||
@ -55,7 +57,8 @@ export const ADDON_MOD_WIKI_PROVIDERS: any[] = [
 | 
			
		||||
        AddonModWikiPageOrMapLinkHandler,
 | 
			
		||||
        AddonModWikiCreateLinkHandler,
 | 
			
		||||
        AddonModWikiEditLinkHandler,
 | 
			
		||||
        AddonModWikiListLinkHandler
 | 
			
		||||
        AddonModWikiListLinkHandler,
 | 
			
		||||
        AddonModWikiTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModWikiModule {
 | 
			
		||||
@ -64,7 +67,8 @@ export class AddonModWikiModule {
 | 
			
		||||
            cronDelegate: CoreCronDelegate, syncHandler: AddonModWikiSyncCronHandler, linksDelegate: CoreContentLinksDelegate,
 | 
			
		||||
            indexHandler: AddonModWikiIndexLinkHandler, pageOrMapHandler: AddonModWikiPageOrMapLinkHandler,
 | 
			
		||||
            createHandler: AddonModWikiCreateLinkHandler, editHandler: AddonModWikiEditLinkHandler,
 | 
			
		||||
            updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModWikiListLinkHandler) {
 | 
			
		||||
            updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModWikiListLinkHandler,
 | 
			
		||||
            tagAreaDelegate: CoreTagAreaDelegate, tagAreaHandler: AddonModWikiTagAreaHandler) {
 | 
			
		||||
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        prefetchDelegate.registerHandler(prefetchHandler);
 | 
			
		||||
@ -74,6 +78,7 @@ export class AddonModWikiModule {
 | 
			
		||||
        linksDelegate.registerHandler(createHandler);
 | 
			
		||||
        linksDelegate.registerHandler(editHandler);
 | 
			
		||||
        linksDelegate.registerHandler(listLinkHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
 | 
			
		||||
        // Allow migrating the tables from the old app to the new schema.
 | 
			
		||||
        updateManager.registerSiteTableMigration({
 | 
			
		||||
 | 
			
		||||
@ -81,6 +81,7 @@ import { CoreQuestionModule } from '@core/question/question.module';
 | 
			
		||||
import { CoreCommentsModule } from '@core/comments/comments.module';
 | 
			
		||||
import { CoreBlockModule } from '@core/block/block.module';
 | 
			
		||||
import { CoreRatingModule } from '@core/rating/rating.module';
 | 
			
		||||
import { CoreTagModule } from '@core/tag/tag.module';
 | 
			
		||||
 | 
			
		||||
// Addon modules.
 | 
			
		||||
import { AddonBadgesModule } from '@addon/badges/badges.module';
 | 
			
		||||
@ -225,6 +226,7 @@ export const WP_PROVIDER: any = null;
 | 
			
		||||
        CoreBlockModule,
 | 
			
		||||
        CoreRatingModule,
 | 
			
		||||
        CorePushNotificationsModule,
 | 
			
		||||
        CoreTagModule,
 | 
			
		||||
        AddonBadgesModule,
 | 
			
		||||
        AddonBlogModule,
 | 
			
		||||
        AddonCalendarModule,
 | 
			
		||||
 | 
			
		||||
@ -419,6 +419,7 @@
 | 
			
		||||
    "addon.mod_assign_submission_onlinetext.wordlimitexceeded": "The word limit for this assignment is {{$a.limit}} words and you are attempting to submit {{$a.count}} words. Please review your submission and try again.",
 | 
			
		||||
    "addon.mod_book.errorchapter": "Error reading chapter of book.",
 | 
			
		||||
    "addon.mod_book.modulenameplural": "Books",
 | 
			
		||||
    "addon.mod_book.tagarea_book_chapters": "Book chapters",
 | 
			
		||||
    "addon.mod_book.toc": "Table of contents",
 | 
			
		||||
    "addon.mod_chat.beep": "Beep",
 | 
			
		||||
    "addon.mod_chat.chatreport": "Chat sessions",
 | 
			
		||||
@ -478,6 +479,7 @@
 | 
			
		||||
    "addon.mod_data.confirmdeleterecord": "Are you sure you want to delete this entry?",
 | 
			
		||||
    "addon.mod_data.descending": "Descending",
 | 
			
		||||
    "addon.mod_data.disapprove": "Undo approval",
 | 
			
		||||
    "addon.mod_data.edittagsnotsupported": "Sorry, editing tags is not supported by the app.",
 | 
			
		||||
    "addon.mod_data.emptyaddform": "You did not fill out any fields!",
 | 
			
		||||
    "addon.mod_data.entrieslefttoadd": "You must add {{$a.entriesleft}} more entry/entries in order to complete this activity",
 | 
			
		||||
    "addon.mod_data.entrieslefttoaddtoview": "You must add {{$a.entrieslefttoview}} more entry/entries before you can view other participants' entries.",
 | 
			
		||||
@ -502,8 +504,10 @@
 | 
			
		||||
    "addon.mod_data.recorddisapproved": "Entry unapproved",
 | 
			
		||||
    "addon.mod_data.resetsettings": "Reset filters",
 | 
			
		||||
    "addon.mod_data.search": "Search",
 | 
			
		||||
    "addon.mod_data.searchbytagsnotsupported": "Sorry, searching by tags is not supported by the app.",
 | 
			
		||||
    "addon.mod_data.selectedrequired": "All selected required",
 | 
			
		||||
    "addon.mod_data.single": "View single",
 | 
			
		||||
    "addon.mod_data.tagarea_data_records": "Data records",
 | 
			
		||||
    "addon.mod_data.timeadded": "Time added",
 | 
			
		||||
    "addon.mod_data.timemodified": "Time modified",
 | 
			
		||||
    "addon.mod_data.usedate": "Include in search.",
 | 
			
		||||
@ -596,6 +600,7 @@
 | 
			
		||||
    "addon.mod_forum.reply": "Reply",
 | 
			
		||||
    "addon.mod_forum.replyplaceholder": "Write your reply...",
 | 
			
		||||
    "addon.mod_forum.subject": "Subject",
 | 
			
		||||
    "addon.mod_forum.tagarea_forum_posts": "Forum posts",
 | 
			
		||||
    "addon.mod_forum.thisforumhasduedate": "The due date for posting to this forum is {{$a}}.",
 | 
			
		||||
    "addon.mod_forum.thisforumisdue": "The due date for posting to this forum was {{$a}}.",
 | 
			
		||||
    "addon.mod_forum.unlockdiscussion": "Unlock this discussion",
 | 
			
		||||
@ -630,6 +635,7 @@
 | 
			
		||||
    "addon.mod_glossary.modulenameplural": "Glossaries",
 | 
			
		||||
    "addon.mod_glossary.noentriesfound": "No entries were found.",
 | 
			
		||||
    "addon.mod_glossary.searchquery": "Search query",
 | 
			
		||||
    "addon.mod_glossary.tagarea_glossary_entries": "Glossary entries",
 | 
			
		||||
    "addon.mod_imscp.deploymenterror": "Content package error!",
 | 
			
		||||
    "addon.mod_imscp.modulenameplural": "IMS content packages",
 | 
			
		||||
    "addon.mod_imscp.showmoduledescription": "Show description",
 | 
			
		||||
@ -886,6 +892,7 @@
 | 
			
		||||
    "addon.mod_wiki.pageexists": "This page already exists.",
 | 
			
		||||
    "addon.mod_wiki.pagename": "Page name",
 | 
			
		||||
    "addon.mod_wiki.subwiki": "Sub-wiki",
 | 
			
		||||
    "addon.mod_wiki.tagarea_wiki_pages": "Wiki pages",
 | 
			
		||||
    "addon.mod_wiki.titleshouldnotbeempty": "The title should not be empty",
 | 
			
		||||
    "addon.mod_wiki.viewpage": "View page",
 | 
			
		||||
    "addon.mod_wiki.wikipage": "Wiki page",
 | 
			
		||||
@ -1863,6 +1870,20 @@
 | 
			
		||||
    "core.submit": "Submit",
 | 
			
		||||
    "core.success": "Success",
 | 
			
		||||
    "core.tablet": "Tablet",
 | 
			
		||||
    "core.tag.defautltagcoll": "Default collection",
 | 
			
		||||
    "core.tag.errorareanotsupported": "This tag area is not supported by the app.",
 | 
			
		||||
    "core.tag.inalltagcoll": "Everywhere",
 | 
			
		||||
    "core.tag.itemstaggedwith": "{{$a.tagarea}} tagged with \"{{$a.tag}}\"",
 | 
			
		||||
    "core.tag.notagsfound": "No tags matching \"{{$a}}\" found",
 | 
			
		||||
    "core.tag.searchtags": "Search tags",
 | 
			
		||||
    "core.tag.showingfirsttags": "Showing {{$a}} most popular tags",
 | 
			
		||||
    "core.tag.tag": "Tag",
 | 
			
		||||
    "core.tag.tagarea_course": "Courses",
 | 
			
		||||
    "core.tag.tagarea_course_modules": "Activities and resources",
 | 
			
		||||
    "core.tag.tagarea_post": "Blog posts",
 | 
			
		||||
    "core.tag.tagarea_user": "User interests",
 | 
			
		||||
    "core.tag.tags": "Tags",
 | 
			
		||||
    "core.tag.warningareasnotsupported": "Some of the tag areas are not displayed because they are not supported by the app.",
 | 
			
		||||
    "core.teachers": "Teachers",
 | 
			
		||||
    "core.thereisdatatosync": "There are offline {{$a}} to be synchronised.",
 | 
			
		||||
    "core.thisdirection": "ltr",
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,7 @@ export class CoreSearchBoxComponent implements OnInit {
 | 
			
		||||
    @Input() lengthCheck = 3; // Check value length before submit. If 0, any string will be submitted.
 | 
			
		||||
    @Input() showClear = true; // Show/hide clear button.
 | 
			
		||||
    @Input() disabled = false; // Disables the input text.
 | 
			
		||||
    @Input() initialSearch: string; // Initial search text.
 | 
			
		||||
    @Output() onSubmit: EventEmitter<string>; // Send data when submitting the search form.
 | 
			
		||||
    @Output() onClear: EventEmitter<void>; // Send event when clearing the search form.
 | 
			
		||||
 | 
			
		||||
@ -55,6 +56,7 @@ export class CoreSearchBoxComponent implements OnInit {
 | 
			
		||||
        this.placeholder = this.placeholder || this.translate.instant('core.search');
 | 
			
		||||
        this.spellcheck = this.utils.isTrueOrOne(this.spellcheck);
 | 
			
		||||
        this.showClear = this.utils.isTrueOrOne(this.showClear);
 | 
			
		||||
        this.searchText = this.initialSearch || '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ import { CoreCourseFormatComponent } from './format/format';
 | 
			
		||||
import { CoreCourseModuleComponent } from './module/module';
 | 
			
		||||
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';
 | 
			
		||||
import { CoreCourseModuleDescriptionComponent } from './module-description/module-description';
 | 
			
		||||
import { CoreCourseTagAreaComponent } from './tag-area/tag-area';
 | 
			
		||||
import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsupported-module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
@ -31,6 +32,7 @@ import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsup
 | 
			
		||||
        CoreCourseModuleComponent,
 | 
			
		||||
        CoreCourseModuleCompletionComponent,
 | 
			
		||||
        CoreCourseModuleDescriptionComponent,
 | 
			
		||||
        CoreCourseTagAreaComponent,
 | 
			
		||||
        CoreCourseUnsupportedModuleComponent
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
@ -48,10 +50,12 @@ import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsup
 | 
			
		||||
        CoreCourseModuleComponent,
 | 
			
		||||
        CoreCourseModuleCompletionComponent,
 | 
			
		||||
        CoreCourseModuleDescriptionComponent,
 | 
			
		||||
        CoreCourseTagAreaComponent,
 | 
			
		||||
        CoreCourseUnsupportedModuleComponent
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        CoreCourseUnsupportedModuleComponent
 | 
			
		||||
        CoreCourseUnsupportedModuleComponent,
 | 
			
		||||
        CoreCourseTagAreaComponent
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class CoreCourseComponentsModule {}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,5 @@
 | 
			
		||||
<a ion-item text-wrap *ngFor="let item of items" (click)="openCourse(item.courseId)" [title]="item.courseName">
 | 
			
		||||
    <core-icon name="fa-graduation-cap" item-start></core-icon>
 | 
			
		||||
    <h2>{{ item.courseName }}</h2>
 | 
			
		||||
    <p *ngIf="item.categoryName">{{ 'core.category' | translate }}: {{ item.categoryName }}</p>
 | 
			
		||||
</a>
 | 
			
		||||
							
								
								
									
										43
									
								
								src/core/course/components/tag-area/tag-area.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/core/course/components/tag-area/tag-area.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
// (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, Optional } from '@angular/core';
 | 
			
		||||
import { NavController } from 'ionic-angular';
 | 
			
		||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
 | 
			
		||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that renders the course tag area.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'core-course-tag-area',
 | 
			
		||||
    templateUrl: 'core-course-tag-area.html'
 | 
			
		||||
})
 | 
			
		||||
export class CoreCourseTagAreaComponent {
 | 
			
		||||
    @Input() items: any[]; // Area items to render.
 | 
			
		||||
 | 
			
		||||
    constructor(private navCtrl: NavController,  @Optional() private splitviewCtrl: CoreSplitViewComponent,
 | 
			
		||||
            private courseHelper: CoreCourseHelperProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Open a course.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} courseId The course to open.
 | 
			
		||||
     */
 | 
			
		||||
    openCourse(courseId: number): void {
 | 
			
		||||
        // If this component is inside a split view, use the master nav to open it.
 | 
			
		||||
        const navCtrl = this.splitviewCtrl ? this.splitviewCtrl.getMasterNav() : this.navCtrl;
 | 
			
		||||
        this.courseHelper.getAndOpenCourse(navCtrl, courseId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -33,6 +33,9 @@ import { CoreCourseFormatWeeksModule } from './formats/weeks/weeks.module';
 | 
			
		||||
import { CoreCourseSyncProvider } from './providers/sync';
 | 
			
		||||
import { CoreCourseSyncCronHandler } from './providers/sync-cron-handler';
 | 
			
		||||
import { CoreCourseLogCronHandler } from './providers/log-cron-handler';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreCourseTagAreaHandler } from './providers/course-tag-area-handler';
 | 
			
		||||
import { CoreCourseModulesTagAreaHandler } from './providers/modules-tag-area-handler';
 | 
			
		||||
 | 
			
		||||
// List of providers (without handlers).
 | 
			
		||||
export const CORE_COURSE_PROVIDERS: any[] = [
 | 
			
		||||
@ -68,15 +71,20 @@ export const CORE_COURSE_PROVIDERS: any[] = [
 | 
			
		||||
        CoreCourseFormatDefaultHandler,
 | 
			
		||||
        CoreCourseModuleDefaultHandler,
 | 
			
		||||
        CoreCourseSyncCronHandler,
 | 
			
		||||
        CoreCourseLogCronHandler
 | 
			
		||||
        CoreCourseLogCronHandler,
 | 
			
		||||
        CoreCourseTagAreaHandler,
 | 
			
		||||
        CoreCourseModulesTagAreaHandler
 | 
			
		||||
    ],
 | 
			
		||||
    exports: []
 | 
			
		||||
})
 | 
			
		||||
export class CoreCourseModule {
 | 
			
		||||
    constructor(cronDelegate: CoreCronDelegate, syncHandler: CoreCourseSyncCronHandler, logHandler: CoreCourseLogCronHandler,
 | 
			
		||||
        platform: Platform, eventsProvider: CoreEventsProvider) {
 | 
			
		||||
                platform: Platform, eventsProvider: CoreEventsProvider, tagAreaDelegate: CoreTagAreaDelegate,
 | 
			
		||||
                courseTagAreaHandler: CoreCourseTagAreaHandler, modulesTagAreaHandler: CoreCourseModulesTagAreaHandler) {
 | 
			
		||||
        cronDelegate.register(syncHandler);
 | 
			
		||||
        cronDelegate.register(logHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(courseTagAreaHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(modulesTagAreaHandler);
 | 
			
		||||
 | 
			
		||||
        platform.resume.subscribe(() => {
 | 
			
		||||
            // Log the app is open to keep user in online status.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										74
									
								
								src/core/course/providers/course-tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/core/course/providers/course-tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreCourseTagAreaComponent } from '../components/tag-area/tag-area';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreCourseTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'CoreCourseTagAreaHandler';
 | 
			
		||||
    type = 'core/course';
 | 
			
		||||
 | 
			
		||||
    constructor(private domUtils: CoreDomUtilsProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        const items = [];
 | 
			
		||||
        const element = this.domUtils.convertToElement(content);
 | 
			
		||||
 | 
			
		||||
        Array.from(element.querySelectorAll('div.coursebox')).forEach((coursebox) => {
 | 
			
		||||
            const courseId = parseInt(coursebox.getAttribute('data-courseid'), 10);
 | 
			
		||||
            const courseLink = coursebox.querySelector('.coursename > a');
 | 
			
		||||
            const categoryLink = coursebox.querySelector('.coursecat > a');
 | 
			
		||||
 | 
			
		||||
            if (courseId > 0 && courseLink) {
 | 
			
		||||
                items.push({
 | 
			
		||||
                    courseId,
 | 
			
		||||
                    courseName: courseLink.innerHTML,
 | 
			
		||||
                    categoryName: categoryLink ? categoryLink.innerHTML : null
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return items;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreCourseTagAreaComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								src/core/course/providers/modules-tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/core/course/providers/modules-tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreTagHelperProvider } from '@core/tag/providers/helper';
 | 
			
		||||
import { CoreTagFeedComponent } from '@core/tag/components/feed/feed';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreCourseModulesTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'CoreCourseModulesTagAreaHandler';
 | 
			
		||||
    type = 'core/course_modules';
 | 
			
		||||
 | 
			
		||||
    constructor(protected tagHelper: CoreTagHelperProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        return this.tagHelper.parseFeedContent(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								src/core/tag/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/tag/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
// (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 { IonicModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreTagFeedComponent } from './feed/feed';
 | 
			
		||||
import { CoreTagListComponent } from './list/list';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreTagFeedComponent,
 | 
			
		||||
        CoreTagListComponent
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        CoreTagFeedComponent,
 | 
			
		||||
        CoreTagListComponent
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        CoreTagFeedComponent
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagComponentsModule {}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/core/tag/components/feed/core-tag-feed.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/core/tag/components/feed/core-tag-feed.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
<a ion-item text-wrap *ngFor="let item of items" [href]="item.url" core-link [capture]="true">
 | 
			
		||||
    <ion-avatar item-start *ngIf="item.avatarUrl">
 | 
			
		||||
        <img [src]="item.avatarUrl" core-external-content alt="" role="presentation" onError="this.src='assets/img/user-avatar.png'">
 | 
			
		||||
    </ion-avatar>
 | 
			
		||||
    <img item-start *ngIf="item.iconUrl" [src]="item.iconUrl" core-external-content alt="" role="presentation" class="core-module-icon">
 | 
			
		||||
    <h2>{{ item.heading }}</h2>
 | 
			
		||||
    <p *ngFor="let text of item.details">{{ text }}</p>
 | 
			
		||||
</a>
 | 
			
		||||
							
								
								
									
										26
									
								
								src/core/tag/components/feed/feed.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/core/tag/components/feed/feed.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component to render a tag area that uses the "core_tag/tagfeed" web template.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'core-tag-feed',
 | 
			
		||||
    templateUrl: 'core-tag-feed.html'
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagFeedComponent {
 | 
			
		||||
    @Input() items: any[]; // Area items to render.
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								src/core/tag/components/list/core-tag-list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/core/tag/components/list/core-tag-list.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
<ng-container *ngFor="let tag of tags">
 | 
			
		||||
    <ion-badge (click)="openTag(tag)" class="core-tag-list-tag">{{ tag.rawname }}</ion-badge>
 | 
			
		||||
</ng-container>
 | 
			
		||||
							
								
								
									
										7
									
								
								src/core/tag/components/list/list.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/core/tag/components/list/list.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
ion-app.app-root core-tag-list {
 | 
			
		||||
    line-height: 1.6;
 | 
			
		||||
 | 
			
		||||
    ion-badge {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/core/tag/components/list/list.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/core/tag/components/list/list.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
// (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, Optional } from '@angular/core';
 | 
			
		||||
import { NavController } from 'ionic-angular';
 | 
			
		||||
import { CoreTagItem } from '@core/tag/providers/tag';
 | 
			
		||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays the list of tags of an item.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'core-tag-list',
 | 
			
		||||
    templateUrl: 'core-tag-list.html'
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagListComponent {
 | 
			
		||||
    @Input() tags: CoreTagItem[];
 | 
			
		||||
 | 
			
		||||
    constructor(private navCtrl: NavController,  @Optional() private svComponent: CoreSplitViewComponent) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Go to tag index page.
 | 
			
		||||
     */
 | 
			
		||||
    openTag(tag: CoreTagItem): void {
 | 
			
		||||
        const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
 | 
			
		||||
        const params = {
 | 
			
		||||
            tagId: tag.id,
 | 
			
		||||
            tagName: tag.rawname,
 | 
			
		||||
            collectionId: tag.tagcollid,
 | 
			
		||||
            fromContextId: tag.taginstancecontextid
 | 
			
		||||
        };
 | 
			
		||||
        navCtrl.push('CoreTagIndexPage', params);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/core/tag/lang/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/core/tag/lang/en.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
    "defautltagcoll": "Default collection",
 | 
			
		||||
    "errorareanotsupported": "This tag area is not supported by the app.",
 | 
			
		||||
    "inalltagcoll": "Everywhere",
 | 
			
		||||
    "itemstaggedwith": "{{$a.tagarea}} tagged with \"{{$a.tag}}\"",
 | 
			
		||||
    "notagsfound": "No tags matching \"{{$a}}\" found",
 | 
			
		||||
    "searchtags": "Search tags",
 | 
			
		||||
    "showingfirsttags": "Showing {{$a}} most popular tags",
 | 
			
		||||
    "tag": "Tag",
 | 
			
		||||
    "tagarea_course": "Courses",
 | 
			
		||||
    "tagarea_course_modules": "Activities and resources",
 | 
			
		||||
    "tagarea_post": "Blog posts",
 | 
			
		||||
    "tagarea_user": "User interests",
 | 
			
		||||
    "tags": "Tags",
 | 
			
		||||
    "warningareasnotsupported": "Some of the tag areas are not displayed because they are not supported by the app."
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/core/tag/pages/index-area/index-area.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/core/tag/pages/index-area/index-area.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-navbar core-back-button>
 | 
			
		||||
        <ion-title>{{ 'core.tag.itemstaggedwith' | translate: { $a: {tagarea: areaNameKey | translate, tag: tagName} } }}</ion-title>
 | 
			
		||||
    </ion-navbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher [enabled]="loaded" (ionRefresh)="refreshData($event)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
    <core-loading [hideUntil]="loaded">
 | 
			
		||||
        <ng-container *ngIf="loaded">
 | 
			
		||||
            <core-dynamic-component [component]="areaComponent" [data]="{items: items}"></core-dynamic-component>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
        <core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError"></core-infinite-loading>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/core/tag/pages/index-area/index-area.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/tag/pages/index-area/index-area.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// (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 { IonicPageModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreTagIndexAreaPage } from './index-area';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreTagIndexAreaPage
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        IonicPageModule.forChild(CoreTagIndexAreaPage),
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagIndexAreaPageModule {}
 | 
			
		||||
							
								
								
									
										150
									
								
								src/core/tag/pages/index-area/index-area.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/core/tag/pages/index-area/index-area.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
			
		||||
// (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, Injector } from '@angular/core';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { IonicPage, NavParams } from 'ionic-angular';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays the tag index area.
 | 
			
		||||
 */
 | 
			
		||||
@IonicPage({ segment: 'core-tag-index-area' })
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-core-tag-index-area',
 | 
			
		||||
    templateUrl: 'index-area.html',
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagIndexAreaPage {
 | 
			
		||||
    tagId: number;
 | 
			
		||||
    tagName: string;
 | 
			
		||||
    collectionId: number;
 | 
			
		||||
    areaId: number;
 | 
			
		||||
    fromContextId: number;
 | 
			
		||||
    contextId: number;
 | 
			
		||||
    recursive: boolean;
 | 
			
		||||
    areaNameKey: string;
 | 
			
		||||
    loaded = false;
 | 
			
		||||
    componentName: string;
 | 
			
		||||
    itemType: string;
 | 
			
		||||
    items = [];
 | 
			
		||||
    nextPage = 0;
 | 
			
		||||
    canLoadMore = false;
 | 
			
		||||
    areaComponent: any;
 | 
			
		||||
    loadMoreError = false;
 | 
			
		||||
 | 
			
		||||
    constructor(navParams: NavParams, private injector: Injector, private translate: TranslateService,
 | 
			
		||||
            private tagProvider: CoreTagProvider, private domUtils: CoreDomUtilsProvider,
 | 
			
		||||
            private tagAreaDelegate: CoreTagAreaDelegate) {
 | 
			
		||||
        this.tagId = navParams.get('tagId');
 | 
			
		||||
        this.tagName = navParams.get('tagName');
 | 
			
		||||
        this.collectionId = navParams.get('collectionId');
 | 
			
		||||
        this.areaId = navParams.get('areaId');
 | 
			
		||||
        this.fromContextId = navParams.get('fromContextId');
 | 
			
		||||
        this.contextId = navParams.get('contextId');
 | 
			
		||||
        this.recursive = navParams.get('recursive');
 | 
			
		||||
        this.areaNameKey = navParams.get('areaNameKey');
 | 
			
		||||
 | 
			
		||||
        // Pass the the following parameters to avoid fetching the first page.
 | 
			
		||||
        this.componentName = navParams.get('componentName');
 | 
			
		||||
        this.itemType = navParams.get('itemType');
 | 
			
		||||
        this.items = navParams.get('items') || [];
 | 
			
		||||
        this.nextPage = navParams.get('nextPage') || 0;
 | 
			
		||||
        this.canLoadMore = !!navParams.get('canLoadMore');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * View loaded.
 | 
			
		||||
     */
 | 
			
		||||
    ionViewDidLoad(): void {
 | 
			
		||||
        let promise: Promise<any>;
 | 
			
		||||
        if (!this.componentName || !this.itemType || !this.items.length || this.nextPage == 0) {
 | 
			
		||||
            promise = this.fetchData(true);
 | 
			
		||||
        } else {
 | 
			
		||||
            promise = Promise.resolve();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        promise.then(() => {
 | 
			
		||||
            return this.tagAreaDelegate.getComponent(this.componentName, this.itemType, this.injector).then((component) => {
 | 
			
		||||
                this.areaComponent = component;
 | 
			
		||||
            });
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch next page of the tag index area.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {boolean} [refresh=false] Whether to refresh the data or fetch a new page.
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    fetchData(refresh: boolean = false): Promise<any> {
 | 
			
		||||
        this.loadMoreError = false;
 | 
			
		||||
        const page = refresh ? 0 : this.nextPage;
 | 
			
		||||
 | 
			
		||||
        return this.tagProvider.getTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId,
 | 
			
		||||
                this.contextId, this.recursive, page).then((areas) => {
 | 
			
		||||
            const area = areas[0];
 | 
			
		||||
 | 
			
		||||
            return this.tagAreaDelegate.parseContent(area.component, area.itemtype, area.content).then((items) => {
 | 
			
		||||
                if (!items || !items.length) {
 | 
			
		||||
                    // Tag area not supported.
 | 
			
		||||
                    return Promise.reject(this.translate.instant('core.tag.errorareanotsupported'));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (page == 0) {
 | 
			
		||||
                    this.items = items;
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.items.push(...items);
 | 
			
		||||
                }
 | 
			
		||||
                this.componentName = area.component;
 | 
			
		||||
                this.itemType = area.itemtype;
 | 
			
		||||
                this.areaNameKey = this.tagAreaDelegate.getDisplayNameKey(area.component, area.itemtype);
 | 
			
		||||
                this.canLoadMore = !!area.nextpageurl;
 | 
			
		||||
                this.nextPage = page + 1;
 | 
			
		||||
            });
 | 
			
		||||
        }).catch((error) => {
 | 
			
		||||
            this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | 
			
		||||
            this.domUtils.showErrorModalDefault(error, 'Error loading tag index');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load more items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} infiniteComplete Infinite scroll complete function.
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    loadMore(infiniteComplete: any): Promise<any> {
 | 
			
		||||
        return this.fetchData().finally(() => {
 | 
			
		||||
            infiniteComplete();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} refresher Refresher.
 | 
			
		||||
     */
 | 
			
		||||
    refreshData(refresher: any): void {
 | 
			
		||||
        this.tagProvider.invalidateTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId,
 | 
			
		||||
                this.contextId, this.recursive).finally(() => {
 | 
			
		||||
            this.fetchData(true).finally(() => {
 | 
			
		||||
                refresher.complete();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/core/tag/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/core/tag/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-navbar core-back-button>
 | 
			
		||||
        <ion-title>{{ 'core.tag.tag' | translate }}: {{ tagName }}</ion-title>
 | 
			
		||||
    </ion-navbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<core-split-view>
 | 
			
		||||
    <ion-content>
 | 
			
		||||
        <ion-refresher [enabled]="loaded" (ionRefresh)="refreshData($event)">
 | 
			
		||||
            <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
        </ion-refresher>
 | 
			
		||||
        <core-loading [hideUntil]="loaded">
 | 
			
		||||
            <ion-list>
 | 
			
		||||
                <ion-item text-wrap *ngIf="hasUnsupportedAreas" class="core-warning-item">
 | 
			
		||||
                    <ion-icon item-start name="warning" color="warning"></ion-icon>
 | 
			
		||||
                    {{ 'core.tag.warningareasnotsupported' | translate }}
 | 
			
		||||
                </ion-item>
 | 
			
		||||
                <a ion-item text-wrap *ngFor="let area of areas" [title]="area.nameKey | translate" (click)="openArea(area)" [class.core-split-item-selected]="area.id == selectedAreaId">
 | 
			
		||||
                    <h2>{{ area.nameKey | translate }}</h2>
 | 
			
		||||
                    <ion-badge item-end *ngIf="area.badge">{{ area.badge }}</ion-badge>
 | 
			
		||||
                </a>
 | 
			
		||||
            </ion-list>
 | 
			
		||||
        </core-loading>
 | 
			
		||||
    </ion-content>
 | 
			
		||||
</core-split-view>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/core/tag/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/tag/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// (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 { IonicPageModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreTagIndexPage } from './index';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreTagIndexPage
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        IonicPageModule.forChild(CoreTagIndexPage),
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagIndexPageModule {}
 | 
			
		||||
							
								
								
									
										154
									
								
								src/core/tag/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/core/tag/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,154 @@
 | 
			
		||||
// (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, ViewChild } from '@angular/core';
 | 
			
		||||
import { IonicPage, NavParams } from 'ionic-angular';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
 | 
			
		||||
import { CoreTagProvider } from '@core/tag/providers/tag';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays the tag index.
 | 
			
		||||
 */
 | 
			
		||||
@IonicPage({ segment: 'core-tag-index' })
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-core-tag-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagIndexPage {
 | 
			
		||||
    @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
 | 
			
		||||
 | 
			
		||||
    tagId: number;
 | 
			
		||||
    tagName: string;
 | 
			
		||||
    collectionId: number;
 | 
			
		||||
    areaId: number;
 | 
			
		||||
    fromContextId: number;
 | 
			
		||||
    contextId: number;
 | 
			
		||||
    recursive: boolean;
 | 
			
		||||
    loaded = false;
 | 
			
		||||
    areas: Array<{
 | 
			
		||||
        id: number,
 | 
			
		||||
        componentName: string,
 | 
			
		||||
        itemType: string,
 | 
			
		||||
        nameKey: string,
 | 
			
		||||
        items: any[],
 | 
			
		||||
        canLoadMore: boolean,
 | 
			
		||||
        badge: string
 | 
			
		||||
    }>;
 | 
			
		||||
    selectedAreaId: number;
 | 
			
		||||
    hasUnsupportedAreas = false;
 | 
			
		||||
 | 
			
		||||
    constructor(navParams: NavParams, private tagProvider: CoreTagProvider, private domUtils: CoreDomUtilsProvider,
 | 
			
		||||
            private tagAreaDelegate: CoreTagAreaDelegate) {
 | 
			
		||||
        this.tagId = navParams.get('tagId') || 0;
 | 
			
		||||
        this.tagName = navParams.get('tagName') || '';
 | 
			
		||||
        this.collectionId = navParams.get('collectionId');
 | 
			
		||||
        this.areaId = navParams.get('areaId') || 0;
 | 
			
		||||
        this.fromContextId = navParams.get('fromContextId') || 0;
 | 
			
		||||
        this.contextId = navParams.get('contextId') || 0;
 | 
			
		||||
        this.recursive = navParams.get('recursive') || true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * View loaded.
 | 
			
		||||
     */
 | 
			
		||||
    ionViewDidLoad(): void {
 | 
			
		||||
        this.fetchData().then(() => {
 | 
			
		||||
            if (this.splitviewCtrl.isOn() && this.areas && this.areas.length > 0) {
 | 
			
		||||
                const area = this.areas.find((area) => area.id == this.areaId);
 | 
			
		||||
                this.openArea(area || this.areas[0]);
 | 
			
		||||
            }
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch first page of tag index per area.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    fetchData(): Promise<any> {
 | 
			
		||||
        return this.tagProvider.getTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId,
 | 
			
		||||
                this.contextId, this.recursive, 0).then((areas) => {
 | 
			
		||||
            this.areas = [];
 | 
			
		||||
            this.hasUnsupportedAreas = false;
 | 
			
		||||
 | 
			
		||||
            return Promise.all(areas.map((area) => {
 | 
			
		||||
                return this.tagAreaDelegate.parseContent(area.component, area.itemtype, area.content).then((items) => {
 | 
			
		||||
                    if (!items || !items.length) {
 | 
			
		||||
                        // Tag area not supported, skip.
 | 
			
		||||
                        this.hasUnsupportedAreas = true;
 | 
			
		||||
 | 
			
		||||
                        return null;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return {
 | 
			
		||||
                        id: area.ta,
 | 
			
		||||
                        componentName: area.component,
 | 
			
		||||
                        itemType: area.itemtype,
 | 
			
		||||
                        nameKey: this.tagAreaDelegate.getDisplayNameKey(area.component, area.itemtype),
 | 
			
		||||
                        items,
 | 
			
		||||
                        canLoadMore: !!area.nextpageurl,
 | 
			
		||||
                        badge: items && items.length ? items.length + (area.nextpageurl ? '+' : '') : '',
 | 
			
		||||
                    };
 | 
			
		||||
                });
 | 
			
		||||
            })).then((areas) => {
 | 
			
		||||
                this.areas = areas.filter((area) => area != null);
 | 
			
		||||
            });
 | 
			
		||||
        }).catch((error) => {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(error, 'Error loading tag index');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} refresher Refresher.
 | 
			
		||||
     */
 | 
			
		||||
    refreshData(refresher: any): void {
 | 
			
		||||
        this.tagProvider.invalidateTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId,
 | 
			
		||||
                this.contextId, this.recursive).finally(() => {
 | 
			
		||||
            this.fetchData().finally(() => {
 | 
			
		||||
                refresher.complete();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Navigate to an index area.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} area Area.
 | 
			
		||||
     */
 | 
			
		||||
    openArea(area: any): void {
 | 
			
		||||
        this.selectedAreaId = area.id;
 | 
			
		||||
        const params = {
 | 
			
		||||
            tagId: this.tagId,
 | 
			
		||||
            tagName: this.tagName,
 | 
			
		||||
            collectionId: this.collectionId,
 | 
			
		||||
            areaId: area.id,
 | 
			
		||||
            fromContextId: this.fromContextId,
 | 
			
		||||
            contextId: this.contextId,
 | 
			
		||||
            recursive: this.recursive,
 | 
			
		||||
            areaNameKey: area.nameKey,
 | 
			
		||||
            componentName: area.component,
 | 
			
		||||
            itemType: area.itemType,
 | 
			
		||||
            items: area.items.slice(),
 | 
			
		||||
            canLoadMore: area.canLoadMore,
 | 
			
		||||
            nextPage: 1
 | 
			
		||||
        };
 | 
			
		||||
        this.splitviewCtrl.push('CoreTagIndexAreaPage', params);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/core/tag/pages/search/search.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/core/tag/pages/search/search.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-navbar core-back-button>
 | 
			
		||||
        <ion-title>{{ 'core.tag.searchtags' | translate }}</ion-title>
 | 
			
		||||
    </ion-navbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher [enabled]="loaded" (ionRefresh)="refreshData($event)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
    <ion-grid>
 | 
			
		||||
        <ion-row>
 | 
			
		||||
            <ion-col col-12 [attr.col-sm-6]="collections && collections.length > 1 ? '' : null">
 | 
			
		||||
                <core-search-box (onSubmit)="searchTags($event)" (onClear)="searchTags('')" [initialSearch]="query" [disabled]="searching" autocorrect="off" [spellcheck]="false" [autoFocus]="true" [lengthCheck]="0"></core-search-box>
 | 
			
		||||
            </ion-col>
 | 
			
		||||
            <ion-col col-12 col-sm-6 *ngIf="collections && collections.length > 1">
 | 
			
		||||
                <ion-select text-start [(ngModel)]="collectionId" (ngModelChange)="searchTags(query)" [disabled]="searching" interface="popover" class="core-button-select">
 | 
			
		||||
                    <ion-option [value]="0">{{ 'core.tag.inalltagcoll' | translate }}</ion-option>
 | 
			
		||||
                    <ion-option *ngFor="let collection of collections" [value]="collection.id">{{ collection.name }}</ion-option>
 | 
			
		||||
                </ion-select>
 | 
			
		||||
            </ion-col>
 | 
			
		||||
        </ion-row>
 | 
			
		||||
    </ion-grid>
 | 
			
		||||
    <core-loading [hideUntil]="loaded && !searching">
 | 
			
		||||
        <core-empty-box *ngIf="!cloud || !cloud.tags || !cloud.tags.length" icon="pricetags" [message]="'core.tag.notagsfound' | translate: {$a: query}"></core-empty-box>
 | 
			
		||||
 | 
			
		||||
        <ng-container *ngIf="cloud && cloud.tags && cloud.tags.length > 0">
 | 
			
		||||
            <div text-center class="core-tag-cloud">
 | 
			
		||||
                <ion-badge *ngFor="let tag of cloud.tags" (click)="openTag(tag)" text-wrap>
 | 
			
		||||
                   <span [class]="'size' + tag.size" >{{ tag.name }}</span>
 | 
			
		||||
                </ion-badge>
 | 
			
		||||
            </div>
 | 
			
		||||
            <p *ngIf="cloud.tags.length < cloud.totalcount" text-center>
 | 
			
		||||
                {{ 'core.tag.showingfirsttags' | translate: {$a: cloud.tags.length} }}
 | 
			
		||||
            </p>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/core/tag/pages/search/search.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/tag/pages/search/search.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// (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 { IonicPageModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreTagSearchPage } from './search';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreTagSearchPage
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        IonicPageModule.forChild(CoreTagSearchPage),
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagSerchPageModule {}
 | 
			
		||||
							
								
								
									
										95
									
								
								src/core/tag/pages/search/search.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/core/tag/pages/search/search.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
			
		||||
ion-app.app-root page-core-tag-search {
 | 
			
		||||
    core-search-box ion-card {
 | 
			
		||||
        width: 100% !important;
 | 
			
		||||
        margin: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .core-tag-cloud ion-badge {
 | 
			
		||||
        margin: 8px;
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
 | 
			
		||||
        .size20 {
 | 
			
		||||
            font-size: 3.4rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size19 {
 | 
			
		||||
            font-size: 3.3rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size18 {
 | 
			
		||||
            font-size: 3.2rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size17 {
 | 
			
		||||
            font-size: 3.1rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size16 {
 | 
			
		||||
            font-size: 3rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size15 {
 | 
			
		||||
            font-size: 2.9rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size14 {
 | 
			
		||||
            font-size: 2.8rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size13 {
 | 
			
		||||
            font-size: 2.7rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size12 {
 | 
			
		||||
            font-size: 2.6rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size11 {
 | 
			
		||||
            font-size: 2.5rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size10 {
 | 
			
		||||
            font-size: 2.4rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size9 {
 | 
			
		||||
            font-size: 2.3rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size8 {
 | 
			
		||||
            font-size: 2.2rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size7 {
 | 
			
		||||
            font-size: 2.1rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size6 {
 | 
			
		||||
            font-size: 2rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size5 {
 | 
			
		||||
            font-size: 1.9rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size4 {
 | 
			
		||||
            font-size: 1.8rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size3 {
 | 
			
		||||
            font-size: 1.7rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size2 {
 | 
			
		||||
            font-size: 1.6rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size1 {
 | 
			
		||||
            font-size: 1.5rem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .size0 {
 | 
			
		||||
            font-size: 1.4rem;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										135
									
								
								src/core/tag/pages/search/search.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/core/tag/pages/search/search.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,135 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { IonicPage, NavParams, NavController } from 'ionic-angular';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { CoreAppProvider } from '@providers/app';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
			
		||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
			
		||||
import { CoreTagProvider, CoreTagCloud, CoreTagCollection, CoreTagCloudTag } from '@core/tag/providers/tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays most used tags and allows searching.
 | 
			
		||||
 */
 | 
			
		||||
@IonicPage({ segment: 'core-tag-search' })
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-core-tag-search',
 | 
			
		||||
    templateUrl: 'search.html',
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagSearchPage {
 | 
			
		||||
    collectionId: number;
 | 
			
		||||
    query: string;
 | 
			
		||||
    collections: CoreTagCollection[] = [];
 | 
			
		||||
    cloud: CoreTagCloud;
 | 
			
		||||
    loaded = false;
 | 
			
		||||
    searching = false;
 | 
			
		||||
 | 
			
		||||
    constructor(private navCtrl: NavController, navParams: NavParams, private appProvider: CoreAppProvider,
 | 
			
		||||
            private translate: TranslateService, private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider,
 | 
			
		||||
            private textUtils: CoreTextUtilsProvider, private contentLinksHelper: CoreContentLinksHelperProvider,
 | 
			
		||||
            private tagProvider: CoreTagProvider) {
 | 
			
		||||
        this.collectionId = navParams.get('collectionId') || 0;
 | 
			
		||||
        this.query = navParams.get('query') || '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * View loaded.
 | 
			
		||||
     */
 | 
			
		||||
    ionViewDidLoad(): void {
 | 
			
		||||
        this.fetchData().finally(() => {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fetchData(): Promise<any> {
 | 
			
		||||
        return Promise.all([
 | 
			
		||||
            this.fetchCollections(),
 | 
			
		||||
            this.fetchTags()
 | 
			
		||||
        ]).catch((error) => {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(error, 'Error loading tags.');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch tag collections.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    fetchCollections(): Promise<any> {
 | 
			
		||||
        return this.tagProvider.getTagCollections().then((collections) => {
 | 
			
		||||
            collections.forEach((collection) => {
 | 
			
		||||
                if (!collection.name && collection.isdefault) {
 | 
			
		||||
                    collection.name = this.translate.instant('core.tag.defautltagcoll');
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            this.collections = collections;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch tags.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    fetchTags(): Promise<any> {
 | 
			
		||||
        return this.tagProvider.getTagCloud(this.collectionId, undefined, undefined, this.query).then((cloud) => {
 | 
			
		||||
            this.cloud = cloud;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Go to tag index page.
 | 
			
		||||
     */
 | 
			
		||||
    openTag(tag: CoreTagCloudTag): void {
 | 
			
		||||
        const url = this.textUtils.decodeURI(tag.viewurl);
 | 
			
		||||
        this.contentLinksHelper.handleLink(url, undefined, this.navCtrl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} refresher Refresher.
 | 
			
		||||
     */
 | 
			
		||||
    refreshData(refresher: any): void {
 | 
			
		||||
        this.utils.allPromises([
 | 
			
		||||
            this.tagProvider.invalidateTagCollections(),
 | 
			
		||||
            this.tagProvider.invalidateTagCloud(this.collectionId, undefined, undefined, this.query),
 | 
			
		||||
        ]).finally(() => {
 | 
			
		||||
            return this.fetchData().finally(() => {
 | 
			
		||||
                refresher.complete();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search tags.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} query Search query.
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    searchTags(query: string): Promise<any> {
 | 
			
		||||
        this.searching = true;
 | 
			
		||||
        this.query = query;
 | 
			
		||||
        this.appProvider.closeKeyboard();
 | 
			
		||||
 | 
			
		||||
        return this.fetchTags().catch((error) => {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(error, 'Error loading tags.');
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
            this.searching = false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								src/core/tag/providers/area-delegate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/core/tag/providers/area-delegate.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreEventsProvider } from '@providers/events';
 | 
			
		||||
import { CoreLoggerProvider } from '@providers/logger';
 | 
			
		||||
import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface that all tag area handlers must implement.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreTagAreaHandler extends CoreDelegateHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * Component and item type separated by a slash. E.g. 'core/course_modules'.
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     */
 | 
			
		||||
    type: string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]>;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Delegate to register tag area handlers.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreTagAreaDelegate extends CoreDelegate {
 | 
			
		||||
 | 
			
		||||
    protected handlerNameProperty = 'type';
 | 
			
		||||
 | 
			
		||||
    constructor(logger: CoreLoggerProvider, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) {
 | 
			
		||||
        super('CoreTagAreaDelegate', logger, sitesProvider, eventsProvider);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the display name string for this area.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} component Component name.
 | 
			
		||||
     * @param {string} itemType Item type.
 | 
			
		||||
     * @return {string} String key.
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayNameKey(component: string, itemType: string): string {
 | 
			
		||||
        return (component == 'core' ? 'core.tag' : 'addon.' + component) + '.tagarea_' + itemType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} component Component name.
 | 
			
		||||
     * @param {string} itemType Item type.
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {Promise<any[]>} Promise resolved with the area items, or undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(component: string, itemType: string, content: string): Promise<any[]> {
 | 
			
		||||
        const type = component + '/' + itemType;
 | 
			
		||||
 | 
			
		||||
        return Promise.resolve(this.executeFunctionOnEnabled(type, 'parseContent', [content]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display an area item.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} component Component name.
 | 
			
		||||
     * @param {string} itemType Item type.
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(component: string, itemType: string, injector: Injector): Promise<any> {
 | 
			
		||||
        const type = component + '/' + itemType;
 | 
			
		||||
 | 
			
		||||
        return Promise.resolve(this.executeFunctionOnEnabled(type, 'getComponent', [injector]));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								src/core/tag/providers/helper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/core/tag/providers/helper.ts
									
									
									
									
									
										Normal 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 { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service with helper functions for tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreTagHelperProvider {
 | 
			
		||||
 | 
			
		||||
    constructor(protected domUtils: CoreDomUtilsProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of the "core_tag/tagfeed" web template and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]} Area items.
 | 
			
		||||
     */
 | 
			
		||||
    parseFeedContent(content: string): any[] {
 | 
			
		||||
        const items = [];
 | 
			
		||||
        const element = this.domUtils.convertToElement(content);
 | 
			
		||||
 | 
			
		||||
        Array.from(element.querySelectorAll('ul.tag_feed > li.media')).forEach((itemElement) => {
 | 
			
		||||
            const item: any = { details: [] };
 | 
			
		||||
 | 
			
		||||
            Array.from(itemElement.querySelectorAll('div.media-body > div')).forEach((div: HTMLElement) => {
 | 
			
		||||
                if (div.classList.contains('media-heading')) {
 | 
			
		||||
                    item.heading = div.innerText.trim();
 | 
			
		||||
                    const link = div.querySelector('a');
 | 
			
		||||
                    if (link) {
 | 
			
		||||
                        item.url = link.getAttribute('href');
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Separate details by lines.
 | 
			
		||||
                    const lines = [''];
 | 
			
		||||
                    Array.from(div.childNodes).forEach((childNode: Node) => {
 | 
			
		||||
                        if (childNode.nodeType == Node.TEXT_NODE) {
 | 
			
		||||
                            lines[lines.length - 1] += childNode.textContent;
 | 
			
		||||
                        } else if (childNode.nodeType == Node.ELEMENT_NODE) {
 | 
			
		||||
                            const childElement = childNode as HTMLElement;
 | 
			
		||||
                            if (childElement.tagName == 'BR') {
 | 
			
		||||
                                lines.push('');
 | 
			
		||||
                            } else {
 | 
			
		||||
                                lines[lines.length - 1] += childElement.innerText;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    item.details.push(...lines.map((line) => line.trim()).filter((line) => line != ''));
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const image = itemElement.querySelector('div.itemimage img');
 | 
			
		||||
            if (image) {
 | 
			
		||||
                if (image.classList.contains('userpicture')) {
 | 
			
		||||
                    item.avatarUrl = image.getAttribute('src');
 | 
			
		||||
                } else {
 | 
			
		||||
                    item.iconUrl = image.getAttribute('src');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (item.heading && item.url) {
 | 
			
		||||
                items.push(item);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return items;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								src/core/tag/providers/index-link-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/core/tag/providers/index-link-handler.ts
									
									
									
									
									
										Normal 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 { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
 | 
			
		||||
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
			
		||||
import { CoreTagProvider } from './tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to tag index.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreTagIndexLinkHandler extends CoreContentLinksHandlerBase {
 | 
			
		||||
    name = 'CoreTagIndexLinkHandler';
 | 
			
		||||
    pattern = /\/tag\/index\.php/;
 | 
			
		||||
 | 
			
		||||
    constructor(private tagProvider: CoreTagProvider, private linkHelper: CoreContentLinksHelperProvider) {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the list of actions for a link (url).
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string[]} siteIds List of sites the URL belongs to.
 | 
			
		||||
     * @param {string} url The URL to treat.
 | 
			
		||||
     * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
 | 
			
		||||
     * @param {number} [courseId] Course ID related to the URL. Optional but recommended.
 | 
			
		||||
     * @param {any} [data] Extra data to handle the URL.
 | 
			
		||||
     * @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
 | 
			
		||||
     */
 | 
			
		||||
    getActions(siteIds: string[], url: string, params: any, courseId?: number, data?: any):
 | 
			
		||||
            CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
 | 
			
		||||
        return [{
 | 
			
		||||
            action: (siteId, navCtrl?): void => {
 | 
			
		||||
                const pageParams = {
 | 
			
		||||
                    tagId: parseInt(params.id, 10) || 0,
 | 
			
		||||
                    tagName: params.tag || '',
 | 
			
		||||
                    collectionId: parseInt(params.tc, 10) || 0,
 | 
			
		||||
                    areaId: parseInt(params.ta, 10) || 0,
 | 
			
		||||
                    fromContextId: parseInt(params.from, 10) || 0,
 | 
			
		||||
                    contextId: parseInt(params.ctx, 10) || 0,
 | 
			
		||||
                    recursive: parseInt(params.rec, 10) || 1
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (!pageParams.tagId && (!pageParams.tagName || !pageParams.collectionId)) {
 | 
			
		||||
                    this.linkHelper.goInSite(navCtrl, 'CoreTagSearchPage', {}, siteId);
 | 
			
		||||
                } else if (pageParams.areaId) {
 | 
			
		||||
                    this.linkHelper.goInSite(navCtrl, 'CoreTagIndexAreaPage', pageParams, siteId);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.linkHelper.goInSite(navCtrl, 'CoreTagIndexPage', pageParams, siteId);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled for a certain site (site + user) and a URL.
 | 
			
		||||
     * If not defined, defaults to true.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} siteId The site ID.
 | 
			
		||||
     * @param {string} url The URL to treat.
 | 
			
		||||
     * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
 | 
			
		||||
     * @param {number} [courseId] Course ID related to the URL. Optional but recommended.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
 | 
			
		||||
        return this.tagProvider.areTagsAvailable(siteId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								src/core/tag/providers/mainmenu-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/core/tag/providers/mainmenu-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreTagProvider } from './tag';
 | 
			
		||||
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
 | 
			
		||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to inject an option into main menu.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreTagMainMenuHandler implements CoreMainMenuHandler {
 | 
			
		||||
    name = 'CoreTag';
 | 
			
		||||
    priority = 300;
 | 
			
		||||
 | 
			
		||||
    constructor(private tagProvider: CoreTagProvider, private utils: CoreUtilsProvider) { }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled on a site level.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {boolean | Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return this.tagProvider.areTagsAvailable().then((available) => {
 | 
			
		||||
            if (!available) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // The only way to check whether tags are enabled on web is to perform a WS call.
 | 
			
		||||
            return this.utils.promiseWorks(this.tagProvider.getTagCollections());
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the data needed to render the handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {CoreMainMenuHandlerData} Data needed to render the handler.
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(): CoreMainMenuHandlerData {
 | 
			
		||||
        return {
 | 
			
		||||
            icon: 'pricetags',
 | 
			
		||||
            title: 'core.tag.tags',
 | 
			
		||||
            page: 'CoreTagSearchPage',
 | 
			
		||||
            class: 'core-tag-search-handler'
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								src/core/tag/providers/search-link-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/core/tag/providers/search-link-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
 | 
			
		||||
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
			
		||||
import { CoreTagProvider } from './tag';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to tag search.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreTagSearchLinkHandler extends CoreContentLinksHandlerBase {
 | 
			
		||||
    name = 'CoreTagSearchLinkHandler';
 | 
			
		||||
    pattern = /\/tag\/search\.php/;
 | 
			
		||||
 | 
			
		||||
    constructor(private tagProvider: CoreTagProvider, private linkHelper: CoreContentLinksHelperProvider) {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the list of actions for a link (url).
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string[]} siteIds List of sites the URL belongs to.
 | 
			
		||||
     * @param {string} url The URL to treat.
 | 
			
		||||
     * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
 | 
			
		||||
     * @param {number} [courseId] Course ID related to the URL. Optional but recommended.
 | 
			
		||||
     * @param {any} [data] Extra data to handle the URL.
 | 
			
		||||
     * @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
 | 
			
		||||
     */
 | 
			
		||||
    getActions(siteIds: string[], url: string, params: any, courseId?: number, data?: any):
 | 
			
		||||
            CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
 | 
			
		||||
        return [{
 | 
			
		||||
            action: (siteId, navCtrl?): void => {
 | 
			
		||||
                const pageParams = {
 | 
			
		||||
                    collectionId: parseInt(params.tc, 10) || 0,
 | 
			
		||||
                    query: params.query || '',
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                this.linkHelper.goInSite(navCtrl, 'CoreTagSearchPage', pageParams, siteId);
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled for a certain site (site + user) and a URL.
 | 
			
		||||
     * If not defined, defaults to true.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} siteId The site ID.
 | 
			
		||||
     * @param {string} url The URL to treat.
 | 
			
		||||
     * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
 | 
			
		||||
     * @param {number} [courseId] Course ID related to the URL. Optional but recommended.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
 | 
			
		||||
        return this.tagProvider.areTagsAvailable(siteId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										345
									
								
								src/core/tag/providers/tag.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								src/core/tag/providers/tag.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,345 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Structure of a tag cloud returned by WS.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreTagCloud {
 | 
			
		||||
    tags: CoreTagCloudTag[];
 | 
			
		||||
    tagscount: number;
 | 
			
		||||
    totalcount: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Structure of a tag cloud tag returned by WS.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreTagCloudTag {
 | 
			
		||||
    name: string;
 | 
			
		||||
    viewurl: string;
 | 
			
		||||
    flag: boolean;
 | 
			
		||||
    isstandard: boolean;
 | 
			
		||||
    count: number;
 | 
			
		||||
    size: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Structure of a tag collection returned by WS.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreTagCollection {
 | 
			
		||||
    id: number;
 | 
			
		||||
    name: string;
 | 
			
		||||
    isdefault: boolean;
 | 
			
		||||
    component: string;
 | 
			
		||||
    sortoder: number;
 | 
			
		||||
    searchable: boolean;
 | 
			
		||||
    customurl: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Structure of a tag index returned by WS.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreTagIndex {
 | 
			
		||||
    tagid: number;
 | 
			
		||||
    ta: number;
 | 
			
		||||
    component: string;
 | 
			
		||||
    itemtype: string;
 | 
			
		||||
    nextpageurl: string;
 | 
			
		||||
    prevpageurl: string;
 | 
			
		||||
    exclusiveurl: string;
 | 
			
		||||
    exclusivetext: string;
 | 
			
		||||
    title: string;
 | 
			
		||||
    content: string;
 | 
			
		||||
    hascontent: number;
 | 
			
		||||
    anchor: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Structure of a tag item returned by WS.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreTagItem {
 | 
			
		||||
    id: number;
 | 
			
		||||
    name: string;
 | 
			
		||||
    rawname: string;
 | 
			
		||||
    isstandard: boolean;
 | 
			
		||||
    tagcollid: number;
 | 
			
		||||
    taginstanceid: number;
 | 
			
		||||
    taginstancecontextid: number;
 | 
			
		||||
    itemid: number;
 | 
			
		||||
    ordering: number;
 | 
			
		||||
    flag: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service to handle tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreTagProvider {
 | 
			
		||||
 | 
			
		||||
    static SEARCH_LIMIT = 150;
 | 
			
		||||
 | 
			
		||||
    protected ROOT_CACHE_KEY = 'CoreTag:';
 | 
			
		||||
 | 
			
		||||
    constructor(private sitesProvider: CoreSitesProvider, private translate: TranslateService) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether tags are available in a certain site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} [siteId] Site Id. If not defined, use current site.
 | 
			
		||||
     * @return {Promise<boolean>} Promise resolved with true if available, resolved with false otherwise.
 | 
			
		||||
     * @since 3.7
 | 
			
		||||
     */
 | 
			
		||||
    areTagsAvailable(siteId?: string): Promise<boolean> {
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            return this.areTagsAvailableInSite(site);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether tags are available in a certain site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {CoreSite} [site] Site. If not defined, use current site.
 | 
			
		||||
     * @return {boolean} True if available.
 | 
			
		||||
     */
 | 
			
		||||
    areTagsAvailableInSite(site?: CoreSite): boolean {
 | 
			
		||||
        site = site || this.sitesProvider.getCurrentSite();
 | 
			
		||||
 | 
			
		||||
        return site.wsAvailable('core_tag_get_tagindex_per_area') &&
 | 
			
		||||
                site.wsAvailable('core_tag_get_tag_cloud') &&
 | 
			
		||||
                site.wsAvailable('core_tag_get_tag_collections') &&
 | 
			
		||||
                !site.isFeatureDisabled('NoDelegate_CoreTag');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch the tag cloud.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} [collectionId=0] Tag collection ID.
 | 
			
		||||
     * @param {boolean} [isStandard=false] Whether to return only standard tags.
 | 
			
		||||
     * @param {string} [sort='name'] Sort order for display (id, name, rawname, count, flag, isstandard, tagcollid).
 | 
			
		||||
     * @param {string} [search=''] Search string.
 | 
			
		||||
     * @param {number} [fromContextId=0] Context ID where this tag cloud is displayed.
 | 
			
		||||
     * @param {number} [contextId=0] Only retrieve tag instances in this context.
 | 
			
		||||
     * @param {boolean} [recursive=true] Retrieve tag instances in the context and its children.
 | 
			
		||||
     * @param {number} [limit] Maximum number of tags to retrieve. Defaults to SEARCH_LIMIT.
 | 
			
		||||
     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
			
		||||
     * @return {Promise<CoreTagCloud>} Promise resolved with the tag cloud.
 | 
			
		||||
     * @since 3.7
 | 
			
		||||
     */
 | 
			
		||||
    getTagCloud(collectionId: number = 0, isStandard: boolean = false, sort: string = 'name', search: string = '',
 | 
			
		||||
            fromContextId: number = 0, contextId: number = 0, recursive: boolean = true, limit?: number, siteId?: string):
 | 
			
		||||
            Promise<CoreTagCloud> {
 | 
			
		||||
        limit = limit || CoreTagProvider.SEARCH_LIMIT;
 | 
			
		||||
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            const params = {
 | 
			
		||||
                tagcollid: collectionId,
 | 
			
		||||
                isstandard: isStandard,
 | 
			
		||||
                limit: limit,
 | 
			
		||||
                sort: sort,
 | 
			
		||||
                search: search,
 | 
			
		||||
                fromctx: fromContextId,
 | 
			
		||||
                ctx: contextId,
 | 
			
		||||
                rec: recursive
 | 
			
		||||
            };
 | 
			
		||||
            const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
                updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
 | 
			
		||||
                cacheKey: this.getTagCloudKey(collectionId, isStandard, sort, search, fromContextId, contextId, recursive),
 | 
			
		||||
                getFromCache: search != '' // Try to get updated data when searching.
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return site.read('core_tag_get_tag_cloud', params, preSets);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch the tag collections.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
			
		||||
     * @return {Promise<CoreTagCollection[]>} Promise resolved with the tag collections.
 | 
			
		||||
     * @since 3.7
 | 
			
		||||
     */
 | 
			
		||||
    getTagCollections(siteId?: string): Promise<CoreTagCollection[]> {
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
                updateFrequency: CoreSite.FREQUENCY_RARELY,
 | 
			
		||||
                cacheKey: this.getTagCollectionsKey()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return site.read('core_tag_get_tag_collections', null, preSets).then((response) => {
 | 
			
		||||
                if (!response || !response.collections) {
 | 
			
		||||
                    return Promise.reject(null);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return response.collections;
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch the tag index.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} [id=0] Tag ID.
 | 
			
		||||
     * @param {string} [name=''] Tag name.
 | 
			
		||||
     * @param {number} [collectionId=0] Tag collection ID.
 | 
			
		||||
     * @param {number} [areaId=0] Tag area ID.
 | 
			
		||||
     * @param {number} [fromContextId=0] Context ID where the link was displayed.
 | 
			
		||||
     * @param {number} [contextId=0] Context ID where to search for items.
 | 
			
		||||
     * @param {boolean} [recursive=true] Search in the context and its children.
 | 
			
		||||
     * @param {number} [page=0] Page number.
 | 
			
		||||
     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
			
		||||
     * @return {Promise<CoreTagIndex[]>} Promise resolved with the tag index per area.
 | 
			
		||||
     * @since 3.7
 | 
			
		||||
     */
 | 
			
		||||
    getTagIndexPerArea(id: number, name: string = '', collectionId: number = 0, areaId: number = 0, fromContextId: number = 0,
 | 
			
		||||
            contextId: number = 0, recursive: boolean = true, page: number = 0, siteId?: string): Promise<CoreTagIndex[]> {
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            const params = {
 | 
			
		||||
                tagindex: {
 | 
			
		||||
                    id: id,
 | 
			
		||||
                    tag: name,
 | 
			
		||||
                    tc: collectionId,
 | 
			
		||||
                    ta: areaId,
 | 
			
		||||
                    excl: true,
 | 
			
		||||
                    from: fromContextId,
 | 
			
		||||
                    ctx: contextId,
 | 
			
		||||
                    rec: recursive,
 | 
			
		||||
                    page: page
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
            const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
                updateFrequency: CoreSite.FREQUENCY_OFTEN,
 | 
			
		||||
                cacheKey: this.getTagIndexPerAreaKey(id, name, collectionId, areaId, fromContextId, contextId, recursive)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return site.read('core_tag_get_tagindex_per_area', params, preSets).catch((error) => {
 | 
			
		||||
                // Workaround for WS not passing parameter to error string.
 | 
			
		||||
                if (error && error.errorcode == 'notagsfound') {
 | 
			
		||||
                    error.message = this.translate.instant('core.tag.notagsfound', {$a: name || id || ''});
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return Promise.reject(error);
 | 
			
		||||
            }).then((response) => {
 | 
			
		||||
                if (!response || !response.length) {
 | 
			
		||||
                    return Promise.reject(null);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return response;
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate tag cloud.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} [collectionId=0] Tag collection ID.
 | 
			
		||||
     * @param {boolean} [isStandard=false] Whether to return only standard tags.
 | 
			
		||||
     * @param {string} [sort='name'] Sort order for display (id, name, rawname, count, flag, isstandard, tagcollid).
 | 
			
		||||
     * @param {string} [search=''] Search string.
 | 
			
		||||
     * @param {number} [fromContextId=0] Context ID where this tag cloud is displayed.
 | 
			
		||||
     * @param {number} [contextId=0] Only retrieve tag instances in this context.
 | 
			
		||||
     * @param {boolean} [recursive=true] Retrieve tag instances in the context and its children.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateTagCloud(collectionId: number = 0, isStandard: boolean = false, sort: string = 'name', search: string = '',
 | 
			
		||||
            fromContextId: number = 0, contextId: number = 0, recursive: boolean = true, siteId?: string): Promise<any> {
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            const key = this.getTagCloudKey(collectionId, isStandard, sort, search, fromContextId, contextId, recursive);
 | 
			
		||||
 | 
			
		||||
            return site.invalidateWsCacheForKey(key);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate tag collections.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateTagCollections(siteId?: string): Promise<any> {
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            const key = this.getTagCollectionsKey();
 | 
			
		||||
 | 
			
		||||
            return site.invalidateWsCacheForKey(key);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate tag index.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} [id=0] Tag ID.
 | 
			
		||||
     * @param {string} [name=''] Tag name.
 | 
			
		||||
     * @param {number} [collectionId=0] Tag collection ID.
 | 
			
		||||
     * @param {number} [areaId=0] Tag area ID.
 | 
			
		||||
     * @param {number} [fromContextId=0] Context ID where the link was displayed.
 | 
			
		||||
     * @param {number} [contextId=0] Context ID where to search for items.
 | 
			
		||||
     * @param {boolean} [recursive=true] Search in the context and its children.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateTagIndexPerArea(id: number, name: string = '', collectionId: number = 0, areaId: number = 0,
 | 
			
		||||
            fromContextId: number = 0, contextId: number = 0, recursive: boolean = true, siteId?: string): Promise<any> {
 | 
			
		||||
        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
			
		||||
            const key = this.getTagIndexPerAreaKey(id, name, collectionId, areaId, fromContextId, contextId, recursive);
 | 
			
		||||
 | 
			
		||||
            return site.invalidateWsCacheForKey(key);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for tag cloud.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} collectionId Tag collection ID.
 | 
			
		||||
     * @param {boolean} isStandard Whether to return only standard tags.
 | 
			
		||||
     * @param {string} sort Sort order for display (id, name, rawname, count, flag, isstandard, tagcollid).
 | 
			
		||||
     * @param {string} search Search string.
 | 
			
		||||
     * @param {number} fromContextId Context ID where this tag cloud is displayed.
 | 
			
		||||
     * @param {number} contextId Only retrieve tag instances in this context.
 | 
			
		||||
     * @param {boolean} recursive Retrieve tag instances in the context and it's children.
 | 
			
		||||
     * @return {string} Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getTagCloudKey(collectionId: number, isStandard: boolean, sort: string, search: string, fromContextId: number,
 | 
			
		||||
            contextId: number, recursive: boolean): string {
 | 
			
		||||
        return this.ROOT_CACHE_KEY + 'cloud:' + collectionId + ':' + (isStandard ? 1 : 0) + ':' + sort + ':' + search + ':' +
 | 
			
		||||
            fromContextId + ':' + contextId + ':' +  (recursive ? 1 : 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for tag collections.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {string} Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getTagCollectionsKey(): string {
 | 
			
		||||
        return this.ROOT_CACHE_KEY + 'collections';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for tag index.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} id Tag ID.
 | 
			
		||||
     * @param {string} name Tag name.
 | 
			
		||||
     * @param {number} collectionId Tag collection ID.
 | 
			
		||||
     * @param {number} areaId Tag area ID.
 | 
			
		||||
     * @param {number} fromContextId Context ID where the link was displayed.
 | 
			
		||||
     * @param {number} contextId Context ID where to search for items.
 | 
			
		||||
     * @param {boolean} [recursive=true] Search in the context and its children.
 | 
			
		||||
     * @return {string} Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getTagIndexPerAreaKey(id: number, name: string, collectionId: number, areaId: number,  fromContextId: number,
 | 
			
		||||
            contextId: number, recursive: boolean): string {
 | 
			
		||||
        return this.ROOT_CACHE_KEY + 'index:' + id + ':' + name + ':' + collectionId + ':' + areaId + ':' + fromContextId + ':'
 | 
			
		||||
            + contextId + ':' +  (recursive ? 1 : 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/core/tag/tag.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/core/tag/tag.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
// (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 { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreTagProvider } from './providers/tag';
 | 
			
		||||
import { CoreTagHelperProvider } from './providers/helper';
 | 
			
		||||
import { CoreTagAreaDelegate } from './providers/area-delegate';
 | 
			
		||||
import { CoreTagMainMenuHandler } from './providers/mainmenu-handler';
 | 
			
		||||
import { CoreTagIndexLinkHandler } from './providers/index-link-handler';
 | 
			
		||||
import { CoreTagSearchLinkHandler } from './providers/search-link-handler';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        CoreTagProvider,
 | 
			
		||||
        CoreTagHelperProvider,
 | 
			
		||||
        CoreTagAreaDelegate,
 | 
			
		||||
        CoreTagMainMenuHandler,
 | 
			
		||||
        CoreTagIndexLinkHandler,
 | 
			
		||||
        CoreTagSearchLinkHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class CoreTagModule {
 | 
			
		||||
 | 
			
		||||
    constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: CoreTagMainMenuHandler,
 | 
			
		||||
            contentLinksDelegate: CoreContentLinksDelegate, indexLinkHandler: CoreTagIndexLinkHandler,
 | 
			
		||||
            searchLinkHandler: CoreTagSearchLinkHandler) {
 | 
			
		||||
        mainMenuDelegate.registerHandler(mainMenuHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(indexLinkHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(searchLinkHandler);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -18,6 +18,7 @@ import { IonicModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreUserParticipantsComponent } from './participants/participants';
 | 
			
		||||
import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile-field';
 | 
			
		||||
import { CoreUserTagAreaComponent } from './tag-area/tag-area';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CorePipesModule } from '@pipes/pipes.module';
 | 
			
		||||
@ -25,7 +26,8 @@ import { CorePipesModule } from '@pipes/pipes.module';
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreUserParticipantsComponent,
 | 
			
		||||
        CoreUserProfileFieldComponent
 | 
			
		||||
        CoreUserProfileFieldComponent,
 | 
			
		||||
        CoreUserTagAreaComponent
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
@ -39,10 +41,12 @@ import { CorePipesModule } from '@pipes/pipes.module';
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        CoreUserParticipantsComponent,
 | 
			
		||||
        CoreUserProfileFieldComponent
 | 
			
		||||
        CoreUserProfileFieldComponent,
 | 
			
		||||
        CoreUserTagAreaComponent
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        CoreUserParticipantsComponent
 | 
			
		||||
        CoreUserParticipantsComponent,
 | 
			
		||||
        CoreUserTagAreaComponent
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class CoreUserComponentsModule {}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,4 @@
 | 
			
		||||
<a ion-item text-wrap *ngFor="let item of items" core-user-link [userId]="item.id">
 | 
			
		||||
    <ion-avatar core-user-avatar [user]="item" item-start></ion-avatar>
 | 
			
		||||
    <h2>{{ item.fullname }}</h2>
 | 
			
		||||
</a>
 | 
			
		||||
							
								
								
									
										26
									
								
								src/core/user/components/tag-area/tag-area.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/core/user/components/tag-area/tag-area.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component to render the user tag area.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'core-user-tag-area',
 | 
			
		||||
    templateUrl: 'core-user-tag-area.html'
 | 
			
		||||
})
 | 
			
		||||
export class CoreUserTagAreaComponent {
 | 
			
		||||
    @Input() items: any[]; // Area items to render.
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								src/core/user/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/core/user/providers/tag-area-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
// (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 } from '@angular/core';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreTagAreaHandler } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreUserTagAreaComponent } from '../components/tag-area/tag-area';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CoreUserTagAreaHandler implements CoreTagAreaHandler {
 | 
			
		||||
    name = 'CoreUserTagAreaHandler';
 | 
			
		||||
    type = 'core/user';
 | 
			
		||||
 | 
			
		||||
    constructor(private domUtils: CoreDomUtilsProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} content Rendered content.
 | 
			
		||||
     * @return {any[]|Promise<any[]>} Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    parseContent(content: string): any[] | Promise<any[]> {
 | 
			
		||||
        const items = [];
 | 
			
		||||
        const element = this.domUtils.convertToElement(content);
 | 
			
		||||
 | 
			
		||||
        Array.from(element.querySelectorAll('div.user-box')).forEach((userbox: HTMLElement) => {
 | 
			
		||||
            const item: any = {};
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            item.id = parseInt(match[1], 10);
 | 
			
		||||
            const avatarImg = avatarLink.querySelector('img.userpicture');
 | 
			
		||||
            item.profileimageurl = avatarImg ? avatarImg.getAttribute('src') : '';
 | 
			
		||||
            item.fullname = userbox.innerText;
 | 
			
		||||
 | 
			
		||||
            items.push(item);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return items;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Injector} injector Injector.
 | 
			
		||||
     * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(injector: Injector): any | Promise<any> {
 | 
			
		||||
        return CoreUserTagAreaComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -30,6 +30,8 @@ import { CoreCronDelegate } from '@providers/cron';
 | 
			
		||||
import { CoreUserOfflineProvider } from './providers/offline';
 | 
			
		||||
import { CoreUserSyncProvider } from './providers/sync';
 | 
			
		||||
import { CoreUserSyncCronHandler } from './providers/sync-cron-handler';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate';
 | 
			
		||||
import { CoreUserTagAreaHandler } from './providers/tag-area-handler';
 | 
			
		||||
 | 
			
		||||
// List of providers (without handlers).
 | 
			
		||||
export const CORE_USER_PROVIDERS: any[] = [
 | 
			
		||||
@ -59,6 +61,7 @@ export const CORE_USER_PROVIDERS: any[] = [
 | 
			
		||||
        CoreUserParticipantsCourseOptionHandler,
 | 
			
		||||
        CoreUserParticipantsLinkHandler,
 | 
			
		||||
        CoreUserSyncCronHandler,
 | 
			
		||||
        CoreUserTagAreaHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class CoreUserModule {
 | 
			
		||||
@ -67,13 +70,14 @@ export class CoreUserModule {
 | 
			
		||||
            contentLinksDelegate: CoreContentLinksDelegate, userLinkHandler: CoreUserProfileLinkHandler,
 | 
			
		||||
            courseOptionHandler: CoreUserParticipantsCourseOptionHandler, linkHandler: CoreUserParticipantsLinkHandler,
 | 
			
		||||
            courseOptionsDelegate: CoreCourseOptionsDelegate, cronDelegate: CoreCronDelegate,
 | 
			
		||||
            syncHandler: CoreUserSyncCronHandler) {
 | 
			
		||||
            syncHandler: CoreUserSyncCronHandler, tagAreaDelegate: CoreTagAreaDelegate, tagAreaHandler: CoreUserTagAreaHandler) {
 | 
			
		||||
 | 
			
		||||
        userDelegate.registerHandler(userProfileMailHandler);
 | 
			
		||||
        courseOptionsDelegate.registerHandler(courseOptionHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(userLinkHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(linkHandler);
 | 
			
		||||
        cronDelegate.register(syncHandler);
 | 
			
		||||
        tagAreaDelegate.registerHandler(tagAreaHandler);
 | 
			
		||||
 | 
			
		||||
        eventsProvider.on(CoreEventsProvider.USER_DELETED, (data) => {
 | 
			
		||||
            // Search for userid in params.
 | 
			
		||||
 | 
			
		||||
@ -394,7 +394,7 @@ export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
            anchors.forEach((anchor) => {
 | 
			
		||||
                // Angular 2 doesn't let adding directives dynamically. Create the CoreLinkDirective manually.
 | 
			
		||||
                const linkDir = new CoreLinkDirective(anchor, this.domUtils, this.utils, this.sitesProvider, this.urlUtils,
 | 
			
		||||
                    this.contentLinksHelper, this.navCtrl, this.content, this.svComponent);
 | 
			
		||||
                    this.contentLinksHelper, this.navCtrl, this.content, this.svComponent, this.textUtils);
 | 
			
		||||
                linkDir.capture = true;
 | 
			
		||||
                linkDir.ngOnInit();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
			
		||||
import { CoreConfigConstants } from '../configconstants';
 | 
			
		||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
 | 
			
		||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Directive to open a link in external browser.
 | 
			
		||||
@ -41,7 +42,8 @@ export class CoreLinkDirective implements OnInit {
 | 
			
		||||
    constructor(element: ElementRef, private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider,
 | 
			
		||||
            private sitesProvider: CoreSitesProvider, private urlUtils: CoreUrlUtilsProvider,
 | 
			
		||||
            private contentLinksHelper: CoreContentLinksHelperProvider, @Optional() private navCtrl: NavController,
 | 
			
		||||
            @Optional() private content: Content, @Optional() private svComponent: CoreSplitViewComponent) {
 | 
			
		||||
            @Optional() private content: Content, @Optional() private svComponent: CoreSplitViewComponent,
 | 
			
		||||
            private textUtils: CoreTextUtilsProvider) {
 | 
			
		||||
        // This directive can be added dynamically. In that case, the first param is the anchor HTMLElement.
 | 
			
		||||
        this.element = element.nativeElement || element;
 | 
			
		||||
    }
 | 
			
		||||
@ -62,12 +64,13 @@ export class CoreLinkDirective implements OnInit {
 | 
			
		||||
        this.element.addEventListener('click', (event) => {
 | 
			
		||||
            // If the event prevented default action, do nothing.
 | 
			
		||||
            if (!event.defaultPrevented) {
 | 
			
		||||
                const href = this.element.getAttribute('href');
 | 
			
		||||
                let href = this.element.getAttribute('href');
 | 
			
		||||
                if (href) {
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
                    event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
                    if (this.utils.isTrueOrOne(this.capture)) {
 | 
			
		||||
                        href = this.textUtils.decodeURI(href);
 | 
			
		||||
                        this.contentLinksHelper.handleLink(href, undefined, navCtrl, true, true).then((treated) => {
 | 
			
		||||
                            if (!treated) {
 | 
			
		||||
                                this.navigate(href);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user