class Workout { // ---------- constructor(cont, plan) { const wo_cont = document.createElement("div"); wo_cont.classList.add("workout-wrapper"); cont.appendChild(wo_cont); // Inputs to the class. Workout plan and container to display it in this.container = wo_cont; this.plan = plan; // Status tracking information this.action = ""; this.set_idx = 0; this.set_repeat_idx = 0; this.exercise_idx = 0; this.workout_done = 0; // Enable debug this.show_debug_status = 1; } // ---------- text_element(typ, txt) { const el = document.createElement(typ); el.textContent = txt; return el; } // ---------- progress_indicator(id) { const indicator = this.text_element("div", " "); indicator.setAttribute("id", id); indicator.classList.add("progress-indicator"); indicator.classList.add("pending"); return indicator; } // ---------- render_workout_header() { const hdr = this.text_element("h1", this.plan.name); const wo_indicator = this.progress_indicator("wo-indicator"); hdr.appendChild(wo_indicator); this.container.appendChild(hdr); } // ---------- render_debug_status() { const dbg_div = document.createElement("div"); dbg_div.classList.add("app_debug"); const dt = document.createElement("p"); dt.setAttribute("id", "app_debug_div"); dbg_div.appendChild(dt); this.container.appendChild(dbg_div); } // ---------- update_debug_info() { if (this.show_debug_status) { const dt = this.container.querySelector("#app_debug_div"); const curr_set_repeat_max_idx = this.plan.set[this.set_idx].count-1; const done_str = (this.workout_done === 1) ? "Done " : ""; dt.textContent = `${done_str}Action: ${this.action} Current: Set-${this.set_idx} [${this.set_repeat_idx}/${curr_set_repeat_max_idx}]/Exercise-${this.exercise_idx}`; } } // ---------- render_exercise(prnt, el, idx) { const tblr = document.createElement("tr"); tblr.setAttribute("class", `exercise-row exercise-idx-${idx} exercise-pending`); const sts_td = document.createElement("td"); const sts_cb = document.createElement("input"); sts_cb.setAttribute("type", "checkbox"); sts_td.appendChild(sts_cb); sts_cb.setAttribute("disabled", true); // Status let col = sts_td; col.classList.add("col-status"); tblr.appendChild(col); el.done = 0; // Name col = this.text_element("td", el.name); col.classList.add("col-name"); tblr.appendChild(col); // Pattern/count col = this.text_element("td", `${el.pattern} x ${el.count}`); col.classList.add("col-pattern-count"); tblr.appendChild(col); prnt.appendChild(tblr); } // ---------- render_set(el, idx) { const wo = this; // Table with one set const tbl = document.createElement("table"); tbl.setAttribute("class", `set-table set-table-idx-${idx}`); const tcap = this.text_element("caption", el.name); for (var i = 0; i < el.count; i++) { const set_indicator = this.progress_indicator(`set-${idx}-${i}-indicator`); tcap.appendChild(set_indicator); } tbl.appendChild(tcap); let show_header = 0; if (show_header) { // Header of the table const tblh = document.createElement("thead"); const tblhr = document.createElement("tr"); let col = this.text_element("th", "Status"); col.classList.add("col-status"); tblhr.appendChild(col); col = this.text_element("th", "Exercise"); col.classList.add("col-name"); tblhr.appendChild(col); col = this.text_element("th", "Pattern/Count"); col.classList.add("col-pattern-count"); tblhr.appendChild(col); tblh.appendChild(tblhr); tbl.appendChild(tblh); } // Content of table - exercises in the set const tblb = document.createElement("tbody"); el.exercise.forEach(function(ex_el,idx) { wo.render_exercise(tblb, ex_el, idx); }); tbl.appendChild(tblb); this.container.appendChild(tbl); } // ---------- render_workout() { const wo = this; this.render_workout_header(); if (this.show_debug_status) { this.render_debug_status(); } this.plan.set.forEach(function(el,idx) { wo.render_set(el, idx); }); this.update_debug_info(); } // ---------- update_active_item() { let wo = this; // Make current active exercise row inactive const curr_active_tr = this.container.querySelector(".exercise-row.active"); let wo_set_idx = this.set_idx; let wo_exercise_idx = this.exercise_idx; let wo_set_repeat_idx = this.set_repeat_idx; const max_set_idx = this.plan.set.length-1; const max_set_repeat_idx = this.plan.set[max_set_idx].count-1; const max_exercise_idx = this.plan.set[max_set_idx].exercise.length-1; if (curr_active_tr != null) { curr_active_tr.classList.remove("active"); } // Set active exercise row let qstr = `table.set-table-idx-${wo_set_idx} tr.exercise-idx-${wo_exercise_idx}`; console.log(`update_active_item - Looking for ${qstr}`); const next_active_tr = this.container.querySelector(qstr); if (next_active_tr != null) { next_active_tr.classList.add("active"); } // Set set repeat indicators let set_tables = this.container.querySelectorAll(".set-table"); set_tables.forEach(function(stbl, tidx) { let indicators = stbl.querySelectorAll(".progress-indicator"); indicators.forEach(function(ids, iidx) { let ind_selector = `#set-${tidx}-${iidx}-indicator`; console.log(`update_active_item - Ind: ${ind_selector} for set_idx ${wo_set_idx} repeat_idx ${wo_set_repeat_idx}`); // if (stbl.querySelector(ind_selector) == null) return; console.log(`update_active_item - Ind: tidx ${tidx} is ?? set_idx ${wo_set_idx}`); if (tidx < wo_set_idx) { stbl.querySelector(ind_selector).classList.remove("pending"); stbl.querySelector(ind_selector).classList.remove("active"); stbl.querySelector(ind_selector).classList.add("done"); } else if (tidx > wo_set_idx) { stbl.querySelector(ind_selector).classList.remove("done"); stbl.querySelector(ind_selector).classList.remove("active"); stbl.querySelector(ind_selector).classList.add("pending"); } else if (tidx == wo_set_idx) { const ex_chkbox = stbl.querySelector(`tr.exercise-idx-${wo_exercise_idx} input`); if ((iidx < wo_set_repeat_idx) // || ((iidx == wo_set_repeat_idx) && ex_chkbox.checked) || ((iidx == wo_set_repeat_idx) && wo.plan.set[tidx].exercise[wo_exercise_idx].done) ){ console.log(`update_active_item - Ind: iidx ${iidx} is < repeat_idx ${wo_set_repeat_idx} DONE`); stbl.querySelector(ind_selector).classList.remove("pending"); stbl.querySelector(ind_selector).classList.remove("active"); stbl.querySelector(ind_selector).classList.add("done"); } else if (iidx > wo_set_repeat_idx) { console.log(`update_active_item - Ind: iidx ${iidx} is > repeat_idx ${wo_set_repeat_idx} PENDING`); stbl.querySelector(ind_selector).classList.remove("done"); stbl.querySelector(ind_selector).classList.remove("active"); stbl.querySelector(ind_selector).classList.add("pending"); } else { console.log(`update_active_item - Ind: iidx ${iidx} is = repeat_idx ${wo_set_repeat_idx} ACTIVE`); stbl.querySelector(ind_selector).classList.remove("pending"); stbl.querySelector(ind_selector).classList.remove("done"); stbl.querySelector(ind_selector).classList.add("active"); } } }); }); this.plan.set.forEach(function(el,idx) { let sidx = idx; el.exercise.forEach(function(eel, eidx) { let qstr = `table.set-table-idx-${sidx} tr.exercise-idx-${eidx}`; const active_tr = wo.container.querySelector(qstr); active_tr.classList.remove("exercise-pending"); qstr = `table.set-table-idx-${sidx} tr.exercise-idx-${eidx} input`; const active_chkbox = wo.container.querySelector(qstr); active_chkbox.disabled = true; active_chkbox.checked = (wo.plan.set[sidx].exercise[eidx].done == 1); }); }); // Mark workout done if (this.workout_done == 1) { const wo_indicator = this.container.querySelector("#wo-indicator"); wo_indicator.classList.remove("pending"); wo_indicator.classList.add("done"); } } // ---------- handle_exercise_advance() { const curr_exercise_max_idx = this.plan.set[this.set_idx].exercise.length-1; const curr_set_repeat_max_idx = this.plan.set[this.set_idx].count-1; const curr_set_max_idx = this.plan.set.length-1; console.log(`handle_exercise_advance - Workout done ${this.workout_done} curr_exercise_max_idx = ${curr_exercise_max_idx} curr_set_max_idx = ${curr_set_max_idx}`); this.handle_exercise_done(); if (this.exercise_idx === curr_exercise_max_idx) { if (this.set_repeat_idx == curr_set_repeat_max_idx) { if (this.set_idx === curr_set_max_idx) { if (this.workout_done === 1) { console.log("handle_exercise_advance - Exercise done"); } } else { this.set_idx += 1; this.set_repeat_idx = 0; this.exercise_idx = 0; this.handle_set_undone(); } } else { this.set_repeat_idx += 1; this.exercise_idx = 0; this.handle_set_undone(); } } else { this.exercise_idx += 1; } } // ---------- handle_exercise_regress() { const curr_set_max_idx = this.plan.set.length-1; const curr_set_repeat_max_idx = this.plan.set[this.set_idx].count-1; if (this.exercise_idx === 0) { if (this.set_repeat_idx === 0) { if (this.set_idx === 0) { console.log("handle_exercise_regress - Exercise start"); } else { this.set_idx -= 1; this.set_repeat_idx = this.plan.set[this.set_idx].count-1; this.exercise_idx = this.plan.set[this.set_idx].exercise.length-1; this.handle_set_done(); } } else { this.set_repeat_idx -= 1; this.exercise_idx = this.plan.set[this.set_idx].exercise.length-1; this.handle_set_done(); } } else { this.exercise_idx -= 1; } this.handle_exercise_undone(); } // ---------- handle_exercise_done() { if (this.plan.set[this.set_idx].exercise[this.exercise_idx].done == 0) { this.plan.set[this.set_idx].exercise[this.exercise_idx].done = 1; } console.log(this.plan.set[this.set_idx]); this.handle_workout_done(); } // ---------- handle_exercise_undone() { if (this.plan.set[this.set_idx].exercise[this.exercise_idx].done == 1) { this.plan.set[this.set_idx].exercise[this.exercise_idx].done = 0; } } // ---------- handle_set_done() { // Set active exercise row let qstr = `table.set-table-idx-${this.set_idx} tr input`; console.log(`handle_set_done - Looking for ${qstr}`); this.plan.set[this.set_idx].exercise.forEach(function(ex, idx) { ex.done = 1; }); } // ---------- handle_set_undone() { // Set active exercise row let qstr = `table.set-table-idx-${this.set_idx} tr input`; console.log(`handle_set_undone - Looking for ${qstr}`); this.plan.set[this.set_idx].exercise.forEach(function(ex, idx) { ex.done = 0; }); } // ---------- handle_workout_done() { let wo = this; const max_set_idx = this.plan.set.length-1; const max_set_repeat_idx = this.plan.set[max_set_idx].count-1; const max_exercise_idx = this.plan.set[max_set_idx].exercise.length-1; if ((this.set_idx === max_set_idx) && (this.set_repeat_idx === max_set_repeat_idx) && (this.exercise_idx === max_exercise_idx) && (this.plan.set[this.set_idx].exercise[this.exercise_idx].done == 1)) { this.workout_done = 1; } console.log(`handle_workout_done - ${this.workout_done}`); console.log(` compare: ${this.set_idx} === ${max_set_idx}`); console.log(` compare: ${this.set_repeat_idx} === ${max_set_idx}`); console.log(` compare: ${this.exercise_idx} === ${max_exercise_idx}`); } // ---------- handle_key_press(app, ev) { if (app.workout_done) { return; } // Access the pressed key using ev.key const key = ev.key; // Advance exercise if (key === 'n') { app.action = `Key-${ev.key}`; app.handle_exercise_advance(); } else if (key === 'N') { app.action = `Key-${ev.key}`; app.handle_exercise_regress(); } else if (key === ' ') { app.action = `Key-${ev.key}`; app.handle_exercise_done(); } else { app.action = `UN Key-${ev.key}`; } app.update_debug_info(); app.update_active_item(); } // ---------- render() { const app = this; this.render_workout(); this.update_active_item(); document.addEventListener('keydown', function(ev) { app.handle_key_press(app, ev); }); } }