diff --git a/src/addon/mod/data/components/action/action.ts b/src/addon/mod/data/components/action/action.ts index dab8a35d0..32be60ec3 100644 --- a/src/addon/mod/data/components/action/action.ts +++ b/src/addon/mod/data/components/action/action.ts @@ -30,6 +30,7 @@ export class AddonModDataActionComponent implements OnInit { @Input() action: string; // The field to render. @Input() entry?: any; // The value of the field. @Input() database: any; // Database object. + @Input() offset?: number; // Offset of the entry. siteId: string; rootUrl: string; @@ -67,6 +68,9 @@ export class AddonModDataActionComponent implements OnInit { switch (this.action) { case 'more': this.url = this.rootUrl + '/mod/data/view.php?d= ' + this.entry.dataid + '&rid=' + this.entry.id; + if (typeof this.offset == 'number') { + this.url += '&mode=single&page=' + this.offset; + } break; case 'edit': this.url = this.rootUrl + '/mod/data/edit.php?d= ' + this.entry.dataid + '&rid=' + this.entry.id; diff --git a/src/addon/mod/data/components/index/index.ts b/src/addon/mod/data/components/index/index.ts index 9e32c7afb..9da9180fe 100644 --- a/src/addon/mod/data/components/index/index.ts +++ b/src/addon/mod/data/components/index/index.ts @@ -47,7 +47,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp timeAvailableToReadable: string | boolean; isEmpty = false; groupInfo: CoreGroupInfo; - entries = {}; + entries = []; firstEntry = false; canAdd = false; canSearch = false; @@ -317,6 +317,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp }); return Promise.all(promises).then((entries) => { + this.entries = entries; + let entriesHTML = this.data.listtemplateheader || ''; // Get first entry from the whole list. @@ -326,12 +328,15 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp const template = this.data.listtemplate || this.dataHelper.getDefaultTemplate('list', this.fieldsArray); - entries.forEach((entry) => { - this.entries[entry.id] = entry; + const entriesById = {}; + entries.forEach((entry, index) => { + entriesById[entry.id] = entry; const actions = this.dataHelper.getActions(this.data, this.access, entry); + const offset = this.search.page * AddonModDataProvider.PER_PAGE + index; - entriesHTML += this.dataHelper.displayShowFields(template, this.fieldsArray, entry, 'list', actions); + entriesHTML += this.dataHelper.displayShowFields(template, this.fieldsArray, entry, offset, 'list', + actions); }); entriesHTML += this.data.listtemplatefooter || ''; @@ -340,7 +345,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp // Pass the input data to the component. this.jsData = { fields: this.fields, - entries: this.entries, + entries: entriesById, data: this.data, gotoEntry: this.gotoEntry.bind(this) }; @@ -440,9 +445,16 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp module: this.module, courseId: this.courseId, entryId: entryId, - group: this.selectedGroup + group: this.selectedGroup, + offset: null }; + // Try to find page number and offset of the entry. + const pageXOffset = this.entries.findIndex((entry) => entry.id == entryId); + if (pageXOffset >= 0) { + params.offset = this.search.page * AddonModDataProvider.PER_PAGE + pageXOffset; + } + this.navCtrl.push('AddonModDataEntryPage', params); } diff --git a/src/addon/mod/data/pages/entry/entry.html b/src/addon/mod/data/pages/entry/entry.html index c1d727795..a49acdf57 100644 --- a/src/addon/mod/data/pages/entry/entry.html +++ b/src/addon/mod/data/pages/entry/entry.html @@ -34,16 +34,16 @@ - + - - - - diff --git a/src/addon/mod/data/pages/entry/entry.ts b/src/addon/mod/data/pages/entry/entry.ts index 8ea967f72..16a35f39e 100644 --- a/src/addon/mod/data/pages/entry/entry.ts +++ b/src/addon/mod/data/pages/entry/entry.ts @@ -41,7 +41,7 @@ export class AddonModDataEntryPage implements OnDestroy { protected module: any; protected entryId: number; protected courseId: number; - protected page: number; + protected offset: number; protected syncObserver: any; // It will observe the sync auto event. protected entryChangedObserver: any; // It will observe the changed entry event. protected fields = {}; @@ -55,8 +55,8 @@ export class AddonModDataEntryPage implements OnDestroy { offlineActions = []; hasOffline = false; cssTemplate = ''; - previousId: number; - nextId: number; + previousOffset: number; + nextOffset: number; access: any; data: any; groupInfo: any; @@ -77,7 +77,7 @@ export class AddonModDataEntryPage implements OnDestroy { this.entryId = params.get('entryId') || null; this.courseId = params.get('courseId'); this.selectedGroup = params.get('group') || 0; - this.page = params.get('page') || null; + this.offset = params.get('offset'); this.siteId = sitesProvider.getCurrentSiteId(); @@ -133,7 +133,7 @@ export class AddonModDataEntryPage implements OnDestroy { this.data = data; this.cssClass = 'addon-data-entries-' + data.id; - return this.setEntryIdFromPage(data.id, this.page, this.selectedGroup).then(() => { + return this.setEntryIdFromOffset(data.id, this.offset, this.selectedGroup).then(() => { return this.dataProvider.getDatabaseAccessInformation(data.id); }); }).then((accessData) => { @@ -177,7 +177,7 @@ export class AddonModDataEntryPage implements OnDestroy { const actions = this.dataHelper.getActions(this.data, this.access, this.entry); const templte = this.data.singletemplate || this.dataHelper.getDefaultTemplate('single', fieldsArray); - this.entryRendered = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, 'show', actions); + this.entryRendered = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, this.offset, 'show', actions); this.showComments = actions.comments; const entries = {}; @@ -189,11 +189,6 @@ export class AddonModDataEntryPage implements OnDestroy { entries: entries, data: this.data }; - - return this.dataHelper.getPageInfoByEntry(this.data.id, this.entryId, this.selectedGroup).then((result) => { - this.previousId = result.previousId; - this.nextId = result.nextId; - }); }).catch((message) => { if (!refresh) { // Some call failed, retry without using cache since it might be a new activity. @@ -210,13 +205,13 @@ export class AddonModDataEntryPage implements OnDestroy { /** * Go to selected entry without changing state. * - * @param {number} entry Entry Id where to go. - * @return {Promise} Resolved when done. + * @param {number} offset Entry offset. + * @return {Promise} Resolved when done. */ - gotoEntry(entry: number): Promise { - this.entryId = entry; + gotoEntry(offset: number): Promise { + this.offset = offset; + this.entryId = null; this.entry = null; - this.page = null; this.entryLoaded = false; return this.fetchEntryData(); @@ -264,30 +259,56 @@ export class AddonModDataEntryPage implements OnDestroy { */ setGroup(groupId: number): Promise { this.selectedGroup = groupId; + this.offset = 0; + this.entry = null; + this.entryId = null; this.entryLoaded = false; - return this.setEntryIdFromPage(this.data.id, 0, this.selectedGroup).then(() => { - return this.fetchEntryData(); - }); + return this.fetchEntryData(); } /** - * Convenience function to translate page number to entry identifier. + * Convenience function to translate offset to entry identifier and set next/previous entries. * - * @param {number} dataId Data Id. - * @param {number} [pageNumber] Page number where to go - * @param {number} group Group Id to get the entry. - * @return {Promise} Resolved when done. + * @param {number} dataId Data Id. + * @param {number} [offset] Offset of the entry. + * @param {number} [groupId] Group Id to get the entry. + * @return {Promise} Resolved when done. */ - protected setEntryIdFromPage(dataId: number, pageNumber?: number, group?: number): Promise { - if (typeof pageNumber == 'number') { - return this.dataHelper.getPageInfoByPage(dataId, pageNumber, group).then((result) => { - this.entryId = result.entryId; - this.page = null; - }); + protected setEntryIdFromOffset(dataId: number, offset?: number, groupId?: number): Promise { + if (typeof offset != 'number') { + // Entry id passed as navigation parameter instead of the offset. + // We don't display next/previous buttons in this case. + this.nextOffset = null; + this.previousOffset = null; + + return Promise.resolve(); } - return Promise.resolve(); + const perPage = AddonModDataProvider.PER_PAGE; + const page = Math.floor(offset / perPage); + const pageOffset = offset % perPage; + + return this.dataProvider.getEntries(dataId, groupId, undefined, undefined, page, perPage).then((entries) => { + if (!entries || !entries.entries || !entries.entries.length || pageOffset >= entries.entries.length) { + return Promise.reject(null); + } + + this.entryId = entries.entries[pageOffset].id; + this.previousOffset = offset > 0 ? offset - 1 : null; + if (pageOffset + 1 < entries.entries.length) { + // Not the last entry on the page; + this.nextOffset = offset + 1; + } else if (entries.entries.length < perPage) { + // Last entry of the last page. + this.nextOffset = null; + } else { + // Last entry of the page, check if there are more pages. + return this.dataProvider.getEntries(dataId, groupId, undefined, undefined, page + 1, perPage).then((entries) => { + this.nextOffset = entries && entries.entries && entries.entries.length > 0 ? offset + 1 : null; + }); + } + }); } /** diff --git a/src/addon/mod/data/providers/helper.ts b/src/addon/mod/data/providers/helper.ts index 97f6ac5e2..a94879196 100644 --- a/src/addon/mod/data/providers/helper.ts +++ b/src/addon/mod/data/providers/helper.ts @@ -100,11 +100,12 @@ export class AddonModDataHelperProvider { * @param {string} template Template HMTL. * @param {any[]} fields Fields that defines every content in the entry. * @param {any} entry Entry. + * @param {number} offset Entry offset. * @param {string} mode Mode list or show. * @param {any} actions Actions that can be performed to the record. * @return {string} Generated HTML. */ - displayShowFields(template: string, fields: any[], entry: any, mode: string, actions: any): string { + displayShowFields(template: string, fields: any[], entry: any, offset: number, mode: string, actions: any): string { if (!template) { return ''; } @@ -135,7 +136,7 @@ export class AddonModDataHelperProvider { render = this.translate.instant('addon.mod_data.' + (entry.approved ? 'approved' : 'notapproved')); } else { render = ''; + ']" mode="' + mode + '" [database]="data" [offset]="' + offset + '">'; } template = template.replace(replace, render); } else { @@ -177,24 +178,6 @@ export class AddonModDataHelperProvider { }; } - /** - * Fetch all entries and return it's Id - * - * @param {number} dataId Data ID. - * @param {number} groupId Group ID. - * @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. - * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). - * @param {string} [siteId] Site ID. Current if not defined. - * @return {Promise} Resolved with an array of entry ID. - */ - getAllEntriesIds(dataId: number, groupId: number, forceCache: boolean = false, ignoreCache: boolean = false, siteId?: string): - Promise { - return this.dataProvider.fetchAllEntries(dataId, groupId, undefined, undefined, undefined, forceCache, ignoreCache, siteId) - .then((entries) => { - return entries.map((entry) => entry.id); - }); - } - /** * Returns the default template of a certain type. * @@ -398,67 +381,6 @@ export class AddonModDataHelperProvider { }); } - /** - * Get page info related to an entry. - * - * @param {number} dataId Data ID. - * @param {number} entryId Entry ID. - * @param {number} groupId Group ID. - * @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. - * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). - * @param {string} [siteId] Site ID. Current if not defined. - * @return {Promise} Containing page number, if has next and have following page. - */ - getPageInfoByEntry(dataId: number, entryId: number, groupId: number, forceCache: boolean = false, - ignoreCache: boolean = false, siteId?: string): Promise { - return this.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then((entries) => { - const index = entries.findIndex((entry) => entry == entryId); - - if (index >= 0) { - return { - previousId: entries[index - 1] || false, - nextId: entries[index + 1] || false, - entryId: entryId, - page: index + 1, // Parsed to natural language. - numEntries: entries.length - }; - } - - return false; - }); - } - - /** - * Get page info related to an entry by page number. - * - * @param {number} dataId Data ID. - * @param {number} page Page number. - * @param {number} groupId Group ID. - * @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. - * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). - * @param {string} [siteId] Site ID. Current if not defined. - * @return {Promise} Containing page number, if has next and have following page. - */ - getPageInfoByPage(dataId: number, page: number, groupId: number, forceCache: boolean = false, - ignoreCache: boolean = false, siteId?: string): Promise { - return this.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then((entries) => { - const index = page - 1, - entryId = entries[index]; - - if (entryId) { - return { - previousId: entries[index - 1] || null, - nextId: entries[index + 1] || null, - entryId: entryId, - page: page, // Parsed to natural language. - numEntries: entries.length - }; - } - - return false; - }); - } - /** * Get a list of stored attachment files for a new entry. See $mmaModDataHelper#storeFiles. * diff --git a/src/addon/mod/data/providers/show-link-handler.ts b/src/addon/mod/data/providers/show-link-handler.ts index 1d30f33ea..3685df23e 100644 --- a/src/addon/mod/data/providers/show-link-handler.ts +++ b/src/addon/mod/data/providers/show-link-handler.ts @@ -65,7 +65,7 @@ export class AddonModDataShowLinkHandler extends CoreContentLinksHandlerBase { } if (params.mode && params.mode == 'single') { - pageParams['page'] = page || 1; + pageParams['offset'] = page || 0; } else if (rId) { pageParams['entryId'] = rId; }