From 18a4241fee3f57d6c49e7fe15a282aa7ada7ca0f Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Wed, 12 Oct 2022 10:06:40 +0800 Subject: [PATCH] MDL-75962 js: Fix jsdoc violations --- blocks/timeline/amd/build/event_list.min.js.map | 2 +- blocks/timeline/amd/src/event_list.js | 4 ++-- lib/amd/build/chart_output_chartjs.min.js.map | 2 +- lib/amd/src/chart_output_chartjs.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/blocks/timeline/amd/build/event_list.min.js.map b/blocks/timeline/amd/build/event_list.min.js.map index 10576772a91..7c831abb698 100644 --- a/blocks/timeline/amd/build/event_list.min.js.map +++ b/blocks/timeline/amd/build/event_list.min.js.map @@ -1 +1 @@ -{"version":3,"file":"event_list.min.js","sources":["../src/event_list.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript to load and render the list of calendar events for a\n * given day range.\n *\n * @module block_timeline/event_list\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n 'jquery',\n 'core/notification',\n 'core/templates',\n 'core/str',\n 'core/user_date',\n 'block_timeline/calendar_events_repository',\n 'core/pending'\n],\nfunction(\n $,\n Notification,\n Templates,\n Str,\n UserDate,\n CalendarEventsRepository,\n Pending\n) {\n\n var SECONDS_IN_DAY = 60 * 60 * 24;\n var courseview = false;\n\n var SELECTORS = {\n EMPTY_MESSAGE: '[data-region=\"no-events-empty-message\"]',\n ROOT: '[data-region=\"event-list-container\"]',\n EVENT_LIST_CONTENT: '[data-region=\"event-list-content\"]',\n EVENT_LIST_WRAPPER: '[data-region=\"event-list-wrapper\"]',\n EVENT_LIST_LOADING_PLACEHOLDER: '[data-region=\"event-list-loading-placeholder\"]',\n TIMELINE_BLOCK: '[data-region=\"timeline\"]',\n TIMELINE_SEARCH: '[data-action=\"search\"]',\n MORE_ACTIVITIES_BUTTON: '[data-action=\"more-events\"]',\n MORE_ACTIVITIES_BUTTON_CONTAINER: '[data-region=\"more-events-button-container\"]'\n };\n\n var TEMPLATES = {\n EVENT_LIST_CONTENT: 'block_timeline/event-list-content',\n MORE_ACTIVITIES_BUTTON: 'block_timeline/event-list-loadmore',\n LOADING_ICON: 'core/loading'\n };\n\n /** @type {number} The total items will be shown on the first load. */\n const DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD = 5;\n /** @type {number} The total items will be shown when click on the Show more activities button. */\n const DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD = 10;\n\n /**\n * Hide the content area and display the empty content message.\n *\n * @param {object} root The container element\n */\n var hideContent = function(root) {\n root.find(SELECTORS.EVENT_LIST_CONTENT).addClass('hidden');\n root.find(SELECTORS.EMPTY_MESSAGE).removeClass('hidden');\n };\n\n /**\n * Show the content area and hide the empty content message.\n *\n * @param {object} root The container element\n */\n var showContent = function(root) {\n root.find(SELECTORS.EVENT_LIST_CONTENT).removeClass('hidden');\n root.find(SELECTORS.EMPTY_MESSAGE).addClass('hidden');\n };\n\n /**\n * Empty the content area.\n *\n * @param {object} root The container element\n */\n var emptyContent = function(root) {\n root.find(SELECTORS.EVENT_LIST_CONTENT).empty();\n };\n\n /**\n * Construct the template context from a list of calendar events. The events\n * are grouped by which day they are on. The day is calculated from the user's\n * midnight timestamp to ensure that the calculation is timezone agnostic.\n *\n * The return data structure will look like:\n * {\n * eventsbyday: [\n * {\n * dayTimestamp: 1533744000,\n * events: [\n * { ...event 1 data... },\n * { ...event 2 data... }\n * ]\n * },\n * {\n * dayTimestamp: 1533830400,\n * events: [\n * { ...event 3 data... },\n * { ...event 4 data... }\n * ]\n * }\n * ]\n * }\n *\n * Each day timestamp is the day's midnight in the user's timezone.\n *\n * @param {array} calendarEvents List of calendar events\n * @return {object}\n */\n var buildTemplateContext = function(calendarEvents) {\n var eventsByDay = {};\n var templateContext = {\n courseview,\n eventsbyday: []\n };\n\n calendarEvents.forEach(function(calendarEvent) {\n var dayTimestamp = calendarEvent.timeusermidnight;\n if (eventsByDay[dayTimestamp]) {\n eventsByDay[dayTimestamp].push(calendarEvent);\n } else {\n eventsByDay[dayTimestamp] = [calendarEvent];\n }\n });\n\n Object.keys(eventsByDay).forEach(function(dayTimestamp) {\n var events = eventsByDay[dayTimestamp];\n templateContext.eventsbyday.push({\n dayTimestamp: dayTimestamp,\n events: events\n });\n });\n\n return templateContext;\n };\n\n /**\n * Render the HTML for the given calendar events.\n *\n * @param {array} calendarEvents A list of calendar events\n * @return {promise} Resolved with HTML and JS strings.\n */\n var render = function(calendarEvents) {\n var templateContext = buildTemplateContext(calendarEvents);\n var templateName = TEMPLATES.EVENT_LIST_CONTENT;\n\n return Templates.render(templateName, templateContext);\n };\n\n /**\n * Retrieve a list of calendar events from the server for the given\n * constraints.\n *\n * @param {Number} midnight The user's midnight time in unix timestamp.\n * @param {Number} limit Limit the result set to this number of items\n * @param {Number} daysOffset How many days (from midnight) to offset the results from\n * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to\n * @param {int|false} lastId The ID of the last seen event (if any)\n * @param {int|undefined} courseId Course ID to restrict events to\n * @param {string|undefined} searchValue Search value\n * @return {Promise} A jquery promise\n */\n var load = function(midnight, limit, daysOffset, daysLimit, lastId, courseId, searchValue) {\n var startTime = midnight + (daysOffset * SECONDS_IN_DAY);\n var endTime = daysLimit != undefined ? midnight + (daysLimit * SECONDS_IN_DAY) : false;\n\n var args = {\n starttime: startTime,\n limit: limit,\n };\n\n if (lastId) {\n args.aftereventid = lastId;\n }\n\n if (endTime) {\n args.endtime = endTime;\n }\n\n if (searchValue) {\n args.searchvalue = searchValue;\n }\n\n if (courseId) {\n // If we have a course id then we only want events from that course.\n args.courseid = courseId;\n return CalendarEventsRepository.queryByCourse(args);\n } else {\n // Otherwise we want events from any course.\n return CalendarEventsRepository.queryByTime(args);\n }\n };\n\n /**\n * Create a lazy-loading region for the calendar events in the given root element.\n *\n * @param {object} root The event list container element.\n * @param {object} additionalConfig Additional config options to pass to pagedContentFactory.\n */\n var init = function(root, additionalConfig = {}) {\n const pendingPromise = new Pending('block/timeline:event-init');\n root = $(root);\n\n courseview = !!additionalConfig.courseview;\n\n // Create a promise that will be resolved once the first set of page\n // data has been loaded. This ensures that the loading placeholder isn't\n // hidden until we have all of the data back to prevent the page elements\n // jumping around.\n var firstLoad = $.Deferred();\n var eventListContent = root.find(SELECTORS.EVENT_LIST_CONTENT);\n var loadingPlaceholder = root.find(SELECTORS.EVENT_LIST_LOADING_PLACEHOLDER);\n var courseId = root.attr('data-course-id');\n var daysOffset = parseInt(root.attr('data-days-offset'), 10);\n var daysLimit = root.attr('data-days-limit');\n var midnight = parseInt(root.attr('data-midnight'), 10);\n const searchValue = root.closest(SELECTORS.TIMELINE_BLOCK).find(SELECTORS.TIMELINE_SEARCH).val();\n\n // Make sure the content area and loading placeholder is visible.\n // This is because the init function can be called to re-initialise\n // an existing event list area.\n emptyContent(root);\n showContent(root);\n loadingPlaceholder.removeClass('hidden');\n\n // Days limit isn't mandatory.\n if (daysLimit != undefined) {\n daysLimit = parseInt(daysLimit, 10);\n }\n\n // Create the lazy loading content element.\n return createLazyLoadingContent(root, firstLoad,\n DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD, midnight, 0, courseId, daysOffset, daysLimit, searchValue)\n .then(function(html, js) {\n firstLoad.then(function(data) {\n if (!data.hasContent) {\n loadingPlaceholder.addClass('hidden');\n // If we didn't get any data then show the empty data message.\n return hideContent(root);\n }\n\n html = $(html);\n // Hide the content for now.\n html.addClass('hidden');\n // Replace existing elements with the newly created lazy-loading region.\n Templates.replaceNodeContents(eventListContent, html, js);\n\n // Prevent changing page elements too much by only showing the content\n // once we've loaded some data for the first time. This allows our\n // fancy loading placeholder to shine.\n html.removeClass('hidden');\n loadingPlaceholder.addClass('hidden');\n\n if (!data.loadedAll) {\n Templates.render(TEMPLATES.MORE_ACTIVITIES_BUTTON, {courseview}).then(function(html) {\n eventListContent.append(html);\n setLastTimestamp(root, data.lastTimeStamp);\n // Init the event handler.\n initEventListener(root);\n return html;\n }).catch(function() {\n return false;\n });\n }\n\n return data;\n })\n .catch(function() {\n return false;\n });\n\n return html;\n }).then(() => {\n return pendingPromise.resolve();\n })\n .catch(Notification.exception);\n };\n\n /**\n * Create a lazy-loading content element for showing the event list for the initial load.\n *\n * @param {object} root The event list container element.\n * @param {object} firstLoad A jQuery promise to be resolved after the first set of data is loaded.\n * @param {int} itemLimit Limit the number of items.\n * @param {Number} midnight The user's midnight time in unix timestamp.\n * @param {int} lastId The last event ID for each loaded page. Page number is key, id is value.\n * @param {int|undefined} courseId Course ID to restrict events to.\n * @param {Number} daysOffset How many days (from midnight) to offset the results from.\n * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to.\n * @param {string|undefined} searchValue Search value.\n * @return {object} jQuery promise resolved with calendar events.\n */\n const createLazyLoadingContent = (root, firstLoad, itemLimit, midnight, lastId,\n courseId, daysOffset, daysLimit, searchValue) => {\n return loadEventsForLazyLoading(\n root,\n itemLimit,\n midnight,\n lastId,\n courseId,\n daysOffset,\n daysLimit,\n searchValue\n ).then(data => {\n if (data.calendarEvents.length) {\n const lastEventId = data.calendarEvents.at(-1).id;\n const lastTimeStamp = data.calendarEvents.at(-1).timeusermidnight;\n firstLoad.resolve({\n hasContent: true,\n lastId: lastEventId,\n lastTimeStamp: lastTimeStamp,\n loadedAll: data.loadedAll\n });\n return render(data.calendarEvents, midnight);\n } else {\n firstLoad.resolve({\n hasContent: false,\n lastId: 0,\n lastTimeStamp: 0,\n loadedAll: true\n });\n return data.calendarEvents;\n }\n }).catch(Notification.exception);\n };\n\n /**\n * Handle the request from the lazy-loading region.\n * Uses the given data like course id, offset... to request the events from the server.\n *\n * @param {object} root The event list container element.\n * @param {int} itemLimit Limit the number of items.\n * @param {Number} midnight The user's midnight time in unix timestamp.\n * @param {int} lastId The last event ID for each loaded page.\n * @param {int|undefined} courseId Course ID to restrict events to.\n * @param {Number} daysOffset How many days (from midnight) to offset the results from.\n * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to.\n * @param {string|undefined} searchValue Search value.\n * @return {object} jQuery promise resolved with calendar events.\n */\n const loadEventsForLazyLoading = (root, itemLimit, midnight, lastId, courseId, daysOffset, daysLimit, searchValue) => {\n // Load one more than the given limit so that we can tell if there\n // is more content to load after this.\n const eventsPromise = load(midnight, itemLimit + 1, daysOffset, daysLimit, lastId, courseId, searchValue);\n let calendarEvents = [];\n let loadedAll = true;\n\n return eventsPromise.then(result => {\n if (!result.events.length) {\n return {calendarEvents, loadedAll};\n }\n\n // Determine if the overdue filter is applied.\n const overdueFilter = document.querySelector(\"[data-filtername='overdue']\");\n const filterByOverdue = (overdueFilter && overdueFilter.getAttribute('aria-current'));\n\n calendarEvents = result.events.filter(event => {\n if (event.eventtype == 'open' || event.eventtype == 'opensubmission') {\n const dayTimestamp = UserDate.getUserMidnightForTimestamp(event.timesort, midnight);\n return dayTimestamp > midnight;\n }\n // When filtering by overdue, we fetch all events due today, in case any have elapsed already and are overdue.\n // This means if filtering by overdue, some events fetched might not be required (eg if due later today).\n return (!filterByOverdue || event.overdue);\n });\n\n loadedAll = calendarEvents.length <= itemLimit;\n\n if (!loadedAll) {\n // Remove the last element from the array because it isn't\n // needed in this result set.\n calendarEvents.pop();\n }\n\n if (calendarEvents.length) {\n const lastEventId = calendarEvents.at(-1).id;\n setOffset(root, lastEventId);\n }\n\n return {calendarEvents, loadedAll};\n });\n };\n\n /**\n * Load new events and append to current list.\n *\n * @param {object} root The event list container element.\n */\n const loadMoreEvents = root => {\n const midnight = parseInt(root.attr('data-midnight'), 10);\n const courseId = root.attr('data-course-id');\n const daysOffset = parseInt(root.attr('data-days-offset'), 10);\n const daysLimit = root.attr('data-days-limit');\n const lastId = getOffset(root);\n const eventListWrapper = root.find(SELECTORS.EVENT_LIST_WRAPPER);\n const searchValue = root.closest(SELECTORS.TIMELINE_BLOCK).find(SELECTORS.TIMELINE_SEARCH).val();\n const eventsPromise = loadEventsForLazyLoading(\n root,\n DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD,\n midnight,\n lastId,\n courseId,\n daysOffset,\n daysLimit,\n searchValue\n );\n eventsPromise.then(data => {\n if (data.calendarEvents.length) {\n const renderPromise = render(data.calendarEvents);\n const lastTimestamp = getLastTimestamp(root);\n renderPromise.then((html, js) => {\n html = $(html);\n\n // Remove the date heading if it has the same value as the previous one.\n html.find(`[data-timestamp=\"${lastTimestamp}\"]`).remove();\n Templates.appendNodeContents(eventListWrapper, html.html(), js);\n\n if (!data.loadedAll) {\n Templates.render(TEMPLATES.MORE_ACTIVITIES_BUTTON, {}).then(html => {\n eventListWrapper.append(html);\n setLastTimestamp(root, data.calendarEvents.at(-1).timeusermidnight);\n // Init the event handler.\n initEventListener(root);\n\n return html;\n }).catch(() => {\n return false;\n });\n }\n\n return html;\n }).catch(Notification.exception);\n }\n\n return data;\n }).then(() => {\n return disableMoreActivitiesButtonLoading(root);\n }).catch(Notification.exception);\n };\n\n /**\n * Return the offset value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @return {Number} Offset value.\n */\n const getOffset = element => {\n return parseInt(element.attr('data-lazyload-offset'), 10);\n };\n\n /**\n * Set the offset value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @param {Number} offset Offset value.\n */\n const setOffset = (element, offset) => {\n element.attr('data-lazyload-offset', offset);\n };\n\n /**\n * Return the timestamp value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @return {Number} Timestamp value.\n */\n const getLastTimestamp = element => {\n return parseInt(element.attr('data-timestamp'), 10);\n };\n\n /**\n * Set the timestamp value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @param {Number} timestamp Timestamp value.\n */\n const setLastTimestamp = (element, timestamp) => {\n element.attr('data-timestamp', timestamp);\n };\n\n /**\n * Add the \"Show more activities\" button and remove and loading spinner.\n *\n * @param {object} root The event list container element.\n */\n const enableMoreActivitiesButtonLoading = root => {\n const loadMoreButton = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON);\n loadMoreButton.prop('disabled', true);\n Templates.render(TEMPLATES.LOADING_ICON, {}).then(html => {\n loadMoreButton.append(html);\n return html;\n }).catch(() => {\n // It's not important if this false so just do so silently.\n return false;\n });\n };\n\n /**\n * Remove the \"Show more activities\" button and remove and loading spinner.\n *\n * @param {object} root The event list container element.\n */\n const disableMoreActivitiesButtonLoading = root => {\n const loadMoreButtonContainer = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON_CONTAINER);\n loadMoreButtonContainer.remove();\n };\n\n /**\n * Event initialise.\n *\n * @param {object} root The event list container element.\n */\n const initEventListener = root => {\n const loadMoreButton = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON);\n loadMoreButton.on('click', () => {\n enableMoreActivitiesButtonLoading(root);\n loadMoreEvents(root);\n });\n };\n\n return {\n init: init,\n rootSelector: SELECTORS.ROOT,\n };\n});\n"],"names":["define","$","Notification","Templates","Str","UserDate","CalendarEventsRepository","Pending","courseview","SELECTORS","TEMPLATES","hideContent","root","find","addClass","removeClass","showContent","emptyContent","empty","render","calendarEvents","templateContext","eventsByDay","eventsbyday","forEach","calendarEvent","dayTimestamp","timeusermidnight","push","Object","keys","events","buildTemplateContext","templateName","createLazyLoadingContent","firstLoad","itemLimit","midnight","lastId","courseId","daysOffset","daysLimit","searchValue","loadEventsForLazyLoading","then","data","length","lastEventId","at","id","lastTimeStamp","resolve","hasContent","loadedAll","catch","exception","eventsPromise","limit","endTime","undefined","args","starttime","aftereventid","endtime","searchvalue","courseid","queryByCourse","queryByTime","load","result","overdueFilter","document","querySelector","filterByOverdue","getAttribute","filter","event","eventtype","getUserMidnightForTimestamp","timesort","overdue","pop","setOffset","getOffset","element","parseInt","attr","offset","getLastTimestamp","setLastTimestamp","timestamp","disableMoreActivitiesButtonLoading","remove","initEventListener","on","loadMoreButton","prop","html","append","enableMoreActivitiesButtonLoading","eventListWrapper","closest","val","renderPromise","lastTimestamp","js","appendNodeContents","loadMoreEvents","init","additionalConfig","pendingPromise","Deferred","eventListContent","loadingPlaceholder","replaceNodeContents","rootSelector"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"event_list.min.js","sources":["../src/event_list.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript to load and render the list of calendar events for a\n * given day range.\n *\n * @module block_timeline/event_list\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n 'jquery',\n 'core/notification',\n 'core/templates',\n 'core/str',\n 'core/user_date',\n 'block_timeline/calendar_events_repository',\n 'core/pending'\n],\nfunction(\n $,\n Notification,\n Templates,\n Str,\n UserDate,\n CalendarEventsRepository,\n Pending\n) {\n\n var SECONDS_IN_DAY = 60 * 60 * 24;\n var courseview = false;\n\n var SELECTORS = {\n EMPTY_MESSAGE: '[data-region=\"no-events-empty-message\"]',\n ROOT: '[data-region=\"event-list-container\"]',\n EVENT_LIST_CONTENT: '[data-region=\"event-list-content\"]',\n EVENT_LIST_WRAPPER: '[data-region=\"event-list-wrapper\"]',\n EVENT_LIST_LOADING_PLACEHOLDER: '[data-region=\"event-list-loading-placeholder\"]',\n TIMELINE_BLOCK: '[data-region=\"timeline\"]',\n TIMELINE_SEARCH: '[data-action=\"search\"]',\n MORE_ACTIVITIES_BUTTON: '[data-action=\"more-events\"]',\n MORE_ACTIVITIES_BUTTON_CONTAINER: '[data-region=\"more-events-button-container\"]'\n };\n\n var TEMPLATES = {\n EVENT_LIST_CONTENT: 'block_timeline/event-list-content',\n MORE_ACTIVITIES_BUTTON: 'block_timeline/event-list-loadmore',\n LOADING_ICON: 'core/loading'\n };\n\n /** @property {number} The total items will be shown on the first load. */\n const DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD = 5;\n /** @property {number} The total items will be shown when click on the Show more activities button. */\n const DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD = 10;\n\n /**\n * Hide the content area and display the empty content message.\n *\n * @param {object} root The container element\n */\n var hideContent = function(root) {\n root.find(SELECTORS.EVENT_LIST_CONTENT).addClass('hidden');\n root.find(SELECTORS.EMPTY_MESSAGE).removeClass('hidden');\n };\n\n /**\n * Show the content area and hide the empty content message.\n *\n * @param {object} root The container element\n */\n var showContent = function(root) {\n root.find(SELECTORS.EVENT_LIST_CONTENT).removeClass('hidden');\n root.find(SELECTORS.EMPTY_MESSAGE).addClass('hidden');\n };\n\n /**\n * Empty the content area.\n *\n * @param {object} root The container element\n */\n var emptyContent = function(root) {\n root.find(SELECTORS.EVENT_LIST_CONTENT).empty();\n };\n\n /**\n * Construct the template context from a list of calendar events. The events\n * are grouped by which day they are on. The day is calculated from the user's\n * midnight timestamp to ensure that the calculation is timezone agnostic.\n *\n * The return data structure will look like:\n * {\n * eventsbyday: [\n * {\n * dayTimestamp: 1533744000,\n * events: [\n * { ...event 1 data... },\n * { ...event 2 data... }\n * ]\n * },\n * {\n * dayTimestamp: 1533830400,\n * events: [\n * { ...event 3 data... },\n * { ...event 4 data... }\n * ]\n * }\n * ]\n * }\n *\n * Each day timestamp is the day's midnight in the user's timezone.\n *\n * @param {array} calendarEvents List of calendar events\n * @return {object}\n */\n var buildTemplateContext = function(calendarEvents) {\n var eventsByDay = {};\n var templateContext = {\n courseview,\n eventsbyday: []\n };\n\n calendarEvents.forEach(function(calendarEvent) {\n var dayTimestamp = calendarEvent.timeusermidnight;\n if (eventsByDay[dayTimestamp]) {\n eventsByDay[dayTimestamp].push(calendarEvent);\n } else {\n eventsByDay[dayTimestamp] = [calendarEvent];\n }\n });\n\n Object.keys(eventsByDay).forEach(function(dayTimestamp) {\n var events = eventsByDay[dayTimestamp];\n templateContext.eventsbyday.push({\n dayTimestamp: dayTimestamp,\n events: events\n });\n });\n\n return templateContext;\n };\n\n /**\n * Render the HTML for the given calendar events.\n *\n * @param {array} calendarEvents A list of calendar events\n * @return {promise} Resolved with HTML and JS strings.\n */\n var render = function(calendarEvents) {\n var templateContext = buildTemplateContext(calendarEvents);\n var templateName = TEMPLATES.EVENT_LIST_CONTENT;\n\n return Templates.render(templateName, templateContext);\n };\n\n /**\n * Retrieve a list of calendar events from the server for the given\n * constraints.\n *\n * @param {Number} midnight The user's midnight time in unix timestamp.\n * @param {Number} limit Limit the result set to this number of items\n * @param {Number} daysOffset How many days (from midnight) to offset the results from\n * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to\n * @param {int|false} lastId The ID of the last seen event (if any)\n * @param {int|undefined} courseId Course ID to restrict events to\n * @param {string|undefined} searchValue Search value\n * @return {Promise} A jquery promise\n */\n var load = function(midnight, limit, daysOffset, daysLimit, lastId, courseId, searchValue) {\n var startTime = midnight + (daysOffset * SECONDS_IN_DAY);\n var endTime = daysLimit != undefined ? midnight + (daysLimit * SECONDS_IN_DAY) : false;\n\n var args = {\n starttime: startTime,\n limit: limit,\n };\n\n if (lastId) {\n args.aftereventid = lastId;\n }\n\n if (endTime) {\n args.endtime = endTime;\n }\n\n if (searchValue) {\n args.searchvalue = searchValue;\n }\n\n if (courseId) {\n // If we have a course id then we only want events from that course.\n args.courseid = courseId;\n return CalendarEventsRepository.queryByCourse(args);\n } else {\n // Otherwise we want events from any course.\n return CalendarEventsRepository.queryByTime(args);\n }\n };\n\n /**\n * Create a lazy-loading region for the calendar events in the given root element.\n *\n * @param {object} root The event list container element.\n * @param {object} additionalConfig Additional config options to pass to pagedContentFactory.\n */\n var init = function(root, additionalConfig = {}) {\n const pendingPromise = new Pending('block/timeline:event-init');\n root = $(root);\n\n courseview = !!additionalConfig.courseview;\n\n // Create a promise that will be resolved once the first set of page\n // data has been loaded. This ensures that the loading placeholder isn't\n // hidden until we have all of the data back to prevent the page elements\n // jumping around.\n var firstLoad = $.Deferred();\n var eventListContent = root.find(SELECTORS.EVENT_LIST_CONTENT);\n var loadingPlaceholder = root.find(SELECTORS.EVENT_LIST_LOADING_PLACEHOLDER);\n var courseId = root.attr('data-course-id');\n var daysOffset = parseInt(root.attr('data-days-offset'), 10);\n var daysLimit = root.attr('data-days-limit');\n var midnight = parseInt(root.attr('data-midnight'), 10);\n const searchValue = root.closest(SELECTORS.TIMELINE_BLOCK).find(SELECTORS.TIMELINE_SEARCH).val();\n\n // Make sure the content area and loading placeholder is visible.\n // This is because the init function can be called to re-initialise\n // an existing event list area.\n emptyContent(root);\n showContent(root);\n loadingPlaceholder.removeClass('hidden');\n\n // Days limit isn't mandatory.\n if (daysLimit != undefined) {\n daysLimit = parseInt(daysLimit, 10);\n }\n\n // Create the lazy loading content element.\n return createLazyLoadingContent(root, firstLoad,\n DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD, midnight, 0, courseId, daysOffset, daysLimit, searchValue)\n .then(function(html, js) {\n firstLoad.then(function(data) {\n if (!data.hasContent) {\n loadingPlaceholder.addClass('hidden');\n // If we didn't get any data then show the empty data message.\n return hideContent(root);\n }\n\n html = $(html);\n // Hide the content for now.\n html.addClass('hidden');\n // Replace existing elements with the newly created lazy-loading region.\n Templates.replaceNodeContents(eventListContent, html, js);\n\n // Prevent changing page elements too much by only showing the content\n // once we've loaded some data for the first time. This allows our\n // fancy loading placeholder to shine.\n html.removeClass('hidden');\n loadingPlaceholder.addClass('hidden');\n\n if (!data.loadedAll) {\n Templates.render(TEMPLATES.MORE_ACTIVITIES_BUTTON, {courseview}).then(function(html) {\n eventListContent.append(html);\n setLastTimestamp(root, data.lastTimeStamp);\n // Init the event handler.\n initEventListener(root);\n return html;\n }).catch(function() {\n return false;\n });\n }\n\n return data;\n })\n .catch(function() {\n return false;\n });\n\n return html;\n }).then(() => {\n return pendingPromise.resolve();\n })\n .catch(Notification.exception);\n };\n\n /**\n * Create a lazy-loading content element for showing the event list for the initial load.\n *\n * @param {object} root The event list container element.\n * @param {object} firstLoad A jQuery promise to be resolved after the first set of data is loaded.\n * @param {int} itemLimit Limit the number of items.\n * @param {Number} midnight The user's midnight time in unix timestamp.\n * @param {int} lastId The last event ID for each loaded page. Page number is key, id is value.\n * @param {int|undefined} courseId Course ID to restrict events to.\n * @param {Number} daysOffset How many days (from midnight) to offset the results from.\n * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to.\n * @param {string|undefined} searchValue Search value.\n * @return {object} jQuery promise resolved with calendar events.\n */\n const createLazyLoadingContent = (root, firstLoad, itemLimit, midnight, lastId,\n courseId, daysOffset, daysLimit, searchValue) => {\n return loadEventsForLazyLoading(\n root,\n itemLimit,\n midnight,\n lastId,\n courseId,\n daysOffset,\n daysLimit,\n searchValue\n ).then(data => {\n if (data.calendarEvents.length) {\n const lastEventId = data.calendarEvents.at(-1).id;\n const lastTimeStamp = data.calendarEvents.at(-1).timeusermidnight;\n firstLoad.resolve({\n hasContent: true,\n lastId: lastEventId,\n lastTimeStamp: lastTimeStamp,\n loadedAll: data.loadedAll\n });\n return render(data.calendarEvents, midnight);\n } else {\n firstLoad.resolve({\n hasContent: false,\n lastId: 0,\n lastTimeStamp: 0,\n loadedAll: true\n });\n return data.calendarEvents;\n }\n }).catch(Notification.exception);\n };\n\n /**\n * Handle the request from the lazy-loading region.\n * Uses the given data like course id, offset... to request the events from the server.\n *\n * @param {object} root The event list container element.\n * @param {int} itemLimit Limit the number of items.\n * @param {Number} midnight The user's midnight time in unix timestamp.\n * @param {int} lastId The last event ID for each loaded page.\n * @param {int|undefined} courseId Course ID to restrict events to.\n * @param {Number} daysOffset How many days (from midnight) to offset the results from.\n * @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to.\n * @param {string|undefined} searchValue Search value.\n * @return {object} jQuery promise resolved with calendar events.\n */\n const loadEventsForLazyLoading = (root, itemLimit, midnight, lastId, courseId, daysOffset, daysLimit, searchValue) => {\n // Load one more than the given limit so that we can tell if there\n // is more content to load after this.\n const eventsPromise = load(midnight, itemLimit + 1, daysOffset, daysLimit, lastId, courseId, searchValue);\n let calendarEvents = [];\n let loadedAll = true;\n\n return eventsPromise.then(result => {\n if (!result.events.length) {\n return {calendarEvents, loadedAll};\n }\n\n // Determine if the overdue filter is applied.\n const overdueFilter = document.querySelector(\"[data-filtername='overdue']\");\n const filterByOverdue = (overdueFilter && overdueFilter.getAttribute('aria-current'));\n\n calendarEvents = result.events.filter(event => {\n if (event.eventtype == 'open' || event.eventtype == 'opensubmission') {\n const dayTimestamp = UserDate.getUserMidnightForTimestamp(event.timesort, midnight);\n return dayTimestamp > midnight;\n }\n // When filtering by overdue, we fetch all events due today, in case any have elapsed already and are overdue.\n // This means if filtering by overdue, some events fetched might not be required (eg if due later today).\n return (!filterByOverdue || event.overdue);\n });\n\n loadedAll = calendarEvents.length <= itemLimit;\n\n if (!loadedAll) {\n // Remove the last element from the array because it isn't\n // needed in this result set.\n calendarEvents.pop();\n }\n\n if (calendarEvents.length) {\n const lastEventId = calendarEvents.at(-1).id;\n setOffset(root, lastEventId);\n }\n\n return {calendarEvents, loadedAll};\n });\n };\n\n /**\n * Load new events and append to current list.\n *\n * @param {object} root The event list container element.\n */\n const loadMoreEvents = root => {\n const midnight = parseInt(root.attr('data-midnight'), 10);\n const courseId = root.attr('data-course-id');\n const daysOffset = parseInt(root.attr('data-days-offset'), 10);\n const daysLimit = root.attr('data-days-limit');\n const lastId = getOffset(root);\n const eventListWrapper = root.find(SELECTORS.EVENT_LIST_WRAPPER);\n const searchValue = root.closest(SELECTORS.TIMELINE_BLOCK).find(SELECTORS.TIMELINE_SEARCH).val();\n const eventsPromise = loadEventsForLazyLoading(\n root,\n DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD,\n midnight,\n lastId,\n courseId,\n daysOffset,\n daysLimit,\n searchValue\n );\n eventsPromise.then(data => {\n if (data.calendarEvents.length) {\n const renderPromise = render(data.calendarEvents);\n const lastTimestamp = getLastTimestamp(root);\n renderPromise.then((html, js) => {\n html = $(html);\n\n // Remove the date heading if it has the same value as the previous one.\n html.find(`[data-timestamp=\"${lastTimestamp}\"]`).remove();\n Templates.appendNodeContents(eventListWrapper, html.html(), js);\n\n if (!data.loadedAll) {\n Templates.render(TEMPLATES.MORE_ACTIVITIES_BUTTON, {}).then(html => {\n eventListWrapper.append(html);\n setLastTimestamp(root, data.calendarEvents.at(-1).timeusermidnight);\n // Init the event handler.\n initEventListener(root);\n\n return html;\n }).catch(() => {\n return false;\n });\n }\n\n return html;\n }).catch(Notification.exception);\n }\n\n return data;\n }).then(() => {\n return disableMoreActivitiesButtonLoading(root);\n }).catch(Notification.exception);\n };\n\n /**\n * Return the offset value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @return {Number} Offset value.\n */\n const getOffset = element => {\n return parseInt(element.attr('data-lazyload-offset'), 10);\n };\n\n /**\n * Set the offset value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @param {Number} offset Offset value.\n */\n const setOffset = (element, offset) => {\n element.attr('data-lazyload-offset', offset);\n };\n\n /**\n * Return the timestamp value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @return {Number} Timestamp value.\n */\n const getLastTimestamp = element => {\n return parseInt(element.attr('data-timestamp'), 10);\n };\n\n /**\n * Set the timestamp value for lazy loading fetching.\n *\n * @param {object} element The event list container element.\n * @param {Number} timestamp Timestamp value.\n */\n const setLastTimestamp = (element, timestamp) => {\n element.attr('data-timestamp', timestamp);\n };\n\n /**\n * Add the \"Show more activities\" button and remove and loading spinner.\n *\n * @param {object} root The event list container element.\n */\n const enableMoreActivitiesButtonLoading = root => {\n const loadMoreButton = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON);\n loadMoreButton.prop('disabled', true);\n Templates.render(TEMPLATES.LOADING_ICON, {}).then(html => {\n loadMoreButton.append(html);\n return html;\n }).catch(() => {\n // It's not important if this false so just do so silently.\n return false;\n });\n };\n\n /**\n * Remove the \"Show more activities\" button and remove and loading spinner.\n *\n * @param {object} root The event list container element.\n */\n const disableMoreActivitiesButtonLoading = root => {\n const loadMoreButtonContainer = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON_CONTAINER);\n loadMoreButtonContainer.remove();\n };\n\n /**\n * Event initialise.\n *\n * @param {object} root The event list container element.\n */\n const initEventListener = root => {\n const loadMoreButton = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON);\n loadMoreButton.on('click', () => {\n enableMoreActivitiesButtonLoading(root);\n loadMoreEvents(root);\n });\n };\n\n return {\n init: init,\n rootSelector: SELECTORS.ROOT,\n };\n});\n"],"names":["define","$","Notification","Templates","Str","UserDate","CalendarEventsRepository","Pending","courseview","SELECTORS","TEMPLATES","hideContent","root","find","addClass","removeClass","showContent","emptyContent","empty","render","calendarEvents","templateContext","eventsByDay","eventsbyday","forEach","calendarEvent","dayTimestamp","timeusermidnight","push","Object","keys","events","buildTemplateContext","templateName","createLazyLoadingContent","firstLoad","itemLimit","midnight","lastId","courseId","daysOffset","daysLimit","searchValue","loadEventsForLazyLoading","then","data","length","lastEventId","at","id","lastTimeStamp","resolve","hasContent","loadedAll","catch","exception","eventsPromise","limit","endTime","undefined","args","starttime","aftereventid","endtime","searchvalue","courseid","queryByCourse","queryByTime","load","result","overdueFilter","document","querySelector","filterByOverdue","getAttribute","filter","event","eventtype","getUserMidnightForTimestamp","timesort","overdue","pop","setOffset","getOffset","element","parseInt","attr","offset","getLastTimestamp","setLastTimestamp","timestamp","disableMoreActivitiesButtonLoading","remove","initEventListener","on","loadMoreButton","prop","html","append","enableMoreActivitiesButtonLoading","eventListWrapper","closest","val","renderPromise","lastTimestamp","js","appendNodeContents","loadMoreEvents","init","additionalConfig","pendingPromise","Deferred","eventListContent","loadingPlaceholder","replaceNodeContents","rootSelector"],"mappings":"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"} \ No newline at end of file diff --git a/blocks/timeline/amd/src/event_list.js b/blocks/timeline/amd/src/event_list.js index f4042dc0b64..c7679cf87b7 100644 --- a/blocks/timeline/amd/src/event_list.js +++ b/blocks/timeline/amd/src/event_list.js @@ -62,9 +62,9 @@ function( LOADING_ICON: 'core/loading' }; - /** @type {number} The total items will be shown on the first load. */ + /** @property {number} The total items will be shown on the first load. */ const DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD = 5; - /** @type {number} The total items will be shown when click on the Show more activities button. */ + /** @property {number} The total items will be shown when click on the Show more activities button. */ const DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD = 10; /** diff --git a/lib/amd/build/chart_output_chartjs.min.js.map b/lib/amd/build/chart_output_chartjs.min.js.map index 556377c15f5..0acf2c7d24d 100644 --- a/lib/amd/build/chart_output_chartjs.min.js.map +++ b/lib/amd/build/chart_output_chartjs.min.js.map @@ -1 +1 @@ -{"version":3,"file":"chart_output_chartjs.min.js","sources":["../src/chart_output_chartjs.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Chart output for chart.js.\n *\n * @copyright 2016 Frédéric Massart - FMCorz.net\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @module core/chart_output_chartjs\n */\ndefine([\n 'jquery',\n 'core/chartjs',\n 'core/chart_axis',\n 'core/chart_bar',\n 'core/chart_output_base',\n 'core/chart_line',\n 'core/chart_pie',\n 'core/chart_series'\n], function($, Chartjs, Axis, Bar, Base, Line, Pie, Series) {\n\n /**\n * Makes an axis ID.\n *\n * @param {String} xy Accepts 'x' and 'y'.\n * @param {Number} index The axis index.\n * @return {String}\n */\n var makeAxisId = function(xy, index) {\n return 'axis-' + xy + '-' + index;\n };\n\n /**\n * Chart output for Chart.js.\n *\n * @class\n * @extends {module:core/chart_output_base}\n */\n function Output() {\n Base.prototype.constructor.apply(this, arguments);\n\n // Make sure that we've got a canvas tag.\n this._canvas = this._node;\n if (this._canvas.prop('tagName') != 'CANVAS') {\n this._canvas = $('');\n this._node.append(this._canvas);\n }\n\n this._build();\n }\n Output.prototype = Object.create(Base.prototype);\n\n /**\n * Reference to the chart config object.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._config = null;\n\n /**\n * Reference to the instance of chart.js.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._chartjs = null;\n\n /**\n * Reference to the canvas node.\n *\n * @type {Jquery}\n * @protected\n */\n Output.prototype._canvas = null;\n\n /**\n * Builds the config and the chart.\n *\n * @protected\n */\n Output.prototype._build = function() {\n this._config = this._makeConfig();\n this._chartjs = new Chartjs(this._canvas[0], this._config);\n };\n\n /**\n * Clean data.\n *\n * @param {(String|String[])} data A single string or an array of strings.\n * @returns {(String|String[])}\n * @protected\n */\n Output.prototype._cleanData = function(data) {\n if (data instanceof Array) {\n return data.map(function(value) {\n return $('').html(value).text();\n });\n } else {\n return $('').html(data).text();\n }\n };\n\n /**\n * Get the chart type and handles the Chart.js specific chart types.\n *\n * By default returns the current chart TYPE value. Also does the handling of specific chart types, for example\n * check if the bar chart should be horizontal and the pie chart should be displayed as a doughnut.\n *\n * @method getChartType\n * @returns {String} the chart type.\n * @protected\n */\n Output.prototype._getChartType = function() {\n var type = this._chart.getType();\n\n // Bars can be displayed vertically and horizontally, defining horizontalBar type.\n if (this._chart.getType() === Bar.prototype.TYPE && this._chart.getHorizontal() === true) {\n type = 'horizontalBar';\n } else if (this._chart.getType() === Pie.prototype.TYPE && this._chart.getDoughnut() === true) {\n // Pie chart can be displayed as doughnut.\n type = 'doughnut';\n }\n\n return type;\n };\n\n /**\n * Make the axis config.\n *\n * @protected\n * @param {module:core/chart_axis} axis The axis.\n * @param {String} xy Accepts 'x' or 'y'.\n * @param {Number} index The axis index.\n * @return {Object} The axis config.\n */\n Output.prototype._makeAxisConfig = function(axis, xy, index) {\n var scaleData = {\n id: makeAxisId(xy, index)\n };\n\n if (axis.getPosition() !== Axis.prototype.POS_DEFAULT) {\n scaleData.position = axis.getPosition();\n }\n\n if (axis.getLabel() !== null) {\n scaleData.title = {\n display: true,\n text: this._cleanData(axis.getLabel())\n };\n }\n\n if (axis.getStepSize() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.stepSize = axis.getStepSize();\n }\n\n if (axis.getMax() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.max = axis.getMax();\n }\n\n if (axis.getMin() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.min = axis.getMin();\n }\n\n return scaleData;\n };\n\n /**\n * Make the config config.\n *\n * @protected\n * @return {Object} The axis config.\n */\n Output.prototype._makeConfig = function() {\n var charType = this._getChartType();\n var config = {\n type: charType,\n data: {\n labels: this._cleanData(this._chart.getLabels()),\n datasets: this._makeDatasetsConfig()\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n title: {\n display: this._chart.getTitle() !== null,\n text: this._cleanData(this._chart.getTitle())\n }\n }\n }\n };\n\n if (charType === 'horizontalBar') {\n config.type = 'bar';\n config.options.indexAxis = 'y';\n }\n\n var legendOptions = this._chart.getLegendOptions();\n if (legendOptions) {\n config.options.plugins.legend = legendOptions;\n }\n\n\n this._chart.getXAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.x = config.options.scales.x || {};\n config.options.scales.x[i] = this._makeAxisConfig(axis, 'x', i);\n\n if (axisLabels !== null) {\n config.options.scales.x[i].ticks.callback = function(value, index) {\n return axisLabels[index] || '';\n };\n }\n config.options.scales.x.stacked = this._isStacked();\n }.bind(this));\n\n this._chart.getYAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.y = config.options.scales.yAxes || {};\n config.options.scales.y[i] = this._makeAxisConfig(axis, 'y', i);\n\n if (axisLabels !== null) {\n config.options.scales.y[i].ticks.callback = function(value) {\n return axisLabels[parseInt(value, 10)] || '';\n };\n }\n config.options.scales.y.stacked = this._isStacked();\n }.bind(this));\n\n config.options.plugins.tooltip = {\n callbacks: {\n label: this._makeTooltip.bind(this)\n }\n };\n\n return config;\n };\n\n /**\n * Get the datasets configurations.\n *\n * @protected\n * @return {Object[]}\n */\n Output.prototype._makeDatasetsConfig = function() {\n var sets = this._chart.getSeries().map(function(series) {\n var colors = series.hasColoredValues() ? series.getColors() : series.getColor();\n var dataset = {\n label: this._cleanData(series.getLabel()),\n data: series.getValues(),\n type: series.getType(),\n fill: series.getFill(),\n backgroundColor: colors,\n // Pie charts look better without borders.\n borderColor: this._chart.getType() == Pie.prototype.TYPE ? '#fff' : colors,\n tension: this._isSmooth(series) ? 0.3 : 0\n };\n\n if (series.getXAxis() !== null) {\n dataset.xAxisID = makeAxisId('x', series.getXAxis());\n }\n if (series.getYAxis() !== null) {\n dataset.yAxisID = makeAxisId('y', series.getYAxis());\n }\n\n return dataset;\n }.bind(this));\n return sets;\n };\n\n /**\n * Get the chart data, add labels and rebuild the tooltip.\n *\n * @param {Object[]} tooltipItem The tooltip item object.\n * @returns {*[]}\n * @protected\n */\n Output.prototype._makeTooltip = function(tooltipItem) {\n\n // Get series and chart data to rebuild the tooltip and add labels.\n var series = this._chart.getSeries()[tooltipItem.datasetIndex];\n var serieLabel = series.getLabel();\n var chartData = tooltipItem.dataset.data;\n var tooltipData = chartData[tooltipItem.dataIndex];\n\n // Build default tooltip.\n var tooltip = [];\n\n // Pie and doughnut charts tooltip are different.\n if (this._chart.getType() === Pie.prototype.TYPE) {\n var chartLabels = this._cleanData(this._chart.getLabels());\n tooltip.push(chartLabels[tooltipItem.dataIndex] + ' - ' + this._cleanData(serieLabel) + ': ' + tooltipData);\n } else {\n tooltip.push(this._cleanData(serieLabel) + ': ' + tooltipData);\n }\n\n return tooltip;\n };\n\n /**\n * Verify if the chart line is smooth or not.\n *\n * @protected\n * @param {module:core/chart_series} series The series.\n * @returns {Bool}\n */\n Output.prototype._isSmooth = function(series) {\n var smooth = false;\n if (this._chart.getType() === Line.prototype.TYPE) {\n smooth = series.getSmooth();\n if (smooth === null) {\n smooth = this._chart.getSmooth();\n }\n } else if (series.getType() === Series.prototype.TYPE_LINE) {\n smooth = series.getSmooth();\n }\n\n return smooth;\n };\n\n /**\n * Verify if the bar chart is stacked or not.\n *\n * @protected\n * @returns {Bool}\n */\n Output.prototype._isStacked = function() {\n var stacked = false;\n\n // Stacking is (currently) only supported for bar charts.\n if (this._chart.getType() === Bar.prototype.TYPE) {\n stacked = this._chart.getStacked();\n }\n\n return stacked;\n };\n\n /** @override */\n Output.prototype.update = function() {\n $.extend(true, this._config, this._makeConfig());\n this._chartjs.update();\n };\n\n return Output;\n\n});\n"],"names":["define","$","Chartjs","Axis","Bar","Base","Line","Pie","Series","makeAxisId","xy","index","Output","prototype","constructor","apply","this","arguments","_canvas","_node","prop","append","_build","Object","create","_config","_chartjs","_makeConfig","_cleanData","data","Array","map","value","html","text","_getChartType","type","_chart","getType","TYPE","getHorizontal","getDoughnut","_makeAxisConfig","axis","scaleData","id","getPosition","POS_DEFAULT","position","getLabel","title","display","getStepSize","ticks","stepSize","getMax","max","getMin","min","charType","config","labels","getLabels","datasets","_makeDatasetsConfig","options","responsive","maintainAspectRatio","plugins","getTitle","indexAxis","legendOptions","getLegendOptions","legend","getXAxes","forEach","i","axisLabels","scales","x","callback","stacked","_isStacked","bind","getYAxes","y","yAxes","parseInt","tooltip","callbacks","label","_makeTooltip","getSeries","series","colors","hasColoredValues","getColors","getColor","dataset","getValues","fill","getFill","backgroundColor","borderColor","tension","_isSmooth","getXAxis","xAxisID","getYAxis","yAxisID","tooltipItem","serieLabel","datasetIndex","tooltipData","dataIndex","chartLabels","push","smooth","getSmooth","TYPE_LINE","getStacked","update","extend"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"chart_output_chartjs.min.js","sources":["../src/chart_output_chartjs.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Chart output for chart.js.\n *\n * @copyright 2016 Frédéric Massart - FMCorz.net\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @module core/chart_output_chartjs\n */\ndefine([\n 'jquery',\n 'core/chartjs',\n 'core/chart_axis',\n 'core/chart_bar',\n 'core/chart_output_base',\n 'core/chart_line',\n 'core/chart_pie',\n 'core/chart_series'\n], function($, Chartjs, Axis, Bar, Base, Line, Pie, Series) {\n\n /**\n * Makes an axis ID.\n *\n * @param {String} xy Accepts 'x' and 'y'.\n * @param {Number} index The axis index.\n * @return {String}\n */\n var makeAxisId = function(xy, index) {\n return 'axis-' + xy + '-' + index;\n };\n\n /**\n * Chart output for Chart.js.\n *\n * @class\n * @extends {module:core/chart_output_base}\n */\n function Output() {\n Base.prototype.constructor.apply(this, arguments);\n\n // Make sure that we've got a canvas tag.\n this._canvas = this._node;\n if (this._canvas.prop('tagName') != 'CANVAS') {\n this._canvas = $('');\n this._node.append(this._canvas);\n }\n\n this._build();\n }\n Output.prototype = Object.create(Base.prototype);\n\n /**\n * Reference to the chart config object.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._config = null;\n\n /**\n * Reference to the instance of chart.js.\n *\n * @type {Object}\n * @protected\n */\n Output.prototype._chartjs = null;\n\n /**\n * Reference to the canvas node.\n *\n * @type {Jquery}\n * @protected\n */\n Output.prototype._canvas = null;\n\n /**\n * Builds the config and the chart.\n *\n * @protected\n */\n Output.prototype._build = function() {\n this._config = this._makeConfig();\n this._chartjs = new Chartjs(this._canvas[0], this._config);\n };\n\n /**\n * Clean data.\n *\n * @param {(String|String[])} data A single string or an array of strings.\n * @returns {(String|String[])}\n * @protected\n */\n Output.prototype._cleanData = function(data) {\n if (data instanceof Array) {\n return data.map(function(value) {\n return $('').html(value).text();\n });\n } else {\n return $('').html(data).text();\n }\n };\n\n /**\n * Get the chart type and handles the Chart.js specific chart types.\n *\n * By default returns the current chart TYPE value. Also does the handling of specific chart types, for example\n * check if the bar chart should be horizontal and the pie chart should be displayed as a doughnut.\n *\n * @method getChartType\n * @returns {String} the chart type.\n * @protected\n */\n Output.prototype._getChartType = function() {\n var type = this._chart.getType();\n\n // Bars can be displayed vertically and horizontally, defining horizontalBar type.\n if (this._chart.getType() === Bar.prototype.TYPE && this._chart.getHorizontal() === true) {\n type = 'horizontalBar';\n } else if (this._chart.getType() === Pie.prototype.TYPE && this._chart.getDoughnut() === true) {\n // Pie chart can be displayed as doughnut.\n type = 'doughnut';\n }\n\n return type;\n };\n\n /**\n * Make the axis config.\n *\n * @protected\n * @param {module:core/chart_axis} axis The axis.\n * @param {String} xy Accepts 'x' or 'y'.\n * @param {Number} index The axis index.\n * @return {Object} The axis config.\n */\n Output.prototype._makeAxisConfig = function(axis, xy, index) {\n var scaleData = {\n id: makeAxisId(xy, index)\n };\n\n if (axis.getPosition() !== Axis.prototype.POS_DEFAULT) {\n scaleData.position = axis.getPosition();\n }\n\n if (axis.getLabel() !== null) {\n scaleData.title = {\n display: true,\n text: this._cleanData(axis.getLabel())\n };\n }\n\n if (axis.getStepSize() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.stepSize = axis.getStepSize();\n }\n\n if (axis.getMax() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.max = axis.getMax();\n }\n\n if (axis.getMin() !== null) {\n scaleData.ticks = scaleData.ticks || {};\n scaleData.ticks.min = axis.getMin();\n }\n\n return scaleData;\n };\n\n /**\n * Make the config config.\n *\n * @protected\n * @return {Object} The axis config.\n */\n Output.prototype._makeConfig = function() {\n var charType = this._getChartType();\n var config = {\n type: charType,\n data: {\n labels: this._cleanData(this._chart.getLabels()),\n datasets: this._makeDatasetsConfig()\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n title: {\n display: this._chart.getTitle() !== null,\n text: this._cleanData(this._chart.getTitle())\n }\n }\n }\n };\n\n if (charType === 'horizontalBar') {\n config.type = 'bar';\n config.options.indexAxis = 'y';\n }\n\n var legendOptions = this._chart.getLegendOptions();\n if (legendOptions) {\n config.options.plugins.legend = legendOptions;\n }\n\n\n this._chart.getXAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.x = config.options.scales.x || {};\n config.options.scales.x[i] = this._makeAxisConfig(axis, 'x', i);\n\n if (axisLabels !== null) {\n config.options.scales.x[i].ticks.callback = function(value, index) {\n return axisLabels[index] || '';\n };\n }\n config.options.scales.x.stacked = this._isStacked();\n }.bind(this));\n\n this._chart.getYAxes().forEach(function(axis, i) {\n var axisLabels = axis.getLabels();\n\n config.options.scales = config.options.scales || {};\n config.options.scales.y = config.options.scales.yAxes || {};\n config.options.scales.y[i] = this._makeAxisConfig(axis, 'y', i);\n\n if (axisLabels !== null) {\n config.options.scales.y[i].ticks.callback = function(value) {\n return axisLabels[parseInt(value, 10)] || '';\n };\n }\n config.options.scales.y.stacked = this._isStacked();\n }.bind(this));\n\n config.options.plugins.tooltip = {\n callbacks: {\n label: this._makeTooltip.bind(this)\n }\n };\n\n return config;\n };\n\n /**\n * Get the datasets configurations.\n *\n * @protected\n * @return {Object[]}\n */\n Output.prototype._makeDatasetsConfig = function() {\n var sets = this._chart.getSeries().map(function(series) {\n var colors = series.hasColoredValues() ? series.getColors() : series.getColor();\n var dataset = {\n label: this._cleanData(series.getLabel()),\n data: series.getValues(),\n type: series.getType(),\n fill: series.getFill(),\n backgroundColor: colors,\n // Pie charts look better without borders.\n borderColor: this._chart.getType() == Pie.prototype.TYPE ? '#fff' : colors,\n tension: this._isSmooth(series) ? 0.3 : 0\n };\n\n if (series.getXAxis() !== null) {\n dataset.xAxisID = makeAxisId('x', series.getXAxis());\n }\n if (series.getYAxis() !== null) {\n dataset.yAxisID = makeAxisId('y', series.getYAxis());\n }\n\n return dataset;\n }.bind(this));\n return sets;\n };\n\n /**\n * Get the chart data, add labels and rebuild the tooltip.\n *\n * @param {Object[]} tooltipItem The tooltip item object.\n * @returns {Array}\n * @protected\n */\n Output.prototype._makeTooltip = function(tooltipItem) {\n\n // Get series and chart data to rebuild the tooltip and add labels.\n var series = this._chart.getSeries()[tooltipItem.datasetIndex];\n var serieLabel = series.getLabel();\n var chartData = tooltipItem.dataset.data;\n var tooltipData = chartData[tooltipItem.dataIndex];\n\n // Build default tooltip.\n var tooltip = [];\n\n // Pie and doughnut charts tooltip are different.\n if (this._chart.getType() === Pie.prototype.TYPE) {\n var chartLabels = this._cleanData(this._chart.getLabels());\n tooltip.push(chartLabels[tooltipItem.dataIndex] + ' - ' + this._cleanData(serieLabel) + ': ' + tooltipData);\n } else {\n tooltip.push(this._cleanData(serieLabel) + ': ' + tooltipData);\n }\n\n return tooltip;\n };\n\n /**\n * Verify if the chart line is smooth or not.\n *\n * @protected\n * @param {module:core/chart_series} series The series.\n * @returns {Bool}\n */\n Output.prototype._isSmooth = function(series) {\n var smooth = false;\n if (this._chart.getType() === Line.prototype.TYPE) {\n smooth = series.getSmooth();\n if (smooth === null) {\n smooth = this._chart.getSmooth();\n }\n } else if (series.getType() === Series.prototype.TYPE_LINE) {\n smooth = series.getSmooth();\n }\n\n return smooth;\n };\n\n /**\n * Verify if the bar chart is stacked or not.\n *\n * @protected\n * @returns {Bool}\n */\n Output.prototype._isStacked = function() {\n var stacked = false;\n\n // Stacking is (currently) only supported for bar charts.\n if (this._chart.getType() === Bar.prototype.TYPE) {\n stacked = this._chart.getStacked();\n }\n\n return stacked;\n };\n\n /** @override */\n Output.prototype.update = function() {\n $.extend(true, this._config, this._makeConfig());\n this._chartjs.update();\n };\n\n return Output;\n\n});\n"],"names":["define","$","Chartjs","Axis","Bar","Base","Line","Pie","Series","makeAxisId","xy","index","Output","prototype","constructor","apply","this","arguments","_canvas","_node","prop","append","_build","Object","create","_config","_chartjs","_makeConfig","_cleanData","data","Array","map","value","html","text","_getChartType","type","_chart","getType","TYPE","getHorizontal","getDoughnut","_makeAxisConfig","axis","scaleData","id","getPosition","POS_DEFAULT","position","getLabel","title","display","getStepSize","ticks","stepSize","getMax","max","getMin","min","charType","config","labels","getLabels","datasets","_makeDatasetsConfig","options","responsive","maintainAspectRatio","plugins","getTitle","indexAxis","legendOptions","getLegendOptions","legend","getXAxes","forEach","i","axisLabels","scales","x","callback","stacked","_isStacked","bind","getYAxes","y","yAxes","parseInt","tooltip","callbacks","label","_makeTooltip","getSeries","series","colors","hasColoredValues","getColors","getColor","dataset","getValues","fill","getFill","backgroundColor","borderColor","tension","_isSmooth","getXAxis","xAxisID","getYAxis","yAxisID","tooltipItem","serieLabel","datasetIndex","tooltipData","dataIndex","chartLabels","push","smooth","getSmooth","TYPE_LINE","getStacked","update","extend"],"mappings":"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"} \ No newline at end of file diff --git a/lib/amd/src/chart_output_chartjs.js b/lib/amd/src/chart_output_chartjs.js index 70930ec7afc..ddd6c71927b 100644 --- a/lib/amd/src/chart_output_chartjs.js +++ b/lib/amd/src/chart_output_chartjs.js @@ -292,7 +292,7 @@ define([ * Get the chart data, add labels and rebuild the tooltip. * * @param {Object[]} tooltipItem The tooltip item object. - * @returns {*[]} + * @returns {Array} * @protected */ Output.prototype._makeTooltip = function(tooltipItem) {