@@ -1,20 +1,50 @@ | |||
var NESPaletteSchema = JSON.stringify({ | |||
"$schema": "http://json-schema.org/draft-07/schema#", | |||
"$id": "NESPaletteSchema.json", | |||
"type":"array", | |||
"minItems":25, | |||
"maxItems":25, | |||
"items":{ | |||
"type":"number", | |||
"minimum": 0, | |||
"exclusiveMaximum": 64 | |||
var SCHEMA_LIST = []; | |||
var DIRTY = false; | |||
var CUR_AJV = null; | |||
export default Object.freeze({ | |||
add:function(s){ | |||
if (!("$id" in s)) | |||
throw new Error("Missing '$id' property in schema."); | |||
for (let i=0; i < SCHEMA_LIST.length; i++){ | |||
if (SCHEMA_LIST[i]["$id"] === s["$id"]) | |||
throw new Error("Schema already exists with $id '" + s["$id"] + "'."); | |||
} | |||
SCHEMA_LIST.push(s); | |||
DIRTY = true; | |||
}, | |||
remove:function(id){ | |||
var idx = SCHEMA_LIST.findIndex((item) => { | |||
return item["$id"] === id; | |||
}); | |||
if (idx >= 0){ | |||
SCHEMA_LIST.splice(idx, 1); | |||
DIRTY = true; | |||
} | |||
}, | |||
has:function(id){ | |||
return SCHEMA_LIST.findIndex((item) => { | |||
return item["$id"] === id; | |||
}) >= 0; | |||
}, | |||
getValidator:function(id){ | |||
if (DIRTY){ | |||
DIRTY = false; | |||
if (SCHEMA_LIST.length <= 0){ | |||
CUR_AJV = null; | |||
} else { | |||
CUR_AJV = new Ajv({schema:SCHEMA_LIST}); | |||
} | |||
} | |||
return (CUR_AJV !== null) ? CUR_AJV.getSchema(id) : null; | |||
} | |||
}); | |||
var PalettesStoreSchema = JSON.stringify({ | |||
"$schema": "http://json-schema.org/draft-07/schema#", | |||
"$id": "PalettesStoreSchema.json", | |||
}); | |||
@@ -1,5 +1,6 @@ | |||
import GlobalEvents from "/app/js/common/EventCaller.js"; | |||
import Utils from "/app/js/common/Utils.js"; | |||
import JSONSchema from "/app/js/common/JSONSchema.js"; | |||
import EditableText from "/app/js/ui/EditableText.js"; | |||
import Renderer from "/app/js/ui/Renderer.js"; | |||
import NESBank from "/app/js/models/NESBank.js"; | |||
@@ -16,6 +17,29 @@ var Banks = {}; | |||
var CurrentBank = ""; | |||
JSONSchema.add({ | |||
"$schema": "http://json-schema.org/draft-07/schema#", | |||
"$id": "BanksStoreSchema.json", | |||
"type": "array", | |||
"items":{ | |||
"type": "object", | |||
"properties":{ | |||
"name":{ | |||
"type": "string", | |||
"minLength": 1 | |||
}, | |||
"data":{ | |||
"type": "string", | |||
"media": { | |||
"binaryEncoding": "base64" | |||
} | |||
} | |||
}, | |||
"required":["name", "data"] | |||
} | |||
}); | |||
function HANDLE_BankClick(e){ | |||
var name = this.getAttribute("bankname"); | |||
if (name !== CurrentBank){ | |||
@@ -122,7 +146,12 @@ class CTRLBanksStore{ | |||
} | |||
set obj(d){ | |||
if (!(d instanceof Array)) | |||
try { | |||
this.json = JSON.stringify(d); | |||
} catch (e) { | |||
throw e; | |||
} | |||
/*if (!(d instanceof Array)) | |||
throw new TypeError("Expected Array object."); | |||
this.clear(); | |||
d.forEach((item) => { | |||
@@ -133,13 +162,32 @@ class CTRLBanksStore{ | |||
console.log("WARNING: Bank object missing required properties. Skipped."); | |||
} | |||
} | |||
}); | |||
});*/ | |||
} | |||
get json(){ | |||
return JSON.stringify(this.obj); | |||
} | |||
set json(j){ | |||
var validator = null; | |||
try { | |||
validator = JSONSchema.getValidator("BanksStoreSchema.json"); | |||
} catch (e) { | |||
throw e; | |||
} | |||
if (validator(j)){ | |||
this.clear(); | |||
var o = JSON.parse(j); | |||
o.forEach((item) => { | |||
this.createBank(item.name, item.data); | |||
}); | |||
} else { | |||
throw new Error("JSON Object validation failed."); | |||
} | |||
} | |||
initialize(){ | |||
if (this.length <= 0){ | |||
this.createBank("Bank"); |
@@ -1,18 +1,46 @@ | |||
import GlobalEvents from "/app/js/common/EventCaller.js"; | |||
import Utils from "/app/js/common/Utils.js"; | |||
import JSONSchema from "/app/js/common/JSONSchema.js"; | |||
import NESBank from "/app/js/models/NESBank.js"; | |||
import NESPalette from "/app/js/models/NESPalette.js"; | |||
import CTRLPalettesStore from "/app/js/ctrls/CTRLPalettesStore.js"; | |||
import CTRLBanksStore from "/app/js/ctrls/CTRLBanksStore.js"; | |||
const SUPPORTED_PROJECT_VERSIONS=[ | |||
"0.1" | |||
]; | |||
JSONSchema.add({ | |||
"$schema": "http://json-schema.org/draft-07/schema#", | |||
"$id": "NESPainterProject.json", | |||
"type":"object", | |||
"properties":{ | |||
"id":{ | |||
"type":"string", | |||
"enum":["NESPProj"] | |||
}, | |||
"version":{ | |||
"type":"string", | |||
"pattern":"^[0-9]{1,}\.[0-9]{1,}$" | |||
}, | |||
"paletteStore":{"$ref":"PalettesStoreSchema.json"}, | |||
"bankStore":{"$ref":"BanksStoreSchema.json"} | |||
}, | |||
"required":["id","version","paletteStore","bankStore"] | |||
}); | |||
var SURF = null; | |||
function JSONFromProject(){ | |||
var proj = { | |||
palettesStore:CTRLPalettesStore.obj, | |||
banksStore:CTRLBanksStore.obj | |||
id:"NESPProj", | |||
version:SUPPORTED_PROJECT_VERSIONS[SUPPORTED_PROJECT_VERSIONS.length - 1], | |||
paletteStore:CTRLPalettesStore.obj, | |||
bankStore:CTRLBanksStore.obj | |||
}; | |||
return JSON.stringify(proj); | |||
} | |||
@@ -76,8 +104,19 @@ function HANDLE_LoadProject(e){ | |||
if (this.files && this.files.length > 0){ | |||
var reader = new FileReader(); | |||
reader.onload = (function(e) { | |||
var content = e.target.result; | |||
console.log(content); | |||
var validator = null; | |||
try{ | |||
validator = JSONSchema.getValidator("NESPainterProject.json"); | |||
} catch (e) { | |||
console.log("Failed to validate project file. " + e.toString()); | |||
return; | |||
} | |||
if (validator(e.target.result)){ | |||
var o = JSON.parse(e.target.result); | |||
// TODO: Validate 'id' and 'version' properties. | |||
CTRLPalettesStore.obj = o.paletteStore; | |||
CTRLBanksStore.obj = o.banksStore; | |||
} | |||
if (this.parentNode.nodeName.toLowerCase() === "form"){ | |||
this.parentNode.reset(); | |||
} else { |
@@ -1,5 +1,6 @@ | |||
import GlobalEvents from "/app/js/common/EventCaller.js"; | |||
import Utils from "/app/js/common/Utils.js"; | |||
import JSONSchema from "/app/js/common/JSONSchema.js"; | |||
import EditableText from "/app/js/ui/EditableText.js"; | |||
import NESPalette from "/app/js/models/NESPalette.js"; | |||
@@ -19,6 +20,26 @@ var CurrentPaletteIndex = 0; | |||
var BlockEmits = false; | |||
JSONSchema.add({ | |||
"$schema": "http://json-schema.org/draft-07/schema#", | |||
"$id": "PalettesStoreSchema.json", | |||
"type": "array", | |||
"items": { | |||
"type": "object", | |||
"properties": { | |||
"name":{ | |||
"type":"string", | |||
"minLength":1 | |||
}, | |||
"palette":{ | |||
"$ref":"NESPaletteSchema.json" | |||
} | |||
}, | |||
"required":["name","palette"] | |||
} | |||
}); | |||
function HANDLE_PaletteClick(e){ | |||
if (!this.hasAttribute("palname")){return;} | |||
var pname = this.getAttribute("palname"); | |||
@@ -154,19 +175,21 @@ class CTRLPalettesStore{ | |||
} | |||
get obj(){ | |||
var d = { | |||
cpi: CurrentPaletteIndex, | |||
pals: [] | |||
}; | |||
var d = []; | |||
for (let i=0; i < Palettes.length; i++){ | |||
d.pals.push([Palettes[i][0].value, Palettes[i][1].json]); | |||
d.push({name:Palettes[i][0].value, palette:Palettes[i][1].obj}); | |||
} | |||
return d; | |||
} | |||
set obj(d){ | |||
if (d.hasOwnProperty("cpi") && d.hasOwnProperty("pals")){ | |||
try { | |||
this.json = JSON.stringify(d); | |||
} catch (e) { | |||
throw e; | |||
} | |||
/*if (d.hasOwnProperty("cpi") && d.hasOwnProperty("pals")){ | |||
if (Utils.isInt(d.cpi) && d.pals instanceof Array){ | |||
var newPalettes = [] | |||
for (let i=0; i < d.pals.length; i++){ | |||
@@ -188,7 +211,7 @@ class CTRLPalettesStore{ | |||
} | |||
} else { | |||
throw new TypeError("Object missing expected properties."); | |||
} | |||
}*/ | |||
} | |||
get json(){ | |||
@@ -196,11 +219,22 @@ class CTRLPalettesStore{ | |||
} | |||
set json(j){ | |||
var validator = null; | |||
try { | |||
this.obj = JSON.parse(j); | |||
validator = JSONSchema.getValidator("PalettesStoreSchema.json"); | |||
} catch (e) { | |||
throw e; | |||
} | |||
if (validator(j)){ | |||
this.clear(); | |||
var o = JSON.parse(j); | |||
for (let i=0; i < o.length; i++){ | |||
this.createPalette(o[i].name, JSON.stringify(o[i].palette)); | |||
} | |||
} else { | |||
throw new Error("JSON Object failed verification."); | |||
} | |||
} | |||
initialize(){ |
@@ -1,4 +1,19 @@ | |||
import {EventCaller} from "/app/js/common/EventCaller.js" | |||
import {EventCaller} from "/app/js/common/EventCaller.js"; | |||
import JSONSchema from "/app/js/common/JSONSchema.js"; | |||
JSONSchema.add({ | |||
"$schema": "http://json-schema.org/draft-07/schema#", | |||
"$id": "NESPaletteSchema.json", | |||
"type":"array", | |||
"minItems":25, | |||
"maxItems":25, | |||
"items":{ | |||
"type":"number", | |||
"minimum": 0, | |||
"exclusiveMaximum": 64 | |||
} | |||
}); | |||
/** | |||
* Object for manipulating the eight NES palettes. | |||
@@ -27,10 +42,8 @@ export default class NESPalette extends EventCaller{ | |||
} | |||
set obj(d){ | |||
if (!(d instanceof Array) || d.length !== 25) | |||
throw new TypeError("Invalid Object or value range."); | |||
try { | |||
this.set_palette(d); | |||
this.json = JSON.stringify(d); | |||
} catch (e) { | |||
throw e; | |||
} | |||
@@ -42,10 +55,16 @@ export default class NESPalette extends EventCaller{ | |||
set json(j){ | |||
try{ | |||
this.obj = JSON.parse(j); | |||
var validator = JSONSchema.getValidator("NESPaletteSchema.json"); | |||
} catch (e) { | |||
throw e; | |||
} | |||
if (validator(j)){ | |||
this.set_palette(JSON.parse(j)); | |||
} else { | |||
throw new Error("JSON Object failed to pass validation."); | |||
} | |||
} | |||
/** |