forked from CIT/Vmeda.Online
		
	
						commit
						019c7ab73f
					
				@ -56,6 +56,16 @@
 | 
				
			|||||||
  "addon.block_timeline.pluginname": "block_timeline",
 | 
					  "addon.block_timeline.pluginname": "block_timeline",
 | 
				
			||||||
  "addon.block_timeline.sortbycourses": "block_timeline",
 | 
					  "addon.block_timeline.sortbycourses": "block_timeline",
 | 
				
			||||||
  "addon.block_timeline.sortbydates": "block_timeline",
 | 
					  "addon.block_timeline.sortbydates": "block_timeline",
 | 
				
			||||||
 | 
					  "addon.blog.blog": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.blogentries": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.errorloadentries": "local_moodlemobileapp",
 | 
				
			||||||
 | 
					  "addon.blog.linktooriginalentry": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.noentriesyet": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.publishtonoone": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.publishtosite": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.publishtoworld": "blog",
 | 
				
			||||||
 | 
					  "addon.blog.showonlyyourentries": "local_moodlemobileapp",
 | 
				
			||||||
 | 
					  "addon.blog.siteblogheading": "blog",
 | 
				
			||||||
  "addon.calendar.calendar": "calendar",
 | 
					  "addon.calendar.calendar": "calendar",
 | 
				
			||||||
  "addon.calendar.calendarevents": "local_moodlemobileapp",
 | 
					  "addon.calendar.calendarevents": "local_moodlemobileapp",
 | 
				
			||||||
  "addon.calendar.defaultnotificationtime": "local_moodlemobileapp",
 | 
					  "addon.calendar.defaultnotificationtime": "local_moodlemobileapp",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										46
									
								
								src/addon/blog/blog.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addon/blog/blog.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					// (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 { CoreUserDelegate } from '@core/user/providers/user-delegate';
 | 
				
			||||||
 | 
					import { CoreCourseOptionsDelegate } from '@core/course/providers/options-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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        AddonBlogComponentsModule
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    providers: [
 | 
				
			||||||
 | 
					        AddonBlogProvider,
 | 
				
			||||||
 | 
					        AddonBlogMainMenuHandler,
 | 
				
			||||||
 | 
					        AddonBlogUserHandler,
 | 
				
			||||||
 | 
					        AddonBlogCourseOptionHandler
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonBlogModule {
 | 
				
			||||||
 | 
					    constructor(mainMenuDelegate: CoreMainMenuDelegate, menuHandler: AddonBlogMainMenuHandler,
 | 
				
			||||||
 | 
					            userHandler: AddonBlogUserHandler, userDelegate: CoreUserDelegate,
 | 
				
			||||||
 | 
					            courseOptionHandler: AddonBlogCourseOptionHandler, courseOptionsDelegate: CoreCourseOptionsDelegate) {
 | 
				
			||||||
 | 
					        mainMenuDelegate.registerHandler(menuHandler);
 | 
				
			||||||
 | 
					        userDelegate.registerHandler(userHandler);
 | 
				
			||||||
 | 
					        courseOptionsDelegate.registerHandler(courseOptionHandler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/addon/blog/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/addon/blog/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					// (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 { 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 { AddonBlogEntriesComponent } from './entries/entries';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					        AddonBlogEntriesComponent
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        CommonModule,
 | 
				
			||||||
 | 
					        IonicModule,
 | 
				
			||||||
 | 
					        TranslateModule.forChild(),
 | 
				
			||||||
 | 
					        CoreComponentsModule,
 | 
				
			||||||
 | 
					        CoreDirectivesModule,
 | 
				
			||||||
 | 
					        CorePipesModule,
 | 
				
			||||||
 | 
					        CoreCommentsComponentsModule
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    providers: [
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    exports: [
 | 
				
			||||||
 | 
					        AddonBlogEntriesComponent
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    entryComponents: [
 | 
				
			||||||
 | 
					        AddonBlogEntriesComponent
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonBlogComponentsModule {}
 | 
				
			||||||
							
								
								
									
										49
									
								
								src/addon/blog/components/entries/addon-blog-entries.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/addon/blog/components/entries/addon-blog-entries.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					<ion-content>
 | 
				
			||||||
 | 
					    <ion-refresher [enabled]="loaded" (ionRefresh)="refresh($event)">
 | 
				
			||||||
 | 
					        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
				
			||||||
 | 
					    </ion-refresher>
 | 
				
			||||||
 | 
					    <core-loading [hideUntil]="loaded" class="core-loading-center">
 | 
				
			||||||
 | 
					        <div class="safe-padding-horizontal">
 | 
				
			||||||
 | 
					            <ion-item *ngIf="showMyIssuesToggle">
 | 
				
			||||||
 | 
					                <ion-label>{{ 'addon.blog.showonlyyourentries' | translate }}</ion-label>
 | 
				
			||||||
 | 
					                <ion-toggle [(ngModel)]="onlyMyEntries"></ion-toggle>
 | 
				
			||||||
 | 
					            </ion-item>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <core-empty-box *ngIf="entries && entries.length == 0" icon="fa-newspaper-o" [message]="'addon.blog.noentriesyet' | translate"></core-empty-box>
 | 
				
			||||||
 | 
					        <ng-container *ngFor="let entry of entries">
 | 
				
			||||||
 | 
					            <ion-card *ngIf="!onlyMyEntries || entry.userid == currentUserId">
 | 
				
			||||||
 | 
					                <ion-item text-wrap>
 | 
				
			||||||
 | 
					                    <ion-avatar core-user-avatar [user]="entry.user" item-start [courseId]="entry.courseid"></ion-avatar>
 | 
				
			||||||
 | 
					                    <h2>
 | 
				
			||||||
 | 
					                        <core-format-text [text]="entry.subject"></core-format-text>
 | 
				
			||||||
 | 
					                        <ion-note float-end padding-left text-end>
 | 
				
			||||||
 | 
					                            {{ 'addon.blog.' + entry.publishTranslated | translate}}
 | 
				
			||||||
 | 
					                        </ion-note>
 | 
				
			||||||
 | 
					                    </h2>
 | 
				
			||||||
 | 
					                    <p>
 | 
				
			||||||
 | 
					                        <ion-note float-end padding-left text-end>
 | 
				
			||||||
 | 
					                            {{entry.created | coreDateDayOrTime}}
 | 
				
			||||||
 | 
					                        </ion-note>
 | 
				
			||||||
 | 
					                        {{entry.user && entry.user.fullname}}
 | 
				
			||||||
 | 
					                    </p>
 | 
				
			||||||
 | 
					                </ion-item>
 | 
				
			||||||
 | 
					                <ion-card-content>
 | 
				
			||||||
 | 
					                    <core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id"></core-format-text>
 | 
				
			||||||
 | 
					                    <ion-item>
 | 
				
			||||||
 | 
					                        <core-comments [component]="this.component" [itemId]="entry.id" area="format_blog" [instanceId]="entry.userid" contextLevel="user"></core-comments>
 | 
				
			||||||
 | 
					                    </ion-item>
 | 
				
			||||||
 | 
					                    <core-file *ngFor="let file of entry.attachmentfiles" [file]="file" [component]="this.component" [componentId]="entry.id"></core-file>
 | 
				
			||||||
 | 
					                    <a ion-item *ngIf="entry.uniquehash" [href]="entry.uniquehash" core-link>{{ 'addon.blog.linktooriginalentry' | translate }}</a>
 | 
				
			||||||
 | 
					                </ion-card-content>
 | 
				
			||||||
 | 
					                <ion-row text-center>
 | 
				
			||||||
 | 
					                    <ion-col *ngIf="entry.lastmodified > entry.created">
 | 
				
			||||||
 | 
					                        <ion-note>
 | 
				
			||||||
 | 
					                            <ion-icon name="time"></ion-icon> {{entry.lastmodified | coreTimeAgo}}
 | 
				
			||||||
 | 
					                        </ion-note>
 | 
				
			||||||
 | 
					                    </ion-col>
 | 
				
			||||||
 | 
					                </ion-row>
 | 
				
			||||||
 | 
					            </ion-card>
 | 
				
			||||||
 | 
					        </ng-container>
 | 
				
			||||||
 | 
					        <core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError"></core-infinite-loading>
 | 
				
			||||||
 | 
					    </core-loading>
 | 
				
			||||||
 | 
					</ion-content>
 | 
				
			||||||
							
								
								
									
										163
									
								
								src/addon/blog/components/entries/entries.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/addon/blog/components/entries/entries.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Component, Input, OnInit, ViewChild } from '@angular/core';
 | 
				
			||||||
 | 
					import { Content } from 'ionic-angular';
 | 
				
			||||||
 | 
					import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
				
			||||||
 | 
					import { CoreSitesProvider } from '@providers/sites';
 | 
				
			||||||
 | 
					import { CoreUserProvider } from '@core/user/providers/user';
 | 
				
			||||||
 | 
					import { AddonBlogProvider } from '../../providers/blog';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Component that displays the blog entries.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'addon-blog-entries',
 | 
				
			||||||
 | 
					    templateUrl: 'addon-blog-entries.html',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonBlogEntriesComponent implements OnInit {
 | 
				
			||||||
 | 
					    @Input() userId?: number;
 | 
				
			||||||
 | 
					    @Input() courseId?: number;
 | 
				
			||||||
 | 
					    @Input() cmId?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected filter = {};
 | 
				
			||||||
 | 
					    protected pageLoaded = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @ViewChild(Content) content: Content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loaded = false;
 | 
				
			||||||
 | 
					    canLoadMore = false;
 | 
				
			||||||
 | 
					    loadMoreError = false;
 | 
				
			||||||
 | 
					    entries = [];
 | 
				
			||||||
 | 
					    currentUserId: number;
 | 
				
			||||||
 | 
					    showMyIssuesToggle = false;
 | 
				
			||||||
 | 
					    onlyMyEntries = false;
 | 
				
			||||||
 | 
					    component = AddonBlogProvider.COMPONENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(protected blogProvider: AddonBlogProvider, protected domUtils: CoreDomUtilsProvider,
 | 
				
			||||||
 | 
					            protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider) {
 | 
				
			||||||
 | 
					        this.currentUserId = sitesProvider.getCurrentSiteUserId();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Component being initialized.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ngOnInit(): void {
 | 
				
			||||||
 | 
					        if (this.userId) {
 | 
				
			||||||
 | 
					            this.filter['userid'] = this.userId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.courseId) {
 | 
				
			||||||
 | 
					            this.filter['courseid'] = this.courseId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.cmId) {
 | 
				
			||||||
 | 
					            this.filter['cmid'] = this.cmId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.fetchEntries().then(() => {
 | 
				
			||||||
 | 
					            this.blogProvider.logView(this.filter).catch(() => {
 | 
				
			||||||
 | 
					                // Ignore errors.
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Fetch blog entries.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {boolean} [refresh] Empty events array first.
 | 
				
			||||||
 | 
					     * @return {Promise<any>}         Promise with the entries.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private fetchEntries(refresh: boolean = false): Promise<any> {
 | 
				
			||||||
 | 
					        this.loadMoreError = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (refresh) {
 | 
				
			||||||
 | 
					            this.pageLoaded = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.blogProvider.getEntries(this.filter, this.pageLoaded).then((result) => {
 | 
				
			||||||
 | 
					            const promises = result.entries.map((entry) => {
 | 
				
			||||||
 | 
					                switch (entry.publishstate) {
 | 
				
			||||||
 | 
					                    case 'draft':
 | 
				
			||||||
 | 
					                        entry.publishTranslated = 'publishtonoone';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case 'site':
 | 
				
			||||||
 | 
					                        entry.publishTranslated = 'publishtosite';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case 'public':
 | 
				
			||||||
 | 
					                        entry.publishTranslated = 'publishtoworld';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    default:
 | 
				
			||||||
 | 
					                        entry.publishTranslated = 'privacy:unknown';
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return this.userProvider.getProfile(entry.userid, entry.courseid, true).then((user) => {
 | 
				
			||||||
 | 
					                    entry.user = user;
 | 
				
			||||||
 | 
					                }).catch(() => {
 | 
				
			||||||
 | 
					                    // Ignore errors.
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (refresh) {
 | 
				
			||||||
 | 
					                this.showMyIssuesToggle = false;
 | 
				
			||||||
 | 
					                this.entries = result.entries;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.entries = this.entries.concat(result.entries);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.canLoadMore = result.totalentries > this.entries.length;
 | 
				
			||||||
 | 
					            this.pageLoaded++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.showMyIssuesToggle = !this.userId && (this.showMyIssuesToggle || this.entries.some((entry) => {
 | 
				
			||||||
 | 
					                return entry.userid == this.currentUserId;
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Promise.all(promises);
 | 
				
			||||||
 | 
					        }).catch((message) => {
 | 
				
			||||||
 | 
					            this.domUtils.showErrorModalDefault(message, 'addon.blog.errorloadentries', true);
 | 
				
			||||||
 | 
					            this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | 
				
			||||||
 | 
					        }).finally(() => {
 | 
				
			||||||
 | 
					            this.loaded = true;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Function to load more entries.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    loadMore(infiniteComplete?: any): Promise<any> {
 | 
				
			||||||
 | 
					        return this.fetchEntries().finally(() => {
 | 
				
			||||||
 | 
					            infiniteComplete && infiniteComplete();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Refresh blog entries on PTR.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {any}     refresher  Refresher instance.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    refresh(refresher?: any): void {
 | 
				
			||||||
 | 
					        this.blogProvider.invalidateEntries(this.filter).finally(() => {
 | 
				
			||||||
 | 
					            this.fetchEntries(true).finally(() => {
 | 
				
			||||||
 | 
					                if (refresher) {
 | 
				
			||||||
 | 
					                    refresher.complete();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/addon/blog/lang/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/addon/blog/lang/en.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "blog": "Blog",
 | 
				
			||||||
 | 
					    "blogentries": "Blog entries",
 | 
				
			||||||
 | 
					    "errorloadentries": "Error loading blog entries.",
 | 
				
			||||||
 | 
					    "linktooriginalentry": "Link to original blog entry",
 | 
				
			||||||
 | 
					    "noentriesyet": "No visible entries here",
 | 
				
			||||||
 | 
					    "publishtonoone": "Yourself (draft)",
 | 
				
			||||||
 | 
					    "publishtosite": "Anyone on this site",
 | 
				
			||||||
 | 
					    "publishtoworld": "Anyone in the world",
 | 
				
			||||||
 | 
					    "showonlyyourentries": "Show only your entries",
 | 
				
			||||||
 | 
					    "siteblogheading": "Site blog"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/addon/blog/pages/entries/entries.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/addon/blog/pages/entries/entries.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					<ion-header>
 | 
				
			||||||
 | 
					    <ion-navbar core-back-button>
 | 
				
			||||||
 | 
					        <ion-title>{{ title | translate }}</ion-title>
 | 
				
			||||||
 | 
					        <ion-buttons end></ion-buttons>
 | 
				
			||||||
 | 
					    </ion-navbar>
 | 
				
			||||||
 | 
					</ion-header>
 | 
				
			||||||
 | 
					<addon-blog-entries class="core-avoid-header" [courseId]="courseId" [userId]="userId" [cmId]="cmId"></addon-blog-entries>
 | 
				
			||||||
							
								
								
									
										33
									
								
								src/addon/blog/pages/entries/entries.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/addon/blog/pages/entries/entries.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 { CoreDirectivesModule } from '@directives/directives.module';
 | 
				
			||||||
 | 
					import { AddonBlogEntriesPage } from './entries';
 | 
				
			||||||
 | 
					import { AddonBlogComponentsModule } from '../../components/components.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					        AddonBlogEntriesPage,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        CoreDirectivesModule,
 | 
				
			||||||
 | 
					        AddonBlogComponentsModule,
 | 
				
			||||||
 | 
					        IonicPageModule.forChild(AddonBlogEntriesPage),
 | 
				
			||||||
 | 
					        TranslateModule.forChild()
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonBlogEntriesPageModule {}
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/addon/blog/pages/entries/entries.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/addon/blog/pages/entries/entries.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 } from '@angular/core';
 | 
				
			||||||
 | 
					import { IonicPage, NavParams } from 'ionic-angular';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Page that displays the list of blog entries.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@IonicPage({ segment: 'addon-blog-entries' })
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'page-addon-blog-entries',
 | 
				
			||||||
 | 
					    templateUrl: 'entries.html',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonBlogEntriesPage {
 | 
				
			||||||
 | 
					    userId: number;
 | 
				
			||||||
 | 
					    courseId: number;
 | 
				
			||||||
 | 
					    cmId: number;
 | 
				
			||||||
 | 
					    title: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(params: NavParams) {
 | 
				
			||||||
 | 
					        this.userId = params.get('userId');
 | 
				
			||||||
 | 
					        this.courseId = params.get('courseId');
 | 
				
			||||||
 | 
					        this.cmId = params.get('cmId');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.userId && !this.courseId && !this.cmId) {
 | 
				
			||||||
 | 
					            this.title = 'addon.blog.siteblogheading';
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.title = 'addon.blog.blogentries';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										113
									
								
								src/addon/blog/providers/blog.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/addon/blog/providers/blog.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					// (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 { CoreLoggerProvider } from '@providers/logger';
 | 
				
			||||||
 | 
					import { CoreSitesProvider } from '@providers/sites';
 | 
				
			||||||
 | 
					import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Service to handle blog entries.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class AddonBlogProvider {
 | 
				
			||||||
 | 
					    static ENTRIES_PER_PAGE = 10;
 | 
				
			||||||
 | 
					    static COMPONENT = 'blog';
 | 
				
			||||||
 | 
					    protected ROOT_CACHE_KEY = 'addonBlog:';
 | 
				
			||||||
 | 
					    protected logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(logger: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, protected utils: CoreUtilsProvider) {
 | 
				
			||||||
 | 
					        this.logger = logger.getInstance('AddonBlogProvider');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns whether or not the blog plugin is enabled for a certain site.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This method is called quite often and thus should only perform a quick
 | 
				
			||||||
 | 
					     * check, we should not be calling WS from here.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {string} [siteId]  Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false or rejected otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isPluginEnabled(siteId?: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            return site.wsAvailable('core_blog_get_entries') &&
 | 
				
			||||||
 | 
					                site.canUseAdvancedFeature('enableblogs');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the cache key for the blog entries.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {any}     [filter]     Filter to apply on search.
 | 
				
			||||||
 | 
					     * @return {string}          Cache key.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getEntriesCacheKey(filter: any = {}): string {
 | 
				
			||||||
 | 
					        return this.ROOT_CACHE_KEY + this.utils.sortAndStringify(filter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get blog entries.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {any}     [filter]     Filter to apply on search.
 | 
				
			||||||
 | 
					     * @param  {any}     [page=0]     Page of the blog entries to fetch.
 | 
				
			||||||
 | 
					     * @param  {string}  [siteId]     Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>}         Promise to be resolved when the entries are retrieved.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getEntries(filter: any = {}, page: number = 0, siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const data = {
 | 
				
			||||||
 | 
					                filters: this.utils.objectToArrayOfObjects(filter, 'name', 'value'),
 | 
				
			||||||
 | 
					                page: page,
 | 
				
			||||||
 | 
					                perpage: AddonBlogProvider.ENTRIES_PER_PAGE
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const preSets = {
 | 
				
			||||||
 | 
					                cacheKey: this.getEntriesCacheKey(filter)
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.read('core_blog_get_entries', data, preSets);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Invalidate blog entries WS call.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {any}     [filter]     Filter to apply on search
 | 
				
			||||||
 | 
					     * @param  {string}  [siteId]     Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>}         Promise resolved when data is invalidated.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    invalidateEntries(filter: any = {}, siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            return site.invalidateWsCacheForKey(this.getEntriesCacheKey(filter));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Trigger the blog_entries_viewed event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  {any}     [filter]     Filter to apply on search.
 | 
				
			||||||
 | 
					     * @param  {string}  [siteId]     Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>}         Promise to be resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    logView(filter: any = {}, siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const data = {
 | 
				
			||||||
 | 
					                filters: this.utils.objectToArrayOfObjects(filter, 'name', 'value')
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.write('core_blog_view_entries', data);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										120
									
								
								src/addon/blog/providers/course-option-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/addon/blog/providers/course-option-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
				
			|||||||
 | 
					// (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 { CoreSitesProvider } from '@providers/sites';
 | 
				
			||||||
 | 
					import { CoreFilepoolProvider } from '@providers/filepool';
 | 
				
			||||||
 | 
					import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate';
 | 
				
			||||||
 | 
					import { CoreCoursesProvider } from '@core/courses/providers/courses';
 | 
				
			||||||
 | 
					import { CoreCourseProvider } from '@core/course/providers/course';
 | 
				
			||||||
 | 
					import { CoreCourseHelperProvider } from '@core/course/providers/helper';
 | 
				
			||||||
 | 
					import { AddonBlogEntriesComponent } from '../components/entries/entries';
 | 
				
			||||||
 | 
					import { AddonBlogProvider } from './blog';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Course nav handler.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class AddonBlogCourseOptionHandler implements CoreCourseOptionsHandler {
 | 
				
			||||||
 | 
					    name = 'AddonBlog';
 | 
				
			||||||
 | 
					    priority = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(protected coursesProvider: CoreCoursesProvider, protected blogProvider: AddonBlogProvider,
 | 
				
			||||||
 | 
					        protected courseHelper: CoreCourseHelperProvider, protected courseProvider: CoreCourseProvider,
 | 
				
			||||||
 | 
					        protected sitesProvider: CoreSitesProvider, protected filepoolProvider: CoreFilepoolProvider) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Should invalidate the data to determine if the handler is enabled for a certain course.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {number} courseId The course ID.
 | 
				
			||||||
 | 
					     * @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
 | 
				
			||||||
 | 
					     * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    invalidateEnabledForCourse(courseId: number, navOptions?: any, admOptions?: any): Promise<any> {
 | 
				
			||||||
 | 
					        return this.courseProvider.invalidateCourseBlocks(courseId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the handler is enabled on a site level.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return {boolean} Whether or not the handler is enabled on a site level.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabled(): boolean | Promise<boolean> {
 | 
				
			||||||
 | 
					        return this.blogProvider.isPluginEnabled();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Whether or not the handler is enabled for a certain course.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {number} courseId The course ID.
 | 
				
			||||||
 | 
					     * @param {any} accessData Access type and data. Default, guest, ...
 | 
				
			||||||
 | 
					     * @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
 | 
				
			||||||
 | 
					     * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
 | 
				
			||||||
 | 
					     * @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
 | 
				
			||||||
 | 
					        return this.courseHelper.hasABlockNamed(courseId, 'blog_menu').then((enabled) => {
 | 
				
			||||||
 | 
					            if (enabled && navOptions && typeof navOptions.blogs != 'undefined') {
 | 
				
			||||||
 | 
					                return navOptions.blogs;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return enabled;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the data needed to render the handler.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {Injector} injector Injector.
 | 
				
			||||||
 | 
					     * @param {number} courseId The course ID.
 | 
				
			||||||
 | 
					     * @return {CoreCourseOptionsHandlerData|Promise<CoreCourseOptionsHandlerData>} Data or promise resolved with the data.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getDisplayData(injector: Injector, courseId: number): CoreCourseOptionsHandlerData | Promise<CoreCourseOptionsHandlerData> {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            title: 'addon.blog.blog',
 | 
				
			||||||
 | 
					            class: 'addon-blog-handler',
 | 
				
			||||||
 | 
					            component: AddonBlogEntriesComponent
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when a course is downloaded. It should prefetch all the data to be able to see the addon in offline.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {any} course The course.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    prefetch(course: any): Promise<any> {
 | 
				
			||||||
 | 
					        const siteId = this.sitesProvider.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.blogProvider.getEntries({courseid: course.id}).then((result) => {
 | 
				
			||||||
 | 
					            return result.entries.map((entry) => {
 | 
				
			||||||
 | 
					                let files = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (entry.attachmentfiles && entry.attachmentfiles.length) {
 | 
				
			||||||
 | 
					                    files = entry.attachmentfiles;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (entry.summaryfiles && entry.summaryfiles.length) {
 | 
				
			||||||
 | 
					                    files = files.concat(entry.summaryfiles);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (files.length > 0) {
 | 
				
			||||||
 | 
					                    return this.filepoolProvider.addFilesToQueue(siteId, files, entry.module, entry.id);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return Promise.resolve();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/addon/blog/providers/mainmenu-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/addon/blog/providers/mainmenu-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					// (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 { AddonBlogProvider } from './blog';
 | 
				
			||||||
 | 
					import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler to inject an option into main menu.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class AddonBlogMainMenuHandler implements CoreMainMenuHandler {
 | 
				
			||||||
 | 
					    name = 'AddonBlog';
 | 
				
			||||||
 | 
					    priority = 450;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(private blogProvider: AddonBlogProvider) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the handler is enabled on a site level.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return {boolean} Whether or not the handler is enabled on a site level.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabled(): boolean | Promise<boolean> {
 | 
				
			||||||
 | 
					        return this.blogProvider.isPluginEnabled();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the data needed to render the handler.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return {CoreMainMenuHandlerData} Data needed to render the handler.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getDisplayData(): CoreMainMenuHandlerData {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            icon: 'fa-newspaper-o',
 | 
				
			||||||
 | 
					            title: 'addon.blog.siteblogheading',
 | 
				
			||||||
 | 
					            page: 'AddonBlogEntriesPage',
 | 
				
			||||||
 | 
					            class: 'addon-blog-handler'
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								src/addon/blog/providers/user-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/addon/blog/providers/user-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					// (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 { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
 | 
				
			||||||
 | 
					import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
				
			||||||
 | 
					import { AddonBlogProvider } from './blog';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Profile item handler.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class AddonBlogUserHandler implements CoreUserProfileHandler {
 | 
				
			||||||
 | 
					    name = 'AddonBlog:blogs';
 | 
				
			||||||
 | 
					    priority = 300;
 | 
				
			||||||
 | 
					    type = CoreUserDelegate.TYPE_NEW_PAGE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(protected linkHelper: CoreContentLinksHelperProvider, protected 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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if handler is enabled for this user in this context.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {any} user User to check.
 | 
				
			||||||
 | 
					     * @param {number} courseId Course ID.
 | 
				
			||||||
 | 
					     * @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
 | 
				
			||||||
 | 
					     * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
 | 
				
			||||||
 | 
					     * @return {boolean|Promise<boolean>} Promise resolved with true if enabled, resolved with false otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the data needed to render the handler.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return {CoreUserProfileHandlerData} Data needed to render the handler.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            icon: 'fa-newspaper-o',
 | 
				
			||||||
 | 
					            title: 'addon.blog.blogentries',
 | 
				
			||||||
 | 
					            class: 'addon-blog-handler',
 | 
				
			||||||
 | 
					            action: (event, navCtrl, user, courseId): void => {
 | 
				
			||||||
 | 
					                event.preventDefault();
 | 
				
			||||||
 | 
					                event.stopPropagation();
 | 
				
			||||||
 | 
					                // Always use redirect to make it the new history root (to avoid "loops" in history).
 | 
				
			||||||
 | 
					                this.linkHelper.goInSite(navCtrl, 'AddonBlogEntriesPage', { userId: user.id, courseId: courseId });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="assign && (description || (assign.introattachments && assign.introattachments.length))" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="assign && (description || (assign.introattachments && assign.introattachments.length))" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
    </core-context-menu>
 | 
					    </core-context-menu>
 | 
				
			||||||
</core-navbar-buttons>
 | 
					</core-navbar-buttons>
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,7 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
 | 
				
			|||||||
    protected title: string;
 | 
					    protected title: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(injector: Injector, private chatProvider: AddonModChatProvider, private timeUtils: CoreTimeUtilsProvider,
 | 
					    constructor(injector: Injector, private chatProvider: AddonModChatProvider, private timeUtils: CoreTimeUtilsProvider,
 | 
				
			||||||
            private navCtrl: NavController) {
 | 
					            protected navCtrl: NavController) {
 | 
				
			||||||
        super(injector);
 | 
					        super(injector);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="500" *ngIf="canAdd" [content]="'addon.mod_data.addentries' | translate" [iconAction]="'add'" (action)="gotoAddEntries($event)"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="500" *ngIf="canAdd" [content]="'addon.mod_data.addentries' | translate" [iconAction]="'add'" (action)="gotoAddEntries($event)"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -70,7 +70,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
 | 
					    constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
 | 
				
			||||||
            private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
					            private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
				
			||||||
            private feedbackSync: AddonModFeedbackSyncProvider, private navCtrl: NavController,
 | 
					            private feedbackSync: AddonModFeedbackSyncProvider, protected navCtrl: NavController,
 | 
				
			||||||
            private feedbackHelper: AddonModFeedbackHelperProvider, private timeUtils: CoreTimeUtilsProvider) {
 | 
					            private feedbackHelper: AddonModFeedbackHelperProvider, private timeUtils: CoreTimeUtilsProvider) {
 | 
				
			||||||
        super(injector, content);
 | 
					        super(injector, content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="650" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="650" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="canAdd" [priority]="600" [content]="'addon.mod_glossary.addentry' | translate" (action)="openNewEntry()" iconAction="add"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="canAdd" [priority]="600" [content]="'addon.mod_glossary.addentry' | translate" (action)="openNewEntry()" iconAction="add"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
    </core-context-menu>
 | 
					    </core-context-menu>
 | 
				
			||||||
</core-navbar-buttons>
 | 
					</core-navbar-buttons>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="size" [priority]="500" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
    </core-context-menu>
 | 
					    </core-context-menu>
 | 
				
			||||||
</core-navbar-buttons>
 | 
					</core-navbar-buttons>
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline && !pageIsOffline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline && !pageIsOffline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && isOnline && (hasOffline || pageIsOffline)"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && isOnline && (hasOffline || pageIsOffline)"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="canEdit && (isOnline || pageIsOffline)" [priority]="590" [content]="'core.edit' | translate" iconAction="create" (action)="goToEditPage()"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="canEdit && (isOnline || pageIsOffline)" [priority]="590" [content]="'core.edit' | translate" iconAction="create" (action)="goToEditPage()"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
    <core-context-menu>
 | 
					    <core-context-menu>
 | 
				
			||||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
				
			||||||
 | 
				
			|||||||
@ -67,7 +67,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content,
 | 
					    constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content,
 | 
				
			||||||
            private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
					            private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
				
			||||||
            private navCtrl: NavController, private modalCtrl: ModalController, private utils: CoreUtilsProvider,
 | 
					            protected navCtrl: NavController, private modalCtrl: ModalController, private utils: CoreUtilsProvider,
 | 
				
			||||||
            platform: Platform, private workshopHelper: AddonModWorkshopHelperProvider,
 | 
					            platform: Platform, private workshopHelper: AddonModWorkshopHelperProvider,
 | 
				
			||||||
            private workshopSync: AddonModWorkshopSyncProvider) {
 | 
					            private workshopSync: AddonModWorkshopSyncProvider) {
 | 
				
			||||||
        super(injector, content);
 | 
					        super(injector, content);
 | 
				
			||||||
 | 
				
			|||||||
@ -79,7 +79,7 @@ export class AddonNotesUserHandler implements CoreUserProfileHandler {
 | 
				
			|||||||
            return this.noteEnabledCache[courseId];
 | 
					            return this.noteEnabledCache[courseId];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.notesProvider.isPluginAddNoteEnabledForCourse(courseId).then((enabled) => {
 | 
					        return this.notesProvider.isPluginViewNotesEnabledForCourse(courseId).then((enabled) => {
 | 
				
			||||||
            this.noteEnabledCache[courseId] = enabled;
 | 
					            this.noteEnabledCache[courseId] = enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return enabled;
 | 
					            return enabled;
 | 
				
			||||||
 | 
				
			|||||||
@ -81,6 +81,7 @@ import { CoreBlockModule } from '@core/block/block.module';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Addon modules.
 | 
					// Addon modules.
 | 
				
			||||||
import { AddonBadgesModule } from '@addon/badges/badges.module';
 | 
					import { AddonBadgesModule } from '@addon/badges/badges.module';
 | 
				
			||||||
 | 
					import { AddonBlogModule } from '@addon/blog/blog.module';
 | 
				
			||||||
import { AddonCalendarModule } from '@addon/calendar/calendar.module';
 | 
					import { AddonCalendarModule } from '@addon/calendar/calendar.module';
 | 
				
			||||||
import { AddonCompetencyModule } from '@addon/competency/competency.module';
 | 
					import { AddonCompetencyModule } from '@addon/competency/competency.module';
 | 
				
			||||||
import { AddonCourseCompletionModule } from '@addon/coursecompletion/coursecompletion.module';
 | 
					import { AddonCourseCompletionModule } from '@addon/coursecompletion/coursecompletion.module';
 | 
				
			||||||
@ -198,6 +199,7 @@ export const CORE_PROVIDERS: any[] = [
 | 
				
			|||||||
        CoreCommentsModule,
 | 
					        CoreCommentsModule,
 | 
				
			||||||
        CoreBlockModule,
 | 
					        CoreBlockModule,
 | 
				
			||||||
        AddonBadgesModule,
 | 
					        AddonBadgesModule,
 | 
				
			||||||
 | 
					        AddonBlogModule,
 | 
				
			||||||
        AddonCalendarModule,
 | 
					        AddonCalendarModule,
 | 
				
			||||||
        AddonCompetencyModule,
 | 
					        AddonCompetencyModule,
 | 
				
			||||||
        AddonCourseCompletionModule,
 | 
					        AddonCourseCompletionModule,
 | 
				
			||||||
 | 
				
			|||||||
@ -990,7 +990,9 @@ details summary {
 | 
				
			|||||||
  pointer-events: auto;
 | 
					  pointer-events: auto;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.icon.fa-graduation-cap{
 | 
					.icon.fa-graduation-cap,
 | 
				
			||||||
 | 
					.item > .icon.fa,
 | 
				
			||||||
 | 
					.item-inner > .icon.fa {
 | 
				
			||||||
    font-size: 21px;
 | 
					    font-size: 21px;
 | 
				
			||||||
    width: 21px;
 | 
					    width: 21px;
 | 
				
			||||||
    line-height: 28px;
 | 
					    line-height: 28px;
 | 
				
			||||||
 | 
				
			|||||||
@ -56,6 +56,16 @@
 | 
				
			|||||||
    "addon.block_timeline.pluginname": "Timeline",
 | 
					    "addon.block_timeline.pluginname": "Timeline",
 | 
				
			||||||
    "addon.block_timeline.sortbycourses": "Sort by courses",
 | 
					    "addon.block_timeline.sortbycourses": "Sort by courses",
 | 
				
			||||||
    "addon.block_timeline.sortbydates": "Sort by dates",
 | 
					    "addon.block_timeline.sortbydates": "Sort by dates",
 | 
				
			||||||
 | 
					    "addon.blog.blog": "Blog",
 | 
				
			||||||
 | 
					    "addon.blog.blogentries": "Blog entries",
 | 
				
			||||||
 | 
					    "addon.blog.errorloadentries": "Error loading blog entries.",
 | 
				
			||||||
 | 
					    "addon.blog.linktooriginalentry": "Link to original blog entry",
 | 
				
			||||||
 | 
					    "addon.blog.noentriesyet": "No visible entries here",
 | 
				
			||||||
 | 
					    "addon.blog.publishtonoone": "Yourself (draft)",
 | 
				
			||||||
 | 
					    "addon.blog.publishtosite": "Anyone on this site",
 | 
				
			||||||
 | 
					    "addon.blog.publishtoworld": "Anyone in the world",
 | 
				
			||||||
 | 
					    "addon.blog.showonlyyourentries": "Show only your entries",
 | 
				
			||||||
 | 
					    "addon.blog.siteblogheading": "Site blog",
 | 
				
			||||||
    "addon.calendar.calendar": "Calendar",
 | 
					    "addon.calendar.calendar": "Calendar",
 | 
				
			||||||
    "addon.calendar.calendarevents": "Calendar events",
 | 
					    "addon.calendar.calendarevents": "Calendar events",
 | 
				
			||||||
    "addon.calendar.defaultnotificationtime": "Default notification time",
 | 
					    "addon.calendar.defaultnotificationtime": "Default notification time",
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@
 | 
				
			|||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { OnInit, OnDestroy, Input, Output, EventEmitter, Injector } from '@angular/core';
 | 
					import { OnInit, OnDestroy, Input, Output, EventEmitter, Injector } from '@angular/core';
 | 
				
			||||||
 | 
					import { NavController } from 'ionic-angular';
 | 
				
			||||||
import { TranslateService } from '@ngx-translate/core';
 | 
					import { TranslateService } from '@ngx-translate/core';
 | 
				
			||||||
import { CoreLoggerProvider } from '@providers/logger';
 | 
					import { CoreLoggerProvider } from '@providers/logger';
 | 
				
			||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
					import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
				
			||||||
@ -20,6 +21,8 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
				
			|||||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
 | 
					import { CoreCourseHelperProvider } from '@core/course/providers/helper';
 | 
				
			||||||
import { CoreCourseModuleMainComponent, CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
					import { CoreCourseModuleMainComponent, CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
				
			||||||
import { CoreCourseSectionPage } from '@core/course/pages/section/section.ts';
 | 
					import { CoreCourseSectionPage } from '@core/course/pages/section/section.ts';
 | 
				
			||||||
 | 
					import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
 | 
				
			||||||
 | 
					import { AddonBlogProvider } from '@addon/blog/providers/blog';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Template class to easily create CoreCourseModuleMainComponent of resources (or activities without syncing).
 | 
					 * Template class to easily create CoreCourseModuleMainComponent of resources (or activities without syncing).
 | 
				
			||||||
@ -32,6 +35,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
    loaded: boolean; // If the component has been loaded.
 | 
					    loaded: boolean; // If the component has been loaded.
 | 
				
			||||||
    component: string; // Component name.
 | 
					    component: string; // Component name.
 | 
				
			||||||
    componentId: number; // Component ID.
 | 
					    componentId: number; // Component ID.
 | 
				
			||||||
 | 
					    blog: boolean; // If blog is avalaible.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Data for context menu.
 | 
					    // Data for context menu.
 | 
				
			||||||
    externalUrl: string; // External URL to open in browser.
 | 
					    externalUrl: string; // External URL to open in browser.
 | 
				
			||||||
@ -54,6 +58,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
    protected domUtils: CoreDomUtilsProvider;
 | 
					    protected domUtils: CoreDomUtilsProvider;
 | 
				
			||||||
    protected moduleDelegate: CoreCourseModuleDelegate;
 | 
					    protected moduleDelegate: CoreCourseModuleDelegate;
 | 
				
			||||||
    protected courseSectionPage: CoreCourseSectionPage;
 | 
					    protected courseSectionPage: CoreCourseSectionPage;
 | 
				
			||||||
 | 
					    protected linkHelper: CoreContentLinksHelperProvider;
 | 
				
			||||||
 | 
					    protected navCtrl: NavController;
 | 
				
			||||||
 | 
					    protected blogProvider: AddonBlogProvider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected logger;
 | 
					    protected logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -64,6 +71,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
        this.domUtils = injector.get(CoreDomUtilsProvider);
 | 
					        this.domUtils = injector.get(CoreDomUtilsProvider);
 | 
				
			||||||
        this.moduleDelegate = injector.get(CoreCourseModuleDelegate);
 | 
					        this.moduleDelegate = injector.get(CoreCourseModuleDelegate);
 | 
				
			||||||
        this.courseSectionPage = injector.get(CoreCourseSectionPage, null);
 | 
					        this.courseSectionPage = injector.get(CoreCourseSectionPage, null);
 | 
				
			||||||
 | 
					        this.linkHelper = injector.get(CoreContentLinksHelperProvider);
 | 
				
			||||||
 | 
					        this.navCtrl = injector.get(NavController, null);
 | 
				
			||||||
 | 
					        this.blogProvider = injector.get(AddonBlogProvider, null);
 | 
				
			||||||
        this.dataRetrieved = new EventEmitter();
 | 
					        this.dataRetrieved = new EventEmitter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const loggerProvider = injector.get(CoreLoggerProvider);
 | 
					        const loggerProvider = injector.get(CoreLoggerProvider);
 | 
				
			||||||
@ -79,6 +89,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
        this.externalUrl = this.module.url;
 | 
					        this.externalUrl = this.module.url;
 | 
				
			||||||
        this.loaded = false;
 | 
					        this.loaded = false;
 | 
				
			||||||
        this.refreshIcon = 'spinner';
 | 
					        this.refreshIcon = 'spinner';
 | 
				
			||||||
 | 
					        this.blogProvider.isPluginEnabled().then((enabled) => {
 | 
				
			||||||
 | 
					            this.blog = enabled;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -216,6 +229,16 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
        this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id);
 | 
					        this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Go to blog posts.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {any} event Event.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    gotoBlog(event: any): void {
 | 
				
			||||||
 | 
					        // Always use redirect to make it the new history root (to avoid "loops" in history).
 | 
				
			||||||
 | 
					        this.linkHelper.goInSite(this.navCtrl, 'AddonBlogEntriesPage', { cmId: this.module.id });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Prefetch the module.
 | 
					     * Prefetch the module.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
				
			|||||||
@ -753,6 +753,25 @@ export class CoreCourseHelperProvider {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the course has a block with that name.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {number} courseId Course ID.
 | 
				
			||||||
 | 
					     * @param {string} name     Block name to search.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<boolean>} Promise resolved with true if the block exists or false otherwise.
 | 
				
			||||||
 | 
					     * @since 3.3
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    hasABlockNamed(courseId: number, name: string, siteId?: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        return this.courseProvider.getCourseBlocks(courseId, siteId).then((blocks) => {
 | 
				
			||||||
 | 
					            return blocks.some((block) => {
 | 
				
			||||||
 | 
					                return block.name == name;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }).catch(() => {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Initialize the prefetch icon for selected courses.
 | 
					     * Initialize the prefetch icon for selected courses.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@
 | 
				
			|||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
import { CoreSitesProvider } from '@providers/sites';
 | 
					import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
 | 
				
			||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
					import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
				
			||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
					import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
				
			||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
					import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
				
			||||||
@ -27,7 +27,10 @@ export class CoreCourseLogHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Variables for database.
 | 
					    // Variables for database.
 | 
				
			||||||
    static ACTIVITY_LOG_TABLE = 'course_activity_log';
 | 
					    static ACTIVITY_LOG_TABLE = 'course_activity_log';
 | 
				
			||||||
    protected tablesSchema = [
 | 
					    protected siteSchema: CoreSiteSchema = {
 | 
				
			||||||
 | 
					        name: 'CoreCourseOfflineProvider',
 | 
				
			||||||
 | 
					        version: 1,
 | 
				
			||||||
 | 
					        tables: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                name: CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
 | 
					                name: CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
 | 
				
			||||||
                columns: [
 | 
					                columns: [
 | 
				
			||||||
@ -54,12 +57,13 @@ export class CoreCourseLogHelperProvider {
 | 
				
			|||||||
                ],
 | 
					                ],
 | 
				
			||||||
                primaryKeys: ['component', 'componentid', 'ws', 'time']
 | 
					                primaryKeys: ['component', 'componentid', 'ws', 'time']
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
    ];
 | 
					        ]
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(protected sitesProvider: CoreSitesProvider, protected timeUtils: CoreTimeUtilsProvider,
 | 
					    constructor(protected sitesProvider: CoreSitesProvider, protected timeUtils: CoreTimeUtilsProvider,
 | 
				
			||||||
            protected textUtils: CoreTextUtilsProvider, protected utils: CoreUtilsProvider,
 | 
					            protected textUtils: CoreTextUtilsProvider, protected utils: CoreUtilsProvider,
 | 
				
			||||||
            protected appProvider: CoreAppProvider) {
 | 
					            protected appProvider: CoreAppProvider) {
 | 
				
			||||||
        this.sitesProvider.createTablesFromSchema(this.tablesSchema);
 | 
					        this.sitesProvider.registerSiteSchema(this.siteSchema);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user