446 lines
16 KiB
JavaScript
446 lines
16 KiB
JavaScript
var Shredifier = Shredifier || function() {
|
|
// page data array
|
|
this.pages = [];
|
|
this.page = null;
|
|
// DOM view elements
|
|
this.menu = null;
|
|
this.graph = null;
|
|
this.graph_head = null;
|
|
this.tabular = null;
|
|
this.tabular_head = null;
|
|
this.entries = null;
|
|
this.entries_head = null;
|
|
//
|
|
this.pages_dom = null;
|
|
//
|
|
this.tabular_object = null;
|
|
this.entries_object = null;
|
|
//
|
|
this.nodes = [];
|
|
};
|
|
/* ======== Initialize and Close methods ======== */
|
|
Shredifier.prototype.doInit = function() {
|
|
var self = this;
|
|
// find our elements
|
|
this.menu = document.getElementById('menu');
|
|
if (this.menu == null) return 1;
|
|
this.graph_head = document.getElementById('graph_head');
|
|
if (this.graph_head == null) return 2;
|
|
this.graph = document.getElementById('graph');
|
|
if (this.graph == null) return 3;
|
|
this.tabular = document.getElementById('tabular');
|
|
if (this.tabular == null) return 4;
|
|
this.tabular_head = document.getElementById('tabular_head');
|
|
if (this.tabular_head == null) return 4;
|
|
this.entries = document.getElementById('entries');
|
|
if (this.entries == null) return 4;
|
|
this.entries_head = document.getElementById('entries_head');
|
|
if (this.entries_head == null) return 4;
|
|
this.pages_dom = document.getElementById('pages');
|
|
if (this.pages_dom == null) return 5;
|
|
// add synchronization for tabular_head and tabular
|
|
this.tabular_head.addEventListener('scroll', function(e) {
|
|
self.tabular.scrollTop = self.tabular_head.scrollTop;
|
|
});
|
|
this.tabular_head.addEventListener('head-input', function(e) {
|
|
// FIXME
|
|
if (e.set_index == 0) {
|
|
self.page.exercises[e.exercise_index].name = e.value;
|
|
}
|
|
});
|
|
|
|
this.graph_object = new Graph(this.graph);
|
|
// set up our Graph listeners
|
|
this.graph_object.element.addEventListener('nodemove', function(e) {
|
|
var weight = (self.graph_object.row_count-e.to-1) * self.page.step_weight;
|
|
self.graph_object.setNodeText(e.node.id, e.node.column, weight, e.node.color);
|
|
var cell_id = 'input_'+(new ShredId(e.node.id.parts[0], e.node.id.parts[1], e.node.column-1).toString());
|
|
var cell = document.getElementById(cell_id);
|
|
// Okay, we're doing something weird now. This is to keep any trailing non-numeric value attached to the cell's value. For example, if the original value was "85x6" and the new weight value is "90", then it would set it to "90x6".
|
|
cell.value = weight + cell.value.substring(parseFloat(cell.value).toString().length);
|
|
var event = document.createEvent('HTMLEvents');
|
|
event.initEvent('input', true, true);
|
|
event.target = cell;
|
|
cell.dispatchEvent(event);
|
|
|
|
});
|
|
// FIXME: entries b0rks when col_count reaches 1
|
|
this.graph_object.element.addEventListener('coladded', function(e) {
|
|
if (e.col_count > 1) { // skip first padding column
|
|
for (var i = 0; i < self.tabular_object.exercises.length; i++) {
|
|
var exercise = self.tabular_object.exercises[i];
|
|
for (var j = 0; j < exercise.sets.length; j++) {
|
|
if (exercise.sets[j].entries.length < self.page.entry_count+1) {
|
|
exercise.sets[j].addEntry();
|
|
}
|
|
}
|
|
}
|
|
self.entries_object.addEntry();
|
|
if (self.page.entries[self.page.entry_count]) self.entries_object.entries[self.page.entry_count].input.value = self.page.entries[self.page.entry_count];
|
|
self.page.entry_count++;
|
|
}
|
|
});
|
|
this.graph_object.element.addEventListener('colremoved', function(e) {
|
|
if (e.col_count > 1) {
|
|
for (var i = 0; i < self.tabular_object.exercises.length; i++) {
|
|
var exercise = self.tabular_object.exercises[i];
|
|
for (var j = 0; j < exercise.sets.length; j++) {
|
|
exercise.sets[j].removeEntry(exercise.sets[j].entries.length-1);
|
|
}
|
|
}
|
|
self.entries_object.removeEntry(self.entries_object.entries.length-1);
|
|
self.page.entry_count--;
|
|
}
|
|
});
|
|
this.graph_object.element.addEventListener('rowremove', function(e) {
|
|
});
|
|
this.graph_object.element.addEventListener('colsadd', function(e) {
|
|
});
|
|
this.graph_object.element.addEventListener('celladd', function(e) {
|
|
});
|
|
this.graph_object.element.addEventListener('cellremove', function(e) {
|
|
});
|
|
// set up our entries
|
|
this.entries_object = new Entries(this.entries_head, this.entries);
|
|
// set up our entries listeners
|
|
this.entries_object.element.addEventListener('headinput', function(e) {
|
|
self.page.entries[e.entry_index] = e.entry.input.value;
|
|
});
|
|
// set up our Tabular
|
|
this.tabular_object = new Tabular(this.tabular_head, this.tabular);
|
|
// set up our Tabular listeners
|
|
this.tabular_object.element.addEventListener('addexercise', function(e) {
|
|
var exercise = self.page.exercises[e.exercise.index];
|
|
for (var s = 0; s < exercise.sets.length; s++) {
|
|
e.exercise.addSet();
|
|
}
|
|
});
|
|
this.tabular_object.element.addEventListener('removeexercise', function(e) {
|
|
self.page.removeExercise(e.exercise);
|
|
});
|
|
this.tabular_object.element.addEventListener('addset', function(e) {
|
|
var exercise = self.page.exercises[e.set.parent.index];
|
|
// set the Set header name
|
|
if (e.set.index == 0) {
|
|
e.set.head_input.value = exercise.name;
|
|
// add settings button
|
|
var btn = document.createElement('div');
|
|
btn.className = 'button conf';
|
|
btn.addEventListener('click', function(evt) {
|
|
console.log('bip');
|
|
// open settings dialog
|
|
});
|
|
e.set.row_head.appendChild(btn);
|
|
// add set button
|
|
var btn = document.createElement('div');
|
|
var set = e.set;
|
|
btn.className = 'button add';
|
|
btn.addEventListener('click', function(evt) {
|
|
set.parent.addSet();
|
|
});
|
|
e.set.row_head.appendChild(btn);
|
|
} else {
|
|
e.set.head_input.value = 'Set ' + (e.set.index+1);
|
|
// add delete button
|
|
var btn = document.createElement('div');
|
|
var set = e.set;
|
|
btn.className = 'button rem';
|
|
btn.addEventListener('click', function(evt) {
|
|
set.parent.removeSet(set.index);
|
|
});
|
|
e.set.row_head.appendChild(btn);
|
|
}
|
|
// set the row color
|
|
var r, g, b;
|
|
r = Math.round(exercise.color[0] + exercise.color[0] / 6 * e.set.index);
|
|
g = Math.round(exercise.color[1] + exercise.color[1] / 6 * e.set.index);
|
|
b = Math.round(exercise.color[2] + exercise.color[2] / 6 * e.set.index);
|
|
e.set.row.style.backgroundColor = 'rgba('+r+','+g+','+b+',0.75)';
|
|
e.set.row_head.style.backgroundColor = 'rgb('+r+','+g+','+b+')';
|
|
// add the entries
|
|
if (e.set.parent.sets.length > exercise.sets.length) {
|
|
exercise.createSet({text: e.set.head_input.value});
|
|
}
|
|
if (e.set.entries.length < self.page.entry_count) {
|
|
for (var i = 0; i < self.page.entry_count; i++) e.set.addEntry();
|
|
}
|
|
});
|
|
this.tabular_object.element.addEventListener('removeset', function(e) {
|
|
var exercise = self.page.exercises[e.set.parent.index];
|
|
exercise.removeSet(e.set_index);
|
|
});
|
|
this.tabular_object.element.addEventListener('addentry', function(e) {
|
|
var exercise = self.page.exercises[e.entry.parent.parent.index];
|
|
if (exercise) {
|
|
var set = exercise.sets[e.entry.parent.index];
|
|
if (set) {
|
|
var entry = set.entries[e.entry.index];
|
|
}
|
|
}
|
|
if (typeof entry !== 'undefined') e.entry.cell_input.value = entry;
|
|
// connect the entry to the graph table
|
|
e.entry.cell_input.id = 'input_'+(new ShredId(e.entry.parent.parent.index, e.entry.parent.index, e.entry.index).toString());
|
|
e.entry.cell_input.addEventListener('input', function(e) {
|
|
var parts = e.target.id.split('_');
|
|
var exercise = parts[1];
|
|
var set = parts[2];
|
|
var entry = parts[3];
|
|
self.updateSet(exercise, set, entry, parseFloat(e.target.value));
|
|
});
|
|
});
|
|
this.tabular_object.element.addEventListener('removeentry', function(e) {
|
|
var node_id = new ShredId(e.entry.parent.parent.index, e.entry.parent.index);
|
|
self.graph_object.clearNode(node_id, e.entry.index);
|
|
});
|
|
// Set up additional controls
|
|
var btn_add = document.getElementById('page-add');
|
|
btn_add.addEventListener('click', function(e) {
|
|
self.loadPage({});
|
|
});
|
|
var btn_new = document.getElementById('new');
|
|
btn_new.addEventListener('click', function(e) {
|
|
self.clearPages();
|
|
});
|
|
var btn_save = document.getElementById('save');
|
|
btn_save.addEventListener('click', function(e) {
|
|
self.saveFile();
|
|
});
|
|
var file_load = document.createElement('input');
|
|
file_load.type = 'file';
|
|
file_load.addEventListener('change', function(e) {
|
|
var files = e.target.files;
|
|
if (files.length <= 0) return;
|
|
var file = files[0];
|
|
if (typeof FileReader !== 'undefined') {
|
|
var reader = new FileReader;
|
|
reader.onload = function(evt) {
|
|
self.loadPages(JSON.parse(evt.target.result));
|
|
};
|
|
reader.readAsText(file);
|
|
}
|
|
});
|
|
var btn_load = document.getElementById('load');
|
|
btn_load.addEventListener('click', function(e) {
|
|
file_load.click();
|
|
});
|
|
|
|
var btn_exercise_add = document.getElementById('exercise-add');
|
|
btn_exercise_add.addEventListener('click', function(e) {
|
|
self.addExercise();
|
|
});
|
|
|
|
return 0;
|
|
};
|
|
/* ======== ======== */
|
|
Shredifier.prototype.clearPages = function() {
|
|
for (var i = 0; i < this.pages.length; i++) {
|
|
this.pages[i].tab.parentNode.removeChild(this.pages[i].tab);
|
|
}
|
|
this.pages = [];
|
|
this.page = null;
|
|
this.clearGraph();
|
|
this.clearTable();
|
|
this.clearEntries();
|
|
};
|
|
Shredifier.prototype.loadPages = function(json) {
|
|
var self = this;
|
|
self.clearPages();
|
|
for (var i = 0; i < json.pages.length; i++) {
|
|
this.loadPage(json.pages[i]);
|
|
}
|
|
};
|
|
Shredifier.prototype.loadPage = function(json) {
|
|
var self = this;
|
|
|
|
var page = new Page();
|
|
|
|
page.tab = document.createElement('span');
|
|
page.tab.className = 'tab';
|
|
page.input = document.createElement('input');
|
|
page.input.type = 'button';
|
|
page.input.value = '';
|
|
page.input.addEventListener('click', function(e) {
|
|
if (self.page === page) return;
|
|
self.focusPage(page);
|
|
});
|
|
page.input.addEventListener('dblclick', function(e) {
|
|
page.input.type = 'text';
|
|
});
|
|
page.input.addEventListener('blur', function(e) {
|
|
if (page.input.type == 'text') {
|
|
page.input.type = 'button';
|
|
page.name = page.input.value;
|
|
}
|
|
});
|
|
page.tab.appendChild(page.input);
|
|
page.remove = document.createElement('div');
|
|
page.remove.className = 'button close';
|
|
page.tab.appendChild(page.remove);
|
|
this.pages_dom.insertBefore(page.tab, this.pages_dom.lastElementChild);
|
|
|
|
this.pages.push(page);
|
|
|
|
page.loadJSON(json);
|
|
if (!this.page) {
|
|
self.focusPage(page);
|
|
}
|
|
|
|
page.element.addEventListener('addexercise', function(e) {
|
|
if (e.exercise.sets.length <= 0) {
|
|
//e.exercise.createSet({});
|
|
for (var i = 0; i < self.page.entry_count; i++) e.exercise.sets[0].addEntry();
|
|
}
|
|
});
|
|
};
|
|
Shredifier.prototype.loadFile = function() {
|
|
};
|
|
Shredifier.prototype.saveFile = function() {
|
|
var json = {
|
|
pages: []
|
|
};
|
|
for (var i = 0; i < this.pages.length; i++) {
|
|
json.pages.push(this.pages[i].getJSON());
|
|
}
|
|
var str_data = JSON.stringify(json);
|
|
var filename = (json.name ? json.name : 'swole').replace(/[\'\"\,`\.\!\?]/gi, '').replace(/[^a-z0-9_\-]/gi, '-').toLowerCase()+'.json';
|
|
var file = null;
|
|
file = new Blob([str_data], {type: 'data:application/json'});
|
|
// NOTE: we are assuming the user did not cancel the save action
|
|
// Save file
|
|
if (window.navigator.msSaveOrOpenBlob) { // IE10+
|
|
window.navigator.msSaveOrOpenBlob(file, filename);
|
|
return;
|
|
}
|
|
var url = URL.createObjectURL(file);
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
setTimeout(function() {
|
|
document.body.removeChild(a);
|
|
window.URL.revokeObjectURL(url);
|
|
}, 0);
|
|
};
|
|
Shredifier.prototype.focusPage = function(page) {
|
|
this.clearGraph();
|
|
this.clearTable();
|
|
this.clearEntries();
|
|
if (this.page) this.page.tab.className = 'tab';
|
|
this.page = page;
|
|
this.page.tab.className = 'tab selected';
|
|
this.buildEntries();
|
|
this.buildTable();
|
|
this.buildGraph();
|
|
};
|
|
/* ======== ======== */
|
|
Shredifier.prototype.syncPage = function() {
|
|
if (this.page == null) return;
|
|
};
|
|
Shredifier.prototype.addExercise = function() {
|
|
this.page.createExercise({});
|
|
this.tabular_object.addExercise();
|
|
};
|
|
/* ======== Page to Graph synchronization methods ======== */
|
|
Shredifier.prototype.buildGraph = function() {
|
|
// TODO: this should be calculated from a 'newrow' event, as per the new design
|
|
// this.graph_object.populate(rows+1, this.page.entry_count+1);
|
|
var rows = (this.page.end_weight/this.page.step_weight);
|
|
var entries = this.page.entry_count+1;
|
|
this.page.entry_count = 0; // FIXME: this is dumb
|
|
this.graph_object.populate(rows+1, entries);
|
|
// set our first cell text
|
|
var max = Math.max(this.page.start_weight, this.page.end_weight);
|
|
var min = Math.min(this.page.start_weight, this.page.end_weight);
|
|
var rows = (min < 0 ? Math.abs(min) + Math.abs(max) : max-min) / this.page.step_weight;
|
|
for (var i = 0; i <= rows; i++) {
|
|
// TODO: round to two decimal places
|
|
this.graph_object.setCellText(i, 0, (rows-i)*this.page.step_weight);
|
|
}
|
|
for (var e = 0; e < this.page.exercises.length; e++) {
|
|
var exercise = this.page.exercises[e];
|
|
for (var s = 0; s < exercise.sets.length; s++) {
|
|
var set = exercise.sets[s];
|
|
for (var i = 0; i < set.entries.length; i++) {
|
|
this.updateSet(e, s, i, parseFloat(set.entries[i]));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Shredifier.prototype.clearGraph = function() {
|
|
this.graph_object.clear();
|
|
};
|
|
Shredifier.prototype.buildEntries = function() {
|
|
};
|
|
Shredifier.prototype.clearEntries = function() {
|
|
this.entries_object.clear();
|
|
};
|
|
Shredifier.prototype.buildTable = function() {
|
|
for (var e = 0; e < this.page.exercises.length; e++) {
|
|
this.tabular_object.addExercise();
|
|
}
|
|
};
|
|
Shredifier.prototype.clearTable = function() {
|
|
this.tabular_object.clear();
|
|
};
|
|
/* ======== Update Methods ======== */
|
|
Shredifier.prototype.updateSet = function(exercise_id, set_id, entry_id, value) {
|
|
if (typeof this.page.exercises !== 'undefined' && this.page.exercises.length <= exercise_id) {
|
|
alert('cannot updateSet, exercise '+exercise_id+' is OOR!');
|
|
return;
|
|
}
|
|
var exercise = this.page.exercises[exercise_id];
|
|
if (typeof exercise.sets !== 'undefined' && exercise.sets.length <= set_id) {
|
|
alert('cannot updateSet, set '+set_id+' is OOR!');
|
|
return;
|
|
}
|
|
var set = exercise.sets[set_id];
|
|
/*if (typeof set.entries !== 'undefined' && set.entries.length <= entry_id) {
|
|
alert('cannot updateSet, entry '+entry_id+' is OOR!');
|
|
return;
|
|
}*/
|
|
var entry = set.entries[entry_id];
|
|
set.entries[entry_id] = value;
|
|
|
|
var nvalue = set.entries[entry_id]/this.page.step_weight;
|
|
if (isNaN(nvalue)) nvalue = 0;
|
|
|
|
var max = Math.max(this.page.start_weight, this.page.end_weight);
|
|
var min = Math.min(this.page.start_weight, this.page.end_weight);
|
|
var rows = (min < 0 ? Math.abs(min) + Math.abs(max) : max-min) / this.page.step_weight;
|
|
|
|
entry_id = parseInt(entry_id);
|
|
|
|
var node_id = new ShredId(exercise_id, set_id);
|
|
if (value == '') {
|
|
this.graph_object.clearNode(node_id, entry_id+1);
|
|
} else {
|
|
this.graph_object.setNode(node_id, entry_id+1, (rows-nvalue), exercise.color_string);
|
|
this.graph_object.setNodeText(node_id, entry_id+1, value, exercise.color_string);
|
|
}
|
|
};
|
|
Shredifier.prototype.syncGraph = function(exercise_id, value) {
|
|
if (value < this.page.start_weight || value > this.page.end_weight) {
|
|
}
|
|
};
|
|
|
|
Shredifier.prototype.createId = function(exercise_id, set_id, entry_id) {
|
|
return (typeof exercise_id !== 'undefined' ? exercise_id+'_' : '')+(typeof set_id !== 'undefined' ? set_id+'_' : '')+(typeof entry_id !== 'undefined' ? entry_id : '');
|
|
};
|
|
|
|
var ShredId = ShredId || function(a, b, c) {
|
|
this.parts = [];
|
|
this.parts[0] = a;
|
|
this.parts[1] = b;
|
|
this.parts[2] = c;
|
|
};
|
|
ShredId.prototype.toString = function() {
|
|
var str = '';
|
|
for (i = 0, len = this.parts.length; i < len; i++) {
|
|
if (typeof this.parts[i] !== 'undefined') {
|
|
str += this.parts[i] + (typeof this.parts[i+1] !== 'undefined' ? '_' : '');
|
|
}
|
|
}
|
|
return str;
|
|
};
|