diff --git a/src/addon/mod/wiki/pages/edit/edit.ts b/src/addon/mod/wiki/pages/edit/edit.ts
index b64a0fbe5..0a7dfdc14 100644
--- a/src/addon/mod/wiki/pages/edit/edit.ts
+++ b/src/addon/mod/wiki/pages/edit/edit.ts
@@ -482,8 +482,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
pageId: this.pageId,
subwikiId: this.subwikiId,
pageTitle: title,
- siteId: this.sitesProvider.getCurrentSiteId()
- });
+ }, this.sitesProvider.getCurrentSiteId());
});
} else {
// Page stored in offline. Go to see the offline page.
diff --git a/src/addon/mod/workshop/components/index/index.ts b/src/addon/mod/workshop/components/index/index.ts
index ecbb91bbf..dbe91b367 100644
--- a/src/addon/mod/workshop/components/index/index.ts
+++ b/src/addon/mod/workshop/components/index/index.ts
@@ -117,7 +117,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
* @param {any} data Data received by the event.
*/
protected eventReceived(data: any): void {
- if ((this.workshop && this.workshop.id === data.workshopid) || data.cmid === module.id) {
+ if ((this.workshop && this.workshop.id === data.workshopId) || data.cmId === this.module.id) {
this.content && this.content.scrollToTop();
this.loaded = false;
@@ -297,7 +297,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
if (task.code == 'submit' && this.canSubmit && ((this.access.creatingsubmissionallowed && !this.submission) ||
(this.access.modifyingsubmissionallowed && this.submission))) {
const params = {
- module: module,
+ module: this.module,
access: this.access,
courseId: this.courseId,
submission: this.submission
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.html b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
new file mode 100644
index 000000000..e03d7087c
--- /dev/null
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
@@ -0,0 +1,30 @@
+
+
+ {{ 'addon.mod_workshop.editsubmission' | translate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
new file mode 100644
index 000000000..c49f5e606
--- /dev/null
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
@@ -0,0 +1,33 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { NgModule } from '@angular/core';
+import { IonicPageModule } from 'ionic-angular';
+import { TranslateModule } from '@ngx-translate/core';
+import { CoreComponentsModule } from '@components/components.module';
+import { CoreDirectivesModule } from '@directives/directives.module';
+import { AddonModWorkshopEditSubmissionPage } from './edit-submission';
+
+@NgModule({
+ declarations: [
+ AddonModWorkshopEditSubmissionPage,
+ ],
+ imports: [
+ CoreDirectivesModule,
+ CoreComponentsModule,
+ IonicPageModule.forChild(AddonModWorkshopEditSubmissionPage),
+ TranslateModule.forChild()
+ ],
+})
+export class AddonModWorkshopEditSubmissionPageModule {}
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
new file mode 100644
index 000000000..213aebe00
--- /dev/null
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
@@ -0,0 +1,395 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { IonicPage, NavParams, NavController } from 'ionic-angular';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { TranslateService } from '@ngx-translate/core';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
+import { CoreSyncProvider } from '@providers/sync';
+import { CoreFileSessionProvider } from '@providers/file-session';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
+import { CoreTextUtilsProvider } from '@providers/utils/text';
+import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
+import { AddonModWorkshopProvider } from '../../providers/workshop';
+import { AddonModWorkshopHelperProvider } from '../../providers/helper';
+import { AddonModWorkshopOfflineProvider } from '../../providers/offline';
+
+/**
+ * Page that displays the workshop edit submission.
+ */
+@IonicPage({ segment: 'addon-mod-workshop-edit-submission' })
+@Component({
+ selector: 'page-addon-mod-workshop-edit-submission',
+ templateUrl: 'edit-submission.html',
+})
+export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
+
+ module: any;
+ courseId: number;
+ access: any;
+ submission: any;
+
+ title: string;
+ loaded = false;
+ component = AddonModWorkshopProvider.COMPONENT;
+ componentId: number;
+ editForm: FormGroup; // The form group.
+
+ protected workshopId: number;
+ protected userId: number;
+ protected originalData: any = {};
+ protected hasOffline = false;
+ protected editing = false;
+ protected forceLeave = false;
+ protected siteId: string;
+ protected workshop: any;
+
+ constructor(navParams: NavParams, sitesProvider: CoreSitesProvider, protected fileUploaderProvider: CoreFileUploaderProvider,
+ protected workshopProvider: AddonModWorkshopProvider, protected workshopOffline: AddonModWorkshopOfflineProvider,
+ protected workshopHelper: AddonModWorkshopHelperProvider, protected navCtrl: NavController,
+ protected fileSessionprovider: CoreFileSessionProvider, protected syncProvider: CoreSyncProvider,
+ protected textUtils: CoreTextUtilsProvider, protected domUtils: CoreDomUtilsProvider, protected fb: FormBuilder,
+ protected translate: TranslateService, protected eventsProvider: CoreEventsProvider) {
+ this.module = navParams.get('module');
+ this.courseId = navParams.get('courseId');
+ this.access = navParams.get('access');
+ this.submission = navParams.get('submission') || {};
+
+ this.title = this.module.name;
+ this.workshopId = this.module.instance;
+ this.componentId = this.module.id;
+ this.userId = sitesProvider.getCurrentSiteUserId();
+ this.siteId = sitesProvider.getCurrentSiteId();
+
+ this.editForm = new FormGroup({});
+ this.editForm.addControl('title', this.fb.control('', Validators.required));
+ this.editForm.addControl('content', this.fb.control(''));
+ }
+
+ /**
+ * Component being initialized.
+ */
+ ngOnInit(): void {
+ this.fetchSubmissionData();
+ }
+
+ /**
+ * Check if we can leave the page or not.
+ *
+ * @return {boolean|Promise} Resolved if we can leave it, rejected if not.
+ */
+ ionViewCanLeave(): boolean | Promise {
+ if (this.forceLeave) {
+ return true;
+ }
+
+ let promise;
+
+ // Check if data has changed.
+ if (!this.hasDataChanged()) {
+ promise = Promise.resolve();
+ } else {
+ // Show confirmation if some data has been modified.
+ promise = this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
+ }
+
+ return promise.then(() => {
+ if (this.submission.attachmentfiles) {
+ // Delete the local files from the tmp folder.
+ this.fileUploaderProvider.clearTmpFiles(this.submission.attachmentfiles);
+ }
+ });
+ }
+
+ /**
+ * Fetch the submission data.
+ *
+ * @return {Promise} Resolved when done.
+ */
+ protected fetchSubmissionData(): Promise {
+ return this.workshopProvider.getWorkshop(this.courseId, this.module.id).then((workshopData) => {
+ this.workshop = workshopData;
+
+ if (this.submission && this.submission.id > 0) {
+ this.editing = true;
+
+ return this.workshopHelper.getSubmissionById(this.workshopId, this.submission.id).then((submissionData) => {
+ this.submission = submissionData;
+ this.submission.text = submissionData.content;
+
+ const canEdit = (this.userId == submissionData.authorid && this.access.cansubmit &&
+ this.access.modifyingsubmissionallowed);
+ if (!canEdit) {
+ // Should not happen, but go back if does.
+ this.forceLeavePage();
+
+ return;
+ }
+ });
+ } else if (!this.access.cansubmit || !this.access.creatingsubmissionallowed) {
+ // Should not happen, but go back if does.
+ this.forceLeavePage();
+
+ return;
+ }
+
+ }).then(() => {
+ return this.workshopOffline.getSubmissions(this.workshopId).then((submissionsActions) => {
+ if (submissionsActions && submissionsActions.length) {
+ this.hasOffline = true;
+ const actions = this.workshopHelper.filterSubmissionActions(submissionsActions, this.editing ?
+ this.submission.id : false);
+
+ return this.workshopHelper.applyOfflineData(this.submission, actions).then((offlineSubmission) => {
+ this.submission.title = offlineSubmission.title;
+ this.submission.text = offlineSubmission.content;
+ this.submission.attachmentfiles = offlineSubmission.attachmentfiles;
+ });
+ } else {
+ this.hasOffline = false;
+ }
+ }).finally(() => {
+ this.originalData.title = this.submission.title;
+ this.originalData.content = this.submission.text;
+ this.originalData.attachmentfiles = [];
+
+ this.submission.attachmentfiles.forEach((file) => {
+ let filename;
+ if (file.filename) {
+ filename = file.filename;
+ } else {
+ // We don't have filename, extract it from the path.
+ filename = file.filepath[0] == '/' ? file.filepath.substr(1) : file.filepath;
+ }
+
+ this.originalData.attachmentfiles.push({
+ filename : filename,
+ fileurl: file.fileurl
+ });
+ });
+ });
+ }).then(() => {
+ // Create the form group and its controls.
+ this.editForm.controls['title'].setValue(this.submission.title);
+ this.editForm.controls['content'].setValue(this.submission.content);
+
+ const submissionId = this.submission.id || 'newsub';
+ this.fileSessionprovider.setFiles(this.component,
+ this.workshopId + '_' + submissionId, this.submission.attachmentfiles || []);
+
+ this.loaded = true;
+ }).catch((message) => {
+ this.loaded = false;
+
+ this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
+
+ this.forceLeavePage();
+ });
+ }
+
+ /**
+ * Force leaving the page, without checking for changes.
+ */
+ protected forceLeavePage(): void {
+ this.forceLeave = true;
+ this.navCtrl.pop();
+ }
+
+ /**
+ * Get the form input data.
+ *
+ * @return {any} Object with all the info.
+ */
+ protected getInputData(): any {
+ const submissionId = this.submission.id || 'newsub';
+
+ const values = this.editForm.value;
+ values['attachmentfiles'] = this.fileSessionprovider.getFiles(this.component, this.workshopId + '_' + submissionId) || [];
+
+ return values;
+ }
+
+ /**
+ * Check if data has changed.
+ *
+ * @return {boolean} True if changed or false if not.
+ */
+ protected hasDataChanged(): boolean {
+ if (!this.loaded) {
+ return false;
+ }
+
+ const inputData = this.getInputData();
+ if (!this.originalData || typeof this.originalData.title == 'undefined') {
+ // There is no original data, assume it hasn't changed.
+ return false;
+ }
+
+ if (this.originalData.title != inputData.title || this.originalData.content != inputData.content) {
+ return true;
+ }
+
+ return this.fileUploaderProvider.areFileListDifferent(inputData.attachmentfiles, this.originalData.attachmentfiles);
+ }
+
+ /**
+ * Pull to refresh.
+ *
+ * @param {any} refresher Refresher.
+ */
+ refreshSubmission(refresher: any): void {
+ if (this.loaded) {
+ const promises = [];
+
+ promises.push(this.workshopProvider.invalidateSubmissionData(this.workshopId, this.submission.id));
+ promises.push(this.workshopProvider.invalidateSubmissionsData(this.workshopId));
+
+ Promise.all(promises).finally(() => {
+ return this.fetchSubmissionData();
+ }).finally(() => {
+ refresher.complete();
+ });
+ }
+ }
+
+ /**
+ * Save the submission.
+ */
+ save(): void {
+ // Check if data has changed.
+ if (this.hasDataChanged()) {
+ this.saveSubmission().then(() => {
+ // Go back to entry list.
+ this.forceLeavePage();
+ }).catch(() => {
+ // Nothing to do.
+ });
+ } else {
+ // Nothing to save, just go back.
+ this.forceLeavePage();
+ }
+ }
+
+ /**
+ * Send submission and save.
+ *
+ * @return {Promise} Resolved when done.
+ */
+ protected saveSubmission(): Promise {
+ const inputData = this.getInputData();
+
+ if (!inputData.title) {
+ this.domUtils.showAlert('core.notice', 'core.requireduserdatamissing');
+
+ return Promise.reject(null);
+ }
+ if (!inputData.content) {
+ this.domUtils.showAlert('core.notice', 'addon.mod_workshop.submissionrequiredcontent');
+
+ return Promise.reject(null);
+ }
+
+ let allowOffline = true,
+ saveOffline = false;
+
+ const modal = this.domUtils.showModalLoading('core.sending', true),
+ submissionId = this.submission && (this.submission.id || this.submission.submissionid) || false;
+
+ // Check if rich text editor is enabled or not.
+ return this.domUtils.isRichTextEditorEnabled().then((rteEnabled) => {
+ if (rteEnabled) {
+ inputData.content = this.textUtils.restorePluginfileUrls(inputData.content, this.submission.inlinefiles);
+ } else {
+ // Rich text editor not enabled, add some HTML to the message if needed.
+ inputData.content = this.textUtils.formatHtmlLines(inputData.content);
+ }
+
+ // Upload attachments first if any.
+ allowOffline = !inputData.attachmentfiles.length;
+
+ return this.workshopHelper.uploadOrStoreSubmissionFiles(this.workshopId, submissionId, inputData.attachmentfiles,
+ this.editing, saveOffline).catch(() => {
+ // Cannot upload them in online, save them in offline.
+ saveOffline = true;
+ allowOffline = true;
+
+ return this.workshopHelper.uploadOrStoreSubmissionFiles(this.workshopId, submissionId, inputData.attachmentfiles,
+ this.editing, saveOffline);
+ });
+ }).then((attachmentsId) => {
+ if (this.editing) {
+ if (saveOffline) {
+ // Save submission in offline.
+ return this.workshopOffline.saveSubmission(this.workshopId, this.courseId, inputData.title,
+ inputData.content, attachmentsId, submissionId, 'update').then(() => {
+ // Don't return anything.
+ });
+ }
+
+ // Try to send it to server.
+ // Don't allow offline if there are attachments since they were uploaded fine.
+ return this.workshopProvider.updateSubmission(this.workshopId, submissionId, this.courseId, inputData.title,
+ inputData.content, attachmentsId, undefined, allowOffline);
+ }
+
+ if (saveOffline) {
+ // Save submission in offline.
+ return this.workshopOffline.saveSubmission(this.workshopId, this.courseId, inputData.title, inputData.content,
+ attachmentsId, submissionId, 'add').then(() => {
+ // Don't return anything.
+ });
+ }
+
+ // Try to send it to server.
+ // Don't allow offline if there are attachments since they were uploaded fine.
+ return this.workshopProvider.addSubmission(this.workshopId, this.courseId, inputData.title, inputData.content,
+ attachmentsId, undefined, submissionId, allowOffline);
+ }).then((newSubmissionId) => {
+ const data = {
+ workshopId: this.workshopId,
+ cmId: this.module.cmid
+ };
+
+ if (newSubmissionId && submissionId) {
+ // Data sent to server, delete stored files (if any).
+ this.workshopOffline.deleteSubmissionAction(this.workshopId, submissionId, this.editing ? 'update' : 'add');
+ this.workshopHelper.deleteSubmissionStoredFiles(this.workshopId, submissionId, this.editing);
+ data['submissionId'] = newSubmissionId;
+ }
+
+ const promise = newSubmissionId ? this.workshopProvider.invalidateSubmissionData(this.workshopId, newSubmissionId) :
+ Promise.resolve();
+
+ return promise.finally(() => {
+ this.eventsProvider.trigger(AddonModWorkshopProvider.SUBMISSION_CHANGED, data, this.siteId);
+
+ // Delete the local files from the tmp folder.
+ this.fileUploaderProvider.clearTmpFiles(inputData.attachmentfiles);
+ });
+ }).catch((message) => {
+ this.domUtils.showErrorModalDefault(message, 'Cannot save submission');
+ }).finally(() => {
+ modal.dismiss();
+ });
+ }
+
+ /**
+ * Component being destroyed.
+ */
+ ngOnDestroy(): void {
+ this.syncProvider.unblockOperation(this.component, this.workshopId);
+ }
+}
diff --git a/src/addon/mod/workshop/providers/workshop.ts b/src/addon/mod/workshop/providers/workshop.ts
index 9962b836d..27660ef6f 100644
--- a/src/addon/mod/workshop/providers/workshop.ts
+++ b/src/addon/mod/workshop/providers/workshop.ts
@@ -215,10 +215,9 @@ export class AddonModWorkshopProvider {
return site.read('mod_workshop_get_workshops_by_courses', params, preSets).then((response) => {
if (response && response.workshops) {
- for (const x in response.workshops) {
- if (response.workshops[x][key] == value) {
- return response.workshops[x];
- }
+ const workshopFound = response.workshops.find((workshop) => workshop[key] == value);
+ if (workshopFound) {
+ return workshopFound;
}
}