forked from EVOgeek/Vmeda.Online
		
	
						commit
						eb19e61a2d
					
				| @ -24,9 +24,7 @@ | ||||
|             </ion-item-divider> | ||||
|             <ion-item text-wrap> | ||||
|                 <h2>{{ 'core.name' | translate}}</h2> | ||||
|                 <p> | ||||
|                     <core-format-text clean="true" [text]="user.fullname"></core-format-text> | ||||
|                 </p> | ||||
|                 <p>{{ user.fullname }}</p> | ||||
|             </ion-item> | ||||
|         </ion-item-group> | ||||
| 
 | ||||
| @ -36,14 +34,12 @@ | ||||
|             </ion-item-divider> | ||||
|             <ion-item text-wrap *ngIf="badge.issuername"> | ||||
|                 <h2>{{ 'addon.badges.issuername' | translate}}</h2> | ||||
|                 <p> | ||||
|                     <core-format-text clean="true" [text]="badge.issuername"></core-format-text> | ||||
|                 </p> | ||||
|                 <p>{{ badge.issuername }}</p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.issuercontact"> | ||||
|                 <h2>{{ 'addon.badges.contact' | translate}}</h2> | ||||
|                 <p><a href="mailto:{{badge.issuercontact}}" core-link auto-login="no"> | ||||
|                     <core-format-text [text]="badge.issuercontact"></core-format-text> | ||||
|                     {{ badge.issuercontact }} | ||||
|                 </a></p> | ||||
|             </ion-item> | ||||
|         </ion-item-group> | ||||
| @ -66,9 +62,7 @@ | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.description"> | ||||
|                 <h2>{{ 'core.description' | translate}}</h2> | ||||
|                 <p> | ||||
|                     <core-format-text clean="true" [text]="badge.description"></core-format-text> | ||||
|                 </p> | ||||
|                 <p>{{ badge.description }}</p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.imageauthorname"> | ||||
|                 <h2>{{ 'addon.badges.imageauthorname' | translate}}</h2> | ||||
| @ -77,23 +71,23 @@ | ||||
|             <ion-item text-wrap *ngIf="badge.imageauthoremail"> | ||||
|                 <h2>{{ 'addon.badges.imageauthoremail' | translate}}</h2> | ||||
|                 <p><a href="mailto:{{badge.imageauthoremail}}" core-link auto-login="no"> | ||||
|                     <core-format-text [text]="badge.imageauthoremail"></core-format-text> | ||||
|                     {{ badge.imageauthoremail }} | ||||
|                 </a></p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.imageauthorurl"> | ||||
|                 <h2>{{ 'addon.badges.imageauthorurl' | translate}}</h2> | ||||
|                 <p><a [href]="badge.imageauthorurl" core-link auto-login="no"> | ||||
|                     <core-format-text [text]="badge.imageauthorurl"></core-format-text> | ||||
|                     {{ badge.imageauthorurl }} | ||||
|                 </a></p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.imagecaption"> | ||||
|                 <h2>{{ 'addon.badges.imagecaption' | translate}}</h2> | ||||
|                 <p><core-format-text [text]="badge.imagecaption"></core-format-text></p> | ||||
|                 <p>{{ badge.imagecaption }}</p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="course.fullname"> | ||||
|                 <h2>{{ 'core.course' | translate}}</h2> | ||||
|                 <p> | ||||
|                     <core-format-text [text]="course.fullname"></core-format-text> | ||||
|                     <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId"></core-format-text> | ||||
|                 </p> | ||||
|             </ion-item> | ||||
|             <!-- Criteria (not yet avalaible) --> | ||||
| @ -131,13 +125,13 @@ | ||||
|             <ion-item text-wrap *ngIf="badge.endorsement.issueremail"> | ||||
|                 <h2>{{ 'addon.badges.issueremail' | translate}}</h2> | ||||
|                 <p><a href="mailto:{{badge.endorsement.issueremail}}" core-link auto-login="no"> | ||||
|                     <core-format-text [text]="badge.endorsement.issueremail"></core-format-text> | ||||
|                     {{ badge.endorsement.issueremail }} | ||||
|                 </a></p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.endorsement.issuerurl"> | ||||
|                 <h2>{{ 'addon.badges.issuerurl' | translate}}</h2> | ||||
|                 <p><a [href]="badge.endorsement.issuerurl" core-link auto-login="no"> | ||||
|                     <core-format-text [text]="badge.endorsement.issuerurl"></core-format-text> | ||||
|                     {{ badge.endorsement.issuerurl }} | ||||
|                 </a></p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.endorsement.dateissued"> | ||||
| @ -147,14 +141,12 @@ | ||||
|             <ion-item text-wrap *ngIf="badge.endorsement.claimid"> | ||||
|                 <h2>{{ 'addon.badges.claimid' | translate}}</h2> | ||||
|                 <p><a [href]="badge.endorsement.claimid" core-link auto-login="no"> | ||||
|                     <core-format-text [text]="badge.endorsement.claimid"></core-format-text> | ||||
|                     {{ badge.endorsement.claimid }} | ||||
|                 </a></p> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.endorsement.claimcomment"> | ||||
|                 <h2>{{ 'addon.badges.claimcomment' | translate}}</h2> | ||||
|                 <p> | ||||
|                     <core-format-text [text]="badge.endorsement.claimcomment"></core-format-text> | ||||
|                 </p> | ||||
|                 <p>{{ badge.endorsement.claimcomment }}</p> | ||||
|             </ion-item> | ||||
|         </ion-item-group> | ||||
| 
 | ||||
| @ -164,7 +156,7 @@ | ||||
|                 <h2>{{ 'addon.badges.relatedbages' | translate}}</h2> | ||||
|             </ion-item-divider> | ||||
|             <ion-item text-wrap *ngFor="let relatedBadge of badge.relatedbadges"> | ||||
|                 <h2><core-format-text [text]="relatedBadge.name"></core-format-text></h2> | ||||
|                 <h2><{{ relatedBadge.name }}</h2> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="badge.relatedbadges.length == 0"> | ||||
|                 <h2>{{ 'addon.badges.norelated' | translate}}</h2> | ||||
| @ -177,7 +169,7 @@ | ||||
|                 <h2>{{ 'addon.badges.alignment' | translate}}</h2> | ||||
|             </ion-item-divider> | ||||
|             <a ion-item text-wrap *ngFor="let alignment of badge.alignment" [href]="alignment.targeturl" core-link auto-login="no"> | ||||
|                 <h2><core-format-text [text]="alignment.targetname"></core-format-text></h2> | ||||
|                 <h2>{{ alignment.targetname }}</h2> | ||||
|             </a> | ||||
|             <ion-item text-wrap *ngIf="badge.alignment.length == 0"> | ||||
|                 <h2>{{ 'addon.badges.noalignment' | translate}}</h2> | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
|                     <ion-avatar item-start> | ||||
|                         <img [src]="badge.badgeurl" [alt]="badge.name" item-start core-external-content> | ||||
|                     </ion-avatar> | ||||
|                     <h2><core-format-text [text]="badge.name"></core-format-text></h2> | ||||
|                     <h2>{{ badge.name }}</h2> | ||||
|                     <p>{{ badge.dateissued * 1000 | coreFormatDate :'strftimedatetimeshort' }}</p> | ||||
|                     <ion-badge item-end color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire"> | ||||
|                         {{ 'addon.badges.expired' | translate }} | ||||
|  | ||||
| @ -4,6 +4,6 @@ | ||||
| <core-loading [hideUntil]="loaded" class="core-loading-center"> | ||||
|     <a ion-item text-wrap *ngFor="let entry of entries" class="item-media" detail-none [navPush]="'CoreCourseListModTypePage'" [navParams]="{title: entry.name, courseId: instanceId, modName: entry.modName}"> | ||||
|         <img item-start [src]="entry.icon" alt="" role="presentation" class="core-module-icon"> | ||||
|         <core-format-text [text]="entry.name"></core-format-text> | ||||
|         {{ entry.name }} | ||||
|     </a> | ||||
| </core-loading> | ||||
|  | ||||
| @ -7,8 +7,8 @@ | ||||
|             <ion-card> | ||||
|                 <a ion-item text-wrap detail-none class="core-course-module-handler item-media" (click)="action($event, item)" [title]="item.name"> | ||||
|                     <img item-start [src]="item.iconUrl" alt="" role="presentation" *ngIf="item.iconUrl" class="core-module-icon"> | ||||
|                     <h2><core-format-text [text]="item.name"></core-format-text></h2> | ||||
|                     <p><core-format-text [text]="item.coursename"></core-format-text></p> | ||||
|                     <h2><core-format-text [text]="item.name" contextLevel="module" [contextInstanceId]="item.cmid" [courseId]="item.courseid"></core-format-text></h2> | ||||
|                     <p><core-format-text [text]="item.coursename" contextLevel="course" [contextInstanceId]="item.courseid"></core-format-text></p> | ||||
|                 </a> | ||||
|             </ion-card> | ||||
|         </div> | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| <core-loading [hideUntil]="loaded" class="core-loading-center"> | ||||
|     <ng-container *ngIf="mainMenuBlock"> | ||||
|         <ion-item text-wrap *ngIf="mainMenuBlock.summary"> | ||||
|             <core-format-text [text]="mainMenuBlock.summary"></core-format-text> | ||||
|             <core-format-text [text]="mainMenuBlock.summary" [component]="component" [componentId]="siteHomeId" contextLevel="course" [contextInstanceId]="siteHomeId"></core-format-text> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <core-course-module *ngFor="let module of mainMenuBlock.modules" [module]="module" [courseId]="siteHomeId" [downloadEnabled]="downloadEnabled" [section]="mainMenuBlock"></core-course-module> | ||||
|  | ||||
| @ -30,6 +30,7 @@ import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component | ||||
| export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent implements OnInit { | ||||
|     @Input() downloadEnabled: boolean; | ||||
| 
 | ||||
|     component = 'AddonBlockSiteMainMenu'; | ||||
|     mainMenuBlock: any; | ||||
|     siteHomeId: number; | ||||
| 
 | ||||
|  | ||||
| @ -5,9 +5,9 @@ | ||||
|     <ng-container *ngFor="let event of dayEvents.events"> | ||||
|         <a ion-item text-wrap detail-none class="core-course-module-handler item-media" (click)="action($event, event.url)" [title]="event.name"> | ||||
|             <img item-start [src]="event.iconUrl" alt="" role="presentation" *ngIf="event.iconUrl" class="core-module-icon"> | ||||
|             <h2><core-format-text [text]="event.name"></core-format-text></h2> | ||||
|             <h2><core-format-text [text]="event.name" contextLevel="module" [contextInstanceId]="event.id" [courseId]="event.course.id"></core-format-text></h2> | ||||
|             <p *ngIf="showCourse"> | ||||
|                 <core-format-text [text]="event.course.fullnamedisplay"></core-format-text> | ||||
|                 <core-format-text [text]="event.course.fullnamedisplay" contextLevel="course" [contextInstanceId]="event.course.id"></core-format-text> | ||||
|             </p> | ||||
| 
 | ||||
|             <button ion-button clear class="hidden-tablet" (click)="action($event, event.action.url)" [title]="event.action.name" [disabled]="!event.action.actionable" *ngIf="event.action"> | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
|                 <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> | ||||
|                         <core-format-text [text]="entry.subject" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"></core-format-text> | ||||
|                         <ion-note float-end padding-left text-end> | ||||
|                             {{ 'addon.blog.' + entry.publishTranslated | translate}} | ||||
|                         </ion-note> | ||||
| @ -27,7 +27,7 @@ | ||||
|                 </ion-item> | ||||
|                 <ion-card-content> | ||||
|                     <ion-item> | ||||
|                         <core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id"></core-format-text> | ||||
|                         <core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"></core-format-text> | ||||
|                     </ion-item> | ||||
|                     <ion-item text-wrap *ngIf="tagsEnabled && entry.tags && entry.tags.length > 0"> | ||||
|                         <div item-start>{{ 'core.tag.tags' | translate }}:</div> | ||||
|  | ||||
| @ -42,6 +42,7 @@ export class AddonBlogEntriesComponent implements OnInit { | ||||
|     protected userPageLoaded = 0; | ||||
|     protected canLoadMoreEntries = false; | ||||
|     protected canLoadMoreUserEntries = true; | ||||
|     protected siteHomeId: number; | ||||
| 
 | ||||
|     @ViewChild(Content) content: Content; | ||||
| 
 | ||||
| @ -55,11 +56,14 @@ export class AddonBlogEntriesComponent implements OnInit { | ||||
|     component = AddonBlogProvider.COMPONENT; | ||||
|     commentsEnabled: boolean; | ||||
|     tagsEnabled: boolean; | ||||
|     contextLevel: string; | ||||
|     contextInstanceId: number; | ||||
| 
 | ||||
|     constructor(protected blogProvider: AddonBlogProvider, protected domUtils: CoreDomUtilsProvider, | ||||
|             protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider, protected utils: CoreUtilsProvider, | ||||
|             protected commentsProvider: CoreCommentsProvider, private tagProvider: CoreTagProvider) { | ||||
|         this.currentUserId = sitesProvider.getCurrentSiteUserId(); | ||||
|         this.siteHomeId = sitesProvider.getCurrentSiteHomeId(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -91,6 +95,18 @@ export class AddonBlogEntriesComponent implements OnInit { | ||||
|             this.filter['tagid'] = this.tagId; | ||||
|         } | ||||
| 
 | ||||
|         // Calculate the context level.
 | ||||
|         if (this.userId && !this.courseId && !this.cmId) { | ||||
|             this.contextLevel = 'user'; | ||||
|             this.contextInstanceId = this.userId; | ||||
|         } else if (this.courseId && this.courseId != this.siteHomeId) { | ||||
|             this.contextLevel = 'course'; | ||||
|             this.contextInstanceId = this.courseId; | ||||
|         } else { | ||||
|             this.contextLevel = 'system'; | ||||
|             this.contextInstanceId = 0; | ||||
|         } | ||||
| 
 | ||||
|         this.commentsEnabled = !this.commentsProvider.areCommentsDisabledInSite(); | ||||
|         this.tagsEnabled = this.tagProvider.areTagsAvailableInSite(); | ||||
| 
 | ||||
| @ -134,6 +150,18 @@ export class AddonBlogEntriesComponent implements OnInit { | ||||
|                         break; | ||||
|                 } | ||||
| 
 | ||||
|                 // Calculate the context. This code was inspired by calendar events, Moodle doesn't do this for blogs.
 | ||||
|                 if (entry.moduleid || entry.coursemoduleid) { | ||||
|                     entry.contextLevel = 'module'; | ||||
|                     entry.contextInstanceId = entry.moduleid || entry.coursemoduleid; | ||||
|                 } else if (entry.courseid) { | ||||
|                     entry.contextLevel = 'course'; | ||||
|                     entry.contextInstanceId = entry.courseid; | ||||
|                 } else { | ||||
|                     entry.contextLevel = 'user'; | ||||
|                     entry.contextInstanceId = entry.userid; | ||||
|                 } | ||||
| 
 | ||||
|                 return this.userProvider.getProfile(entry.userid, entry.courseid, true).then((user) => { | ||||
|                     entry.user = user; | ||||
|                 }).catch(() => { | ||||
| @ -245,4 +273,6 @@ export class AddonBlogEntriesComponent implements OnInit { | ||||
| type AddonBlogPostFormatted = AddonBlogPost & { | ||||
|     publishTranslated?: string; // Calculated in the app. Key of the string to translate the publish state of the post.
 | ||||
|     user?: any; // Calculated in the app. Data of the user that wrote the post.
 | ||||
|     contextLevel?: string; // Calculated in the app. The context level of the entry.
 | ||||
|     contextInstanceId?: number; // Calculated in the app. The context instance id.
 | ||||
| }; | ||||
|  | ||||
| @ -7,8 +7,8 @@ | ||||
|             <a ion-item text-wrap [title]="event.name" (click)="eventClicked(event)" [class.core-split-item-selected]="event.id == eventId" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> | ||||
|                 <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon"> | ||||
|                 <core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon> | ||||
|                 <h2><core-format-text [text]="event.name"></core-format-text></h2> | ||||
|                 <p><core-format-text [text]="event.formattedtime"></core-format-text></p> | ||||
|                 <h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text></h2> | ||||
|                 <p [innerHTML]="event.formattedtime"></p> | ||||
|                 <ion-note *ngIf="event.offline && !event.deleted" item-end> | ||||
|                     <ion-icon name="time"></ion-icon> | ||||
|                     <span text-wrap>{{ 'core.notsent' | translate }}</span> | ||||
|  | ||||
| @ -51,8 +51,8 @@ | ||||
|                 <ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.item-dimmed]="event.ispast" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> | ||||
|                     <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon"> | ||||
|                     <core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon> | ||||
|                     <h2><core-format-text [text]="event.name"></core-format-text></h2> | ||||
|                     <p><core-format-text [text]="event.formattedtime"></core-format-text></p> | ||||
|                     <h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text></h2> | ||||
|                     <p [innerHTML]="event.formattedtime"></p> | ||||
|                     <ion-note *ngIf="event.offline && !event.deleted" item-end> | ||||
|                         <ion-icon name="time"></ion-icon> | ||||
|                         <span text-wrap>{{ 'core.notsent' | translate }}</span> | ||||
|  | ||||
| @ -21,7 +21,6 @@ import { CoreGroupsProvider } from '@providers/groups'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreSyncProvider } from '@providers/sync'; | ||||
| import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||
| import { CoreTimeUtilsProvider } from '@providers/utils/time'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreCoursesProvider } from '@core/courses/providers/courses'; | ||||
| @ -32,6 +31,7 @@ import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline'; | ||||
| import { AddonCalendarHelperProvider } from '../../providers/helper'; | ||||
| import { AddonCalendarSyncProvider } from '../../providers/calendar-sync'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays a form to create/edit an event. | ||||
| @ -81,7 +81,6 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy { | ||||
|             private navCtrl: NavController, | ||||
|             private translate: TranslateService, | ||||
|             private domUtils: CoreDomUtilsProvider, | ||||
|             private textUtils: CoreTextUtilsProvider, | ||||
|             private timeUtils: CoreTimeUtilsProvider, | ||||
|             private eventsProvider: CoreEventsProvider, | ||||
|             private groupsProvider: CoreGroupsProvider, | ||||
| @ -94,6 +93,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy { | ||||
|             private calendarSync: AddonCalendarSyncProvider, | ||||
|             private fb: FormBuilder, | ||||
|             private syncProvider: CoreSyncProvider, | ||||
|             private filterHelper: CoreFilterHelperProvider, | ||||
|             @Optional() private svComponent: CoreSplitViewComponent) { | ||||
| 
 | ||||
|         this.eventId = navParams.get('eventId'); | ||||
| @ -244,7 +244,8 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy { | ||||
|                     // Format the name of the courses.
 | ||||
|                     const subPromises = []; | ||||
|                     courses.forEach((course) => { | ||||
|                         subPromises.push(this.textUtils.formatText(course.fullname).then((text) => { | ||||
|                         subPromises.push(this.filterHelper.getFiltersAndFormatText(course.fullname, 'course', course.id) | ||||
|                                 .then((text) => { | ||||
|                             course.fullname = text; | ||||
|                         }).catch(() => { | ||||
|                             // Ignore errors.
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|         <ion-title> | ||||
|             <img *ngIf="event && event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation" class="core-module-icon"> | ||||
|             <core-icon *ngIf="event && event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon> | ||||
|             <core-format-text *ngIf="event" [text]="event.name"></core-format-text> | ||||
|             <core-format-text *ngIf="event" [text]="event.name" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|         </ion-title> | ||||
|         <ion-buttons end> | ||||
|             <!-- The context menu will be added in here. --> | ||||
| @ -34,14 +34,14 @@ | ||||
|                     <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start alt="" role="presentation" class="core-module-icon"> | ||||
|                     <core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon> | ||||
|                     <h2>{{ 'addon.calendar.eventname' | translate }}</h2> | ||||
|                     <p><core-format-text [text]="event.name"></core-format-text></p> | ||||
|                     <p><core-format-text [text]="event.name" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text></p> | ||||
|                     <ion-note item-end *ngIf="event.deleted"> | ||||
|                         <ion-icon name="trash"></ion-icon> {{ 'core.deletedoffline' | translate }} | ||||
|                     </ion-note> | ||||
|                 </ion-item> | ||||
|                 <ion-item> | ||||
|                     <h2>{{ 'addon.calendar.when' | translate }}</h2> | ||||
|                     <p><core-format-text [text]="event.formattedtime"></core-format-text></p> | ||||
|                     <p [innerHTML]="event.formattedtime"></p> | ||||
|                     <ion-note item-end *ngIf="!isSplitViewOn && event.deleted"> | ||||
|                         <ion-icon name="trash"></ion-icon> {{ 'core.deletedoffline' | translate }} | ||||
|                     </ion-note> | ||||
| @ -52,7 +52,7 @@ | ||||
|                 </ion-item> | ||||
|                 <a ion-item text-wrap *ngIf="courseName" [href]="courseUrl" core-link capture="true"> | ||||
|                     <h2>{{ 'core.course' | translate}}</h2> | ||||
|                     <p><core-format-text [text]="courseName"></core-format-text></p> | ||||
|                     <p><core-format-text [text]="courseName" contextLevel="course" [contextInstanceId]="courseId"></core-format-text></p> | ||||
|                 </a> | ||||
|                 <ion-item text-wrap *ngIf="groupName"> | ||||
|                     <h2>{{ 'core.group' | translate}}</h2> | ||||
| @ -60,19 +60,19 @@ | ||||
|                 </ion-item> | ||||
|                 <a ion-item text-wrap *ngIf="categoryPath"> | ||||
|                     <h2>{{ 'core.category' | translate}}</h2> | ||||
|                     <p><core-format-text [text]="categoryPath"></core-format-text></p> | ||||
|                     <p><core-format-text [text]="categoryPath" contextLevel="category" [contextInstanceId]="event.category.id"></core-format-text></p> | ||||
|                 </a> | ||||
|                 <ion-item text-wrap *ngIf="event.description"> | ||||
|                     <h2>{{ 'core.description' | translate}}</h2> | ||||
|                     <p> | ||||
|                         <core-format-text [text]="event.description"></core-format-text> | ||||
|                         <core-format-text [text]="event.description" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                     </p> | ||||
|                 </ion-item> | ||||
|                 <ion-item text-wrap *ngIf="event.location"> | ||||
|                     <h2>{{ 'core.location' | translate}}</h2> | ||||
|                     <p> | ||||
|                         <a [href]="event.encodedLocation" core-link auto-login="no"> | ||||
|                             <core-format-text [text]="event.location"></core-format-text> | ||||
|                             <core-format-text [text]="event.location" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                         </a> | ||||
|                     </p> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -57,6 +57,7 @@ export class AddonCalendarEventPage implements OnDestroy { | ||||
|     notificationMax: string; | ||||
|     notificationTimeText: string; | ||||
|     event: any = {}; | ||||
|     courseId: number; | ||||
|     courseName: string; | ||||
|     groupName: string; | ||||
|     courseUrl = ''; | ||||
| @ -250,11 +251,13 @@ export class AddonCalendarEventPage implements OnDestroy { | ||||
| 
 | ||||
|             // If the event belongs to a course, get the course name and the URL to view it.
 | ||||
|             if (canGetById && event.course && event.course.id != this.siteHomeId) { | ||||
|                 this.courseId = event.course.id; | ||||
|                 this.courseName = event.course.fullname; | ||||
|                 this.courseUrl = event.course.viewurl; | ||||
|             } else if (event.courseid && event.courseid != this.siteHomeId) { | ||||
|                 // Retrieve the course.
 | ||||
|                 promises.push(this.coursesProvider.getUserCourse(event.courseid, true).then((course) => { | ||||
|                     this.courseId = course.id; | ||||
|                     this.courseName = course.fullname; | ||||
|                     this.courseUrl = currentSite ? this.textUtils.concatenatePaths(currentSite.siteUrl, | ||||
|                             '/course/view.php?id=' + event.courseid) : ''; | ||||
|  | ||||
| @ -35,7 +35,7 @@ | ||||
|                     <a ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> | ||||
|                         <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon"> | ||||
|                         <core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon> | ||||
|                         <h2><core-format-text [text]="event.name"></core-format-text></h2> | ||||
|                         <h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"></core-format-text></h2> | ||||
|                         <p> | ||||
|                             {{ event.timestart * 1000 | coreFormatDate: "strftimetime" }} | ||||
|                             <span *ngIf="event.timeduration && event.endsSameDay"> - {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimetime" }}</span> | ||||
|  | ||||
| @ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; | ||||
| import { CoreLoggerProvider } from '@providers/logger'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreCourseProvider } from '@core/course/providers/course'; | ||||
| import { AddonCalendarProvider, AddonCalendarCalendarEvent } from './calendar'; | ||||
| import { AddonCalendarProvider } from './calendar'; | ||||
| import { CoreConstants } from '@core/constants'; | ||||
| import { CoreConfigProvider } from '@providers/config'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| @ -130,7 +130,7 @@ export class AddonCalendarHelperProvider { | ||||
|      * | ||||
|      * @param e Event to format. | ||||
|      */ | ||||
|     formatEventData(e: AddonCalendarCalendarEvent): void { | ||||
|     formatEventData(e: any): void { | ||||
|         e.eventIcon = this.EVENTICONS[e.eventtype] || ''; | ||||
|         if (!e.eventIcon) { | ||||
|             e.eventIcon = this.courseProvider.getModuleIconSrc(e.modulename); | ||||
| @ -139,6 +139,21 @@ export class AddonCalendarHelperProvider { | ||||
| 
 | ||||
|         e.formattedType = this.calendarProvider.getEventType(e); | ||||
| 
 | ||||
|         // Calculate context.
 | ||||
|         const categoryId = e.category ? e.category.id : e.categoryid, | ||||
|             courseId = e.course ? e.course.id : e.courseid; | ||||
| 
 | ||||
|         if (categoryId > 0) { | ||||
|             e.contextLevel = 'category'; | ||||
|             e.contextInstanceId = categoryId; | ||||
|         } else if (courseId > 0) { | ||||
|             e.contextLevel = 'course'; | ||||
|             e.contextInstanceId = courseId; | ||||
|         } else { | ||||
|             e.contextLevel = 'user'; | ||||
|             e.contextInstanceId = e.userid; | ||||
|         } | ||||
| 
 | ||||
|         if (typeof e.duration != 'undefined') { | ||||
|             // It's an offline event, add some calculated data.
 | ||||
|             e.format = 1; | ||||
|  | ||||
| @ -30,7 +30,7 @@ | ||||
|         <ion-card *ngIf="user"> | ||||
|              <ion-item text-wrap> | ||||
|                 <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar> | ||||
|                 <h2><core-format-text [text]="user.fullname"></core-format-text></h2> | ||||
|                 <h2>{{ user.fullname }}</h2> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|         <core-empty-box *ngIf="competencies && competencies.statistics.competencycount == 0" icon="ribbon" message="{{ 'addon.competency.nocompetenciesincourse' | translate }}"></core-empty-box> | ||||
| @ -43,7 +43,7 @@ | ||||
|                 </ion-item> | ||||
|                 <ion-item text-wrap> | ||||
|                     <p *ngIf="competency.competency.description"> | ||||
|                         <core-format-text [text]=" competency.competency.description "></core-format-text> | ||||
|                         <core-format-text [text]="competency.competency.description" contextLevel="course" [contextInstanceId]="courseId"></core-format-text> | ||||
|                     </p> | ||||
|                     <div> | ||||
|                         <strong>{{ 'addon.competency.path' | translate }}</strong> | ||||
| @ -59,9 +59,7 @@ | ||||
|                     <div *ngIf="competencies.statistics.canmanagecoursecompetencies"> | ||||
|                         <strong>{{ 'addon.competency.uponcoursecompletion' | translate }}</strong> | ||||
|                          <ng-container *ngFor="let ruleoutcome of competency.ruleoutcomeoptions"> | ||||
|                             <span *ngIf="ruleoutcome.selected"> | ||||
|                                 <core-format-text [text]="ruleoutcome.text"></core-format-text> | ||||
|                             </span> | ||||
|                             <span *ngIf="ruleoutcome.selected">{{ ruleoutcome.text }}</span> | ||||
|                         </ng-container> | ||||
|                     </div> | ||||
|                     <div> | ||||
| @ -71,7 +69,7 @@ | ||||
|                         </p> | ||||
|                         <a ion-item text-wrap *ngFor="let activity of competency.coursemodules" [href]="activity.url" [title]="activity.name" core-link capture="true" class="core-course-module-handler item-media"> | ||||
|                             <img item-start [src]="activity.iconurl" core-external-content alt="" role="presentation" *ngIf="activity.iconurl" class="core-module-icon"> | ||||
|                             <core-format-text [text]="activity.name"></core-format-text> | ||||
|                             <core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id" [courseId]="courseId"></core-format-text> | ||||
|                         </a> | ||||
|                     </div> | ||||
|                     <div *ngIf="competency.plans"> | ||||
| @ -80,7 +78,7 @@ | ||||
|                             {{ 'addon.competency.nouserplanswithcompetency' | translate }} | ||||
|                         </p> | ||||
|                         <a ion-item text-wrap *ngFor="let plan of competency.plans" [href]="plan.url" [title]="plan.name" core-link capture="true"> | ||||
|                             <core-format-text [text]="plan.name"></core-format-text> | ||||
|                             <core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid"></core-format-text> | ||||
|                         </a> | ||||
|                     </div> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -86,7 +86,11 @@ export class AddonCompetencyCourseComponent { | ||||
|      * @param competencyId | ||||
|      */ | ||||
|     openCompetencySummary(competencyId: number): void { | ||||
|         this.navCtrl.push('AddonCompetencyCompetencySummaryPage', {competencyId}); | ||||
|         this.navCtrl.push('AddonCompetencyCompetencySummaryPage', { | ||||
|             competencyId, | ||||
|             contextLevel: 'course', | ||||
|             contextInstanceId: this.courseId | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -11,13 +11,13 @@ | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item text-wrap> | ||||
|                 <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar> | ||||
|                 <h2><core-format-text [text]="user.fullname"></core-format-text></h2> | ||||
|                 <h2>{{ user.fullname }}</h2> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ion-card *ngIf="competency"> | ||||
|             <ion-item text-wrap *ngIf="competency.competency.competency.description"> | ||||
|                 <core-format-text [text]="competency.competency.competency.description"></core-format-text> | ||||
|                 <core-format-text [text]="competency.competency.competency.description" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"></core-format-text> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap> | ||||
|                 <strong>{{ 'addon.competency.path' | translate }}</strong> | ||||
| @ -48,7 +48,7 @@ | ||||
|                 </p> | ||||
|                 <a ion-item text-wrap *ngFor="let activity of coursemodules" [href]="activity.url" [title]="activity.name" core-link capture="true"> | ||||
|                     <img item-start core-external-content [src]="activity.iconurl" alt="" role="presentation" *ngIf="activity.iconurl" class="core-module-icon"> | ||||
|                     <core-format-text [text]="activity.name"></core-format-text> | ||||
|                     <core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id" [courseId]="courseId"></core-format-text> | ||||
|                 </a> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap *ngIf="userCompetency.status"> | ||||
| @ -84,7 +84,7 @@ | ||||
|                 <ion-item text-wrap> | ||||
|                     <p><ion-badge color="dark">{{ evidence.gradename }}</ion-badge></p> | ||||
|                     <p margin-top *ngIf="evidence.description">{{ evidence.description }}</p> | ||||
|                     <blockquote *ngIf="evidence.note"><core-format-text [text]="evidence.note"></core-format-text></blockquote> | ||||
|                     <blockquote *ngIf="evidence.note">{{ evidence.note }}</blockquote> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
|         </div> | ||||
|  | ||||
| @ -46,6 +46,8 @@ export class AddonCompetencyCompetencyPage { | ||||
|     user: CoreUserSummary; | ||||
|     competency: AddonCompetencyUserCompetencySummary; | ||||
|     userCompetency: AddonCompetencyUserCompetencyPlan | AddonCompetencyUserCompetency | AddonCompetencyUserCompetencyCourse; | ||||
|     contextLevel: string; | ||||
|     contextInstanceId: number; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, navParams: NavParams, private translate: TranslateService, | ||||
|             private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider, | ||||
| @ -99,6 +101,15 @@ export class AddonCompetencyCompetencyPage { | ||||
| 
 | ||||
|         return promise.then((competency) => { | ||||
| 
 | ||||
|             // Calculate the context.
 | ||||
|             if (this.courseId) { | ||||
|                 this.contextLevel = 'course'; | ||||
|                 this.contextInstanceId = this.courseId; | ||||
|             } else { | ||||
|                 this.contextLevel = 'user'; | ||||
|                 this.contextInstanceId = this.userId || competency.usercompetencysummary.user.id; | ||||
|             } | ||||
| 
 | ||||
|             this.competency = competency.usercompetencysummary; | ||||
|             this.userCompetency = this.competency.usercompetencyplan || this.competency.usercompetency; | ||||
| 
 | ||||
| @ -155,6 +166,10 @@ export class AddonCompetencyCompetencyPage { | ||||
|     openCompetencySummary(competencyId: number): void { | ||||
|         // Decide which navCtrl to use. If this page is inside a split view, use the split view's master nav.
 | ||||
|         const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; | ||||
|         navCtrl.push('AddonCompetencyCompetencySummaryPage', {competencyId}); | ||||
|         navCtrl.push('AddonCompetencyCompetencySummaryPage', { | ||||
|             competencyId, | ||||
|             contextLevel: this.contextLevel, | ||||
|             contextInstanceId: this.contextInstanceId | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
|     <core-loading [hideUntil]="competencyLoaded"> | ||||
|         <ion-card *ngIf="competency"> | ||||
|             <ion-item text-wrap *ngIf="competency.competency.description"> | ||||
|                 <core-format-text [text]="competency.competency.description"></core-format-text> | ||||
|                 <core-format-text [text]="competency.competency.description" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"></core-format-text> | ||||
|             </ion-item> | ||||
|             <ion-item text-wrap> | ||||
|                 <strong>{{ 'addon.competency.path' | translate }}</strong> | ||||
|  | ||||
| @ -30,10 +30,14 @@ export class AddonCompetencyCompetencySummaryPage { | ||||
|     competencyLoaded = false; | ||||
|     competencyId: number; | ||||
|     competency: AddonCompetencySummary; | ||||
|     contextLevel: string; | ||||
|     contextInstanceId: number; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, navParams: NavParams, private domUtils: CoreDomUtilsProvider, | ||||
|             @Optional() private svComponent: CoreSplitViewComponent, private competencyProvider: AddonCompetencyProvider) { | ||||
|         this.competencyId = navParams.get('competencyId'); | ||||
|         this.contextLevel = navParams.get('contextLevel'); | ||||
|         this.contextInstanceId = navParams.get('contextInstanceId'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -57,8 +61,14 @@ export class AddonCompetencyCompetencySummaryPage { | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected fetchCompetency(): Promise<void> { | ||||
|         return this.competencyProvider.getCompetencySummary(this.competencyId).then((competency) => { | ||||
|             this.competency = competency; | ||||
|         return this.competencyProvider.getCompetencySummary(this.competencyId).then((result) => { | ||||
|             if (!this.contextLevel || typeof this.contextInstanceId == 'undefined') { | ||||
|                 // Context not specified, use user context.
 | ||||
|                 this.contextLevel = 'user'; | ||||
|                 this.contextInstanceId = result.usercompetency.userid; | ||||
|             } | ||||
| 
 | ||||
|             this.competency = result.competency; | ||||
|         }).catch((message) => { | ||||
|             this.domUtils.showErrorModalDefault(message, 'Error getting competency summary data.'); | ||||
|         }); | ||||
| @ -85,6 +95,10 @@ export class AddonCompetencyCompetencySummaryPage { | ||||
|     openCompetencySummary(competencyId: number): void { | ||||
|         // Decide which navCtrl to use. If this page is inside a split view, use the split view's master nav.
 | ||||
|         const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; | ||||
|         navCtrl.push('AddonCompetencyCompetencySummaryPage', {competencyId}); | ||||
|         navCtrl.push('AddonCompetencyCompetencySummaryPage', { | ||||
|             competencyId, | ||||
|             contextLevel: this.contextLevel, | ||||
|             contextInstanceId: this.contextInstanceId | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -11,13 +11,13 @@ | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item text-wrap> | ||||
|                 <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar> | ||||
|                 <h2><core-format-text [text]="user.fullname"></core-format-text></h2> | ||||
|                 <h2>{{ user.fullname }}</h2> | ||||
|             </ion-item> | ||||
|        </ion-card> | ||||
|         <ion-card *ngIf="plan"> | ||||
|             <ion-list> | ||||
|                 <ion-item text-wrap *ngIf="plan.plan.description"> | ||||
|                     <core-format-text [text]="plan.plan.description"></core-format-text> | ||||
|                     <core-format-text [text]="plan.plan.description" contextLevel="user" [contextInstanceId]="plan.plan.userid"></core-format-text> | ||||
|                 </ion-item> | ||||
|                 <ion-item text-wrap> | ||||
|                     <strong>{{ 'addon.competency.status' | translate }}</strong>: | ||||
|  | ||||
| @ -299,7 +299,7 @@ export class AddonCompetencyProvider { | ||||
|      * @return Promise to be resolved when the competency summary is retrieved. | ||||
|      */ | ||||
|     getCompetencySummary(competencyId: number, userId?: number, siteId?: string, ignoreCache?: boolean) | ||||
|             : Promise<AddonCompetencySummary> { | ||||
|             : Promise<AddonCompetencyUserCompetencySummary> { | ||||
| 
 | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
|             userId = userId || site.getUserId(); | ||||
| @ -324,7 +324,7 @@ export class AddonCompetencyProvider { | ||||
|                     .then((response: AddonCompetencyUserCompetencySummary): any => { | ||||
| 
 | ||||
|                 if (response.competency) { | ||||
|                     return response.competency; | ||||
|                     return response; | ||||
|                 } | ||||
| 
 | ||||
|                 return Promise.reject(null); | ||||
|  | ||||
| @ -17,6 +17,7 @@ import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/co | ||||
| import { CoreCourseProvider } from '@core/course/providers/course'; | ||||
| import { AddonCompetencyCourseComponent } from '../components/course/course'; | ||||
| import { AddonCompetencyProvider } from '../providers/competency'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Course nav handler. | ||||
| @ -26,7 +27,7 @@ export class AddonCompetencyCourseOptionHandler implements CoreCourseOptionsHand | ||||
|     name = 'AddonCompetency'; | ||||
|     priority = 300; | ||||
| 
 | ||||
|     constructor(private competencyProvider: AddonCompetencyProvider) {} | ||||
|     constructor(private competencyProvider: AddonCompetencyProvider, protected filterHelper: CoreFilterHelperProvider) {} | ||||
| 
 | ||||
|     /** | ||||
|      * Whether or not the handler is enabled ona site level. | ||||
| @ -110,6 +111,18 @@ export class AddonCompetencyCourseOptionHandler implements CoreCourseOptionsHand | ||||
| 
 | ||||
|                     promises.push(this.competencyProvider.getCompetencySummary(competency.competency.id, undefined, undefined, | ||||
|                             true)); | ||||
| 
 | ||||
|                     if (competency.coursemodules) { | ||||
|                         competency.coursemodules.forEach((module) => { | ||||
|                             promises.push(this.filterHelper.getFilters('module', module.id, {courseId: course.id})); | ||||
|                         }); | ||||
|                     } | ||||
| 
 | ||||
|                     if (competency.plans) { | ||||
|                         competency.plans.forEach((plan) => { | ||||
|                             promises.push(this.filterHelper.getFilters('user', plan.userid)); | ||||
|                         }); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|  | ||||
| @ -17,8 +17,8 @@ | ||||
|         <ion-card *ngIf="completion && tracked"> | ||||
|             <ion-item-divider>{{ 'addon.coursecompletion.requiredcriteria' | translate }}</ion-item-divider> | ||||
|             <ion-item class="hidden-tablet" text-wrap *ngFor="let criteria of completion.completions"> | ||||
|                 <h2><core-format-text clean="true" [text]="criteria.details.criteria"></core-format-text></h2> | ||||
|                 <p><core-format-text clean="true" [text]="criteria.details.requirement"></core-format-text></p> | ||||
|                 <h2><core-format-text clean="true" [text]="criteria.details.criteria" [filter]="false"></core-format-text></h2> | ||||
|                 <p><core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false"></core-format-text></p> | ||||
|                 <strong item-end>{{ criteria.status }}</strong> | ||||
|             </ion-item> | ||||
|             <ion-item class="hidden-phone" text-wrap> | ||||
| @ -31,10 +31,10 @@ | ||||
|                     <ion-col><strong>{{ 'addon.coursecompletion.completiondate' | translate }}</strong></ion-col> | ||||
|                 </ion-row> | ||||
|                 <ion-row *ngFor="let criteria of completion.completions"> | ||||
|                     <ion-col><core-format-text clean="true" [text]="criteria.title"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text clean="true" [text]="criteria.details.criteria"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text clean="true" [text]="criteria.details.requirement"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text [text]="criteria.details.status"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text clean="true" [text]="criteria.title" [filter]="false"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text clean="true" [text]="criteria.details.criteria" [filter]="false"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false"></core-format-text></ion-col> | ||||
|                     <ion-col><core-format-text [text]="criteria.details.status" [filter]="false"></core-format-text></ion-col> | ||||
|                     <ion-col>{{ criteria.status }}</ion-col> | ||||
|                     <ion-col *ngIf="criteria.timecompleted">{{ criteria.timecompleted * 1000 | coreFormatDate :'strftimedatetimeshort' }}</ion-col> | ||||
|                     <ion-col *ngIf="!criteria.timecompleted"></ion-col> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title>{{ title }}</ion-title> | ||||
|     </ion-navbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
							
								
								
									
										34
									
								
								src/addon/filter/activitynames/activitynames.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/activitynames/activitynames.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterActivityNamesHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterActivityNamesHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterActivityNamesModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterActivityNamesHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/activitynames/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/activitynames/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Activity names filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterActivityNamesHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterActivityNamesHandler'; | ||||
|     filterName = 'activitynames'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/algebra/algebra.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/algebra/algebra.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterAlgebraHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterAlgebraHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterAlgebraModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterAlgebraHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/algebra/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/algebra/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Algebra notation filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterAlgebraHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterAlgebraHandler'; | ||||
|     filterName = 'algebra'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/censor/censor.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/censor/censor.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterCensorHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterCensorHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterCensorModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterCensorHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/censor/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/censor/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Word censorship filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterCensorHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterCensorHandler'; | ||||
|     filterName = 'censor'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/data/data.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/data/data.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterDataHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterDataHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterDataModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterDataHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/data/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/data/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Database auto-link filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterDataHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterDataHandler'; | ||||
|     filterName = 'data'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/emailprotect/emailprotect.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/emailprotect/emailprotect.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterEmailProtectHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterEmailProtectHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterEmailProtectModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterEmailProtectHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/emailprotect/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/emailprotect/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Email protection filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterEmailProtectHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterEmailProtectHandler'; | ||||
|     filterName = 'emailprotect'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/emoticon/emoticon.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/emoticon/emoticon.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterEmoticonHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterEmoticonHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterEmoticonModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterEmoticonHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/emoticon/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/emoticon/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Emoticon filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterEmoticonHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterEmoticonHandler'; | ||||
|     filterName = 'emoticon'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										49
									
								
								src/addon/filter/filter.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/addon/filter/filter.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { AddonFilterActivityNamesModule } from './activitynames/activitynames.module'; | ||||
| import { AddonFilterAlgebraModule } from './algebra/algebra.module'; | ||||
| import { AddonFilterCensorModule } from './censor/censor.module'; | ||||
| import { AddonFilterDataModule } from './data/data.module'; | ||||
| import { AddonFilterEmailProtectModule } from './emailprotect/emailprotect.module'; | ||||
| import { AddonFilterEmoticonModule } from './emoticon/emoticon.module'; | ||||
| import { AddonFilterGlossaryModule } from './glossary/glossary.module'; | ||||
| import { AddonFilterMediaPluginModule } from './mediaplugin/mediaplugin.module'; | ||||
| import { AddonFilterMultilangModule } from './multilang/multilang.module'; | ||||
| import { AddonFilterTexModule } from './tex/tex.module'; | ||||
| import { AddonFilterTidyModule } from './tidy/tidy.module'; | ||||
| import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [], | ||||
|     imports: [ | ||||
|         AddonFilterActivityNamesModule, | ||||
|         AddonFilterAlgebraModule, | ||||
|         AddonFilterCensorModule, | ||||
|         AddonFilterDataModule, | ||||
|         AddonFilterEmailProtectModule, | ||||
|         AddonFilterEmoticonModule, | ||||
|         AddonFilterGlossaryModule, | ||||
|         AddonFilterMediaPluginModule, | ||||
|         AddonFilterMultilangModule, | ||||
|         AddonFilterTexModule, | ||||
|         AddonFilterTidyModule, | ||||
|         AddonFilterUrlToLinkModule | ||||
|     ], | ||||
|     providers: [ | ||||
|     ], | ||||
|     exports: [] | ||||
| }) | ||||
| export class AddonFilterModule { } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/glossary/glossary.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/glossary/glossary.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterGlossaryHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterGlossaryHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterGlossaryModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterGlossaryHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/glossary/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/glossary/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Glossary auto-link filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterGlossaryHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterGlossaryHandler'; | ||||
|     filterName = 'glossary'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/mediaplugin/mediaplugin.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/mediaplugin/mediaplugin.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterMediaPluginHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterMediaPluginHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterMediaPluginModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterMediaPluginHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										139
									
								
								src/addon/filter/mediaplugin/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/addon/filter/mediaplugin/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Multimedia filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterMediaPluginHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterMediaPluginHandler'; | ||||
|     filterName = 'mediaplugin'; | ||||
| 
 | ||||
|     constructor(private textUtils: CoreTextUtilsProvider) { | ||||
|         super(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string) | ||||
|             : string | Promise<string> { | ||||
| 
 | ||||
|         const div = document.createElement('div'); | ||||
|         div.innerHTML = text; | ||||
| 
 | ||||
|         const videos = Array.from(div.querySelectorAll('video')); | ||||
| 
 | ||||
|         videos.forEach((video) => { | ||||
|             this.treatVideoFilters(video); | ||||
|         }); | ||||
| 
 | ||||
|         return div.innerHTML; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Treat video filters. Currently only treating youtube video using video JS. | ||||
|      * | ||||
|      * @param el Video element. | ||||
|      * @param navCtrl NavController to use. | ||||
|      */ | ||||
|     protected treatVideoFilters(video: HTMLElement): void { | ||||
|         // Treat Video JS Youtube video links and translate them to iframes.
 | ||||
|         if (!video.classList.contains('video-js')) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const data = this.textUtils.parseJSON(video.getAttribute('data-setup') || video.getAttribute('data-setup-lazy') || '{}'), | ||||
|             youtubeData = data.techOrder && data.techOrder[0] && data.techOrder[0] == 'youtube' && | ||||
|                     this.parseYoutubeUrl(data.sources && data.sources[0] && data.sources[0].src); | ||||
| 
 | ||||
|         if (!youtubeData || !youtubeData.videoId) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const iframe = document.createElement('iframe'); | ||||
|         iframe.id = video.id; | ||||
|         iframe.src = 'https://www.youtube.com/embed/' + youtubeData.videoId; // Don't apply other params to align with Moodle web.
 | ||||
|         iframe.setAttribute('frameborder', '0'); | ||||
|         iframe.setAttribute('allowfullscreen', '1'); | ||||
|         iframe.width = '100%'; | ||||
|         iframe.height = '300'; | ||||
| 
 | ||||
|         // Replace video tag by the iframe.
 | ||||
|         video.parentNode.replaceChild(iframe, video); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Parse a YouTube URL. | ||||
|      * Based on Youtube.parseUrl from Moodle media/player/videojs/amd/src/Youtube-lazy.js | ||||
|      * | ||||
|      * @param url URL of the video. | ||||
|      * @return Data of the video. | ||||
|      */ | ||||
|     protected parseYoutubeUrl(url: string): {videoId: string, listId?: string, start?: number} { | ||||
|         const result = { | ||||
|             videoId: null, | ||||
|             listId: null, | ||||
|             start: null | ||||
|         }; | ||||
| 
 | ||||
|         if (!url) { | ||||
|             return result; | ||||
|         } | ||||
| 
 | ||||
|         url = this.textUtils.decodeHTML(url); | ||||
| 
 | ||||
|         // Get the video ID.
 | ||||
|         let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/); | ||||
| 
 | ||||
|         if (match && match[2].length === 11) { | ||||
|             result.videoId = match[2]; | ||||
|         } | ||||
| 
 | ||||
|         // Now get the playlist (if any).
 | ||||
|         match = url.match(/[?&]list=([^#\&\?]+)/); | ||||
| 
 | ||||
|         if (match && match[1]) { | ||||
|             result.listId = match[1]; | ||||
|         } | ||||
| 
 | ||||
|         // Now get the start time (if any).
 | ||||
|         match = url.match(/[?&]start=(\d+)/); | ||||
| 
 | ||||
|         if (match && match[1]) { | ||||
|             result.start = parseInt(match[1], 10); | ||||
|         } else { | ||||
|             // No start param, but it could have a time param.
 | ||||
|             match = url.match(/[?&]t=(\d+h)?(\d+m)?(\d+s)?/); | ||||
|             if (match) { | ||||
|                 result.start = (match[1] ? parseInt(match[1], 10) * 3600 : 0) + (match[2] ? parseInt(match[2], 10) * 60 : 0) + | ||||
|                         (match[3] ? parseInt(match[3], 10) : 0); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/multilang/multilang.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/multilang/multilang.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterMultilangHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterMultilangHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterMultilangModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterMultilangHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										93
									
								
								src/addon/filter/multilang/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/addon/filter/multilang/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreLangProvider } from '@providers/lang'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Multilang filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterMultilangHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterMultilangHandler'; | ||||
|     filterName = 'multilang'; | ||||
| 
 | ||||
|     constructor(private langProvider: CoreLangProvider, | ||||
|             private sitesProvider: CoreSitesProvider) { | ||||
|         super(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string) | ||||
|             : string | Promise<string> { | ||||
| 
 | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
| 
 | ||||
|             // Don't apply this filter if Moodle is 3.7 or higher and the WS already filtered the content.
 | ||||
|             if (!this.shouldBeApplied(options, site)) { | ||||
|                 return text; | ||||
|             } | ||||
| 
 | ||||
|             return this.langProvider.getCurrentLanguage().then((language) => { | ||||
|                 // Match the current language.
 | ||||
|                 const anyLangRegEx = /<(?:lang|span)[^>]+lang="[a-zA-Z0-9_-]+"[^>]*>(.*?)<\/(?:lang|span)>/g; | ||||
|                 let currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', 'g'); | ||||
| 
 | ||||
|                 if (!text.match(currentLangRegEx)) { | ||||
|                     // Current lang not found. Try to find the first language.
 | ||||
|                     const matches = text.match(anyLangRegEx); | ||||
|                     if (matches && matches[0]) { | ||||
|                         language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)[1]; | ||||
|                         currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', | ||||
|                                 'g'); | ||||
|                     } else { | ||||
|                         // No multi-lang tag found, stop.
 | ||||
|                         return text; | ||||
|                     } | ||||
|                 } | ||||
|                 // Extract contents of current language.
 | ||||
|                 text = text.replace(currentLangRegEx, '$1'); | ||||
|                 // Delete the rest of languages
 | ||||
|                 text = text.replace(anyLangRegEx, ''); | ||||
| 
 | ||||
|                 return text; | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // The filter should be applied if site is older than 3.7 or the WS didn't filter the text.
 | ||||
|         return options.wsNotFiltered || !site.isVersionGreaterEqualThan('3.7'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/tex/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/tex/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the TeX notation filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterTexHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterTexHandler'; | ||||
|     filterName = 'tex'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/tex/tex.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/tex/tex.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterTexHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterTexHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterTexModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterTexHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/tidy/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/tidy/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the HTML tidy filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterTidyHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterTidyHandler'; | ||||
|     filterName = 'tidy'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/tidy/tidy.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/tidy/tidy.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterTidyHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterTidyHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterTidyModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterTidyHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/addon/filter/urltolink/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/filter/urltolink/providers/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| 
 | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the URL to link and images filter. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonFilterUrlToLinkHandler extends CoreFilterDefaultHandler { | ||||
|     name = 'AddonFilterUrlToLinkHandler'; | ||||
|     filterName = 'urltolink'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/addon/filter/urltolink/urltolink.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addon/filter/urltolink/urltolink.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { IonicModule } from 'ionic-angular'; | ||||
| import { CoreFilterDelegate } from '@core/filter/providers/delegate'; | ||||
| import { AddonFilterUrlToLinkHandler } from './providers/handler'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|         IonicModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         AddonFilterUrlToLinkHandler | ||||
|     ] | ||||
| }) | ||||
| export class AddonFilterUrlToLinkModule { | ||||
|     constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterUrlToLinkHandler) { | ||||
|         filterDelegate.registerHandler(handler); | ||||
|     } | ||||
| } | ||||
| @ -7,7 +7,7 @@ | ||||
|             <a ion-item text-wrap *ngFor="let contact of contacts" [title]="contact.fullname" (click)="selectUser(contact.id)" [class.core-split-item-selected]="contact.id == selectedUserId" class="addon-messages-conversation-item"> | ||||
|                 <ion-avatar item-start core-user-avatar [user]="contact" [checkOnline]="contact.showonlinestatus" [linkProfile]="false"></ion-avatar> | ||||
|                 <h2> | ||||
|                     <core-format-text [text]="contact.fullname"></core-format-text> | ||||
|                     {{ contact.fullname }} | ||||
|                     <core-icon *ngIf="contact.isblocked" name="fa-ban" item-end></core-icon> | ||||
|                 </h2> | ||||
|             </a> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|         <ion-list no-margin> | ||||
|             <a ion-item text-wrap *ngFor="let request of requests" [title]="request.fullname" (click)="selectUser(request.id)" [class.core-split-item-selected]="request.id == selectedUserId" class="addon-messages-conversation-item"> | ||||
|                 <ion-avatar item-start core-user-avatar [user]="request" [linkProfile]="false"></ion-avatar> | ||||
|                 <h2><core-format-text [text]="request.fullname"></core-format-text></h2> | ||||
|                 <h2>{{ request.fullname }}</h2> | ||||
|                 <p *ngIf="!request.iscontact && !request.confirmedOrDeclined">{{ 'addon.messages.wouldliketocontactyou' | translate }}</p> | ||||
|             </a> | ||||
|         </ion-list> | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
|                     <!-- Don't show deleted users --> | ||||
|                     <a ion-item text-wrap *ngIf="contact.profileimageurl || contact.profileimageurlsmall"  [title]="contact.fullname" (click)="gotoDiscussion(contact.id)" [class.core-split-item-selected]="contact.id == discussionUserId" class="addon-messages-conversation-item"> | ||||
|                         <ion-avatar core-user-avatar [user]="contact" item-start [checkOnline]="contact.showonlinestatus"></ion-avatar> | ||||
|                         <h2><core-format-text [text]="contact.fullname"></core-format-text></h2> | ||||
|                         <h2>{{ contact.fullname }}</h2> | ||||
|                     </a> | ||||
|                 </ng-container> | ||||
|             </ng-container> | ||||
|  | ||||
| @ -14,22 +14,20 @@ | ||||
|             </ion-item-divider> | ||||
|             <a ion-item text-wrap *ngFor="let result of search.results" [title]="result.fullname" (click)="gotoDiscussion(result.userid, result.messageid)" [class.core-split-item-selected]="result.userid == discussionUserId" class="addon-message-discussion"> | ||||
|                 <ion-avatar core-user-avatar [user]="result" item-start [checkOnline]="result.showonlinestatus"></ion-avatar> | ||||
|                 <h2><core-format-text [text]="result.fullname"></core-format-text></h2> | ||||
|                 <p><core-format-text clean="true" singleLine="true" [text]="result.lastmessage"></core-format-text></p> | ||||
|                 <h2>{{ result.fullname }}</h2> | ||||
|                 <p><core-format-text clean="true" singleLine="true" [text]="result.lastmessage" contextLevel="system" [contextInstanceId]="0"></core-format-text></p> | ||||
|             </a> | ||||
|         </ion-list> | ||||
| 
 | ||||
|         <ion-list *ngIf="!search.showResults" no-margin> | ||||
|             <a ion-item text-wrap *ngFor="let discussion of discussions" [title]="discussion.fullname" (click)="gotoDiscussion(discussion.message.user)" [class.core-split-item-selected]="discussion.message.user == discussionUserId" class="addon-message-discussion"> | ||||
|                 <ion-avatar core-user-avatar [user]="discussion" item-start [checkOnline]="discussion.showonlinestatus"></ion-avatar> | ||||
|                 <h2> | ||||
|                     <core-format-text [text]="discussion.fullname"></core-format-text> | ||||
|                 </h2> | ||||
|                 <h2>{{ discussion.fullname }}</h2> | ||||
|                 <ion-note *ngIf="discussion.message.timecreated > 0 || discussion.unread"> | ||||
|                     <span *ngIf="discussion.unread" class="core-primary-circle"></span> | ||||
|                     <span *ngIf="discussion.message.timecreated > 0">{{discussion.message.timecreated / 1000 | coreDateDayOrTime}}</span> | ||||
|                 </ion-note> | ||||
|                 <p><core-format-text clean="true" singleLine="true" [text]="discussion.message.message"></core-format-text></p> | ||||
|                 <p><core-format-text clean="true" singleLine="true" [text]="discussion.message.message" contextLevel="system" [contextInstanceId]="0"></core-format-text></p> | ||||
|             </a> | ||||
|         </ion-list> | ||||
| 
 | ||||
|  | ||||
| @ -18,15 +18,15 @@ | ||||
|             <div class="item-avatar-center"> | ||||
|                 <img class="avatar" [src]="conversation.imageurl" core-external-content [alt]="conversation.name" role="presentation" onError="this.src='assets/img/group-avatar.png'"> | ||||
|             </div> | ||||
|             <h2><core-format-text [text]="conversation.name"></core-format-text></h2> | ||||
|             <p><core-format-text *ngIf="conversation.subname" [text]="conversation.subname"></core-format-text></p> | ||||
|             <h2><core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0"></core-format-text></h2> | ||||
|             <p><core-format-text *ngIf="conversation.subname" [text]="conversation.subname" contextLevel="system" [contextInstanceId]="0"></core-format-text></p> | ||||
|             <p>{{ 'addon.messages.numparticipants' | translate:{$a: conversation.membercount} }}</p> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <a ion-item text-wrap *ngFor="let member of members" (click)="closeModal(member.id)" class="addon-messages-conversation-item"> | ||||
|             <ion-avatar core-user-avatar [user]="member" [linkProfile]="false" [checkOnline]="member.showonlinestatus" item-start></ion-avatar> | ||||
|             <h2> | ||||
|                 <core-format-text [text]="member.fullname"></core-format-text> | ||||
|                 {{ member.fullname }} | ||||
|                 <core-icon name="fa-ban" *ngIf="member.isblocked" [label]="'addon.messages.contactblocked' | translate"></core-icon> | ||||
|             </h2> | ||||
|         </a> | ||||
|  | ||||
| @ -18,6 +18,7 @@ import { | ||||
|     AddonMessagesProvider, AddonMessagesConversationFormatted, AddonMessagesConversationMember | ||||
| } from '../../providers/messages'; | ||||
| import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays the list of conversations, including group conversations. | ||||
| @ -38,7 +39,7 @@ export class AddonMessagesConversationInfoPage implements OnInit { | ||||
|     protected conversationId: number; | ||||
| 
 | ||||
|     constructor(private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams, | ||||
|             protected viewCtrl: ViewController) { | ||||
|             protected viewCtrl: ViewController, sitesProvider: CoreSitesProvider) { | ||||
|         this.conversationId = navParams.get('conversationId'); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|         <ion-title> | ||||
|             <img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [src]="conversationImage" [alt]="title" onError="this.src='assets/img/group-avatar.png'" core-external-content role="presentation" [siteId]="siteId || null"> | ||||
|             <ion-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" core-user-avatar [user]="otherMember" [linkProfile]="false" [checkOnline]="otherMember.showonlinestatus" item-start (click)="showInfo && viewInfo()"></ion-avatar> | ||||
|             <core-format-text [text]="title" (click)="showInfo && !isGroup && viewInfo()"></core-format-text> | ||||
|             <core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0" (click)="showInfo && !isGroup && viewInfo()"></core-format-text> | ||||
|             <core-icon *ngIf="conversation && conversation.isfavourite" name="fa-star" [label]="'core.favourites' | translate"></core-icon> | ||||
|             <core-icon *ngIf="conversation && conversation.ismuted" name="volume-off" [label]="'addon.messages.mutedconversation' | translate"></core-icon> | ||||
|         </ion-title> | ||||
| @ -58,7 +58,7 @@ | ||||
| 
 | ||||
|                     <!-- Some messages have <p> and some others don't. Add a <p> so they all have same styles. --> | ||||
|                     <p class="addon-message-text"> | ||||
|                         <core-format-text (afterRender)="last && scrollToBottom()" [text]="message.text"></core-format-text> | ||||
|                         <core-format-text (afterRender)="last && scrollToBottom()" [text]="message.text" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|                     </p> | ||||
| 
 | ||||
|                     <button ion-button icon-only clear="true" *ngIf="!message.sending && showDelete" (click)="deleteMessage(message, index)" class="addon-messages-delete-button" [@coreSlideInOut]="'fromRight'" [attr.aria-label]=" 'addon.messages.deletemessage' | translate"> | ||||
|  | ||||
| @ -99,7 +99,7 @@ | ||||
|         <ion-avatar *ngIf="conversation.type != typeGroup" core-user-avatar [user]="conversation.otherUser" [linkProfile]="false" [checkOnline]="conversation.showonlinestatus" item-start></ion-avatar> | ||||
| 
 | ||||
|         <h2> | ||||
|             <core-format-text [text]="conversation.name"></core-format-text> | ||||
|             <core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|             <core-icon name="fa-ban" *ngIf="conversation.isblocked" [label]="'addon.messages.contactblocked' | translate"></core-icon> | ||||
|             <core-icon *ngIf="conversation.ismuted" name="volume-off" [label]="'addon.messages.mutedconversation' | translate"></core-icon> | ||||
|         </h2> | ||||
| @ -107,11 +107,11 @@ | ||||
|             <ion-badge *ngIf="conversation.unreadcount > 0">{{ conversation.unreadcount }}</ion-badge> | ||||
|             <span *ngIf="conversation.lastmessagedate > 0">{{conversation.lastmessagedate | coreDateDayOrTime}}</span> | ||||
|         </ion-note> | ||||
|         <p *ngIf="conversation.subname"><core-format-text [text]="conversation.subname"></core-format-text></p> | ||||
|         <p *ngIf="conversation.subname"><core-format-text [text]="conversation.subname" contextLevel="system" [contextInstanceId]="0"></core-format-text></p> | ||||
|         <p class="addon-message-last-message"> | ||||
|             <span *ngIf="conversation.sentfromcurrentuser" class="addon-message-last-message-user">{{ 'addon.messages.you' | translate }}</span> | ||||
|             <core-format-text *ngIf="!conversation.sentfromcurrentuser && conversation.type == typeGroup && conversation.members[0]" [text]="conversation.members[0].fullname + ':'" class="addon-message-last-message-user"></core-format-text> | ||||
|             <core-format-text clean="true" singleLine="true" [text]="conversation.lastmessage" class="addon-message-last-message-text"></core-format-text> | ||||
|             <span *ngIf="!conversation.sentfromcurrentuser && conversation.type == typeGroup && conversation.members[0]" class="addon-message-last-message-user">{{ conversation.members[0].fullname + ':' }}</span> | ||||
|             <core-format-text clean="true" singleLine="true" [text]="conversation.lastmessage" class="addon-message-last-message-text" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|         </p> | ||||
|     </a> | ||||
| </ng-template> | ||||
|  | ||||
| @ -33,7 +33,7 @@ | ||||
|         <a ion-item text-wrap *ngFor="let result of item.results" [title]="result.fullname" (click)="openConversation(result)" [class.core-split-item-selected]="result == selectedResult" class="addon-message-discussion"> | ||||
|             <ion-avatar item-start core-user-avatar [user]="result" [checkOnline]="true" [linkProfile]="false"></ion-avatar> | ||||
|             <h2> | ||||
|                 <core-format-text [text]="result.fullname" [highlight]="result.highlightName"></core-format-text> | ||||
|                 <core-format-text [text]="result.fullname" [highlight]="result.highlightName" [filter]="false"></core-format-text> | ||||
|                 <core-icon name="fa-ban" *ngIf="result.isblocked" [label]="'addon.messages.contactblocked' | translate"></core-icon> | ||||
|             </h2> | ||||
|             <ion-note *ngIf="result.lastmessagedate > 0"> | ||||
| @ -41,7 +41,7 @@ | ||||
|             </ion-note> | ||||
|             <p class="addon-message-last-message"> | ||||
|                 <span *ngIf="result.sentfromcurrentuser" class="addon-message-last-message-user">{{ 'addon.messages.you' | translate }}</span> | ||||
|                 <core-format-text clean="true" singleLine="true" [text]="result.lastmessage" [highlight]="result.highlightMessage" class="addon-message-last-message-text"></core-format-text> | ||||
|                 <core-format-text clean="true" singleLine="true" [text]="result.lastmessage" [highlight]="result.highlightMessage" contextLevel="system" [contextInstanceId]="0" class="addon-message-last-message-text"></core-format-text> | ||||
|             </p> | ||||
|         </a> | ||||
| 
 | ||||
|  | ||||
| @ -19,12 +19,12 @@ import { CoreCronHandler } from '@providers/cron'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreEventsProvider } from '@providers/events'; | ||||
| import { CoreAppProvider } from '@providers/app'; | ||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; | ||||
| import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications'; | ||||
| import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate'; | ||||
| import { CoreEmulatorHelperProvider } from '@core/emulator/providers/helper'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to inject an option into main menu. | ||||
| @ -49,7 +49,7 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr | ||||
| 
 | ||||
|     constructor(private messagesProvider: AddonMessagesProvider, private sitesProvider: CoreSitesProvider, | ||||
|             eventsProvider: CoreEventsProvider, private appProvider: CoreAppProvider, | ||||
|             private localNotificationsProvider: CoreLocalNotificationsProvider, private textUtils: CoreTextUtilsProvider, | ||||
|             private localNotificationsProvider: CoreLocalNotificationsProvider, private filterHelper: CoreFilterHelperProvider, | ||||
|             private pushNotificationsProvider: CorePushNotificationsProvider, utils: CoreUtilsProvider, | ||||
|             pushNotificationsDelegate: CorePushNotificationsDelegate, private emulatorHelper: CoreEmulatorHelperProvider) { | ||||
| 
 | ||||
| @ -297,7 +297,7 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr | ||||
|             title: message.name || message.userfromfullname, | ||||
|         }; | ||||
| 
 | ||||
|         return this.textUtils.formatText(message.text, true, true).catch(() => { | ||||
|         return this.filterHelper.getFiltersAndFormatText(message.text, 'system', 0, {clean: true, singleLine: true}).catch(() => { | ||||
|             return message.text; | ||||
|         }).then((formattedText) => { | ||||
|             data['text'] = formattedText; | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|                 {{ 'addon.mod_assign.feedbacknotsupported' | translate }} | ||||
|             </ion-badge> | ||||
|             <p *ngIf="text"> | ||||
|                 <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text"></core-format-text> | ||||
|                 <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"></core-format-text> | ||||
|             </p> | ||||
|             <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true"></core-file> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
|     <!-- Description and intro attachments. --> | ||||
|     <ion-card *ngIf="description" (click)="expandDescription($event)"> | ||||
|         <ion-item text-wrap> | ||||
|             <core-format-text [text]="description" [component]="component" [componentId]="componentId" maxHeight="120" (click)="expandDescription($event)"></core-format-text> | ||||
|             <core-format-text [text]="description" [component]="component" [componentId]="componentId" maxHeight="120" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" (click)="expandDescription($event)"></core-format-text> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|  | ||||
| @ -134,7 +134,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo | ||||
| 
 | ||||
|         if (this.assign && (this.description || this.assign.introattachments)) { | ||||
|             this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, | ||||
|                     this.module.id, this.assign.introattachments); | ||||
|                     this.module.id, this.assign.introattachments, true, 'module', this.module.id, this.courseId); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|                 {{ 'addon.mod_assign.submissionnotsupported' | translate }} | ||||
|             </ion-badge> | ||||
|             <p *ngIf="text"> | ||||
|                 <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text"></core-format-text> | ||||
|                 <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"></core-format-text> | ||||
|             </p> | ||||
|             <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true"></core-file> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| 
 | ||||
|                 <ion-item text-wrap *ngIf="timeRemaining" [ngClass]="[timeRemainingClass]"> | ||||
|                     <h2>{{ 'addon.mod_assign.timeremaining' | translate }}</h2> | ||||
|                     <p><core-format-text [text]="timeRemaining"></core-format-text></p> | ||||
|                     <p [innerHTML]="timeRemaining"></p> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <ion-item text-wrap *ngIf="fromDate && !isSubmittedForGrading"> | ||||
| @ -91,7 +91,7 @@ | ||||
|                 <!-- Submit for grading form. --> | ||||
|                 <div *ngIf="canSubmit"> | ||||
|                     <ion-item text-wrap *ngIf="submissionStatement"> | ||||
|                         <ion-label><core-format-text [text]="submissionStatement"></core-format-text></ion-label> | ||||
|                         <ion-label><core-format-text [text]="submissionStatement" [filter]="false"></core-format-text></ion-label> | ||||
|                         <ion-checkbox item-end name="submissionstatement" [(ngModel)]="submitModel.submissionStatement"> | ||||
|                         </ion-checkbox> | ||||
|                     </ion-item> | ||||
| @ -115,7 +115,7 @@ | ||||
|                             <h2>{{ user.fullname }}</h2> | ||||
|                         </a> | ||||
|                         <ion-item text-wrap *ngIf="!user.fullname"> | ||||
|                             {{ 'addon.mod_assign.hiddenuser' | translate }} <core-format-text [text]="user"></core-format-text> | ||||
|                             {{ 'addon.mod_assign.hiddenuser' | translate }} {{ user }} | ||||
|                         </ion-item> | ||||
|                     </div> | ||||
|                 </ion-item> | ||||
| @ -140,7 +140,7 @@ | ||||
|                 <!-- Current grade if method is advanced. --> | ||||
|                 <ion-item text-wrap *ngIf="feedback.gradefordisplay && (!isGrading || grade.method != 'simple')" class="core-grading-summary"> | ||||
|                     <h2>{{ 'addon.mod_assign.currentgrade' | translate }}</h2> | ||||
|                     <p><core-format-text [text]="feedback.gradefordisplay"></core-format-text></p> | ||||
|                     <p><core-format-text [text]="feedback.gradefordisplay" [filter]="false"></core-format-text></p> | ||||
|                     <a ion-button item-end icon-only *ngIf="feedback.advancedgrade" (click)="showAdvancedGrade()"> | ||||
|                         <ion-icon name="search"></ion-icon> | ||||
|                     </a> | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| <ion-item text-wrap *ngIf="(text || canEdit) && !edit"> | ||||
|     <h2>{{ plugin.name }}</h2> | ||||
|     <p> | ||||
|         <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text"></core-format-text> | ||||
|         <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"></core-format-text> | ||||
|     </p> | ||||
|     <div item-end> | ||||
|         <div text-end> | ||||
|  | ||||
| @ -65,7 +65,8 @@ export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedb | ||||
| 
 | ||||
|                     if (this.text) { | ||||
|                         // Open a new state with the text.
 | ||||
|                         this.textUtils.expandText(this.plugin.name, this.text, this.component, this.assign.cmid); | ||||
|                         this.textUtils.expandText(this.plugin.name, this.text, this.component, this.assign.cmid, undefined, true, | ||||
|                                 'module', this.assign.cmid, this.assign.course); | ||||
|                     } | ||||
|                 }); | ||||
|             } else if (this.edit) { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="plugin.name"></core-format-text></ion-title> | ||||
|         <ion-title>{{ plugin.name }}</ion-title> | ||||
|         <ion-buttons end> | ||||
|             <button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="close"></ion-icon> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end> | ||||
|             <button ion-button clear (click)="save()" [attr.aria-label]="'core.save' | translate"> | ||||
| @ -16,7 +16,7 @@ | ||||
|             <form name="addon-mod_assign-edit-form" *ngIf="userSubmission && userSubmission.plugins && userSubmission.plugins.length"> | ||||
|                 <!-- Submission statement. --> | ||||
|                 <ion-item text-wrap *ngIf="submissionStatement"> | ||||
|                     <ion-label><core-format-text [text]="submissionStatement"></core-format-text></ion-label> | ||||
|                     <ion-label><core-format-text [text]="submissionStatement" [filter]="false"></core-format-text></ion-label> | ||||
|                     <ion-checkbox item-end name="submissionstatement" [(ngModel)]="submissionStatementAccepted"></ion-checkbox> | ||||
| 
 | ||||
|                     <!-- ion-checkbox doesn't use an input. Create a hidden input to hold the value. --> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId"  [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end></ion-buttons> | ||||
|     </ion-navbar> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end></ion-buttons> | ||||
|     </ion-navbar> | ||||
|  | ||||
| @ -31,6 +31,7 @@ import { AddonModAssignHelperProvider, AddonModAssignSubmissionFormatted } from | ||||
| import { AddonModAssignSyncProvider } from './assign-sync'; | ||||
| import { AddonModAssignFeedbackDelegate } from './feedback-delegate'; | ||||
| import { AddonModAssignSubmissionDelegate } from './submission-delegate'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch assigns. | ||||
| @ -42,16 +43,26 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan | ||||
|     component = AddonModAssignProvider.COMPONENT; | ||||
|     updatesNames = /^configuration$|^.*files$|^submissions$|^grades$|^gradeitems$|^outcomes$|^comments$/; | ||||
| 
 | ||||
|     constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, protected assignProvider: AddonModAssignProvider, | ||||
|             protected textUtils: CoreTextUtilsProvider, protected feedbackDelegate: AddonModAssignFeedbackDelegate, | ||||
|             protected submissionDelegate: AddonModAssignSubmissionDelegate, protected courseHelper: CoreCourseHelperProvider, | ||||
|             protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider, | ||||
|             protected userProvider: CoreUserProvider, protected assignHelper: AddonModAssignHelperProvider, | ||||
|     constructor(translate: TranslateService, | ||||
|             appProvider: CoreAppProvider, | ||||
|             utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, | ||||
|             filepoolProvider: CoreFilepoolProvider, | ||||
|             sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, | ||||
|             filterHelper: CoreFilterHelperProvider, | ||||
|             protected assignProvider: AddonModAssignProvider, | ||||
|             protected textUtils: CoreTextUtilsProvider, | ||||
|             protected feedbackDelegate: AddonModAssignFeedbackDelegate, | ||||
|             protected submissionDelegate: AddonModAssignSubmissionDelegate, | ||||
|             protected courseHelper: CoreCourseHelperProvider, | ||||
|             protected groupsProvider: CoreGroupsProvider, | ||||
|             protected gradesHelper: CoreGradesHelperProvider, | ||||
|             protected userProvider: CoreUserProvider, | ||||
|             protected assignHelper: AddonModAssignHelperProvider, | ||||
|             protected syncProvider: AddonModAssignSyncProvider) { | ||||
| 
 | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <a *ngIf="commentsEnabled" ion-item text-wrap (click)="showComments($event)" detail-none> | ||||
|     <h2>{{plugin.name}}</h2> | ||||
|     <core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" [itemId]="submission.id" area="submission_comments" [title]="plugin.name"></core-comments> | ||||
|     <core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" [itemId]="submission.id" area="submission_comments" [title]="plugin.name" [courseId]="assign.course"></core-comments> | ||||
| </a> | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|     <h2>{{ plugin.name }}</h2> | ||||
|     <p *ngIf="words">{{ 'addon.mod_assign.numwords' | translate: {'$a': words} }}</p> | ||||
|     <p> | ||||
|         <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text"></core-format-text> | ||||
|         <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"></core-format-text> | ||||
|     </p> | ||||
| </ion-item> | ||||
| 
 | ||||
|  | ||||
| @ -75,7 +75,8 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS | ||||
| 
 | ||||
|                     if (text) { | ||||
|                         // Open a new state with the interpolated contents.
 | ||||
|                         this.textUtils.expandText(this.plugin.name, text, this.component, this.assign.cmid); | ||||
|                         this.textUtils.expandText(this.plugin.name, text, this.component, this.assign.cmid, undefined, true, | ||||
|                                 'module', this.assign.cmid, this.assign.course); | ||||
|                     } | ||||
|                 }); | ||||
|             } else { | ||||
|  | ||||
| @ -16,11 +16,11 @@ | ||||
| <!-- Content. --> | ||||
| <core-loading [hideUntil]="loaded" class="core-loading-center"> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description> | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description> | ||||
| 
 | ||||
|     <div padding class="safe-padding-horizontal"> | ||||
|         <core-navigation-bar [previous]="previousChapter > 0 && previousChapter" [next]="nextChapter > 0 && nextChapter" (action)="changeChapter($event)"></core-navigation-bar> | ||||
|         <core-format-text [component]="component" [componentId]="componentId" [text]="chapterContent"></core-format-text> | ||||
|         <core-format-text [component]="component" [componentId]="componentId" [text]="chapterContent" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text> | ||||
|         <div margin-top *ngIf="tagsEnabled && contentsMap && contentsMap[currentChapter] && contentsMap[currentChapter].tags && contentsMap[currentChapter].tags.length > 0"> | ||||
|             <b>{{ 'core.tag.tags' | translate }}:</b> | ||||
|             <core-tag-list [tags]="contentsMap[currentChapter].tags"></core-tag-list> | ||||
|  | ||||
| @ -66,8 +66,10 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp | ||||
|     showToc(event: MouseEvent): void { | ||||
|         // Create the toc modal.
 | ||||
|         const modal =  this.modalCtrl.create('AddonModBookTocPage', { | ||||
|             moduleId: this.module.id, | ||||
|             chapters: this.chapters, | ||||
|             selected: this.currentChapter | ||||
|             selected: this.currentChapter, | ||||
|             courseId: this.courseId | ||||
|         }, { cssClass: 'core-modal-lateral', | ||||
|             showBackdrop: true, | ||||
|             enableBackdropDismiss: true, | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
|     <nav> | ||||
|         <ion-list> | ||||
|             <a ion-item text-wrap *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)" [class.core-nav-item-selected]="selected == chapter.id" [class.item-dimmed]="chapter.hidden"> | ||||
|                 <p [attr.padding-left]="chapter.level == 1 ? true : null">{{chapter.number}} {{chapter.title}}</p> | ||||
|                 <p [attr.padding-left]="chapter.level == 1 ? true : null">{{chapter.number}} <core-format-text [text]="chapter.title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"></core-format-text></p> | ||||
|             </a> | ||||
|         </ion-list> | ||||
|     </nav> | ||||
|  | ||||
| @ -25,12 +25,16 @@ import { AddonModBookTocChapter } from '../../providers/book'; | ||||
|     templateUrl: 'toc.html' | ||||
| }) | ||||
| export class AddonModBookTocPage { | ||||
|     moduleId: number; | ||||
|     chapters: AddonModBookTocChapter[]; | ||||
|     selected: number; | ||||
|     courseId: number; | ||||
| 
 | ||||
|     constructor(navParams: NavParams, private viewCtrl: ViewController) { | ||||
|         this.moduleId = navParams.get('moduleId'); | ||||
|         this.chapters = navParams.get('chapters') || []; | ||||
|         this.selected = navParams.get('selected'); | ||||
|         this.courseId = navParams.get('courseId'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -22,6 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreCourseProvider } from '@core/course/providers/course'; | ||||
| import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; | ||||
| import { AddonModBookProvider } from './book'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch books. | ||||
| @ -33,11 +34,17 @@ export class AddonModBookPrefetchHandler extends CoreCourseResourcePrefetchHandl | ||||
|     component = AddonModBookProvider.COMPONENT; | ||||
|     updatesNames = /^configuration$|^.*files$|^entries$/; | ||||
| 
 | ||||
|     constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, protected bookProvider: AddonModBookProvider) { | ||||
|     constructor(translate: TranslateService, | ||||
|             appProvider: CoreAppProvider, | ||||
|             utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, | ||||
|             filepoolProvider: CoreFilepoolProvider, | ||||
|             sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, | ||||
|             filterHelper: CoreFilterHelperProvider, | ||||
|             protected bookProvider: AddonModBookProvider) { | ||||
| 
 | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| <!-- Content. --> | ||||
| <core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page"> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description> | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description> | ||||
| 
 | ||||
|     <ion-card icon-start class="core-info-card" *ngIf="chatInfo"> | ||||
|         <ion-icon name="time"></ion-icon> {{ 'addon.mod_chat.sessionstart' | translate:{$a: chatInfo} }} | ||||
|  | ||||
| @ -95,7 +95,12 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp | ||||
|      */ | ||||
|     enterChat(): void { | ||||
|         const title = this.chat.name || this.moduleName; | ||||
|         this.navCtrl.push('AddonModChatChatPage', {chatId: this.chat.id, courseId: this.courseId, title: title }); | ||||
|         this.navCtrl.push('AddonModChatChatPage', { | ||||
|             chatId: this.chat.id, | ||||
|             courseId: this.courseId, | ||||
|             title: title, | ||||
|             cmId: this.module.id | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"></core-format-text></ion-title> | ||||
|         <ion-buttons end> | ||||
|             <button *ngIf="loaded" ion-button icon-only (click)="showChatUsers()"> | ||||
|                 <ion-icon name="people"></ion-icon> | ||||
| @ -43,7 +43,7 @@ | ||||
| 
 | ||||
|                     <ion-badge text-wrap color="info" *ngIf="!message.system && !message.beep"> | ||||
|                         <span><core-icon name="fa-asterisk"></core-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             <strong>{{ message.userfullname }} <core-format-text [text]="message.message" (afterRender)="last && scrollToBottom()"></core-format-text></strong></span> | ||||
|                             <strong>{{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" (afterRender)="last && scrollToBottom()"></core-format-text></strong></span> | ||||
|                     </ion-badge> | ||||
|                 </div> | ||||
| 
 | ||||
| @ -56,7 +56,7 @@ | ||||
|                     </h2> | ||||
| 
 | ||||
|                     <p class="addon-message-text"> | ||||
|                         <core-format-text [text]="message.message" (afterRender)="last && scrollToBottom()"></core-format-text> | ||||
|                         <core-format-text [text]="message.message" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" (afterRender)="last && scrollToBottom()"></core-format-text> | ||||
|                     </p> | ||||
|                     <div class="tail" *ngIf="message.showTail"></div> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -46,6 +46,7 @@ export class AddonModChatChatPage { | ||||
|     isOnline: boolean; | ||||
|     currentUserId: number; | ||||
|     sending: boolean; | ||||
|     cmId: number; | ||||
| 
 | ||||
|     protected logger; | ||||
|     protected courseId: number; | ||||
| @ -67,6 +68,8 @@ export class AddonModChatChatPage { | ||||
|         this.chatId = navParams.get('chatId'); | ||||
|         this.courseId = navParams.get('courseId'); | ||||
|         this.title = navParams.get('title'); | ||||
|         this.cmId = navParams.get('cmId'); | ||||
| 
 | ||||
|         this.logger = logger.getInstance('AddonModChoiceChoicePage'); | ||||
|         this.currentUserId = sitesProvider.getCurrentSiteUserId(); | ||||
|         this.isOnline = this.appProvider.isOnline(); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -40,7 +40,7 @@ | ||||
| 
 | ||||
|                     <ion-badge text-wrap color="info" *ngIf="!message.issystem && !message.beep"> | ||||
|                         <span><core-icon name="fa-asterisk"></core-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             <strong>{{ message.userfullname }} <core-format-text [text]="message.message"></core-format-text></strong></span> | ||||
|                             <strong>{{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"></core-format-text></strong></span> | ||||
|                     </ion-badge> | ||||
|                 </div> | ||||
| 
 | ||||
| @ -53,7 +53,7 @@ | ||||
|                     </h2> | ||||
| 
 | ||||
|                     <p class="addon-message-text"> | ||||
|                         <core-format-text [text]="message.message"></core-format-text> | ||||
|                         <core-format-text [text]="message.message" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"></core-format-text> | ||||
|                     </p> | ||||
|                     <div class="tail" *ngIf="message.showTail"></div> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -31,14 +31,15 @@ import { AddonModChatHelperProvider, AddonModChatSessionMessageForView } from '. | ||||
| export class AddonModChatSessionMessagesPage { | ||||
| 
 | ||||
|     currentUserId: number; | ||||
|     cmId: number; | ||||
|     messages: AddonModChatSessionMessageForView[] = []; | ||||
|     loaded = false; | ||||
| 
 | ||||
|     protected courseId: number; | ||||
|     protected chatId: number; | ||||
|     protected sessionStart: number; | ||||
|     protected sessionEnd: number; | ||||
|     protected groupId: number; | ||||
|     protected loaded = false; | ||||
|     protected messages: AddonModChatSessionMessageForView[] = []; | ||||
| 
 | ||||
|     constructor(navParams: NavParams, private domUtils: CoreDomUtilsProvider, private chatProvider: AddonModChatProvider, | ||||
|         sitesProvider: CoreSitesProvider, private chatHelper: AddonModChatHelperProvider, private userProvider: CoreUserProvider) { | ||||
| @ -47,6 +48,7 @@ export class AddonModChatSessionMessagesPage { | ||||
|         this.groupId = navParams.get('groupId'); | ||||
|         this.sessionStart = navParams.get('sessionStart'); | ||||
|         this.sessionEnd = navParams.get('sessionEnd'); | ||||
|         this.cmId = navParams.get('cmId'); | ||||
|         this.currentUserId = sitesProvider.getCurrentSiteUserId(); | ||||
| 
 | ||||
|         this.fetchMessages(); | ||||
|  | ||||
| @ -140,7 +140,8 @@ export class AddonModChatSessionsPage { | ||||
|             chatId: this.chatId, | ||||
|             groupId: this.groupId, | ||||
|             sessionStart: session.sessionstart, | ||||
|             sessionEnd: session.sessionend | ||||
|             sessionEnd: session.sessionend, | ||||
|             cmId: this.cmId | ||||
|         }; | ||||
|         this.splitviewCtrl.push('AddonModChatSessionMessagesPage', params); | ||||
|     } | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
|     <core-loading [hideUntil]="usersLoaded"> | ||||
|         <ion-item text-wrap *ngFor="let user of users" [class.addon-mod-chat-user]="currentUserId != user.id && isOnline"> | ||||
|             <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar> | ||||
|             <h2><core-format-text [text]="user.fullname"></core-format-text></h2> | ||||
|             <h2>{{ user.fullname }}</h2> | ||||
|             <ng-container *ngIf="currentUserId != user.id && isOnline"> | ||||
|                 <button ion-button clear icon-left (click)="talkTo(user)"> | ||||
|                     <ion-icon name="chatboxes"></ion-icon> | ||||
|  | ||||
| @ -24,6 +24,7 @@ import { CoreCourseProvider } from '@core/course/providers/course'; | ||||
| import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; | ||||
| import { CoreUserProvider } from '@core/user/providers/user'; | ||||
| import { AddonModChatProvider, AddonModChatChat } from './chat'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch chats. | ||||
| @ -41,11 +42,12 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl | ||||
|             filepoolProvider: CoreFilepoolProvider, | ||||
|             sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, | ||||
|             filterHelper: CoreFilterHelperProvider, | ||||
|             private groupsProvider: CoreGroupsProvider, | ||||
|             private userProvider: CoreUserProvider, | ||||
|             private chatProvider: AddonModChatProvider) { | ||||
| 
 | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| <!-- Content. --> | ||||
| <core-loading [hideUntil]="loaded" class="core-loading-center"> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description> | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description> | ||||
| 
 | ||||
|     <!-- Activity availability messages --> | ||||
|     <ion-card class="core-info-card" icon-start *ngIf="choiceNotOpenYet"> | ||||
| @ -24,7 +24,7 @@ | ||||
|     </ion-card> | ||||
|     <ion-card class="core-info-card" icon-start *ngIf="choiceClosed"> | ||||
|         <ion-icon name="information-circle"></ion-icon> | ||||
|         <p *ngIf="options && options.length">{{ 'addon.mod_choice.yourselection' | translate }} <core-format-text [text]="options[0].text"></core-format-text></p> | ||||
|         <p *ngIf="options && options.length">{{ 'addon.mod_choice.yourselection' | translate }} <core-format-text [text]="options[0].text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></p> | ||||
|         <p>{{ 'addon.mod_choice.expired' | translate:{$a: closeTimeReadable} }}</p> | ||||
|     </ion-card> | ||||
| 
 | ||||
| @ -43,13 +43,13 @@ | ||||
|     <ion-card *ngIf="options && options.length"> | ||||
|         <ng-container *ngIf="choice.allowmultiple"> | ||||
|             <ion-item text-wrap *ngFor="let option of options"> | ||||
|                 <ion-label><core-format-text [text]="option.text"></core-format-text> <span *ngIf="choice.limitanswers && option.countanswers >= option.maxanswers">{{ 'addon.mod_choice.full' | translate }}</span></ion-label> | ||||
|                 <ion-label><core-format-text [text]="option.text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text> <span *ngIf="choice.limitanswers && option.countanswers >= option.maxanswers">{{ 'addon.mod_choice.full' | translate }}</span></ion-label> | ||||
|                 <ion-checkbox item-end [(ngModel)]="option.checked" [disabled]="option.disabled || !canEdit"></ion-checkbox> | ||||
|             </ion-item> | ||||
|         </ng-container> | ||||
|         <ng-container *ngIf="!choice.allowmultiple"> | ||||
|             <ion-item text-wrap *ngFor="let option of options" radio-group [(ngModel)]="selectedOption.id"> | ||||
|                 <ion-label><core-format-text [text]="option.text"></core-format-text> <span *ngIf="choice.limitanswers && option.countanswers >= option.maxanswers">{{ 'addon.mod_choice.full' | translate }}</span></ion-label> | ||||
|                 <ion-label><core-format-text [text]="option.text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text> <span *ngIf="choice.limitanswers && option.countanswers >= option.maxanswers">{{ 'addon.mod_choice.full' | translate }}</span></ion-label> | ||||
|                 <ion-radio color="primary" [value]="option.id" [disabled]="option.disabled || !canEdit"></ion-radio> | ||||
|             </ion-item> | ||||
|         </ng-container> | ||||
| @ -73,13 +73,13 @@ | ||||
|                         <ion-icon item-start name="warning" color="warning"></ion-icon> {{ 'addon.mod_choice.resultsnotsynced' | translate }} | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <core-chart type="pie" [data]="data" [labels]="labels" height="300"></core-chart> | ||||
|                         <core-chart type="pie" [data]="data" [labels]="labels" height="300" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-chart> | ||||
|                     </ion-item> | ||||
|                 </ion-col> | ||||
|                 <ion-col *ngIf="choice.publish && results" col-12 col-lg-7> | ||||
|                     <ion-item-group *ngFor="let result of results"> | ||||
|                         <ion-item-divider text-wrap> | ||||
|                             <h2><core-format-text [text]="result.text"></core-format-text></h2> | ||||
|                             <h2><core-format-text [text]="result.text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></h2> | ||||
|                             <p>{{ 'addon.mod_choice.numberofuser' | translate }}: {{ result.numberofuser }} ({{ 'core.percentagenumber' | translate: {$a: result.percentageamountfixed} }})</p> | ||||
|                         </ion-item-divider> | ||||
|                         <a ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseid" [userId]="user.userid" [title]="user.fullname" text-wrap> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <ion-header> | ||||
|     <ion-navbar core-back-button> | ||||
|         <ion-title><core-format-text [text]="title"></core-format-text></ion-title> | ||||
|         <ion-title><core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></ion-title> | ||||
| 
 | ||||
|         <ion-buttons end> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -24,6 +24,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti | ||||
| import { CoreUserProvider } from '@core/user/providers/user'; | ||||
| import { AddonModChoiceSyncProvider } from './sync'; | ||||
| import { AddonModChoiceProvider } from './choice'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch choices. | ||||
| @ -37,12 +38,19 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan | ||||
| 
 | ||||
|     protected syncProvider: AddonModChoiceSyncProvider; // It will be injected later to prevent circular dependencies.
 | ||||
| 
 | ||||
|     constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, protected choiceProvider: AddonModChoiceProvider, | ||||
|             protected userProvider: CoreUserProvider, protected injector: Injector) { | ||||
|     constructor(translate: TranslateService, | ||||
|             appProvider: CoreAppProvider, | ||||
|             utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, | ||||
|             filepoolProvider: CoreFilepoolProvider, | ||||
|             sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, | ||||
|             filterHelper: CoreFilterHelperProvider, | ||||
|             protected choiceProvider: AddonModChoiceProvider, | ||||
|             protected userProvider: CoreUserProvider, | ||||
|             protected injector: Injector) { | ||||
| 
 | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -22,15 +22,15 @@ | ||||
|     <ion-icon name="thumbs-down"></ion-icon> | ||||
| </a> | ||||
| 
 | ||||
| <core-comments *ngIf="action == 'comments' && mode == 'list'" contextLevel="module" [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry"></core-comments> | ||||
| <core-comments *ngIf="action == 'comments' && mode == 'list'" contextLevel="module" [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="database.course"></core-comments> | ||||
| 
 | ||||
| <span *ngIf="action == 'timeadded'">{{ entry.timecreated * 1000 |  coreFormatDate }}</span> | ||||
| <span *ngIf="action == 'timemodified'">{{ entry.timemodified * 1000 |  coreFormatDate }}</span> | ||||
| 
 | ||||
| <a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname"> | ||||
| <a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname"> | ||||
|     <img class="avatar-round" [src]="userPicture" [alt]="'core.pictureof' | translate:{$a: entry.fullname}" core-external-content onError="this.src='assets/img/user-avatar.png'" role="presentation"> | ||||
| </a> | ||||
| 
 | ||||
| <a *ngIf="action == 'user' && entry" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">{{entry.fullname}}</a> | ||||
| <a *ngIf="action == 'user' && entry" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname">{{entry.fullname}}</a> | ||||
| 
 | ||||
| <core-tag-list *ngIf="tagsEnabled && action == 'tags' && entry" [tags]="entry.tags"></core-tag-list> | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
| <!-- Content. --> | ||||
| <core-loading [hideUntil]="loaded" class="core-loading-center"> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description> | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description> | ||||
| 
 | ||||
|     <!-- Data done in offline but not synchronized --> | ||||
|     <div class="core-warning-card" icon-start *ngIf="hasOffline || hasOfflineRatings"> | ||||
|  | ||||
| @ -12,4 +12,4 @@ | ||||
|     </ion-item> | ||||
| </span> | ||||
| 
 | ||||
| <core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text> | ||||
| <core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content" [filter]="false"></core-format-text> | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user