From: Alex-Laptop <alexmjoss2413@gmail.com> Date: Tue, 19 Dec 2017 22:06:37 +0000 (-0800) Subject: added old php files X-Git-Tag: v1.0.0~90 X-Git-Url: http://git.infiniteadaptability.org/?a=commitdiff_plain;h=798713a7114c9f2a7c18c4d7d468ab4feb9f238f;p=workouts added old php files --- diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..0da445d --- /dev/null +++ b/README.txt @@ -0,0 +1,15 @@ +Created by Alex Joss +Version: 0.0.0 +Publish Date: 0000-00-00 +Last Updated: 2017-07-05 + +Currently Working On: + +Bugs: + +Plan: +-consider adding add workout button + +Tests: + +Summary: \ No newline at end of file diff --git a/WorkoutManagementAttributesManager/AttributesManagerRow/AttributesManagerRow.php b/WorkoutManagementAttributesManager/AttributesManagerRow/AttributesManagerRow.php new file mode 100644 index 0000000..c113ad0 --- /dev/null +++ b/WorkoutManagementAttributesManager/AttributesManagerRow/AttributesManagerRow.php @@ -0,0 +1,133 @@ +<script type="text/javascript"> +var AttributesManagerRow = React.createClass({ + getInitialState: function () { + return ({dragEnd:Number(this.props.data.attribute_num)*5,edit:0,name:this.props.data.attribute_name,label:this.props.data.attribute_label,comments:this.props.data.comments}); + }, + componentDidUpdate: function (prevProps,prevState) { + if((this.state.dragging)&&(!prevState.dragging)&&(this.state.edit===0)){ + document.addEventListener('mousemove',this.onMouseMove); + document.addEventListener('mouseup',this.onMouseUp); + } + else if((!this.state.dragging)&&(prevState.dragging)){ + document.removeEventListener('mousemove',this.onMouseMove); + document.removeEventListener('mouseup',this.onMouseUp); + } + /*var attrnum = this.props.data.attribute_num; + $('#attribute-manager-row-'+this.props.data.id).draggable({ + containment:'parent', + revert:true, + start: function () { + //console.log('start drag'); + }, + stop: function (e,ui) { + var vd = ui.position.top/$(this).outerHeight(); + serverRequest({query_type:"workout_management_attributes_reorder",attrnum:attrnum,vd:vd}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("AttributesManagerRow","workout_management_attributes_reorder",error); + }); + + } + });*/ + }, + componentWillReceiveProps: function (nextProps) { + if(this.state.edit!==1){ + if((!(Number.isInteger(this.state.dragEnd)))||(this.props.data.attribute_num!=nextProps.data.attribute_num)){ + this.setState({dragEnd:Number(nextProps.data.attribute_num)*5}); + } + } + }, + shouldComponentUpdate: function (nextProps,nextState) { + if((JSON.stringify(nextState)==JSON.stringify(this.state))&&(JSON.stringify(nextProps)==JSON.stringify(this.props))){ + return false; + } + return true; + }, + onMouseDown: function (event) { + var target = event.target; + var targettype = target.tagName.toLowerCase(); + if((targettype!="i")&&(targettype!="input")){ + this.setState({dragging:true,dragStart:event.pageY}); + event.stopPropagation(); + event.preventDefault(); + } + }, + onMouseUp: function (event) { + this.setState({dragging:false},function () { + this.handleDragEnd(); + }); + event.stopPropagation(); + event.preventDefault(); + }, + onMouseMove: function (event) { + if(!(this.state.dragging)){ + return false; + } + this.setState({dragEnd:(100*(event.pageY-this.state.dragStart)/document.documentElement.clientHeight)+this.props.data.attribute_num*5}); + }, + handleDragEnd: function () { + var vd = (this.state.dragEnd - this.props.data.attribute_num*5)/5; + serverRequest({query_type:"workout_management_attributes_reorder",attrnum:this.props.data.attribute_num,vd:vd}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("AttributeManagerRow.php","workout_management_attributes_reorder",error); + }); + }, + handleSetEdit: function () { + this.setState({edit:(this.state.edit==0)?1:0}); + }, + handleChange: function (type,event) { + if(this.state.edit==1){ + switch(type){ + case "name": + this.setState({name:event.target.value}); + break; + case "label": + this.setState({label:event.target.value}); + break; + case "comments": + this.setState({comments:event.target.value}); + break; + default: + console.log('error'); + break; + } + } + }, + handleAcceptChanges: function () { + serverRequest({query_type:"workout_management_attribute_save",id:this.props.data.id,name:this.state.name,label:this.state.label,comments:this.state.comments}) + .then(function(data) { + console.log(data); + this.setState({edit:0}); + }.bind(this)) + .catch(function(error) { + console.error("AttributesManagerRow","workout_management_attribute_save",error); + }); + }, + handleDelete: function () { + var c = confirm("Are you sure you wish to delete this attribute [name=\""+this.state.name+"\"] ?"); + if(c==true){ + serverRequest({query_type:"workout_management_attribute_delete",id:this.props.data.id}) + .then(function(data) { + console.log(data); + this.setState({edit:"deleted"}); + }.bind(this)) + .catch(function(error) { + console.error("AttributesManagerRow","workout_management_attribute_delete",error); + }); + } + }, + render: function () { + return React.createElement("div",{style:{top:this.state.dragEnd+"vh"},className:((this.state.edit==1)?"editable":"")+" wm-attributes-manager-row",onMouseDown:this.onMouseDown}, + (this.state.edit===1)?React.createElement("input",{type:"text",value:this.state.name,onChange:this.handleChange.bind(this,"name")}):React.createElement("span",null,this.state.name), + (this.state.edit===1)?React.createElement("i",{className:"fa fa-check",onClick:this.handleAcceptChanges}):"", + React.createElement("i",{className:"fa fa-pencil",onClick:this.handleSetEdit}), + React.createElement("i",{className:"fa fa-trash",onClick:this.handleDelete}) + ); + } +}); +</script> \ No newline at end of file diff --git a/WorkoutManagementAttributesManager/WorkoutManagementAttributesManager.php b/WorkoutManagementAttributesManager/WorkoutManagementAttributesManager.php new file mode 100644 index 0000000..e89cc97 --- /dev/null +++ b/WorkoutManagementAttributesManager/WorkoutManagementAttributesManager.php @@ -0,0 +1,27 @@ +<script type="text/javascript"> +var WorkoutManagementAttributesManager = React.createClass({ + handleAddNewAttr: function () { + serverRequest({query_type:"workout_management_add_attribute"}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("WorkoutManagementAttributesManager","workout_management_add_attribute",error); + }); + }, + render: function () { + var rows = []; + for(var attr in this.props.data){ + rows.push(React.createElement(AttributesManagerRow,{key:"wm-attr-manager-row-"+this.props.data[attr].id,data:this.props.data[attr]})); + } + return React.createElement("div",{className:"wm-attr-manager-div"}, + React.createElement("h3",null,"Manage Attributes"), + React.createElement("div",{style:{height:5*this.props.data.length+"vh"},className:"wm-attr-manager-container"},rows), + React.createElement("input",{type:"button",onClick:this.handleAddNewAttr,value:"Add New Attribute"}) + ); + } +}); +</script> +<?php +require("AttributesManagerRow/AttributesManagerRow.php"); +?> \ No newline at end of file diff --git a/WorkoutManagementDaysAgoTableData/WorkoutManagementDaysAgoTableData.php b/WorkoutManagementDaysAgoTableData/WorkoutManagementDaysAgoTableData.php new file mode 100644 index 0000000..e31bf55 --- /dev/null +++ b/WorkoutManagementDaysAgoTableData/WorkoutManagementDaysAgoTableData.php @@ -0,0 +1,26 @@ +<script type="text/javascript"> +var WorkoutManagementDaysAgoTableData = React.createClass({//Recent Workouts Table + render: function() { + var heads = []; + for(var attr in this.props.attributes){ + heads.push(React.createElement("th",{key:"da-th-"+attr},this.props.attributes[attr]["attribute_name"])); + } + var rows=[]; + rows.push(React.createElement("td",{key:"da"},"Days Ago")); + for(var key in this.props.data){ + rows.push(React.createElement("td",{key:"da-"+key},this.props.data[key])); + } + return React.createElement("table",{className:(heads.length>0)?"":"hidden"}, + React.createElement("thead",null, + React.createElement("tr",null, + React.createElement("th",null), + heads + ) + ), + React.createElement("tbody",null, + React.createElement("tr",null,rows) + ) + ); + } +}); +</script> \ No newline at end of file diff --git a/WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTable.php b/WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTable.php new file mode 100644 index 0000000..8785b46 --- /dev/null +++ b/WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTable.php @@ -0,0 +1,107 @@ +<script type="text/javascript"> +var WorkoutManagementWorkoutTable = React.createClass({ + loadDataFromServer: function () { + serverRequest({query_type:"workout_management_table_data",sorting:this.state.sorting,order:this.state.order},"json") + .then(function(data) { + //console.log(data); + if(data.hash!=this.state.hash){ + this.setState({data:data.raw,hash:data.hash}); + } + }.bind(this)) + .catch(function(error) { + console.error("WorkoutManagementWorkoutTable.php","workout_management_table_data",error); + }); + }, + componentDidMount: function () { + this.loadDataFromServer(); + }, + shouldComponentUpdate: function (nextProps,nextState) { + if((this.props.hash!=nextProps.hash)||(JSON.stringify(this.state)!=JSON.stringify(nextState))){ + return true; + } + return false; + }, + componentWillReceiveProps: function (nextProps) { + if(this.props.hash!=nextProps.hash){ + this.loadDataFromServer(); + } + }, + getInitialState: function() { + return {data:[],hash:""}; + }, + changeSorting: function (key,event) { + if(typeof this.state.sorting=="undefined"){ + var toset = {}; + toset[key]="ASC"; + var order = [key]; + } + else { + var toset = this.state.sorting; + var order = (typeof this.state.order!="undefined")?this.state.order:[]; + if(typeof this.state.sorting[key]!="undefined"){ + toset[key]=(this.state.sorting[key]=="ASC")?"DESC":"ASC"; + } + else { + toset[key]="ASC"; + } + if(event.shiftKey){ + if(order.indexOf(key)<0){ + order.push(key); + } + } + else { + for(var i in toset){ + if(i!=key){ + delete toset[i]; + } + } + order = [key]; + } + } + this.setState({sorting:toset,order:order},function () { + this.loadDataFromServer(); + }); + }, + render: function() { + var rows = []; + var rowtype = "odd"; + for(var i in this.state.data){ + rows.push(React.createElement(WorkoutManagementWorkoutTableRows,{key:"wm-row-"+this.state.data[i].id,data:this.state.data[i],rowtype:rowtype})); + rowtype = (rowtype=="odd")?"even":"odd"; + } + var heads = []; + for(var head in this.props.attributes){ + heads.push(React.createElement("th",{key:"workout-table-head-"+head,className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting["workout_attributes_"+this.props.attributes[head]["attribute_num"]]!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"workout_attributes_"+this.props.attributes[head]["attribute_num"])},this.props.attributes[head]["attribute_name"], + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting["workout_attributes_"+this.props.attributes[head]["attribute_num"]]!="undefined"))?"fa fa-sort-"+this.state.sorting["workout_attributes_"+this.props.attributes[head]["attribute_num"]].toLowerCase():"fa fa-sort"}) + )); + } + return React.createElement("div",null, + React.createElement("div",{className:"workout-management-table-div"}, + React.createElement("table",{className:"workout-management-table"}, + React.createElement("thead",null, + React.createElement("tr",null, + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.workout_name!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"workout_name")},"Workout Name", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.workout_name!="undefined"))?"fa fa-sort-"+this.state.sorting.workout_name.toLowerCase():"fa fa-sort"}) + ), + heads, + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.times!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"times")},"Times Done", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.times!="undefined"))?"fa fa-sort-"+this.state.sorting.times.toLowerCase():"fa fa-sort"}) + ), + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.last!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"last")},"Last Done", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.last!="undefined"))?"fa fa-sort-"+this.state.sorting.last.toLowerCase():"fa fa-sort"}) + ), + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.comments!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"comments")},"Comments", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.comments!="undefined"))?"fa fa-sort-"+this.state.sorting.comments.toLowerCase():"fa fa-sort"}) + ) + ) + ), + React.createElement("tbody",null,rows) + ) + ) + ); + } +}); +</script> +<?php +require("WorkoutManagementWorkoutTableRows/WorkoutManagementWorkoutTableRows.php"); +?> \ No newline at end of file diff --git a/WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTableRows/WorkoutManagementWorkoutTableRows.php b/WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTableRows/WorkoutManagementWorkoutTableRows.php new file mode 100644 index 0000000..34cad12 --- /dev/null +++ b/WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTableRows/WorkoutManagementWorkoutTableRows.php @@ -0,0 +1,81 @@ +<script type="text/javascript"> +var WorkoutManagementWorkoutTableRows = React.createClass({//Workout Management Table Rows + getInitialState: function () { + var attrs = JSON.parse(JSON.stringify(this.props.data.attrs)); + return {workout_name:this.props.data.name,comments:this.props.data.comments,attributes:attrs,view:""}; + }, + handleValueChange: function(type,event) { + switch(type){ + case "workout_name": + this.setState({workout_name:event.target.value}); + break; + case "comments": + this.setState({comments:event.target.value}); + break; + default: + console.log('error'); + } + }, + sendValues: function () { + serverRequest({query_type:'workout_management_edit',id:this.props.data.id,workout_name:this.state.workout_name,attributes:this.state.attributes,comments:this.state.comments}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("WorkoutManagementWorkoutTableRows.php","workout_management_edit",error); + }); + }, + handleAttrToggle: function (attr) { + var attrs = JSON.parse(JSON.stringify(this.state.attributes)); + attrs[attr]=(attrs[attr]=="No")?"Yes":"No"; + this.setState({attributes:attrs},function () { + this.sendValues(); + }); + }, + deleteToggle: function (type) { + this.setState({deletetd:type}); + }, + deleteEntry: function () { + var c = confirm("Are you sure you wish to delete this workout? This will also delete all data of completion of this workout."); + if(c==true){ + this.setState({view:"hidden"},function () { + serverRequest({query_type:'workout_management_delete',id:this.props.data.id}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("WorkoutManagementWorkoutTableRows.php","workout_management_delete",error); + }); + }); + } + }, + render: function () { + var cells = []; + for(var attr in this.state.attributes){ + cells.push(React.createElement("td",{key:"wm-row-"+this.props.data.id+"-attr-"+attr,onClick:this.handleAttrToggle.bind(this,attr)}, + React.createElement("span",null,this.state.attributes[attr]) + )); + } + return React.createElement("tr",{className:this.props.rowtype+" "+this.state.view}, + React.createElement("td",{className:"inputok"}, + React.createElement("input",{className:"workout-management-table-input",value:this.state.workout_name,type:"text",onChange:this.handleValueChange.bind(this,"workout_name"),onBlur:this.sendValues}) + ), + cells, + React.createElement("td",null, + React.createElement("span",null,this.props.data['times_done']) + ), + React.createElement("td",null, + React.createElement("span",null,this.props.data['last_done']) + ), + React.createElement("td",{className:"inputok"}, + React.createElement("textarea",{className:"workout-management-table-comments",value:this.state.comments,onChange:this.handleValueChange.bind(this,"comments"),onBlur:this.sendValues}), + React.createElement("div",{className:this.state.deletetd}, + React.createElement("div",{className:"workout-management-table-delete-container"}, + React.createElement("i",{className:"fa fa-trash-o",onClick:this.deleteEntry}) + ) + ) + ) + ); + } +}); +</script> \ No newline at end of file diff --git a/class.module_workout_management.php b/class.module_workout_management.php new file mode 100644 index 0000000..d5257e1 --- /dev/null +++ b/class.module_workout_management.php @@ -0,0 +1,232 @@ +<?php + +/** + * Workout Management Module + * Required methods, then custom methods, then variables + * Three variables are required (header, stylesheets, module_file) + * Add to required_table_structure variable and uncomment the table_verify function in the __construct method to check table structure before loading class + */ + +class module_workout_management extends module implements imodule { + + const MODULE_NAME = "Workout Management"; + + public function __construct() { + parent::__construct(); + if(!($this->table_verify($this->get_required_module_table_data()))){ + self::log_error(self::MODULE_NAME." required tables verification failed."); + } + //Options: Module Name,linked module path,quick_tool_icon (font awesome icon class) + //Default is array ("",NULL,NULL) + $options = array (self::MODULE_NAME,NULL,"fa fa-bolt fa-lg"); + if(!($this->module_check(__FILE__,$options))){ + self::log_error(self::MODULE_NAME." module not loaded correctly."); + } + if(!($this->public_check($this->fields_marked_public,__FILE__))){ + self::log_error(self::MODULE_NAME." public fields not correctly implemented."); + } + } + + //Start required methods + public function cron_tasks () { + //Insert any methods here to run every 30 minutes, make sure to return TRUE + return TRUE; + } + + public function get_header () { + //Add any extra javascript scripts/css required to header + $return = $this->get_default_header(); + if((stripos($return,"</HEAD>")!==FALSE)&&(stripos($return,"</HEAD>")==strlen($return)-7)){ + if((is_array($this->header_scripts))&&(count($this->header_scripts)>0)){ + $return = rtrim($return,"</HEAD>"); + foreach($this->header_scripts as $i=>$v){ + if($v['sri']!=""){ + $return .= "<script type='".$v['type']."' src='".$v['src']."' integrity='".$v['sri']."' crossorigin='anonymous'></script>\n"; + } + else { + $return .= "<script type='".$v['type']."' src='".$v['src']."'></script>\n"; + } + } + $return .= "</HEAD>"; + } + $stylesheets = $this->get_stylesheets(); + if($stylesheets!=""){ + $return = rtrim($return,"</HEAD>"); + $return .= $stylesheets; + $return .= "</HEAD>"; + } + } + return $return; + } + + public function get_required_module_table_data ($type = "all") { + $tables = $this->required_table_structure; + foreach($tables as $name=>$rows){ + //Double check blockchain tracking row and delete once found + if(!((isset($rows[0]))&&(($rows[0]===0)||($rows[0]===1)))){ + unset($tables[$name]); + self::log_error(sprintf("Table structure data for `%s` not formatted correctly.%s",$name)); + continue; + } + if(($rows[0]===0)&&($type!="all")){ + unset($tables[$name]); + } + else { + unset($rows[0]); + $tables[$name] = array_values($rows); + } + } + return $tables; + } + + public function get_stylesheets () { + //Generate stylesheet <link>(s) + $return = ""; + if(file_exists(__DIR__.DIRECTORY_SEPARATOR."style.css")){ + $return .= "<LINK href='".ltrim(substr(__DIR__.DIRECTORY_SEPARATOR."style.css",strlen(dirname(dirname(dirname(__DIR__))))),"/")."' rel='stylesheet' type='text/css'>\n"; + } + foreach($this->stylesheets as $i=>$v){ + $return .= "<LINK href='".$v['href']."' rel='".$v['rel']."' type='".$v['type']."'>\n"; + } + return $return; + } + + public function load_module ($get_header = NULL,$module_file = NULL,$generate_menu = FALSE) { + //Add 3rd parameter bool (TRUE to generate menu, FALSE or omit to not) + //Check to see if this has been called from child module + if(($get_header===NULL)||($module_file===NULL)){ + if(!(parent::load_module($this->get_header(),__DIR__.DIRECTORY_SEPARATOR.$this->module_file,TRUE))){ + return FALSE; + } + } + else { + if(!(parent::load_module($get_header,$module_file,$generate_menu))){ + return FALSE; + } + } + return TRUE; + } + //End required methods + + //Start custom methods + protected function build_sortby ($sort = array(),$order = array()) { + $return = " ORDER BY"; + $valid_fields = array( + "c" => array (//Fields in/derived from workout_count (always abbreviated `c` in SQL) + "comments_count", + "date", + "last_done", + "times_done" + ), + "w" => array (//Fields in/derived from `workouts` (always abbreviated `w` in SQL) + "workout_name", + "workout_attributes", + "comments" + ), + "a" => array (//Fields in `worktous_attributes` (always abbreviated `a` in SQL) + "attribute_num", + "attribute_name", + "attribute_label", + ) + ); + foreach($sort as $f=>$type) { + if(strpos($f,"workout_attributes")!==FALSE){ + continue; + } + if(!((in_array($f,$valid_fields["c"]))||(in_array($f,$valid_fields["w"]))||(in_array($f,$valid_fields["a"])))){ + unset($sort[$f]); + } + } + foreach($order as $i=>$f){ + if(in_array($f,$valid_fields["c"])){ + if($f=="comments_count"){ + $f="comments"; + $sort[$f]=$sort["comments_count"]; + } + $return .= sprintf(" `c`.`%s` %s,",$f,($sort[$f]=="ASC")?"ASC":"DESC"); + } + else if(strpos($f,"workout_attributes")!==FALSE){ + $return .= sprintf(" SUBSTRING(`w`.`workout_attributes`,%d,1) %s,",((int) substr($f,19))+1,($sort[$f]=="ASC")?"ASC":"DESC"); + } + else if(in_array($f,$valid_fields["w"])){ + $return .= sprintf(" `w`.`%s` %s,",$f,($sort[$f]=="ASC")?"ASC":"DESC"); + } + else if(in_array($f,$valid_fields["a"])){ + $return .= sprintf(" `a`.`%s` %s,",$f,($sort[$f]=="ASC")?"ASC":"DESC"); + } + } + $return = rtrim($return,","); + if($return==" ORDER BY"){ + return ""; + } + else { + return $return; + } + } + //End custom methods + + //Start required table structure data + //Use the following code to generate table data + /* + $data = array(0 => 0);//Change to 1 if tracked by blockchain + $query = "DESCRIBE `%%TABLE_NAME%%`;"; + $result = mysqli_query($db,$query) or die(mysqli_error($db)); + while($row = mysqli_fetch_assoc($result)){ + $data[]=$row; + } + exit("<pre>".var_export($data)."</pre>"); + */ + private $required_table_structure = array ( + "workouts" => array ( + 0 => 1, + 1 => array ( 'Field' => 'id', 'Type' => 'int(11)', 'Null' => 'NO', 'Key' => 'PRI', 'Default' => NULL, 'Extra' => 'auto_increment', ), + 2 => array ( 'Field' => 'siid', 'Type' => 'int(11)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 3 => array ( 'Field' => 'workout_name', 'Type' => 'varchar(50)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 4 => array ( 'Field' => 'workout_attributes', 'Type' => 'varchar(30)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 5 => array ( 'Field' => 'comments', 'Type' => 'text', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 6 => array ( 'Field' => 'modified', 'Type' => 'timestamp', 'Null' => 'NO', 'Key' => '', 'Default' => 'CURRENT_TIMESTAMP', 'Extra' => 'on update CURRENT_TIMESTAMP', ), + ), + "workouts_attributes" => array ( + 0 => 1, + 1 => array ( 'Field' => 'id', 'Type' => 'int(11)', 'Null' => 'NO', 'Key' => 'PRI', 'Default' => NULL, 'Extra' => 'auto_increment', ), + 2 => array ( 'Field' => 'attribute_num', 'Type' => 'int(11)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 3 => array ( 'Field' => 'attribute_name', 'Type' => 'varchar(255)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 4 => array ( 'Field' => 'attribute_label', 'Type' => 'varchar(255)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 5 => array ( 'Field' => 'comments', 'Type' => 'text', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 6 => array ( 'Field' => 'modified', 'Type' => 'timestamp', 'Null' => 'NO', 'Key' => '', 'Default' => 'CURRENT_TIMESTAMP', 'Extra' => 'on update CURRENT_TIMESTAMP', ), + ), + "workout_count" => array ( + 0 => 1, + 1 => array ( 'Field' => 'id', 'Type' => 'int(11)', 'Null' => 'NO', 'Key' => 'PRI', 'Default' => NULL, 'Extra' => 'auto_increment', ), + 2 => array ( 'Field' => 'wid', 'Type' => 'int(11)', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 3 => array ( 'Field' => 'date', 'Type' => 'date', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 4 => array ( 'Field' => 'comments', 'Type' => 'text', 'Null' => 'NO', 'Key' => '', 'Default' => NULL, 'Extra' => '', ), + 5 => array ( 'Field' => 'modified', 'Type' => 'timestamp', 'Null' => 'NO', 'Key' => '', 'Default' => 'CURRENT_TIMESTAMP', 'Extra' => 'on update CURRENT_TIMESTAMP', ), + ) + ); + //End required table structure data + + //Start public fields + //Fields in this area will be added to the public table so that they will be displayed in the public feed area + //Format of each row: 0 => array ("table" => "", "title_field" => "", "description_field" => "","denotes_public_field" => "","denotes_public_value"=>"" ) + private $fields_marked_public = array ( + + ); + //End public fields + + //Header Variable (each row contains info linking to a javascript script used by the module and inserted into the header) + //Format of each row: 0 => array ("type" => "", "src" => "", "sri" => "") + private $header_scripts = array ( + + ); + + //Extra stylesheet information (each row contains a stylesheet to be loaded with the module + //Format for each row: 0 => array ( "href" => "", "rel"=> "", "type"=>"" ) + private $stylesheets = array ( + + ); + + //Main file to load -- fill in and update + private $module_file = "workout_management.php"; + +} \ No newline at end of file diff --git a/recent_workouts/RecentWorkoutsTableRow/RecentWorkoutsTableRow.php b/recent_workouts/RecentWorkoutsTableRow/RecentWorkoutsTableRow.php new file mode 100644 index 0000000..cc21535 --- /dev/null +++ b/recent_workouts/RecentWorkoutsTableRow/RecentWorkoutsTableRow.php @@ -0,0 +1,82 @@ +<script type="text/javascript"> +var RecentWorkoutsTableRow = React.createClass({ + getInitialState: function () { + return {wid:this.props.data.wid,date:this.props.data.date,comments:this.props.data.comments,deletetd:"hidden",view:""}; + }, + handleValueChange: function(event,type) { + switch(type){ + case "wid": + this.setState({wid:event.target.value},function () { + this.sendValues(); + }); + break; + case "comments": + this.setState({comments:event.target.value}); + break; + default: + console.log('error'); + } + }, + setDate: function (newdate) { + this.setState({date:newdate},function () { + this.sendValues(); + }); + }, + handleDatePicker: function (event) { + generateDatePicker(event.target.value) + .then(function(result) { + if(result!==false){ + this.setDate(result); + } + }.bind(this)); + }, + sendValues: function () { + serverRequest({query_type:'recent_workouts_edit',wid:this.state.wid,comments:this.state.comments,date:this.state.date,id:this.props.data.id}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("RecentWorkoutsTableRow.php","recent_workouts_edit",error); + }); + }, + deleteToggle: function (type) { + this.setState({deletetd:type}); + }, + deleteEntry: function () { + var c = confirm("Are you sure you wish to delete this workout?"); + if(c==true){ + this.setState({view:"hidden"},function () { + serverRequest({query_type:'recent_workouts_delete',id:this.props.data.id}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("RecentWorkoutsTableRow.php","recent_workouts_delete",error); + }); + }); + } + }, + render: function() { + var options = []; + for (var workout in this.props.workouts){ + options.push(React.createElement("option",{value:this.props.workouts[workout].id,key:this.props.data.id+'-'+workout},this.props.workouts[workout].workout_name)); + } + return React.createElement("tr",{onMouseEnter:this.deleteToggle.bind(this,""),onMouseLeave:this.deleteToggle.bind(this,"hidden"),className:this.props.rowtype+" "+this.state.view}, + React.createElement("td",{className:"inputok"}, + React.createElement("select",{className:"recent-workouts-table-select",value:this.state.wid,onChange:this.handleValueChange.bind(this,"wid")},options) + ), + React.createElement("td",{className:"inputok"}, + React.createElement("input",{readOnly:true,className:"recent-workouts-table-input",value:this.state.date,onClick:this.handleDatePicker}) + ), + React.createElement("td",{className:"inputok"}, + React.createElement("textarea",{className:"recent-workouts-table-textarea",value:this.state.comments,onChange:this.handleValueChange.bind(this,"comments"),onBlur:this.sendValues}), + React.createElement("div",{className:this.state.deletetd}, + React.createElement("div",{className:"recent-workouts-table-delete-container"}, + React.createElement("i",{className:"fa fa-trash-o",onClick:this.deleteEntry}) + ) + ) + ) + ); + } +}); +</script> \ No newline at end of file diff --git a/recent_workouts/class.module_recent_workouts.php b/recent_workouts/class.module_recent_workouts.php new file mode 100644 index 0000000..b78bd75 --- /dev/null +++ b/recent_workouts/class.module_recent_workouts.php @@ -0,0 +1,154 @@ +<?php + +/** + * Recent Workouts Module Class + * Required methods, then custom methods, then variables + * Three variables are required (header, stylesheets, module_file) + * Add to required_table_structure variable and uncomment the table_verify function in the __construct method to check table structure before loading class + */ + +class module_recent_workouts extends module_workout_management implements imodule { + + const MODULE_NAME = "Recent Workouts"; + + public function __construct() { + parent::__construct(); + if(!($this->table_verify($this->get_required_module_table_data()))){ + self::log_error(self::MODULE_NAME." required tables verification failed."); + } + //Options: Module Name,linked module path,quick_tool_icon (font awesome icon class) + //Default is array ("",NULL,NULL) + $options = array (self::MODULE_NAME,"workout_management/",NULL); + if(!($this->module_check(__FILE__,$options))){ + self::log_error(self::MODULE_NAME." module not loaded correctly."); + } + if(!($this->public_check($this->fields_marked_public,__FILE__))){ + self::log_error(self::MODULE_NAME." public fields not correctly implemented."); + } + } + + //Start required methods + public function cron_tasks () { + //Insert any methods here to run every 30 minutes, make sure to return TRUE + return TRUE; + } + + public function get_header () { + //Add any extra javascript scripts/css required to header + $return = $this->get_default_header(); + if((stripos($return,"</HEAD>")!==FALSE)&&(stripos($return,"</HEAD>")==strlen($return)-7)){ + if((is_array($this->header_scripts))&&(count($this->header_scripts)>0)){ + $return = rtrim($return,"</HEAD>"); + foreach($this->header_scripts as $i=>$v){ + if($v['sri']!=""){ + $return .= "<script type='".$v['type']."' src='".$v['src']."' integrity='".$v['sri']."' crossorigin='anonymous'></script>\n"; + } + else { + $return .= "<script type='".$v['type']."' src='".$v['src']."'></script>\n"; + } + } + $return .= "</HEAD>"; + } + $stylesheets = $this->get_stylesheets(); + if($stylesheets!=""){ + $return = rtrim($return,"</HEAD>"); + $return .= $stylesheets; + $return .= "</HEAD>"; + } + } + return $return; + } + + public function get_required_module_table_data ($type = "all") { + $tables = $this->required_table_structure; + foreach($tables as $name=>$rows){ + //Double check blockchain tracking row and delete once found + if(!((isset($rows[0]))&&(($rows[0]===0)||($rows[0]===1)))){ + unset($tables[$name]); + self::log_error(sprintf("Table structure data for `%s` not formatted correctly.%s",$name)); + continue; + } + if(($rows[0]===0)&&($type!="all")){ + unset($tables[$name]); + } + else { + unset($rows[0]); + $tables[$name] = array_values($rows); + } + } + return $tables; + } + + public function get_stylesheets () { + //Generate stylesheet <link>(s) + $return = ""; + if(file_exists(__DIR__.DIRECTORY_SEPARATOR."style.css")){ + $return .= "<LINK href='".ltrim(substr(__DIR__.DIRECTORY_SEPARATOR."style.css",strlen(dirname(dirname(dirname(__DIR__))))),"/")."' rel='stylesheet' type='text/css'>\n"; + } + foreach($this->stylesheets as $i=>$v){ + $return .= "<LINK href='".$v['href']."' rel='".$v['rel']."' type='".$v['type']."'>\n"; + } + return $return; + } + + public function load_module ($get_header = NULL,$module_file = NULL,$generate_menu = FALSE) { + //Add 3rd parameter bool (TRUE to generate menu, FALSE or omit to not) + //Check to see if this has been called from child module + if(($get_header===NULL)||($module_file===NULL)){ + if(!(parent::load_module($this->get_header(),__DIR__.DIRECTORY_SEPARATOR.$this->module_file,TRUE))){ + return FALSE; + } + } + else { + if(!(parent::load_module($get_header,$module_file,$generate_menu))){ + return FALSE; + } + } + return TRUE; + } + //End required methods + + //Start custom methods + + //End custom methods + + //Start required table structure data + //Use the following code to generate table data + /* + $data = array(0 => 0);//Change to 1 if tracked by blockchain + $query = "DESCRIBE `%%TABLE_NAME%%`;"; + $result = mysqli_query($db,$query) or die(mysqli_error($db)); + while($row = mysqli_fetch_assoc($result)){ + $data[]=$row; + } + exit("<pre>".var_export($data)."</pre>"); + */ + private $required_table_structure = array ( + + ); + //End required table structure data + + //Start public fields + //Fields in this area will be added to the public table so that they will be displayed in the public feed area + //Format of each row: 0 => array ("table" => "", "title_field" => "", "description_field" => "","denotes_public_field" => "","denotes_public_value"=>"" ) + private $fields_marked_public = array ( + + ); + //End public fields + + //Header Variable (each row contains info linking to a javascript script used by the module and inserted into the header) + //Format of each row: 0 => array ("type" => "", "src" => "", "sri" => "") + private $header_scripts = array ( + 0 => array ("type" => "text/javascript", "src" => "js/custom/datepicker.js", "sri" => "sha384-AbJvjf2C2pgqlpImUmOmuW/mmbyLeKADFVtJynfREH6mETlFGqjxUyXLbDcVy7RY") + ); + + //Extra stylesheet information (each row contains a stylesheet to be loaded with the module + //Format for each row: 0 => array ( "href" => "", "rel"=> "", "type"=>"" ) + private $stylesheets = array ( + 0 => array ("href" => "js/custom/datepicker.css", "rel" => "stylesheet", "type" => "text/css") + ); + + //Main file to load -- fill in and update + private $module_file = "recent_workouts.php"; + +} \ No newline at end of file diff --git a/recent_workouts/recent_workouts.php b/recent_workouts/recent_workouts.php new file mode 100644 index 0000000..d95d197 --- /dev/null +++ b/recent_workouts/recent_workouts.php @@ -0,0 +1,106 @@ +<div class='top-bar'> +<h1>Recent Workouts</h1> +</div> +<div id='content'></div> +<script type="text/javascript">//Recent Workouts Table and Functionality +var RecentWorkoutsTable = React.createClass({ + loadDataFromServer: function () { + serverRequest({query_type:"recent_workouts_data",sorting:this.state.sorting,order:this.state.order,filter:this.state.filter},"json") + .then(function(data) { + console.log(data); + this.setState({workouts:data.workouts,data:data.raw}); + }.bind(this)) + .catch(function(error) { + console.error("recent_workouts.php","recent_workouts_data",error); + }); + }, + getInitialState: function() { + return {hash:"",workouts:[],data:[],filter:""}; + }, + componentDidMount: function() { + this.loadDataFromServer(); + setInterval(this.loadDataFromServer, 2000); + }, + shouldComponentUpdate: function (nextProps,nextState) { + if(JSON.stringify(nextState)==JSON.stringify(this.state)){ + return false; + } + return true; + }, + changeSorting: function (key,event) { + if(typeof this.state.sorting=="undefined"){ + var toset = {}; + toset[key]="ASC"; + var order = [key]; + } + else { + var toset = this.state.sorting; + var order = (typeof this.state.order!="undefined")?this.state.order:[]; + if(typeof this.state.sorting[key]!="undefined"){ + toset[key]=(this.state.sorting[key]=="ASC")?"DESC":"ASC"; + } + else { + toset[key]="ASC"; + } + if(event.shiftKey){ + if(order.indexOf(key)<0){ + order.push(key); + } + } + else { + for(var i in toset){ + if(i!=key){ + delete toset[i]; + } + } + order = [key]; + } + } + this.setState({sorting:toset,order:order},function () { + this.loadDataFromServer(); + }); + }, + handleFilterChange: function (event) { + this.setState({filter:event.target.value}); + }, + render: function() { + var rows = []; + var rowtype = "odd"; + for( var i in this.state.data){ + rows.push(React.createElement(RecentWorkoutsTableRow,{data:this.state.data[i],key:"rtr-"+this.state.data[i].id,workouts:this.state.workouts,rowtype:rowtype})); + rowtype = (rowtype=="odd")?"even":"odd"; + }; + return React.createElement("div",null, + React.createElement("div",{className:"recent-workouts-table-div"}, + React.createElement("div",{className:"recent-workouts-filter-div"}, + React.createElement("input",{placeholder:"Search workouts...",value:this.state.filter,onChange:this.handleFilterChange}) + ), + (rows.length==0)?React.createElement("div",null, + React.createElement("span",null,"No workouts logged.") + ):React.createElement("table",{className:"recent-workouts-table"}, + React.createElement("thead",null, + React.createElement("tr",null, + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.workout_name!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"workout_name")},"Workout Name", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.workout_name!="undefined"))?"fa fa-sort-"+this.state.sorting.workout_name.toLowerCase():"fa fa-sort"}) + ), + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.date!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"date")},"Date", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.date!="undefined"))?"fa fa-sort-"+this.state.sorting.date.toLowerCase():"fa fa-sort"}) + ), + React.createElement("th",{className:(typeof this.state.sorting!="undefined")?(typeof this.state.sorting.comments_count!="undefined")?"sortedby":"":"",onClick:this.changeSorting.bind(this,"comments_count")},"Comments", + React.createElement("i",{className:((typeof this.state.sorting!="undefined")&&(typeof this.state.sorting.comments_count!="undefined"))?"fa fa-sort-"+this.state.sorting.comments_count.toLowerCase():"fa fa-sort"}) + ) + ) + ), + React.createElement("tbody",null,rows) + ) + ) + ); + } +}); +</script> +<?php +require("RecentWorkoutsTableRow/RecentWorkoutsTableRow.php"); +?> +<script type="text/javascript"> +var ReactTable = ReactDOM.render(React.createElement(RecentWorkoutsTable,null),document.getElementById('content')); +</script> diff --git a/recent_workouts/recent_workouts_data.php b/recent_workouts/recent_workouts_data.php new file mode 100644 index 0000000..820b951 --- /dev/null +++ b/recent_workouts/recent_workouts_data.php @@ -0,0 +1,49 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class recent_workouts_data extends module_recent_workouts implements imodquery { + + //Query: recent_workouts_data + + public function execute () { + $db = $this->db; + $tosend = array("raw"=>array(),"workouts"=>array()); + $_POST['filter']="%".$_POST['filter']."%"; + $sortby = ((isset($_POST['sorting']))&&(isset($_POST['order'])))?$this->build_sortby($_POST['sorting'],$_POST['order']):"";//build_sortby is from class_workout_management.php + $stmt = $db->prepare(sprintf("SELECT `c`.`id`,`c`.`wid`,`c`.`date`,`c`.`comments` as `comments_count`,`w`.`workout_name` FROM `workout_count` as `c` INNER JOIN `workouts` as `w` ON `c`.`wid`=`w`.`siid` WHERE `workout_name` LIKE ? OR `c`.`comments` LIKE ? %s LIMIT 100",$sortby)); + $stmt->bind_param('ss',$_POST['filter'],$_POST['filter']); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$wid,$date,$comments,$name); + while($stmt->fetch()){ + $tosend["raw"][]=array("id"=>$id,"wid"=>$wid,"date"=>$date,"comments"=>$comments,"workout_name"=>$name); + } + $stmt->close(); + $stmt = $db->prepare("SELECT `id`,`workout_name`,`comments` FROM `workouts` WHERE 1"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$name,$comments); + while($stmt->fetch()){ + $tosend["workouts"][$id]=array("id"=>$id,"workout_name"=>$name,"comments"=>$comments); + } + $stmt->close(); + echo json_encode($tosend); + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/recent_workouts/recent_workouts_delete.php b/recent_workouts/recent_workouts_delete.php new file mode 100644 index 0000000..9e5e253 --- /dev/null +++ b/recent_workouts/recent_workouts_delete.php @@ -0,0 +1,32 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class recent_workouts_delete extends module_recent_workouts implements imodquery { + + //Query: recent_workouts_delete + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("DELETE FROM `workout_count` WHERE `id`=? LIMIT 1"); + $stmt->bind_param('i',$_POST['id']); + $content = array("DELETE","workout_count",array($_POST['id'])); + if(!($this->database_query($stmt,$content,"DELETE",$_POST['id']))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/recent_workouts/recent_workouts_edit.php b/recent_workouts/recent_workouts_edit.php new file mode 100644 index 0000000..ef88063 --- /dev/null +++ b/recent_workouts/recent_workouts_edit.php @@ -0,0 +1,32 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class recent_workouts_edit extends module_recent_workouts implements imodquery { + + //Query: recent_workouts_edit + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("UPDATE `workout_count` SET `wid`=?,`comments`=?,`date`=? WHERE `id`=? LIMIT 1;"); + $stmt->bind_param('issi',$_POST['wid'],$_POST['comments'],$_POST['date'],$_POST['id']); + $content = array("UPDATE","workout_count",array("wid","comments","date"),array($_POST['wid'],$_POST['comments'],$_POST['date'])); + if(!($this->database_query($stmt,$content,"UPDATE",$_POST['id']))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/recent_workouts/style.css b/recent_workouts/style.css new file mode 100644 index 0000000..7d891fb --- /dev/null +++ b/recent_workouts/style.css @@ -0,0 +1,87 @@ +/*Page - Recent Workouts*/ +table.recent-workouts-table { + width:100%; + font:12px/18px Arial, Sans-serif; + color:#333; + background-color:#fff; + border-spacing:0; + margin:10px 0 15px; + text-align:left; +} + +table.recent-workouts-table > thead > tr > th { + -webkit-user-select:none; + font:bold 12px/18px Arial, Sans-serif; + color:#000; + background-color:#fff; + border-collapse:collapse; + border-bottom:#ccc 2px solid; + cursor:pointer; + white-space:normal; +} + +table.recent-workouts-table > thead > tr > th.sortedby { + border-bottom:#000 2px solid; +} + +table.recent-workouts-table > thead > tr > th > i { + padding:4px; + float:right; +} + +table.recent-workouts-table > tbody > tr > td { + border-bottom:#ccc 1px solid; + padding:4px; + vertical-align:top; +} + +table.recent-workouts-table > tbody > tr.odd > td { + background-color:#dfdfdf; +} + +table.recent-workouts-table > tbody > tr.even > td { + background-color:#efefef; +} + +table.recent-workouts-table > tbody > tr:hover > td, +table.recent-workouts-table > tbody > tr.odd > td:hover, +table.recent-workouts-table > tbody > tr.even > td:hover { + background: #fff; + color: #000; +} + +select.recent-workouts-table-select,input.recent-workouts-table-input { + padding:4px; + width:100%; + background-color:inherit; + border:none; + font-size:inherit; + font:inherit; + display:block; + box-sizing:border-box; +} + +textarea.recent-workouts-table-textarea { + background-color:inherit; + border:none; + font-size:inherit; + font:inherit; + display:block; + box-sizing:border-box; + width:100%; + resize:none; +} + +div.recent-workouts-table-delete-container { + background-color:inherit; + position:absolute; + right:-1.5px; + top:-46px; +} + +div.recent-workouts-loading-div { + width:100%; + box-sizing:border-box; + padding:5%; + text-align:center; +} \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..2bd4b6b --- /dev/null +++ b/style.css @@ -0,0 +1,157 @@ +/*Page - Workout Management */ +table#daysago { + border:1px solid black; + text-align:center; + border-collapse:collapse; + margin-top:4px; +} + +div.wm-attr-manager-div { + +} + +div.wm-attr-manager-container { + width:50vw; + position:relative; +} + +div.wm-attr-manager-container > div { + display:block; + border:1px solid black; + box-sizing:border-box; + width:70%; + height:5vh; + line-height:5vh; + position:absolute; + cursor:move; +} + +div.wm-attr-manager-container > div.editable > input { + pointer-events:auto; + border:2px ridge lightgreen; +} + +div.wm-attr-manager-container > div > input { + pointer-events:none; + border:none; +} + +div.wm-attr-manager-container > div > i { + display:none; +} + +div.wm-attr-manager-container > div:hover > i,div.wm-attr-manager-container > div.editable > i { + float:right; + display:inline-block; + margin-right:5px; + cursor:pointer; +} + +table.workout-management-table { + width:100%; + font:12px/18px Arial, Sans-serif; + color:#333; + background-color:#fff; + border-spacing:0; + margin:10px 0 15px; + text-align:left; +} + +table.workout-management-table > thead > tr > th { + -webkit-user-select:none; + font:bold 12px/18px Arial, Sans-serif; + color:#000; + background-color:#fff; + border-collapse:collapse; + border-bottom:#ccc 2px solid; + cursor:pointer; + white-space:normal; +} + +table.workout-management-table > thead > tr > th.sortedby { + border-bottom:#000 2px solid; +} + +table.workout-management-table > thead > tr > th > i { + padding:4px; + float:right; +} + +table.workout-management-table > tbody > tr > td { + border-bottom:#ccc 1px solid; + padding:4px; + vertical-align:top; +} + +table.workout-management-table > tbody > tr.odd > td { + background-color:#dfdfdf; +} + +table.workout-management-table > tbody > tr.even > td { + background-color:#efefef; +} + +table.workout-management-table > tbody > tr:hover > td, +table.workout-management-table > tbody > tr.odd > td:hover, +table.workout-management-table > tbody > tr.even > td:hover { + background: #fff; + color: #000; +} + +input.workout-management-table-input,select.workout-management-table-select { + padding:4px; + width:100%; + background-color:inherit; + border:none; + font-size:inherit; + font:inherit; + display:block; + box-sizing:border-box; +} + +input.workout-management-table-input-toggles { + padding:4px; + width:30px; + background-color:inherit; + border:none; + font-size:inherit; + font:inherit; + display:block; + box-sizing:border-box; +} + +textarea.workout-management-table-comments { + background-color:inherit; + border:none; + resize:none; + width:100%; + padding:0; + margin:0; + font-size:inherit; + font:inherit; + box-sizing:border-box; +} + +td.inputok { + position:relative; +} + +tr:hover > td.inputok > div > div.workout-management-table-delete-container { + display:block; +} + +div.workout-management-table-delete-container { + display:none; + background-color:inherit; + position:absolute; + right:0; + top:0; + cursor:pointer; +} + +div.workout-management-loading-div { + width:100%; + box-sizing:border-box; + padding:5%; + text-align:center; +} \ No newline at end of file diff --git a/workout_management.php b/workout_management.php new file mode 100644 index 0000000..02aa150 --- /dev/null +++ b/workout_management.php @@ -0,0 +1,57 @@ +<div class='top-bar'><h1>Workout Management</h1></div> +<div id='content'></div> +<script type="text/javascript"> +var WorkoutManagementContent = React.createClass({//Main React Component + loadDataFromServer: function () { + serverRequest({query_type:'workout_management_data'},"json") + .then(function(data) { + console.log(data); + this.setState({hash:data.hash,recent:data.recent,attributes:data.attributes}); + }.bind(this)) + .catch(function(error) { + console.error("workout_management.php","workout_management_data",error); + }); + }, + getInitialState: function() { + return {hash:"",recent:[],attributes:[],view:""}; + }, + componentDidMount: function() { + this.loadDataFromServer(); + setInterval(this.loadDataFromServer, 2000); + }, + handleView: function (type) { + this.setState({view:type}); + }, + handleAddNew: function () { + serverRequest({query_type:'workout_management_add_new'}) + .then(function(data) { + console.log(data); + }) + .catch(function(error) { + console.error("workout_management.php","workout_management_add_new",error); + }); + }, + render: function() { + return React.createElement("div",null, + (this.state.attributes.length==0)?React.createElement("div",null,"No Workout Attributes defined. Click the 'Manage Attributes' button below."):"", + React.createElement(WorkoutManagementDaysAgoTableData,{data:this.state.recent,attributes:this.state.attributes}), + React.createElement("input",{type:"button",value:(this.state.view=="")?"Manage Attributes":"Save Attributes",onClick:this.handleView.bind(this,(this.state.view=="")?"edit":"")}), + (this.state.view=="edit")?React.createElement(WorkoutManagementAttributesManager,{data:this.state.attributes}):"", + React.createElement(WorkoutManagementWorkoutTable,{hash:this.state.hash,attributes:this.state.attributes}), + React.createElement("input",{type:"button",value:"Add new Workout",onClick:this.handleAddNew}), + React.createElement("form",{className:"link-to-page-form",method:"post"}, + React.createElement("input",{type:"hidden",name:"page",value:"recent_workouts"}), + React.createElement("input",{type:"submit",className:"link-to-page-button",value:"Recent Workouts"}) + ) + ); + } +}); +</script> +<?php +require("WorkoutManagementDaysAgoTableData/WorkoutManagementDaysAgoTableData.php"); +require("WorkoutManagementAttributesManager/WorkoutManagementAttributesManager.php"); +require("WorkoutManagementWorkoutTable/WorkoutManagementWorkoutTable.php"); +?> +<script type="text/javascript"> +var ReactTable = ReactDOM.render(React.createElement(WorkoutManagementContent,null),document.getElementById('content')); +</script> \ No newline at end of file diff --git a/workout_management_add_attribute.php b/workout_management_add_attribute.php new file mode 100644 index 0000000..6f6df60 --- /dev/null +++ b/workout_management_add_attribute.php @@ -0,0 +1,40 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_add_attribute extends module_workout_management implements imodquery { + + //Query: workout_management_add_attribute + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("SELECT IFNULL(MAX(`attribute_num`)+1,0) FROM `workouts_attributes` WHERE 1"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($max); + $stmt->fetch(); + $stmt->close(); + $stmt = $db->prepare("INSERT INTO `workouts_attributes` (attribute_num,attribute_name,attribute_label,comments) VALUES (?,'New Attribute','Attribute Label','New Attribute')"); + $stmt->bind_param('i',$max); + $content = array("INSERT","workouts_attributes",array("attribute_num","attribute_name","attribute_label","comments"),array($max,"New Attribute","Attribute Label","New Attribute")); + if(!($this->database_query($stmt,$content,"INSERT",NULL))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_add_new.php b/workout_management_add_new.php new file mode 100644 index 0000000..c915ee1 --- /dev/null +++ b/workout_management_add_new.php @@ -0,0 +1,48 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_add_new extends module_workout_management implements imodquery { + + //Query: workout_management_add_new + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("SELECT RPAD('',(SELECT COUNT(*) as `count` FROM `workouts_attributes` WHERE 1),'0') FROM `workouts_attributes` WHERE 1 LIMIT 1"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($attr); + $stmt->fetch(); + $stmt->close(); + $stmt = $db->prepare("SELECT IFNULL(MAX(`siid`)+1,0) FROM `workouts` WHERE 1"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($max); + $stmt->fetch(); + $stmt->close(); + $stmt = $db->prepare("INSERT INTO `workouts` (`siid`,`workout_name`,`workout_attributes`,`comments`) VALUES (?,'New Workout',?,'New Workout')"); + $stmt->bind_param('is',$max,$attr); + $content = array("INSERT","workouts",array("siid","workout_name","workout_attributes","comments"),array($max,"New Workout",$attr,"New Workout")); + if(!($this->database_query($stmt,$content,"INSERT",NULL))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_attribute_delete.php b/workout_management_attribute_delete.php new file mode 100644 index 0000000..f371d8d --- /dev/null +++ b/workout_management_attribute_delete.php @@ -0,0 +1,86 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_attribute_delete extends module_workout_management implements imodquery { + + //Query: workout_management_attribute_delete + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("SELECT `attribute_num` FROM `workouts_attributes` WHERE `id`=?"); + $stmt->bind_param('i',$_POST['id']); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($num); + $stmt->fetch(); + $stmt->close(); + $stmt = $db->prepare("DELETE FROM `workouts_attributes` WHERE `id`=? LIMIT 1"); + $stmt->bind_param('i',$_POST['id']); + $content = array("DELETE","workouts_attributes",$_POST['id']); + if(!($this->database_query($stmt,$content,"DELETE",$_POST['id']))){ + self::log_error("Database query failed."); + return FALSE; + } + $stmt = $db->prepare("SELECT `id`,`attribute_num` FROM `workouts_attributes` WHERE `attribute_num`>?"); + $stmt->bind_param('i',$num); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$attrnum); + $data = array(); + while($stmt->fetch()){ + $data[$id]=$attrnum-1; + } + $stmt->close(); + foreach($data as $id=>$newnum){ + $stmt = $db->prepare("UPDATE `workouts_attributes` SET `attribute_num`=? WHERE `id`=? LIMIT 1"); + $stmt->bind_param('ii',$newnum,$id); + $content = array("UPDATE","workouts_attributes",array("attribute_num"),array($newnum)); + if(!($this->database_query($stmt,$content,"UPDATE",$id))){ + self::log_error("Database query failed."); + return FALSE; + } + } + $stmt = $db->prepare("SELECT `id`,`workout_attributes` FROM `workouts` WHERE 1"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$attrs); + $toset = array(); + while($stmt->fetch()){ + $toset[$id]=str_split($attrs); + } + $stmt->close(); + foreach($toset as $k=>$attrs){ + unset($attrs[$num]); + $toset[$k]=implode("",$attrs); + } + foreach($toset as $k=>$attrs){ + $stmt = $db->prepare("UPDATE `workouts` SET `workout_attributes`=? WHERE `id`=? LIMIT 1"); + $stmt->bind_param('si',$attrs,$k); + $content = array("UPDATE","workouts",array("workout_attributes"),array($attrs)); + if(!($this->database_query($stmt,$content,"UPDATE",$k))){ + self::log_error("Database query failed."); + return FALSE; + } + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_attribute_save.php b/workout_management_attribute_save.php new file mode 100644 index 0000000..7dc41df --- /dev/null +++ b/workout_management_attribute_save.php @@ -0,0 +1,32 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_attribute_save extends module_workout_management implements imodquery { + + //Query: workout_management_attribute_save + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("UPDATE `workouts_attributes` SET `attribute_name`=?,`attribute_label`=?,`comments`=? WHERE `id`=? LIMIT 1"); + $stmt->bind_param('sssi',$_POST['name'],$_POST['label'],$_POST['comments'],$_POST['id']); + $content = array("UPDATE","workouts_attributes",array("attribute_name","attribute_label","comments"),array($_POST['name'],$_POST['label'],$_POST['comments'])); + if(!($this->database_query($stmt,$content,"UPDATE",$_POST['id']))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_attributes_reorder.php b/workout_management_attributes_reorder.php new file mode 100644 index 0000000..2c4496f --- /dev/null +++ b/workout_management_attributes_reorder.php @@ -0,0 +1,61 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_attributes_reorder extends module_workout_management implements imodquery { + + //Query: workout_management_attributes_reorder + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("SELECT `id`,`attribute_num` FROM `workouts_attributes` WHERE 1 ORDER BY `attribute_num` ASC"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$num); + $data = array(); + while($stmt->fetch()){ + $data[$num]=$id; + } + $stmt->close(); + $initial=$data; + $key=$data[$_POST['attrnum']]; + unset($data[$_POST['attrnum']]); + $data = array_values($data); + if($_POST['vd']<0){ + $diff = ceil($_POST['vd']); + $pos = (($_POST['attrnum']+$diff)<0)?0:$_POST['attrnum']+$diff; + } + else { + $diff = floor($_POST['vd']); + $pos = $_POST['attrnum']+$diff; + } + array_splice($data,$pos,0,$key); + $data = array_values($data); + foreach($initial as $key=>$value){ + if($value!=$data[$key]){ + $stmt = $db->prepare("UPDATE `workouts_attributes` SET `attribute_num`=? WHERE `id`=? LIMIT 1"); + $stmt->bind_param('ii',$key,$data[$key]); + $content = array("UPDATE","workouts_attributes",array("attribute_num"),array($key)); + if(!($this->database_query($stmt,$content,"UPDATE",$data[$key]))){ + self::log_error("Database query failed."); + return FALSE; + } + } + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_data.php b/workout_management_data.php new file mode 100644 index 0000000..d85a847 --- /dev/null +++ b/workout_management_data.php @@ -0,0 +1,82 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_data extends module_workout_management implements imodquery { + + //Query: workout_management_data + + public function execute () { + $db = $this->db; + $tosend = array("hash"=>"","recent"=>array(),"attributes"=>array()); + $stmt = $db->prepare("SELECT md5(CONCAT_WS('%%',`c`.`id`,`c`.`wid`,`c`.`date`,`c`.`comments`,`c`.`modified`)) FROM `workout_count` as `c` WHERE 1 UNION SELECT md5(CONCAT_WS('%%',`w`.`id`,`w`.`siid`,`w`.`workout_name`,`w`.`workout_attributes`,`w`.`comments`,`w`.`modified`)) FROM `workouts` as `w` WHERE 1 UNION SELECT md5(CONCAT_WS('%%',`a`.`id`,`a`.`attribute_num`,`a`.`attribute_name`,`a`.`attribute_label`,`a`.`comments`,`a`.`modified`)) FROM `workouts_attributes` as `a` WHERE 1"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($hash); + while($stmt->fetch()){ + $tosend['hash']=($tosend['hash']=="")?$hash:md5($hash.$tosend['hash']); + } + $stmt->close(); + $stmt = $db->prepare("SELECT `id`,`attribute_num`,`attribute_name`,`attribute_label`,`comments` FROM `workouts_attributes` WHERE 1 ORDER BY `attribute_num` ASC;"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$num,$name,$label,$comments); + while($stmt->fetch()){ + $tosend['attributes'][$num]=array("id"=>$id,"attribute_num"=>$num,"attribute_name"=>$name,"attribute_label"=>$label,"comments"=>$comments); + $tosend['recent'][$num]=NULL; + } + $stmt->close(); + $stmt = $db->prepare("SELECT `w`.`workout_attributes`,MAX(`c`.`date`) as `last_done` FROM `workouts` as `w` LEFT JOIN `workout_count` as `c` ON `w`.`siid`=`c`.`wid` WHERE 1 GROUP BY `w`.`siid` ORDER BY `last_done` DESC"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($attrs,$last); + while($stmt->fetch()){ + $temp = str_split($attrs); + while(count($temp)<count($tosend['attributes'])){ + $temp[]=0; + } + $i=0; + while($i<count($temp)){ + if($temp[$i]==1){ + if(isset($tosend['recent'][$i])){ + if($tosend['recent'][$i]<$last){ + $tosend['recent'][$i]=$last; + } + } + else { + $tosend['recent'][$i]=$last; + } + } + $i++; + } + unset($temp); + } + $stmt->close(); + ksort($tosend['recent']); + $i=0; + foreach($tosend['recent'] as $key=>$val){ + $now = time(); + $tosend['recent'][$key] = ($val!=NULL)?floor(($now-strtotime($val))/(60*60*24)):"N/A"; + } + $tosend["recent"]=$tosend['recent']; + echo json_encode($tosend); + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_delete.php b/workout_management_delete.php new file mode 100644 index 0000000..2f548a5 --- /dev/null +++ b/workout_management_delete.php @@ -0,0 +1,53 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_delete extends module_workout_management implements imodquery { + + //Query: workout_management_delete + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("DELETE FROM `workouts` WHERE `id`=? LIMIT 1"); + $stmt->bind_param('i',$_POST['id']); + $content = array("DELETE","workouts",array($_POST['id'])); + if(!($this->database_query($stmt,$content,"DELETE",$_POST['id']))){ + self::log_error("Database query failed."); + return FALSE; + } + $stmt = $db->prepare("SELECT `id` FROM `workout_count` WHERE `wid`=?"); + $stmt->bind_param('i',$_POST['id']); + $todelete = array(); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id); + while($stmt->fetch()){ + $todelete[]=$id; + } + $stmt->close(); + foreach($todelete as $i=>$id){ + $stmt = $db->prepare("DELETE FROM `workout_count` WHERE `id`=? LIMIT 1"); + $stmt->bind_param('i',$id); + $content = array("DELETE","workout_count",array($id)); + if(!($this->database_query($stmt,$content,"DELETE",$id))){ + self::log_error("Database query failed."); + return FALSE; + } + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_edit.php b/workout_management_edit.php new file mode 100644 index 0000000..94b976a --- /dev/null +++ b/workout_management_edit.php @@ -0,0 +1,36 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_edit extends module_workout_management implements imodquery { + + //Query: workout_management_edit + + public function execute () { + $db = $this->db; + foreach($_POST['attributes'] as $k=>$v){ + $_POST['attributes'][$k]=($v=="Yes")?"1":"0"; + } + $_POST['attributes']=implode($_POST['attributes']); + $stmt = $db->prepare("UPDATE `workouts` SET `workout_attributes`=?,`workout_name`=?,`comments`=? WHERE `id`=? LIMIT 1"); + $stmt->bind_param('sssi',$_POST['attributes'],$_POST['workout_name'],$_POST['comments'],$_POST['id']); + $content = array("UPDATE","workouts",array("workout_attributes","workout_name","comments"),array($_POST['attributes'],$_POST['workout_name'],$_POST['comments'])); + if(!($this->database_query($stmt,$content,"UPDATE",$_POST['id']))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_options_change.php b/workout_management_options_change.php new file mode 100644 index 0000000..8c37432 --- /dev/null +++ b/workout_management_options_change.php @@ -0,0 +1,44 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_options_change extends module_workout_management implements imodquery { + + //Query: workout_management_options_change + + public function execute () { + $db = $this->db; + if(($_POST['field']=="workout")&&($_POST['value']=="added")){ + if(!($this->option_delete("date","workout_management"))){ + self::log_error("Option delete failed."); + return FALSE; + } + if(!($this->option_delete("wid","workout_management"))){ + self::log_error("Option delete failed."); + return FALSE; + } + if(!($this->option_delete("comments","workout_management"))){ + self::log_error("Option delete failed."); + return FALSE; + } + } + else { + if((isset($_POST['value']))&&(isset($_POST['field']))){ + $this->option_set($_POST['field'],$_POST['value'],"workout_management"); + } + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_quick_tools_add_new_workout.php b/workout_management_quick_tools_add_new_workout.php new file mode 100644 index 0000000..ba6ed13 --- /dev/null +++ b/workout_management_quick_tools_add_new_workout.php @@ -0,0 +1,32 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_quick_tools_add_new_workout extends module_workout_management implements imodquery { + + //Query: workout_management_quick_tools_add_new_workout + + public function execute () { + $db = $this->db; + $stmt = $db->prepare("INSERT INTO `workout_count`(`wid`, `date`, `comments`) VALUES (?,?,?)"); + $stmt->bind_param('iss',$_POST['wid'],$_POST['date'],$_POST['comments']); + $content=array("INSERT","workout_count",array("wid","date","comments"),array($_POST['wid'],$_POST['date'],$_POST['comments'])); + if(!($this->database_query($stmt,$content,"INSERT",NULL))){ + self::log_error("Database query failed."); + return FALSE; + } + echo "success"; + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_quick_tools_data.php b/workout_management_quick_tools_data.php new file mode 100644 index 0000000..6ca838f --- /dev/null +++ b/workout_management_quick_tools_data.php @@ -0,0 +1,36 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_quick_tools_data extends module_workout_management implements imodquery { + + //Query: workout_management_quick_tools_data + + public function execute () { + $db = $this->db; + $tosend = array("workouts"=>array(),"options"=>array()); + $stmt = $db->prepare("SELECT `id`,`siid`,`workout_name`,`workout_attributes`,`comments` FROM `workouts` WHERE 1 ORDER BY `workout_name` ASC"); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$siid,$name,$attrs,$comments); + while($stmt->fetch()){ + $tosend["workouts"][]=array("id"=>$id,"siid"=>$siid,"workout_name"=>$name,"workout_attributes"=>$attrs,"comments"=>$comments); + } + $tosend['options']=$this->page_options_get("workout_management"); + echo json_encode($tosend); + return TRUE; + } + +} + +?> \ No newline at end of file diff --git a/workout_management_table_data.php b/workout_management_table_data.php new file mode 100644 index 0000000..ff3cff5 --- /dev/null +++ b/workout_management_table_data.php @@ -0,0 +1,56 @@ +<?php + +$source = debug_backtrace(); +if($source[0]['file']!=dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR."dbq.php"){ + exit("Unauthorized"); +} + +/** + * Echo anything necessary from execute, but make sure it returns true otherwise it will log an error +*/ + + +class workout_management_table_data extends module_workout_management implements imodquery { + + //Query: workout_management_table_data + + public function execute () { + $db = $this->db; + $tosend = array("raw"=>array(),"hash"=>""); + $sortby = ((isset($_POST['sorting']))&&(isset($_POST['order'])))?$this->build_sortby($_POST['sorting'],$_POST['order']):"";//build_sortby is from class_workout_management.php + $stmt = $db->prepare(sprintf("SELECT md5(CONCAT_WS('%%',`w`.`id`,`w`.`siid`,`w`.`workout_name`,RPAD(`w`.`workout_attributes`,(SELECT COUNT(*) FROM `workouts_attributes`),'0'),`w`.`comments`,MAX(`c`.`date`),COUNT(`c`.`wid`))) FROM `workouts` as `w` LEFT JOIN `workout_count` as `c` ON `w`.`siid`=`c`.`wid` WHERE 1 GROUP BY `w`.`siid`%s",$sortby)); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($hash); + while($stmt->fetch()){ + $tosend['hash']=($tosend['hash']=="")?$hash:md5($hash.$tosend['hash']); + } + $stmt->close(); + $stmt = $db->prepare(sprintf("SELECT `w`.`id`,`w`.`siid`,`w`.`workout_name`,RPAD(`w`.`workout_attributes`,(SELECT COUNT(*) FROM `workouts_attributes`),'0') as `workout_attributes`,`w`.`comments`,MAX(`c`.`date`) as `last_done`,COUNT(`c`.`wid`) as `times_done` FROM `workouts` as `w` LEFT JOIN `workout_count` as `c` ON `w`.`siid`=`c`.`wid` WHERE 1 GROUP BY `w`.`siid`%s",$sortby)); + if(!($stmt->execute())){ + self::log_error(mysqli_stmt_error($stmt)); + return FALSE; + } + $stmt->bind_result($id,$siid,$name,$attrs,$comments,$last,$times); + while($stmt->fetch()){ + $row = array("id"=>$id,"siid"=>$siid,"name"=>$name,"attrs"=>array(),"comments"=>$comments,"last"=>$last,"times"=>$times); + $temp = str_split($attrs); + for($i=0;$i<count($temp);$i++){ + if($temp[$i]==1){ + $row["attrs"][$i]="Yes"; + } + else { + $row["attrs"][$i]="No"; + } + } + $tosend['raw'][]=$row; + } + echo json_encode($tosend); + return TRUE; + } + +} + +?> \ No newline at end of file