From 3ad47706131b6f86efeff48d58ff2bbba6ad3767 Mon Sep 17 00:00:00 2001 From: Jan Britz Date: Tue, 2 Jul 2024 13:54:57 +0200 Subject: [PATCH] feat: ui update expandable description and local package badge --- amd/build/edit_question.min.js | 2 +- amd/build/edit_question.min.js.map | 2 +- .../package_search/components/package.min.js | 2 +- .../components/package.min.js.map | 2 +- amd/build/showmore.min.js | 3 ++ amd/build/showmore.min.js.map | 1 + amd/build/utils.min.js.map | 2 +- amd/src/edit_question.js | 26 +++++----- amd/src/package_search/components/package.js | 3 +- amd/src/showmore.js | 52 +++++++++++++++++++ amd/src/utils.js | 2 +- lang/en/qtype_questionpy.php | 3 ++ styles.css | 43 ++++++++++++--- templates/package/package_base.mustache | 28 ++++++++-- templates/package/package_selection.mustache | 26 ++++++---- 15 files changed, 155 insertions(+), 42 deletions(-) create mode 100644 amd/build/showmore.min.js create mode 100644 amd/build/showmore.min.js.map create mode 100644 amd/src/showmore.js diff --git a/amd/build/edit_question.min.js b/amd/build/edit_question.min.js index b35e8438..9976b1ac 100644 --- a/amd/build/edit_question.min.js +++ b/amd/build/edit_question.min.js @@ -1,3 +1,3 @@ -define("qtype_questionpy/edit_question",["exports","core_form/changechecker","core/notification","qtype_questionpy/utils"],(function(_exports,_changechecker,_notification,_utils){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.initActionButton=function(card,selected){const packageHash=document.querySelector('input[name="qpy_package_hash"]'),packageSelected=document.querySelector('input[name="qpy_package_selected"]');if(selected){const packageFile=document.querySelector('input[name="qpy_package_file"]'),changeButton=card.getElementsByClassName("qpy-version-selection-button")[0];changeButton.addEventListener("click",(e=>{e.preventDefault(),packageSelected.value=!1,packageSelected.removeAttribute("disabled"),packageFile&&(packageFile.disabled=!0),packageHash&&(packageHash.value=""),(0,_changechecker.resetFormDirtyState)(changeButton),e.target.form.submit()}))}else{const selectedHash=card.getElementsByClassName("qpy-version-selection")[0],selectButton=card.getElementsByClassName("qpy-version-selection-button")[0];selectButton.addEventListener("click",(e=>{e.preventDefault(),packageSelected.value=!0,packageSelected.removeAttribute("disabled"),packageHash.value=selectedHash.value,(0,_changechecker.resetFormDirtyState)(selectButton),e.target.form.submit()}))}},_exports.initFavouriteButton=function(card,packageId){const button=card.querySelector('[data-for="favourite-button"]');if(!button)return;button.addEventListener("click",(async()=>{try{const isFavourite=button.hasAttribute("data-is-favourite");await(0,_utils.favouritePackage)(packageId,!isFavourite)&&button.toggleAttribute("data-is-favourite",!isFavourite)}catch(exception){await _notification.default.exception(exception)}}))},_exports.initUploadForm=function(){const packageFile=document.querySelector('input[name="qpy_package_file"]'),packageSelected=document.querySelector('input[name="qpy_package_selected"]');packageFile.addEventListener("change",(e=>{packageSelected.value=!0,packageSelected.removeAttribute("disabled"),(0,_changechecker.resetFormDirtyState)(packageFile),e.target.form.submit()}))},_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj}})); +define("qtype_questionpy/edit_question",["exports","core_form/changechecker","core/notification","qtype_questionpy/utils"],(function(_exports,_changechecker,_notification,_utils){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.initActionButton=function(card,selected){const packageSelected=document.querySelector('input[name="qpy_package_selected"]');if(selected){const changeButton=card.getElementsByClassName("qpy-version-selection-button")[0];changeButton.addEventListener("click",(e=>{e.preventDefault();const qpyElements=document.querySelectorAll('[name^="qpy_"]:not(input[name="qpy_package_source"])');for(const qpyElement of qpyElements)qpyElement.disabled=!0;document.querySelector('input[name="qpy_package_source"]').value="search",packageSelected.value=!1,packageSelected.disabled=!1,(0,_changechecker.resetFormDirtyState)(changeButton),e.target.form.submit()}))}else{const packageHash=document.querySelector('input[name="qpy_package_hash"]'),selectedHash=card.getElementsByClassName("qpy-version-selection")[0],selectButton=card.getElementsByClassName("qpy-version-selection-button")[0];selectButton.addEventListener("click",(e=>{e.preventDefault(),packageSelected.value=!0,packageSelected.disabled=!1,packageHash.value=selectedHash.value,(0,_changechecker.resetFormDirtyState)(selectButton),e.target.form.submit()}))}},_exports.initFavouriteButton=function(card,packageId){const button=card.querySelector('[data-for="favourite-button"]');if(!button)return;button.addEventListener("click",(async()=>{try{const isFavourite=button.hasAttribute("data-is-favourite");await(0,_utils.favouritePackage)(packageId,!isFavourite)&&button.toggleAttribute("data-is-favourite",!isFavourite)}catch(exception){await _notification.default.exception(exception)}}))},_exports.initUploadForm=function(){const packageFile=document.querySelector('input[name="qpy_package_file"]'),packageSelected=document.querySelector('input[name="qpy_package_selected"]');packageFile.addEventListener("change",(e=>{packageSelected.value=!0,packageSelected.removeAttribute("disabled"),(0,_changechecker.resetFormDirtyState)(packageFile),e.target.form.submit()}))},_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj}})); //# sourceMappingURL=edit_question.min.js.map \ No newline at end of file diff --git a/amd/build/edit_question.min.js.map b/amd/build/edit_question.min.js.map index 95a4d83c..62ee1d3a 100644 --- a/amd/build/edit_question.min.js.map +++ b/amd/build/edit_question.min.js.map @@ -1 +1 @@ -{"version":3,"file":"edit_question.min.js","sources":["../src/edit_question.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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\nimport {resetFormDirtyState} from 'core_form/changechecker';\nimport Notification from 'core/notification';\nimport {favouritePackage} from 'qtype_questionpy/utils';\n\n/**\n * This function is called by the package_selection-template and initializes the action button.\n *\n * When the package is changed, this function enables the hidden form element qpy_package_changed and\n * submits the form. Since qpy_package_changed is registered as a no-submit button, it prevents the form\n * data from being saved to the question, while still re-rendering the form with access to the new selected package\n * hash.\n *\n * @param {HTMLDivElement} card\n * @param {boolean} selected\n */\nexport function initActionButton(card, selected) {\n const packageHash = document.querySelector('input[name=\"qpy_package_hash\"]');\n const packageSelected = document.querySelector('input[name=\"qpy_package_selected\"]');\n\n if (selected) {\n const packageFile = document.querySelector('input[name=\"qpy_package_file\"]');\n\n // Initialize the button to change the package.\n const changeButton = card.getElementsByClassName(\"qpy-version-selection-button\")[0];\n changeButton.addEventListener(\"click\", (e) => {\n e.preventDefault();\n\n packageSelected.value = false;\n packageSelected.removeAttribute(\"disabled\");\n\n if (packageFile) {\n // We want to prevent, that the same draft id will be used when changing a package.\n packageFile.disabled = true;\n }\n if (packageHash) {\n packageHash.value = '';\n }\n\n // We do not want any form checking when changing a package.\n resetFormDirtyState(changeButton);\n\n e.target.form.submit();\n });\n } else {\n const selectedHash = card.getElementsByClassName(\"qpy-version-selection\")[0];\n const selectButton = card.getElementsByClassName(\"qpy-version-selection-button\")[0];\n\n selectButton.addEventListener(\"click\", (e) => {\n e.preventDefault();\n\n packageSelected.value = true;\n packageSelected.removeAttribute(\"disabled\");\n packageHash.value = selectedHash.value;\n\n // We do not want any form checking when selecting a package.\n resetFormDirtyState(selectButton);\n\n e.target.form.submit();\n });\n }\n}\n\n/**\n * This function enables an auto-submit of the form if a package gets uploaded.\n */\nexport function initUploadForm() {\n const packageFile = document.querySelector('input[name=\"qpy_package_file\"]');\n const packageSelected = document.querySelector('input[name=\"qpy_package_selected\"]');\n packageFile.addEventListener(\"change\", (e) => {\n packageSelected.value = true;\n packageSelected.removeAttribute(\"disabled\");\n // We do not want any form checking when uploading a package.\n resetFormDirtyState(packageFile);\n e.target.form.submit();\n });\n}\n\n/**\n * This function is called by the package_selection-template and initializes the favourite button, when\n * a package is already selected.\n *\n * @param {HTMLDivElement} card\n * @param {number} packageId\n */\nexport function initFavouriteButton(card, packageId) {\n const button = card.querySelector('[data-for=\"favourite-button\"]');\n if (!button) {\n return;\n }\n const isFavouriteAttributeName = \"data-is-favourite\";\n button.addEventListener(\"click\", async() => {\n try {\n const isFavourite = button.hasAttribute(isFavouriteAttributeName);\n const successful = await favouritePackage(packageId, !isFavourite);\n if (successful) {\n button.toggleAttribute(isFavouriteAttributeName, !isFavourite);\n }\n } catch (exception) {\n await Notification.exception(exception);\n }\n });\n}\n"],"names":["card","selected","packageHash","document","querySelector","packageSelected","packageFile","changeButton","getElementsByClassName","addEventListener","e","preventDefault","value","removeAttribute","disabled","target","form","submit","selectedHash","selectButton","packageId","button","async","isFavourite","hasAttribute","toggleAttribute","exception","Notification"],"mappings":"sRAgCiCA,KAAMC,gBAC7BC,YAAcC,SAASC,cAAc,kCACrCC,gBAAkBF,SAASC,cAAc,yCAE3CH,SAAU,OACJK,YAAcH,SAASC,cAAc,kCAGrCG,aAAeP,KAAKQ,uBAAuB,gCAAgC,GACjFD,aAAaE,iBAAiB,SAAUC,IACpCA,EAAEC,iBAEFN,gBAAgBO,OAAQ,EACxBP,gBAAgBQ,gBAAgB,YAE5BP,cAEAA,YAAYQ,UAAW,GAEvBZ,cACAA,YAAYU,MAAQ,2CAIJL,cAEpBG,EAAEK,OAAOC,KAAKC,gBAEf,OACGC,aAAelB,KAAKQ,uBAAuB,yBAAyB,GACpEW,aAAenB,KAAKQ,uBAAuB,gCAAgC,GAEjFW,aAAaV,iBAAiB,SAAUC,IACpCA,EAAEC,iBAEFN,gBAAgBO,OAAQ,EACxBP,gBAAgBQ,gBAAgB,YAChCX,YAAYU,MAAQM,aAAaN,6CAGbO,cAEpBT,EAAEK,OAAOC,KAAKC,oDA2BUjB,KAAMoB,iBAChCC,OAASrB,KAAKI,cAAc,qCAC7BiB,cAILA,OAAOZ,iBAAiB,SAASa,oBAEnBC,YAAcF,OAAOG,aAHF,2BAIA,2BAAiBJ,WAAYG,cAElDF,OAAOI,gBANc,qBAM6BF,aAExD,MAAOG,iBACCC,sBAAaD,UAAUA,yDAhC/BpB,YAAcH,SAASC,cAAc,kCACrCC,gBAAkBF,SAASC,cAAc,sCAC/CE,YAAYG,iBAAiB,UAAWC,IACpCL,gBAAgBO,OAAQ,EACxBP,gBAAgBQ,gBAAgB,mDAEZP,aACpBI,EAAEK,OAAOC,KAAKC"} \ No newline at end of file +{"version":3,"file":"edit_question.min.js","sources":["../src/edit_question.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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\nimport {resetFormDirtyState} from 'core_form/changechecker';\nimport Notification from 'core/notification';\nimport {favouritePackage} from 'qtype_questionpy/utils';\n\n/**\n * This function is called by the package_selection-template and initializes the action button.\n *\n * When the package is changed, this function enables the hidden form element qpy_package_changed and\n * submits the form. Since qpy_package_changed is registered as a no-submit button, it prevents the form\n * data from being saved to the question, while still re-rendering the form with access to the new selected package\n * hash.\n *\n * @param {HTMLDivElement} card\n * @param {boolean} selected\n */\nexport function initActionButton(card, selected) {\n const packageSelected = document.querySelector('input[name=\"qpy_package_selected\"]');\n\n if (selected) {\n // Initialize the button to change the package.\n const changeButton = card.getElementsByClassName(\"qpy-version-selection-button\")[0];\n changeButton.addEventListener(\"click\", (e) => {\n e.preventDefault();\n\n // We want to reduce the amount of unnecessary data exchange.\n const qpyElements = document.querySelectorAll('[name^=\"qpy_\"]:not(input[name=\"qpy_package_source\"])');\n for (const qpyElement of qpyElements) {\n qpyElement.disabled = true;\n }\n\n // When unselecting, view the search container, even if the current package was uploaded.\n const packageSource = document.querySelector('input[name=\"qpy_package_source\"]');\n packageSource.value = 'search';\n\n packageSelected.value = false;\n packageSelected.disabled = false;\n\n // We do not want any form checking when changing a package.\n resetFormDirtyState(changeButton);\n\n e.target.form.submit();\n });\n } else {\n const packageHash = document.querySelector('input[name=\"qpy_package_hash\"]');\n const selectedHash = card.getElementsByClassName(\"qpy-version-selection\")[0];\n const selectButton = card.getElementsByClassName(\"qpy-version-selection-button\")[0];\n\n selectButton.addEventListener(\"click\", (e) => {\n e.preventDefault();\n\n packageSelected.value = true;\n packageSelected.disabled = false;\n packageHash.value = selectedHash.value;\n\n // We do not want any form checking when selecting a package.\n resetFormDirtyState(selectButton);\n\n e.target.form.submit();\n });\n }\n}\n\n/**\n * This function enables an auto-submit of the form if a package gets uploaded.\n */\nexport function initUploadForm() {\n const packageFile = document.querySelector('input[name=\"qpy_package_file\"]');\n const packageSelected = document.querySelector('input[name=\"qpy_package_selected\"]');\n packageFile.addEventListener(\"change\", (e) => {\n packageSelected.value = true;\n packageSelected.removeAttribute(\"disabled\");\n // We do not want any form checking when uploading a package.\n resetFormDirtyState(packageFile);\n e.target.form.submit();\n });\n}\n\n/**\n * This function is called by the package_selection-template and initializes the favourite button, when\n * a package is already selected.\n *\n * @param {HTMLDivElement} card\n * @param {number} packageId\n */\nexport function initFavouriteButton(card, packageId) {\n const button = card.querySelector('[data-for=\"favourite-button\"]');\n if (!button) {\n return;\n }\n const isFavouriteAttributeName = \"data-is-favourite\";\n button.addEventListener(\"click\", async() => {\n try {\n const isFavourite = button.hasAttribute(isFavouriteAttributeName);\n const successful = await favouritePackage(packageId, !isFavourite);\n if (successful) {\n button.toggleAttribute(isFavouriteAttributeName, !isFavourite);\n }\n } catch (exception) {\n await Notification.exception(exception);\n }\n });\n}\n"],"names":["card","selected","packageSelected","document","querySelector","changeButton","getElementsByClassName","addEventListener","e","preventDefault","qpyElements","querySelectorAll","qpyElement","disabled","value","target","form","submit","packageHash","selectedHash","selectButton","packageId","button","async","isFavourite","hasAttribute","toggleAttribute","exception","Notification","packageFile","removeAttribute"],"mappings":"sRAgCiCA,KAAMC,gBAC7BC,gBAAkBC,SAASC,cAAc,yCAE3CH,SAAU,OAEJI,aAAeL,KAAKM,uBAAuB,gCAAgC,GACjFD,aAAaE,iBAAiB,SAAUC,IACpCA,EAAEC,uBAGIC,YAAcP,SAASQ,iBAAiB,4DACzC,MAAMC,cAAcF,YACrBE,WAAWC,UAAW,EAIJV,SAASC,cAAc,oCAC/BU,MAAQ,SAEtBZ,gBAAgBY,OAAQ,EACxBZ,gBAAgBW,UAAW,yCAGPR,cAEpBG,EAAEO,OAAOC,KAAKC,gBAEf,OACGC,YAAcf,SAASC,cAAc,kCACrCe,aAAenB,KAAKM,uBAAuB,yBAAyB,GACpEc,aAAepB,KAAKM,uBAAuB,gCAAgC,GAEjFc,aAAab,iBAAiB,SAAUC,IACpCA,EAAEC,iBAEFP,gBAAgBY,OAAQ,EACxBZ,gBAAgBW,UAAW,EAC3BK,YAAYJ,MAAQK,aAAaL,6CAGbM,cAEpBZ,EAAEO,OAAOC,KAAKC,oDA2BUjB,KAAMqB,iBAChCC,OAAStB,KAAKI,cAAc,qCAC7BkB,cAILA,OAAOf,iBAAiB,SAASgB,oBAEnBC,YAAcF,OAAOG,aAHF,2BAIA,2BAAiBJ,WAAYG,cAElDF,OAAOI,gBANc,qBAM6BF,aAExD,MAAOG,iBACCC,sBAAaD,UAAUA,yDAhC/BE,YAAc1B,SAASC,cAAc,kCACrCF,gBAAkBC,SAASC,cAAc,sCAC/CyB,YAAYtB,iBAAiB,UAAWC,IACpCN,gBAAgBY,OAAQ,EACxBZ,gBAAgB4B,gBAAgB,mDAEZD,aACpBrB,EAAEO,OAAOC,KAAKC"} \ No newline at end of file diff --git a/amd/build/package_search/components/package.min.js b/amd/build/package_search/components/package.min.js index 4e3bfc0d..eaf83858 100644 --- a/amd/build/package_search/components/package.min.js +++ b/amd/build/package_search/components/package.min.js @@ -1,3 +1,3 @@ -define("qtype_questionpy/package_search/components/package",["exports","qtype_questionpy/package_search/component"],(function(_exports,_component){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_component=(obj=_component)&&obj.__esModule?obj:{default:obj};class _default extends _component.default{getWatchers(){return[{watch:"".concat(this.category,"Packages[").concat(this.packageid,"].isfavourite:updated"),handler:this.favouriteChanged}]}create(descriptor){this.packageid=descriptor.packageid,this.category=descriptor.category,this.selectors={FAVOURITE_BUTTON:'[data-for="favourite-button"]'}}isFavourite(){return this.getState()["".concat(this.category,"Packages")].get(this.packageid).isfavourite}stateReady(){this.addEventListener(this.getElement(this.selectors.FAVOURITE_BUTTON),"click",(()=>{this.reactive.dispatch("favourite",this.packageid,!this.isFavourite())}))}async favouriteChanged(){const isFavourite=this.isFavourite();this.getElement(this.selectors.FAVOURITE_BUTTON).toggleAttribute("data-is-favourite",isFavourite)}}return _exports.default=_default,_exports.default})); +define("qtype_questionpy/package_search/components/package",["exports","qtype_questionpy/package_search/component"],(function(_exports,_component){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_component=(obj=_component)&&obj.__esModule?obj:{default:obj};class _default extends _component.default{getWatchers(){return[{watch:"".concat(this.category,"Packages[").concat(this.packageid,"].isfavourite:updated"),handler:this.favouriteChanged}]}create(descriptor){this.packageid=descriptor.packageid,this.category=descriptor.category,this.selectors={FAVOURITE_BUTTON:'[data-for="favourite-button"]'}}isFavourite(){return this.getState()["".concat(this.category,"Packages")].get(this.packageid).isfavourite}stateReady(){this.addEventListener(this.getElement(this.selectors.FAVOURITE_BUTTON),"click",(event=>{event.preventDefault(),this.reactive.dispatch("favourite",this.packageid,!this.isFavourite())}))}async favouriteChanged(){const isFavourite=this.isFavourite();this.getElement(this.selectors.FAVOURITE_BUTTON).toggleAttribute("data-is-favourite",isFavourite)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=package.min.js.map \ No newline at end of file diff --git a/amd/build/package_search/components/package.min.js.map b/amd/build/package_search/components/package.min.js.map index f52e8d13..7117f0b6 100644 --- a/amd/build/package_search/components/package.min.js.map +++ b/amd/build/package_search/components/package.min.js.map @@ -1 +1 @@ -{"version":3,"file":"package.min.js","sources":["../../../src/package_search/components/package.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/components/package\n */\n\nimport Component from 'qtype_questionpy/package_search/component';\n\nexport default class extends Component {\n getWatchers() {\n return [\n {watch: `${this.category}Packages[${this.packageid}].isfavourite:updated`, handler: this.favouriteChanged},\n ];\n }\n\n create(descriptor) {\n this.packageid = descriptor.packageid;\n this.category = descriptor.category;\n this.selectors = {\n FAVOURITE_BUTTON: '[data-for=\"favourite-button\"]',\n };\n }\n\n isFavourite() {\n return this.getState()[`${this.category}Packages`].get(this.packageid).isfavourite;\n }\n\n stateReady() {\n this.addEventListener(this.getElement(this.selectors.FAVOURITE_BUTTON), \"click\", () => {\n this.reactive.dispatch(\"favourite\", this.packageid, !this.isFavourite());\n });\n }\n\n async favouriteChanged() {\n const isFavourite = this.isFavourite();\n this.getElement(this.selectors.FAVOURITE_BUTTON).toggleAttribute(\"data-is-favourite\", isFavourite);\n }\n}\n"],"names":["Component","getWatchers","watch","this","category","packageid","handler","favouriteChanged","create","descriptor","selectors","FAVOURITE_BUTTON","isFavourite","getState","get","isfavourite","stateReady","addEventListener","getElement","reactive","dispatch","toggleAttribute"],"mappings":"gUAuB6BA,mBACzBC,oBACW,CACH,CAACC,gBAAUC,KAAKC,6BAAoBD,KAAKE,mCAAkCC,QAASH,KAAKI,mBAIjGC,OAAOC,iBACEJ,UAAYI,WAAWJ,eACvBD,SAAWK,WAAWL,cACtBM,UAAY,CACbC,iBAAkB,iCAI1BC,qBACWT,KAAKU,qBAAcV,KAAKC,sBAAoBU,IAAIX,KAAKE,WAAWU,YAG3EC,kBACSC,iBAAiBd,KAAKe,WAAWf,KAAKO,UAAUC,kBAAmB,SAAS,UACxEQ,SAASC,SAAS,YAAajB,KAAKE,WAAYF,KAAKS,iDAKxDA,YAAcT,KAAKS,mBACpBM,WAAWf,KAAKO,UAAUC,kBAAkBU,gBAAgB,oBAAqBT"} \ No newline at end of file +{"version":3,"file":"package.min.js","sources":["../../../src/package_search/components/package.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/components/package\n */\n\nimport Component from 'qtype_questionpy/package_search/component';\n\nexport default class extends Component {\n getWatchers() {\n return [\n {watch: `${this.category}Packages[${this.packageid}].isfavourite:updated`, handler: this.favouriteChanged},\n ];\n }\n\n create(descriptor) {\n this.packageid = descriptor.packageid;\n this.category = descriptor.category;\n this.selectors = {\n FAVOURITE_BUTTON: '[data-for=\"favourite-button\"]',\n };\n }\n\n isFavourite() {\n return this.getState()[`${this.category}Packages`].get(this.packageid).isfavourite;\n }\n\n stateReady() {\n this.addEventListener(this.getElement(this.selectors.FAVOURITE_BUTTON), \"click\", (event) => {\n event.preventDefault();\n this.reactive.dispatch(\"favourite\", this.packageid, !this.isFavourite());\n });\n }\n\n async favouriteChanged() {\n const isFavourite = this.isFavourite();\n this.getElement(this.selectors.FAVOURITE_BUTTON).toggleAttribute(\"data-is-favourite\", isFavourite);\n }\n}\n"],"names":["Component","getWatchers","watch","this","category","packageid","handler","favouriteChanged","create","descriptor","selectors","FAVOURITE_BUTTON","isFavourite","getState","get","isfavourite","stateReady","addEventListener","getElement","event","preventDefault","reactive","dispatch","toggleAttribute"],"mappings":"gUAuB6BA,mBACzBC,oBACW,CACH,CAACC,gBAAUC,KAAKC,6BAAoBD,KAAKE,mCAAkCC,QAASH,KAAKI,mBAIjGC,OAAOC,iBACEJ,UAAYI,WAAWJ,eACvBD,SAAWK,WAAWL,cACtBM,UAAY,CACbC,iBAAkB,iCAI1BC,qBACWT,KAAKU,qBAAcV,KAAKC,sBAAoBU,IAAIX,KAAKE,WAAWU,YAG3EC,kBACSC,iBAAiBd,KAAKe,WAAWf,KAAKO,UAAUC,kBAAmB,SAAUQ,QAC9EA,MAAMC,sBACDC,SAASC,SAAS,YAAanB,KAAKE,WAAYF,KAAKS,iDAKxDA,YAAcT,KAAKS,mBACpBM,WAAWf,KAAKO,UAAUC,kBAAkBY,gBAAgB,oBAAqBX"} \ No newline at end of file diff --git a/amd/build/showmore.min.js b/amd/build/showmore.min.js new file mode 100644 index 00000000..4eac89e1 --- /dev/null +++ b/amd/build/showmore.min.js @@ -0,0 +1,3 @@ +define("qtype_questionpy/showmore",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;const isOverflowing=element=>element.scrollHeight>element.clientHeight;_exports.init=id=>{const element=document.getElementById(id),container=element.querySelector(".qpy-show-more-container"),button=element.querySelector(".qpy-show-more-button");window.addEventListener("resize",(()=>{button.classList.contains("collapsed")&&button.classList.toggle("d-none",!isOverflowing(container))})),button.classList.toggle("d-none",!isOverflowing(container))}})); + +//# sourceMappingURL=showmore.min.js.map \ No newline at end of file diff --git a/amd/build/showmore.min.js.map b/amd/build/showmore.min.js.map new file mode 100644 index 00000000..378de919 --- /dev/null +++ b/amd/build/showmore.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"showmore.min.js","sources":["../src/showmore.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/showmore\n */\n\n\n/**\n * Return `true` if the element is overflowing.\n *\n * @param {HTMLElement} element\n * @returns {boolean}\n */\nconst isOverflowing = (element) => {\n return element.scrollHeight > element.clientHeight;\n};\n\n\n/**\n * Initializes the dynamic description box.\n *\n * @param {string} id\n */\nexport const init = (id) => {\n const element = document.getElementById(id);\n\n const container = element.querySelector(\".qpy-show-more-container\");\n const button = element.querySelector(\".qpy-show-more-button\");\n\n window.addEventListener(\"resize\", () => {\n if (button.classList.contains(\"collapsed\")) {\n button.classList.toggle(\"d-none\", !isOverflowing(container));\n }\n });\n\n button.classList.toggle(\"d-none\", !isOverflowing(container));\n};\n"],"names":["isOverflowing","element","scrollHeight","clientHeight","id","document","getElementById","container","querySelector","button","window","addEventListener","classList","contains","toggle"],"mappings":"sJA4BMA,cAAiBC,SACZA,QAAQC,aAAeD,QAAQE,2BASrBC,WACXH,QAAUI,SAASC,eAAeF,IAElCG,UAAYN,QAAQO,cAAc,4BAClCC,OAASR,QAAQO,cAAc,yBAErCE,OAAOC,iBAAiB,UAAU,KAC1BF,OAAOG,UAAUC,SAAS,cAC1BJ,OAAOG,UAAUE,OAAO,UAAWd,cAAcO,eAIzDE,OAAOG,UAAUE,OAAO,UAAWd,cAAcO"} \ No newline at end of file diff --git a/amd/build/utils.min.js.map b/amd/build/utils.min.js.map index 01a9797d..7316da16 100644 --- a/amd/build/utils.min.js.map +++ b/amd/build/utils.min.js.map @@ -1 +1 @@ -{"version":3,"file":"utils.min.js","sources":["../src/utils.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/utils\n */\n\nimport Ajax from 'core/ajax';\n\n\n/**\n * Favourites a package.\n *\n * @param {number} packageid\n * @param {boolean} favourite\n * @returns {Promise}\n */\nexport const favouritePackage = async(packageid, favourite) => {\n return await Ajax.call([{\n methodname: \"qtype_questionpy_favourite_package\",\n args: {\n packageid: packageid,\n favourite: favourite,\n },\n }])[0];\n};"],"names":["async","packageid","favourite","Ajax","call","methodname","args"],"mappings":"iQA+BgCA,MAAMC,UAAWC,kBAChCC,cAAKC,KAAK,CAAC,CACpBC,WAAY,qCACZC,KAAM,CACFL,UAAWA,UACXC,UAAWA,cAEf"} \ No newline at end of file +{"version":3,"file":"utils.min.js","sources":["../src/utils.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/utils\n */\n\nimport Ajax from 'core/ajax';\n\n\n/**\n * Favourites a package.\n *\n * @param {number} packageid\n * @param {boolean} favourite\n * @returns {Promise}\n */\nexport const favouritePackage = async(packageid, favourite) => {\n return await Ajax.call([{\n methodname: \"qtype_questionpy_favourite_package\",\n args: {\n packageid: packageid,\n favourite: favourite,\n },\n }])[0];\n};\n"],"names":["async","packageid","favourite","Ajax","call","methodname","args"],"mappings":"iQA+BgCA,MAAMC,UAAWC,kBAChCC,cAAKC,KAAK,CAAC,CACpBC,WAAY,qCACZC,KAAM,CACFL,UAAWA,UACXC,UAAWA,cAEf"} \ No newline at end of file diff --git a/amd/src/edit_question.js b/amd/src/edit_question.js index 5e22f656..135826df 100644 --- a/amd/src/edit_question.js +++ b/amd/src/edit_question.js @@ -31,34 +31,34 @@ import {favouritePackage} from 'qtype_questionpy/utils'; * @param {boolean} selected */ export function initActionButton(card, selected) { - const packageHash = document.querySelector('input[name="qpy_package_hash"]'); const packageSelected = document.querySelector('input[name="qpy_package_selected"]'); if (selected) { - const packageFile = document.querySelector('input[name="qpy_package_file"]'); - // Initialize the button to change the package. const changeButton = card.getElementsByClassName("qpy-version-selection-button")[0]; changeButton.addEventListener("click", (e) => { e.preventDefault(); - packageSelected.value = false; - packageSelected.removeAttribute("disabled"); - - if (packageFile) { - // We want to prevent, that the same draft id will be used when changing a package. - packageFile.disabled = true; - } - if (packageHash) { - packageHash.value = ''; + // We want to reduce the amount of unnecessary data exchange. + const qpyElements = document.querySelectorAll('[name^="qpy_"]:not(input[name="qpy_package_source"])'); + for (const qpyElement of qpyElements) { + qpyElement.disabled = true; } + // When unselecting, view the search container, even if the current package was uploaded. + const packageSource = document.querySelector('input[name="qpy_package_source"]'); + packageSource.value = 'search'; + + packageSelected.value = false; + packageSelected.disabled = false; + // We do not want any form checking when changing a package. resetFormDirtyState(changeButton); e.target.form.submit(); }); } else { + const packageHash = document.querySelector('input[name="qpy_package_hash"]'); const selectedHash = card.getElementsByClassName("qpy-version-selection")[0]; const selectButton = card.getElementsByClassName("qpy-version-selection-button")[0]; @@ -66,7 +66,7 @@ export function initActionButton(card, selected) { e.preventDefault(); packageSelected.value = true; - packageSelected.removeAttribute("disabled"); + packageSelected.disabled = false; packageHash.value = selectedHash.value; // We do not want any form checking when selecting a package. diff --git a/amd/src/package_search/components/package.js b/amd/src/package_search/components/package.js index d48329eb..c7e78731 100644 --- a/amd/src/package_search/components/package.js +++ b/amd/src/package_search/components/package.js @@ -41,7 +41,8 @@ export default class extends Component { } stateReady() { - this.addEventListener(this.getElement(this.selectors.FAVOURITE_BUTTON), "click", () => { + this.addEventListener(this.getElement(this.selectors.FAVOURITE_BUTTON), "click", (event) => { + event.preventDefault(); this.reactive.dispatch("favourite", this.packageid, !this.isFavourite()); }); } diff --git a/amd/src/showmore.js b/amd/src/showmore.js new file mode 100644 index 00000000..2f4d4a5c --- /dev/null +++ b/amd/src/showmore.js @@ -0,0 +1,52 @@ +/* + * This file is part of the QuestionPy Moodle plugin - https://questionpy.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 . + */ + +/** + * @module qtype_questionpy/showmore + */ + + +/** + * Return `true` if the element is overflowing. + * + * @param {HTMLElement} element + * @returns {boolean} + */ +const isOverflowing = (element) => { + return element.scrollHeight > element.clientHeight; +}; + + +/** + * Initializes the dynamic description box. + * + * @param {string} id + */ +export const init = (id) => { + const element = document.getElementById(id); + + const container = element.querySelector(".qpy-show-more-container"); + const button = element.querySelector(".qpy-show-more-button"); + + window.addEventListener("resize", () => { + if (button.classList.contains("collapsed")) { + button.classList.toggle("d-none", !isOverflowing(container)); + } + }); + + button.classList.toggle("d-none", !isOverflowing(container)); +}; diff --git a/amd/src/utils.js b/amd/src/utils.js index cb7015c7..dae9a3c9 100644 --- a/amd/src/utils.js +++ b/amd/src/utils.js @@ -37,4 +37,4 @@ export const favouritePackage = async(packageid, favourite) => { favourite: favourite, }, }])[0]; -}; \ No newline at end of file +}; diff --git a/lang/en/qtype_questionpy.php b/lang/en/qtype_questionpy.php index e57368b9..014b0795 100644 --- a/lang/en/qtype_questionpy.php +++ b/lang/en/qtype_questionpy.php @@ -63,6 +63,9 @@ $string['selection_no_icon'] = 'Could not load the icon.'; $string['selection_required'] = 'Please select a package.'; +$string['selection_custom_package_header'] = 'Custom Package'; +$string['selection_custom_package_text'] = 'This package was uploaded by a user and might not appear in the package search.'; + $string['select_package'] = 'Select'; $string['select_package_element_aria'] = 'Choose version.'; $string['change_package'] = 'Change'; diff --git a/styles.css b/styles.css index a8e23230..d4185035 100644 --- a/styles.css +++ b/styles.css @@ -35,7 +35,7 @@ display: flex; flex-flow: column; row-gap: 5px; - overflow-y: scroll; + overflow: auto; max-height: 400px; } @@ -45,9 +45,10 @@ display: flex; gap: 10px; align-items: stretch; - height: 120px; + min-height: 120px; width: var(--qpy-card-width); padding: 10px; + flex: none; } .qpy-card-image { @@ -72,12 +73,6 @@ flex-direction: column; } -.qpy-card-description { - flex: 1; - overflow-y: auto; - margin: 0; -} - .qpy-card-action { display: flex; flex-direction: column; @@ -150,3 +145,35 @@ padding-left: 5px; margin-top: 20px; } + +.qpy-card-description { + text-align: justify; +} +.qpy-show-more .collapse:not(.show) { + display: block; + overflow: hidden; +} + +.qpy-show-more .collapse:not(.show), +.qpy-show-more .collapsing { + height: 4rem; + -webkit-mask-image: linear-gradient(to bottom, black 75%, transparent 100%); + mask-image: linear-gradient(to bottom, black 75%, transparent 100%); +} + +.qpy-show-more :not(.collapsed) .qpy-show-more-button-more, +.qpy-show-more .collapsed .qpy-show-more-button-less { + display: none; +} + +.qpy-show-more .collapsing > :first-child, +.qpy-show-more .collapse > :first-child { + padding-top: 0; + margin-top: 0; +} + +.qpy-show-more .collapsing > :last-child, +.qpy-show-more .collapse > :last-child { + padding-bottom: 0; + margin-bottom: 0; +} diff --git a/templates/package/package_base.mustache b/templates/package/package_base.mustache index 1265798e..8c8a5f81 100644 --- a/templates/package/package_base.mustache +++ b/templates/package/package_base.mustache @@ -39,9 +39,29 @@
{{name}} {{namespace}}
-

- {{description}} -

+
+ + +
{{$action}} Default action section {{/action}} - \ No newline at end of file + +{{#js}} + require(['qtype_questionpy/showmore'], function(showmore) { + showmore.init("qpy-show-more-{{uniqid}}"); + }); +{{/js}} diff --git a/templates/package/package_selection.mustache b/templates/package/package_selection.mustache index 28578cf7..52a76503 100644 --- a/templates/package/package_selection.mustache +++ b/templates/package/package_selection.mustache @@ -55,7 +55,6 @@ }} {{