From a1e15a5e437c832927e083f69675af4cf237d7ea Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Tue, 23 Sep 2025 16:52:55 +0100 Subject: [PATCH 01/66] iss1171 - reactive start --- amd/build/metadata/container.min.js | 12 +++ amd/build/metadata/container.min.js.map | 1 + amd/build/metadata/contributors.min.js | 12 +++ amd/build/metadata/contributors.min.js.map | 1 + amd/build/metadata/events.min.js | 12 +++ amd/build/metadata/events.min.js.map | 1 + amd/build/metadata/exporter.min.js | 13 ++++ amd/build/metadata/exporter.min.js.map | 1 + amd/build/metadata/main.min.js | 12 +++ amd/build/metadata/main.min.js.map | 1 + amd/build/metadata/metadata.min.js | 3 + amd/build/metadata/metadata.min.js.map | 1 + amd/build/metadata/mutations.min.js | 12 +++ amd/build/metadata/mutations.min.js.map | 1 + amd/src/metadata/container.js | 88 ++++++++++++++++++++++ amd/src/metadata/contributors.js | 53 +++++++++++++ amd/src/metadata/events.js | 56 ++++++++++++++ amd/src/metadata/exporter.js | 40 ++++++++++ amd/src/metadata/metadata.js | 76 +++++++++++++++++++ amd/src/metadata/mutations.js | 79 +++++++++++++++++++ classes/output/metadata.php | 67 ++++++++++++++++ edit_stack_form.php | 7 +- templates/metadata.mustache | 32 ++++++++ templates/metadata/contributors.mustache | 45 +++++++++++ 24 files changed, 623 insertions(+), 3 deletions(-) create mode 100644 amd/build/metadata/container.min.js create mode 100644 amd/build/metadata/container.min.js.map create mode 100644 amd/build/metadata/contributors.min.js create mode 100644 amd/build/metadata/contributors.min.js.map create mode 100644 amd/build/metadata/events.min.js create mode 100644 amd/build/metadata/events.min.js.map create mode 100644 amd/build/metadata/exporter.min.js create mode 100644 amd/build/metadata/exporter.min.js.map create mode 100644 amd/build/metadata/main.min.js create mode 100644 amd/build/metadata/main.min.js.map create mode 100644 amd/build/metadata/metadata.min.js create mode 100644 amd/build/metadata/metadata.min.js.map create mode 100644 amd/build/metadata/mutations.min.js create mode 100644 amd/build/metadata/mutations.min.js.map create mode 100644 amd/src/metadata/container.js create mode 100644 amd/src/metadata/contributors.js create mode 100644 amd/src/metadata/events.js create mode 100644 amd/src/metadata/exporter.js create mode 100644 amd/src/metadata/metadata.js create mode 100644 amd/src/metadata/mutations.js create mode 100644 classes/output/metadata.php create mode 100644 templates/metadata.mustache create mode 100644 templates/metadata/contributors.mustache diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js new file mode 100644 index 00000000000..1b33b5152df --- /dev/null +++ b/amd/build/metadata/container.min.js @@ -0,0 +1,12 @@ +define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/metadata/metadata"],(function(_exports,_reactive,_metadata){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * The beginner main app component. + * + * @module mod_nosferatu/local/beginner + * @class mod_nosferatu/local/beginner + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-app-container",this.selectors={METADATACONTAINER:"[data-for='metadata-contrib']"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){this._reloadCityComponent({state:state})}async _reloadCityComponent(_ref){let{state:state}=_ref;const data={people:[]};state.people.forEach((person=>{data.people.push({...person})})),data.haspeople=0!=data.people.length;const citiyContainer=this.getElement(this.selectors.METADATACONTAINER);if(!citiyContainer)throw new Error("Missing city container.");window.console.log(data),this.cityComponent=await this.renderComponent(citiyContainer,"qtype_stack/metadata/contributors",data)}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map new file mode 100644 index 00000000000..f03e4e554ec --- /dev/null +++ b/amd/build/metadata/container.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.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 * The beginner main app component.\n *\n * @module mod_nosferatu/local/beginner\n * @class mod_nosferatu/local/beginner\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n\n /**\n * All the component definition should be initialized on the \"create\" method.\n */\n create() {\n // This is an optional name for the debugging messages.\n this.name = 'stack-metadata-app-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='metadata-contrib']`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * Note in this case we want our stateReady to be async.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n this._reloadCityComponent({state});\n }\n\n async _reloadCityComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object. In the intermediate level you will learng how to centralize this\n // kind of operations to keep your components cleaner.\n const data = {\n people: [],\n };\n state.people.forEach(person => {\n data.people.push({...person});\n });\n data.haspeople = (data.people.length != 0);\n\n // To render a child component we need a container.\n const citiyContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!citiyContainer) {\n throw new Error('Missing city container.');\n }\n window.console.log(data);\n // We store the new content into an attribute in case we want to remove it in the future.\n this.cityComponent = await this.renderComponent(citiyContainer, 'qtype_stack/metadata/contributors', data);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","target","this","element","document","querySelector","reactive","metadata","state","_reloadCityComponent","data","people","forEach","person","push","haspeople","length","citiyContainer","getElement","Error","window","console","log","cityComponent","renderComponent"],"mappings":";;;;;;;;;uBA2B6BA,wBAKzBC,cAESC,KAAO,oCACPC,UAAY,CACbC,+DAWIC,OAAQF,kBACT,IAAIG,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVR,UAAAA,6BAWSS,YACRC,qBAAqB,CAACD,MAAAA,6CAGJA,MAACA,kBAIlBE,KAAO,CACTC,OAAQ,IAEZH,MAAMG,OAAOC,SAAQC,SACjBH,KAAKC,OAAOG,KAAK,IAAID,YAEzBH,KAAKK,UAAmC,GAAtBL,KAAKC,OAAOK,aAGxBC,eAAiBf,KAAKgB,WAAWhB,KAAKH,UAAUC,uBACjDiB,qBACK,IAAIE,MAAM,2BAEpBC,OAAOC,QAAQC,IAAIZ,WAEda,oBAAsBrB,KAAKsB,gBAAgBP,eAAgB,oCAAqCP"} \ No newline at end of file diff --git a/amd/build/metadata/contributors.min.js b/amd/build/metadata/contributors.min.js new file mode 100644 index 00000000000..16e5b177c18 --- /dev/null +++ b/amd/build/metadata/contributors.min.js @@ -0,0 +1,12 @@ +define("qtype_stack/metadata/contributors",["exports","core/reactive","qtype_stack/metadata/metadata"],(function(_exports,_reactive,_metadata){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * The beginner main app component. + * + * @module mod_nosferatu/local/beginner + * @class mod_nosferatu/local/beginner + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-contrib"}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=contributors.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/contributors.min.js.map b/amd/build/metadata/contributors.min.js.map new file mode 100644 index 00000000000..894ceb5f75e --- /dev/null +++ b/amd/build/metadata/contributors.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"contributors.min.js","sources":["../../src/metadata/contributors.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 * The beginner main app component.\n *\n * @module mod_nosferatu/local/beginner\n * @class mod_nosferatu/local/beginner\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n\n /**\n * All the component definition should be initialized on the \"create\" method.\n */\n create() {\n // This is an optional name for the debugging messages.\n this.name = 'stack-metadata-contrib';\n\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n}"],"names":["BaseComponent","create","name","target","selectors","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;;uBA2B6BA,wBAKzBC,cAESC,KAAO,qCAWJC,OAAQC,kBACT,IAAIC,KAAK,CACZC,QAASC,SAASC,cAAcL,QAChCM,SAAUC,mBACVN,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/events.min.js b/amd/build/metadata/events.min.js new file mode 100644 index 00000000000..2dd87572f43 --- /dev/null +++ b/amd/build/metadata/events.min.js @@ -0,0 +1,12 @@ +define("qtype_stack/metadata/events",["exports","core/event_dispatcher"],(function(_exports,_event_dispatcher){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.notifyQtypeStackStateUpdated=_exports.eventTypes=void 0; +/** + * Javascript events for the `mod_nosferatu` activity. + * + * @module mod_nosferatu/events + * @copyright 2021 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since 4.0 + */ +const eventTypes={qtypeStackStateUpdated:"qtype_stack/stateUpdated"};_exports.eventTypes=eventTypes;_exports.notifyQtypeStackStateUpdated=(detail,container)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.qtypeStackStateUpdated,detail,container)})); + +//# sourceMappingURL=events.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/events.min.js.map b/amd/build/metadata/events.min.js.map new file mode 100644 index 00000000000..89e91e6c631 --- /dev/null +++ b/amd/build/metadata/events.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"events.min.js","sources":["../../src/metadata/events.js"],"sourcesContent":["\n// 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\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Javascript events for the `mod_nosferatu` activity.\n *\n * @module mod_nosferatu/events\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\n/**\n * Events for the `mod_nosferatu` activity.\n *\n * @constant\n * @property {String} modNosferatuStateUpdated See {@link event:modNosferatuStateUpdated}\n */\nexport const eventTypes = {\n /**\n * Event triggered when the activity reactive state is updated.\n *\n * @event modNosferatuStateUpdated\n * @type {CustomEvent}\n * @property {Array} nodes The list of parent nodes which were updated\n */\n qtypeStackStateUpdated: 'qtype_stack/stateUpdated',\n};\n\n/**\n * Trigger an event to indicate that the activity state is updated.\n *\n * @method notifyModNosferatuStateUpdated\n * @param {object} detail the full state\n * @param {HTMLElement} container the custom event target (document if none provided)\n * @returns {CustomEvent}\n * @fires modNosferatuStateUpdated\n */\nexport const notifyQtypeStackStateUpdated = (detail, container) => {\n return dispatchEvent(eventTypes.qtypeStackStateUpdated, detail, container);\n};"],"names":["eventTypes","qtypeStackStateUpdated","detail","container"],"mappings":";;;;;;;;;MAiCaA,WAAa,CAQtBC,uBAAwB,iGAYgB,CAACC,OAAQC,aAC1C,mCAAcH,WAAWC,uBAAwBC,OAAQC"} \ No newline at end of file diff --git a/amd/build/metadata/exporter.min.js b/amd/build/metadata/exporter.min.js new file mode 100644 index 00000000000..f9b2ec197bb --- /dev/null +++ b/amd/build/metadata/exporter.min.js @@ -0,0 +1,13 @@ +define("qtype_stack/metadata/exporter",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default= +/** + * Module to export parts of the state and transform them to be used in templates + * and as draggable data. + * + * @module mod_nosferatu/local/intermediate/exporter + * @class mod_nosferatu/local/intermediate/exporter + * @copyright 2022 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class{constructor(reactive){this.reactive=reactive}metadata(state){const data={people:[]};return state.people.forEach((person=>{data.people.push({...person})})),data.haspeople=0!=data.people.length,data}},_exports.default})); + +//# sourceMappingURL=exporter.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/exporter.min.js.map b/amd/build/metadata/exporter.min.js.map new file mode 100644 index 00000000000..6b374ffc987 --- /dev/null +++ b/amd/build/metadata/exporter.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"exporter.min.js","sources":["../../src/metadata/exporter.js"],"sourcesContent":["// along with Moodle. If not, see .\n\n/**\n * Module to export parts of the state and transform them to be used in templates\n * and as draggable data.\n *\n * @module mod_nosferatu/local/intermediate/exporter\n * @class mod_nosferatu/local/intermediate/exporter\n * @copyright 2022 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n\n /**\n * Class constructor.\n * @param {Reactive} reactive the course editor object\n */\n constructor(reactive) {\n this.reactive = reactive;\n }\n\n /**\n * Generate the people export data from the state.\n *\n * @param {Object} state the current state.\n * @returns {Object}\n */\n metadata(state) {\n // Collect section information from the state.\n const data = {\n // State stores maps of key-values instead of simple arrays.\n people: [],\n };\n state.people.forEach(person => {\n data.people.push({...person});\n });\n data.haspeople = (data.people.length != 0);\n return data;\n }\n}"],"names":["constructor","reactive","metadata","state","data","people","forEach","person","push","haspeople","length"],"mappings":";;;;;;;;;;MAiBIA,YAAYC,eACHA,SAAWA,SASpBC,SAASC,aAECC,KAAO,CAETC,OAAQ,WAEZF,MAAME,OAAOC,SAAQC,SACjBH,KAAKC,OAAOG,KAAK,IAAID,YAEzBH,KAAKK,UAAmC,GAAtBL,KAAKC,OAAOK,OACvBN"} \ No newline at end of file diff --git a/amd/build/metadata/main.min.js b/amd/build/metadata/main.min.js new file mode 100644 index 00000000000..f8d9e9051b2 --- /dev/null +++ b/amd/build/metadata/main.min.js @@ -0,0 +1,12 @@ +define("qtype_stack/metadata/main",["exports","core/reactive","qtype_stack/metadata/metadata"],(function(_exports,_reactive,_metadata){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * The beginner main app component. + * + * @module mod_nosferatu/local/beginner + * @class mod_nosferatu/local/beginner + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-app-container",this.selectors={METADATACONTAINER:"[data-for='metadata']"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){this._reloadCityComponent({state:state})}async _reloadCityComponent(_ref){let{state:state}=_ref;const data={people:[]};state.people.forEach((person=>{data.people.push({...person})})),data.haspeople=0!=data.people.length;const citiyContainer=this.getElement(this.selectors.METADATACONTAINER);if(!citiyContainer)throw new Error("Missing city container.");window.console.log(data),this.cityComponent=await this.renderComponent(citiyContainer,"qtype_stack/metadata",data)}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=main.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/main.min.js.map b/amd/build/metadata/main.min.js.map new file mode 100644 index 00000000000..15be14c93ef --- /dev/null +++ b/amd/build/metadata/main.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.min.js","sources":["../../src/metadata/main.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 * The beginner main app component.\n *\n * @module mod_nosferatu/local/beginner\n * @class mod_nosferatu/local/beginner\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n\n /**\n * All the component definition should be initialized on the \"create\" method.\n */\n create() {\n // This is an optional name for the debugging messages.\n this.name = 'stack-metadata-app-container';\n\n this.selectors = {\n METADATACONTAINER: `[data-for='metadata']`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * Note in this case we want our stateReady to be async.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n this._reloadCityComponent({state});\n }\n\n async _reloadCityComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object. In the intermediate level you will learng how to centralize this\n // kind of operations to keep your components cleaner.\n const data = {\n people: [],\n };\n state.people.forEach(person => {\n data.people.push({...person});\n });\n data.haspeople = (data.people.length != 0);\n\n // To render a child component we need a container.\n const citiyContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!citiyContainer) {\n throw new Error('Missing city container.');\n }\n window.console.log(data);\n // We store the new content into an attribute in case we want to remove it in the future.\n this.cityComponent = await this.renderComponent(citiyContainer, 'qtype_stack/metadata', data);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","target","this","element","document","querySelector","reactive","metadata","state","_reloadCityComponent","data","people","forEach","person","push","haspeople","length","citiyContainer","getElement","Error","window","console","log","cityComponent","renderComponent"],"mappings":";;;;;;;;;uBA2B6BA,wBAKzBC,cAESC,KAAO,oCAEPC,UAAY,CACbC,uDAWIC,OAAQF,kBACT,IAAIG,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVR,UAAAA,6BAWSS,YACRC,qBAAqB,CAACD,MAAAA,6CAGJA,MAACA,kBAIlBE,KAAO,CACTC,OAAQ,IAEZH,MAAMG,OAAOC,SAAQC,SACjBH,KAAKC,OAAOG,KAAK,IAAID,YAEzBH,KAAKK,UAAmC,GAAtBL,KAAKC,OAAOK,aAGxBC,eAAiBf,KAAKgB,WAAWhB,KAAKH,UAAUC,uBACjDiB,qBACK,IAAIE,MAAM,2BAEpBC,OAAOC,QAAQC,IAAIZ,WAEda,oBAAsBrB,KAAKsB,gBAAgBP,eAAgB,uBAAwBP"} \ No newline at end of file diff --git a/amd/build/metadata/metadata.min.js b/amd/build/metadata/metadata.min.js new file mode 100644 index 00000000000..2db6fb5c501 --- /dev/null +++ b/amd/build/metadata/metadata.min.js @@ -0,0 +1,3 @@ +define("qtype_stack/metadata/metadata",["exports","core/reactive","qtype_stack/metadata/mutations","qtype_stack/metadata/events"],(function(_exports,_reactive,_mutations,_events){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.metadata=_exports.init=void 0;class StackMetadata extends _reactive.Reactive{}const metadata=new StackMetadata({name:"qtype_stack_metadata",eventName:_events.eventTypes.qtypeStackStateUpdated,eventDispatch:_events.notifyQtypeStackStateUpdated,state:{people:[{id:1,name:"Carlos",bitten:!1},{id:2,name:"Amaia",bitten:!1},{id:3,name:"Sara",bitten:!1},{id:4,name:"Ilya",bitten:!0},{id:5,name:"Ferran",bitten:!1}]},mutations:_mutations.mutations});_exports.metadata=metadata;_exports.init=()=>{}})); + +//# sourceMappingURL=metadata.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadata.min.js.map b/amd/build/metadata/metadata.min.js.map new file mode 100644 index 00000000000..e87322e0389 --- /dev/null +++ b/amd/build/metadata/metadata.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nconst state = {\n 'people': [\n {\n id: 1,\n name: 'Carlos',\n bitten: false,\n },\n {\n id: 2,\n name: 'Amaia',\n bitten: false,\n },\n {\n id: 3,\n name: 'Sara',\n bitten: false,\n },\n {\n id: 4,\n name: 'Ilya',\n bitten: true,\n },\n {\n id: 5,\n name: 'Ferran',\n bitten: false,\n },\n ],\n};\n\nclass StackMetadata extends Reactive {\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n state,\n mutations,\n});\n\n/**\n * Load the initial state.\n */\nexport const init = () => {\n //state.metadata = JSON.parse(metadata);\n};"],"names":["StackMetadata","Reactive","metadata","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","state","id","bitten","mutations"],"mappings":"wRAwDMA,sBAAsBC,0BAMfC,SAAW,IAAIF,cAAc,CACtCG,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,MAxCU,QACA,CACN,CACIC,GAAI,EACJP,KAAM,SACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,QACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,SACNQ,QAAQ,KAgBhBC,UAAAA,gEAMgB"} \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js b/amd/build/metadata/mutations.min.js new file mode 100644 index 00000000000..df36d6b1103 --- /dev/null +++ b/amd/build/metadata/mutations.min.js @@ -0,0 +1,12 @@ +define("qtype_stack/metadata/mutations",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.mutations=void 0;const mutations=new +/** + * Default mutation manager + * + * @module mod_nosferatu/local/beginner/mutations + * @class mod_nosferatu/local/beginner/mutations + * @copyright 2021 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class{bite(stateManager,personId){const state=stateManager.state;stateManager.setReadOnly(!1),state.people.get(personId).bitten=!0,stateManager.setReadOnly(!0)}cureAll(stateManager){const result=this._callCureAll(stateManager.state);stateManager.processUpdates(result)}_callCureAll(state){const result=[];return state.people.forEach((person=>{result.push({name:"people",action:"update",fields:{...person,bitten:!1}})})),result}};_exports.mutations=mutations})); + +//# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js.map b/amd/build/metadata/mutations.min.js.map new file mode 100644 index 00000000000..3c42e492b92 --- /dev/null +++ b/amd/build/metadata/mutations.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module mod_nosferatu/local/beginner/mutations\n * @class mod_nosferatu/local/beginner/mutations\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nclass Mutations {\n /**\n * Bite a person.\n *\n * All mutations recive a StateManager object as a first parameter. Whith this object the mutation\n * can acces the state (stateManager.state) but also set the read mode (statemanager.setReadOnly(true|false)).\n * In next steps we will see some other stateManager features. But for now you don't need them.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {Number} personId the person id to bite\n */\n bite(stateManager, personId) {\n // The first thing we need to do is get the current state.\n const state = stateManager.state;\n // State is always on read mode. To change any value first we need to unlock it.\n stateManager.setReadOnly(false);\n // Now we do as many state changes as we need.\n state.people.get(personId).bitten = true;\n // All mutations should restore the read mode. This will trigger all the reactive events.\n stateManager.setReadOnly(true);\n }\n\n /**\n * The cureAll mutation.\n *\n * @param {StateManager} stateManager the current state manager\n */\n cureAll(stateManager) {\n // We call our hipotetical webservice.\n const result = this._callCureAll(stateManager.state);\n // And now we send the results to the stateManager.\n stateManager.processUpdates(result);\n }\n /**\n * Ok. we don't have a webservice yet, so we fake it.\n *\n * @param {object} state if this was a real webservice we probably won't need the full state.\n * @returns {array} the state updates object.\n */\n _callCureAll(state) {\n const result = [];\n state.people.forEach(person => {\n result.push({\n name: 'people',\n action: 'update',\n fields: {\n ...person,\n bitten: false,\n }\n });\n });\n return result;\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","bite","stateManager","personId","state","setReadOnly","people","get","bitten","cureAll","result","this","_callCureAll","processUpdates","forEach","person","push","name","action","fields"],"mappings":"gKA8EaA,UAAY;;;;;;;;;MA5CrBC,KAAKC,aAAcC,gBAETC,MAAQF,aAAaE,MAE3BF,aAAaG,aAAY,GAEzBD,MAAME,OAAOC,IAAIJ,UAAUK,QAAS,EAEpCN,aAAaG,aAAY,GAQ7BI,QAAQP,oBAEEQ,OAASC,KAAKC,aAAaV,aAAaE,OAE9CF,aAAaW,eAAeH,QAQhCE,aAAaR,aACHM,OAAS,UACfN,MAAME,OAAOQ,SAAQC,SACjBL,OAAOM,KAAK,CACRC,KAAM,SACNC,OAAQ,SACRC,OAAQ,IACDJ,OACHP,QAAQ,QAIbE"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js new file mode 100644 index 00000000000..817e1bd2867 --- /dev/null +++ b/amd/src/metadata/container.js @@ -0,0 +1,88 @@ +// 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 . + +/** + * The beginner main app component. + * + * @module mod_nosferatu/local/beginner + * @class mod_nosferatu/local/beginner + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {BaseComponent} from 'core/reactive'; +import {metadata} from 'qtype_stack/metadata/metadata'; + +export default class extends BaseComponent { + + /** + * All the component definition should be initialized on the "create" method. + */ + create() { + // This is an optional name for the debugging messages. + this.name = 'stack-metadata-app-container'; + this.selectors = { + METADATACONTAINER: `[data-for='metadata-contrib']`, + }; + } + + /** + * Static method to create a component instance form the mustache template. + * + * @param {string} target the DOM main element or its ID + * @param {object} selectors optional css selector overrides + * @return {Component} + */ + static init(target, selectors) { + return new this({ + element: document.querySelector(target), + reactive: metadata, + selectors, + }); + } + + /** + * Initial state ready method. + * + * Note in this case we want our stateReady to be async. + * + * @param {object} state the initial state + */ + async stateReady(state) { + this._reloadCityComponent({state}); + } + + async _reloadCityComponent({state}) { + // Mustache data is not fully compatible with state object so we need to convert it + // into a plain object. In the intermediate level you will learng how to centralize this + // kind of operations to keep your components cleaner. + const data = { + people: [], + }; + state.people.forEach(person => { + data.people.push({...person}); + }); + data.haspeople = (data.people.length != 0); + + // To render a child component we need a container. + const citiyContainer = this.getElement(this.selectors.METADATACONTAINER); + if (!citiyContainer) { + throw new Error('Missing city container.'); + } + window.console.log(data); + // We store the new content into an attribute in case we want to remove it in the future. + this.cityComponent = await this.renderComponent(citiyContainer, 'qtype_stack/metadata/contributors', data); + } +} \ No newline at end of file diff --git a/amd/src/metadata/contributors.js b/amd/src/metadata/contributors.js new file mode 100644 index 00000000000..0491319b7d7 --- /dev/null +++ b/amd/src/metadata/contributors.js @@ -0,0 +1,53 @@ +// 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 . + +/** + * The beginner main app component. + * + * @module mod_nosferatu/local/beginner + * @class mod_nosferatu/local/beginner + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {BaseComponent} from 'core/reactive'; +import {metadata} from 'qtype_stack/metadata/metadata'; + +export default class extends BaseComponent { + + /** + * All the component definition should be initialized on the "create" method. + */ + create() { + // This is an optional name for the debugging messages. + this.name = 'stack-metadata-contrib'; + + } + + /** + * Static method to create a component instance form the mustache template. + * + * @param {string} target the DOM main element or its ID + * @param {object} selectors optional css selector overrides + * @return {Component} + */ + static init(target, selectors) { + return new this({ + element: document.querySelector(target), + reactive: metadata, + selectors, + }); + } +} \ No newline at end of file diff --git a/amd/src/metadata/events.js b/amd/src/metadata/events.js new file mode 100644 index 00000000000..2a9b3d82630 --- /dev/null +++ b/amd/src/metadata/events.js @@ -0,0 +1,56 @@ + +// 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 . + +import {dispatchEvent} from 'core/event_dispatcher'; + +/** + * Javascript events for the `mod_nosferatu` activity. + * + * @module mod_nosferatu/events + * @copyright 2021 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since 4.0 + */ + +/** + * Events for the `mod_nosferatu` activity. + * + * @constant + * @property {String} modNosferatuStateUpdated See {@link event:modNosferatuStateUpdated} + */ +export const eventTypes = { + /** + * Event triggered when the activity reactive state is updated. + * + * @event modNosferatuStateUpdated + * @type {CustomEvent} + * @property {Array} nodes The list of parent nodes which were updated + */ + qtypeStackStateUpdated: 'qtype_stack/stateUpdated', +}; + +/** + * Trigger an event to indicate that the activity state is updated. + * + * @method notifyModNosferatuStateUpdated + * @param {object} detail the full state + * @param {HTMLElement} container the custom event target (document if none provided) + * @returns {CustomEvent} + * @fires modNosferatuStateUpdated + */ +export const notifyQtypeStackStateUpdated = (detail, container) => { + return dispatchEvent(eventTypes.qtypeStackStateUpdated, detail, container); +}; \ No newline at end of file diff --git a/amd/src/metadata/exporter.js b/amd/src/metadata/exporter.js new file mode 100644 index 00000000000..d41e5b12b24 --- /dev/null +++ b/amd/src/metadata/exporter.js @@ -0,0 +1,40 @@ +// along with Moodle. If not, see . + +/** + * Module to export parts of the state and transform them to be used in templates + * and as draggable data. + * + * @module mod_nosferatu/local/intermediate/exporter + * @class mod_nosferatu/local/intermediate/exporter + * @copyright 2022 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +export default class { + + /** + * Class constructor. + * @param {Reactive} reactive the course editor object + */ + constructor(reactive) { + this.reactive = reactive; + } + + /** + * Generate the people export data from the state. + * + * @param {Object} state the current state. + * @returns {Object} + */ + metadata(state) { + // Collect section information from the state. + const data = { + // State stores maps of key-values instead of simple arrays. + people: [], + }; + state.people.forEach(person => { + data.people.push({...person}); + }); + data.haspeople = (data.people.length != 0); + return data; + } +} \ No newline at end of file diff --git a/amd/src/metadata/metadata.js b/amd/src/metadata/metadata.js new file mode 100644 index 00000000000..f93f57f2cc8 --- /dev/null +++ b/amd/src/metadata/metadata.js @@ -0,0 +1,76 @@ +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack 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. +// +// Stack 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 Stack. If not, see . + +/** + * Metadata entry reactive component + * + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {Reactive} from 'core/reactive'; +import {mutations} from 'qtype_stack/metadata/mutations'; +import {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events'; + +const state = { + 'people': [ + { + id: 1, + name: 'Carlos', + bitten: false, + }, + { + id: 2, + name: 'Amaia', + bitten: false, + }, + { + id: 3, + name: 'Sara', + bitten: false, + }, + { + id: 4, + name: 'Ilya', + bitten: true, + }, + { + id: 5, + name: 'Ferran', + bitten: false, + }, + ], +}; + +class StackMetadata extends Reactive { +} + +/** + * The metadata state instance. + */ +export const metadata = new StackMetadata({ + name: 'qtype_stack_metadata', + eventName: eventTypes.qtypeStackStateUpdated, + eventDispatch: notifyQtypeStackStateUpdated, + state, + mutations, +}); + +/** + * Load the initial state. + */ +export const init = () => { + //state.metadata = JSON.parse(metadata); +}; \ No newline at end of file diff --git a/amd/src/metadata/mutations.js b/amd/src/metadata/mutations.js new file mode 100644 index 00000000000..fecbcdda9e0 --- /dev/null +++ b/amd/src/metadata/mutations.js @@ -0,0 +1,79 @@ +// 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 . + +/** + * Default mutation manager + * + * @module mod_nosferatu/local/beginner/mutations + * @class mod_nosferatu/local/beginner/mutations + * @copyright 2021 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class Mutations { + /** + * Bite a person. + * + * All mutations recive a StateManager object as a first parameter. Whith this object the mutation + * can acces the state (stateManager.state) but also set the read mode (statemanager.setReadOnly(true|false)). + * In next steps we will see some other stateManager features. But for now you don't need them. + * + * @param {StateManager} stateManager the current state manager + * @param {Number} personId the person id to bite + */ + bite(stateManager, personId) { + // The first thing we need to do is get the current state. + const state = stateManager.state; + // State is always on read mode. To change any value first we need to unlock it. + stateManager.setReadOnly(false); + // Now we do as many state changes as we need. + state.people.get(personId).bitten = true; + // All mutations should restore the read mode. This will trigger all the reactive events. + stateManager.setReadOnly(true); + } + + /** + * The cureAll mutation. + * + * @param {StateManager} stateManager the current state manager + */ + cureAll(stateManager) { + // We call our hipotetical webservice. + const result = this._callCureAll(stateManager.state); + // And now we send the results to the stateManager. + stateManager.processUpdates(result); + } + /** + * Ok. we don't have a webservice yet, so we fake it. + * + * @param {object} state if this was a real webservice we probably won't need the full state. + * @returns {array} the state updates object. + */ + _callCureAll(state) { + const result = []; + state.people.forEach(person => { + result.push({ + name: 'people', + action: 'update', + fields: { + ...person, + bitten: false, + } + }); + }); + return result; + } +} + +export const mutations = new Mutations(); \ No newline at end of file diff --git a/classes/output/metadata.php b/classes/output/metadata.php new file mode 100644 index 00000000000..89350a46b30 --- /dev/null +++ b/classes/output/metadata.php @@ -0,0 +1,67 @@ +. + +/** + * Contains class mod_nosferatu\output\reportlink + * + * @package mod_nosferatu + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace qtype_stack\output; + +defined('MOODLE_INTERNAL') || die(); + +use qtype_stack\metadatamanager; +use renderable; +use templatable; +use renderer_base; +use stdClass; + +/** + * Class to help display report link in mod_nosferatu. + * + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class metadata implements renderable, templatable { + + + /** + * Constructor. + * + */ + public function __construct() { + global $PAGE; + + $PAGE->requires->js_call_amd('qtype_stack/metadata/metadata', 'init'); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * Initial data shown. + * + * @param renderer_base $output + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + + $data = ['haspeople' => true, 'people' => ['name' => 'bob']]; + + return $data; + } +} \ No newline at end of file diff --git a/edit_stack_form.php b/edit_stack_form.php index 54d786766bc..330f66a122b 100644 --- a/edit_stack_form.php +++ b/edit_stack_form.php @@ -255,7 +255,8 @@ protected function definition_inner(/* MoodleQuickForm */ $mform) { $warnings = ($warnings) ? $warnings . '
' : $warnings; $warnings .= '' . stack_string('usetextarea'); } - + $widget = new qtype_stack\output\metadata(); + echo $OUTPUT->render($widget); // Note that for the editor elements, we are using $mform->getElement('prtincorrect')->setValue(...); instead // of setDefault, because setDefault does not work for editors. @@ -298,8 +299,8 @@ protected function definition_inner(/* MoodleQuickForm */ $mform) { if ($courseid = optional_param('courseid', 0, PARAM_INT)) { $liburlparams['courseid'] = $courseid; } - if ($cmid = optional_param('returnurl', null, PARAM_LOCALURL)) { - $liburlparams['returnurl'] = $cmid; + if ($returnurl = optional_param('returnurl', null, PARAM_LOCALURL)) { + $liburlparams['returnurl'] = $returnurl; } $qlibrarylink = html_writer::link(new moodle_url('/question/type/stack/questionlibrary.php', $liburlparams), $out, []) . ' ' . $OUTPUT->help_icon('stack_library', 'qtype_stack'); diff --git a/templates/metadata.mustache b/templates/metadata.mustache new file mode 100644 index 00000000000..60ff868df53 --- /dev/null +++ b/templates/metadata.mustache @@ -0,0 +1,32 @@ +{{! + This file is part of Stack - http://stack.maths.ed.ac.uk/ + 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 . +}} +{{! + @template mod_nosferatu/local/beginner/city + + This component renders all people in the city. + + Example context (json): + { + } +}} +
+
+ {{> qtype_stack/metadata/contributors}} +
+
+{{#js}} +require(['qtype_stack/metadata/container'], function(component) { + component.init('#qtype-stack-metadata-main'); +}); +{{/js}} \ No newline at end of file diff --git a/templates/metadata/contributors.mustache b/templates/metadata/contributors.mustache new file mode 100644 index 00000000000..19a42134ff1 --- /dev/null +++ b/templates/metadata/contributors.mustache @@ -0,0 +1,45 @@ +{{! + This file is part of Stack - http://stack.maths.ed.ac.uk/ + 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 . +}} +{{! + @template mod_nosferatu/local/beginner/city + + This component renders all people in the city. + + Example context (json): + { + } +}} +
+ {{^haspeople}} +
+ No contributors. +
+ {{/haspeople}} + {{#haspeople}} +
    + {{#people}} +
  • +

    + {{name}} +

    +
  • + {{/people}} +
+ {{/haspeople}} +
+{{#js}} +require(['qtype_stack/metadata/contributors'], function(component) { + component.init('#qtype-stack-metadata-contributors-{{uniqid}}'); +}); +{{/js}} \ No newline at end of file From a34f275406306cc57e21a6b4d9cb5043d821d3b6 Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Wed, 24 Sep 2025 12:51:44 +0100 Subject: [PATCH 02/66] iss1171 - modal --- amd/build/metadata/metadata.min.js.map | 2 +- amd/build/metadata/metadatalaunch.min.js | 3 + amd/build/metadata/metadatalaunch.min.js.map | 1 + amd/build/metadata/metadatamodal.min.js | 3 + amd/build/metadata/metadatamodal.min.js.map | 1 + amd/build/metadatalaunch.min.js | 3 + amd/build/metadatalaunch.min.js.map | 1 + amd/src/metadata/metadata.js | 3 +- amd/src/metadata/metadatalaunch.js | 18 ++++++ amd/src/metadata/metadatamodal.js | 13 ++++ classes/output/metadatamodal.php | 67 ++++++++++++++++++++ edit_stack_form.php | 7 +- lang/en/qtype_stack.php | 1 + stackmetadatamodal.php | 0 templates/metadata.mustache | 2 +- templates/metadata/contributors.mustache | 4 +- templates/metadatamodal.mustache | 40 ++++++++++++ 17 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 amd/build/metadata/metadatalaunch.min.js create mode 100644 amd/build/metadata/metadatalaunch.min.js.map create mode 100644 amd/build/metadata/metadatamodal.min.js create mode 100644 amd/build/metadata/metadatamodal.min.js.map create mode 100644 amd/build/metadatalaunch.min.js create mode 100644 amd/build/metadatalaunch.min.js.map create mode 100644 amd/src/metadata/metadatalaunch.js create mode 100644 amd/src/metadata/metadatamodal.js create mode 100644 classes/output/metadatamodal.php create mode 100644 stackmetadatamodal.php create mode 100644 templates/metadatamodal.mustache diff --git a/amd/build/metadata/metadata.min.js.map b/amd/build/metadata/metadata.min.js.map index e87322e0389..c1bbd5af8cc 100644 --- a/amd/build/metadata/metadata.min.js.map +++ b/amd/build/metadata/metadata.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nconst state = {\n 'people': [\n {\n id: 1,\n name: 'Carlos',\n bitten: false,\n },\n {\n id: 2,\n name: 'Amaia',\n bitten: false,\n },\n {\n id: 3,\n name: 'Sara',\n bitten: false,\n },\n {\n id: 4,\n name: 'Ilya',\n bitten: true,\n },\n {\n id: 5,\n name: 'Ferran',\n bitten: false,\n },\n ],\n};\n\nclass StackMetadata extends Reactive {\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n state,\n mutations,\n});\n\n/**\n * Load the initial state.\n */\nexport const init = () => {\n //state.metadata = JSON.parse(metadata);\n};"],"names":["StackMetadata","Reactive","metadata","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","state","id","bitten","mutations"],"mappings":"wRAwDMA,sBAAsBC,0BAMfC,SAAW,IAAIF,cAAc,CACtCG,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,MAxCU,QACA,CACN,CACIC,GAAI,EACJP,KAAM,SACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,QACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,SACNQ,QAAQ,KAgBhBC,UAAAA,gEAMgB"} \ No newline at end of file +{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nconst state = {\n 'people': [\n {\n id: 1,\n name: 'Carlos',\n bitten: false,\n },\n {\n id: 2,\n name: 'Amaia',\n bitten: false,\n },\n {\n id: 3,\n name: 'Sara',\n bitten: false,\n },\n {\n id: 4,\n name: 'Ilya',\n bitten: true,\n },\n {\n id: 5,\n name: 'Ferran',\n bitten: false,\n },\n ],\n};\n\nclass StackMetadata extends Reactive {\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n state,\n mutations,\n});\n\n/**\n * Load the initial state.\n */\nexport const init = () => {\n //state.metadata = JSON.parse(metadata);\n};\n\n"],"names":["StackMetadata","Reactive","metadata","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","state","id","bitten","mutations"],"mappings":"wRAwDMA,sBAAsBC,0BAMfC,SAAW,IAAIF,cAAc,CACtCG,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,MAxCU,QACA,CACN,CACIC,GAAI,EACJP,KAAM,SACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,QACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,SACNQ,QAAQ,KAgBhBC,UAAAA,gEAMgB"} \ No newline at end of file diff --git a/amd/build/metadata/metadatalaunch.min.js b/amd/build/metadata/metadatalaunch.min.js new file mode 100644 index 00000000000..96350ce73c0 --- /dev/null +++ b/amd/build/metadata/metadatalaunch.min.js @@ -0,0 +1,3 @@ +define("qtype_stack/metadata/metadatalaunch",["exports","core/modal_factory","./metadatamodal"],(function(_exports,_modal_factory,_metadatamodal){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_metadatamodal=_interopRequireDefault(_metadatamodal);async function openModal(){(await _modal_factory.default.create({type:_metadatamodal.default.TYPE})).show()}_exports.setup=()=>{var _document$querySelect;null===(_document$querySelect=document.querySelector("#id_metadatamodal"))||void 0===_document$querySelect||_document$querySelect.addEventListener("click",openModal)}})); + +//# sourceMappingURL=metadatalaunch.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatalaunch.min.js.map b/amd/build/metadata/metadatalaunch.min.js.map new file mode 100644 index 00000000000..86b64c22fe8 --- /dev/null +++ b/amd/build/metadata/metadatalaunch.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"metadatalaunch.min.js","sources":["../../src/metadata/metadatalaunch.js"],"sourcesContent":["import ModalFactory from 'core/modal_factory';\nimport MetadataModal from './metadatamodal';\n\nexport const setup = () => {\n document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal);\n};\n\n/**\n * Open the metadata modal.\n */\nasync function openModal() {\n // ...\n const modal = await ModalFactory.create({\n type: MetadataModal.TYPE,\n });\n\n modal.show();\n}"],"names":["openModal","ModalFactory","create","type","MetadataModal","TYPE","show","document","querySelector","addEventListener"],"mappings":"6aAUeA,mBAESC,uBAAaC,OAAO,CACpCC,KAAMC,uBAAcC,QAGlBC,sBAbW,6DAClBC,SAASC,cAAc,6EAAsBC,iBAAiB,QAAST"} \ No newline at end of file diff --git a/amd/build/metadata/metadatamodal.min.js b/amd/build/metadata/metadatamodal.min.js new file mode 100644 index 00000000000..fd3839a61f6 --- /dev/null +++ b/amd/build/metadata/metadatamodal.min.js @@ -0,0 +1,3 @@ +define("qtype_stack/metadata/metadatamodal",["exports","core/modal","core/modal_registry"],(function(_exports,_modal,_modal_registry){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry);class MetadataModal extends _modal.default{}_exports.default=MetadataModal,_defineProperty(MetadataModal,"TYPE","qtype_stack/metadatamodal"),_defineProperty(MetadataModal,"TEMPLATE","qtype_stack/metadatamodal");let registered=!1;return registered||(_modal_registry.default.register(MetadataModal.TYPE,MetadataModal,MetadataModal.TEMPLATE),registered=!0),_exports.default})); + +//# sourceMappingURL=metadatamodal.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatamodal.min.js.map b/amd/build/metadata/metadatamodal.min.js.map new file mode 100644 index 00000000000..b93ae74d8ea --- /dev/null +++ b/amd/build/metadata/metadatamodal.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"metadatamodal.min.js","sources":["../../src/metadata/metadatamodal.js"],"sourcesContent":["import Modal from 'core/modal';\nimport ModalRegistry from 'core/modal_registry';\n\nexport default class MetadataModal extends Modal {\n static TYPE = \"qtype_stack/metadatamodal\";\n static TEMPLATE = \"qtype_stack/metadatamodal\";\n}\n\nlet registered = false;\nif (!registered) {\n ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE);\n registered = true;\n}"],"names":["MetadataModal","Modal","registered","register","TYPE","TEMPLATE"],"mappings":"gjBAGqBA,sBAAsBC,+DAAtBD,qBACH,6CADGA,yBAEC,iCAGlBE,YAAa,SACZA,qCACaC,SAASH,cAAcI,KAAMJ,cAAeA,cAAcK,UACxEH,YAAa"} \ No newline at end of file diff --git a/amd/build/metadatalaunch.min.js b/amd/build/metadatalaunch.min.js new file mode 100644 index 00000000000..7075a6e851c --- /dev/null +++ b/amd/build/metadatalaunch.min.js @@ -0,0 +1,3 @@ +define("qtype_stack/metadatalaunch",["exports","core/modal_factory","mod_example/my_modal"],(function(_exports,_modal_factory,_my_modal){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_my_modal=_interopRequireDefault(_my_modal);async function openModal(){(await _modal_factory.default.create({type:_my_modal.default.TYPE})).show()}_exports.setup=()=>{var _document$querySelect;null===(_document$querySelect=document.querySelector("#id_metadatamodal"))||void 0===_document$querySelect||_document$querySelect.addEventListener("click",openModal)}})); + +//# sourceMappingURL=metadatalaunch.min.js.map \ No newline at end of file diff --git a/amd/build/metadatalaunch.min.js.map b/amd/build/metadatalaunch.min.js.map new file mode 100644 index 00000000000..6d832e112de --- /dev/null +++ b/amd/build/metadatalaunch.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"metadatalaunch.min.js","sources":["../src/metadatalaunch.js"],"sourcesContent":["import ModalFactory from 'core/modal_factory';\nimport MyModal from 'mod_example/my_modal';\n\nexport const setup = () => {\n document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal);\n};\n\n/**\n * Open the metadata modal.\n */\nasync function openModal() {\n // ...\n const modal = await ModalFactory.create({\n type: MyModal.TYPE,\n });\n\n modal.show();\n}"],"names":["openModal","ModalFactory","create","type","MyModal","TYPE","show","document","querySelector","addEventListener"],"mappings":"0ZAUeA,mBAESC,uBAAaC,OAAO,CACpCC,KAAMC,kBAAQC,QAGZC,sBAbW,6DAClBC,SAASC,cAAc,6EAAsBC,iBAAiB,QAAST"} \ No newline at end of file diff --git a/amd/src/metadata/metadata.js b/amd/src/metadata/metadata.js index f93f57f2cc8..91febe1c741 100644 --- a/amd/src/metadata/metadata.js +++ b/amd/src/metadata/metadata.js @@ -73,4 +73,5 @@ export const metadata = new StackMetadata({ */ export const init = () => { //state.metadata = JSON.parse(metadata); -}; \ No newline at end of file +}; + diff --git a/amd/src/metadata/metadatalaunch.js b/amd/src/metadata/metadatalaunch.js new file mode 100644 index 00000000000..d7a64948326 --- /dev/null +++ b/amd/src/metadata/metadatalaunch.js @@ -0,0 +1,18 @@ +import ModalFactory from 'core/modal_factory'; +import MetadataModal from './metadatamodal'; + +export const setup = () => { + document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal); +}; + +/** + * Open the metadata modal. + */ +async function openModal() { + // ... + const modal = await ModalFactory.create({ + type: MetadataModal.TYPE, + }); + + modal.show(); +} \ No newline at end of file diff --git a/amd/src/metadata/metadatamodal.js b/amd/src/metadata/metadatamodal.js new file mode 100644 index 00000000000..1943c7bec72 --- /dev/null +++ b/amd/src/metadata/metadatamodal.js @@ -0,0 +1,13 @@ +import Modal from 'core/modal'; +import ModalRegistry from 'core/modal_registry'; + +export default class MetadataModal extends Modal { + static TYPE = "qtype_stack/metadatamodal"; + static TEMPLATE = "qtype_stack/metadatamodal"; +} + +let registered = false; +if (!registered) { + ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE); + registered = true; +} \ No newline at end of file diff --git a/classes/output/metadatamodal.php b/classes/output/metadatamodal.php new file mode 100644 index 00000000000..5e1ce78ec99 --- /dev/null +++ b/classes/output/metadatamodal.php @@ -0,0 +1,67 @@ +. + +/** + * Contains class mod_nosferatu\output\reportlink + * + * @package mod_nosferatu + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace qtype_stack\output; + +defined('MOODLE_INTERNAL') || die(); + +use qtype_stack\metadatamanager; +use renderable; +use templatable; +use renderer_base; +use stdClass; + +/** + * Class to help display report link in mod_nosferatu. + * + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class metadatamodal implements renderable, templatable { + + + /** + * Constructor. + * + */ + public function __construct() { + global $PAGE; + + $PAGE->requires->js_call_amd('qtype_stack/metadata/metadatamodal', 'init'); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * Initial data shown. + * + * @param renderer_base $output + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + + $data = ['haspeople' => true, 'people' => ['name' => 'bob']]; + + return $data; + } +} \ No newline at end of file diff --git a/edit_stack_form.php b/edit_stack_form.php index 330f66a122b..1babbe0f257 100644 --- a/edit_stack_form.php +++ b/edit_stack_form.php @@ -209,7 +209,7 @@ protected function definition() { // phpcs:ignore moodle.Commenting.MissingDocblock.Function protected function definition_inner(/* MoodleQuickForm */ $mform) { - global $OUTPUT; + global $OUTPUT, $PAGE; // Load the configuration. $this->stackconfig = stack_utils::get_config(); @@ -255,8 +255,9 @@ protected function definition_inner(/* MoodleQuickForm */ $mform) { $warnings = ($warnings) ? $warnings . '
' : $warnings; $warnings .= '' . stack_string('usetextarea'); } - $widget = new qtype_stack\output\metadata(); - echo $OUTPUT->render($widget); + $PAGE->requires->js_call_amd('qtype_stack/metadata/metadatalaunch', 'setup'); + $mform->addElement('button', 'metadatamodal', stack_string("editmetadata")); + // Note that for the editor elements, we are using $mform->getElement('prtincorrect')->setValue(...); instead // of setDefault, because setDefault does not work for editors. diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php index 954a11579e3..8d2aff06d2e 100644 --- a/lang/en/qtype_stack.php +++ b/lang/en/qtype_stack.php @@ -409,6 +409,7 @@ $string['mustconfirm'] = 'You have changes to confirm.'; $string['moodleerrors'] = 'You have errors related to Moodle\'s basic question setup.'; $string['stackerrors'] = 'You have errors in your question.'; +$string['editmetadata'] = 'Edit metadata'; // Strings used by input elements. $string['studentinputtoolong'] = 'Your input is longer than permitted by STACK.'; diff --git a/stackmetadatamodal.php b/stackmetadatamodal.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/templates/metadata.mustache b/templates/metadata.mustache index 60ff868df53..2cc381b1b2d 100644 --- a/templates/metadata.mustache +++ b/templates/metadata.mustache @@ -22,7 +22,7 @@ }}
- {{> qtype_stack/metadata/contributors}} +
{{#js}} diff --git a/templates/metadata/contributors.mustache b/templates/metadata/contributors.mustache index 19a42134ff1..aa3b5d8cef4 100644 --- a/templates/metadata/contributors.mustache +++ b/templates/metadata/contributors.mustache @@ -20,7 +20,7 @@ { } }} -
+
{{^haspeople}}
No contributors. @@ -40,6 +40,6 @@
{{#js}} require(['qtype_stack/metadata/contributors'], function(component) { - component.init('#qtype-stack-metadata-contributors-{{uniqid}}'); + component.init('#qtype-stack-metadata-contributors-main'); }); {{/js}} \ No newline at end of file diff --git a/templates/metadatamodal.mustache b/templates/metadatamodal.mustache new file mode 100644 index 00000000000..e49da4fade0 --- /dev/null +++ b/templates/metadatamodal.mustache @@ -0,0 +1,40 @@ +{{! + 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 . +}} +{{! + @template core/modal_copytoclipboard + + This template renders a modal. The body contains a readonly input text field. + The Footer contains a button "Copy to clipboard" that copies the content + of the text field into the clipboard. + The purpose of the dialog element is to copy a permalink of a section into + the clipboard. Thus, the header of the modal dialog contains the label "Permalink". + + Example context (json): + { + "text": "content for the input field that is being copied to the clipboard" + } +}} +{{< core/modal }} + {{$title}}{{#str}} login {{/str}}{{/title}} + {{$body}} +
+ {{> qtype_stack/metadata}} +
+ {{/body}} + {{$footer}} + {{/footer}} +{{/ core/modal }} \ No newline at end of file From 575863248d4a06983cafaae26695984d6a1b7916 Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Thu, 6 Nov 2025 11:59:07 +0000 Subject: [PATCH 03/66] iss1171 - Working basic display --- amd/build/metadata/container.min.js | 8 +-- amd/build/metadata/container.min.js.map | 2 +- amd/build/metadata/contributors.min.js.map | 2 +- amd/build/metadata/events.min.js.map | 2 +- amd/build/metadata/metadata.min.js | 9 ++- amd/build/metadata/metadata.min.js.map | 2 +- amd/build/metadata/metadatamodal.min.js | 2 +- amd/build/metadata/metadatamodal.min.js.map | 2 +- amd/src/metadata/container.js | 56 ++++++++--------- amd/src/metadata/contributors.js | 53 ---------------- amd/src/metadata/events.js | 9 ++- amd/src/metadata/exporter.js | 40 ------------ amd/src/metadata/metadata.js | 42 ++----------- amd/src/metadata/metadatalaunch.js | 18 ------ amd/src/metadata/metadatamodal.js | 36 ++++++++++- amd/src/metadata/sample.json | 24 ++++++++ classes/output/metadata.php | 67 --------------------- classes/output/metadatamodal.php | 1 - edit_stack_form.php | 7 ++- stackmetadatamodal.php | 0 templates/metadata.mustache | 22 +++---- templates/metadata/contributors.mustache | 45 -------------- templates/metadatamodal.mustache | 13 +++- 23 files changed, 135 insertions(+), 327 deletions(-) delete mode 100644 amd/src/metadata/contributors.js delete mode 100644 amd/src/metadata/exporter.js delete mode 100644 amd/src/metadata/metadatalaunch.js create mode 100644 amd/src/metadata/sample.json delete mode 100644 classes/output/metadata.php delete mode 100644 stackmetadatamodal.php delete mode 100644 templates/metadata/contributors.mustache diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js index 1b33b5152df..39d0514cadc 100644 --- a/amd/build/metadata/container.min.js +++ b/amd/build/metadata/container.min.js @@ -1,12 +1,10 @@ define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/metadata/metadata"],(function(_exports,_reactive,_metadata){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; /** - * The beginner main app component. + * Main STACK metadata component * - * @module mod_nosferatu/local/beginner - * @class mod_nosferatu/local/beginner - * @copyright 2020 Ferran Recio + * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-app-container",this.selectors={METADATACONTAINER:"[data-for='metadata-contrib']"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){this._reloadCityComponent({state:state})}async _reloadCityComponent(_ref){let{state:state}=_ref;const data={people:[]};state.people.forEach((person=>{data.people.push({...person})})),data.haspeople=0!=data.people.length;const citiyContainer=this.getElement(this.selectors.METADATACONTAINER);if(!citiyContainer)throw new Error("Missing city container.");window.console.log(data),this.cityComponent=await this.renderComponent(citiyContainer,"qtype_stack/metadata/contributors",data)}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}stateReady(state){this.reloadContainerComponent({state:state})}reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:"",isPartOf:"",additional:[]};state.contributor.forEach((contributor=>{data.contributor.push({...contributor})}));const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");this.renderComponent(metadataContainer,"qtype_stack/metadata",data)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map index f03e4e554ec..e6ea2ecd476 100644 --- a/amd/build/metadata/container.min.js.map +++ b/amd/build/metadata/container.min.js.map @@ -1 +1 @@ -{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.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 * The beginner main app component.\n *\n * @module mod_nosferatu/local/beginner\n * @class mod_nosferatu/local/beginner\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n\n /**\n * All the component definition should be initialized on the \"create\" method.\n */\n create() {\n // This is an optional name for the debugging messages.\n this.name = 'stack-metadata-app-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='metadata-contrib']`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * Note in this case we want our stateReady to be async.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n this._reloadCityComponent({state});\n }\n\n async _reloadCityComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object. In the intermediate level you will learng how to centralize this\n // kind of operations to keep your components cleaner.\n const data = {\n people: [],\n };\n state.people.forEach(person => {\n data.people.push({...person});\n });\n data.haspeople = (data.people.length != 0);\n\n // To render a child component we need a container.\n const citiyContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!citiyContainer) {\n throw new Error('Missing city container.');\n }\n window.console.log(data);\n // We store the new content into an attribute in case we want to remove it in the future.\n this.cityComponent = await this.renderComponent(citiyContainer, 'qtype_stack/metadata/contributors', data);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","target","this","element","document","querySelector","reactive","metadata","state","_reloadCityComponent","data","people","forEach","person","push","haspeople","length","citiyContainer","getElement","Error","window","console","log","cityComponent","renderComponent"],"mappings":";;;;;;;;;uBA2B6BA,wBAKzBC,cAESC,KAAO,oCACPC,UAAY,CACbC,+DAWIC,OAAQF,kBACT,IAAIG,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVR,UAAAA,6BAWSS,YACRC,qBAAqB,CAACD,MAAAA,6CAGJA,MAACA,kBAIlBE,KAAO,CACTC,OAAQ,IAEZH,MAAMG,OAAOC,SAAQC,SACjBH,KAAKC,OAAOG,KAAK,IAAID,YAEzBH,KAAKK,UAAmC,GAAtBL,KAAKC,OAAOK,aAGxBC,eAAiBf,KAAKgB,WAAWhB,KAAKH,UAAUC,uBACjDiB,qBACK,IAAIE,MAAM,2BAEpBC,OAAOC,QAAQC,IAAIZ,WAEda,oBAAsBrB,KAAKsB,gBAAgBP,eAAgB,oCAAqCP"} \ No newline at end of file +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n stateReady(state) {\n this.reloadContainerComponent({state});\n }\n\n reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: '',\n isPartOf: '',\n additional: []\n };\n state.contributor.forEach(contributor => {\n data.contributor.push({...contributor});\n });\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n this.renderComponent(metadataContainer, 'qtype_stack/metadata', data);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","target","this","element","document","querySelector","reactive","metadata","stateReady","state","reloadContainerComponent","data","creator","contributor","language","license","isPartOf","additional","forEach","push","metadataContainer","getElement","Error","renderComponent"],"mappings":";;;;;;;uBAyB6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,mEAWIC,OAAQF,kBACT,IAAIG,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVR,UAAAA,YASRS,WAAWC,YACFC,yBAAyB,CAACD,MAAAA,QAGnCC,mCAAyBD,MAACA,kBAGhBE,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAAS,GACTC,SAAU,GACVC,WAAY,IAEhBR,MAAMI,YAAYK,SAAQL,cACtBF,KAAKE,YAAYM,KAAK,IAAIN,uBAIxBO,kBAAoBlB,KAAKmB,WAAWnB,KAAKH,UAAUC,uBACpDoB,wBACK,IAAIE,MAAM,oCAEfC,gBAAgBH,kBAAmB,uBAAwBT"} \ No newline at end of file diff --git a/amd/build/metadata/contributors.min.js.map b/amd/build/metadata/contributors.min.js.map index 894ceb5f75e..f77da20d7bc 100644 --- a/amd/build/metadata/contributors.min.js.map +++ b/amd/build/metadata/contributors.min.js.map @@ -1 +1 @@ -{"version":3,"file":"contributors.min.js","sources":["../../src/metadata/contributors.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 * The beginner main app component.\n *\n * @module mod_nosferatu/local/beginner\n * @class mod_nosferatu/local/beginner\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n\n /**\n * All the component definition should be initialized on the \"create\" method.\n */\n create() {\n // This is an optional name for the debugging messages.\n this.name = 'stack-metadata-contrib';\n\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n}"],"names":["BaseComponent","create","name","target","selectors","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;;uBA2B6BA,wBAKzBC,cAESC,KAAO,qCAWJC,OAAQC,kBACT,IAAIC,KAAK,CACZC,QAASC,SAASC,cAAcL,QAChCM,SAAUC,mBACVN,UAAAA"} \ No newline at end of file +{"version":3,"file":"contributors.min.js","sources":["../../src/metadata/contributors.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 * The beginner main app component.\n *\n * @module mod_nosferatu/local/beginner\n * @class mod_nosferatu/local/beginner\n * @copyright 2020 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n\n /**\n * All the component definition should be initialized on the \"create\" method.\n */\n create() {\n // This is an optional name for the debugging messages.\n this.name = 'stack-metadata-contrib';\n\n }\n\n /**\n * Static method to create a component instance from the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n}"],"names":["BaseComponent","create","name","target","selectors","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;;uBA2B6BA,wBAKzBC,cAESC,KAAO,qCAWJC,OAAQC,kBACT,IAAIC,KAAK,CACZC,QAASC,SAASC,cAAcL,QAChCM,SAAUC,mBACVN,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/events.min.js.map b/amd/build/metadata/events.min.js.map index 89e91e6c631..0b1d94739af 100644 --- a/amd/build/metadata/events.min.js.map +++ b/amd/build/metadata/events.min.js.map @@ -1 +1 @@ -{"version":3,"file":"events.min.js","sources":["../../src/metadata/events.js"],"sourcesContent":["\n// 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\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Javascript events for the `mod_nosferatu` activity.\n *\n * @module mod_nosferatu/events\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\n/**\n * Events for the `mod_nosferatu` activity.\n *\n * @constant\n * @property {String} modNosferatuStateUpdated See {@link event:modNosferatuStateUpdated}\n */\nexport const eventTypes = {\n /**\n * Event triggered when the activity reactive state is updated.\n *\n * @event modNosferatuStateUpdated\n * @type {CustomEvent}\n * @property {Array} nodes The list of parent nodes which were updated\n */\n qtypeStackStateUpdated: 'qtype_stack/stateUpdated',\n};\n\n/**\n * Trigger an event to indicate that the activity state is updated.\n *\n * @method notifyModNosferatuStateUpdated\n * @param {object} detail the full state\n * @param {HTMLElement} container the custom event target (document if none provided)\n * @returns {CustomEvent}\n * @fires modNosferatuStateUpdated\n */\nexport const notifyQtypeStackStateUpdated = (detail, container) => {\n return dispatchEvent(eventTypes.qtypeStackStateUpdated, detail, container);\n};"],"names":["eventTypes","qtypeStackStateUpdated","detail","container"],"mappings":";;;;;;;;;MAiCaA,WAAa,CAQtBC,uBAAwB,iGAYgB,CAACC,OAAQC,aAC1C,mCAAcH,WAAWC,uBAAwBC,OAAQC"} \ No newline at end of file +{"version":3,"file":"events.min.js","sources":["../../src/metadata/events.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Javascript events for the `mod_nosferatu` activity.\n *\n * @module mod_nosferatu/events\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\n/**\n * Events for the `mod_nosferatu` activity.\n *\n * @constant\n * @property {String} modNosferatuStateUpdated See {@link event:modNosferatuStateUpdated}\n */\nexport const eventTypes = {\n /**\n * Event triggered when the activity reactive state is updated.\n *\n * @event modNosferatuStateUpdated\n * @type {CustomEvent}\n * @property {Array} nodes The list of parent nodes which were updated\n */\n qtypeStackStateUpdated: 'qtype_stack/stateUpdated',\n};\n\n/**\n * Trigger an event to indicate that the activity state is updated.\n *\n * @method notifyModNosferatuStateUpdated\n * @param {object} detail the full state\n * @param {HTMLElement} container the custom event target (document if none provided)\n * @returns {CustomEvent}\n * @fires modNosferatuStateUpdated\n */\nexport const notifyQtypeStackStateUpdated = (detail, container) => {\n return dispatchEvent(eventTypes.qtypeStackStateUpdated, detail, container);\n};"],"names":["eventTypes","qtypeStackStateUpdated","detail","container"],"mappings":";;;;;;;;;MAgCaA,WAAa,CAQtBC,uBAAwB,iGAYgB,CAACC,OAAQC,aAC1C,mCAAcH,WAAWC,uBAAwBC,OAAQC"} \ No newline at end of file diff --git a/amd/build/metadata/metadata.min.js b/amd/build/metadata/metadata.min.js index 2db6fb5c501..d6c68e19e37 100644 --- a/amd/build/metadata/metadata.min.js +++ b/amd/build/metadata/metadata.min.js @@ -1,3 +1,10 @@ -define("qtype_stack/metadata/metadata",["exports","core/reactive","qtype_stack/metadata/mutations","qtype_stack/metadata/events"],(function(_exports,_reactive,_mutations,_events){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.metadata=_exports.init=void 0;class StackMetadata extends _reactive.Reactive{}const metadata=new StackMetadata({name:"qtype_stack_metadata",eventName:_events.eventTypes.qtypeStackStateUpdated,eventDispatch:_events.notifyQtypeStackStateUpdated,state:{people:[{id:1,name:"Carlos",bitten:!1},{id:2,name:"Amaia",bitten:!1},{id:3,name:"Sara",bitten:!1},{id:4,name:"Ilya",bitten:!0},{id:5,name:"Ferran",bitten:!1}]},mutations:_mutations.mutations});_exports.metadata=metadata;_exports.init=()=>{}})); +define("qtype_stack/metadata/metadata",["exports","core/reactive","qtype_stack/metadata/mutations","qtype_stack/metadata/events"],(function(_exports,_reactive,_mutations,_events){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.metadata=void 0; +/** + * Metadata entry reactive component + * + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class StackMetadata extends _reactive.Reactive{loadState(){var _metadata;let metadata=document.querySelector('input[name="metadata"]');metadata=JSON.parse(null===(_metadata=metadata)||void 0===_metadata?void 0:_metadata.value),this.setInitialState(metadata)}}const metadata=new StackMetadata({name:"qtype_stack_metadata",eventName:_events.eventTypes.qtypeStackStateUpdated,eventDispatch:_events.notifyQtypeStackStateUpdated,mutations:_mutations.mutations});_exports.metadata=metadata})); //# sourceMappingURL=metadata.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadata.min.js.map b/amd/build/metadata/metadata.min.js.map index c1bbd5af8cc..a8dcf5b5bf7 100644 --- a/amd/build/metadata/metadata.min.js.map +++ b/amd/build/metadata/metadata.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nconst state = {\n 'people': [\n {\n id: 1,\n name: 'Carlos',\n bitten: false,\n },\n {\n id: 2,\n name: 'Amaia',\n bitten: false,\n },\n {\n id: 3,\n name: 'Sara',\n bitten: false,\n },\n {\n id: 4,\n name: 'Ilya',\n bitten: true,\n },\n {\n id: 5,\n name: 'Ferran',\n bitten: false,\n },\n ],\n};\n\nclass StackMetadata extends Reactive {\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n state,\n mutations,\n});\n\n/**\n * Load the initial state.\n */\nexport const init = () => {\n //state.metadata = JSON.parse(metadata);\n};\n\n"],"names":["StackMetadata","Reactive","metadata","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","state","id","bitten","mutations"],"mappings":"wRAwDMA,sBAAsBC,0BAMfC,SAAW,IAAIF,cAAc,CACtCG,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,MAxCU,QACA,CACN,CACIC,GAAI,EACJP,KAAM,SACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,QACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,OACNQ,QAAQ,GAEZ,CACID,GAAI,EACJP,KAAM,SACNQ,QAAQ,KAgBhBC,UAAAA,gEAMgB"} \ No newline at end of file +{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nclass StackMetadata extends Reactive {\n loadState() {\n let metadata = document.querySelector('input[name=\"metadata\"]');\n metadata = JSON.parse(metadata?.value);\n this.setInitialState(metadata);\n }\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n mutations,\n});\n\n\n"],"names":["StackMetadata","Reactive","loadState","metadata","document","querySelector","JSON","parse","_metadata","value","setInitialState","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","mutations"],"mappings":";;;;;;;MA0BMA,sBAAsBC,mBACxBC,8BACQC,SAAWC,SAASC,cAAc,0BACtCF,SAAWG,KAAKC,wBAAMJ,qCAAAK,UAAUC,YAC3BC,gBAAgBP,iBAOhBA,SAAW,IAAIH,cAAc,CACtCW,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/metadatamodal.min.js b/amd/build/metadata/metadatamodal.min.js index fd3839a61f6..dcc18e63f67 100644 --- a/amd/build/metadata/metadatamodal.min.js +++ b/amd/build/metadata/metadatamodal.min.js @@ -1,3 +1,3 @@ -define("qtype_stack/metadata/metadatamodal",["exports","core/modal","core/modal_registry"],(function(_exports,_modal,_modal_registry){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry);class MetadataModal extends _modal.default{}_exports.default=MetadataModal,_defineProperty(MetadataModal,"TYPE","qtype_stack/metadatamodal"),_defineProperty(MetadataModal,"TEMPLATE","qtype_stack/metadatamodal");let registered=!1;return registered||(_modal_registry.default.register(MetadataModal.TYPE,MetadataModal,MetadataModal.TEMPLATE),registered=!0),_exports.default})); +define("qtype_stack/metadata/metadatamodal",["exports","core/modal","core/modal_registry","core/modal_factory","qtype_stack/metadata/metadata"],(function(_exports,_modal,_modal_registry,_modal_factory,_metadata){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=_exports.MetadataModal=void 0,_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry),_modal_factory=_interopRequireDefault(_modal_factory);class MetadataModal extends _modal.default{}_exports.MetadataModal=MetadataModal,_defineProperty(MetadataModal,"TYPE","qtype_stack/metadatamodal"),_defineProperty(MetadataModal,"TEMPLATE","qtype_stack/metadatamodal");let registered=!1;registered||(_modal_registry.default.register(MetadataModal.TYPE,MetadataModal,MetadataModal.TEMPLATE),registered=!0);async function openModal(){(await _modal_factory.default.create({type:MetadataModal.TYPE})).show()}_exports.setup=()=>{var _document$querySelect;null===(_document$querySelect=document.querySelector("#id_metadatamodal"))||void 0===_document$querySelect||_document$querySelect.addEventListener("click",openModal),_metadata.metadata.loadState()}})); //# sourceMappingURL=metadatamodal.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatamodal.min.js.map b/amd/build/metadata/metadatamodal.min.js.map index b93ae74d8ea..1824a48b8d0 100644 --- a/amd/build/metadata/metadatamodal.min.js.map +++ b/amd/build/metadata/metadatamodal.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadatamodal.min.js","sources":["../../src/metadata/metadatamodal.js"],"sourcesContent":["import Modal from 'core/modal';\nimport ModalRegistry from 'core/modal_registry';\n\nexport default class MetadataModal extends Modal {\n static TYPE = \"qtype_stack/metadatamodal\";\n static TEMPLATE = \"qtype_stack/metadatamodal\";\n}\n\nlet registered = false;\nif (!registered) {\n ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE);\n registered = true;\n}"],"names":["MetadataModal","Modal","registered","register","TYPE","TEMPLATE"],"mappings":"gjBAGqBA,sBAAsBC,+DAAtBD,qBACH,6CADGA,yBAEC,iCAGlBE,YAAa,SACZA,qCACaC,SAASH,cAAcI,KAAMJ,cAAeA,cAAcK,UACxEH,YAAa"} \ No newline at end of file +{"version":3,"file":"metadatamodal.min.js","sources":["../../src/metadata/metadatamodal.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\nimport Modal from 'core/modal';\nimport ModalRegistry from 'core/modal_registry';\nimport ModalFactory from 'core/modal_factory';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport class MetadataModal extends Modal {\n static TYPE = \"qtype_stack/metadatamodal\";\n static TEMPLATE = \"qtype_stack/metadatamodal\";\n}\n\nlet registered = false;\nif (!registered) {\n ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE);\n registered = true;\n}\n\nexport const setup = () => {\n document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal);\n metadata.loadState();\n};\n\n/**\n * Open the metadata modal.\n */\nasync function openModal() {\n // ...\n const modal = await ModalFactory.create({\n type: MetadataModal.TYPE,\n });\n\n modal.show();\n}"],"names":["MetadataModal","Modal","registered","register","TYPE","TEMPLATE","openModal","ModalFactory","create","type","show","document","querySelector","addEventListener","loadState"],"mappings":"ysBAoBaA,sBAAsBC,qEAAtBD,qBACK,6CADLA,yBAES,iCAGlBE,YAAa,EACZA,qCACaC,SAASH,cAAcI,KAAMJ,cAAeA,cAAcK,UACxEH,YAAa,kBAWFI,mBAESC,uBAAaC,OAAO,CACpCC,KAAMT,cAAcI,QAGlBM,sBAdW,6DAClBC,SAASC,cAAc,6EAAsBC,iBAAiB,QAASP,8BAC9DQ"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js index 817e1bd2867..252d62e0004 100644 --- a/amd/src/metadata/container.js +++ b/amd/src/metadata/container.js @@ -1,24 +1,22 @@ -// This file is part of Moodle - http://moodle.org/ +// This file is part of Stack - http://stack.maths.ed.ac.uk/ // -// Moodle is free software: you can redistribute it and/or modify +// Stack 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, +// Stack 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 . +// along with Stack. If not, see . /** - * The beginner main app component. + * Main STACK metadata component * - * @module mod_nosferatu/local/beginner - * @class mod_nosferatu/local/beginner - * @copyright 2020 Ferran Recio + * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -26,15 +24,10 @@ import {BaseComponent} from 'core/reactive'; import {metadata} from 'qtype_stack/metadata/metadata'; export default class extends BaseComponent { - - /** - * All the component definition should be initialized on the "create" method. - */ create() { - // This is an optional name for the debugging messages. - this.name = 'stack-metadata-app-container'; + this.name = 'stack-metadata-container'; this.selectors = { - METADATACONTAINER: `[data-for='metadata-contrib']`, + METADATACONTAINER: `[data-for='qtype-stack-metadata']`, }; } @@ -56,33 +49,32 @@ export default class extends BaseComponent { /** * Initial state ready method. * - * Note in this case we want our stateReady to be async. - * * @param {object} state the initial state */ - async stateReady(state) { - this._reloadCityComponent({state}); + stateReady(state) { + this.reloadContainerComponent({state}); } - async _reloadCityComponent({state}) { + reloadContainerComponent({state}) { // Mustache data is not fully compatible with state object so we need to convert it - // into a plain object. In the intermediate level you will learng how to centralize this - // kind of operations to keep your components cleaner. + // into a plain object. const data = { - people: [], + creator: {}, + contributor: [], + language: [], + license: '', + isPartOf: '', + additional: [] }; - state.people.forEach(person => { - data.people.push({...person}); + state.contributor.forEach(contributor => { + data.contributor.push({...contributor}); }); - data.haspeople = (data.people.length != 0); // To render a child component we need a container. - const citiyContainer = this.getElement(this.selectors.METADATACONTAINER); - if (!citiyContainer) { - throw new Error('Missing city container.'); + const metadataContainer = this.getElement(this.selectors.METADATACONTAINER); + if (!metadataContainer) { + throw new Error('Missing metadata container.'); } - window.console.log(data); - // We store the new content into an attribute in case we want to remove it in the future. - this.cityComponent = await this.renderComponent(citiyContainer, 'qtype_stack/metadata/contributors', data); + this.renderComponent(metadataContainer, 'qtype_stack/metadata', data); } } \ No newline at end of file diff --git a/amd/src/metadata/contributors.js b/amd/src/metadata/contributors.js deleted file mode 100644 index 0491319b7d7..00000000000 --- a/amd/src/metadata/contributors.js +++ /dev/null @@ -1,53 +0,0 @@ -// 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 . - -/** - * The beginner main app component. - * - * @module mod_nosferatu/local/beginner - * @class mod_nosferatu/local/beginner - * @copyright 2020 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -import {BaseComponent} from 'core/reactive'; -import {metadata} from 'qtype_stack/metadata/metadata'; - -export default class extends BaseComponent { - - /** - * All the component definition should be initialized on the "create" method. - */ - create() { - // This is an optional name for the debugging messages. - this.name = 'stack-metadata-contrib'; - - } - - /** - * Static method to create a component instance form the mustache template. - * - * @param {string} target the DOM main element or its ID - * @param {object} selectors optional css selector overrides - * @return {Component} - */ - static init(target, selectors) { - return new this({ - element: document.querySelector(target), - reactive: metadata, - selectors, - }); - } -} \ No newline at end of file diff --git a/amd/src/metadata/events.js b/amd/src/metadata/events.js index 2a9b3d82630..a1fe5fe91d8 100644 --- a/amd/src/metadata/events.js +++ b/amd/src/metadata/events.js @@ -1,18 +1,17 @@ - -// This file is part of Moodle - http://moodle.org/ +// This file is part of Stack - http://stack.maths.ed.ac.uk/ // -// Moodle is free software: you can redistribute it and/or modify +// Stack 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, +// Stack 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 . +// along with Stack. If not, see . import {dispatchEvent} from 'core/event_dispatcher'; diff --git a/amd/src/metadata/exporter.js b/amd/src/metadata/exporter.js deleted file mode 100644 index d41e5b12b24..00000000000 --- a/amd/src/metadata/exporter.js +++ /dev/null @@ -1,40 +0,0 @@ -// along with Moodle. If not, see . - -/** - * Module to export parts of the state and transform them to be used in templates - * and as draggable data. - * - * @module mod_nosferatu/local/intermediate/exporter - * @class mod_nosferatu/local/intermediate/exporter - * @copyright 2022 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -export default class { - - /** - * Class constructor. - * @param {Reactive} reactive the course editor object - */ - constructor(reactive) { - this.reactive = reactive; - } - - /** - * Generate the people export data from the state. - * - * @param {Object} state the current state. - * @returns {Object} - */ - metadata(state) { - // Collect section information from the state. - const data = { - // State stores maps of key-values instead of simple arrays. - people: [], - }; - state.people.forEach(person => { - data.people.push({...person}); - }); - data.haspeople = (data.people.length != 0); - return data; - } -} \ No newline at end of file diff --git a/amd/src/metadata/metadata.js b/amd/src/metadata/metadata.js index 91febe1c741..c94d757e3a7 100644 --- a/amd/src/metadata/metadata.js +++ b/amd/src/metadata/metadata.js @@ -24,37 +24,12 @@ import {Reactive} from 'core/reactive'; import {mutations} from 'qtype_stack/metadata/mutations'; import {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events'; -const state = { - 'people': [ - { - id: 1, - name: 'Carlos', - bitten: false, - }, - { - id: 2, - name: 'Amaia', - bitten: false, - }, - { - id: 3, - name: 'Sara', - bitten: false, - }, - { - id: 4, - name: 'Ilya', - bitten: true, - }, - { - id: 5, - name: 'Ferran', - bitten: false, - }, - ], -}; - class StackMetadata extends Reactive { + loadState() { + let metadata = document.querySelector('input[name="metadata"]'); + metadata = JSON.parse(metadata?.value); + this.setInitialState(metadata); + } } /** @@ -64,14 +39,7 @@ export const metadata = new StackMetadata({ name: 'qtype_stack_metadata', eventName: eventTypes.qtypeStackStateUpdated, eventDispatch: notifyQtypeStackStateUpdated, - state, mutations, }); -/** - * Load the initial state. - */ -export const init = () => { - //state.metadata = JSON.parse(metadata); -}; diff --git a/amd/src/metadata/metadatalaunch.js b/amd/src/metadata/metadatalaunch.js deleted file mode 100644 index d7a64948326..00000000000 --- a/amd/src/metadata/metadatalaunch.js +++ /dev/null @@ -1,18 +0,0 @@ -import ModalFactory from 'core/modal_factory'; -import MetadataModal from './metadatamodal'; - -export const setup = () => { - document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal); -}; - -/** - * Open the metadata modal. - */ -async function openModal() { - // ... - const modal = await ModalFactory.create({ - type: MetadataModal.TYPE, - }); - - modal.show(); -} \ No newline at end of file diff --git a/amd/src/metadata/metadatamodal.js b/amd/src/metadata/metadatamodal.js index 1943c7bec72..1a778efa446 100644 --- a/amd/src/metadata/metadatamodal.js +++ b/amd/src/metadata/metadatamodal.js @@ -1,7 +1,24 @@ +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack 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. +// +// Stack 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 Stack. If not, see . + import Modal from 'core/modal'; import ModalRegistry from 'core/modal_registry'; +import ModalFactory from 'core/modal_factory'; +import {metadata} from 'qtype_stack/metadata/metadata'; -export default class MetadataModal extends Modal { +export class MetadataModal extends Modal { static TYPE = "qtype_stack/metadatamodal"; static TEMPLATE = "qtype_stack/metadatamodal"; } @@ -10,4 +27,21 @@ let registered = false; if (!registered) { ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE); registered = true; +} + +export const setup = () => { + document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal); + metadata.loadState(); +}; + +/** + * Open the metadata modal. + */ +async function openModal() { + // ... + const modal = await ModalFactory.create({ + type: MetadataModal.TYPE, + }); + + modal.show(); } \ No newline at end of file diff --git a/amd/src/metadata/sample.json b/amd/src/metadata/sample.json new file mode 100644 index 00000000000..df5d7b61b65 --- /dev/null +++ b/amd/src/metadata/sample.json @@ -0,0 +1,24 @@ +{ + "creator": { + "firstName": "Edmund", + "lastName": "Farrow", + "institution": "University of Edinburgh", + "year": 2024 + }, + "contributor": [ + { + "id": 1, + "firstName": "Chris", + "lastName": "Andrews", + "institution": "University of Mars", + "year": 2025 + }, + { + "id": 2, + "firstName": "Bob", + "lastName": "Smith", + "institution": "MIT", + "year": 2025 + } + ] +} \ No newline at end of file diff --git a/classes/output/metadata.php b/classes/output/metadata.php deleted file mode 100644 index 89350a46b30..00000000000 --- a/classes/output/metadata.php +++ /dev/null @@ -1,67 +0,0 @@ -. - -/** - * Contains class mod_nosferatu\output\reportlink - * - * @package mod_nosferatu - * @copyright 2020 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace qtype_stack\output; - -defined('MOODLE_INTERNAL') || die(); - -use qtype_stack\metadatamanager; -use renderable; -use templatable; -use renderer_base; -use stdClass; - -/** - * Class to help display report link in mod_nosferatu. - * - * @copyright 2020 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class metadata implements renderable, templatable { - - - /** - * Constructor. - * - */ - public function __construct() { - global $PAGE; - - $PAGE->requires->js_call_amd('qtype_stack/metadata/metadata', 'init'); - } - - /** - * Export this data so it can be used as the context for a mustache template. - * Initial data shown. - * - * @param renderer_base $output - * @return stdClass - */ - public function export_for_template(renderer_base $output) { - - $data = ['haspeople' => true, 'people' => ['name' => 'bob']]; - - return $data; - } -} \ No newline at end of file diff --git a/classes/output/metadatamodal.php b/classes/output/metadatamodal.php index 5e1ce78ec99..b84607dcbb2 100644 --- a/classes/output/metadatamodal.php +++ b/classes/output/metadatamodal.php @@ -47,7 +47,6 @@ class metadatamodal implements renderable, templatable { */ public function __construct() { global $PAGE; - $PAGE->requires->js_call_amd('qtype_stack/metadata/metadatamodal', 'init'); } diff --git a/edit_stack_form.php b/edit_stack_form.php index 1babbe0f257..bac2424bc37 100644 --- a/edit_stack_form.php +++ b/edit_stack_form.php @@ -255,8 +255,13 @@ protected function definition_inner(/* MoodleQuickForm */ $mform) { $warnings = ($warnings) ? $warnings . '
' : $warnings; $warnings .= '' . stack_string('usetextarea'); } - $PAGE->requires->js_call_amd('qtype_stack/metadata/metadatalaunch', 'setup'); + $PAGE->requires->js_call_amd('qtype_stack/metadata/metadatamodal', 'setup'); $mform->addElement('button', 'metadatamodal', stack_string("editmetadata")); + global $CFG; + $data = file_get_contents($CFG->dirroot . '/question/type/stack/amd/src/metadata/sample.json'); + $md = $mform->createElement('hidden', 'metadata', $data); + $mform->insertElementBefore($md, 'metadatamodal'); + $mform->setType('metadata', PARAM_RAW); // Note that for the editor elements, we are using $mform->getElement('prtincorrect')->setValue(...); instead // of setDefault, because setDefault does not work for editors. diff --git a/stackmetadatamodal.php b/stackmetadatamodal.php deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/templates/metadata.mustache b/templates/metadata.mustache index 2cc381b1b2d..fa7097820ac 100644 --- a/templates/metadata.mustache +++ b/templates/metadata.mustache @@ -12,21 +12,19 @@ along with Moodle. If not, see . }} {{! - @template mod_nosferatu/local/beginner/city + @template qtype_stack/metadata - This component renders all people in the city. Example context (json): { } }} -
-
- -
-
-{{#js}} -require(['qtype_stack/metadata/container'], function(component) { - component.init('#qtype-stack-metadata-main'); -}); -{{/js}} \ No newline at end of file +
+
    + {{#contributor}} +
  • + {{firstName}} {{lastName}} +
  • + {{/contributor}} +
+
\ No newline at end of file diff --git a/templates/metadata/contributors.mustache b/templates/metadata/contributors.mustache deleted file mode 100644 index aa3b5d8cef4..00000000000 --- a/templates/metadata/contributors.mustache +++ /dev/null @@ -1,45 +0,0 @@ -{{! - This file is part of Stack - http://stack.maths.ed.ac.uk/ - 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 . -}} -{{! - @template mod_nosferatu/local/beginner/city - - This component renders all people in the city. - - Example context (json): - { - } -}} -
- {{^haspeople}} -
- No contributors. -
- {{/haspeople}} - {{#haspeople}} -
    - {{#people}} -
  • -

    - {{name}} -

    -
  • - {{/people}} -
- {{/haspeople}} -
-{{#js}} -require(['qtype_stack/metadata/contributors'], function(component) { - component.init('#qtype-stack-metadata-contributors-main'); -}); -{{/js}} \ No newline at end of file diff --git a/templates/metadatamodal.mustache b/templates/metadatamodal.mustache index e49da4fade0..b87ae053f77 100644 --- a/templates/metadatamodal.mustache +++ b/templates/metadatamodal.mustache @@ -31,10 +31,17 @@ {{< core/modal }} {{$title}}{{#str}} login {{/str}}{{/title}} {{$body}} -
- {{> qtype_stack/metadata}} +
+
+ +
{{/body}} {{$footer}} {{/footer}} -{{/ core/modal }} \ No newline at end of file +{{/ core/modal }} +{{#js}} +require(['qtype_stack/metadata/container'], function(component) { + component.init('#qtype-stack-metadata-main'); +}); +{{/js}} \ No newline at end of file From 65f120ca11324fcfd380908e85ff8f4b4fed1bcc Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Mon, 1 Dec 2025 10:56:51 +0000 Subject: [PATCH 04/66] iss1171 - bump version --- stack/maxima/stackmaxima.mac | 10 +++++----- version.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stack/maxima/stackmaxima.mac b/stack/maxima/stackmaxima.mac index e9595120562..0a4a28e2141 100644 --- a/stack/maxima/stackmaxima.mac +++ b/stack/maxima/stackmaxima.mac @@ -223,7 +223,7 @@ make_complexJ(OPT_COMPLEXJ) := block( /* Choose the symbol for the multiplication sign. */ make_multsgn(OPT_MULTSGN) := block( - if ev(not(elementp(OPT_MULTSGN, {"cross", "dot", "onum", "none", "space"})), simp) + if ev(not(elementp(OPT_MULTSGN, {"cross", "dot", "onum", "none", "space"})), simp) then error("make_multsgn received un-supported option: ", OPT_MULTSGN), if OPT_MULTSGN = "cross" then (texput("*", "\\times ", nary), texput("nounmul", "\\times ", nary)), @@ -1227,7 +1227,7 @@ ATAlgEquivfun(SA, SB) := block([SApoly, SBpoly, keepfloat, RawMark, FeedBack, A /* Are we dealing with lists? */ if listp(SB) then if listp(SA)#true then - if is(stackfltsep=".") then + if is(stackfltsep=".") then return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_list")) else return([false, false, StackAddNote("", "ATAlgEquiv_SA_not_list"), StackAddFeedback("", "ATAlgEquiv_SA_not_list_semi")]) @@ -1236,7 +1236,7 @@ ATAlgEquivfun(SA, SB) := block([SApoly, SBpoly, keepfloat, RawMark, FeedBack, A /* Are we dealing with sets? */ if safe_setp(SB) then if safe_setp(SA)=false then - if is(stackfltsep=".") then + if is(stackfltsep=".") then return(StackBasicReturn(false, false, "ATAlgEquiv_SA_not_set")) else return([false, false, StackAddNote("", "ATAlgEquiv_SA_not_set"), StackAddFeedback("", "ATAlgEquiv_SA_not_set_semi")]) @@ -1655,7 +1655,7 @@ ATSets(SA, SB) := block([RawMark, FeedBack, AnswerNote, SAsimp, SBsimp], if not(safe_setp(SB)) then return(StackBasicReturn(false, false, "ATSets_SB_not_set")), if not(safe_setp(SA)) then - if is(stackfltsep=".") then + if is(stackfltsep=".") then return(StackBasicReturn(false, false, "ATSets_SA_not_set")) else return([false, false, StackAddNote("", "ATSets_SA_not_set"), StackAddFeedback("", "ATSets_SA_not_set_semi")]), @@ -3523,4 +3523,4 @@ is_lang(code):=ev(is(%_STACK_LANG=code),simp=true)$ /* Stack expects some output with the version number the output happens at */ /* maximalocal.mac after additional library loading */ -stackmaximaversion:2025080100$ +stackmaximaversion:2025102200$ diff --git a/version.php b/version.php index 20846b419d8..2cbd4aa4dcb 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2025080100; +$plugin->version = 2025102200; $plugin->requires = 2022041900; $plugin->cron = 0; $plugin->component = 'qtype_stack'; From acfc5c8daa2cc0a3402c2a110b907ed6decf9851 Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Mon, 1 Dec 2025 15:12:33 +0000 Subject: [PATCH 05/66] iss1171 - Working reaction --- amd/build/metadata/container.min.js | 5 +- amd/build/metadata/container.min.js.map | 2 +- amd/build/metadata/events.min.js | 7 +-- amd/build/metadata/events.min.js.map | 2 +- amd/build/metadata/metadata.min.js | 3 +- amd/build/metadata/metadata.min.js.map | 2 +- amd/build/metadata/metadatacontent.min.js | 11 ++++ amd/build/metadata/metadatacontent.min.js.map | 1 + amd/build/metadata/metadatamodal.min.js | 2 +- amd/build/metadata/metadatamodal.min.js.map | 2 +- amd/build/metadata/mutations.min.js | 9 ++- amd/build/metadata/mutations.min.js.map | 2 +- amd/src/metadata/container.js | 38 ++++++++++-- amd/src/metadata/events.js | 7 +-- amd/src/metadata/metadata.js | 3 +- amd/src/metadata/metadatacontent.js | 51 ++++++++++++++++ amd/src/metadata/metadatamodal.js | 19 ++++-- amd/src/metadata/mutations.js | 59 +++---------------- ...data.mustache => metadatacontent.mustache} | 18 +++++- templates/metadatamodal.mustache | 1 - 20 files changed, 157 insertions(+), 87 deletions(-) create mode 100644 amd/build/metadata/metadatacontent.min.js create mode 100644 amd/build/metadata/metadatacontent.min.js.map create mode 100644 amd/src/metadata/metadatacontent.js rename templates/{metadata.mustache => metadatacontent.mustache} (59%) diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js index 39d0514cadc..e317640a3f7 100644 --- a/amd/build/metadata/container.min.js +++ b/amd/build/metadata/container.min.js @@ -2,9 +2,10 @@ define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/ /** * Main STACK metadata component * + * @module qtype_stack/metadata * @copyright 2025 University of Edinburgh - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}stateReady(state){this.reloadContainerComponent({state:state})}reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:"",isPartOf:"",additional:[]};state.contributor.forEach((contributor=>{data.contributor.push({...contributor})}));const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");this.renderComponent(metadataContainer,"qtype_stack/metadata",data)}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state}),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}getWatchers(){return[{watch:"contributor:updated",handler:this.reloadContainerComponent}]}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:"",isPartOf:"",additional:[]};state.contributor.forEach((contributor=>{data.contributor.push({...contributor})}));const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data)}update(event){event.preventDefault();const first=this.getElement("#contributor-1-firstName").value,last=this.getElement("#contributor-1-lastName").value;this.reactive.dispatch("updateContributor",1,first,last)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map index e6ea2ecd476..86d64e7f1d5 100644 --- a/amd/build/metadata/container.min.js.map +++ b/amd/build/metadata/container.min.js.map @@ -1 +1 @@ -{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n stateReady(state) {\n this.reloadContainerComponent({state});\n }\n\n reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: '',\n isPartOf: '',\n additional: []\n };\n state.contributor.forEach(contributor => {\n data.contributor.push({...contributor});\n });\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n this.renderComponent(metadataContainer, 'qtype_stack/metadata', data);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","target","this","element","document","querySelector","reactive","metadata","stateReady","state","reloadContainerComponent","data","creator","contributor","language","license","isPartOf","additional","forEach","push","metadataContainer","getElement","Error","renderComponent"],"mappings":";;;;;;;uBAyB6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,mEAWIC,OAAQF,kBACT,IAAIG,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVR,UAAAA,YASRS,WAAWC,YACFC,yBAAyB,CAACD,MAAAA,QAGnCC,mCAAyBD,MAACA,kBAGhBE,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAAS,GACTC,SAAU,GACVC,WAAY,IAEhBR,MAAMI,YAAYK,SAAQL,cACtBF,KAAKE,YAAYM,KAAK,IAAIN,uBAIxBO,kBAAoBlB,KAAKmB,WAAWnB,KAAKH,UAAUC,uBACpDoB,wBACK,IAAIE,MAAM,oCAEfC,gBAAgBH,kBAAmB,uBAAwBT"} \ No newline at end of file +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n getWatchers() {\n return [\n {watch: `contributor:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: '',\n isPartOf: '',\n additional: []\n };\n state.contributor.forEach(contributor => {\n data.contributor.push({...contributor});\n });\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n // Get the selected person id.\n const first = this.getElement('#contributor-1-firstName').value;\n const last = this.getElement('#contributor-1-lastName').value;\n this.reactive.dispatch('updateContributor', 1, first, last);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","addEventListener","getElement","update","getWatchers","watch","handler","data","creator","contributor","language","license","isPartOf","additional","forEach","push","metadataContainer","Error","renderComponent","event","preventDefault","first","value","last","dispatch"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,aAChCE,iBACDR,KAAKS,WAAWT,KAAKJ,UAAUE,QAC/B,QACAE,KAAKU,QAIbC,oBACW,CACH,CAACC,4BAA8BC,QAASb,KAAKO,oEAItBD,MAACA,kBAGtBQ,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAAS,GACTC,SAAU,GACVC,WAAY,IAEhBd,MAAMU,YAAYK,SAAQL,cACtBF,KAAKE,YAAYM,KAAK,IAAIN,uBAIxBO,kBAAoBvB,KAAKS,WAAWT,KAAKJ,UAAUC,uBACpD0B,wBACK,IAAIC,MAAM,qCAGdxB,KAAKyB,gBAAgBF,kBAAmB,8BAA+BT,MAQjFJ,OAAOgB,OAEHA,MAAMC,uBAEAC,MAAQ5B,KAAKS,WAAW,4BAA4BoB,MACpDC,KAAO9B,KAAKS,WAAW,2BAA2BoB,WACnDzB,SAAS2B,SAAS,oBAAqB,EAAGH,MAAOE"} \ No newline at end of file diff --git a/amd/build/metadata/events.min.js b/amd/build/metadata/events.min.js index 2dd87572f43..142e506d20d 100644 --- a/amd/build/metadata/events.min.js +++ b/amd/build/metadata/events.min.js @@ -2,10 +2,9 @@ define("qtype_stack/metadata/events",["exports","core/event_dispatcher"],(functi /** * Javascript events for the `mod_nosferatu` activity. * - * @module mod_nosferatu/events - * @copyright 2021 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.0 + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ const eventTypes={qtypeStackStateUpdated:"qtype_stack/stateUpdated"};_exports.eventTypes=eventTypes;_exports.notifyQtypeStackStateUpdated=(detail,container)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.qtypeStackStateUpdated,detail,container)})); diff --git a/amd/build/metadata/events.min.js.map b/amd/build/metadata/events.min.js.map index 0b1d94739af..699adc1d796 100644 --- a/amd/build/metadata/events.min.js.map +++ b/amd/build/metadata/events.min.js.map @@ -1 +1 @@ -{"version":3,"file":"events.min.js","sources":["../../src/metadata/events.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Javascript events for the `mod_nosferatu` activity.\n *\n * @module mod_nosferatu/events\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\n/**\n * Events for the `mod_nosferatu` activity.\n *\n * @constant\n * @property {String} modNosferatuStateUpdated See {@link event:modNosferatuStateUpdated}\n */\nexport const eventTypes = {\n /**\n * Event triggered when the activity reactive state is updated.\n *\n * @event modNosferatuStateUpdated\n * @type {CustomEvent}\n * @property {Array} nodes The list of parent nodes which were updated\n */\n qtypeStackStateUpdated: 'qtype_stack/stateUpdated',\n};\n\n/**\n * Trigger an event to indicate that the activity state is updated.\n *\n * @method notifyModNosferatuStateUpdated\n * @param {object} detail the full state\n * @param {HTMLElement} container the custom event target (document if none provided)\n * @returns {CustomEvent}\n * @fires modNosferatuStateUpdated\n */\nexport const notifyQtypeStackStateUpdated = (detail, container) => {\n return dispatchEvent(eventTypes.qtypeStackStateUpdated, detail, container);\n};"],"names":["eventTypes","qtypeStackStateUpdated","detail","container"],"mappings":";;;;;;;;;MAgCaA,WAAa,CAQtBC,uBAAwB,iGAYgB,CAACC,OAAQC,aAC1C,mCAAcH,WAAWC,uBAAwBC,OAAQC"} \ No newline at end of file +{"version":3,"file":"events.min.js","sources":["../../src/metadata/events.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Javascript events for the `mod_nosferatu` activity.\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\n/**\n * Events for the `mod_nosferatu` activity.\n *\n * @constant\n * @property {String} modNosferatuStateUpdated See {@link event:modNosferatuStateUpdated}\n */\nexport const eventTypes = {\n /**\n * Event triggered when the activity reactive state is updated.\n *\n * @event modNosferatuStateUpdated\n * @type {CustomEvent}\n * @property {Array} nodes The list of parent nodes which were updated\n */\n qtypeStackStateUpdated: 'qtype_stack/stateUpdated',\n};\n\n/**\n * Trigger an event to indicate that the activity state is updated.\n *\n * @method notifyModNosferatuStateUpdated\n * @param {object} detail the full state\n * @param {HTMLElement} container the custom event target (document if none provided)\n * @returns {CustomEvent}\n * @fires modNosferatuStateUpdated\n */\nexport const notifyQtypeStackStateUpdated = (detail, container) => {\n return dispatchEvent(eventTypes.qtypeStackStateUpdated, detail, container);\n};"],"names":["eventTypes","qtypeStackStateUpdated","detail","container"],"mappings":";;;;;;;;MA+BaA,WAAa,CAQtBC,uBAAwB,iGAYgB,CAACC,OAAQC,aAC1C,mCAAcH,WAAWC,uBAAwBC,OAAQC"} \ No newline at end of file diff --git a/amd/build/metadata/metadata.min.js b/amd/build/metadata/metadata.min.js index d6c68e19e37..1a19118a889 100644 --- a/amd/build/metadata/metadata.min.js +++ b/amd/build/metadata/metadata.min.js @@ -2,8 +2,9 @@ define("qtype_stack/metadata/metadata",["exports","core/reactive","qtype_stack/m /** * Metadata entry reactive component * + * @module qtype_stack/metadata * @copyright 2025 University of Edinburgh - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ class StackMetadata extends _reactive.Reactive{loadState(){var _metadata;let metadata=document.querySelector('input[name="metadata"]');metadata=JSON.parse(null===(_metadata=metadata)||void 0===_metadata?void 0:_metadata.value),this.setInitialState(metadata)}}const metadata=new StackMetadata({name:"qtype_stack_metadata",eventName:_events.eventTypes.qtypeStackStateUpdated,eventDispatch:_events.notifyQtypeStackStateUpdated,mutations:_mutations.mutations});_exports.metadata=metadata})); diff --git a/amd/build/metadata/metadata.min.js.map b/amd/build/metadata/metadata.min.js.map index a8dcf5b5bf7..a4de12e6866 100644 --- a/amd/build/metadata/metadata.min.js.map +++ b/amd/build/metadata/metadata.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nclass StackMetadata extends Reactive {\n loadState() {\n let metadata = document.querySelector('input[name=\"metadata\"]');\n metadata = JSON.parse(metadata?.value);\n this.setInitialState(metadata);\n }\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n mutations,\n});\n\n\n"],"names":["StackMetadata","Reactive","loadState","metadata","document","querySelector","JSON","parse","_metadata","value","setInitialState","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","mutations"],"mappings":";;;;;;;MA0BMA,sBAAsBC,mBACxBC,8BACQC,SAAWC,SAASC,cAAc,0BACtCF,SAAWG,KAAKC,wBAAMJ,qCAAAK,UAAUC,YAC3BC,gBAAgBP,iBAOhBA,SAAW,IAAIH,cAAc,CACtCW,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,UAAAA"} \ No newline at end of file +{"version":3,"file":"metadata.min.js","sources":["../../src/metadata/metadata.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Metadata entry reactive component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {Reactive} from 'core/reactive';\nimport {mutations} from 'qtype_stack/metadata/mutations';\nimport {eventTypes, notifyQtypeStackStateUpdated} from 'qtype_stack/metadata/events';\n\nclass StackMetadata extends Reactive {\n loadState() {\n let metadata = document.querySelector('input[name=\"metadata\"]');\n metadata = JSON.parse(metadata?.value);\n this.setInitialState(metadata);\n }\n}\n\n/**\n * The metadata state instance.\n */\nexport const metadata = new StackMetadata({\n name: 'qtype_stack_metadata',\n eventName: eventTypes.qtypeStackStateUpdated,\n eventDispatch: notifyQtypeStackStateUpdated,\n mutations,\n});\n\n\n"],"names":["StackMetadata","Reactive","loadState","metadata","document","querySelector","JSON","parse","_metadata","value","setInitialState","name","eventName","eventTypes","qtypeStackStateUpdated","eventDispatch","notifyQtypeStackStateUpdated","mutations"],"mappings":";;;;;;;;MA2BMA,sBAAsBC,mBACxBC,8BACQC,SAAWC,SAASC,cAAc,0BACtCF,SAAWG,KAAKC,wBAAMJ,qCAAAK,UAAUC,YAC3BC,gBAAgBP,iBAOhBA,SAAW,IAAIH,cAAc,CACtCW,KAAM,uBACNC,UAAWC,mBAAWC,uBACtBC,cAAeC,qCACfC,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/metadatacontent.min.js b/amd/build/metadata/metadatacontent.min.js new file mode 100644 index 00000000000..e22cdaefce3 --- /dev/null +++ b/amd/build/metadata/metadatacontent.min.js @@ -0,0 +1,11 @@ +define("qtype_stack/metadata/metadatacontent",["exports","core/reactive","qtype_stack/metadata/metadata"],(function(_exports,_reactive,_metadata){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * Main STACK metadata component + * + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-content",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=metadatacontent.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatacontent.min.js.map b/amd/build/metadata/metadatacontent.min.js.map new file mode 100644 index 00000000000..8e23b4bc6d9 --- /dev/null +++ b/amd/build/metadata/metadatacontent.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"metadatacontent.min.js","sources":["../../src/metadata/metadatacontent.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-content';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,8BACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/metadatamodal.min.js b/amd/build/metadata/metadatamodal.min.js index dcc18e63f67..a008f6b53f6 100644 --- a/amd/build/metadata/metadatamodal.min.js +++ b/amd/build/metadata/metadatamodal.min.js @@ -1,3 +1,3 @@ -define("qtype_stack/metadata/metadatamodal",["exports","core/modal","core/modal_registry","core/modal_factory","qtype_stack/metadata/metadata"],(function(_exports,_modal,_modal_registry,_modal_factory,_metadata){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=_exports.MetadataModal=void 0,_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry),_modal_factory=_interopRequireDefault(_modal_factory);class MetadataModal extends _modal.default{}_exports.MetadataModal=MetadataModal,_defineProperty(MetadataModal,"TYPE","qtype_stack/metadatamodal"),_defineProperty(MetadataModal,"TEMPLATE","qtype_stack/metadatamodal");let registered=!1;registered||(_modal_registry.default.register(MetadataModal.TYPE,MetadataModal,MetadataModal.TEMPLATE),registered=!0);async function openModal(){(await _modal_factory.default.create({type:MetadataModal.TYPE})).show()}_exports.setup=()=>{var _document$querySelect;null===(_document$querySelect=document.querySelector("#id_metadatamodal"))||void 0===_document$querySelect||_document$querySelect.addEventListener("click",openModal),_metadata.metadata.loadState()}})); +define("qtype_stack/metadata/metadatamodal",["exports","core/modal","core/modal_registry","core/modal_factory","qtype_stack/metadata/metadata"],(function(_exports,_modal,_modal_registry,_modal_factory,_metadata){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setup=_exports.MetadataModal=void 0,_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry),_modal_factory=_interopRequireDefault(_modal_factory);class MetadataModal extends _modal.default{}_exports.MetadataModal=MetadataModal,_defineProperty(MetadataModal,"TYPE","qtype_stack/metadatamodal"),_defineProperty(MetadataModal,"TEMPLATE","qtype_stack/metadatamodal");let registered=!1;registered||(_modal_registry.default.register(MetadataModal.TYPE,MetadataModal,MetadataModal.TEMPLATE),registered=!0);let modal=null;async function openModal(){modal||(modal=await _modal_factory.default.create({type:MetadataModal.TYPE})),modal.show()}_exports.setup=()=>{var _document$querySelect;null===(_document$querySelect=document.querySelector("#id_metadatamodal"))||void 0===_document$querySelect||_document$querySelect.addEventListener("click",openModal),_metadata.metadata.loadState()}})); //# sourceMappingURL=metadatamodal.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatamodal.min.js.map b/amd/build/metadata/metadatamodal.min.js.map index 1824a48b8d0..b747d54cef7 100644 --- a/amd/build/metadata/metadatamodal.min.js.map +++ b/amd/build/metadata/metadatamodal.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadatamodal.min.js","sources":["../../src/metadata/metadatamodal.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\nimport Modal from 'core/modal';\nimport ModalRegistry from 'core/modal_registry';\nimport ModalFactory from 'core/modal_factory';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport class MetadataModal extends Modal {\n static TYPE = \"qtype_stack/metadatamodal\";\n static TEMPLATE = \"qtype_stack/metadatamodal\";\n}\n\nlet registered = false;\nif (!registered) {\n ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE);\n registered = true;\n}\n\nexport const setup = () => {\n document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal);\n metadata.loadState();\n};\n\n/**\n * Open the metadata modal.\n */\nasync function openModal() {\n // ...\n const modal = await ModalFactory.create({\n type: MetadataModal.TYPE,\n });\n\n modal.show();\n}"],"names":["MetadataModal","Modal","registered","register","TYPE","TEMPLATE","openModal","ModalFactory","create","type","show","document","querySelector","addEventListener","loadState"],"mappings":"ysBAoBaA,sBAAsBC,qEAAtBD,qBACK,6CADLA,yBAES,iCAGlBE,YAAa,EACZA,qCACaC,SAASH,cAAcI,KAAMJ,cAAeA,cAAcK,UACxEH,YAAa,kBAWFI,mBAESC,uBAAaC,OAAO,CACpCC,KAAMT,cAAcI,QAGlBM,sBAdW,6DAClBC,SAASC,cAAc,6EAAsBC,iBAAiB,QAASP,8BAC9DQ"} \ No newline at end of file +{"version":3,"file":"metadatamodal.min.js","sources":["../../src/metadata/metadatamodal.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * STACK metadata modal setup\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport Modal from 'core/modal';\nimport ModalRegistry from 'core/modal_registry';\nimport ModalFactory from 'core/modal_factory';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport class MetadataModal extends Modal {\n static TYPE = \"qtype_stack/metadatamodal\";\n static TEMPLATE = \"qtype_stack/metadatamodal\";\n}\n\nlet registered = false;\nif (!registered) {\n ModalRegistry.register(MetadataModal.TYPE, MetadataModal, MetadataModal.TEMPLATE);\n registered = true;\n}\n\nlet modal = null;\n\nexport const setup = () => {\n document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal);\n metadata.loadState();\n};\n\n/**\n * Open the metadata modal.\n */\nasync function openModal() {\n if (!modal) {\n modal = await ModalFactory.create({\n type: MetadataModal.TYPE,\n });\n }\n\n modal.show();\n}"],"names":["MetadataModal","Modal","registered","register","TYPE","TEMPLATE","modal","openModal","ModalFactory","create","type","show","document","querySelector","addEventListener","loadState"],"mappings":"ysBA4BaA,sBAAsBC,qEAAtBD,qBACK,6CADLA,yBAES,iCAGlBE,YAAa,EACZA,qCACaC,SAASH,cAAcI,KAAMJ,cAAeA,cAAcK,UACxEH,YAAa,OAGbI,MAAQ,oBAUGC,YACND,QACDA,YAAcE,uBAAaC,OAAO,CAC9BC,KAAMV,cAAcI,QAI5BE,MAAMK,sBAfW,6DAClBC,SAASC,cAAc,6EAAsBC,iBAAiB,QAASP,8BAC9DQ"} \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js b/amd/build/metadata/mutations.min.js index df36d6b1103..4ae817100ad 100644 --- a/amd/build/metadata/mutations.min.js +++ b/amd/build/metadata/mutations.min.js @@ -2,11 +2,10 @@ define("qtype_stack/metadata/mutations",["exports"],(function(_exports){Object.d /** * Default mutation manager * - * @module mod_nosferatu/local/beginner/mutations - * @class mod_nosferatu/local/beginner/mutations - * @copyright 2021 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class{bite(stateManager,personId){const state=stateManager.state;stateManager.setReadOnly(!1),state.people.get(personId).bitten=!0,stateManager.setReadOnly(!0)}cureAll(stateManager){const result=this._callCureAll(stateManager.state);stateManager.processUpdates(result)}_callCureAll(state){const result=[];return state.people.forEach((person=>{result.push({name:"people",action:"update",fields:{...person,bitten:!1}})})),result}};_exports.mutations=mutations})); +class{updateContributor(stateManager,id,firstName,LastName){const state=stateManager.state;stateManager.setReadOnly(!1),state.contributor.get(id).firstName=firstName,state.contributor.get(id).LastName=LastName,stateManager.setReadOnly(!0),console.log(state)}};_exports.mutations=mutations})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js.map b/amd/build/metadata/mutations.min.js.map index 3c42e492b92..1f911254e81 100644 --- a/amd/build/metadata/mutations.min.js.map +++ b/amd/build/metadata/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module mod_nosferatu/local/beginner/mutations\n * @class mod_nosferatu/local/beginner/mutations\n * @copyright 2021 Ferran Recio \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nclass Mutations {\n /**\n * Bite a person.\n *\n * All mutations recive a StateManager object as a first parameter. Whith this object the mutation\n * can acces the state (stateManager.state) but also set the read mode (statemanager.setReadOnly(true|false)).\n * In next steps we will see some other stateManager features. But for now you don't need them.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {Number} personId the person id to bite\n */\n bite(stateManager, personId) {\n // The first thing we need to do is get the current state.\n const state = stateManager.state;\n // State is always on read mode. To change any value first we need to unlock it.\n stateManager.setReadOnly(false);\n // Now we do as many state changes as we need.\n state.people.get(personId).bitten = true;\n // All mutations should restore the read mode. This will trigger all the reactive events.\n stateManager.setReadOnly(true);\n }\n\n /**\n * The cureAll mutation.\n *\n * @param {StateManager} stateManager the current state manager\n */\n cureAll(stateManager) {\n // We call our hipotetical webservice.\n const result = this._callCureAll(stateManager.state);\n // And now we send the results to the stateManager.\n stateManager.processUpdates(result);\n }\n /**\n * Ok. we don't have a webservice yet, so we fake it.\n *\n * @param {object} state if this was a real webservice we probably won't need the full state.\n * @returns {array} the state updates object.\n */\n _callCureAll(state) {\n const result = [];\n state.people.forEach(person => {\n result.push({\n name: 'people',\n action: 'update',\n fields: {\n ...person,\n bitten: false,\n }\n });\n });\n return result;\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","bite","stateManager","personId","state","setReadOnly","people","get","bitten","cureAll","result","this","_callCureAll","processUpdates","forEach","person","push","name","action","fields"],"mappings":"gKA8EaA,UAAY;;;;;;;;;MA5CrBC,KAAKC,aAAcC,gBAETC,MAAQF,aAAaE,MAE3BF,aAAaG,aAAY,GAEzBD,MAAME,OAAOC,IAAIJ,UAAUK,QAAS,EAEpCN,aAAaG,aAAY,GAQ7BI,QAAQP,oBAEEQ,OAASC,KAAKC,aAAaV,aAAaE,OAE9CF,aAAaW,eAAeH,QAQhCE,aAAaR,aACHM,OAAS,UACfN,MAAME,OAAOQ,SAAQC,SACjBL,OAAOM,KAAK,CACRC,KAAM,SACNC,OAAQ,SACRC,OAAQ,IACDJ,OACHP,QAAQ,QAIbE"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateContributor(stateManager, id, firstName, LastName) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.contributor.get(id).firstName = firstName;\n state.contributor.get(id).LastName = LastName;\n stateManager.setReadOnly(true);\n console.log(state);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateContributor","stateManager","id","firstName","LastName","state","setReadOnly","contributor","get","console","log"],"mappings":"gKAiCaA,UAAY;;;;;;;;MAVrBC,kBAAkBC,aAAcC,GAAIC,UAAWC,gBACrCC,MAAQJ,aAAaI,MAC3BJ,aAAaK,aAAY,GACzBD,MAAME,YAAYC,IAAIN,IAAIC,UAAYA,UACtCE,MAAME,YAAYC,IAAIN,IAAIE,SAAWA,SACrCH,aAAaK,aAAY,GACzBG,QAAQC,IAAIL"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js index 252d62e0004..1885f08b900 100644 --- a/amd/src/metadata/container.js +++ b/amd/src/metadata/container.js @@ -16,8 +16,9 @@ /** * Main STACK metadata component * + * @module qtype_stack/metadata * @copyright 2025 University of Edinburgh - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ import {BaseComponent} from 'core/reactive'; @@ -28,6 +29,7 @@ export default class extends BaseComponent { this.name = 'stack-metadata-container'; this.selectors = { METADATACONTAINER: `[data-for='qtype-stack-metadata']`, + SUBMIT: `#stack-metadata-update`, }; } @@ -51,11 +53,22 @@ export default class extends BaseComponent { * * @param {object} state the initial state */ - stateReady(state) { - this.reloadContainerComponent({state}); + async stateReady(state) { + await this.reloadContainerComponent({state}); + this.addEventListener( + this.getElement(this.selectors.SUBMIT), + 'click', + this.update + ); } - reloadContainerComponent({state}) { + getWatchers() { + return [ + {watch: `contributor:updated`, handler: this.reloadContainerComponent}, + ]; + } + + async reloadContainerComponent({state}) { // Mustache data is not fully compatible with state object so we need to convert it // into a plain object. const data = { @@ -75,6 +88,21 @@ export default class extends BaseComponent { if (!metadataContainer) { throw new Error('Missing metadata container.'); } - this.renderComponent(metadataContainer, 'qtype_stack/metadata', data); + + await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data); + } + + /** + * Our submit handler. + * + * @param {Event} event the click event + */ + update(event) { + // We don't want to submit the form. + event.preventDefault(); + // Get the selected person id. + const first = this.getElement('#contributor-1-firstName').value; + const last = this.getElement('#contributor-1-lastName').value; + this.reactive.dispatch('updateContributor', 1, first, last); } } \ No newline at end of file diff --git a/amd/src/metadata/events.js b/amd/src/metadata/events.js index a1fe5fe91d8..8b5d9b049f6 100644 --- a/amd/src/metadata/events.js +++ b/amd/src/metadata/events.js @@ -18,10 +18,9 @@ import {dispatchEvent} from 'core/event_dispatcher'; /** * Javascript events for the `mod_nosferatu` activity. * - * @module mod_nosferatu/events - * @copyright 2021 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.0 + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ /** diff --git a/amd/src/metadata/metadata.js b/amd/src/metadata/metadata.js index c94d757e3a7..a8077775b8d 100644 --- a/amd/src/metadata/metadata.js +++ b/amd/src/metadata/metadata.js @@ -16,8 +16,9 @@ /** * Metadata entry reactive component * + * @module qtype_stack/metadata * @copyright 2025 University of Edinburgh - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ import {Reactive} from 'core/reactive'; diff --git a/amd/src/metadata/metadatacontent.js b/amd/src/metadata/metadatacontent.js new file mode 100644 index 00000000000..7caddf56840 --- /dev/null +++ b/amd/src/metadata/metadatacontent.js @@ -0,0 +1,51 @@ +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack 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. +// +// Stack 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 Stack. If not, see . + +/** + * Main STACK metadata component + * + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ + +import {BaseComponent} from 'core/reactive'; +import {metadata} from 'qtype_stack/metadata/metadata'; + +export default class extends BaseComponent { + create() { + this.name = 'stack-metadata-content'; + this.selectors = { + METADATACONTAINER: `[data-for='qtype-stack-metadata']`, + SUBMIT: `#stack-metadata-update`, + }; + } + + /** + * Static method to create a component instance form the mustache template. + * + * @param {string} target the DOM main element or its ID + * @param {object} selectors optional css selector overrides + * @return {Component} + */ + static init(target, selectors) { + return new this({ + element: document.querySelector(target), + reactive: metadata, + selectors, + }); + } + +} \ No newline at end of file diff --git a/amd/src/metadata/metadatamodal.js b/amd/src/metadata/metadatamodal.js index 1a778efa446..1b7c7aaa968 100644 --- a/amd/src/metadata/metadatamodal.js +++ b/amd/src/metadata/metadatamodal.js @@ -13,6 +13,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see . +/** + * STACK metadata modal setup + * + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ + import Modal from 'core/modal'; import ModalRegistry from 'core/modal_registry'; import ModalFactory from 'core/modal_factory'; @@ -29,6 +37,8 @@ if (!registered) { registered = true; } +let modal = null; + export const setup = () => { document.querySelector('#id_metadatamodal')?.addEventListener('click', openModal); metadata.loadState(); @@ -38,10 +48,11 @@ export const setup = () => { * Open the metadata modal. */ async function openModal() { - // ... - const modal = await ModalFactory.create({ - type: MetadataModal.TYPE, - }); + if (!modal) { + modal = await ModalFactory.create({ + type: MetadataModal.TYPE, + }); + } modal.show(); } \ No newline at end of file diff --git a/amd/src/metadata/mutations.js b/amd/src/metadata/mutations.js index fecbcdda9e0..245ecab03be 100644 --- a/amd/src/metadata/mutations.js +++ b/amd/src/metadata/mutations.js @@ -16,63 +16,18 @@ /** * Default mutation manager * - * @module mod_nosferatu/local/beginner/mutations - * @class mod_nosferatu/local/beginner/mutations - * @copyright 2021 Ferran Recio - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ class Mutations { - /** - * Bite a person. - * - * All mutations recive a StateManager object as a first parameter. Whith this object the mutation - * can acces the state (stateManager.state) but also set the read mode (statemanager.setReadOnly(true|false)). - * In next steps we will see some other stateManager features. But for now you don't need them. - * - * @param {StateManager} stateManager the current state manager - * @param {Number} personId the person id to bite - */ - bite(stateManager, personId) { - // The first thing we need to do is get the current state. + updateContributor(stateManager, id, firstName, LastName) { const state = stateManager.state; - // State is always on read mode. To change any value first we need to unlock it. stateManager.setReadOnly(false); - // Now we do as many state changes as we need. - state.people.get(personId).bitten = true; - // All mutations should restore the read mode. This will trigger all the reactive events. + state.contributor.get(id).firstName = firstName; + state.contributor.get(id).LastName = LastName; stateManager.setReadOnly(true); - } - - /** - * The cureAll mutation. - * - * @param {StateManager} stateManager the current state manager - */ - cureAll(stateManager) { - // We call our hipotetical webservice. - const result = this._callCureAll(stateManager.state); - // And now we send the results to the stateManager. - stateManager.processUpdates(result); - } - /** - * Ok. we don't have a webservice yet, so we fake it. - * - * @param {object} state if this was a real webservice we probably won't need the full state. - * @returns {array} the state updates object. - */ - _callCureAll(state) { - const result = []; - state.people.forEach(person => { - result.push({ - name: 'people', - action: 'update', - fields: { - ...person, - bitten: false, - } - }); - }); - return result; + console.log(state); } } diff --git a/templates/metadata.mustache b/templates/metadatacontent.mustache similarity index 59% rename from templates/metadata.mustache rename to templates/metadatacontent.mustache index fa7097820ac..2173e6da9a1 100644 --- a/templates/metadata.mustache +++ b/templates/metadatacontent.mustache @@ -19,12 +19,26 @@ { } }} -
+
    {{#contributor}}
  • {{firstName}} {{lastName}} + +
  • {{/contributor}}
-
\ No newline at end of file +
+
+ +
+
+
+{{#js}} +require(['qtype_stack/metadata/metadatacontent'], function(component) { + component.init('#qtype-stack-metadata-content'); +}); +{{/js}} \ No newline at end of file diff --git a/templates/metadatamodal.mustache b/templates/metadatamodal.mustache index b87ae053f77..628f5cf5f4b 100644 --- a/templates/metadatamodal.mustache +++ b/templates/metadatamodal.mustache @@ -33,7 +33,6 @@ {{$body}}
-
{{/body}} From 87bcb1b765187e912f66627119c58fdf61cae23b Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Mon, 1 Dec 2025 17:16:36 +0000 Subject: [PATCH 06/66] iss1171 - Display --- amd/build/metadata/container.min.js | 2 +- amd/build/metadata/container.min.js.map | 2 +- amd/build/metadata/mutations.min.js | 2 +- amd/build/metadata/mutations.min.js.map | 2 +- amd/src/metadata/container.js | 14 +++++++---- amd/src/metadata/mutations.js | 1 - amd/src/metadata/sample.json | 24 +++++++++++++++++++ lang/en/qtype_stack.php | 7 ++++++ styles.css | 9 ++++++- templates/metadatacontent.mustache | 32 ++++++++++++++++++------- templates/metadatamodal.mustache | 3 ++- 11 files changed, 78 insertions(+), 20 deletions(-) diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js index e317640a3f7..ce024847f72 100644 --- a/amd/build/metadata/container.min.js +++ b/amd/build/metadata/container.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/ * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state}),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}getWatchers(){return[{watch:"contributor:updated",handler:this.reloadContainerComponent}]}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:"",isPartOf:"",additional:[]};state.contributor.forEach((contributor=>{data.contributor.push({...contributor})}));const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data)}update(event){event.preventDefault();const first=this.getElement("#contributor-1-firstName").value,last=this.getElement("#contributor-1-lastName").value;this.reactive.dispatch("updateContributor",1,first,last)}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state}),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}getWatchers(){return[{watch:"*:updated",handler:this.reloadContainerComponent}]}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:state.creator,contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[]};state.contributor.forEach((contributor=>{data.contributor.push({...contributor})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})}));const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data)}update(event){event.preventDefault();const first=this.getElement("#contributor-1-firstName").value,last=this.getElement("#contributor-1-lastName").value;this.reactive.dispatch("updateContributor",1,first,last)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map index 86d64e7f1d5..bd8bbd91e5b 100644 --- a/amd/build/metadata/container.min.js.map +++ b/amd/build/metadata/container.min.js.map @@ -1 +1 @@ -{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n getWatchers() {\n return [\n {watch: `contributor:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: '',\n isPartOf: '',\n additional: []\n };\n state.contributor.forEach(contributor => {\n data.contributor.push({...contributor});\n });\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n // Get the selected person id.\n const first = this.getElement('#contributor-1-firstName').value;\n const last = this.getElement('#contributor-1-lastName').value;\n this.reactive.dispatch('updateContributor', 1, first, last);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","addEventListener","getElement","update","getWatchers","watch","handler","data","creator","contributor","language","license","isPartOf","additional","forEach","push","metadataContainer","Error","renderComponent","event","preventDefault","first","value","last","dispatch"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,aAChCE,iBACDR,KAAKS,WAAWT,KAAKJ,UAAUE,QAC/B,QACAE,KAAKU,QAIbC,oBACW,CACH,CAACC,4BAA8BC,QAASb,KAAKO,oEAItBD,MAACA,kBAGtBQ,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAAS,GACTC,SAAU,GACVC,WAAY,IAEhBd,MAAMU,YAAYK,SAAQL,cACtBF,KAAKE,YAAYM,KAAK,IAAIN,uBAIxBO,kBAAoBvB,KAAKS,WAAWT,KAAKJ,UAAUC,uBACpD0B,wBACK,IAAIC,MAAM,qCAGdxB,KAAKyB,gBAAgBF,kBAAmB,8BAA+BT,MAQjFJ,OAAOgB,OAEHA,MAAMC,uBAEAC,MAAQ5B,KAAKS,WAAW,4BAA4BoB,MACpDC,KAAO9B,KAAKS,WAAW,2BAA2BoB,WACnDzB,SAAS2B,SAAS,oBAAqB,EAAGH,MAAOE"} \ No newline at end of file +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n getWatchers() {\n return [\n {watch: `*:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: state.creator,\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: []\n };\n state.contributor.forEach(contributor => {\n data.contributor.push({...contributor});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n // Get the selected person id.\n const first = this.getElement('#contributor-1-firstName').value;\n const last = this.getElement('#contributor-1-lastName').value;\n this.reactive.dispatch('updateContributor', 1, first, last);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","addEventListener","getElement","update","getWatchers","watch","handler","data","creator","contributor","language","license","isPartOf","additional","forEach","push","metadataContainer","Error","renderComponent","event","preventDefault","first","value","last","dispatch"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,aAChCE,iBACDR,KAAKS,WAAWT,KAAKJ,UAAUE,QAC/B,QACAE,KAAKU,QAIbC,oBACW,CACH,CAACC,kBAAoBC,QAASb,KAAKO,oEAIZD,MAACA,kBAGtBQ,KAAO,CACTC,QAAST,MAAMS,QACfC,YAAa,GACbC,SAAU,GACVC,QAASZ,MAAMY,QACfC,SAAUb,MAAMa,SAChBC,WAAY,IAEhBd,MAAMU,YAAYK,SAAQL,cACtBF,KAAKE,YAAYM,KAAK,IAAIN,iBAE9BV,MAAMW,SAASI,SAAQJ,WACnBH,KAAKG,SAASK,KAAK,IAAIL,cAE3BX,MAAMc,WAAWC,SAAQD,aACrBN,KAAKM,WAAWE,KAAK,IAAIF,sBAIvBG,kBAAoBvB,KAAKS,WAAWT,KAAKJ,UAAUC,uBACpD0B,wBACK,IAAIC,MAAM,qCAGdxB,KAAKyB,gBAAgBF,kBAAmB,8BAA+BT,MAQjFJ,OAAOgB,OAEHA,MAAMC,uBAEAC,MAAQ5B,KAAKS,WAAW,4BAA4BoB,MACpDC,KAAO9B,KAAKS,WAAW,2BAA2BoB,WACnDzB,SAAS2B,SAAS,oBAAqB,EAAGH,MAAOE"} \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js b/amd/build/metadata/mutations.min.js index 4ae817100ad..a1c0a8226b0 100644 --- a/amd/build/metadata/mutations.min.js +++ b/amd/build/metadata/mutations.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/mutations",["exports"],(function(_exports){Object.d * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class{updateContributor(stateManager,id,firstName,LastName){const state=stateManager.state;stateManager.setReadOnly(!1),state.contributor.get(id).firstName=firstName,state.contributor.get(id).LastName=LastName,stateManager.setReadOnly(!0),console.log(state)}};_exports.mutations=mutations})); +class{updateContributor(stateManager,id,firstName,LastName){const state=stateManager.state;stateManager.setReadOnly(!1),state.contributor.get(id).firstName=firstName,state.contributor.get(id).LastName=LastName,stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js.map b/amd/build/metadata/mutations.min.js.map index 1f911254e81..a2b19b4d18a 100644 --- a/amd/build/metadata/mutations.min.js.map +++ b/amd/build/metadata/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateContributor(stateManager, id, firstName, LastName) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.contributor.get(id).firstName = firstName;\n state.contributor.get(id).LastName = LastName;\n stateManager.setReadOnly(true);\n console.log(state);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateContributor","stateManager","id","firstName","LastName","state","setReadOnly","contributor","get","console","log"],"mappings":"gKAiCaA,UAAY;;;;;;;;MAVrBC,kBAAkBC,aAAcC,GAAIC,UAAWC,gBACrCC,MAAQJ,aAAaI,MAC3BJ,aAAaK,aAAY,GACzBD,MAAME,YAAYC,IAAIN,IAAIC,UAAYA,UACtCE,MAAME,YAAYC,IAAIN,IAAIE,SAAWA,SACrCH,aAAaK,aAAY,GACzBG,QAAQC,IAAIL"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateContributor(stateManager, id, firstName, LastName) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.contributor.get(id).firstName = firstName;\n state.contributor.get(id).LastName = LastName;\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateContributor","stateManager","id","firstName","LastName","state","setReadOnly","contributor","get"],"mappings":"gKAgCaA,UAAY;;;;;;;;MATrBC,kBAAkBC,aAAcC,GAAIC,UAAWC,gBACrCC,MAAQJ,aAAaI,MAC3BJ,aAAaK,aAAY,GACzBD,MAAME,YAAYC,IAAIN,IAAIC,UAAYA,UACtCE,MAAME,YAAYC,IAAIN,IAAIE,SAAWA,SACrCH,aAAaK,aAAY"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js index 1885f08b900..26a0d91ec3d 100644 --- a/amd/src/metadata/container.js +++ b/amd/src/metadata/container.js @@ -64,7 +64,7 @@ export default class extends BaseComponent { getWatchers() { return [ - {watch: `contributor:updated`, handler: this.reloadContainerComponent}, + {watch: `*:updated`, handler: this.reloadContainerComponent}, ]; } @@ -72,16 +72,22 @@ export default class extends BaseComponent { // Mustache data is not fully compatible with state object so we need to convert it // into a plain object. const data = { - creator: {}, + creator: state.creator, contributor: [], language: [], - license: '', - isPartOf: '', + license: state.license, + isPartOf: state.isPartOf, additional: [] }; state.contributor.forEach(contributor => { data.contributor.push({...contributor}); }); + state.language.forEach(language => { + data.language.push({...language}); + }); + state.additional.forEach(additional => { + data.additional.push({...additional}); + }); // To render a child component we need a container. const metadataContainer = this.getElement(this.selectors.METADATACONTAINER); diff --git a/amd/src/metadata/mutations.js b/amd/src/metadata/mutations.js index 245ecab03be..c477bacfd0f 100644 --- a/amd/src/metadata/mutations.js +++ b/amd/src/metadata/mutations.js @@ -27,7 +27,6 @@ class Mutations { state.contributor.get(id).firstName = firstName; state.contributor.get(id).LastName = LastName; stateManager.setReadOnly(true); - console.log(state); } } diff --git a/amd/src/metadata/sample.json b/amd/src/metadata/sample.json index df5d7b61b65..73d47bec60e 100644 --- a/amd/src/metadata/sample.json +++ b/amd/src/metadata/sample.json @@ -20,5 +20,29 @@ "institution": "MIT", "year": 2025 } + ], + "language": [ + { + "id": "en" + }, + { + "id": "fr" + } + ], + "license": { + "value": "Creative Commons - NoDerivatives 4.0 International" + }, + "isPartOf": { + "value": "HELM" + }, + "additional": [ + { + "id": 1, + "scope": "EdmundsData", + "property": "tags", + "qualifier": "colour", + "value": "red" + } ] + } \ No newline at end of file diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php index 8d2aff06d2e..93be28029e7 100644 --- a/lang/en/qtype_stack.php +++ b/lang/en/qtype_stack.php @@ -410,6 +410,13 @@ $string['moodleerrors'] = 'You have errors related to Moodle\'s basic question setup.'; $string['stackerrors'] = 'You have errors in your question.'; $string['editmetadata'] = 'Edit metadata'; +$string['metadata'] = 'Metadata'; +$string['firstname'] = 'First name'; +$string['lastname'] = 'Last name'; +$string['institution'] = 'Institution'; +$string['year'] = 'Year'; +$string['contributor'] = 'Contributor'; +$string['creator'] = 'Creator'; // Strings used by input elements. $string['studentinputtoolong'] = 'Your input is longer than permitted by STACK.'; diff --git a/styles.css b/styles.css index fc2ae0809a3..2ae565c74ca 100644 --- a/styles.css +++ b/styles.css @@ -1278,4 +1278,11 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. .que .outcome, .que .comment { color: #44331b; -} \ No newline at end of file +} +.stack-metadata input { + width: 98%; +} +.stack-metadata .inputcol { + padding-left: 0px; + padding-right: 0px; +} diff --git a/templates/metadatacontent.mustache b/templates/metadatacontent.mustache index 2173e6da9a1..b1548e95131 100644 --- a/templates/metadatacontent.mustache +++ b/templates/metadatacontent.mustache @@ -20,15 +20,29 @@ } }}
-
    - {{#contributor}} -
  • - {{firstName}} {{lastName}} - - -
  • - {{/contributor}} -
+
+
+
{{#str}} firstname, qtype_stack {{/str}}
+
{{#str}} lastname, qtype_stack {{/str}}
+
{{#str}} institution, qtype_stack {{/str}}
+
{{#str}} year, qtype_stack {{/str}}
+
+
+
{{#str}} creator, qtype_stack {{/str}}
+
+
+
+
+
+ {{#contributor}} +
+
{{#str}} contributor, qtype_stack {{/str}}
+
+
+
+
+
+ {{/contributor}}
{{/contributor}} -
-
- +
+
+
+
+
+
+
+ +
-
+
+
{{#str}} contributor, qtype_stack {{/str}}
+
{{#json}}{{> core_form/element-textarea }}{{/json}}
+
+ {{#js}} require(['qtype_stack/metadata/metadatacontent'], function(component) { component.init('#qtype-stack-metadata-content'); From bb06d38aff7becbff5830eab9174eaf6a87b00b5 Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Wed, 3 Dec 2025 16:12:13 +0000 Subject: [PATCH 08/66] iss1171 - Update multiple --- amd/build/metadata/container.min.js | 2 +- amd/build/metadata/container.min.js.map | 2 +- amd/build/metadata/mutations.min.js | 2 +- amd/build/metadata/mutations.min.js.map | 2 +- amd/src/metadata/container.js | 107 ++++++++---------------- amd/src/metadata/mutations.js | 22 +++-- lang/en/qtype_stack.php | 1 + templates/metadatacontent.mustache | 41 ++++++--- 8 files changed, 89 insertions(+), 90 deletions(-) diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js index e982c320176..1304426691c 100644 --- a/amd/build/metadata/container.min.js +++ b/amd/build/metadata/container.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/ * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state}),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}getWatchers(){return[{watch:"contributor:updated",handler:this.reloadContainerComponent}]}async reloadContainerComponent(_ref){let{state:state}=_ref;console.log("Refresh");const data={creator:{},contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[],element:[]};state.contributor.forEach((contributor=>{const element={firstname:{required:!1,element:{hiddenlabel:"Contributor first name",value:contributor.firstName,wrapperid:"fitem_"+contributor.id+"_confirstname",id:"id_"+contributor.id+"_confirstname",name:contributor.id+"_confirstname"}},lastname:{required:!0,element:{hiddenlabel:"Contributor last name",value:contributor.lastName,wrapperid:"fitem_"+contributor.id+"_conlastname",id:"id_"+contributor.id+"_conlastname",name:contributor.id+"_conlastname"}},institution:{required:!1,element:{hiddenlabel:"Contributor institution",value:contributor.institution,wrapperid:"fitem_"+contributor.id+"_coninstitution",id:"id_"+contributor.id+"_coninstitution",name:contributor.id+"_coninstitution"}},year:{required:!1,element:{hiddenlabel:"Contributor year",value:contributor.year,wrapperid:"fitem_"+contributor.id+"_conyear",id:"id_"+contributor.id+"_conyear",name:contributor.id+"_conyear"}}};data.contributor.push({...element})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})})),data.element.push({hiddenlabel:"Course full name",required:!0,element:{wrapperid:"fitem_id_fullname",id:"id_fullname",name:"fullname"}}),data.creator=data.contributor[0],data.json={required:!0,element:{hiddenlabel:"JSON metadata",value:JSON.stringify(state),wrapperid:"fitem_metadata_json",id:"id_metadata_json",name:"metadata_json"}};const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data)}update(event){event.preventDefault();const elements=this.getElements('#qtype-stack-metadata-content input[aria-required="true"]');for(const element of elements)""===element.value?(0,_events.notifyFieldValidationFailure)(element,"Required"):element.classList.contains("is-invalid")&&(0,_events.notifyFieldValidationFailure)(element,"");const first=this.getElement("#id_2_confirstname").value,last=this.getElement("#id_2_conlastname").value;this.reactive.dispatch("updateContributor",2,first,last)}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state})}getWatchers(){return[{watch:"state:updated",handler:this.reloadContainerComponent}]}createDataElement(required,id,tag,value){return{required:required,element:{value:value,wrapperid:"fitem_smdi_"+id+"_"+tag,id:"smdi_"+id+"_"+tag,name:"smdi_"+id+"_"+tag}}}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[]};state.contributor.forEach((contributor=>{const element={firstname:this.createDataElement(!1,contributor.id,"contributor_firstName",contributor.firstName),lastname:this.createDataElement(!0,contributor.id,"contributor_lastName",contributor.lastName),institution:this.createDataElement(!1,contributor.id,"contributor_institution",contributor.institution),year:this.createDataElement(!1,contributor.id,"contributor_year",contributor.year)};data.contributor.push({...element})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})})),data.creator={firstname:this.createDataElement(!1,0,"creator_firstName",state.creator.firstName),lastname:this.createDataElement(!0,0,"creator_lastName",state.creator.lastName),institution:this.createDataElement(!1,0,"creator_institution",state.creator.institution),year:this.createDataElement(!1,0,"creator_year",state.creator.year)},data.json={required:!0,element:{value:JSON.stringify(state),attributes:'rows="10"',wrapperid:"fitem_metadata_json",id:"id_metadata_json",name:"metadata_json"}};const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}update(event){event.preventDefault();const requiredElements=this.getElements('#qtype-stack-metadata-content input[aria-required="true"]');for(const element of requiredElements)""===element.value?(0,_events.notifyFieldValidationFailure)(element,"Required"):element.classList.contains("is-invalid")&&(0,_events.notifyFieldValidationFailure)(element,"");let inputElements=this.getElements('#qtype-stack-metadata-content input[id^="smdi"]');inputElements=Array.from(inputElements).map((el=>[el.id,el.value])),this.reactive.dispatch("updateAll",inputElements)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map index 2d244fb2e62..af9cda7c680 100644 --- a/amd/build/metadata/container.min.js.map +++ b/amd/build/metadata/container.min.js.map @@ -1 +1 @@ -{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\nimport {notifyFieldValidationFailure} from 'core_form/events';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n getWatchers() {\n return [\n {watch: `contributor:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n async reloadContainerComponent({state}) {\n console.log('Refresh');\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const element = {\n hiddenlabel: \"Course full name\",\n required: true,\n element: {\n wrapperid: \"fitem_id_fullname\",\n id: \"id_fullname\",\n name: \"fullname\"\n }\n };\n\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: [],\n element: []\n };\n state.contributor.forEach(contributor => {\n const element = {\n firstname: {\n required: false,\n element: {\n hiddenlabel: \"Contributor first name\",\n value: contributor.firstName,\n wrapperid: \"fitem_\" + contributor.id + \"_confirstname\",\n id: 'id_' + contributor.id + \"_confirstname\",\n name: contributor.id + \"_confirstname\",\n }\n },\n lastname: {\n required: true,\n element: {\n hiddenlabel: \"Contributor last name\",\n value: contributor.lastName,\n wrapperid: \"fitem_\" + contributor.id + \"_conlastname\",\n id: 'id_' + contributor.id + \"_conlastname\",\n name: contributor.id + \"_conlastname\",\n }\n },\n institution: {\n required: false,\n element: {\n hiddenlabel: \"Contributor institution\",\n value: contributor.institution,\n wrapperid: \"fitem_\" + contributor.id + \"_coninstitution\",\n id: 'id_' + contributor.id + \"_coninstitution\",\n name: contributor.id + \"_coninstitution\",\n }\n },\n year: {\n required: false,\n element: {\n hiddenlabel: \"Contributor year\",\n value: contributor.year,\n wrapperid: \"fitem_\" + contributor.id + \"_conyear\",\n id: 'id_' + contributor.id + \"_conyear\",\n name: contributor.id + \"_conyear\",\n }\n }\n };\n data.contributor.push({...element});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n data.element.push(element);\n data.creator = data.contributor[0];\n data.json = {\n required: true,\n element: {\n hiddenlabel: \"JSON metadata\",\n value: JSON.stringify(state),\n wrapperid: \"fitem_metadata_json\",\n id: \"id_metadata_json\",\n name: \"metadata_json\",\n }\n };\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n const elements = this.getElements('#qtype-stack-metadata-content input[aria-required=\"true\"]');\n for (const element of elements) {\n if (element.value === '') {\n notifyFieldValidationFailure(element, 'Required');\n } else if (element.classList.contains('is-invalid')) {\n notifyFieldValidationFailure(element, '');\n }\n }\n // Get the selected person id.\n const first = this.getElement('#id_2_confirstname').value;\n const last = this.getElement('#id_2_conlastname').value;\n this.reactive.dispatch('updateContributor', 2, first, last);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","addEventListener","getElement","update","getWatchers","watch","handler","console","log","data","creator","contributor","language","license","isPartOf","additional","forEach","firstname","required","hiddenlabel","value","firstName","wrapperid","id","lastname","lastName","institution","year","push","json","JSON","stringify","metadataContainer","Error","renderComponent","event","preventDefault","elements","getElements","classList","contains","first","last","dispatch"],"mappings":";;;;;;;;uBA2B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,aAChCE,iBACDR,KAAKS,WAAWT,KAAKJ,UAAUE,QAC/B,QACAE,KAAKU,QAIbC,oBACW,CACH,CAACC,4BAA8BC,QAASb,KAAKO,oEAItBD,MAACA,YAC5BQ,QAAQC,IAAI,iBAaNC,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAASd,MAAMc,QACfC,SAAUf,MAAMe,SAChBC,WAAY,GACZrB,QAAS,IAEbK,MAAMY,YAAYK,SAAQL,oBAChBjB,QAAU,CACZuB,UAAW,CACPC,UAAU,EACVxB,QAAS,CACLyB,YAAa,yBACbC,MAAOT,YAAYU,UACnBC,UAAW,SAAWX,YAAYY,GAAK,gBACvCA,GAAI,MAAQZ,YAAYY,GAAK,gBAC7BnC,KAAMuB,YAAYY,GAAK,kBAG/BC,SAAU,CACNN,UAAU,EACVxB,QAAS,CACLyB,YAAa,wBACbC,MAAOT,YAAYc,SACnBH,UAAW,SAAWX,YAAYY,GAAK,eACvCA,GAAI,MAAQZ,YAAYY,GAAK,eAC7BnC,KAAMuB,YAAYY,GAAK,iBAG/BG,YAAa,CACTR,UAAU,EACVxB,QAAS,CACLyB,YAAa,0BACbC,MAAOT,YAAYe,YACnBJ,UAAW,SAAWX,YAAYY,GAAK,kBACvCA,GAAI,MAAQZ,YAAYY,GAAK,kBAC7BnC,KAAMuB,YAAYY,GAAK,oBAG/BI,KAAM,CACFT,UAAU,EACVxB,QAAS,CACLyB,YAAa,mBACbC,MAAOT,YAAYgB,KACnBL,UAAW,SAAWX,YAAYY,GAAK,WACvCA,GAAI,MAAQZ,YAAYY,GAAK,WAC7BnC,KAAMuB,YAAYY,GAAK,cAInCd,KAAKE,YAAYiB,KAAK,IAAIlC,aAE9BK,MAAMa,SAASI,SAAQJ,WACnBH,KAAKG,SAASgB,KAAK,IAAIhB,cAE3Bb,MAAMgB,WAAWC,SAAQD,aACrBN,KAAKM,WAAWa,KAAK,IAAIb,gBAE7BN,KAAKf,QAAQkC,KAtEG,CACZT,YAAa,mBACbD,UAAU,EACVxB,QAAS,CACL4B,UAAW,oBACXC,GAAI,cACJnC,KAAM,cAiEdqB,KAAKC,QAAUD,KAAKE,YAAY,GAChCF,KAAKoB,KAAO,CACRX,UAAU,EACVxB,QAAS,CACLyB,YAAa,gBACbC,MAAOU,KAAKC,UAAUhC,OACtBuB,UAAW,sBACXC,GAAI,mBACJnC,KAAM,wBAKR4C,kBAAoBvC,KAAKS,WAAWT,KAAKJ,UAAUC,uBACpD0C,wBACK,IAAIC,MAAM,qCAGdxC,KAAKyC,gBAAgBF,kBAAmB,8BAA+BvB,MAQjFN,OAAOgC,OAEHA,MAAMC,uBACAC,SAAW5C,KAAK6C,YAAY,iEAC7B,MAAM5C,WAAW2C,SACI,KAAlB3C,QAAQ0B,+CACqB1B,QAAS,YAC/BA,QAAQ6C,UAAUC,SAAS,wDACL9C,QAAS,UAIxC+C,MAAQhD,KAAKS,WAAW,sBAAsBkB,MAC9CsB,KAAOjD,KAAKS,WAAW,qBAAqBkB,WAC7CvB,SAAS8C,SAAS,oBAAqB,EAAGF,MAAOC"} \ No newline at end of file +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\nimport {notifyFieldValidationFailure} from 'core_form/events';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n }\n\n getWatchers() {\n return [\n {watch: `state:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n createDataElement(required, id, tag, value) {\n return {\n required: required,\n element: {\n value: value,\n wrapperid: 'fitem_smdi_' + id + '_' + tag,\n id: 'smdi_' + id + '_' + tag,\n name: 'smdi_' + id + '_' + tag,\n }\n };\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: []\n };\n state.contributor.forEach(contributor => {\n const element = {\n firstname: this.createDataElement(false, contributor.id, 'contributor_firstName', contributor.firstName),\n lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName),\n institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution),\n year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year),\n };\n data.contributor.push({...element});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n data.creator = {\n firstname: this.createDataElement(false, 0, 'creator_firstName', state.creator.firstName),\n lastname: this.createDataElement(true, 0, 'creator_lastName', state.creator.lastName),\n institution: this.createDataElement(false, 0, 'creator_institution', state.creator.institution),\n year: this.createDataElement(false, 0, 'creator_year', state.creator.year),\n };\n data.json = {\n required: true,\n element: {\n value: JSON.stringify(state),\n attributes: 'rows=\"10\"',\n wrapperid: 'fitem_metadata_json',\n id: 'id_metadata_json',\n name: 'metadata_json',\n }\n };\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n const requiredElements = this.getElements('#qtype-stack-metadata-content input[aria-required=\"true\"]');\n for (const element of requiredElements) {\n if (element.value === '') {\n notifyFieldValidationFailure(element, 'Required');\n } else if (element.classList.contains('is-invalid')) {\n notifyFieldValidationFailure(element, '');\n }\n }\n let inputElements = this.getElements('#qtype-stack-metadata-content input[id^=\"smdi\"]');\n inputElements = Array.from(inputElements).map((el) => [el.id, el.value]);\n this.reactive.dispatch('updateAll', inputElements);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","getWatchers","watch","handler","createDataElement","required","id","tag","value","wrapperid","data","creator","contributor","language","license","isPartOf","additional","forEach","firstname","firstName","lastname","lastName","institution","year","push","json","JSON","stringify","attributes","metadataContainer","getElement","Error","renderComponent","addEventListener","update","event","preventDefault","requiredElements","getElements","classList","contains","inputElements","Array","from","map","el","dispatch"],"mappings":";;;;;;;;uBA2B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,QAGzCE,oBACW,CACH,CAACC,sBAAwBC,QAASV,KAAKO,2BAI/CI,kBAAkBC,SAAUC,GAAIC,IAAKC,aAC1B,CACHH,SAAUA,SACVX,QAAS,CACLc,MAAOA,MACPC,UAAW,cAAgBH,GAAK,IAAMC,IACtCD,GAAI,QAAUA,GAAK,IAAMC,IACzBnB,KAAM,QAAUkB,GAAK,IAAMC,+CAKRR,MAACA,kBAGtBW,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAASf,MAAMe,QACfC,SAAUhB,MAAMgB,SAChBC,WAAY,IAEhBjB,MAAMa,YAAYK,SAAQL,oBAChBlB,QAAU,CACZwB,UAAWzB,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,wBAAyBM,YAAYO,WAC9FC,SAAU3B,KAAKW,mBAAkB,EAAMQ,YAAYN,GAAI,uBAAwBM,YAAYS,UAC3FC,YAAa7B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,0BAA2BM,YAAYU,aAClGC,KAAM9B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,mBAAoBM,YAAYW,OAExFb,KAAKE,YAAYY,KAAK,IAAI9B,aAE9BK,MAAMc,SAASI,SAAQJ,WACnBH,KAAKG,SAASW,KAAK,IAAIX,cAE3Bd,MAAMiB,WAAWC,SAAQD,aACrBN,KAAKM,WAAWQ,KAAK,IAAIR,gBAE7BN,KAAKC,QAAU,CACXO,UAAWzB,KAAKW,mBAAkB,EAAO,EAAG,oBAAqBL,MAAMY,QAAQQ,WAC/EC,SAAU3B,KAAKW,mBAAkB,EAAM,EAAG,mBAAoBL,MAAMY,QAAQU,UAC5EC,YAAa7B,KAAKW,mBAAkB,EAAO,EAAG,sBAAuBL,MAAMY,QAAQW,aACnFC,KAAM9B,KAAKW,mBAAkB,EAAO,EAAG,eAAgBL,MAAMY,QAAQY,OAEzEb,KAAKe,KAAO,CACRpB,UAAU,EACVX,QAAS,CACLc,MAAOkB,KAAKC,UAAU5B,OACtB6B,WAAY,YACZnB,UAAW,sBACXH,GAAI,mBACJlB,KAAM,wBAKRyC,kBAAoBpC,KAAKqC,WAAWrC,KAAKJ,UAAUC,uBACpDuC,wBACK,IAAIE,MAAM,qCAGdtC,KAAKuC,gBAAgBH,kBAAmB,8BAA+BnB,WACxEuB,iBACDxC,KAAKqC,WAAWrC,KAAKJ,UAAUE,QAC/B,QACAE,KAAKyC,QASbA,OAAOC,OAEHA,MAAMC,uBACAC,iBAAmB5C,KAAK6C,YAAY,iEACrC,MAAM5C,WAAW2C,iBACI,KAAlB3C,QAAQc,+CACqBd,QAAS,YAC/BA,QAAQ6C,UAAUC,SAAS,wDACL9C,QAAS,QAG1C+C,cAAgBhD,KAAK6C,YAAY,mDACrCG,cAAgBC,MAAMC,KAAKF,eAAeG,KAAKC,IAAO,CAACA,GAAGvC,GAAIuC,GAAGrC,cAC5DX,SAASiD,SAAS,YAAaL"} \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js b/amd/build/metadata/mutations.min.js index 27dc88e8e00..8613a030762 100644 --- a/amd/build/metadata/mutations.min.js +++ b/amd/build/metadata/mutations.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/mutations",["exports"],(function(_exports){Object.d * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class{updateContributor(stateManager,id,firstName,lastName){const state=stateManager.state;stateManager.setReadOnly(!1),state.contributor.get(id).firstName=firstName,state.contributor.get(id).lastName=lastName,stateManager.setReadOnly(!0),console.log(state.contributor.get(id).firstName),console.log(state.contributor.get(id).lastName),console.log(state)}};_exports.mutations=mutations})); +class{updateAll(stateManager,inputArray){const state=stateManager.state;stateManager.setReadOnly(!1);for(const field of inputArray){const parts=field[0].split("_"),id=parts[1],property=parts[2],subproperty=parts[3];if(console.log(property,subproperty,id),0!=id){const existing=state[property].get(id);existing&&(existing[subproperty]=field[1])}else state[property][subproperty]=field[1]}stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js.map b/amd/build/metadata/mutations.min.js.map index ea89a28c2ad..54baf5976a9 100644 --- a/amd/build/metadata/mutations.min.js.map +++ b/amd/build/metadata/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateContributor(stateManager, id, firstName, lastName) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.contributor.get(id).firstName = firstName;\n state.contributor.get(id).lastName = lastName;\n stateManager.setReadOnly(true);\n console.log(state.contributor.get(id).firstName);\n console.log(state.contributor.get(id).lastName);\n console.log(state);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateContributor","stateManager","id","firstName","lastName","state","setReadOnly","contributor","get","console","log"],"mappings":"gKAmCaA,UAAY;;;;;;;;MAZrBC,kBAAkBC,aAAcC,GAAIC,UAAWC,gBACrCC,MAAQJ,aAAaI,MAC3BJ,aAAaK,aAAY,GACzBD,MAAME,YAAYC,IAAIN,IAAIC,UAAYA,UACtCE,MAAME,YAAYC,IAAIN,IAAIE,SAAWA,SACrCH,aAAaK,aAAY,GACzBG,QAAQC,IAAIL,MAAME,YAAYC,IAAIN,IAAIC,WACtCM,QAAQC,IAAIL,MAAME,YAAYC,IAAIN,IAAIE,UACtCK,QAAQC,IAAIL"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateAll(stateManager, inputArray) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n for (const field of inputArray) {\n const parts = field[0].split('_');\n const id = parts[1];\n const property = parts[2];\n const subproperty = parts[3];\n console.log(property, subproperty, id);\n if (id != 0) {\n const existing = state[property].get(id);\n if (existing) {\n existing[subproperty] = field[1];\n }\n } else {\n state[property][subproperty] = field[1];\n }\n }\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateAll","stateManager","inputArray","state","setReadOnly","field","parts","split","id","property","subproperty","console","log","existing","get"],"mappings":"gKA6CaA,UAAY;;;;;;;;MAtBrBC,UAAUC,aAAcC,kBACdC,MAAQF,aAAaE,MAC3BF,aAAaG,aAAY,OACpB,MAAMC,SAASH,WAAY,OACtBI,MAAQD,MAAM,GAAGE,MAAM,KACvBC,GAAKF,MAAM,GACXG,SAAWH,MAAM,GACjBI,YAAcJ,MAAM,MAC1BK,QAAQC,IAAIH,SAAUC,YAAaF,IACzB,GAANA,GAAS,OACHK,SAAWV,MAAMM,UAAUK,IAAIN,IACjCK,WACAA,SAASH,aAAeL,MAAM,SAGlCF,MAAMM,UAAUC,aAAeL,MAAM,GAG7CJ,aAAaG,aAAY"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js index 826a23bd8eb..118ceb5179a 100644 --- a/amd/src/metadata/container.js +++ b/amd/src/metadata/container.js @@ -56,84 +56,43 @@ export default class extends BaseComponent { */ async stateReady(state) { await this.reloadContainerComponent({state}); - this.addEventListener( - this.getElement(this.selectors.SUBMIT), - 'click', - this.update - ); } getWatchers() { return [ - {watch: `contributor:updated`, handler: this.reloadContainerComponent}, + {watch: `state:updated`, handler: this.reloadContainerComponent}, ]; } - async reloadContainerComponent({state}) { - console.log('Refresh'); - // Mustache data is not fully compatible with state object so we need to convert it - // into a plain object. - const element = { - hiddenlabel: "Course full name", - required: true, + createDataElement(required, id, tag, value) { + return { + required: required, element: { - wrapperid: "fitem_id_fullname", - id: "id_fullname", - name: "fullname" + value: value, + wrapperid: 'fitem_smdi_' + id + '_' + tag, + id: 'smdi_' + id + '_' + tag, + name: 'smdi_' + id + '_' + tag, } }; + } + async reloadContainerComponent({state}) { + // Mustache data is not fully compatible with state object so we need to convert it + // into a plain object. const data = { creator: {}, contributor: [], language: [], license: state.license, isPartOf: state.isPartOf, - additional: [], - element: [] + additional: [] }; state.contributor.forEach(contributor => { const element = { - firstname: { - required: false, - element: { - hiddenlabel: "Contributor first name", - value: contributor.firstName, - wrapperid: "fitem_" + contributor.id + "_confirstname", - id: 'id_' + contributor.id + "_confirstname", - name: contributor.id + "_confirstname", - } - }, - lastname: { - required: true, - element: { - hiddenlabel: "Contributor last name", - value: contributor.lastName, - wrapperid: "fitem_" + contributor.id + "_conlastname", - id: 'id_' + contributor.id + "_conlastname", - name: contributor.id + "_conlastname", - } - }, - institution: { - required: false, - element: { - hiddenlabel: "Contributor institution", - value: contributor.institution, - wrapperid: "fitem_" + contributor.id + "_coninstitution", - id: 'id_' + contributor.id + "_coninstitution", - name: contributor.id + "_coninstitution", - } - }, - year: { - required: false, - element: { - hiddenlabel: "Contributor year", - value: contributor.year, - wrapperid: "fitem_" + contributor.id + "_conyear", - id: 'id_' + contributor.id + "_conyear", - name: contributor.id + "_conyear", - } - } + firstname: this.createDataElement(false, contributor.id, 'contributor_firstName', contributor.firstName), + lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName), + institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution), + year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year), }; data.contributor.push({...element}); }); @@ -143,16 +102,20 @@ export default class extends BaseComponent { state.additional.forEach(additional => { data.additional.push({...additional}); }); - data.element.push(element); - data.creator = data.contributor[0]; + data.creator = { + firstname: this.createDataElement(false, 0, 'creator_firstName', state.creator.firstName), + lastname: this.createDataElement(true, 0, 'creator_lastName', state.creator.lastName), + institution: this.createDataElement(false, 0, 'creator_institution', state.creator.institution), + year: this.createDataElement(false, 0, 'creator_year', state.creator.year), + }; data.json = { required: true, element: { - hiddenlabel: "JSON metadata", value: JSON.stringify(state), - wrapperid: "fitem_metadata_json", - id: "id_metadata_json", - name: "metadata_json", + attributes: 'rows="10"', + wrapperid: 'fitem_metadata_json', + id: 'id_metadata_json', + name: 'metadata_json', } }; @@ -163,6 +126,11 @@ export default class extends BaseComponent { } await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data); + this.addEventListener( + this.getElement(this.selectors.SUBMIT), + 'click', + this.update + ); } /** @@ -173,17 +141,16 @@ export default class extends BaseComponent { update(event) { // We don't want to submit the form. event.preventDefault(); - const elements = this.getElements('#qtype-stack-metadata-content input[aria-required="true"]'); - for (const element of elements) { + const requiredElements = this.getElements('#qtype-stack-metadata-content input[aria-required="true"]'); + for (const element of requiredElements) { if (element.value === '') { notifyFieldValidationFailure(element, 'Required'); } else if (element.classList.contains('is-invalid')) { notifyFieldValidationFailure(element, ''); } } - // Get the selected person id. - const first = this.getElement('#id_2_confirstname').value; - const last = this.getElement('#id_2_conlastname').value; - this.reactive.dispatch('updateContributor', 2, first, last); + let inputElements = this.getElements('#qtype-stack-metadata-content input[id^="smdi"]'); + inputElements = Array.from(inputElements).map((el) => [el.id, el.value]); + this.reactive.dispatch('updateAll', inputElements); } } \ No newline at end of file diff --git a/amd/src/metadata/mutations.js b/amd/src/metadata/mutations.js index d1a82b04471..b7a4e09cbdc 100644 --- a/amd/src/metadata/mutations.js +++ b/amd/src/metadata/mutations.js @@ -21,15 +21,25 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ class Mutations { - updateContributor(stateManager, id, firstName, lastName) { + updateAll(stateManager, inputArray) { const state = stateManager.state; stateManager.setReadOnly(false); - state.contributor.get(id).firstName = firstName; - state.contributor.get(id).lastName = lastName; + for (const field of inputArray) { + const parts = field[0].split('_'); + const id = parts[1]; + const property = parts[2]; + const subproperty = parts[3]; + console.log(property, subproperty, id); + if (id != 0) { + const existing = state[property].get(id); + if (existing) { + existing[subproperty] = field[1]; + } + } else { + state[property][subproperty] = field[1]; + } + } stateManager.setReadOnly(true); - console.log(state.contributor.get(id).firstName); - console.log(state.contributor.get(id).lastName); - console.log(state); } } diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php index f5abc02f02f..2683eaaf5c3 100644 --- a/lang/en/qtype_stack.php +++ b/lang/en/qtype_stack.php @@ -419,6 +419,7 @@ $string['creator'] = 'Creator'; $string['addcontributor'] = 'Add contributor'; $string['updateJSON'] = 'Update JSON'; +$string['JSONmetadata'] = 'JSON metadata'; // Strings used by input elements. $string['studentinputtoolong'] = 'Your input is longer than permitted by STACK.'; diff --git a/templates/metadatacontent.mustache b/templates/metadatacontent.mustache index 7161dd0fa1a..ddecdf6f16b 100644 --- a/templates/metadatacontent.mustache +++ b/templates/metadatacontent.mustache @@ -20,29 +20,29 @@ } }}
-
+
{{#str}} firstname, qtype_stack {{/str}}
{{#str}} lastname, qtype_stack {{/str}}
{{#str}} institution, qtype_stack {{/str}}
-
{{#str}} year, qtype_stack {{/str}}
+
{{#str}} year, qtype_stack {{/str}}
{{#creator}}
-
{{#str}} creator, qtype_stack {{/str}}
+
{{#str}} creator, qtype_stack {{/str}}
{{#firstname}}{{> core_form/element-text-inline }}{{/firstname}}
{{#lastname}}{{> core_form/element-text-inline }}{{/lastname}}
{{#institution}}{{> core_form/element-text-inline }}{{/institution}}
-
{{#year}}{{> core_form/element-text-inline }}{{/year}}
+
{{#year}}{{> core_form/element-text-inline }}{{/year}}
{{/creator}} {{#contributor}}
-
{{#str}} contributor, qtype_stack {{/str}}
+
{{#str}} contributor, qtype_stack {{/str}}
{{#firstname}}{{> core_form/element-text-inline }}{{/firstname}}
{{#lastname}}{{> core_form/element-text-inline }}{{/lastname}}
{{#institution}}{{> core_form/element-text-inline }}{{/institution}}
-
{{#year}}{{> core_form/element-text-inline }}{{/year}}
+
{{#year}}{{> core_form/element-text-inline }}{{/year}}
{{/contributor}} @@ -50,18 +50,39 @@
+
-
-
+
+
+
+
-
{{#str}} contributor, qtype_stack {{/str}}
-
{{#json}}{{> core_form/element-textarea }}{{/json}}
+
{{#str}} JSONmetadata, qtype_stack {{/str}}
+
+ {{#json}} + {{< core_form/element-template-inline }} + {{$element}} + + {{/element}} + {{/ core_form/element-template-inline }} + {{/json}} +
{{#js}} From 8acee22dab33908c06b8b61e3c4a3ebba7930201 Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Wed, 3 Dec 2025 16:56:39 +0000 Subject: [PATCH 09/66] iss1171 - Sub component --- amd/build/metadata/container.min.js | 2 +- amd/build/metadata/container.min.js.map | 2 +- amd/build/metadata/contributor.min.js | 11 ++++ amd/build/metadata/contributor.min.js.map | 1 + amd/build/metadata/metadatacontent.min.js | 2 +- amd/build/metadata/metadatacontent.min.js.map | 2 +- amd/build/metadata/mutations.min.js | 2 +- amd/build/metadata/mutations.min.js.map | 2 +- amd/src/metadata/container.js | 1 + amd/src/metadata/contributor.js | 51 +++++++++++++++++++ amd/src/metadata/metadatacontent.js | 13 ++++- amd/src/metadata/mutations.js | 1 - templates/metadatacontent.mustache | 9 +--- templates/metadatacontributor.mustache | 34 +++++++++++++ 14 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 amd/build/metadata/contributor.min.js create mode 100644 amd/build/metadata/contributor.min.js.map create mode 100644 amd/src/metadata/contributor.js create mode 100644 templates/metadatacontributor.mustache diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js index 1304426691c..0849fdbc7a5 100644 --- a/amd/build/metadata/container.min.js +++ b/amd/build/metadata/container.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/ * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state})}getWatchers(){return[{watch:"state:updated",handler:this.reloadContainerComponent}]}createDataElement(required,id,tag,value){return{required:required,element:{value:value,wrapperid:"fitem_smdi_"+id+"_"+tag,id:"smdi_"+id+"_"+tag,name:"smdi_"+id+"_"+tag}}}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[]};state.contributor.forEach((contributor=>{const element={firstname:this.createDataElement(!1,contributor.id,"contributor_firstName",contributor.firstName),lastname:this.createDataElement(!0,contributor.id,"contributor_lastName",contributor.lastName),institution:this.createDataElement(!1,contributor.id,"contributor_institution",contributor.institution),year:this.createDataElement(!1,contributor.id,"contributor_year",contributor.year)};data.contributor.push({...element})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})})),data.creator={firstname:this.createDataElement(!1,0,"creator_firstName",state.creator.firstName),lastname:this.createDataElement(!0,0,"creator_lastName",state.creator.lastName),institution:this.createDataElement(!1,0,"creator_institution",state.creator.institution),year:this.createDataElement(!1,0,"creator_year",state.creator.year)},data.json={required:!0,element:{value:JSON.stringify(state),attributes:'rows="10"',wrapperid:"fitem_metadata_json",id:"id_metadata_json",name:"metadata_json"}};const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}update(event){event.preventDefault();const requiredElements=this.getElements('#qtype-stack-metadata-content input[aria-required="true"]');for(const element of requiredElements)""===element.value?(0,_events.notifyFieldValidationFailure)(element,"Required"):element.classList.contains("is-invalid")&&(0,_events.notifyFieldValidationFailure)(element,"");let inputElements=this.getElements('#qtype-stack-metadata-content input[id^="smdi"]');inputElements=Array.from(inputElements).map((el=>[el.id,el.value])),this.reactive.dispatch("updateAll",inputElements)}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state})}getWatchers(){return[{watch:"state:updated",handler:this.reloadContainerComponent}]}createDataElement(required,id,tag,value){return{required:required,element:{value:value,wrapperid:"fitem_smdi_"+id+"_"+tag,id:"smdi_"+id+"_"+tag,name:"smdi_"+id+"_"+tag}}}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[]};state.contributor.forEach((contributor=>{const element={firstname:this.createDataElement(!1,contributor.id,"contributor_firstName",contributor.firstName),lastname:this.createDataElement(!0,contributor.id,"contributor_lastName",contributor.lastName),institution:this.createDataElement(!1,contributor.id,"contributor_institution",contributor.institution),year:this.createDataElement(!1,contributor.id,"contributor_year",contributor.year),id:contributor.id};data.contributor.push({...element})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})})),data.creator={firstname:this.createDataElement(!1,0,"creator_firstName",state.creator.firstName),lastname:this.createDataElement(!0,0,"creator_lastName",state.creator.lastName),institution:this.createDataElement(!1,0,"creator_institution",state.creator.institution),year:this.createDataElement(!1,0,"creator_year",state.creator.year)},data.json={required:!0,element:{value:JSON.stringify(state),attributes:'rows="10"',wrapperid:"fitem_metadata_json",id:"id_metadata_json",name:"metadata_json"}};const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}update(event){event.preventDefault();const requiredElements=this.getElements('#qtype-stack-metadata-content input[aria-required="true"]');for(const element of requiredElements)""===element.value?(0,_events.notifyFieldValidationFailure)(element,"Required"):element.classList.contains("is-invalid")&&(0,_events.notifyFieldValidationFailure)(element,"");let inputElements=this.getElements('#qtype-stack-metadata-content input[id^="smdi"]');inputElements=Array.from(inputElements).map((el=>[el.id,el.value])),this.reactive.dispatch("updateAll",inputElements)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map index af9cda7c680..c1d2f965485 100644 --- a/amd/build/metadata/container.min.js.map +++ b/amd/build/metadata/container.min.js.map @@ -1 +1 @@ -{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\nimport {notifyFieldValidationFailure} from 'core_form/events';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n }\n\n getWatchers() {\n return [\n {watch: `state:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n createDataElement(required, id, tag, value) {\n return {\n required: required,\n element: {\n value: value,\n wrapperid: 'fitem_smdi_' + id + '_' + tag,\n id: 'smdi_' + id + '_' + tag,\n name: 'smdi_' + id + '_' + tag,\n }\n };\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: []\n };\n state.contributor.forEach(contributor => {\n const element = {\n firstname: this.createDataElement(false, contributor.id, 'contributor_firstName', contributor.firstName),\n lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName),\n institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution),\n year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year),\n };\n data.contributor.push({...element});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n data.creator = {\n firstname: this.createDataElement(false, 0, 'creator_firstName', state.creator.firstName),\n lastname: this.createDataElement(true, 0, 'creator_lastName', state.creator.lastName),\n institution: this.createDataElement(false, 0, 'creator_institution', state.creator.institution),\n year: this.createDataElement(false, 0, 'creator_year', state.creator.year),\n };\n data.json = {\n required: true,\n element: {\n value: JSON.stringify(state),\n attributes: 'rows=\"10\"',\n wrapperid: 'fitem_metadata_json',\n id: 'id_metadata_json',\n name: 'metadata_json',\n }\n };\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n const requiredElements = this.getElements('#qtype-stack-metadata-content input[aria-required=\"true\"]');\n for (const element of requiredElements) {\n if (element.value === '') {\n notifyFieldValidationFailure(element, 'Required');\n } else if (element.classList.contains('is-invalid')) {\n notifyFieldValidationFailure(element, '');\n }\n }\n let inputElements = this.getElements('#qtype-stack-metadata-content input[id^=\"smdi\"]');\n inputElements = Array.from(inputElements).map((el) => [el.id, el.value]);\n this.reactive.dispatch('updateAll', inputElements);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","getWatchers","watch","handler","createDataElement","required","id","tag","value","wrapperid","data","creator","contributor","language","license","isPartOf","additional","forEach","firstname","firstName","lastname","lastName","institution","year","push","json","JSON","stringify","attributes","metadataContainer","getElement","Error","renderComponent","addEventListener","update","event","preventDefault","requiredElements","getElements","classList","contains","inputElements","Array","from","map","el","dispatch"],"mappings":";;;;;;;;uBA2B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,QAGzCE,oBACW,CACH,CAACC,sBAAwBC,QAASV,KAAKO,2BAI/CI,kBAAkBC,SAAUC,GAAIC,IAAKC,aAC1B,CACHH,SAAUA,SACVX,QAAS,CACLc,MAAOA,MACPC,UAAW,cAAgBH,GAAK,IAAMC,IACtCD,GAAI,QAAUA,GAAK,IAAMC,IACzBnB,KAAM,QAAUkB,GAAK,IAAMC,+CAKRR,MAACA,kBAGtBW,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAASf,MAAMe,QACfC,SAAUhB,MAAMgB,SAChBC,WAAY,IAEhBjB,MAAMa,YAAYK,SAAQL,oBAChBlB,QAAU,CACZwB,UAAWzB,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,wBAAyBM,YAAYO,WAC9FC,SAAU3B,KAAKW,mBAAkB,EAAMQ,YAAYN,GAAI,uBAAwBM,YAAYS,UAC3FC,YAAa7B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,0BAA2BM,YAAYU,aAClGC,KAAM9B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,mBAAoBM,YAAYW,OAExFb,KAAKE,YAAYY,KAAK,IAAI9B,aAE9BK,MAAMc,SAASI,SAAQJ,WACnBH,KAAKG,SAASW,KAAK,IAAIX,cAE3Bd,MAAMiB,WAAWC,SAAQD,aACrBN,KAAKM,WAAWQ,KAAK,IAAIR,gBAE7BN,KAAKC,QAAU,CACXO,UAAWzB,KAAKW,mBAAkB,EAAO,EAAG,oBAAqBL,MAAMY,QAAQQ,WAC/EC,SAAU3B,KAAKW,mBAAkB,EAAM,EAAG,mBAAoBL,MAAMY,QAAQU,UAC5EC,YAAa7B,KAAKW,mBAAkB,EAAO,EAAG,sBAAuBL,MAAMY,QAAQW,aACnFC,KAAM9B,KAAKW,mBAAkB,EAAO,EAAG,eAAgBL,MAAMY,QAAQY,OAEzEb,KAAKe,KAAO,CACRpB,UAAU,EACVX,QAAS,CACLc,MAAOkB,KAAKC,UAAU5B,OACtB6B,WAAY,YACZnB,UAAW,sBACXH,GAAI,mBACJlB,KAAM,wBAKRyC,kBAAoBpC,KAAKqC,WAAWrC,KAAKJ,UAAUC,uBACpDuC,wBACK,IAAIE,MAAM,qCAGdtC,KAAKuC,gBAAgBH,kBAAmB,8BAA+BnB,WACxEuB,iBACDxC,KAAKqC,WAAWrC,KAAKJ,UAAUE,QAC/B,QACAE,KAAKyC,QASbA,OAAOC,OAEHA,MAAMC,uBACAC,iBAAmB5C,KAAK6C,YAAY,iEACrC,MAAM5C,WAAW2C,iBACI,KAAlB3C,QAAQc,+CACqBd,QAAS,YAC/BA,QAAQ6C,UAAUC,SAAS,wDACL9C,QAAS,QAG1C+C,cAAgBhD,KAAK6C,YAAY,mDACrCG,cAAgBC,MAAMC,KAAKF,eAAeG,KAAKC,IAAO,CAACA,GAAGvC,GAAIuC,GAAGrC,cAC5DX,SAASiD,SAAS,YAAaL"} \ No newline at end of file +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\nimport {notifyFieldValidationFailure} from 'core_form/events';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n }\n\n getWatchers() {\n return [\n {watch: `state:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n createDataElement(required, id, tag, value) {\n return {\n required: required,\n element: {\n value: value,\n wrapperid: 'fitem_smdi_' + id + '_' + tag,\n id: 'smdi_' + id + '_' + tag,\n name: 'smdi_' + id + '_' + tag,\n }\n };\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: []\n };\n state.contributor.forEach(contributor => {\n const element = {\n firstname: this.createDataElement(false, contributor.id, 'contributor_firstName', contributor.firstName),\n lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName),\n institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution),\n year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year),\n id: contributor.id,\n };\n data.contributor.push({...element});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n data.creator = {\n firstname: this.createDataElement(false, 0, 'creator_firstName', state.creator.firstName),\n lastname: this.createDataElement(true, 0, 'creator_lastName', state.creator.lastName),\n institution: this.createDataElement(false, 0, 'creator_institution', state.creator.institution),\n year: this.createDataElement(false, 0, 'creator_year', state.creator.year),\n };\n data.json = {\n required: true,\n element: {\n value: JSON.stringify(state),\n attributes: 'rows=\"10\"',\n wrapperid: 'fitem_metadata_json',\n id: 'id_metadata_json',\n name: 'metadata_json',\n }\n };\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n const requiredElements = this.getElements('#qtype-stack-metadata-content input[aria-required=\"true\"]');\n for (const element of requiredElements) {\n if (element.value === '') {\n notifyFieldValidationFailure(element, 'Required');\n } else if (element.classList.contains('is-invalid')) {\n notifyFieldValidationFailure(element, '');\n }\n }\n let inputElements = this.getElements('#qtype-stack-metadata-content input[id^=\"smdi\"]');\n inputElements = Array.from(inputElements).map((el) => [el.id, el.value]);\n this.reactive.dispatch('updateAll', inputElements);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","getWatchers","watch","handler","createDataElement","required","id","tag","value","wrapperid","data","creator","contributor","language","license","isPartOf","additional","forEach","firstname","firstName","lastname","lastName","institution","year","push","json","JSON","stringify","attributes","metadataContainer","getElement","Error","renderComponent","addEventListener","update","event","preventDefault","requiredElements","getElements","classList","contains","inputElements","Array","from","map","el","dispatch"],"mappings":";;;;;;;;uBA2B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,QAGzCE,oBACW,CACH,CAACC,sBAAwBC,QAASV,KAAKO,2BAI/CI,kBAAkBC,SAAUC,GAAIC,IAAKC,aAC1B,CACHH,SAAUA,SACVX,QAAS,CACLc,MAAOA,MACPC,UAAW,cAAgBH,GAAK,IAAMC,IACtCD,GAAI,QAAUA,GAAK,IAAMC,IACzBnB,KAAM,QAAUkB,GAAK,IAAMC,+CAKRR,MAACA,kBAGtBW,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAASf,MAAMe,QACfC,SAAUhB,MAAMgB,SAChBC,WAAY,IAEhBjB,MAAMa,YAAYK,SAAQL,oBAChBlB,QAAU,CACZwB,UAAWzB,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,wBAAyBM,YAAYO,WAC9FC,SAAU3B,KAAKW,mBAAkB,EAAMQ,YAAYN,GAAI,uBAAwBM,YAAYS,UAC3FC,YAAa7B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,0BAA2BM,YAAYU,aAClGC,KAAM9B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,mBAAoBM,YAAYW,MACpFjB,GAAIM,YAAYN,IAEpBI,KAAKE,YAAYY,KAAK,IAAI9B,aAE9BK,MAAMc,SAASI,SAAQJ,WACnBH,KAAKG,SAASW,KAAK,IAAIX,cAE3Bd,MAAMiB,WAAWC,SAAQD,aACrBN,KAAKM,WAAWQ,KAAK,IAAIR,gBAE7BN,KAAKC,QAAU,CACXO,UAAWzB,KAAKW,mBAAkB,EAAO,EAAG,oBAAqBL,MAAMY,QAAQQ,WAC/EC,SAAU3B,KAAKW,mBAAkB,EAAM,EAAG,mBAAoBL,MAAMY,QAAQU,UAC5EC,YAAa7B,KAAKW,mBAAkB,EAAO,EAAG,sBAAuBL,MAAMY,QAAQW,aACnFC,KAAM9B,KAAKW,mBAAkB,EAAO,EAAG,eAAgBL,MAAMY,QAAQY,OAEzEb,KAAKe,KAAO,CACRpB,UAAU,EACVX,QAAS,CACLc,MAAOkB,KAAKC,UAAU5B,OACtB6B,WAAY,YACZnB,UAAW,sBACXH,GAAI,mBACJlB,KAAM,wBAKRyC,kBAAoBpC,KAAKqC,WAAWrC,KAAKJ,UAAUC,uBACpDuC,wBACK,IAAIE,MAAM,qCAGdtC,KAAKuC,gBAAgBH,kBAAmB,8BAA+BnB,WACxEuB,iBACDxC,KAAKqC,WAAWrC,KAAKJ,UAAUE,QAC/B,QACAE,KAAKyC,QASbA,OAAOC,OAEHA,MAAMC,uBACAC,iBAAmB5C,KAAK6C,YAAY,iEACrC,MAAM5C,WAAW2C,iBACI,KAAlB3C,QAAQc,+CACqBd,QAAS,YAC/BA,QAAQ6C,UAAUC,SAAS,wDACL9C,QAAS,QAG1C+C,cAAgBhD,KAAK6C,YAAY,mDACrCG,cAAgBC,MAAMC,KAAKF,eAAeG,KAAKC,IAAO,CAACA,GAAGvC,GAAIuC,GAAGrC,cAC5DX,SAASiD,SAAS,YAAaL"} \ No newline at end of file diff --git a/amd/build/metadata/contributor.min.js b/amd/build/metadata/contributor.min.js new file mode 100644 index 00000000000..13231b971a4 --- /dev/null +++ b/amd/build/metadata/contributor.min.js @@ -0,0 +1,11 @@ +define("qtype_stack/metadata/contributor",["exports","core/reactive","qtype_stack/metadata/metadata"],(function(_exports,_reactive,_metadata){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * Main STACK metadata component + * + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-contributor",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=contributor.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/contributor.min.js.map b/amd/build/metadata/contributor.min.js.map new file mode 100644 index 00000000000..c3573674ff1 --- /dev/null +++ b/amd/build/metadata/contributor.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"contributor.min.js","sources":["../../src/metadata/contributor.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-contributor';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,kCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/metadatacontent.min.js b/amd/build/metadata/metadatacontent.min.js index e22cdaefce3..4c14e535036 100644 --- a/amd/build/metadata/metadatacontent.min.js +++ b/amd/build/metadata/metadatacontent.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/metadatacontent",["exports","core/reactive","qtype_ * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-content",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-content",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",DELETE:"#smd_1_delete"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}stateReady(){this.addEventListener(this.getElement(this.selectors.DELETE),"click",this.delete)}delete(){console.log("Here")}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=metadatacontent.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatacontent.min.js.map b/amd/build/metadata/metadatacontent.min.js.map index 8e23b4bc6d9..34cd4b20103 100644 --- a/amd/build/metadata/metadatacontent.min.js.map +++ b/amd/build/metadata/metadatacontent.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadatacontent.min.js","sources":["../../src/metadata/metadatacontent.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-content';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,8BACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA"} \ No newline at end of file +{"version":3,"file":"metadatacontent.min.js","sources":["../../src/metadata/metadatacontent.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-content';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n DELETE: `#smd_1_delete`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n stateReady() {\n this.addEventListener(\n this.getElement(this.selectors.DELETE),\n 'click',\n this.delete\n );\n }\n\n delete() {\n console.log('Here');\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","DELETE","target","this","element","document","querySelector","reactive","metadata","stateReady","addEventListener","getElement","delete","console","log"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,8BACPC,UAAY,CACbC,sDACAC,oCAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,YAIRU,kBACSC,iBACDP,KAAKQ,WAAWR,KAAKJ,UAAUE,QAC/B,QACAE,KAAKS,QAIbA,SACIC,QAAQC,IAAI"} \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js b/amd/build/metadata/mutations.min.js index 8613a030762..6dd53b0b09c 100644 --- a/amd/build/metadata/mutations.min.js +++ b/amd/build/metadata/mutations.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/mutations",["exports"],(function(_exports){Object.d * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class{updateAll(stateManager,inputArray){const state=stateManager.state;stateManager.setReadOnly(!1);for(const field of inputArray){const parts=field[0].split("_"),id=parts[1],property=parts[2],subproperty=parts[3];if(console.log(property,subproperty,id),0!=id){const existing=state[property].get(id);existing&&(existing[subproperty]=field[1])}else state[property][subproperty]=field[1]}stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); +class{updateAll(stateManager,inputArray){const state=stateManager.state;stateManager.setReadOnly(!1);for(const field of inputArray){const parts=field[0].split("_"),id=parts[1],property=parts[2],subproperty=parts[3];if(0!=id){const existing=state[property].get(id);existing&&(existing[subproperty]=field[1])}else state[property][subproperty]=field[1]}stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js.map b/amd/build/metadata/mutations.min.js.map index 54baf5976a9..a613a7d985d 100644 --- a/amd/build/metadata/mutations.min.js.map +++ b/amd/build/metadata/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateAll(stateManager, inputArray) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n for (const field of inputArray) {\n const parts = field[0].split('_');\n const id = parts[1];\n const property = parts[2];\n const subproperty = parts[3];\n console.log(property, subproperty, id);\n if (id != 0) {\n const existing = state[property].get(id);\n if (existing) {\n existing[subproperty] = field[1];\n }\n } else {\n state[property][subproperty] = field[1];\n }\n }\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateAll","stateManager","inputArray","state","setReadOnly","field","parts","split","id","property","subproperty","console","log","existing","get"],"mappings":"gKA6CaA,UAAY;;;;;;;;MAtBrBC,UAAUC,aAAcC,kBACdC,MAAQF,aAAaE,MAC3BF,aAAaG,aAAY,OACpB,MAAMC,SAASH,WAAY,OACtBI,MAAQD,MAAM,GAAGE,MAAM,KACvBC,GAAKF,MAAM,GACXG,SAAWH,MAAM,GACjBI,YAAcJ,MAAM,MAC1BK,QAAQC,IAAIH,SAAUC,YAAaF,IACzB,GAANA,GAAS,OACHK,SAAWV,MAAMM,UAAUK,IAAIN,IACjCK,WACAA,SAASH,aAAeL,MAAM,SAGlCF,MAAMM,UAAUC,aAAeL,MAAM,GAG7CJ,aAAaG,aAAY"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateAll(stateManager, inputArray) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n for (const field of inputArray) {\n const parts = field[0].split('_');\n const id = parts[1];\n const property = parts[2];\n const subproperty = parts[3];\n if (id != 0) {\n const existing = state[property].get(id);\n if (existing) {\n existing[subproperty] = field[1];\n }\n } else {\n state[property][subproperty] = field[1];\n }\n }\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateAll","stateManager","inputArray","state","setReadOnly","field","parts","split","id","property","subproperty","existing","get"],"mappings":"gKA4CaA,UAAY;;;;;;;;MArBrBC,UAAUC,aAAcC,kBACdC,MAAQF,aAAaE,MAC3BF,aAAaG,aAAY,OACpB,MAAMC,SAASH,WAAY,OACtBI,MAAQD,MAAM,GAAGE,MAAM,KACvBC,GAAKF,MAAM,GACXG,SAAWH,MAAM,GACjBI,YAAcJ,MAAM,MAChB,GAANE,GAAS,OACHG,SAAWR,MAAMM,UAAUG,IAAIJ,IACjCG,WACAA,SAASD,aAAeL,MAAM,SAGlCF,MAAMM,UAAUC,aAAeL,MAAM,GAG7CJ,aAAaG,aAAY"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js index 118ceb5179a..11044b5a40d 100644 --- a/amd/src/metadata/container.js +++ b/amd/src/metadata/container.js @@ -93,6 +93,7 @@ export default class extends BaseComponent { lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName), institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution), year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year), + id: contributor.id, }; data.contributor.push({...element}); }); diff --git a/amd/src/metadata/contributor.js b/amd/src/metadata/contributor.js new file mode 100644 index 00000000000..d9e7d49bfe4 --- /dev/null +++ b/amd/src/metadata/contributor.js @@ -0,0 +1,51 @@ +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack 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. +// +// Stack 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 Stack. If not, see . + +/** + * Main STACK metadata component + * + * @module qtype_stack/metadata + * @copyright 2025 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ + +import {BaseComponent} from 'core/reactive'; +import {metadata} from 'qtype_stack/metadata/metadata'; + +export default class extends BaseComponent { + create() { + this.name = 'stack-metadata-contributor'; + this.selectors = { + METADATACONTAINER: `[data-for='qtype-stack-metadata']`, + SUBMIT: `#stack-metadata-update`, + }; + } + + /** + * Static method to create a component instance form the mustache template. + * + * @param {string} target the DOM main element or its ID + * @param {object} selectors optional css selector overrides + * @return {Component} + */ + static init(target, selectors) { + return new this({ + element: document.querySelector(target), + reactive: metadata, + selectors, + }); + } + +} \ No newline at end of file diff --git a/amd/src/metadata/metadatacontent.js b/amd/src/metadata/metadatacontent.js index 7caddf56840..d085f8fd213 100644 --- a/amd/src/metadata/metadatacontent.js +++ b/amd/src/metadata/metadatacontent.js @@ -29,7 +29,7 @@ export default class extends BaseComponent { this.name = 'stack-metadata-content'; this.selectors = { METADATACONTAINER: `[data-for='qtype-stack-metadata']`, - SUBMIT: `#stack-metadata-update`, + DELETE: `#smd_1_delete`, }; } @@ -48,4 +48,15 @@ export default class extends BaseComponent { }); } + stateReady() { + this.addEventListener( + this.getElement(this.selectors.DELETE), + 'click', + this.delete + ); + } + + delete() { + console.log('Here'); + } } \ No newline at end of file diff --git a/amd/src/metadata/mutations.js b/amd/src/metadata/mutations.js index b7a4e09cbdc..c5594c389e1 100644 --- a/amd/src/metadata/mutations.js +++ b/amd/src/metadata/mutations.js @@ -29,7 +29,6 @@ class Mutations { const id = parts[1]; const property = parts[2]; const subproperty = parts[3]; - console.log(property, subproperty, id); if (id != 0) { const existing = state[property].get(id); if (existing) { diff --git a/templates/metadatacontent.mustache b/templates/metadatacontent.mustache index ddecdf6f16b..6f8cc2393e6 100644 --- a/templates/metadatacontent.mustache +++ b/templates/metadatacontent.mustache @@ -37,14 +37,7 @@
{{/creator}} {{#contributor}} -
-
{{#str}} contributor, qtype_stack {{/str}}
-
{{#firstname}}{{> core_form/element-text-inline }}{{/firstname}}
-
{{#lastname}}{{> core_form/element-text-inline }}{{/lastname}}
-
{{#institution}}{{> core_form/element-text-inline }}{{/institution}}
-
{{#year}}{{> core_form/element-text-inline }}{{/year}}
-
-
+ {{>qtype_stack/metadatacontributor}} {{/contributor}}
diff --git a/templates/metadatacontributor.mustache b/templates/metadatacontributor.mustache new file mode 100644 index 00000000000..8d7a1e6bf53 --- /dev/null +++ b/templates/metadatacontributor.mustache @@ -0,0 +1,34 @@ +{{! + This file is part of Stack - http://stack.maths.ed.ac.uk/ + 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 . +}} +{{! + @template qtype_stack/metadata + + + Example context (json): + { + } +}} +
+
{{#str}} contributor, qtype_stack {{/str}}
+
{{#firstname}}{{> core_form/element-text-inline }}{{/firstname}}
+
{{#lastname}}{{> core_form/element-text-inline }}{{/lastname}}
+
{{#institution}}{{> core_form/element-text-inline }}{{/institution}}
+
{{#year}}{{> core_form/element-text-inline }}{{/year}}
+
+
+{{#js}} +require(['qtype_stack/metadata/metadatacontent'], function(component) { + component.init('#qtype-stack-metadata-contributor'); +}); +{{/js}} \ No newline at end of file From 161a6156075b7da66e6ced7b645988d6b9016497 Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Thu, 4 Dec 2025 12:18:52 +0000 Subject: [PATCH 10/66] iss1171 - Add/delete contributor. Basic update from JSON. --- amd/build/metadata/container.min.js | 2 +- amd/build/metadata/container.min.js.map | 2 +- amd/build/metadata/contributor.min.js | 2 +- amd/build/metadata/contributor.min.js.map | 2 +- amd/build/metadata/metadatacontent.min.js | 2 +- amd/build/metadata/metadatacontent.min.js.map | 2 +- amd/build/metadata/mutations.min.js | 2 +- amd/build/metadata/mutations.min.js.map | 2 +- amd/src/metadata/container.js | 26 ++++++++++++-- amd/src/metadata/contributor.js | 15 ++++++-- amd/src/metadata/metadatacontent.js | 14 +------- amd/src/metadata/mutations.js | 35 +++++++++++++++++++ lang/en/qtype_stack.php | 1 + templates/metadatacontent.mustache | 6 +++- templates/metadatacontributor.mustache | 8 ++--- 15 files changed, 90 insertions(+), 31 deletions(-) diff --git a/amd/build/metadata/container.min.js b/amd/build/metadata/container.min.js index 0849fdbc7a5..5c71d50a485 100644 --- a/amd/build/metadata/container.min.js +++ b/amd/build/metadata/container.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/container",["exports","core/reactive","qtype_stack/ * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state})}getWatchers(){return[{watch:"state:updated",handler:this.reloadContainerComponent}]}createDataElement(required,id,tag,value){return{required:required,element:{value:value,wrapperid:"fitem_smdi_"+id+"_"+tag,id:"smdi_"+id+"_"+tag,name:"smdi_"+id+"_"+tag}}}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[]};state.contributor.forEach((contributor=>{const element={firstname:this.createDataElement(!1,contributor.id,"contributor_firstName",contributor.firstName),lastname:this.createDataElement(!0,contributor.id,"contributor_lastName",contributor.lastName),institution:this.createDataElement(!1,contributor.id,"contributor_institution",contributor.institution),year:this.createDataElement(!1,contributor.id,"contributor_year",contributor.year),id:contributor.id};data.contributor.push({...element})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})})),data.creator={firstname:this.createDataElement(!1,0,"creator_firstName",state.creator.firstName),lastname:this.createDataElement(!0,0,"creator_lastName",state.creator.lastName),institution:this.createDataElement(!1,0,"creator_institution",state.creator.institution),year:this.createDataElement(!1,0,"creator_year",state.creator.year)},data.json={required:!0,element:{value:JSON.stringify(state),attributes:'rows="10"',wrapperid:"fitem_metadata_json",id:"id_metadata_json",name:"metadata_json"}};const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data),this.addEventListener(this.getElement(this.selectors.SUBMIT),"click",this.update)}update(event){event.preventDefault();const requiredElements=this.getElements('#qtype-stack-metadata-content input[aria-required="true"]');for(const element of requiredElements)""===element.value?(0,_events.notifyFieldValidationFailure)(element,"Required"):element.classList.contains("is-invalid")&&(0,_events.notifyFieldValidationFailure)(element,"");let inputElements=this.getElements('#qtype-stack-metadata-content input[id^="smdi"]');inputElements=Array.from(inputElements).map((el=>[el.id,el.value])),this.reactive.dispatch("updateAll",inputElements)}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-container",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",UPDATEJSON:"#stack-metadata-update",UPDATEINPUTS:"#stack-metadata-update-inputs",ADDCONTRIB:"#stack-metadata-add-contrib"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}async stateReady(state){await this.reloadContainerComponent({state:state})}getWatchers(){return[{watch:"state:updated",handler:this.reloadContainerComponent}]}createDataElement(required,id,tag,value){return{required:required,element:{value:value,wrapperid:"fitem_smdi_"+id+"_"+tag,id:"smdi_"+id+"_"+tag,name:"smdi_"+id+"_"+tag}}}async reloadContainerComponent(_ref){let{state:state}=_ref;const data={creator:{},contributor:[],language:[],license:state.license,isPartOf:state.isPartOf,additional:[]};state.contributor.forEach((contributor=>{const element={firstname:this.createDataElement(!1,contributor.id,"contributor_firstName",contributor.firstName),lastname:this.createDataElement(!0,contributor.id,"contributor_lastName",contributor.lastName),institution:this.createDataElement(!1,contributor.id,"contributor_institution",contributor.institution),year:this.createDataElement(!1,contributor.id,"contributor_year",contributor.year),id:contributor.id};data.contributor.push({...element})})),state.language.forEach((language=>{data.language.push({...language})})),state.additional.forEach((additional=>{data.additional.push({...additional})})),data.creator={firstname:this.createDataElement(!1,0,"creator_firstName",state.creator.firstName),lastname:this.createDataElement(!0,0,"creator_lastName",state.creator.lastName),institution:this.createDataElement(!1,0,"creator_institution",state.creator.institution),year:this.createDataElement(!1,0,"creator_year",state.creator.year)},data.json={required:!0,element:{value:JSON.stringify(state,null,4),attributes:'rows="10"',wrapperid:"fitem_metadata_json",id:"id_metadata_json",name:"metadata_json"}};const metadataContainer=this.getElement(this.selectors.METADATACONTAINER);if(!metadataContainer)throw new Error("Missing metadata container.");await this.renderComponent(metadataContainer,"qtype_stack/metadatacontent",data),this.addEventListener(this.getElement(this.selectors.UPDATEJSON),"click",this.update),this.addEventListener(this.getElement(this.selectors.ADDCONTRIB),"click",this.addContrib),this.addEventListener(this.getElement(this.selectors.UPDATEINPUTS),"click",this.updateInputs)}update(event){event.preventDefault();const requiredElements=this.getElements('#qtype-stack-metadata-content input[aria-required="true"]');for(const element of requiredElements)""===element.value?(0,_events.notifyFieldValidationFailure)(element,"Required"):element.classList.contains("is-invalid")&&(0,_events.notifyFieldValidationFailure)(element,"");let inputElements=this.getElements('#qtype-stack-metadata-content input[id^="smdi"]');inputElements=Array.from(inputElements).map((el=>[el.id,el.value])),this.reactive.dispatch("updateAll",inputElements)}addContrib(){this.reactive.dispatch("addContributor")}updateInputs(){this.reactive.dispatch("updateFromJson",this.getElement("#id_metadata_json").value)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=container.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/container.min.js.map b/amd/build/metadata/container.min.js.map index c1d2f965485..42f77c48c28 100644 --- a/amd/build/metadata/container.min.js.map +++ b/amd/build/metadata/container.min.js.map @@ -1 +1 @@ -{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\nimport {notifyFieldValidationFailure} from 'core_form/events';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n }\n\n getWatchers() {\n return [\n {watch: `state:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n createDataElement(required, id, tag, value) {\n return {\n required: required,\n element: {\n value: value,\n wrapperid: 'fitem_smdi_' + id + '_' + tag,\n id: 'smdi_' + id + '_' + tag,\n name: 'smdi_' + id + '_' + tag,\n }\n };\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: []\n };\n state.contributor.forEach(contributor => {\n const element = {\n firstname: this.createDataElement(false, contributor.id, 'contributor_firstName', contributor.firstName),\n lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName),\n institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution),\n year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year),\n id: contributor.id,\n };\n data.contributor.push({...element});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n data.creator = {\n firstname: this.createDataElement(false, 0, 'creator_firstName', state.creator.firstName),\n lastname: this.createDataElement(true, 0, 'creator_lastName', state.creator.lastName),\n institution: this.createDataElement(false, 0, 'creator_institution', state.creator.institution),\n year: this.createDataElement(false, 0, 'creator_year', state.creator.year),\n };\n data.json = {\n required: true,\n element: {\n value: JSON.stringify(state),\n attributes: 'rows=\"10\"',\n wrapperid: 'fitem_metadata_json',\n id: 'id_metadata_json',\n name: 'metadata_json',\n }\n };\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n this.addEventListener(\n this.getElement(this.selectors.SUBMIT),\n 'click',\n this.update\n );\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n const requiredElements = this.getElements('#qtype-stack-metadata-content input[aria-required=\"true\"]');\n for (const element of requiredElements) {\n if (element.value === '') {\n notifyFieldValidationFailure(element, 'Required');\n } else if (element.classList.contains('is-invalid')) {\n notifyFieldValidationFailure(element, '');\n }\n }\n let inputElements = this.getElements('#qtype-stack-metadata-content input[id^=\"smdi\"]');\n inputElements = Array.from(inputElements).map((el) => [el.id, el.value]);\n this.reactive.dispatch('updateAll', inputElements);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","getWatchers","watch","handler","createDataElement","required","id","tag","value","wrapperid","data","creator","contributor","language","license","isPartOf","additional","forEach","firstname","firstName","lastname","lastName","institution","year","push","json","JSON","stringify","attributes","metadataContainer","getElement","Error","renderComponent","addEventListener","update","event","preventDefault","requiredElements","getElements","classList","contains","inputElements","Array","from","map","el","dispatch"],"mappings":";;;;;;;;uBA2B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,6BASSU,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,QAGzCE,oBACW,CACH,CAACC,sBAAwBC,QAASV,KAAKO,2BAI/CI,kBAAkBC,SAAUC,GAAIC,IAAKC,aAC1B,CACHH,SAAUA,SACVX,QAAS,CACLc,MAAOA,MACPC,UAAW,cAAgBH,GAAK,IAAMC,IACtCD,GAAI,QAAUA,GAAK,IAAMC,IACzBnB,KAAM,QAAUkB,GAAK,IAAMC,+CAKRR,MAACA,kBAGtBW,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAASf,MAAMe,QACfC,SAAUhB,MAAMgB,SAChBC,WAAY,IAEhBjB,MAAMa,YAAYK,SAAQL,oBAChBlB,QAAU,CACZwB,UAAWzB,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,wBAAyBM,YAAYO,WAC9FC,SAAU3B,KAAKW,mBAAkB,EAAMQ,YAAYN,GAAI,uBAAwBM,YAAYS,UAC3FC,YAAa7B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,0BAA2BM,YAAYU,aAClGC,KAAM9B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,mBAAoBM,YAAYW,MACpFjB,GAAIM,YAAYN,IAEpBI,KAAKE,YAAYY,KAAK,IAAI9B,aAE9BK,MAAMc,SAASI,SAAQJ,WACnBH,KAAKG,SAASW,KAAK,IAAIX,cAE3Bd,MAAMiB,WAAWC,SAAQD,aACrBN,KAAKM,WAAWQ,KAAK,IAAIR,gBAE7BN,KAAKC,QAAU,CACXO,UAAWzB,KAAKW,mBAAkB,EAAO,EAAG,oBAAqBL,MAAMY,QAAQQ,WAC/EC,SAAU3B,KAAKW,mBAAkB,EAAM,EAAG,mBAAoBL,MAAMY,QAAQU,UAC5EC,YAAa7B,KAAKW,mBAAkB,EAAO,EAAG,sBAAuBL,MAAMY,QAAQW,aACnFC,KAAM9B,KAAKW,mBAAkB,EAAO,EAAG,eAAgBL,MAAMY,QAAQY,OAEzEb,KAAKe,KAAO,CACRpB,UAAU,EACVX,QAAS,CACLc,MAAOkB,KAAKC,UAAU5B,OACtB6B,WAAY,YACZnB,UAAW,sBACXH,GAAI,mBACJlB,KAAM,wBAKRyC,kBAAoBpC,KAAKqC,WAAWrC,KAAKJ,UAAUC,uBACpDuC,wBACK,IAAIE,MAAM,qCAGdtC,KAAKuC,gBAAgBH,kBAAmB,8BAA+BnB,WACxEuB,iBACDxC,KAAKqC,WAAWrC,KAAKJ,UAAUE,QAC/B,QACAE,KAAKyC,QASbA,OAAOC,OAEHA,MAAMC,uBACAC,iBAAmB5C,KAAK6C,YAAY,iEACrC,MAAM5C,WAAW2C,iBACI,KAAlB3C,QAAQc,+CACqBd,QAAS,YAC/BA,QAAQ6C,UAAUC,SAAS,wDACL9C,QAAS,QAG1C+C,cAAgBhD,KAAK6C,YAAY,mDACrCG,cAAgBC,MAAMC,KAAKF,eAAeG,KAAKC,IAAO,CAACA,GAAGvC,GAAIuC,GAAGrC,cAC5DX,SAASiD,SAAS,YAAaL"} \ No newline at end of file +{"version":3,"file":"container.min.js","sources":["../../src/metadata/container.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\nimport {notifyFieldValidationFailure} from 'core_form/events';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-container';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n UPDATEJSON: `#stack-metadata-update`,\n UPDATEINPUTS: `#stack-metadata-update-inputs`,\n ADDCONTRIB: `#stack-metadata-add-contrib`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n /**\n * Initial state ready method.\n *\n * @param {object} state the initial state\n */\n async stateReady(state) {\n await this.reloadContainerComponent({state});\n }\n\n getWatchers() {\n return [\n {watch: `state:updated`, handler: this.reloadContainerComponent},\n ];\n }\n\n createDataElement(required, id, tag, value) {\n return {\n required: required,\n element: {\n value: value,\n wrapperid: 'fitem_smdi_' + id + '_' + tag,\n id: 'smdi_' + id + '_' + tag,\n name: 'smdi_' + id + '_' + tag,\n }\n };\n }\n\n async reloadContainerComponent({state}) {\n // Mustache data is not fully compatible with state object so we need to convert it\n // into a plain object.\n const data = {\n creator: {},\n contributor: [],\n language: [],\n license: state.license,\n isPartOf: state.isPartOf,\n additional: []\n };\n state.contributor.forEach(contributor => {\n const element = {\n firstname: this.createDataElement(false, contributor.id, 'contributor_firstName', contributor.firstName),\n lastname: this.createDataElement(true, contributor.id, 'contributor_lastName', contributor.lastName),\n institution: this.createDataElement(false, contributor.id, 'contributor_institution', contributor.institution),\n year: this.createDataElement(false, contributor.id, 'contributor_year', contributor.year),\n id: contributor.id,\n };\n data.contributor.push({...element});\n });\n state.language.forEach(language => {\n data.language.push({...language});\n });\n state.additional.forEach(additional => {\n data.additional.push({...additional});\n });\n data.creator = {\n firstname: this.createDataElement(false, 0, 'creator_firstName', state.creator.firstName),\n lastname: this.createDataElement(true, 0, 'creator_lastName', state.creator.lastName),\n institution: this.createDataElement(false, 0, 'creator_institution', state.creator.institution),\n year: this.createDataElement(false, 0, 'creator_year', state.creator.year),\n };\n data.json = {\n required: true,\n element: {\n value: JSON.stringify(state, null, 4),\n attributes: 'rows=\"10\"',\n wrapperid: 'fitem_metadata_json',\n id: 'id_metadata_json',\n name: 'metadata_json',\n }\n };\n\n // To render a child component we need a container.\n const metadataContainer = this.getElement(this.selectors.METADATACONTAINER);\n if (!metadataContainer) {\n throw new Error('Missing metadata container.');\n }\n\n await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data);\n this.addEventListener(\n this.getElement(this.selectors.UPDATEJSON),\n 'click',\n this.update\n );\n this.addEventListener(\n this.getElement(this.selectors.ADDCONTRIB),\n 'click',\n this.addContrib\n );\n this.addEventListener(\n this.getElement(this.selectors.UPDATEINPUTS),\n 'click',\n this.updateInputs\n );\n }\n\n /**\n * Our submit handler.\n *\n * @param {Event} event the click event\n */\n update(event) {\n // We don't want to submit the form.\n event.preventDefault();\n const requiredElements = this.getElements('#qtype-stack-metadata-content input[aria-required=\"true\"]');\n for (const element of requiredElements) {\n if (element.value === '') {\n notifyFieldValidationFailure(element, 'Required');\n } else if (element.classList.contains('is-invalid')) {\n notifyFieldValidationFailure(element, '');\n }\n }\n let inputElements = this.getElements('#qtype-stack-metadata-content input[id^=\"smdi\"]');\n inputElements = Array.from(inputElements).map((el) => [el.id, el.value]);\n this.reactive.dispatch('updateAll', inputElements);\n }\n\n addContrib() {\n this.reactive.dispatch('addContributor');\n }\n\n updateInputs() {\n this.reactive.dispatch('updateFromJson', this.getElement('#id_metadata_json').value);\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","UPDATEJSON","UPDATEINPUTS","ADDCONTRIB","target","this","element","document","querySelector","reactive","metadata","state","reloadContainerComponent","getWatchers","watch","handler","createDataElement","required","id","tag","value","wrapperid","data","creator","contributor","language","license","isPartOf","additional","forEach","firstname","firstName","lastname","lastName","institution","year","push","json","JSON","stringify","attributes","metadataContainer","getElement","Error","renderComponent","addEventListener","update","addContrib","updateInputs","event","preventDefault","requiredElements","getElements","classList","contains","inputElements","Array","from","map","el","dispatch"],"mappings":";;;;;;;;uBA2B6BA,wBACzBC,cACSC,KAAO,gCACPC,UAAY,CACbC,sDACAC,oCACAC,6CACAC,sDAWIC,OAAQL,kBACT,IAAIM,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVX,UAAAA,6BASSY,aACPN,KAAKO,yBAAyB,CAACD,MAAAA,QAGzCE,oBACW,CACH,CAACC,sBAAwBC,QAASV,KAAKO,2BAI/CI,kBAAkBC,SAAUC,GAAIC,IAAKC,aAC1B,CACHH,SAAUA,SACVX,QAAS,CACLc,MAAOA,MACPC,UAAW,cAAgBH,GAAK,IAAMC,IACtCD,GAAI,QAAUA,GAAK,IAAMC,IACzBrB,KAAM,QAAUoB,GAAK,IAAMC,+CAKRR,MAACA,kBAGtBW,KAAO,CACTC,QAAS,GACTC,YAAa,GACbC,SAAU,GACVC,QAASf,MAAMe,QACfC,SAAUhB,MAAMgB,SAChBC,WAAY,IAEhBjB,MAAMa,YAAYK,SAAQL,oBAChBlB,QAAU,CACZwB,UAAWzB,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,wBAAyBM,YAAYO,WAC9FC,SAAU3B,KAAKW,mBAAkB,EAAMQ,YAAYN,GAAI,uBAAwBM,YAAYS,UAC3FC,YAAa7B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,0BAA2BM,YAAYU,aAClGC,KAAM9B,KAAKW,mBAAkB,EAAOQ,YAAYN,GAAI,mBAAoBM,YAAYW,MACpFjB,GAAIM,YAAYN,IAEpBI,KAAKE,YAAYY,KAAK,IAAI9B,aAE9BK,MAAMc,SAASI,SAAQJ,WACnBH,KAAKG,SAASW,KAAK,IAAIX,cAE3Bd,MAAMiB,WAAWC,SAAQD,aACrBN,KAAKM,WAAWQ,KAAK,IAAIR,gBAE7BN,KAAKC,QAAU,CACXO,UAAWzB,KAAKW,mBAAkB,EAAO,EAAG,oBAAqBL,MAAMY,QAAQQ,WAC/EC,SAAU3B,KAAKW,mBAAkB,EAAM,EAAG,mBAAoBL,MAAMY,QAAQU,UAC5EC,YAAa7B,KAAKW,mBAAkB,EAAO,EAAG,sBAAuBL,MAAMY,QAAQW,aACnFC,KAAM9B,KAAKW,mBAAkB,EAAO,EAAG,eAAgBL,MAAMY,QAAQY,OAEzEb,KAAKe,KAAO,CACRpB,UAAU,EACVX,QAAS,CACLc,MAAOkB,KAAKC,UAAU5B,MAAO,KAAM,GACnC6B,WAAY,YACZnB,UAAW,sBACXH,GAAI,mBACJpB,KAAM,wBAKR2C,kBAAoBpC,KAAKqC,WAAWrC,KAAKN,UAAUC,uBACpDyC,wBACK,IAAIE,MAAM,qCAGdtC,KAAKuC,gBAAgBH,kBAAmB,8BAA+BnB,WACxEuB,iBACDxC,KAAKqC,WAAWrC,KAAKN,UAAUE,YAC/B,QACAI,KAAKyC,aAEJD,iBACDxC,KAAKqC,WAAWrC,KAAKN,UAAUI,YAC/B,QACAE,KAAK0C,iBAEJF,iBACDxC,KAAKqC,WAAWrC,KAAKN,UAAUG,cAC/B,QACAG,KAAK2C,cASbF,OAAOG,OAEHA,MAAMC,uBACAC,iBAAmB9C,KAAK+C,YAAY,iEACrC,MAAM9C,WAAW6C,iBACI,KAAlB7C,QAAQc,+CACqBd,QAAS,YAC/BA,QAAQ+C,UAAUC,SAAS,wDACLhD,QAAS,QAG1CiD,cAAgBlD,KAAK+C,YAAY,mDACrCG,cAAgBC,MAAMC,KAAKF,eAAeG,KAAKC,IAAO,CAACA,GAAGzC,GAAIyC,GAAGvC,cAC5DX,SAASmD,SAAS,YAAaL,eAGxCR,kBACStC,SAASmD,SAAS,kBAG3BZ,oBACSvC,SAASmD,SAAS,iBAAkBvD,KAAKqC,WAAW,qBAAqBtB"} \ No newline at end of file diff --git a/amd/build/metadata/contributor.min.js b/amd/build/metadata/contributor.min.js index 13231b971a4..bf05385b359 100644 --- a/amd/build/metadata/contributor.min.js +++ b/amd/build/metadata/contributor.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/contributor",["exports","core/reactive","qtype_stac * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-contributor",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-contributor",this.selectors={DELETE:'[name="smd_delete"]'}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}stateReady(){this.addEventListener(this.getElement(this.selectors.DELETE),"click",this.delete)}delete(event){const id=event.target.id.split("_")[1];this.reactive.dispatch("deleteContributor",id)}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=contributor.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/contributor.min.js.map b/amd/build/metadata/contributor.min.js.map index c3573674ff1..82ae4cb7a1a 100644 --- a/amd/build/metadata/contributor.min.js.map +++ b/amd/build/metadata/contributor.min.js.map @@ -1 +1 @@ -{"version":3,"file":"contributor.min.js","sources":["../../src/metadata/contributor.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-contributor';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,kCACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA"} \ No newline at end of file +{"version":3,"file":"contributor.min.js","sources":["../../src/metadata/contributor.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-contributor';\n this.selectors = {\n DELETE: `[name=\"smd_delete\"]`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n stateReady() {\n this.addEventListener(\n this.getElement(this.selectors.DELETE),\n 'click',\n this.delete\n );\n }\n\n delete(event) {\n const id = event.target.id.split('_')[1];\n this.reactive.dispatch('deleteContributor', id);\n }\n}"],"names":["BaseComponent","create","name","selectors","DELETE","target","this","element","document","querySelector","reactive","metadata","stateReady","addEventListener","getElement","delete","event","id","split","dispatch"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,kCACPC,UAAY,CACbC,0CAWIC,OAAQF,kBACT,IAAIG,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVR,UAAAA,YAIRS,kBACSC,iBACDP,KAAKQ,WAAWR,KAAKH,UAAUC,QAC/B,QACAE,KAAKS,QAIbA,OAAOC,aACGC,GAAKD,MAAMX,OAAOY,GAAGC,MAAM,KAAK,QACjCR,SAASS,SAAS,oBAAqBF"} \ No newline at end of file diff --git a/amd/build/metadata/metadatacontent.min.js b/amd/build/metadata/metadatacontent.min.js index 4c14e535036..e22cdaefce3 100644 --- a/amd/build/metadata/metadatacontent.min.js +++ b/amd/build/metadata/metadatacontent.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/metadatacontent",["exports","core/reactive","qtype_ * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-content",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",DELETE:"#smd_1_delete"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}stateReady(){this.addEventListener(this.getElement(this.selectors.DELETE),"click",this.delete)}delete(){console.log("Here")}}return _exports.default=_default,_exports.default})); +class _default extends _reactive.BaseComponent{create(){this.name="stack-metadata-content",this.selectors={METADATACONTAINER:"[data-for='qtype-stack-metadata']",SUBMIT:"#stack-metadata-update"}}static init(target,selectors){return new this({element:document.querySelector(target),reactive:_metadata.metadata,selectors:selectors})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=metadatacontent.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/metadatacontent.min.js.map b/amd/build/metadata/metadatacontent.min.js.map index 34cd4b20103..9097b1acb22 100644 --- a/amd/build/metadata/metadatacontent.min.js.map +++ b/amd/build/metadata/metadatacontent.min.js.map @@ -1 +1 @@ -{"version":3,"file":"metadatacontent.min.js","sources":["../../src/metadata/metadatacontent.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-content';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n DELETE: `#smd_1_delete`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n\n stateReady() {\n this.addEventListener(\n this.getElement(this.selectors.DELETE),\n 'click',\n this.delete\n );\n }\n\n delete() {\n console.log('Here');\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","DELETE","target","this","element","document","querySelector","reactive","metadata","stateReady","addEventListener","getElement","delete","console","log"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,8BACPC,UAAY,CACbC,sDACAC,oCAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA,YAIRU,kBACSC,iBACDP,KAAKQ,WAAWR,KAAKJ,UAAUE,QAC/B,QACAE,KAAKS,QAIbA,SACIC,QAAQC,IAAI"} \ No newline at end of file +{"version":3,"file":"metadatacontent.min.js","sources":["../../src/metadata/metadatacontent.js"],"sourcesContent":["// This file is part of Stack - http://stack.maths.ed.ac.uk/\n//\n// Stack 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// Stack 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 Stack. If not, see .\n\n/**\n * Main STACK metadata component\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\n\nimport {BaseComponent} from 'core/reactive';\nimport {metadata} from 'qtype_stack/metadata/metadata';\n\nexport default class extends BaseComponent {\n create() {\n this.name = 'stack-metadata-content';\n this.selectors = {\n METADATACONTAINER: `[data-for='qtype-stack-metadata']`,\n SUBMIT: `#stack-metadata-update`,\n };\n }\n\n /**\n * Static method to create a component instance form the mustache template.\n *\n * @param {string} target the DOM main element or its ID\n * @param {object} selectors optional css selector overrides\n * @return {Component}\n */\n static init(target, selectors) {\n return new this({\n element: document.querySelector(target),\n reactive: metadata,\n selectors,\n });\n }\n}"],"names":["BaseComponent","create","name","selectors","METADATACONTAINER","SUBMIT","target","this","element","document","querySelector","reactive","metadata"],"mappings":";;;;;;;;uBA0B6BA,wBACzBC,cACSC,KAAO,8BACPC,UAAY,CACbC,sDACAC,6CAWIC,OAAQH,kBACT,IAAII,KAAK,CACZC,QAASC,SAASC,cAAcJ,QAChCK,SAAUC,mBACVT,UAAAA"} \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js b/amd/build/metadata/mutations.min.js index 6dd53b0b09c..7428e1cb022 100644 --- a/amd/build/metadata/mutations.min.js +++ b/amd/build/metadata/mutations.min.js @@ -6,6 +6,6 @@ define("qtype_stack/metadata/mutations",["exports"],(function(_exports){Object.d * @copyright 2025 University of Edinburgh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ -class{updateAll(stateManager,inputArray){const state=stateManager.state;stateManager.setReadOnly(!1);for(const field of inputArray){const parts=field[0].split("_"),id=parts[1],property=parts[2],subproperty=parts[3];if(0!=id){const existing=state[property].get(id);existing&&(existing[subproperty]=field[1])}else state[property][subproperty]=field[1]}stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); +class{updateAll(stateManager,inputArray){const state=stateManager.state;stateManager.setReadOnly(!1);for(const field of inputArray){const parts=field[0].split("_"),id=parts[1],property=parts[2],subproperty=parts[3];if(0!=id){const existing=state[property].get(id);existing&&(existing[subproperty]=field[1])}else state[property][subproperty]=field[1]}stateManager.setReadOnly(!0)}deleteContributor(stateManager,id){const state=stateManager.state;stateManager.setReadOnly(!1),state.contributor.delete(id),stateManager.setReadOnly(!0)}addContributor(stateManager){const state=stateManager.state,keys=Array.from(state.contributor);keys.sort(((a,b)=>b[0]-a[0]));const newCon={id:1+parseInt(keys[0][0]),firstName:"",lastName:"",institution:"",year:2025};console.log(keys),stateManager.setReadOnly(!1),state.contributor.add(newCon),stateManager.setReadOnly(!0),console.log(state.contributor)}updateFromJson(stateManager,data){const state=stateManager.state;data=JSON.parse(data),stateManager.setReadOnly(!1);for(const prop in data)state[prop]=data[prop];stateManager.setReadOnly(!0)}};_exports.mutations=mutations})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/metadata/mutations.min.js.map b/amd/build/metadata/mutations.min.js.map index a613a7d985d..cf0af30d9eb 100644 --- a/amd/build/metadata/mutations.min.js.map +++ b/amd/build/metadata/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateAll(stateManager, inputArray) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n for (const field of inputArray) {\n const parts = field[0].split('_');\n const id = parts[1];\n const property = parts[2];\n const subproperty = parts[3];\n if (id != 0) {\n const existing = state[property].get(id);\n if (existing) {\n existing[subproperty] = field[1];\n }\n } else {\n state[property][subproperty] = field[1];\n }\n }\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateAll","stateManager","inputArray","state","setReadOnly","field","parts","split","id","property","subproperty","existing","get"],"mappings":"gKA4CaA,UAAY;;;;;;;;MArBrBC,UAAUC,aAAcC,kBACdC,MAAQF,aAAaE,MAC3BF,aAAaG,aAAY,OACpB,MAAMC,SAASH,WAAY,OACtBI,MAAQD,MAAM,GAAGE,MAAM,KACvBC,GAAKF,MAAM,GACXG,SAAWH,MAAM,GACjBI,YAAcJ,MAAM,MAChB,GAANE,GAAS,OACHG,SAAWR,MAAMM,UAAUG,IAAIJ,IACjCG,WACAA,SAASD,aAAeL,MAAM,SAGlCF,MAAMM,UAAUC,aAAeL,MAAM,GAG7CJ,aAAaG,aAAY"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../../src/metadata/mutations.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 * Default mutation manager\n *\n * @module qtype_stack/metadata\n * @copyright 2025 University of Edinburgh\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.\n */\nclass Mutations {\n updateAll(stateManager, inputArray) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n for (const field of inputArray) {\n const parts = field[0].split('_');\n const id = parts[1];\n const property = parts[2];\n const subproperty = parts[3];\n if (id != 0) {\n const existing = state[property].get(id);\n if (existing) {\n existing[subproperty] = field[1];\n }\n } else {\n state[property][subproperty] = field[1];\n }\n }\n stateManager.setReadOnly(true);\n }\n deleteContributor(stateManager, id) {\n const state = stateManager.state;\n stateManager.setReadOnly(false);\n state.contributor.delete(id);\n stateManager.setReadOnly(true);\n }\n\n addContributor(stateManager) {\n const state = stateManager.state;\n const keys = Array.from(state.contributor);\n keys.sort((a, b) => b[0] - a[0]);\n\n const newCon = {\n id: 1 + parseInt(keys[0][0]),\n firstName: \"\",\n lastName: \"\",\n institution: \"\",\n year: 2025\n };\n console.log(keys);\n stateManager.setReadOnly(false);\n state.contributor.add(newCon);\n stateManager.setReadOnly(true);\n console.log(state.contributor);\n }\n\n updateFromJson(stateManager, data) {\n const state = stateManager.state;\n data = JSON.parse(data);\n stateManager.setReadOnly(false);\n for (const prop in data) {\n state[prop] = data[prop];\n }\n stateManager.setReadOnly(true);\n }\n}\n\nexport const mutations = new Mutations();"],"names":["mutations","updateAll","stateManager","inputArray","state","setReadOnly","field","parts","split","id","property","subproperty","existing","get","deleteContributor","contributor","delete","addContributor","keys","Array","from","sort","a","b","newCon","parseInt","firstName","lastName","institution","year","console","log","add","updateFromJson","data","JSON","parse","prop"],"mappings":"gKA+EaA,UAAY;;;;;;;;MAxDrBC,UAAUC,aAAcC,kBACdC,MAAQF,aAAaE,MAC3BF,aAAaG,aAAY,OACpB,MAAMC,SAASH,WAAY,OACtBI,MAAQD,MAAM,GAAGE,MAAM,KACvBC,GAAKF,MAAM,GACXG,SAAWH,MAAM,GACjBI,YAAcJ,MAAM,MAChB,GAANE,GAAS,OACHG,SAAWR,MAAMM,UAAUG,IAAIJ,IACjCG,WACAA,SAASD,aAAeL,MAAM,SAGlCF,MAAMM,UAAUC,aAAeL,MAAM,GAG7CJ,aAAaG,aAAY,GAE7BS,kBAAkBZ,aAAcO,UACtBL,MAAQF,aAAaE,MAC3BF,aAAaG,aAAY,GACzBD,MAAMW,YAAYC,OAAOP,IACzBP,aAAaG,aAAY,GAG7BY,eAAef,oBACLE,MAAQF,aAAaE,MACrBc,KAAOC,MAAMC,KAAKhB,MAAMW,aAC9BG,KAAKG,MAAK,CAACC,EAAGC,IAAMA,EAAE,GAAKD,EAAE,WAEvBE,OAAS,CACXf,GAAI,EAAIgB,SAASP,KAAK,GAAG,IACzBQ,UAAW,GACXC,SAAU,GACVC,YAAa,GACbC,KAAM,MAEVC,QAAQC,IAAIb,MACZhB,aAAaG,aAAY,GACzBD,MAAMW,YAAYiB,IAAIR,QACtBtB,aAAaG,aAAY,GACzByB,QAAQC,IAAI3B,MAAMW,aAGtBkB,eAAe/B,aAAcgC,YACnB9B,MAAQF,aAAaE,MAC3B8B,KAAOC,KAAKC,MAAMF,MAClBhC,aAAaG,aAAY,OACpB,MAAMgC,QAAQH,KACf9B,MAAMiC,MAAQH,KAAKG,MAEvBnC,aAAaG,aAAY"} \ No newline at end of file diff --git a/amd/src/metadata/container.js b/amd/src/metadata/container.js index 11044b5a40d..1fa6c04add9 100644 --- a/amd/src/metadata/container.js +++ b/amd/src/metadata/container.js @@ -30,7 +30,9 @@ export default class extends BaseComponent { this.name = 'stack-metadata-container'; this.selectors = { METADATACONTAINER: `[data-for='qtype-stack-metadata']`, - SUBMIT: `#stack-metadata-update`, + UPDATEJSON: `#stack-metadata-update`, + UPDATEINPUTS: `#stack-metadata-update-inputs`, + ADDCONTRIB: `#stack-metadata-add-contrib`, }; } @@ -112,7 +114,7 @@ export default class extends BaseComponent { data.json = { required: true, element: { - value: JSON.stringify(state), + value: JSON.stringify(state, null, 4), attributes: 'rows="10"', wrapperid: 'fitem_metadata_json', id: 'id_metadata_json', @@ -128,10 +130,20 @@ export default class extends BaseComponent { await this.renderComponent(metadataContainer, 'qtype_stack/metadatacontent', data); this.addEventListener( - this.getElement(this.selectors.SUBMIT), + this.getElement(this.selectors.UPDATEJSON), 'click', this.update ); + this.addEventListener( + this.getElement(this.selectors.ADDCONTRIB), + 'click', + this.addContrib + ); + this.addEventListener( + this.getElement(this.selectors.UPDATEINPUTS), + 'click', + this.updateInputs + ); } /** @@ -154,4 +166,12 @@ export default class extends BaseComponent { inputElements = Array.from(inputElements).map((el) => [el.id, el.value]); this.reactive.dispatch('updateAll', inputElements); } + + addContrib() { + this.reactive.dispatch('addContributor'); + } + + updateInputs() { + this.reactive.dispatch('updateFromJson', this.getElement('#id_metadata_json').value); + } } \ No newline at end of file diff --git a/amd/src/metadata/contributor.js b/amd/src/metadata/contributor.js index d9e7d49bfe4..1c29f301b7e 100644 --- a/amd/src/metadata/contributor.js +++ b/amd/src/metadata/contributor.js @@ -28,8 +28,7 @@ export default class extends BaseComponent { create() { this.name = 'stack-metadata-contributor'; this.selectors = { - METADATACONTAINER: `[data-for='qtype-stack-metadata']`, - SUBMIT: `#stack-metadata-update`, + DELETE: `[name="smd_delete"]`, }; } @@ -48,4 +47,16 @@ export default class extends BaseComponent { }); } + stateReady() { + this.addEventListener( + this.getElement(this.selectors.DELETE), + 'click', + this.delete + ); + } + + delete(event) { + const id = event.target.id.split('_')[1]; + this.reactive.dispatch('deleteContributor', id); + } } \ No newline at end of file diff --git a/amd/src/metadata/metadatacontent.js b/amd/src/metadata/metadatacontent.js index d085f8fd213..1f457a48a3c 100644 --- a/amd/src/metadata/metadatacontent.js +++ b/amd/src/metadata/metadatacontent.js @@ -29,7 +29,7 @@ export default class extends BaseComponent { this.name = 'stack-metadata-content'; this.selectors = { METADATACONTAINER: `[data-for='qtype-stack-metadata']`, - DELETE: `#smd_1_delete`, + SUBMIT: `#stack-metadata-update`, }; } @@ -47,16 +47,4 @@ export default class extends BaseComponent { selectors, }); } - - stateReady() { - this.addEventListener( - this.getElement(this.selectors.DELETE), - 'click', - this.delete - ); - } - - delete() { - console.log('Here'); - } } \ No newline at end of file diff --git a/amd/src/metadata/mutations.js b/amd/src/metadata/mutations.js index c5594c389e1..94ddbfb25d8 100644 --- a/amd/src/metadata/mutations.js +++ b/amd/src/metadata/mutations.js @@ -40,6 +40,41 @@ class Mutations { } stateManager.setReadOnly(true); } + deleteContributor(stateManager, id) { + const state = stateManager.state; + stateManager.setReadOnly(false); + state.contributor.delete(id); + stateManager.setReadOnly(true); + } + + addContributor(stateManager) { + const state = stateManager.state; + const keys = Array.from(state.contributor); + keys.sort((a, b) => b[0] - a[0]); + + const newCon = { + id: 1 + parseInt(keys[0][0]), + firstName: "", + lastName: "", + institution: "", + year: 2025 + }; + console.log(keys); + stateManager.setReadOnly(false); + state.contributor.add(newCon); + stateManager.setReadOnly(true); + console.log(state.contributor); + } + + updateFromJson(stateManager, data) { + const state = stateManager.state; + data = JSON.parse(data); + stateManager.setReadOnly(false); + for (const prop in data) { + state[prop] = data[prop]; + } + stateManager.setReadOnly(true); + } } export const mutations = new Mutations(); \ No newline at end of file diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php index 2683eaaf5c3..607a6273604 100644 --- a/lang/en/qtype_stack.php +++ b/lang/en/qtype_stack.php @@ -419,6 +419,7 @@ $string['creator'] = 'Creator'; $string['addcontributor'] = 'Add contributor'; $string['updateJSON'] = 'Update JSON'; +$string['updateinputs'] = 'Update inputs'; $string['JSONmetadata'] = 'JSON metadata'; // Strings used by input elements. diff --git a/templates/metadatacontent.mustache b/templates/metadatacontent.mustache index 6f8cc2393e6..88f8d9df583 100644 --- a/templates/metadatacontent.mustache +++ b/templates/metadatacontent.mustache @@ -41,7 +41,7 @@ {{/contributor}}
-
+

@@ -51,6 +51,9 @@ +
@@ -62,6 +65,7 @@ {{< core_form/element-template-inline }} {{$element}} + {{/element}} + {{/ core_form/element-template-inline }} + {{/freeform}} +
+
+