MOBILE-3656 wiki: Migrate edit page
parent
2f0eb0088b
commit
d222ca6882
|
@ -1,13 +1,15 @@
|
||||||
<!-- Buttons to add to the header. -->
|
<!-- Buttons to add to the header. -->
|
||||||
<core-navbar-buttons slot="end">
|
<core-navbar-buttons slot="end">
|
||||||
<!-- Select subwiki. -->
|
<!-- Select subwiki. -->
|
||||||
<ion-button slot="icon-only //TODO: mode to icon" *ngIf="subwikiData.count > 1" (click)="showSubwikiPicker($event)" [attr.aria-label]="'addon.mod_wiki.subwiki' | translate">
|
<ion-button *ngIf="subwikiData.count > 1" (click)="showSubwikiPicker($event)"
|
||||||
<ion-icon *ngIf="!groupWiki" name="person"></ion-icon>
|
[attr.aria-label]="'addon.mod_wiki.subwiki' | translate">
|
||||||
<ion-icon *ngIf="groupWiki" name="people"></ion-icon>
|
<ion-icon *ngIf="!groupWiki" name="fas-user"></ion-icon>
|
||||||
|
<ion-icon *ngIf="groupWiki" name="fas-users"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<ion-button *ngIf="loaded && currentPageObj" slot="icon-only //TODO: mode to icon" (click)="openMap($event)"[attr.aria-label]="'addon.mod_wiki.map' | translate" aria-haspopup="true">
|
<ion-button *ngIf="loaded && currentPageObj" (click)="openMap()" [attr.aria-label]="'addon.mod_wiki.map' | translate"
|
||||||
<ion-icon name="map"></ion-icon>
|
aria-haspopup="true">
|
||||||
|
<ion-icon name="fas-map"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<core-context-menu>
|
<core-context-menu>
|
||||||
|
@ -46,7 +48,7 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
<div class="ion-padding" *ngIf="description || pageIsOffline || hasOffline || pageWarning">
|
<div *ngIf="description || pageIsOffline || hasOffline || pageWarning">
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
@ -80,9 +82,9 @@
|
||||||
</core-empty-box>
|
</core-empty-box>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<div class="ion-margin-top" *ngIf="tagsEnabled && currentPageObj && currentPageObj.tags && currentPageObj.tags.length > 0">
|
<div class="ion-margin-top" *ngIf="tagsEnabled && tags.length > 0">
|
||||||
<b>{{ 'core.tag.tags' | translate }}:</b>
|
<b>{{ 'core.tag.tags' | translate }}:</b>
|
||||||
<core-tag-list [tags]="currentPageObj.tags"></core-tag-list>
|
<core-tag-list [tags]="tags"></core-tag-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, Optional, Input, OnInit, OnDestroy } from '@angular/core';
|
import { Component, Optional, Input, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { Params } from '@angular/router';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
|
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
|
||||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
|
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
|
||||||
import { CoreCourse } from '@features/course/services/course';
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreTag } from '@features/tag/services/tag';
|
import { CoreTag, CoreTagItem } from '@features/tag/services/tag';
|
||||||
import { CoreUser } from '@features/user/services/user';
|
import { CoreUser } from '@features/user/services/user';
|
||||||
import { IonContent } from '@ionic/angular';
|
import { IonContent } from '@ionic/angular';
|
||||||
import { CoreGroup, CoreGroups } from '@services/groups';
|
import { CoreGroup, CoreGroups } from '@services/groups';
|
||||||
|
@ -84,6 +85,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
pageContent?: string; // Page content to display.
|
pageContent?: string; // Page content to display.
|
||||||
tagsEnabled = false;
|
tagsEnabled = false;
|
||||||
currentPageObj?: AddonModWikiPageContents | AddonModWikiPageDBRecord; // Object of the current loaded page.
|
currentPageObj?: AddonModWikiPageContents | AddonModWikiPageDBRecord; // Object of the current loaded page.
|
||||||
|
tags: CoreTagItem[] = [];
|
||||||
subwikiData: AddonModWikiSubwikiListData = { // Data for the subwiki selector.
|
subwikiData: AddonModWikiSubwikiListData = { // Data for the subwiki selector.
|
||||||
subwikiSelected: 0,
|
subwikiSelected: 0,
|
||||||
userSelected: 0,
|
userSelected: 0,
|
||||||
|
@ -100,7 +102,6 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
protected manualSyncObserver?: CoreEventObserver; // An observer to watch for manual sync events.
|
protected manualSyncObserver?: CoreEventObserver; // An observer to watch for manual sync events.
|
||||||
protected ignoreManualSyncEvent = false; // Whether manual sync event should be ignored.
|
protected ignoreManualSyncEvent = false; // Whether manual sync event should be ignored.
|
||||||
protected currentUserId?: number; // Current user ID.
|
protected currentUserId?: number; // Current user ID.
|
||||||
protected hasEdited = false; // Whether the user has opened the edit page.
|
|
||||||
protected currentPath!: string;
|
protected currentPath!: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -213,7 +214,10 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
// Get the wiki instance.
|
// Get the wiki instance.
|
||||||
this.wiki = await AddonModWiki.getWiki(this.courseId, this.module.id);
|
this.wiki = await AddonModWiki.getWiki(this.courseId, this.module.id);
|
||||||
|
|
||||||
this.dataRetrieved.emit(this.wiki);
|
if (this.pageContent === undefined) {
|
||||||
|
// Page not loaded yet, emit the data to update the page title.
|
||||||
|
this.dataRetrieved.emit(this.wiki);
|
||||||
|
}
|
||||||
AddonModWiki.wikiPageOpened(this.wiki.id, this.currentPath);
|
AddonModWiki.wikiPageOpened(this.wiki.id, this.currentPath);
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
|
@ -293,19 +297,15 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
}
|
}
|
||||||
|
|
||||||
// No page ID but we received a title. This means we're trying to load an offline page.
|
// No page ID but we received a title. This means we're trying to load an offline page.
|
||||||
if (!this.currentSubwiki) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const title = this.pageTitle || this.wiki!.firstpagetitle!;
|
const title = this.pageTitle || this.wiki!.firstpagetitle!;
|
||||||
|
|
||||||
const offlinePage = await AddonModWikiOffline.getNewPage(
|
const offlinePage = await AddonModWikiOffline.getNewPage(
|
||||||
title,
|
title,
|
||||||
this.currentSubwiki.id,
|
this.currentSubwiki!.id,
|
||||||
this.currentSubwiki.wikiid,
|
this.currentSubwiki!.wikiid,
|
||||||
this.currentSubwiki.userid,
|
this.currentSubwiki!.userid,
|
||||||
this.currentSubwiki.groupid,
|
this.currentSubwiki!.groupid,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.pageIsOffline = true;
|
this.pageIsOffline = true;
|
||||||
|
@ -354,6 +354,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
const firstPage = subwikiPages.find((page) => page.firstpage );
|
const firstPage = subwikiPages.find((page) => page.firstpage );
|
||||||
if (firstPage) {
|
if (firstPage) {
|
||||||
this.currentPage = firstPage.id;
|
this.currentPage = firstPage.id;
|
||||||
|
this.pageTitle = firstPage.title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,9 +418,11 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
this.dataRetrieved.emit(pageContents.title);
|
this.dataRetrieved.emit(pageContents.title);
|
||||||
this.setSelectedWiki(pageContents.subwikiid, pageContents.userid, pageContents.groupid);
|
this.setSelectedWiki(pageContents.subwikiid, pageContents.userid, pageContents.groupid);
|
||||||
|
|
||||||
|
this.pageTitle = pageContents.title;
|
||||||
this.pageContent = this.replaceEditLinks(pageContents.cachedcontent);
|
this.pageContent = this.replaceEditLinks(pageContents.cachedcontent);
|
||||||
this.canEdit = !!pageContents.caneditpage;
|
this.canEdit = !!pageContents.caneditpage;
|
||||||
this.currentPageObj = pageContents;
|
this.currentPageObj = pageContents;
|
||||||
|
this.tags = ('tags' in pageContents && pageContents.tags) || [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,15 +443,14 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
* Open the view to create the first page of the wiki.
|
* Open the view to create the first page of the wiki.
|
||||||
*/
|
*/
|
||||||
protected goToCreateFirstPage(): void {
|
protected goToCreateFirstPage(): void {
|
||||||
// @todo
|
CoreNavigator.navigate('../../edit', {
|
||||||
// CoreNavigator.push('AddonModWikiEditPage', {
|
params: {
|
||||||
// module: this.module,
|
pageTitle: this.wiki!.firstpagetitle,
|
||||||
// courseId: this.courseId,
|
wikiId: this.currentSubwiki?.wikiid,
|
||||||
// pageTitle: this.wiki.firstpagetitle,
|
userId: this.currentSubwiki?.userid,
|
||||||
// wikiId: this.currentSubwiki.wikiid,
|
groupId: this.currentSubwiki?.groupid,
|
||||||
// userId: this.currentSubwiki.userid,
|
},
|
||||||
// groupId: this.currentSubwiki.groupid
|
});
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,28 +461,28 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo
|
if (this.currentPageObj) {
|
||||||
// if (this.currentPageObj) {
|
// Current page exists, go to edit it.
|
||||||
// // Current page exists, go to edit it.
|
const pageParams: Params = {
|
||||||
// const pageParams: any = {
|
pageTitle: this.currentPageObj.title,
|
||||||
// module: this.module,
|
subwikiId: this.currentPageObj.subwikiid,
|
||||||
// courseId: this.courseId,
|
};
|
||||||
// pageId: this.currentPageObj.id,
|
|
||||||
// pageTitle: this.currentPageObj.title,
|
|
||||||
// subwikiId: this.currentPageObj.subwikiid
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if (this.currentSubwiki) {
|
if ('id' in this.currentPageObj) {
|
||||||
// pageParams.wikiId = this.currentSubwiki.wikiid;
|
pageParams.pageId = this.currentPageObj.id;
|
||||||
// pageParams.userId = this.currentSubwiki.userid;
|
}
|
||||||
// pageParams.groupId = this.currentSubwiki.groupid;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.navCtrl.push('AddonModWikiEditPage', pageParams);
|
if (this.currentSubwiki) {
|
||||||
// } else if (this.currentSubwiki) {
|
pageParams.wikiId = this.currentSubwiki.wikiid;
|
||||||
// // No page loaded, the wiki doesn't have first page.
|
pageParams.userId = this.currentSubwiki.userid;
|
||||||
// this.goToCreateFirstPage();
|
pageParams.groupId = this.currentSubwiki.groupid;
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
CoreNavigator.navigate('../../edit', { params: pageParams });
|
||||||
|
} else if (this.currentSubwiki) {
|
||||||
|
// No page loaded, the wiki doesn't have first page.
|
||||||
|
this.goToCreateFirstPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -491,26 +493,23 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo
|
if (this.currentPageObj) {
|
||||||
// if (this.currentPageObj) {
|
// Current page exists, go to edit it.
|
||||||
// // Current page exists, go to edit it.
|
const pageParams: Params = {
|
||||||
// const pageParams: any = {
|
subwikiId: this.currentPageObj.subwikiid,
|
||||||
// module: this.module,
|
};
|
||||||
// courseId: this.courseId,
|
|
||||||
// subwikiId: this.currentPageObj.subwikiid
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if (this.currentSubwiki) {
|
if (this.currentSubwiki) {
|
||||||
// pageParams.wikiId = this.currentSubwiki.wikiid;
|
pageParams.wikiId = this.currentSubwiki.wikiid;
|
||||||
// pageParams.userId = this.currentSubwiki.userid;
|
pageParams.userId = this.currentSubwiki.userid;
|
||||||
// pageParams.groupId = this.currentSubwiki.groupid;
|
pageParams.groupId = this.currentSubwiki.groupid;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// this.navCtrl.push('AddonModWikiEditPage', pageParams);
|
CoreNavigator.navigate('../../edit', { params: pageParams });
|
||||||
// } else if (this.currentSubwiki) {
|
} else if (this.currentSubwiki) {
|
||||||
// // No page loaded, the wiki doesn't have first page.
|
// No page loaded, the wiki doesn't have first page.
|
||||||
// this.goToCreateFirstPage();
|
this.goToCreateFirstPage();
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -522,44 +521,43 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
if (!('id' in page)) {
|
if (!('id' in page)) {
|
||||||
// It's an offline page. Check if we are already in the same offline page.
|
// It's an offline page. Check if we are already in the same offline page.
|
||||||
if (this.currentPage || !this.pageTitle || page.title != this.pageTitle) {
|
if (this.currentPage || !this.pageTitle || page.title != this.pageTitle) {
|
||||||
const hash = <string> Md5.hashAsciiStr(JSON.stringify({
|
this.openPageOrSubwiki({
|
||||||
pageTitle: page.title,
|
pageTitle: page.title,
|
||||||
subwikiId: page.subwikiid,
|
subwikiId: page.subwikiid,
|
||||||
timestamp: Date.now(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
CoreNavigator.navigate(`../${hash}`, {
|
|
||||||
params: {
|
|
||||||
module: this.module,
|
|
||||||
pageTitle: page.title,
|
|
||||||
wikiId: this.wiki!.id,
|
|
||||||
subwikiId: page.subwikiid,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (this.currentPage != page.id) {
|
} else if (this.currentPage != page.id) {
|
||||||
// Add a new State.
|
// Add a new State.
|
||||||
const pageContents = await this.fetchPageContents(page.id);
|
const pageContents = await this.fetchPageContents(page.id);
|
||||||
|
|
||||||
const hash = <string> Md5.hashAsciiStr(JSON.stringify({
|
this.openPageOrSubwiki({
|
||||||
pageTitle: pageContents.title,
|
pageTitle: pageContents.title,
|
||||||
pageId: pageContents.id,
|
pageId: pageContents.id,
|
||||||
subwikiId: page.subwikiid,
|
subwikiId: page.subwikiid,
|
||||||
timestamp: Date.now(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
CoreNavigator.navigate(`../${hash}`, {
|
|
||||||
params: {
|
|
||||||
module: this.module,
|
|
||||||
pageTitle: pageContents.title,
|
|
||||||
pageId: pageContents.id,
|
|
||||||
wikiId: pageContents.wikiid,
|
|
||||||
subwikiId: pageContents.subwikiid,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a page or a subwiki in the current wiki.
|
||||||
|
*
|
||||||
|
* @param options Options
|
||||||
|
* @return Promise.
|
||||||
|
*/
|
||||||
|
protected async openPageOrSubwiki(options: AddonModWikiOpenPageOptions): Promise<void> {
|
||||||
|
const hash = <string> Md5.hashAsciiStr(JSON.stringify({
|
||||||
|
...options,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
await CoreNavigator.navigate(`../${hash}`, {
|
||||||
|
params: {
|
||||||
|
module: this.module,
|
||||||
|
...options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the map.
|
* Show the map.
|
||||||
*/
|
*/
|
||||||
|
@ -569,10 +567,10 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
component: AddonModWikiMapModalComponent,
|
component: AddonModWikiMapModalComponent,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
pages: this.subwikiPages,
|
pages: this.subwikiPages,
|
||||||
selected: this.currentPageObj && 'id' in this.currentPageObj && this.currentPageObj.id,
|
|
||||||
homeView: this.getWikiHomeView(),
|
homeView: this.getWikiHomeView(),
|
||||||
moduleId: this.module.id,
|
moduleId: this.module.id,
|
||||||
courseId: this.courseId,
|
courseId: this.courseId,
|
||||||
|
selectedTitle: this.currentPageObj && this.currentPageObj.title,
|
||||||
},
|
},
|
||||||
cssClass: 'core-modal-lateral',
|
cssClass: 'core-modal-lateral',
|
||||||
showBackdrop: true,
|
showBackdrop: true,
|
||||||
|
@ -613,21 +611,10 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
if (subwikiId != this.currentSubwiki!.id || userId != this.currentSubwiki!.userid ||
|
if (subwikiId != this.currentSubwiki!.id || userId != this.currentSubwiki!.userid ||
|
||||||
groupId != this.currentSubwiki!.groupid) {
|
groupId != this.currentSubwiki!.groupid) {
|
||||||
|
|
||||||
const hash = <string> Md5.hashAsciiStr(JSON.stringify({
|
this.openPageOrSubwiki({
|
||||||
subwikiId: subwikiId,
|
subwikiId: subwikiId,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
timestamp: Date.now(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
CoreNavigator.navigate(`../${hash}`, {
|
|
||||||
params: {
|
|
||||||
module: this.module,
|
|
||||||
wikiId: this.wiki!.id,
|
|
||||||
subwikiId: subwikiId,
|
|
||||||
userId: userId,
|
|
||||||
groupId: groupId,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -714,24 +701,43 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
ionViewDidEnter(): void {
|
ionViewDidEnter(): void {
|
||||||
super.ionViewDidEnter();
|
super.ionViewDidEnter();
|
||||||
|
|
||||||
if (this.hasEdited) {
|
const editedPageData = AddonModWiki.consumeEditedPageData();
|
||||||
this.hasEdited = false;
|
if (!editedPageData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User has just edited a page. Check if it's the current page.
|
||||||
|
if (this.pageId && editedPageData.pageId === this.pageId) {
|
||||||
|
this.showLoadingAndRefresh(true, false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sameSubwiki = this.currentSubwiki &&
|
||||||
|
((this.currentSubwiki.id && this.currentSubwiki.id === editedPageData.subwikiId) ||
|
||||||
|
(this.currentSubwiki.userid === editedPageData.userId && this.currentSubwiki.groupid === editedPageData.groupId));
|
||||||
|
|
||||||
|
if (sameSubwiki && editedPageData.pageTitle === this.pageTitle) {
|
||||||
|
this.showLoadingAndRefresh(true, false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not same page or we cannot tell. Open the page.
|
||||||
|
this.openPageOrSubwiki({
|
||||||
|
pageId: editedPageData.pageId,
|
||||||
|
pageTitle: editedPageData.pageTitle,
|
||||||
|
subwikiId: editedPageData.subwikiId,
|
||||||
|
userId: editedPageData.wikiId,
|
||||||
|
groupId: editedPageData.groupId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (editedPageData.pageId && (!this.pageContent || this.pageContent.indexOf('/mod/wiki/create.php') != -1)) {
|
||||||
|
// Refresh current page anyway because the new page could have been created using the create link.
|
||||||
this.showLoadingAndRefresh(true, false);
|
this.showLoadingAndRefresh(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* User left the page that contains the component.
|
|
||||||
*/
|
|
||||||
ionViewDidLeave(): void {
|
|
||||||
super.ionViewDidLeave();
|
|
||||||
|
|
||||||
// @todo
|
|
||||||
// if (this.navCtrl.getActive().component.name == 'AddonModWikiEditPage') {
|
|
||||||
// this.hasEdited = true;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
|
@ -1039,3 +1045,11 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AddonModWikiOpenPageOptions = {
|
||||||
|
subwikiId?: number;
|
||||||
|
pageTitle?: string;
|
||||||
|
pageId?: number;
|
||||||
|
userId?: number;
|
||||||
|
groupId?: number;
|
||||||
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<ion-title>{{ 'addon.mod_wiki.map' | translate }}</ion-title>
|
<ion-title>{{ 'addon.mod_wiki.map' | translate }}</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||||
<ion-icon name="close" slot="icon-only"></ion-icon>
|
<ion-icon name="fas-times"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
@ -21,17 +21,17 @@
|
||||||
<ion-label>{{ letter.label }}</ion-label>
|
<ion-label>{{ letter.label }}</ion-label>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<ion-item class="ion-text-wrap" *ngFor="let page of letter.pages" (click)="goToPage(page)"
|
<ion-item class="ion-text-wrap" *ngFor="let page of letter.pages" (click)="goToPage(page)"
|
||||||
[class.core-selected-item]="selected == page.id" tappable>
|
[class.core-selected-item]="selectedTitle == page.title" tappable>
|
||||||
<ion-icon name="fas-home" slot="start" *ngIf="page.firstpage"></ion-icon>
|
<ion-icon name="fas-home" slot="start" *ngIf="page.firstpage"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<core-format-text [text]="page.title" contextLevel="module" [contextInstanceId]="moduleId"
|
<core-format-text [text]="page.title" contextLevel="module" [contextInstanceId]="moduleId"
|
||||||
[courseId]="courseId">
|
[courseId]="courseId">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
<ion-note *ngIf="!page.id" slot="end">
|
|
||||||
<ion-icon name="time"></ion-icon>
|
|
||||||
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
|
|
||||||
</ion-note>
|
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
<ion-note *ngIf="!page.id" slot="end">
|
||||||
|
<ion-icon name="fas-clock"></ion-icon>
|
||||||
|
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
|
||||||
|
</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { AddonModWikiSubwikiPage } from '../../services/wiki';
|
||||||
export class AddonModWikiMapModalComponent implements OnInit {
|
export class AddonModWikiMapModalComponent implements OnInit {
|
||||||
|
|
||||||
@Input() pages: (AddonModWikiSubwikiPage | AddonModWikiPageDBRecord)[] = [];
|
@Input() pages: (AddonModWikiSubwikiPage | AddonModWikiPageDBRecord)[] = [];
|
||||||
@Input() selected?: number;
|
@Input() selectedTitle?: string;
|
||||||
@Input() moduleId?: number;
|
@Input() moduleId?: number;
|
||||||
@Input() courseId?: number;
|
@Input() courseId?: number;
|
||||||
@Input() homeView?: string;
|
@Input() homeView?: string;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
[attr.disabled]="!subwiki.canedit && subwiki.id <= 0 ? true : null" tappable
|
[attr.disabled]="!subwiki.canedit && subwiki.id <= 0 ? true : null" tappable
|
||||||
[class.core-selected-item]="isSubwikiSelected(subwiki)" detail="false">
|
[class.core-selected-item]="isSubwikiSelected(subwiki)" detail="false">
|
||||||
<ion-label>{{ subwiki.name }}</ion-label>
|
<ion-label>{{ subwiki.name }}</ion-label>
|
||||||
<ion-icon *ngIf="isSubwikiSelected(subwiki)" name="checkmark" slot="end"></ion-icon>
|
<ion-icon *ngIf="isSubwikiSelected(subwiki)" name="fas-check" slot="end"></ion-icon>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class AddonModWikiSubwikiPickerComponent {
|
||||||
* @param subwiki Subwiki to check.
|
* @param subwiki Subwiki to check.
|
||||||
* @return Whether it's the selected subwiki.
|
* @return Whether it's the selected subwiki.
|
||||||
*/
|
*/
|
||||||
protected isSubwikiSelected(subwiki: AddonModWikiSubwiki): boolean {
|
isSubwikiSelected(subwiki: AddonModWikiSubwiki): boolean {
|
||||||
|
|
||||||
if (subwiki.id > 0 && this.currentSubwiki.id > 0) {
|
if (subwiki.id > 0 && this.currentSubwiki.id > 0) {
|
||||||
return subwiki.id == this.currentSubwiki.id;
|
return subwiki.id == this.currentSubwiki.id;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>
|
||||||
|
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
|
||||||
|
</core-format-text>
|
||||||
|
</ion-title>
|
||||||
|
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<ion-button fill="clear" (click)="save()" [attr.aria-label]="'core.save' | translate">
|
||||||
|
{{ 'core.save' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content>
|
||||||
|
<core-loading [hideUntil]="loaded">
|
||||||
|
<form [formGroup]="pageForm" #editPageForm *ngIf="loaded">
|
||||||
|
<ion-item class="ion-text-wrap" *ngIf="canEditTitle">
|
||||||
|
<ion-label></ion-label>
|
||||||
|
<ion-input name="title" type="text" [placeholder]="'addon.mod_wiki.newpagetitle' | translate"
|
||||||
|
formControlName="title">
|
||||||
|
</ion-input>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label></ion-label>
|
||||||
|
<core-rich-text-editor [control]="contentControl" [placeholder]="'core.content' | translate"
|
||||||
|
name="wiki_page_content" [component]="component" [componentId]="cmId" [autoSave]="true" contextLevel="module"
|
||||||
|
[contextInstanceId]="cmId" elementId="newcontent_editor" [draftExtraParams]="editorExtraParams">
|
||||||
|
</core-rich-text-editor>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item *ngIf="!wrongVersionLock" class="ion-text-center addon-mod_wiki-wrongversionlock" >
|
||||||
|
<ion-label>
|
||||||
|
<ion-badge color="danger" class="ion-padding">{{ 'addon.mod_wiki.wrongversionlock' | translate }}</ion-badge>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</form>
|
||||||
|
</core-loading>
|
||||||
|
</ion-content>
|
|
@ -0,0 +1,448 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
import { FormControl, FormGroup, FormBuilder } from '@angular/forms';
|
||||||
|
import { CoreError } from '@classes/errors/error';
|
||||||
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
|
import { CanLeave } from '@guards/can-leave';
|
||||||
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
import { CoreSites } from '@services/sites';
|
||||||
|
import { CoreSync } from '@services/sync';
|
||||||
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
import { CoreWSExternalFile } from '@services/ws';
|
||||||
|
import { Translate } from '@singletons';
|
||||||
|
import { CoreEvents } from '@singletons/events';
|
||||||
|
import { CoreForms } from '@singletons/form';
|
||||||
|
import { AddonModWiki, AddonModWikiProvider } from '../../services/wiki';
|
||||||
|
import { AddonModWikiOffline } from '../../services/wiki-offline';
|
||||||
|
import { AddonModWikiSync } from '../../services/wiki-sync';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page that allows adding or editing a wiki page.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'page-addon-mod-wiki-edit',
|
||||||
|
templateUrl: 'edit.html',
|
||||||
|
})
|
||||||
|
export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave {
|
||||||
|
|
||||||
|
@ViewChild('editPageForm') formElement?: ElementRef;
|
||||||
|
|
||||||
|
cmId!: number; // Course module ID.
|
||||||
|
courseId!: number; // Course the wiki belongs to.
|
||||||
|
title?: string; // Title to display.
|
||||||
|
pageForm?: FormGroup; // The form group.
|
||||||
|
contentControl?: FormControl; // The FormControl for the page content.
|
||||||
|
canEditTitle = false; // Whether title can be edited.
|
||||||
|
loaded = false; // Whether the data has been loaded.
|
||||||
|
component = AddonModWikiProvider.COMPONENT; // Component to link the files to.
|
||||||
|
wrongVersionLock = false; // Whether the page lock doesn't match the initial one.
|
||||||
|
editorExtraParams: Record<string, unknown> = {};
|
||||||
|
|
||||||
|
protected subwikiId?: number; // Subwiki ID the page belongs to.
|
||||||
|
protected wikiId?: number; // Wiki ID the page belongs to.
|
||||||
|
protected pageId?: number; // The page ID (if editing a page).
|
||||||
|
protected section?: string; // The section being edited.
|
||||||
|
protected groupId?: number; // The group the subwiki belongs to.
|
||||||
|
protected userId?: number; // The user the subwiki belongs to.
|
||||||
|
protected blockId?: string; // ID to block the subwiki.
|
||||||
|
protected editing = false; // Whether the user is editing a page (true) or creating a new one (false).
|
||||||
|
protected editOffline = false; // Whether the user is editing an offline page.
|
||||||
|
protected subwikiFiles: CoreWSExternalFile[] = []; // List of files of the subwiki.
|
||||||
|
protected originalContent?: string; // The original page content.
|
||||||
|
protected version?: number; // Page version.
|
||||||
|
protected renewLockInterval?: number; // An interval to renew the lock every certain time.
|
||||||
|
protected forceLeave = false; // To allow leaving the page without checking for changes.
|
||||||
|
protected isDestroyed = false; // Whether the page has been destroyed.
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected formBuilder: FormBuilder,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
async ngOnInit(): Promise<void> {
|
||||||
|
this.cmId = CoreNavigator.getRouteNumberParam('cmId')!;
|
||||||
|
this.courseId = CoreNavigator.getRouteNumberParam('courseId')!;
|
||||||
|
this.subwikiId = CoreNavigator.getRouteNumberParam('subwikiId');
|
||||||
|
this.wikiId = CoreNavigator.getRouteNumberParam('wikiId');
|
||||||
|
this.pageId = CoreNavigator.getRouteNumberParam('pageId');
|
||||||
|
this.section = CoreNavigator.getRouteParam('section');
|
||||||
|
this.groupId = CoreNavigator.getRouteNumberParam('groupId');
|
||||||
|
this.userId = CoreNavigator.getRouteNumberParam('userId');
|
||||||
|
|
||||||
|
let pageTitle = CoreNavigator.getRouteParam<string>('pageTitle');
|
||||||
|
pageTitle = pageTitle ? pageTitle.replace(/\+/g, ' ') : '';
|
||||||
|
|
||||||
|
this.canEditTitle = !pageTitle;
|
||||||
|
this.title = pageTitle ?
|
||||||
|
Translate.instant('addon.mod_wiki.editingpage', { $a: pageTitle }) :
|
||||||
|
Translate.instant('addon.mod_wiki.newpagehdr');
|
||||||
|
this.blockId = AddonModWikiSync.getSubwikiBlockId(this.subwikiId, this.wikiId, this.userId, this.groupId);
|
||||||
|
|
||||||
|
// Create the form group and its controls.
|
||||||
|
this.contentControl = this.formBuilder.control('');
|
||||||
|
this.pageForm = this.formBuilder.group({
|
||||||
|
title: pageTitle,
|
||||||
|
});
|
||||||
|
this.pageForm.addControl('text', this.contentControl);
|
||||||
|
|
||||||
|
// Block the wiki so it cannot be synced.
|
||||||
|
CoreSync.blockOperation(this.component, this.blockId);
|
||||||
|
|
||||||
|
if (this.pageId) {
|
||||||
|
this.editorExtraParams.pageid = this.pageId;
|
||||||
|
|
||||||
|
if (this.section) {
|
||||||
|
this.editorExtraParams.section = this.section;
|
||||||
|
}
|
||||||
|
} else if (pageTitle) {
|
||||||
|
this.editorExtraParams.pagetitle = pageTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const success = await this.fetchWikiPageData();
|
||||||
|
|
||||||
|
if (success && !this.isDestroyed) {
|
||||||
|
// Block the subwiki now that we have blockId for sure.
|
||||||
|
const newBlockId = AddonModWikiSync.getSubwikiBlockId(this.subwikiId, this.wikiId, this.userId, this.groupId);
|
||||||
|
if (newBlockId != this.blockId) {
|
||||||
|
CoreSync.unblockOperation(this.component, this.blockId);
|
||||||
|
this.blockId = newBlockId;
|
||||||
|
CoreSync.blockOperation(this.component, this.blockId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to get wiki page data.
|
||||||
|
*
|
||||||
|
* @return Promise resolved with boolean: whether it was successful.
|
||||||
|
*/
|
||||||
|
protected async fetchWikiPageData(): Promise<boolean> {
|
||||||
|
let canEdit = false;
|
||||||
|
let fetchFailed = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Wait for sync to be over (if any).
|
||||||
|
const syncResult = await AddonModWikiSync.waitForSync(this.blockId!);
|
||||||
|
|
||||||
|
if (this.pageId) {
|
||||||
|
// Editing a page that already exists.
|
||||||
|
this.canEditTitle = false;
|
||||||
|
this.editing = true;
|
||||||
|
this.editOffline = false; // Cannot edit pages in offline.
|
||||||
|
|
||||||
|
// Get page contents to obtain title and editing permission
|
||||||
|
const pageContents = await AddonModWiki.getPageContents(this.pageId, { cmId: this.cmId });
|
||||||
|
|
||||||
|
this.pageForm!.controls.title.setValue(pageContents.title); // Set the title in the form group.
|
||||||
|
this.wikiId = pageContents.wikiid;
|
||||||
|
this.subwikiId = pageContents.subwikiid;
|
||||||
|
this.title = Translate.instant('addon.mod_wiki.editingpage', { $a: pageContents.title });
|
||||||
|
this.groupId = pageContents.groupid;
|
||||||
|
this.userId = pageContents.userid;
|
||||||
|
canEdit = pageContents.caneditpage;
|
||||||
|
|
||||||
|
// Get subwiki files, needed to replace URLs for rich text editor.
|
||||||
|
this.subwikiFiles = await AddonModWiki.getSubwikiFiles(this.wikiId, {
|
||||||
|
groupId: this.groupId,
|
||||||
|
userId: this.userId,
|
||||||
|
cmId: this.cmId,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get editable text of the page/section.
|
||||||
|
const editContents = await AddonModWiki.getPageForEditing(this.pageId, this.section);
|
||||||
|
|
||||||
|
// Get the original page contents, treating file URLs if needed.
|
||||||
|
const content = CoreTextUtils.replacePluginfileUrls(editContents.content || '', this.subwikiFiles);
|
||||||
|
|
||||||
|
this.contentControl!.setValue(content);
|
||||||
|
this.originalContent = content;
|
||||||
|
this.version = editContents.version;
|
||||||
|
|
||||||
|
if (canEdit) {
|
||||||
|
// Renew the lock every certain time.
|
||||||
|
this.renewLockInterval = window.setInterval(() => {
|
||||||
|
this.renewLock();
|
||||||
|
}, AddonModWikiProvider.RENEW_LOCK_TIME);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const pageTitle = this.pageForm!.controls.title.value;
|
||||||
|
this.editing = false;
|
||||||
|
canEdit = !!this.blockId; // If no blockId, the user cannot edit the page.
|
||||||
|
|
||||||
|
// Make sure we have the wiki ID.
|
||||||
|
if (!this.wikiId) {
|
||||||
|
const module = await CoreCourse.getModule(this.cmId, this.courseId, undefined, true);
|
||||||
|
|
||||||
|
this.wikiId = module.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageTitle) {
|
||||||
|
// Title is set, it could be editing an offline page or creating a new page using an edit link.
|
||||||
|
// First of all, verify if this page was created in the current sync.
|
||||||
|
if (syncResult) {
|
||||||
|
const page = syncResult.created.find((page) => page.title == pageTitle);
|
||||||
|
|
||||||
|
if (page && page.pageId > 0) {
|
||||||
|
// Page was created, now it exists in the site.
|
||||||
|
this.pageId = page.pageId;
|
||||||
|
|
||||||
|
return this.fetchWikiPageData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there's already some offline data for this page.
|
||||||
|
const page = await CoreUtils.ignoreErrors(
|
||||||
|
AddonModWikiOffline.getNewPage(pageTitle, this.subwikiId, this.wikiId, this.userId, this.groupId),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
// Load offline content.
|
||||||
|
this.contentControl!.setValue(page.cachedcontent);
|
||||||
|
this.originalContent = page.cachedcontent;
|
||||||
|
this.editOffline = true;
|
||||||
|
} else {
|
||||||
|
// No offline data found.
|
||||||
|
this.editOffline = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.editOffline = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
CoreDomUtils.showErrorModalDefault(error, 'Error getting wiki data.');
|
||||||
|
fetchFailed = true;
|
||||||
|
|
||||||
|
// Go back.
|
||||||
|
this.forceLeavePage();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (!canEdit && !fetchFailed) {
|
||||||
|
// Cannot edit, show alert and go back.
|
||||||
|
CoreDomUtils.showAlert(Translate.instant('core.notice'), Translate.instant('addon.mod_wiki.cannoteditpage'));
|
||||||
|
this.forceLeavePage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force leaving the page, without checking for changes.
|
||||||
|
*/
|
||||||
|
protected forceLeavePage(): void {
|
||||||
|
this.forceLeave = true;
|
||||||
|
CoreNavigator.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to a page.
|
||||||
|
*
|
||||||
|
* @param title Page title.
|
||||||
|
*/
|
||||||
|
protected goToPage(title: string): void {
|
||||||
|
// Not the firstpage.
|
||||||
|
AddonModWiki.setEditedPageData({
|
||||||
|
cmId: this.cmId,
|
||||||
|
courseId: this.courseId,
|
||||||
|
pageId: this.pageId,
|
||||||
|
pageTitle: title,
|
||||||
|
wikiId: this.wikiId!,
|
||||||
|
subwikiId: this.subwikiId,
|
||||||
|
userId: this.userId,
|
||||||
|
groupId: this.groupId,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.forceLeavePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if data has changed.
|
||||||
|
*
|
||||||
|
* @return Whether data has changed.
|
||||||
|
*/
|
||||||
|
protected hasDataChanged(): boolean {
|
||||||
|
const values = this.pageForm!.value;
|
||||||
|
|
||||||
|
return !(this.originalContent == values.text || (!this.editing && !values.text && !values.title));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
async canLeave(): Promise<boolean> {
|
||||||
|
if (this.forceLeave) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if data has changed.
|
||||||
|
if (this.hasDataChanged()) {
|
||||||
|
await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
ionViewDidLeave(): void {
|
||||||
|
// When going back, the ionViewDidEnter of the previous page should be called before this ionViewDidLeave.
|
||||||
|
// But just in case, use a timeout to make sure it does.
|
||||||
|
setTimeout(() => {
|
||||||
|
// Remove the edited page data (if any) if the previous page isn't a wiki page.
|
||||||
|
AddonModWiki.consumeEditedPageData();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the data.
|
||||||
|
*/
|
||||||
|
async save(): Promise<void> {
|
||||||
|
const values = this.pageForm!.value;
|
||||||
|
const title = values.title;
|
||||||
|
let text = values.text;
|
||||||
|
|
||||||
|
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
||||||
|
|
||||||
|
text = CoreTextUtils.restorePluginfileUrls(text, this.subwikiFiles);
|
||||||
|
text = CoreTextUtils.formatHtmlLines(text);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.editing) {
|
||||||
|
// Edit existing page.
|
||||||
|
await AddonModWiki.editPage(this.pageId!, text, this.section);
|
||||||
|
|
||||||
|
CoreForms.triggerFormSubmittedEvent(this.formElement, true, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
|
// Invalidate page since it changed.
|
||||||
|
await AddonModWiki.invalidatePage(this.pageId!);
|
||||||
|
|
||||||
|
return this.goToPage(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating a new page.
|
||||||
|
if (!title) {
|
||||||
|
// Title is mandatory, stop.
|
||||||
|
modal.dismiss();
|
||||||
|
CoreDomUtils.showAlert(
|
||||||
|
Translate.instant('core.notice'),
|
||||||
|
Translate.instant('addon.mod_wiki.titleshouldnotbeempty'),
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.editOffline) {
|
||||||
|
// Check if the user has an offline page with the same title.
|
||||||
|
const page = await CoreUtils.ignoreErrors(
|
||||||
|
AddonModWikiOffline.getNewPage(title, this.subwikiId, this.wikiId, this.userId, this.groupId),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
// There's a page with same title, reject with error message.
|
||||||
|
throw new CoreError(Translate.instant('addon.mod_wiki.pageexists'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to send the page.
|
||||||
|
const id = await AddonModWiki.newPage(title, text, {
|
||||||
|
subwikiId: this.subwikiId,
|
||||||
|
wikiId: this.wikiId,
|
||||||
|
userId: this.userId,
|
||||||
|
groupId: this.groupId,
|
||||||
|
cmId: this.cmId,
|
||||||
|
});
|
||||||
|
|
||||||
|
CoreForms.triggerFormSubmittedEvent(this.formElement, id > 0, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
|
if (id <= 0) {
|
||||||
|
// Page stored in offline. Go to see the offline page.
|
||||||
|
return this.goToPage(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page was created, get its data and go to the page.
|
||||||
|
CoreEvents.trigger(CoreEvents.ACTIVITY_DATA_SENT, { module: 'wiki' });
|
||||||
|
this.pageId = id;
|
||||||
|
|
||||||
|
const pageContents = await AddonModWiki.getPageContents(this.pageId, { cmId: this.cmId });
|
||||||
|
|
||||||
|
const promises: Promise<unknown>[] = [];
|
||||||
|
this.wikiId = pageContents.wikiid;
|
||||||
|
|
||||||
|
// Invalidate subwiki pages since there are new.
|
||||||
|
promises.push(AddonModWiki.invalidateSubwikiPages(this.wikiId));
|
||||||
|
if (!this.subwikiId) {
|
||||||
|
// Subwiki was not created, invalidate subwikis as well.
|
||||||
|
promises.push(AddonModWiki.invalidateSubwikis(this.wikiId));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subwikiId = pageContents.subwikiid;
|
||||||
|
this.userId = pageContents.userid;
|
||||||
|
this.groupId = pageContents.groupid;
|
||||||
|
|
||||||
|
await CoreUtils.ignoreErrors(Promise.all(promises));
|
||||||
|
|
||||||
|
// Notify page created.
|
||||||
|
CoreEvents.trigger(AddonModWikiProvider.PAGE_CREATED_EVENT, {
|
||||||
|
pageId: this.pageId,
|
||||||
|
subwikiId: this.subwikiId,
|
||||||
|
pageTitle: title,
|
||||||
|
}, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
|
this.goToPage(title);
|
||||||
|
} catch (error) {
|
||||||
|
CoreDomUtils.showErrorModalDefault(error, 'Error saving wiki data.');
|
||||||
|
} finally {
|
||||||
|
modal.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renew lock and control versions.
|
||||||
|
*/
|
||||||
|
protected async renewLock(): Promise<void> {
|
||||||
|
const response = await AddonModWiki.getPageForEditing(this.pageId!, this.section, true);
|
||||||
|
|
||||||
|
if (response.version && this.version != response.version) {
|
||||||
|
this.wrongVersionLock = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.isDestroyed = true;
|
||||||
|
clearInterval(this.renewLockInterval);
|
||||||
|
|
||||||
|
// Unblock the subwiki.
|
||||||
|
if (this.blockId) {
|
||||||
|
CoreSync.unblockOperation(this.component, this.blockId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,13 +14,14 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
||||||
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
||||||
import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course';
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSitesReadingStrategy } from '@services/sites';
|
import { CoreSitesReadingStrategy } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { makeSingleton, Translate } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
import { AddonModWikiIndexPage } from '../../pages/index';
|
import { AddonModWikiIndexPage } from '../../pages/index';
|
||||||
import { AddonModWiki } from '../wiki';
|
import { AddonModWiki } from '../wiki';
|
||||||
import { AddonModWikiModuleHandlerService } from './module';
|
import { AddonModWikiModuleHandlerService } from './module';
|
||||||
|
@ -105,37 +106,39 @@ export class AddonModWikiCreateLinkHandlerService extends CoreContentLinksHandle
|
||||||
const route = CoreNavigator.getCurrentRoute({ pageComponent: AddonModWikiIndexPage });
|
const route = CoreNavigator.getCurrentRoute({ pageComponent: AddonModWikiIndexPage });
|
||||||
const subwikiId = parseInt(params.swid, 10);
|
const subwikiId = parseInt(params.swid, 10);
|
||||||
const wikiId = parseInt(params.wid, 10);
|
const wikiId = parseInt(params.wid, 10);
|
||||||
let module: CoreCourseAnyModuleData;
|
let moduleId: number;
|
||||||
|
|
||||||
// Check if the link is inside the same wiki.
|
// Check if the link is inside the same wiki.
|
||||||
const isSameWiki = await this.currentStateIsSameWiki(route, subwikiId, siteId);
|
const isSameWiki = await this.currentStateIsSameWiki(route, subwikiId, siteId);
|
||||||
|
|
||||||
if (isSameWiki) {
|
if (isSameWiki) {
|
||||||
// User is seeing the wiki, we can get the module from the wiki params.
|
// User is seeing the wiki, we can get the module from the wiki params.
|
||||||
module = route!.snapshot.queryParams.module;
|
moduleId = route!.snapshot.params.cmId;
|
||||||
|
courseId = route!.snapshot.params.courseId;
|
||||||
} else if (wikiId) {
|
} else if (wikiId) {
|
||||||
// The URL specifies which wiki it belongs to. Get the module.
|
// The URL specifies which wiki it belongs to. Get the module.
|
||||||
module = await CoreCourse.getModuleBasicInfoByInstance(wikiId, 'wiki', siteId);
|
const module = await CoreCourse.getModuleBasicInfoByInstance(wikiId, 'wiki', siteId);
|
||||||
|
|
||||||
|
moduleId = module.id;
|
||||||
|
courseId = module.course;
|
||||||
} else {
|
} else {
|
||||||
// Not enough data.
|
// Not enough data.
|
||||||
CoreDomUtils.showErrorModal(Translate.instant('addon.mod_wiki.errorloadingpage'));
|
throw new CoreError();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the page.
|
// Open the page.
|
||||||
CoreNavigator.navigateToSitePath(
|
CoreNavigator.navigateToSitePath(
|
||||||
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/edit`,
|
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${moduleId}/edit`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
module: module,
|
|
||||||
courseId: courseId || module.course || route?.snapshot.params.courseId,
|
|
||||||
pageTitle: params.title,
|
pageTitle: params.title,
|
||||||
subwikiId: subwikiId,
|
subwikiId: subwikiId,
|
||||||
},
|
},
|
||||||
siteId,
|
siteId,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_wiki.errorloadingpage', true);
|
||||||
} finally {
|
} finally {
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,12 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
||||||
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
||||||
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { AddonModWiki } from '../wiki';
|
||||||
|
import { AddonModWikiModuleHandlerService } from './module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to treat links to edit a wiki page.
|
* Handler to treat links to edit a wiki page.
|
||||||
|
@ -36,23 +41,40 @@ export class AddonModWikiEditLinkHandlerService extends CoreContentLinksHandlerB
|
||||||
params: Record<string, string>,
|
params: Record<string, string>,
|
||||||
courseId?: number,
|
courseId?: number,
|
||||||
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||||
courseId = Number(courseId || params.courseid || params.cid);
|
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
action: (siteId: string) => {
|
action: async (siteId: string) => {
|
||||||
|
const modal = await CoreDomUtils.showModalLoading();
|
||||||
|
|
||||||
let section = '';
|
try {
|
||||||
if (typeof params.section != 'undefined') {
|
const pageId = Number(params.pageid);
|
||||||
section = params.section.replace(/\+/g, ' ');
|
|
||||||
|
const pageContents = await AddonModWiki.getPageContents(pageId, { siteId });
|
||||||
|
|
||||||
|
const module = await CoreCourse.getModuleBasicInfoByInstance(pageContents.wikiid, 'wiki', siteId);
|
||||||
|
|
||||||
|
let section = '';
|
||||||
|
if (typeof params.section != 'undefined') {
|
||||||
|
section = params.section.replace(/\+/g, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
courseId = module.course || courseId || Number(params.courseid || params.cid);
|
||||||
|
|
||||||
|
CoreNavigator.navigateToSitePath(
|
||||||
|
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/edit`,
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
section: section,
|
||||||
|
pageId: pageId,
|
||||||
|
},
|
||||||
|
siteId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_wiki.errorloadingpage', true);
|
||||||
|
} finally {
|
||||||
|
modal.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageParams = {
|
|
||||||
courseId: courseId,
|
|
||||||
section: section,
|
|
||||||
pageId: parseInt(params.pageid, 10),
|
|
||||||
};
|
|
||||||
|
|
||||||
// @todo this.linkHelper.goInSite(navCtrl, 'AddonModWikiEditPage', pageParams, siteId);
|
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class AddonModWikiModuleHandlerService implements CoreCourseModuleHandler
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.params = options.params || {};
|
options.params = options.params || {};
|
||||||
Object.assign(options.params, { module });
|
Object.assign(options.params, { module });
|
||||||
const routeParams = `/${courseId}/${module.id}/root`;
|
const routeParams = `/${courseId}/${module.id}/page/root`;
|
||||||
|
|
||||||
CoreNavigator.navigateToSitePath(AddonModWikiModuleHandlerService.PAGE_NAME + routeParams, options);
|
CoreNavigator.navigateToSitePath(AddonModWikiModuleHandlerService.PAGE_NAME + routeParams, options);
|
||||||
},
|
},
|
||||||
|
|
|
@ -67,7 +67,7 @@ export class AddonModWikiPageOrMapLinkHandlerService extends CoreContentLinksHan
|
||||||
courseId = courseId || module.course;
|
courseId = courseId || module.course;
|
||||||
|
|
||||||
CoreNavigator.navigateToSitePath(
|
CoreNavigator.navigateToSitePath(
|
||||||
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/${hash}`,
|
AddonModWikiModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/page/${hash}`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
pageId: page.id,
|
pageId: page.id,
|
||||||
|
|
|
@ -52,7 +52,7 @@ export class AddonModWikiSyncProvider extends CoreSyncBaseProvider<AddonModWikiS
|
||||||
* @param groupId Group ID. Optional, will be used to create the subwiki if subwiki ID not provided.
|
* @param groupId Group ID. Optional, will be used to create the subwiki if subwiki ID not provided.
|
||||||
* @return Identifier.
|
* @return Identifier.
|
||||||
*/
|
*/
|
||||||
getSubwikiBlockId(subwikiId: number, wikiId?: number, userId?: number, groupId?: number): string {
|
getSubwikiBlockId(subwikiId?: number, wikiId?: number, userId?: number, groupId?: number): string {
|
||||||
subwikiId = AddonModWikiOffline.convertToPositiveNumber(subwikiId);
|
subwikiId = AddonModWikiOffline.convertToPositiveNumber(subwikiId);
|
||||||
|
|
||||||
if (subwikiId && subwikiId > 0) {
|
if (subwikiId && subwikiId > 0) {
|
||||||
|
|
|
@ -43,6 +43,7 @@ export class AddonModWikiProvider {
|
||||||
|
|
||||||
protected subwikiListsCache: {[wikiId: number]: AddonModWikiSubwikiListData} = {};
|
protected subwikiListsCache: {[wikiId: number]: AddonModWikiSubwikiListData} = {};
|
||||||
protected wikiFirstViewedPage: Record<string, Record<number, string>> = {};
|
protected wikiFirstViewedPage: Record<string, Record<number, string>> = {};
|
||||||
|
protected editedPage?: AddonModWikiEditedPageData;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Clear subwiki lists cache on logout.
|
// Clear subwiki lists cache on logout.
|
||||||
|
@ -64,6 +65,18 @@ export class AddonModWikiProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete and return the edited page data if any.
|
||||||
|
*
|
||||||
|
* @return Edited page data, undefined if no data.
|
||||||
|
*/
|
||||||
|
consumeEditedPageData(): AddonModWikiEditedPageData | undefined {
|
||||||
|
const editedPage = this.editedPage;
|
||||||
|
delete this.editedPage;
|
||||||
|
|
||||||
|
return editedPage;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save wiki contents on a page or section.
|
* Save wiki contents on a page or section.
|
||||||
*
|
*
|
||||||
|
@ -754,6 +767,15 @@ export class AddonModWikiProvider {
|
||||||
return response.pageid;
|
return response.pageid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set edited page data.
|
||||||
|
*
|
||||||
|
* @param data Data.
|
||||||
|
*/
|
||||||
|
setEditedPageData(data: AddonModWikiEditedPageData): void {
|
||||||
|
this.editedPage = data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save subwiki list for a wiki to the cache.
|
* Save subwiki list for a wiki to the cache.
|
||||||
*
|
*
|
||||||
|
@ -1189,3 +1211,17 @@ export type AddonModWikiPageCreatedData = {
|
||||||
subwikiId: number;
|
subwikiId: number;
|
||||||
pageTitle: string;
|
pageTitle: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data about a page that was just edited.
|
||||||
|
*/
|
||||||
|
export type AddonModWikiEditedPageData = {
|
||||||
|
cmId: number;
|
||||||
|
courseId: number;
|
||||||
|
wikiId: number;
|
||||||
|
pageTitle: string;
|
||||||
|
subwikiId?: number;
|
||||||
|
userId?: number;
|
||||||
|
groupId?: number;
|
||||||
|
pageId?: number;
|
||||||
|
};
|
||||||
|
|
|
@ -17,12 +17,20 @@ import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
import { AddonModWikiComponentsModule } from './components/components.module';
|
import { AddonModWikiComponentsModule } from './components/components.module';
|
||||||
import { AddonModWikiIndexPage } from './pages/index/index';
|
import { AddonModWikiIndexPage } from './pages/index/index';
|
||||||
|
import { CoreEditorComponentsModule } from '@features/editor/components/components.module';
|
||||||
|
import { CanLeaveGuard } from '@guards/can-leave';
|
||||||
|
import { AddonModWikiEditPage } from './pages/edit/edit';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: ':courseId/:cmId/:hash',
|
path: ':courseId/:cmId/page/:hash',
|
||||||
component: AddonModWikiIndexPage,
|
component: AddonModWikiIndexPage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: ':courseId/:cmId/edit',
|
||||||
|
component: AddonModWikiEditPage,
|
||||||
|
canDeactivate: [CanLeaveGuard],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -30,9 +38,11 @@ const routes: Routes = [
|
||||||
RouterModule.forChild(routes),
|
RouterModule.forChild(routes),
|
||||||
CoreSharedModule,
|
CoreSharedModule,
|
||||||
AddonModWikiComponentsModule,
|
AddonModWikiComponentsModule,
|
||||||
|
CoreEditorComponentsModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AddonModWikiIndexPage,
|
AddonModWikiIndexPage,
|
||||||
|
AddonModWikiEditPage,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AddonModWikiLazyModule {}
|
export class AddonModWikiLazyModule {}
|
||||||
|
|
Loading…
Reference in New Issue