ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/lib/amd/src/paged_content_paging_bar.js000064400000050731152267222500026311 0ustar00// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * Javascript to enhance the paged content paging bar. * * @module core/paged_content_paging_bar * @copyright 2018 Ryan Wyllie * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ define([ 'jquery', 'core/custom_interaction_events', 'core/paged_content_events', 'core/str', 'core/pubsub', 'core/pending', ], function( $, CustomEvents, PagedContentEvents, Str, PubSub, Pending ) { var SELECTORS = { ROOT: '[data-region="paging-bar"]', PAGE: '[data-page]', PAGE_ITEM: '[data-region="page-item"]', PAGE_LINK: '[data-region="page-link"]', FIRST_BUTTON: '[data-control="first"]', LAST_BUTTON: '[data-control="last"]', NEXT_BUTTON: '[data-control="next"]', PREVIOUS_BUTTON: '[data-control="previous"]', DOTS_BUTTONS: '[data-dots]', BEGINNING_DOTS_BUTTON: '[data-dots="beginning"]', ENDING_DOTS_BUTTON: '[data-dots="ending"]', }; /** * Get the page element by number. * * @param {object} root The root element. * @param {Number} pageNumber The page number. * @return {jQuery} */ var getPageByNumber = function(root, pageNumber) { return root.find(SELECTORS.PAGE_ITEM + '[data-page-number="' + pageNumber + '"]'); }; /** * Get the next button element. * * @param {object} root The root element. * @return {jQuery} */ var getNextButton = function(root) { return root.find(SELECTORS.NEXT_BUTTON); }; /** * Set the last page number after which no more pages * should be loaded. * * @param {object} root The root element. * @param {Number} number Page number. */ var setLastPageNumber = function(root, number) { root.attr('data-last-page-number', number); }; /** * Get the last page number. * * @param {object} root The root element. * @return {Number} */ var getLastPageNumber = function(root) { return parseInt(root.attr('data-last-page-number'), 10); }; /** * Get the active page number. * * @param {object} root The root element. * @returns {Number} The page number */ var getActivePageNumber = function(root) { return parseInt(root.attr('data-active-page-number'), 10); }; /** * Set the active page number. * * @param {object} root The root element. * @param {Number} number Page number. */ var setActivePageNumber = function(root, number) { root.attr('data-active-page-number', number); }; /** * Check if there is an active page number. * * @param {object} root The root element. * @returns {bool} */ var hasActivePageNumber = function(root) { var number = getActivePageNumber(root); return !isNaN(number) && number != 0; }; /** * Get the page number for a given page. * * @param {object} root The root element. * @param {object} page The page element. * @returns {Number} The page number */ var getPageNumber = function(root, page) { if (page.attr('data-page') != undefined) { // If it's an actual page then we can just use the page number // attribute. return parseInt(page.attr('data-page-number'), 10); } var pageNumber = 1; var activePageNumber = null; switch (page.attr('data-control')) { case 'first': pageNumber = 1; break; case 'last': pageNumber = getLastPageNumber(root); break; case 'next': activePageNumber = getActivePageNumber(root); var lastPage = getLastPageNumber(root); if (!lastPage) { pageNumber = activePageNumber + 1; } else if (activePageNumber && activePageNumber < lastPage) { pageNumber = activePageNumber + 1; } else { pageNumber = lastPage; } break; case 'previous': activePageNumber = getActivePageNumber(root); if (activePageNumber && activePageNumber > 1) { pageNumber = activePageNumber - 1; } else { pageNumber = 1; } break; default: pageNumber = 1; break; } // Make sure we return an int not a string. return parseInt(pageNumber, 10); }; /** * Get the limit of items for each page. * * @param {object} root The root element. * @returns {Number} */ var getLimit = function(root) { return parseInt(root.attr('data-items-per-page'), 10); }; /** * Set the limit of items for each page. * * @param {object} root The root element. * @param {Number} limit Items per page limit. */ var setLimit = function(root, limit) { root.attr('data-items-per-page', limit); }; /** * Show the paging bar. * * @param {object} root The root element. */ var show = function(root) { root.removeClass('hidden'); }; /** * Hide the paging bar. * * @param {object} root The root element. */ var hide = function(root) { root.addClass('hidden'); }; /** * Disable the next and last buttons in the paging bar. * * @param {object} root The root element. */ var disableNextControlButtons = function(root) { var nextButton = root.find(SELECTORS.NEXT_BUTTON); var lastButton = root.find(SELECTORS.LAST_BUTTON); nextButton.addClass('disabled'); nextButton.attr('aria-disabled', true); lastButton.addClass('disabled'); lastButton.attr('aria-disabled', true); }; /** * Enable the next and last buttons in the paging bar. * * @param {object} root The root element. */ var enableNextControlButtons = function(root) { var nextButton = root.find(SELECTORS.NEXT_BUTTON); var lastButton = root.find(SELECTORS.LAST_BUTTON); nextButton.removeClass('disabled'); nextButton.removeAttr('aria-disabled'); lastButton.removeClass('disabled'); lastButton.removeAttr('aria-disabled'); }; /** * Disable the previous and first buttons in the paging bar. * * @param {object} root The root element. */ var disablePreviousControlButtons = function(root) { var previousButton = root.find(SELECTORS.PREVIOUS_BUTTON); var firstButton = root.find(SELECTORS.FIRST_BUTTON); previousButton.addClass('disabled'); previousButton.attr('aria-disabled', true); firstButton.addClass('disabled'); firstButton.attr('aria-disabled', true); }; /** * Adjusts the size of the paging bar and hides unnecessary pages. * * @param {object} root The root element. */ var adjustPagingBarSize = function(root) { var activePageNumber = getActivePageNumber(root); var lastPageNumber = getLastPageNumber(root); var dotsButtons = root.find(SELECTORS.DOTS_BUTTONS); var beginningDotsButton = root.find(SELECTORS.BEGINNING_DOTS_BUTTON); var endingDotsButton = root.find(SELECTORS.ENDING_DOTS_BUTTON); var pages = root.find(SELECTORS.PAGE); var barSize = parseInt(root.attr('data-bar-size'), 10); if (barSize && lastPageNumber > barSize) { var minpage = Math.max(activePageNumber - Math.round(barSize / 2), 1); var maxpage = minpage + barSize - 1; if (maxpage >= lastPageNumber) { maxpage = lastPageNumber; minpage = maxpage - barSize + 1; } if (minpage > 1) { show(beginningDotsButton); minpage++; } else { hide(beginningDotsButton); } if (maxpage < lastPageNumber) { show(endingDotsButton); maxpage--; } else { hide(endingDotsButton); } dotsButtons.addClass('disabled'); dotsButtons.attr('aria-disabled', true); hide(pages); pages.each(function(index, page) { page = $(page); if ((index + 1) >= minpage && (index + 1) <= maxpage) { show(page); } }); } else { hide(dotsButtons); } }; /** * Enable the previous and first buttons in the paging bar. * * @param {object} root The root element. */ var enablePreviousControlButtons = function(root) { var previousButton = root.find(SELECTORS.PREVIOUS_BUTTON); var firstButton = root.find(SELECTORS.FIRST_BUTTON); previousButton.removeClass('disabled'); previousButton.removeAttr('aria-disabled'); firstButton.removeClass('disabled'); firstButton.removeAttr('aria-disabled'); }; /** * Get the components for a get_string request for the aria-label * on a page. The value is a comma separated string of key and * component. * * @param {object} root The root element. * @return {array} First element is the key, second is the component. */ var getPageAriaLabelComponents = function(root) { var componentString = root.attr('data-aria-label-components-pagination-item'); var components = componentString.split(',').map(function(component) { return component.trim(); }); return components; }; /** * Get the components for a get_string request for the aria-label * on an active page. The value is a comma separated string of key and * component. * * @param {object} root The root element. * @return {array} First element is the key, second is the component. */ var getActivePageAriaLabelComponents = function(root) { var componentString = root.attr('data-aria-label-components-pagination-active-item'); var components = componentString.split(',').map(function(component) { return component.trim(); }); return components; }; /** * Set page numbers on each of the given items. Page numbers are set * from 1..n (where n is the number of items). * * Sets the active page number to be the last page found with * an "active" class (if any). * * Sets the last page number. * * @param {object} root The root element. * @param {jQuery} items A jQuery list of items. */ var generatePageNumbers = function(root, items) { var lastPageNumber = 0; setActivePageNumber(root, 0); items.each(function(index, item) { var pageNumber = index + 1; item = $(item); item.attr('data-page-number', pageNumber); lastPageNumber++; if (item.hasClass('active')) { setActivePageNumber(root, pageNumber); } }); setLastPageNumber(root, lastPageNumber); }; /** * Set the aria-labels on each of the page items in the paging bar. * This includes the next, previous, first, and last items. * * @param {object} root The root element. */ var generateAriaLabels = function(root) { var pageAriaLabelComponents = getPageAriaLabelComponents(root); var activePageAriaLabelComponents = getActivePageAriaLabelComponents(root); var activePageNumber = getActivePageNumber(root); var pageItems = root.find(SELECTORS.PAGE_ITEM); // We want to request all of the strings at once rather than // one at a time. var stringRequests = pageItems.toArray().map(function(page) { page = $(page); if (page.attr('data-page') == undefined) { return {}; } var pageNumber = getPageNumber(root, page); if (pageNumber === activePageNumber) { return { key: activePageAriaLabelComponents[0], component: activePageAriaLabelComponents[1], param: pageNumber }; } else { return { key: pageAriaLabelComponents[0], component: pageAriaLabelComponents[1], param: pageNumber }; } }).filter(Boolean); Str.get_strings(stringRequests).then(function(strings) { pageItems.each(function(index, page) { page = $(page); var string = strings[index]; page.attr('aria-label', string); page.find(SELECTORS.PAGE_LINK).attr('aria-label', string); }); return strings; }) .catch(function() { // No need to interrupt the page if we can't load the aria lang strings. return; }); }; /** * Make the paging bar item for the given page number visible and fire * the SHOW_PAGES paged content event to tell any listening content to * update. * * @param {object} root The root element. * @param {Number} pageNumber The number for the page to show. * @param {string} id A uniqie id for this instance. */ var showPage = function(root, pageNumber, id) { var pendingPromise = new Pending('core/paged_content_paging_bar:showPage'); var lastPageNumber = getLastPageNumber(root); var isSamePage = pageNumber == getActivePageNumber(root); var limit = getLimit(root); var offset = (pageNumber - 1) * limit; if (!isSamePage) { // We only need to toggle the active class if the user didn't click // on the already active page. root.find(SELECTORS.PAGE_ITEM).removeClass('active').removeAttr('aria-current'); var page = getPageByNumber(root, pageNumber); page.addClass('active'); page.attr('aria-current', true); setActivePageNumber(root, pageNumber); adjustPagingBarSize(root); } // Make sure the control buttons are disabled as the user navigates // to either end of the limits. if (lastPageNumber && pageNumber >= lastPageNumber) { disableNextControlButtons(root); } else { enableNextControlButtons(root); } if (pageNumber > 1) { enablePreviousControlButtons(root); } else { disablePreviousControlButtons(root); } generateAriaLabels(root); // This event requires a payload that contains a list of all pages that // were activated. In the case of the paging bar we only show one page at // a time. PubSub.publish(id + PagedContentEvents.SHOW_PAGES, [{ pageNumber: pageNumber, limit: limit, offset: offset }]); pendingPromise.resolve(); }; /** * Add event listeners for interactions with the paging bar as well as listening * for custom paged content events. * * Each event will trigger different logic to update parts of the paging bar's * display. * * @param {object} root The root element. * @param {string} id A uniqie id for this instance. */ var registerEventListeners = function(root, id) { var ignoreControlWhileLoading = root.attr('data-ignore-control-while-loading'); var loading = false; if (ignoreControlWhileLoading == "") { // Default to ignoring control while loading if not specified. ignoreControlWhileLoading = true; } CustomEvents.define(root, [ CustomEvents.events.activate ]); root.on(CustomEvents.events.activate, SELECTORS.PAGE_ITEM, function(e, data) { data.originalEvent.preventDefault(); data.originalEvent.stopPropagation(); if (ignoreControlWhileLoading && loading) { // Do nothing if configured to ignore control while loading. return; } var page = $(e.target).closest(SELECTORS.PAGE_ITEM); if (!page.hasClass('disabled')) { var pageNumber = getPageNumber(root, page); showPage(root, pageNumber, id); loading = true; } }); // This event is fired when all of the items have been loaded. Typically used // in an "infinite" pages context when we don't know the exact number of pages // ahead of time. PubSub.subscribe(id + PagedContentEvents.ALL_ITEMS_LOADED, function(pageNumber) { loading = false; var currentLastPage = getLastPageNumber(root); if (!currentLastPage || pageNumber < currentLastPage) { // Somehow the value we've got saved is higher than the new // value we just received. Perhaps events came out of order. // In any case, save the lowest value. setLastPageNumber(root, pageNumber); } if (pageNumber === 1 && root.attr('data-hide-control-on-single-page')) { // If all items were loaded on the first page then we can hide // the paging bar because there are no other pages to load. hide(root); disableNextControlButtons(root); disablePreviousControlButtons(root); } else { show(root); disableNextControlButtons(root); } }); // This event is fired after all of the requested pages have been rendered. PubSub.subscribe(id + PagedContentEvents.PAGES_SHOWN, function() { // All pages have been shown so turn off the loading flag. loading = false; }); // This is triggered when the paging limit is modified. PubSub.subscribe(id + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT, function(limit) { // Update the limit. setLimit(root, limit); setLastPageNumber(root, 0); setActivePageNumber(root, 0); show(root); // Reload the data from page 1 again. showPage(root, 1, id); }); }; /** * Initialise the paging bar. * @param {object} root The root element. * @param {string} id A uniqie id for this instance. */ var init = function(root, id) { root = $(root); var pages = root.find(SELECTORS.PAGE); generatePageNumbers(root, pages); registerEventListeners(root, id); if (hasActivePageNumber(root)) { var activePageNumber = getActivePageNumber(root); // If the the paging bar was rendered with an active page selected // then make sure we fired off the event to tell the content page to // show. getPageByNumber(root, activePageNumber).click(); if (activePageNumber == 1) { // If the first page is active then disable the previous buttons. disablePreviousControlButtons(root); } } else { // There was no active page number so load the first page using // the next button. This allows the infinite pagination to work. getNextButton(root).click(); } adjustPagingBarSize(root); }; return { init: init, disableNextControlButtons: disableNextControlButtons, enableNextControlButtons: enableNextControlButtons, disablePreviousControlButtons: disablePreviousControlButtons, enablePreviousControlButtons: enablePreviousControlButtons, showPage: showPage, rootSelector: SELECTORS.ROOT, }; });