A lot of things
This commit is contained in:
85
resources/js/PlayOnlineAndPatcher.js
Normal file
85
resources/js/PlayOnlineAndPatcher.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import { RomPatcher } from './RomPatcher.js';
|
||||
|
||||
window.PlayOnline = function( initialPatches = {}, emulatorJsConfig = {} ){
|
||||
|
||||
const parent = RomPatcher( initialPatches );
|
||||
|
||||
return {
|
||||
|
||||
...parent,
|
||||
|
||||
currentBlobUrl: null,
|
||||
emuConfig: emulatorJsConfig,
|
||||
launchGame: false,
|
||||
|
||||
init(){
|
||||
parent.init({
|
||||
language: 'en',
|
||||
requireValidation: false,
|
||||
onpatch: this.handlePatchedRomFile.bind(this),
|
||||
});
|
||||
},
|
||||
|
||||
cleanEmulatorJsVars() {
|
||||
['EJS_player','EJS_core','EJS_gameUrl','EJS_pathtodata',
|
||||
'EJS_startOnLoaded','EJS_threads']
|
||||
.forEach(k => delete window[k]);
|
||||
},
|
||||
|
||||
prepareEmulatorJs(){
|
||||
window.EJS_player = '#game';
|
||||
window.EJS_core = this.emuConfig.core;
|
||||
window.EJS_gameUrl = this.currentBlobUrl;
|
||||
window.EJS_pathtodata = "https://cdn.emulatorjs.org/stable/data/";
|
||||
window.EJS_startOnLoaded = true;
|
||||
window.EJS_threads = this.emuConfig.threads ?? false;
|
||||
},
|
||||
|
||||
launchEmulatorJs(){
|
||||
if(!this.currentBlobUrl){
|
||||
console.error("EmulatorJS: Empty Blob field");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(this.currentBlobUrl);
|
||||
|
||||
this.cleanEmulatorJsVars();
|
||||
this.prepareEmulatorJs();
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.id = 'ejs-loader';
|
||||
script.src = 'https://cdn.emulatorjs.org/stable/data/loader.js';
|
||||
document.body.appendChild(script);
|
||||
|
||||
this.launchGame = true;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {BinFile} patchedRomFile
|
||||
*/
|
||||
handlePatchedRomFile( patchedRomFile ){
|
||||
|
||||
patchedRomFile.save = function(){
|
||||
// Remove save.
|
||||
return;
|
||||
}
|
||||
|
||||
const u8 = patchedRomFile._u8array;
|
||||
if( !u8 || u8.byteLength === 0 ){
|
||||
console.error("Patch error: Empty ROM file");
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.currentBlobUrl){
|
||||
URL.revokeObjectURL(this.currentBlobUrl);
|
||||
}
|
||||
|
||||
const blob = new Blob([u8], { type: 'application/octet-stream' });
|
||||
this.currentBlobUrl = URL.createObjectURL(blob);
|
||||
|
||||
this.launchEmulatorJs()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export function RomPatcher( initialPatches = {} ) {
|
||||
export const RomPatcher = function( initialPatches = {} ) {
|
||||
|
||||
let patchesArray = [];
|
||||
if (initialPatches) {
|
||||
@@ -39,9 +39,9 @@ export function RomPatcher( initialPatches = {} ) {
|
||||
patchesData: patchesArray,
|
||||
hasEmbedded: patchesArray.length > 0,
|
||||
|
||||
init() {
|
||||
init( config = {language: 'en', requireValidation: false} ) {
|
||||
|
||||
const CONFIG = {language: 'en', requireValidation: false};
|
||||
const CONFIG = config;
|
||||
|
||||
if (!RomPatcherWeb.isInitialized()){
|
||||
if (this.hasEmbedded) {
|
||||
@@ -112,3 +112,7 @@ export function RomPatcher( initialPatches = {} ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.RomPatcher = RomPatcher;
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
export const CHUNK_SIZE = 8192;
|
||||
|
||||
const PATCH_EXTENSIONS = new Set([
|
||||
'ips', 'bps', 'ups', 'aps', 'ppf', 'xdelta', "zip"
|
||||
]);
|
||||
|
||||
/**
|
||||
* An uploaded file instance.
|
||||
* Create a new file data.
|
||||
@@ -12,6 +16,8 @@ export const CHUNK_SIZE = 8192;
|
||||
*/
|
||||
export function FSFileData(name, totalChunks, rawFile ) {
|
||||
|
||||
const extension = name.split('.').pop().toLowerCase();
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
@@ -66,6 +72,8 @@ export function FSFileData(name, totalChunks, rawFile ) {
|
||||
*/
|
||||
state: 'public',
|
||||
|
||||
can_be_online_patched: PATCH_EXTENSIONS.has(extension),
|
||||
|
||||
/**
|
||||
* If the online patcher is enabled
|
||||
*/
|
||||
@@ -76,6 +84,21 @@ export function FSFileData(name, totalChunks, rawFile ) {
|
||||
*/
|
||||
meta_secondary_online_patcher: false,
|
||||
|
||||
/**
|
||||
* If this patch can be played online.
|
||||
*/
|
||||
meta_play_online: false,
|
||||
|
||||
/**
|
||||
* Selected core for play online
|
||||
*/
|
||||
meta_play_online_core: null,
|
||||
|
||||
/**
|
||||
* If the threads are enabled for playing online.
|
||||
*/
|
||||
meta_play_online_threads: null,
|
||||
|
||||
/**
|
||||
* Look if this file is currently uploading.
|
||||
* @returns {boolean}
|
||||
@@ -164,6 +187,6 @@ export function FSFileData(name, totalChunks, rawFile ) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ export function GalleryManager() {
|
||||
*/
|
||||
images: [],
|
||||
|
||||
dragSrcI: null,
|
||||
|
||||
/**
|
||||
* Forward to this.images.length
|
||||
* @returns {number}
|
||||
@@ -123,6 +125,25 @@ export function GalleryManager() {
|
||||
handleRemoveFile(index){
|
||||
this.images[index].handleRemoveFile(null);
|
||||
this.images.splice(index, 1);
|
||||
},
|
||||
|
||||
dragStart(index){
|
||||
this.dragSrcI = index;
|
||||
},
|
||||
|
||||
dragOver(e, index){
|
||||
e.preventDefault();
|
||||
|
||||
if( this.dragSrcI === null || this.dragSrcI === index )
|
||||
return;
|
||||
|
||||
const moved = this.images.splice(this.dragSrcI, 1)[0];
|
||||
this.images.splice(index, 0, moved);
|
||||
this.dragSrcI = index;
|
||||
},
|
||||
|
||||
dragEnd(){
|
||||
this.dragSrcI = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import hovercard from "./hovercard.js";
|
||||
import notifications from "./notifications.js";
|
||||
import conversations from "./conversations.js";
|
||||
import settings from "./settings.js";
|
||||
import {RomPatcher} from "./RomPatcher.js";
|
||||
|
||||
/**
|
||||
* Get config defined in meta.blade.php
|
||||
@@ -15,7 +14,7 @@ import {RomPatcher} from "./RomPatcher.js";
|
||||
* @return {string|null}
|
||||
*/
|
||||
window.getConfig = function( key ){
|
||||
return document.querySelector('meta[name="config-' + key + '"]').getAttribute('content') ?? null;
|
||||
return document.querySelector('meta[name="config-' + key + '"]')?.getAttribute('content') ?? null;
|
||||
}
|
||||
|
||||
// Lucide icons.
|
||||
@@ -44,6 +43,3 @@ Alpine.store('conversations', conversations() );
|
||||
|
||||
// Settings
|
||||
Alpine.store('settings', settings() );
|
||||
|
||||
// ROMPatcher
|
||||
window.RomPatcher = RomPatcher;
|
||||
|
||||
169
resources/js/news-submissions.js
Normal file
169
resources/js/news-submissions.js
Normal file
@@ -0,0 +1,169 @@
|
||||
import { GalleryManager } from "./SubmissionsClass/GalleryManager.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<string,string>}
|
||||
*/
|
||||
const ERROR_TABLE = {
|
||||
noDescription: "Please provide a description.",
|
||||
noGalleryImages: "Please select at least a gallery image.",
|
||||
isSubmitting: "The entry is already during submission."
|
||||
}
|
||||
|
||||
window.GalleryManager = GalleryManager;
|
||||
|
||||
/**
|
||||
* 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 the description field has at least one character.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
step1_VerifyDescription: function(){
|
||||
return verifyMDE('description');
|
||||
},
|
||||
|
||||
/**
|
||||
* Verify if at least one image is uploaded in the gallery.
|
||||
* @param element this.$el
|
||||
* @return {boolean}
|
||||
*/
|
||||
step2_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.NewsSubmission = 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(){
|
||||
},
|
||||
|
||||
/**
|
||||
* Do each form verifications.
|
||||
* Update also this.errorKey.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
verifyForm(){
|
||||
|
||||
console.log( "Step 1" );
|
||||
if( !SubmissionVerifications.step1_VerifyDescription() ){
|
||||
this.errorKey = "noDescription";
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log( "Step 2" );
|
||||
if( !SubmissionVerifications.step2_verifyGallery( this.$el )){
|
||||
this.errorKey = "noGalleryImages";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll to the specific error field.
|
||||
*/
|
||||
scrollToError(){
|
||||
const refMap = {
|
||||
noDescription: 'descriptionField',
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -14,20 +14,15 @@ export default function settings() {
|
||||
*/
|
||||
xfUrls: {},
|
||||
|
||||
/**
|
||||
* @type {number[]}
|
||||
*/
|
||||
entriesPerPage: [ 12, 30, 48 ],
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
currentTheme: Cookies.get("theme") ?? 'default',
|
||||
currentTheme: 'default',
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @type {list|null}
|
||||
*/
|
||||
currentEntriesPerPage: Cookies.get("entries_per_page") ?? 30,
|
||||
currentActivityFilters: null,
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -43,7 +38,7 @@ export default function settings() {
|
||||
this.currentTheme = newTheme;
|
||||
document.documentElement.classList.toggle('light-mode', this.currentTheme === 'alternate');
|
||||
|
||||
Cookies.set('theme', this.currentTheme, { expires: 365, path: '/', domain: window.getConfig('session-domain') } );
|
||||
// Cookies.set('theme', this.currentTheme, { expires: 365, path: '/', domain: window.getConfig('session-domain') } );
|
||||
this.syncXF();
|
||||
},
|
||||
|
||||
@@ -62,22 +57,48 @@ export default function settings() {
|
||||
this.themeChanged(this.currentTheme === 'default' ? 'alternate' : 'default');
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param n
|
||||
*/
|
||||
entriesPerPageChanged( n ){
|
||||
if( !this.entriesPerPage.includes(n) )
|
||||
return;
|
||||
|
||||
this.entriesPerPage = n;
|
||||
Cookies.set('entries_per_page', this.entriesPerPage, { expires: 365, path: '/', domain: window.getConfig('session-domain') } );
|
||||
if( window.Livewire ){
|
||||
Livewire.dispatch('entriesPerPageChanged', {n});
|
||||
}
|
||||
},
|
||||
|
||||
open(){ this.start = !this.start; },
|
||||
close(){ this.start = false; },
|
||||
|
||||
async toggleActivityFilter( type ){
|
||||
|
||||
if( this.currentActivityFilters === null )
|
||||
return;
|
||||
|
||||
const i = this.currentActivityFilters.indexOf( type );
|
||||
if( i !== -1 && this.currentActivityFilters.length === 1)
|
||||
return;
|
||||
|
||||
if( i === -1 )
|
||||
this.currentActivityFilters.push( type );
|
||||
else
|
||||
this.currentActivityFilters.splice( i, 1 );
|
||||
|
||||
Cookies.set( 'activity_filters', JSON.stringify(this.currentActivityFilters), { expires: 365, path: '/', domain: window.getConfig('session-domain') } );
|
||||
await this.syncTimeline();
|
||||
},
|
||||
|
||||
async syncTimeline(){
|
||||
|
||||
const tl = document.getElementById('activity-timeline');
|
||||
if( !tl )
|
||||
return;
|
||||
|
||||
tl.style.opacity = 0.5;
|
||||
|
||||
const params = this.currentActivityFilters.join(',');
|
||||
const response = await fetch(`/api/dynamic/activity/feed?filters=${params}`);
|
||||
const data = await response.json();
|
||||
|
||||
if( !data.html )
|
||||
return;
|
||||
|
||||
tl.innerHTML = data.html;
|
||||
tl.style.opacity = 1;
|
||||
|
||||
refreshIcons(tl);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ const ERROR_TABLE = {
|
||||
* @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;
|
||||
@@ -403,6 +404,31 @@ window.Submission = function(){
|
||||
}
|
||||
|
||||
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 = '<p>Request submitted</p>';
|
||||
entry_featured_button.style.display = 'none';
|
||||
} else {
|
||||
entry_featured_body.innerHTML = '<p>Request failed. Please refresh the page and retry.</p>';
|
||||
entry_featured_button.style.display = 'none';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user