import { FSUploader } from "./SubmissionsClass/FSUploader.js"; import { HashesManager } from "./SubmissionsClass/HashesManager.js"; import { GameSelector } from "./SubmissionsClass/GameSelector.js"; import { MainImageManager } from "./SubmissionsClass/MainImageManager.js"; import { GalleryManager } from "./SubmissionsClass/GalleryManager.js"; import { Credits } from "./SubmissionsClass/Credits.js"; /** * If there is some server side errors. * We may need reload some things. * @type {boolean} */ const SERVER_SIDE_ERRORS = document.querySelector('meta[name="submission-has-errors"]')?.content === '1'; /** * Object map of errors messages * @type {Object} */ const ERROR_TABLE = { isUploading: "A file is uploading. Please wait.", noFiles: "Please select a file to upload", uploadError: "One or more files failed to upload.", notAllFilesDone: "Not all the files have finished uploading yet.", noModifications: "Please select at least a type of hack.", noSystems: "Please select at least a system.", noDescription: "Please provide a description.", noGame: "Please provide a game or create a new one and fill all the required fields.", noLanguages: "Please select at least a language.", noAuthors: "Please provide at least an author or create a new one and fill all the required fields.", noMainImage: "Please select a main image.", noGalleryImages: "Please select at least a gallery image.", isSubmitting: "The entry is already during submission." } /** * Current section. * @returns {string} * @constructor */ const SECTION = () => document.querySelector("meta[name='fs-section']")?.content ?? ''; const CSRF = () => document.querySelector("meta[name='csrf-token']")?.content ?? ''; window.FSUploader = FSUploader; window.HashesManager = HashesManager; window.GameSelector = GameSelector; window.MainImageManager = MainImageManager; window.GalleryManager = GalleryManager; window.Credits = Credits; /** * Verify if at least one checkbox is checked in this element. * @param {HTMLElement} element * @returns {boolean} */ function verifyCheckboxes( element ){ if( !parent ) return false; return Array.from(element.querySelectorAll('input[type="checkbox"]')).some(el => el.checked); } /** * Verify if an EasyMDE field is filled. * * @param {string} fieldName * @returns {boolean} */ function verifyMDE( fieldName ){ const textarea = document.querySelector('#field_' + fieldName); if( textarea && textarea.value.trim().length > 0 ) { return true; } const field = window['mde_' + fieldName] || null; return field && typeof field.value === 'function' && field.value().trim().length > 0; } window.SubmissionVerifications = { /** * Verify if we are in an upload. * @param {FSUploader} Uploader * @returns {boolean} */ step1_DuringFSUpload: function( Uploader ){ return !Uploader.isUploading; }, /** * Verify if at least one file is uploaded. * @param {FSUploader} Uploader * @returns {boolean} */ step2_NoFilesFSUpload: function( Uploader ){ return Uploader.numberOfFiles > 0; }, /** * Verify if any files haven't error. * @param {FSUploader} Uploader * @returns {boolean} */ step3_ErrorsFSUpload: function( Uploader ){ return !Uploader.hasErrors; }, /** * Check if all files are uploaded. * @param {FSUploader} Uploader * @returns {boolean} */ step4_AllFilesUploadedFSUpload: function( Uploader ){ return Uploader.allFilesUploaded; }, /** * Verify if at least one checkbox of romhacks modifications is checked. * @returns {boolean} */ step5_RomhacksModificationsCheckboxes: function(){ return verifyCheckboxes( document.querySelector( '#modifications-group' ) ); }, step5_UtilitiesSystemsCheckboxes: function(){ return verifyCheckboxes( document.querySelector( '#systems-group' ) ); }, /** * Verify if the description field has at least one character. * @returns {boolean} */ step6_VerifyDescription: function(){ return verifyMDE('description'); }, /** * Verify if a game is provided. * @param element this.$el * @returns {boolean} */ step7_VerifyGame: function( element ){ const GAME_SELECTOR_MODE = document.querySelector('input[name="game_selection_mode"]')?.value ?? "game"; if( GAME_SELECTOR_MODE === 'platform' || GAME_SELECTOR_MODE === 'none' ) return true; // Check if we have an already existent selected game. const GAME_ID_INPUT = document.querySelector('input[name="game_id"]'); if( GAME_ID_INPUT ){ if( GAME_ID_INPUT.value !== '' && Number(GAME_ID_INPUT.value) > 0){ return true; } } // Check if we have a new game. let gameSelector = element.querySelector('[x-data="GameSelector()"]'); gameSelector = gameSelector ? Alpine.$data(gameSelector) : null; if( gameSelector !== null ){ if( !gameSelector.name || !gameSelector.name.toString().trim().length ) return false; if( !gameSelector.platformId || gameSelector.platformId === '' || gameSelector.platformId === 0 ) return false; if( !gameSelector.genreId || gameSelector.genreId === '' || gameSelector.genreId === 0 ) return false; return true; } return false; }, /** * Verify if at least one checkbox of languages is checked. * @returns {boolean} */ step8_LanguagesCheckboxes: function(){ return verifyCheckboxes( document.querySelector( '#languages-group' ) ); }, /** * Verify if at least one (new) author has been filled. * @return {boolean} */ step9_verifyAuthors: function(){ const authorField = document.querySelectorAll('input[name="authors[]"]'); const newAuthorField = document.querySelectorAll('input[name="new-authors[]"]'); return ( authorField.length > 0 || newAuthorField.length > 0 ); }, /** * Verify if a main image has been uploaded. * @param element this.$el * @return {boolean} */ step10_verifyMainImage: function( element ){ let MainImageData = element.querySelector('[x-data="MainImageManager()"]'); MainImageData = MainImageData ? Alpine.$data(MainImageData) : null; if( ! MainImageData ){ return false; } return MainImageData.uploaded; }, /** * Verify if at least one image is uploaded in the gallery. * @param element this.$el * @return {boolean} */ step11_verifyGallery: function( element){ let GalleryData = element.querySelector('[x-data="GalleryManager()"]'); GalleryData = GalleryData ? Alpine.$data(GalleryData) : null; if( ! GalleryData ){ return false; } return GalleryData.number > 0 && GalleryData.allUploaded; } } /** * Handle entire submission process. */ window.Submission = function(){ return { /** * If the script is during a try of submission process. * @type {boolean} */ duringSubmissionProcess: false, /** * Error checked. * @type {string|null} */ errorKey: null, /** * Return error message. * @return {string} */ get errorMessage(){ return ERROR_TABLE[this.errorKey] ?? "Unknown error"; }, init(){ }, /** * Get current FSUploader if initialized. * * @returns {FSUploader|null} * @constructor */ get Uploader(){ const el = this.$el.querySelector('[x-data="FSUploader()"]'); return el ? Alpine.$data(el) : null; }, /** * Do each form verifications. * Update also this.errorKey. * * @returns {boolean} */ verifyForm(){ console.log( "Step 1" ); if( !SubmissionVerifications.step1_DuringFSUpload( this.Uploader ) ){ this.errorKey = "isUploading"; return false; } console.log( "Step 2" ); if( !SubmissionVerifications.step2_NoFilesFSUpload( this.Uploader ) ){ this.errorKey = "noFiles"; return false; } console.log( "Step 3" ); if( !SubmissionVerifications.step3_ErrorsFSUpload( this.Uploader ) ){ this.errorKey = "uploadError"; return false; } console.log( "Step 4" ); if( !SubmissionVerifications.step4_AllFilesUploadedFSUpload( this.Uploader ) ){ this.errorKey = "notAllFilesDone"; return false; } if( SECTION() === "romhacks" || SECTION() === "lua-scripts" ){ console.log( "Step 5" ); if( !SubmissionVerifications.step5_RomhacksModificationsCheckboxes()){ this.errorKey = "noModifications"; return false; } } else if( SECTION() === "utilities" ){ console.log( "Step 5" ); if( !SubmissionVerifications.step5_UtilitiesSystemsCheckboxes()){ this.errorKey = "noSystems"; return false; } } console.log( "Step 6" ); if( !SubmissionVerifications.step6_VerifyDescription() ){ this.errorKey = "noDescription"; return false; } console.log( "Step 7" ); if( !SubmissionVerifications.step7_VerifyGame( this.$el ) ){ this.errorKey = "noGame"; return false; } console.log( "Step 8" ); if( !SubmissionVerifications.step8_LanguagesCheckboxes()){ this.errorKey = "noLanguages"; return false; } console.log( "Step 9" ); if( !SubmissionVerifications.step9_verifyAuthors()){ this.errorKey = "noAuthors"; return false; } console.log( "Step 10" ); if( !SubmissionVerifications.step10_verifyMainImage( this.$el )){ this.errorKey = "noMainImage"; return false; } console.log( "Step 11" ); if( !SubmissionVerifications.step11_verifyGallery( this.$el )){ this.errorKey = "noGalleryImages"; return false; } return true; }, /** * Scroll to the specific error field. */ scrollToError(){ const refMap = { noFiles: 'uploadTarget', isUploading: 'uploadTarget', notAllFilesDone: 'uploadTarget', uploadError: 'uploadTarget', noModifications: 'modificationsGroup', noSystems: 'systemsGroup', noDescription: 'descriptionField', noGame: 'gameSelector', noLanguages: 'languagesGroup', noAuthors: 'authorsSelector', noMainImage: 'main-image-field', noGalleryImages: 'gallery-field', isSubmitting: 'submitButton' }; const target = this.$refs[refMap[this.errorKey]] || this.$el.querySelector('.upload-list') || this.$el.querySelector('.form-upload'); if (target) { target.scrollIntoView({behavior: 'smooth', block: 'center'}); return; } }, /** * If you want to submit the form. * @param {Event} e */ submitForm( e ){ if( this.duringSubmissionProcess ) return; // Don't submit two times. this.errorKey = null; // Reset. this.duringSubmissionProcess = true; const STATE = document.querySelector('select[name="submit-state"]')?.value; if( STATE === 'draft' ){ e.target.submit(); return; } if( !this.verifyForm() ){ this.scrollToError(); this.duringSubmissionProcess = false; return; } e.target.submit(); }, async requestFeatured( entryId ){ const csrf = CSRF(); const response = await fetch(`/api/entry/${entryId}/featured`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf } }); const json = await response.json(); const entry_featured_button = document.querySelector('#entry-featured-button'); const entry_featured_body = document.querySelector('#entry-featured-body'); if( json.success ){ entry_featured_body.innerHTML = '

Request submitted

'; entry_featured_button.style.display = 'none'; } else { entry_featured_body.innerHTML = '

Request failed. Please refresh the page and retry.

'; entry_featured_button.style.display = 'none'; } } } }