Skip to content

Commit

Permalink
WIP everything is on fire but cool
Browse files Browse the repository at this point in the history
  • Loading branch information
Haxxer committed Nov 17, 2024
1 parent 12f61e4 commit ecac7b6
Show file tree
Hide file tree
Showing 12 changed files with 522 additions and 147 deletions.
15 changes: 6 additions & 9 deletions resources/js/calendar/clock_collapsible.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import CollapsibleComponent from "./collapsible_component";

class ClockCollapsible extends CollapsibleComponent {
loads = {
inboundProperties = {
'clock': 'clock'
};

watchers = {
changeHandlers = {
'clock': this.changed
};

outboundProperties = {
"clock": "clock"
}

changed(current, previous) {
this.$dispatch('clock-changed', {
...current
});

this.$dispatch('calendar-rerender-requested', {
rerender: previous.enabled !== current.enabled
|| previous.hours !== current.hours
|| previous.minutes !== current.minutes,
calendar: { clock: { ...current } },
});
}
}

Expand Down
95 changes: 70 additions & 25 deletions resources/js/calendar/collapsible_component.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
export default class CollapsibleComponent {
initialized = false;
processWatchers = false;
loads = {};
watchers = {};
setters = {};

inboundProperties = {};
changeHandlers = {};
outboundProperties = {};

validators = {};
errors = {};
calendar_settings = {};
is_valid = true;

load(static_data) {
if (!static_data) {
Expand All @@ -13,39 +18,54 @@ export default class CollapsibleComponent {

this.calendar_settings = static_data.settings;

// We want to disable the watchers during loading stages so that we don't get recursive calendar rerender calls
// We want to disable the changeHandlers during loading stages so that we don't get recursive calendar rerender calls
this.processWatchers = false;
for (let [localKey, globalKey] of Object.entries(this.loads)) {
for (let [localKey, globalKey] of Object.entries(this.inboundProperties)) {
this[localKey] = _.get(static_data, globalKey);
}
this.processWatchers = true;

if (!this.initialized) {
const collapsibleWatchers = {};
this.setupWatchers();
this.initialized = true;
}

for (let localKey of Object.keys(this.watchers)) {
collapsibleWatchers[localKey] ??= [];
collapsibleWatchers[localKey].push(this.watchers[localKey].bind(this));
}
this.loaded(static_data);
}

for (let [localKey, globalKey] of Object.entries(this.setters)) {
collapsibleWatchers[localKey] ??= [];
collapsibleWatchers[localKey].push(() => {
this.rerender(globalKey, this[localKey]);
});
}
setupWatchers(){

for(const [localKey, methods] of Object.entries(collapsibleWatchers)){
this.$watch(localKey, (...args) => {
if(!this.processWatchers) return;
methods.forEach((method) => method(...args));
});
}
const componentProperties = Array.from(new Set(
Object.keys(this.changeHandlers).concat(Object.keys(this.outboundProperties))
));

this.initialized = true;
}
for(let localKey of componentProperties){
this.$watch(localKey, (...args) => {

this.loaded(static_data);
let isValid = this.validate();
if(!isValid){
if(this.is_valid){
this.is_valid = false;
}
return this.validationFailed();
}

if(!this.is_valid) {
return
}

if(!this.processWatchers) return;

if(this.changeHandlers[localKey]){
this.changeHandlers[localKey](...args);
}

if(this.outboundProperties[localKey]){
this.rerender(this.outboundProperties[localKey], this[localKey]);
}

});
}
}

rerender(key, value) {
Expand All @@ -55,4 +75,29 @@ export default class CollapsibleComponent {
loaded(static_data) {
// throw new Error(`The component ${this.prototype.constructor.name} must implement 'changed()'!`);
}

validate() {
this.errors = {};
let isValid = true;
for(let [localKey, validator] of Object.entries(this.validators)){
let { error, message } = validator(localKey);
if(error){
this.errors[localKey] = message;
isValid = false;
}
}
return isValid;
}

validationFailed() {

}

getError() {

}

hasError() {

}
}
4 changes: 2 additions & 2 deletions resources/js/calendar/cycles_collapsible.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ class CyclesCollapsible extends CollapsibleComponent {
format = "";
cycles = [];

loads = {
inboundProperties = {
"format": "cycles.format",
"cycles": "cycles.data",
}

setters = {
outboundProperties = {
"format": "cycles.format",
"cycles": "cycles.data",
}
Expand Down
91 changes: 50 additions & 41 deletions resources/js/calendar/leap_days_collapsible.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ class LeapDaysCollapsible extends CollapsibleComponent {
weekdays = [];
timespans = [];

loads = {
inboundProperties = {
"leap_days": "year_data.leap_days",
"weekdays": "year_data.global_week",
"timespans": "year_data.timespans"
}

setters = {
outboundProperties = {
"leap_days": "year_data.leap_days"
}

Expand Down Expand Up @@ -54,59 +54,68 @@ class LeapDaysCollapsible extends CollapsibleComponent {
return this.timespans[leapDay.timespan].length;
}

validateLeapDayInterval(leapDay, interval) {
validators = {
"leap_days": this.validateLeapDayInterval
};

interval = interval.replace(/,\s*$/, "");
validateLeapDayInterval() {

if (interval === "0") {
// TODO: Add proper error messaging to outer components, and prevent re-render
// `${leapDay.name}'s interval is 0, please enter a positive number.`
return;
}
for(let leapDay of this.leap_days) {

let invalid = this.interval_wide_regex.test(interval);
let { interval } = leapDay;

if(invalid) {
// TODO: Add proper error messaging to outer components, and prevent re-render
// `${leapDay.name} has an invalid interval formula.`
return;
}
interval = interval.replace(/,\s*$/, "");

if (interval === "0") {
// TODO: Add proper error messaging to outer components, and prevent re-render
// `${leapDay.name}'s interval is 0, please enter a positive number.`
return;
}

let values = interval.split(',');
let invalid = this.interval_wide_regex.test(interval);

for(let value of values){
if (!this.interval_internal_regex.test(value)) {
invalid = true;
break;
if (invalid) {
// TODO: Add proper error messaging to outer components, and prevent re-render
// `${leapDay.name} has an invalid interval formula.`
return;
}
}

if(invalid) {
// TODO: Add proper error messaging to outer components, and prevent re-render
// `${leapDay.name} has an invalid interval formula. Plus before exclamation point.` : '');
return;
}
let values = interval.split(',');

for (let value of values) {
if (!this.interval_internal_regex.test(value)) {
invalid = true;
break;
}
}

if (invalid) {
// TODO: Add proper error messaging to outer components, and prevent re-render
// `${leapDay.name} has an invalid interval formula. Plus before exclamation point.` : '');
return;
}

let unsorted = [];
let unsorted = [];

for (let value of values) {
unsorted.push(Number(value.match(this.interval_numbers_regex)[0]));
}
for (let value of values) {
unsorted.push(Number(value.match(this.interval_numbers_regex)[0]));
}

let sorted = unsorted.slice(0).sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}).reverse();
let sorted = unsorted.slice(0).sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}).reverse();

let result = [];
let result = [];

for (let value of sorted) {
let index = unsorted.indexOf(value);
result.push(values[index]);
}
for (let value of sorted) {
let index = unsorted.indexOf(value);
result.push(values[index]);
}

leapDay.interval = result.join(',');
leapDay.interval = result.join(',');
}

}

Expand Down
89 changes: 84 additions & 5 deletions resources/js/calendar/locations_collapsible.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,86 @@
export default () => ({
reordering: false,
import CollapsibleComponent from "./collapsible_component.js";
import { preset_data } from "./calendar_variables.js";

load: function(static_data) {
//
class LocationsCollapsible extends CollapsibleComponent {

deleting = -1;
name = "";

seasons = [];
locations = [];
season_settings = {};
clock = {};

preset_locations = [];
can_use_preset_locations = false;

inboundProperties = {
"seasons": "seasons.data",
"locations": "seasons.locations",
"season_settings": "seasons.global_settings",
"clock": "clock",
}

outboundProperties = {
"locations": "seasons.locations",
}

loaded() {

this.can_use_preset_locations = (this.seasons.length === 2 || this.seasons.length === 4) && this.season_settings.enable_weather;

if(this.can_use_preset_locations) {
let length = this.can_use_preset_locations ? this.seasons.length : 4;
this.preset_locations = Object.values(preset_data.locations[length]);
}else{
this.preset_locations = [];
}

}

addLocation(){
this.locations.push({
"name": this.name || "New location",
"seasons": this.seasons.map(season => {
return {
"time": season.time,
"weather": {
"temp_low": 0,
"temp_high": 0,
"precipitation": 0,
"precipitation_intensity": 0
}
}
}),

"settings": {
"timezone": {
"hour": 0,
"minute": 0,
},

"season_based_time": true,

"large_noise_frequency": 0.015,
"large_noise_amplitude": 5.0,

"medium_noise_frequency": 0.3,
"medium_noise_amplitude": 2.0,

"small_noise_frequency": 0.8,
"small_noise_amplitude": 3.0
}
});

// TODO: Change the current location to the new location

this.name = "";
}

removeLocation(index){
this.locations.splice(index, 1);
}
})

}

export default () => new LocationsCollapsible();
Loading

0 comments on commit ecac7b6

Please sign in to comment.