Uber-Flexible Help System

For my doctorspost roster, which displays their year-roster, I was looking for a better way to provide documentation and/or help.(1) Separate (electronic or printed) documentation is never where you need it, and ages really fast. Change the layout of a page and you should change the screenshots in the helpfiles.
(2) same goes for help pages you can call up in a browser.So I was looking for something you could put on the page itself, independent of the available real estate.
If you could limit yourself to help based on the icons you use, you’ve tackled the quick ageing process of help-pages: used icons don’t change at the same rate as page layouts, text or menu’s.

Basically you’d like big red numbered arrow pointers pointing to the icon users need to click, telling them the order in which they need to process the screen and what to do once they clicked an icon.
But I wanted it to be generic AND users have be able to get rid of them once you don’t need the help anymore.
! And of course…the helptext should come from a database, not some static HTML page you need to edit.So I’ve come up with the following compromise:Each screen gets an easily detectable floating helpbar with two buttons, open & close. Users can drag the helpbar anywhere on the screen, so it never has to be in the way. The helpbar resides next to the empty breadcrumb and search-bar area. The helpbar has a little opacity so you can see the text underneath.BTW: I use Move Breadcrumbs to the left as is, and always have horizontal menu’s at the top. The color codes I use fit nicely with my look and feel, so change them where needed.If a user needs help, he or she clicks the Open/Help button and a helpbox appears. In the helpbox numbered help-rows appear with big fat round white on red numbers. (to help the user in a mindset, do this, then do that, etc. )Next to the step number is room for the icon they need to click (if any). The icon enlarges when they hover over it. These icons are standard fontawesome and glyphcions that PHPMaker uses. In a next post I’ll provide you with the SQL dump you can use to copy/paste into a MySQL console or runme.sql command file to create the tables in MySQL.The last position on a help-row is the actual user instruction.A helpbox can be filled for any PHP page your application has, and can have as many helprows you need. If you provide no helptext for a page, the helpbox displays ‘Sorry, no helptext for this page’. When the user is finished with the help he/she can click the close button to get back the clean & small helpbar. Refreshing the page will bring back the help-bar to it’s initial place and format. (the user can drag the bar anywhere and resize the box).I’ve field tested this with my client and feedback is positive.I’ve chunked the code you’ll need into the following posts:(1) The PHP code you’ll need to make this happen & where to put it. (My own))
(2) The javascript you’ll need to make the helpbox draggable. (w3schools)
(3) The CSS you’ll need to make the Help-box DIV’s. I’ve kept it simple and use two standard HTML buttons, so simple inline JS enough and no CSS needed. (w3schools & own tweaks)
(4) The SQL dumps to create the Help-tables. A helpbox uses two tables: a Helpcontainer, which is linked to the name of the PHP page, and the underlying Helpcontainer-rows, which are linked to the helpcontainer. The PHP code in (1) creates and populates the Help-box.
(5) The SQL dump needed to create the fa- and glyphicons used by the helpcontainer-rows.I’m quite content with the result, so enjoy & please post any improvements you see!Bob

Addendum 1/5 PHP code for the Help Containers.
Place this in ‘Server_Events/All_Pages/Page_Head’ of your project.

/*
12Feb18/rjm
Fill the Movable/Collapsible/Resizable Help-box (mydiv)
-- Fill mydivheader with Title
-- Fill mydivbody with mydivrow's (each instruction in a new mydivrow)
-- Format mydivrow: stepnr, icon, instruction

*/

$Q='"';
$space=" ";
$phppage=ew_CurrentPage();  //PHP Pagename.php
$breadcrumb=CurrentPageHeading(); //MenuDisplayname of PHP page

//generate empty Generic help box header
$helpbox = "<div id=".$Q."mydiv".$Q."style=".$Q."LEFT:70%; TOP:10%".$Q.">";
//fill help-container HEADER
		if ($breadcrumb=="") {$breadcrumb="Help Function";} //on Homepage breadcrumb is empty, so other text is needed
		$helpbox .= "<div id=".$Q."mydivheader".$Q."><strong>".$breadcrumb."</strong> <br />(Click to drag)<br /></div>";
		//fill buttons
		$helpbox .= "<div id=".$Q."mydivbut".$Q."><button type=".$Q."button".$Q." onclick=".$Q."document.getElementById('mydivbody').style.display='block'".$Q.">Help</button>
	<button type=".$Q."button".$Q." onclick=".$Q."document.getElementById('mydivbody').style.display='none'".$Q.">Close</button></div>";
		$helpbox .= "<div id=".$Q."mydivbody".$Q."style=".$Q."display:none".$Q.">";

//Read Helptext System
$HContainer = ew_ExecuteRow("SELECT * FROM std3_hsc_hulpschermcontainer WHERE hsc_php_pagina_naam = " .$Q.$phppage.$Q); //TextFields must be quoted!
if ($HContainer == "") { //no helptext for this page
		//finish help-container w STD message
		$helpbox .= "<strong>Sorry, no Help for this page</strong><br />";
		$helpbox .= "</div>"; //end mydivbody
		$helpbox .= "</div>"; //end mydiv
		echo $helpbox;

	} else { //helptext for this page
			//Read n Fill draggable helpbox
			//Get the help-instructions
	$MySQL="SELECT * FROM std3_hsr_hulpschermregel WHERE hsr_hsc_php_pagina_naam  = " .$Q.$phppage.$Q." ORDER BY hsr_pos1_regel_volgnummer";
	$Hinstr = ew_ExecuteRows($MySQL);
	$nr=sizeof($Hinstr);
		if ($Hinstr) { //instructions for container
		//fill help-container BODY w instructions
		//$helpbox .= "<strong>MyDivBody</strong><br />"; Title DivBody if needed
		//fill mydivrow's
		if ($nr > 0) {
			$i=0;
			while ($i<$nr){ //fill ONE mydivrow; array starts at 0, so '<' in stead of '<='		
				$dr="";
				$iconkey=$Hinstr [$i][6]; //ico_id
				$icon=ew_executescalar("SELECT ico_preview FROM std3_ico_systemicons WHERE ico_id =".$iconkey);
				$dr .= "<div id=".$Q."mydivrow".$Q.">";
				$dr .= "<div id=".$Q."mydivnr".$Q.">";
				$dr .= $Hinstr [$i][3]."."; //"hsr_pos1_regel_volgnummer"
				$dr .=  "</div>"; //end mydivnr
				$dr .= "<div id=".$Q."mydivico".$Q.">";
				if ($icon ==""){
					$dr .= $space; //force a filled DIV if no icon
					} else {
					$dr .= $icon;
					}
				$dr .=  "</div>"; //end mydivico
				$dr .= "<div id=".$Q."mydivelement".$Q.">";
				$dr .= $Hinstr [$i][7]; //"hsr_pos3_instructie"
				$dr .=  "</div>"; //end mydivelement
				$dr .=  "</div>"; //end mydivrow
				$helpbox .= $dr;
				$i++;
			} //end while			
		}
		$helpbox .= "</div>"; //end mydivbody
		$helpbox .= "</div>"; //end mydiv
		
		echo $helpbox;

			}  else { //no helpcontainer-rows
						//fill help-container STD message
						$helpbox .= "<strong>Sorry, no Help for this page</strong><br />";
						$helpbox .= "</div>"; //end mydivbody
						$helpbox .= "</div>"; //end mydiv
						echo $helpbox;
				
						}	
		}

Addendum 2/5 JAVASCRIPT for the Help Containers.
Place this in ‘Client_Scripts/Global/Pages_with_header footer/Startup_Script’ of your project.

// Write your global startup script here
// document.write("page loaded");


//9Feb18, RJM: Make the Help DIV element draggagle:
//source w3schools:

dragElement(document.getElementById(("mydiv")));

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id + "header")) {
	/* if present, the header is where you move the DIV from:*/
	document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  } else {
	/* otherwise, move the DIV from anywhere inside the DIV:*/
	elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
	e = e || window.event;
	// get the mouse cursor position at startup:
	pos3 = e.clientX;
	pos4 = e.clientY;
	document.onmouseup = closeDragElement;
	// call a function whenever the cursor moves:
	document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
	e = e || window.event;
	// calculate the new cursor position:
	pos1 = pos3 - e.clientX;
	pos2 = pos4 - e.clientY;
	pos3 = e.clientX;
	pos4 = e.clientY;
	// set the element's new position:
	elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
	elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
	/* stop moving when mouse button is released:*/
	document.onmouseup = null;
	document.onmousemove = null;
  }
}

Addendum 3/5 CSS for the Help Containers.
Place this in ‘HTML/Styles/User’ of your project.

/* 7Feb18 moveable helptext (copy from fiddle.css) */

#mydiv { /* the entire helptext container */
    position: absolute;
    z-index: 9;
    background-color: #f1f1f1;
    border: 1px solid #d3d3d3;
    overflow: auto;
    resize: both;
    /* opacity: 0.7;
    filter: alpha(opacity=60);*/ /* For IE8 and earlier */
    opacity: 0.85;
    filter: alpha(opacity=75); /* For IE8 and earlier */
}

#mydivheader { /* the blue helptext bar */
    padding: 10px;
    cursor: move;
    z-index: 10;
    background-color: #3C8DBC;
    color: #fff;
    text-align: center;
}

#mydivbody { /* the helptext container which contain the mydivrow's. This DIV is opened and closed by the Help and Close buttons*/
	z-index: 10;
	}


#mydivbut { /* The Help/Close buttons for if you want to do something fancy*/
	align-items: center;
	text-align: center;
}
	
	
#mydivrow { /* ONE single help/instruction row */
	z-index: 11;
	max-width: 500px;
	border-style: solid;
	border-color: transparent;
	border-left-color:#3C8DBC;
	border-top-width: thin;
	border-top-color:#3C8DBC;
	border-radius:8px; 
	display: -webkit-flex; /* Safari */ 
	-webkit-align-items: center; /* Safari 7.0+ */
	display: flex;
	align-items: center;
	}
	
#mydivnr { /* Position 1: the row number of mydivrow, a red circle with a white number */
    background-color: red;
    border: none;
    color: white;
    padding: 2px;
    text-align: center;
    text-decoration: none;
    /*display: inline-block;*/
     font-size: 150%;
    margin: 1px 1px;
    border-radius: 50%;
    z-index: 12;
    max-width: 7%;
}

	
#mydivelement { /* Position 3: the user instruction in mydivrow */
	z-index: 12;
	/* float: left; */
	text-align: left;
	/* max-width: 86%; */

}

#mydivico { /* Position 2: the icon in mydivrow (if present) */
	z-index: 12;
	max-width: 14%;
	min-width: 14%;
	padding: 2px;
    margin: 1px 1px;
}
#mydivico:hover { /* enlarge icon when mouse hover */
    -ms-transform: scale(2,2); /* IE 9 */
    -webkit-transform: scale(2,2); /* Safari */
    transform: scale(2,2); /* Standard syntax - 2 x bigger (tried 1,2 & 1,5) but 2x is really clear */
    transition-duration: 1s; /* slick enlargement */
    transition-timing-function: ease; /* ease-in-out didn't work, alas */
    
}
	
/* End movable helptext */

Addendum 4/5 SQL for the Help Container/Help Containerrow combi.SQL structure Helpcontainer:
Two entities, 1:m, first one is the help-container to match the php pagename as key; the second one are the help-rows within the help-container.My Example, First Helpcontainer Table, COPY-PASTE the following code into a MySQL console which lets you create a table. I’m not too familiar with the std MyPHPAdmin and/or MySQL workbench functions. I use Navicat which makes every database function a breeze and offers all your databases in a Windows Explorer like environment. Backup the database or a single table? Just drag and drop them/it to one of your other databases at another provider:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `std3_hsc_hulpschermcontainer`
-- ----------------------------
DROP TABLE IF EXISTS `std3_hsc_hulpschermcontainer`;
CREATE TABLE `std3_hsc_hulpschermcontainer` (
  `hsc_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `hsc_php_pagina_naam` varchar(255) NOT NULL COMMENT 'KEY corresponding php_page (w .php extension!))',
  `hsc_titel` varchar(50) DEFAULT 'Your display title',
  PRIMARY KEY (`hsc_id`,`hsc_php_pagina_naam`)
) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;

-- END COPY PASTE

Second Helprow Table, COPY-PASTE the following code into MySQL:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `std3_hsr_hulpschermregel`
-- ----------------------------
DROP TABLE IF EXISTS `std3_hsr_hulpschermregel`;
CREATE TABLE `std3_hsr_hulpschermregel` (
  `hsr_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `hsr_hsc_id` int(11) unsigned NOT NULL COMMENT 'KEY corresponding std3_hsc_hulpschermcontainer',
  `hsr_hsc_php_pagina_naam` varchar(255) NOT NULL COMMENT 'KEY corresponding php_page',
  `hsr_pos1_regel_volgnummer` int(3) unsigned NOT NULL COMMENT '(RowDisplay: Position 1). The helpcontainer will be filled according to this number (ASC)',
  `hsr_pos2_systeem_icon_id` int(11) unsigned DEFAULT NULL COMMENT '(RowDisplay: Position 2). The corresponding screen icon',
  `hsr_pos3_instructie` varchar(255) NOT NULL DEFAULT '(RowDisplay: Position 3). User Instruction, i.e. what to do after clicking icon; 255 chars max, but keep it short & sweet!',
  PRIMARY KEY (`hsr_id`)
) ENGINE=MyISAM AUTO_INCREMENT=19 DEFAULT CHARSET=latin1;
-- END COPY PASTE

In PHPMaker you want to connect hsr_pos2_systeem_icon_id via a lookup to the system icons (std3_ico_systemicons, in next message) for easy data-entering.

Addendum 5/5 SQL for the std System Icons (Font Awesome and Glyphicons).SQL structure System icons:
It uses the std fontawesome and glyph icons which are available within PHPMaker 2018. This table also leaves room to import your own .PNG or .JPG, but I have not implemented this in the code.The two triggers at the end automatically provide the correct HTML to display the icon when inserting or updating. This is the field ico_preview of the table. The   inserted is to force display of the button. If anyone knows a better way, please post.COPY-PASTE the following code into a MySQL console which lets you create tables:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `std3_ico_systemicons`
-- ----------------------------
DROP TABLE IF EXISTS `std3_ico_systemicons`;
CREATE TABLE `std3_ico_systemicons` (
  `ico_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `ico_preview` varchar(255) DEFAULT NULL,
  `ico_name` varchar(50) DEFAULT NULL,
  `ico_sdp_class` varchar(50) DEFAULT NULL COMMENT 'english.xml will provide correct class names',
  `ico_pic` blob COMMENT 'If you need your own image. Not implemented yet! Blob gives 65 kB capacity',
  PRIMARY KEY (`ico_id`)
) ENGINE=MyISAM AUTO_INCREMENT=47 DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of std3_ico_systemicons
-- ----------------------------
INSERT INTO `std3_ico_systemicons` VALUES ('1', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-advanced-search ewIcon \"></span></button>', 'Search Advanced', 'icon-advanced-search ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('2', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-filter ewIcon\"></span></button>', 'Filter', 'icon-filter ewIcon', null);
INSERT INTO `std3_ico_systemicons` VALUES ('12', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-addedit ewIcon\"></span></button>', 'Add-Edit', 'icon-addedit ewIcon', null);
INSERT INTO `std3_ico_systemicons` VALUES ('3', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-home ewIcon\"></span></button>', 'Home', 'glyphicon glyphicon-home ewIcon', null);
INSERT INTO `std3_ico_systemicons` VALUES ('4', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-trash ewIcon \"></span></button>', 'Delete', 'glyphicon glyphicon-trash ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('11', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-options ewIcon \"></span></button>', 'Opties (hamburger)', 'icon-options ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('5', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-excel ewIcon \"></span></button>', 'Export Excel', 'icon-excel ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('6', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-bell ewIcon \"></span></button>', 'Bell', 'glyphicon glyphicon-bell ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('10', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-md-add ewIcon \"></span></button>', 'Plus-inverse', 'icon-md-add ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('8', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-calendar \"></span></button>', 'Calendar', 'glyphicon glyphicon-calendar ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('9', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-plus ewIcon \"></span></button>', 'Plus', 'glyphicon glyphicon-plus ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('13', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-master-detail ewIcon \"></span></button>', 'Master-Detail', 'icon-master-detail ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('14', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-export ewIcon \"></span></button>', 'Export', 'icon-export ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('15', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-search ewIcon \"></span></button>', 'Search', 'icon-search ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('16', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-remove ewIcon \"></span></button>', 'Cancel', 'glyphicon glyphicon-remove ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('17', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-copy ewIcon \"></span></button>', 'Copy', 'icon-copy ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('18', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-md-copy ewIcon \"></span></button>', 'Copy Master-Detail', 'icon-md-copy ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('19', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-md-edit ewIcon \"></span></button>', 'Edit Master-Detail', 'icon-md-edit ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('20', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-table ewIcon \"></span></button>', 'List Detail', 'icon-table ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('21', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-md-view ewIcon \"></span></button>', 'View Master-Detail', 'icon-md-view ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('22', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-csv ewIcon \"></span></button>', 'Export CSV', 'icon-csv ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('23', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-email ewIcon \"></span></button>', 'Email', 'icon-email ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('24', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-html ewIcon \"></span></button>', 'Export HTML', 'icon-html ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('25', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-pdf ewIcon \"></span></button>', 'Export PDF', 'icon-pdf ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('26', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-word ewIcon \"></span></button>', 'Export Word', 'icon-word ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('27', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-xml ewIcon \"></span></button>', 'Export XML', 'icon-xml ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('28', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-flash ewIcon \"></span></button>', 'Password - Generate', 'glyphicon glyphicon-flash ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('29', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-grid-add ewIcon \"></span></button>', 'Grid Add', 'icon-grid-add ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('30', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-grid-edit ewIcon \"></span></button>', 'Grid Edit', 'icon-grid-edit ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('31', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-ok ewIcon \"></span></button>', 'OK', 'glyphicon glyphicon-ok ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('32', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-highlight ewIcon \"></span></button>', 'Highlight', 'icon-highlight ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('33', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-inline-add ewIcon \"></span></button>', 'Inline Add', 'icon-inline-add ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('34', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-inline-copy ewIcon \"></span></button>', 'Inline Copy', 'icon-inline-copy ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('35', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-inline-edit ewIcon \"></span></button>', 'Inline Edit', 'icon-inline-edit ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('36', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-user ewIcon \"></span></button>', 'User', 'icon-user ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('37', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-print ewIcon \"></span></button>', 'Print', 'icon-print ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('38', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-reset-search ewIcon \"></span></button>', 'Show All', 'icon-reset-search ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('39', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-view ewIcon \"></span></button>', 'View', 'icon-view ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('40', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"icon-edit ewIcon \"></span></button>', 'Edit', 'icon-edit ewIcon ', null);
INSERT INTO `std3_ico_systemicons` VALUES ('41', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-warning-sign\"></span></button>', 'Warning', 'glyphicon glyphicon-warning-sign', null);
INSERT INTO `std3_ico_systemicons` VALUES ('42', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"fa fa-exclamation-triangle\"></span></button>', 'Warning-2', 'fa fa-exclamation-triangle', null);
INSERT INTO `std3_ico_systemicons` VALUES ('43', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-info-sign\"></span></button>', 'Info', 'glyphicon glyphicon-info-sign', null);
INSERT INTO `std3_ico_systemicons` VALUES ('44', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-question-sign\"></span></button>', 'question-mark', 'glyphicon glyphicon-question-sign', null);
INSERT INTO `std3_ico_systemicons` VALUES ('45', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"fa fa-lightbulb-o\"></span></button>', 'idea', 'fa fa-lightbulb-o', null);
INSERT INTO `std3_ico_systemicons` VALUES ('46', '&nbsp;<button class=\"btn btn-default\" type=\"button\" title=\"\" ><span class=\"glyphicon glyphicon-unchecked\"></span></button>', 'Unchecked', 'glyphicon glyphicon-unchecked', null);
DELIMITER ;;
CREATE TRIGGER `PreviewConcatNew` BEFORE INSERT ON `std3_ico_systemicons` FOR EACH ROW set new.ico_preview=CONCAT('&nbsp;<button class="btn btn-default" type="button" title="" ><span class="', new.ico_sdp_class,'"></span></button>')
;;
DELIMITER ;
DELIMITER ;;
CREATE TRIGGER `PreviewConcatUpd` BEFORE UPDATE ON `std3_ico_systemicons` FOR EACH ROW set new.ico_preview=CONCAT('&nbsp;<button class="btn btn-default" type="button" title="" ><span class="', new.ico_sdp_class,'"></span></button>')
;;
DELIMITER ;

Thanks for sharing this.
What I liked:
I Like the idea of a floating controll, I think I will be copying this idea into my future help content fucntionalities.
I like where you immediately show the help content after clicking help button.What I think need to be revised.
-I think next time try to setup up an example basing on the demo project as it makes it easier for other to quickly pick it up and test right away, with sample data for help content of demo table if possible.
-I get the idea of using icons but I feel its kind of useless, coz i cat think of a reason anyone would want to choose a different icon for each help content, but i guess it looks nice but i dont see so much use for it.
-Your help content is limited to varcahr(255), yet most of the time people would want to put more instructions etc so maybe change it to text.
-You should also set a HTML editor as your editor for help content such that people can design there own HTML help content with alot more ease.
-You should probably put an option to allow a user to sa “do not show again” such that the help bar can amybe turn to a more minimal look, coz after seeing it like 2 times its always in my face since its floating infront of the page and even if ive seen the help before it still pops it up so it would be nice to have an option to dismiss it for good.-ALso I see your help content had only accounted for plain text, you should revise how it reacts coz when i try to insert help content of pure HTML like copy and paste some widget from admin LTE it does not respond so well to display the help in a readable format without me needing to resize it by pulling at its borders.
-I also feel your help content requires too many tables, I know you wanted a separate table for icons etc, but I feel its overkill, I usually use one table for all that so ist easy for other users to also be able to locate the help and modify it.
-I see you also have the same problem I faced with mine, As you dont have provission for modal dialog forms like modal add/edit/view forms. you need to maybe add consideration for those as wellConclusion:
Ive picked some your post, I’ll probably update how mine works later on.
You can look at how I was going about it and see if you can pick up any hints if any. Coz I was adding the help button on breadcrumb and using phpmaker ew_ModalDialogShow fucntion to show help in modal dialog, although from your example I feell i need to use an external library like alertify so that i can support modal dialog forms.Post is “Dynamic content sensitive Help Content or User Guide” at viewtopic.php?f=18&t=40457

Hi kirondedshem, thx for the feedback.
I had looked for helpsystems on the forum & hadn’t found yours until yesterday and totally by accident. I hadn’t thought of the Modal dialogue & like the idea.

  • the Demo database: good idea. I don’t have it operational, but it would also useful when using the PHPMkr help-file, so you can try stuff out
  • the icons: these relate to the icons the user needs to use in that particular screen. Live example & translated into English, ie the function that the service organisation can send reminder e-mails by hand to the doctors for their upcoming shifts. They do this daily for three days in advance. It has been replaced by a Cronjob that does it automatically for them. The reminder mechanism is: the system takes the shiftdate, gets all the shifts & fills a reminder-template so each doctor gets a personalized reminder with their name, the correct shiftname, location, etc:
------------------------------------------
[Select Date for e-mail reminders]
           (Click to Drag)
------------------------------------------
         [Help]   [Close]
  • [advanced search icon] Click advanced search
  • [calendar icon] Select the date in the pop-up screen. The system returns with all shifts of that day.
  • Click the right-top box of the list to select all doctors. You can also handpick doctors, i.e. to resend a reminder
  • [bell glyphicon which To finish, click the reminder bell to send the e-mails.
    I show at the bottom of the list]
  • The system returns with a notification after sending has finished

As the instructions for each page will vary, so also the number of instructions and the icon you need per instruction.

  • the amount of tables: you could do it in one table, like you prefer. I wanted to force the maker of the help instructions into a uniform format: one action = one line & in a standard format: action number, icon user needs to click, instruction. You can’t enforce that format if you use 1 table, unless you incorporate something like HTML tablerows. But that’s not too flexible. One screen will need 7 instructions, while another userfunction will only need 3.
    My mechanism lets you do that. Having a separate icon-file: lets you choose the appropriate icon for that particular instruction.
    [EDIT:] ah, I see, if you have the help text as HTML you could add or delete table rows, so you won’t have to predict the maximum amount of instructions.
    Well, the other secret reason I put the instructions in a separate table from the helpcontainer itself is that I want to implement a n:m relationship between a help-container and it’s instruction. I do a lot of modals to select a date after clicking on advanced search. So it would be nice to reuse instructions like “Click advanced search” and “Select date in pop-up”.
  • limited helpcontent/no HTML: is by design. This small little helpbox is meant to give step-by-step instructions. Click this, do that. It’s not meant for explaining stuff. For this, I wanted to use Header/Footer in server events, so you can give a short explanation at the start of a table. There you can have the HTML editor and make it into a nice intro. The fields are already there in the Helpcontainer (I deleted those in the SQL addendum), but as adding helptext in the header is table-specific, I’ve abandoned it for now. I want it to be a generic mechanism. I could mimic that by adding the code to each header/footer event of each table & view and read the helpcontainer & display any text that’s put in the database, but I was too lazy.

I plan to experiment with the example in the helpfile to open a right sidebar. This could be a place to put a more elaborate explanation of the particular function. The plus side of this mechanism over the header/footer text is again that you only need to open it when you need it. You don’t want more experienced users have to wade/scroll through text they don’t need anymore to get to the table.

  • I like the idea of being able to dismiss the helpbar, or make it into a really small blue info-circle (like the ones you see for tourist information) that you can click to fold open the helpbar.
    In my particular case: the doctors use one generic login account for read-only, so I can’t do dismissing altogether, at least not for that account. But I COULD do the small info-circle. I really like that idea.

I’m going to look at your solution in more detail and see if I can get it up and running on my testsystem. Curious to see the look and feel.

EDIT: to make the need for icons clearer:My users are real user-users. My super user once asked me to simplify the e-mail reminder menu, as she was having a couple of days off and a colleague needed to send the e-mails (this was before I replaced the function with an automatic cron-job).The email reminder menu is a drop down on the top menubar and consisted of:
[Select Date for e-mail reminders]
[Edit standard Message Templates]
[Edit cron-job (future function)]What I did was
[Select Date for e-mail reminders]
[Edit settings] [Edit standard Message Templates] and deleted the cronjob altogether.That satisfied her, but I thought if you make helptexts and say stuff like ‘Click advanced search’ MY users will probably get glazed over eyes and phone me.And of course, I think I’m making everything super-intuitive but my super-user hadn’t noticed the new bell-icon at the bottom of the email reminder page, so she didn’t know how to send them.
So that’s where I got the idea to show the icons they need to click, because they can directly find them on the page they are looking at. Plus: they don’t need to use any other icons they see on the page (like export or filter options)

I though it was designed purely for help content so i was not understanding why you did what you did BUT I see that your approach has alot of history attached to it as well as some other dependencies, Coz the ideas i was giving are mainly geared to help content, so in a way it makes sense to me now.

HelloThe system help is great.
I have some comments.The fist step,
Addendum 1/5 PHP code for the Help Containers.
Place this in ‘Server_Events/All_Pages/Page_Head’ of your project.I changed these lines

$iconkey=$Hinstr [$i][6]; //ico_id                              ->      $iconkey=$Hinstr [$i][4]; //ico_id
$dr .= $Hinstr [$i][7]; //"hsr_pos3_instructie"            ->      $dr .= $Hinstr [$i][5]; //"hsr_pos3_instructie"

And change the structure the table std3_hsr_hulpschermregel field hsr_pos3_instructie from varchar 255 to mediumtext
To be able to put html codeThank you for share

Yeah, sorry, you’re right. In the SQL table I provided I left out 2 columns (title & description; little bit of overkill) and forgot to update the column indices for this post. Thanks for the update.My next add-on for this system will be just a floating “i-dot” like a tourist info icon. Or maybe as part of the Menu.
You click that first, THEN you get the floating bar.
That probably addresses kirondedshem’s remark as well, wanting to be able to disable the bar.And I agree; change it to medium text to make it even more flexible.

The problem is that the Currentpage() does not generate any value according to me.
this is working for me:

//$phppage=CurrentPage(); //PHP Pagename.php
$phppage=($_SERVER['PHP_SELF']); //PHP Pagename.php

If your site is in a subfolder of the root URL, use this instead to strip out the subfolder name from the start:

$phppage = basename($_SERVER['PHP_SELF']); //PHP Pagename.php

I like this concept very much, however I created a very simplified version (PHP Maker 2022.2.2). So here is my simplified version (based on bobmulder5555 help solution). NOTE that this is my (working) “test” script, so any modifications/enhancements are welcome.The floating window start out as hidden, however the “help text” is “pre-loaded” when the page loads. Only when the user click on the “question mark”, will it display the floating window which in turn can be closed with the “Close” button. You can “copy & paste” the code, but remember to populate the db table with your page information (and your preferred instructions).I used the standard “Red” CSS template, and used the same for the floating help window. Please note that I still need to work through this code in order to optimize it a little.I’m using a PostreSQL database, with only a single table to store the “help text”:

CREATE TABLE IF NOT EXISTS public.helpinfo
(
    helpinfoid bigint NOT NULL DEFAULT nextval('helpinfo_helpinfouid_seq'::regclass),
    tablename character varying(255),
    icon character varying(255),
    instruction text,
    CONSTRAINT helpinfo_pkey PRIMARY KEY (helpinfouid)
)

Then in the Server Events > Global > All Pages > Page_Head section:

$Q='"';
$space="&nbsp;";
$phppage = CurrentPageName(); //PHP Pagename.php
$breadcrumb = CurrentPageHeading(); //MenuDisplayname of PHP page
if ($breadcrumb == "") {$breadcrumb = "Help Function";} //on Homepage breadcrumb is empty, so other text is needed
$helpbox = "<div id=".$Q."helpdiv".$Q."style=".$Q."LEFT:70%; TOP:10%; display:none".$Q.">";
$helpbox .= "<div id=".$Q."helpdivheader".$Q."><strong>".$breadcrumb." Help</strong><br /><div id=".$Q."noticetxt".$Q.">(Click and drag/move this window)<br /></div></div>";
$helpbox .= "<div id=".$Q."helpdivbody".$Q.">";

$HContainer = ExecuteScalar("SELECT instruction FROM helpinfo WHERE tablename = '" . $phppage . "'");

if ($HContainer == "") { //no helptext for this page -->
    $helpbox .= "<strong>There are no Help for the '".$breadcrumb."' page at this time</strong>";
} else {
    $helpbox .= $HContainer;
}
$helpbox .= "</div>"; //end helpdivbody
$helpbox .= "<div id=".$Q."helpdivfooter".$Q.">";
$helpbox .= "<button class=".$Q."btn btn-primary ew-btn".$Q." name=".$Q."helpdivbtn".$Q." id=".$Q."helpdivbtn".$Q." style=".$Q."align-items:center; text-align:center;".$Q." type=".$Q."button".$Q." onclick=".$Q."document.getElementById('helpdiv').style.display='none'".$Q.">Close</button></div></div>";
$helpbox .= "</div>";
echo $helpbox;

And in the Client Scripts > Global > Pages with Header/footer > Stratup Script section:

// the first few lines add a "question mark" in the top nav-bar
var helpI = document.createElement("i");
helpI.setAttribute("class", "fas fa-question-circle");
helpI.setAttribute("style", "font-size:20px; color:#fff; padding:1px 1px 0px 10px; opacity:0.7;");

var helpA = document.createElement("a");
helpA.setAttribute("class", "nav-link");
helpA.setAttribute("data-enable-remember", "true");
helpA.setAttribute("data-ew-action", "none");
helpA.setAttribute("onclick", "document.getElementById('helpdiv').style.display='block'");
helpA.appendChild(helpI);

var helpLI = document.createElement("li");
helpLI.className = "nav-item d-block";
helpLI.appendChild(helpA);

var nvbr = document.getElementById('ew-navbar-end');
nvbr.appendChild(helpLI);

//9Feb18, RJM: Make the Help DIV element draggagle:
//source w3schools:

dragElement(document.getElementById(("helpdiv")));

function dragElement(elmnt) {
    var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    if (document.getElementById(elmnt.id + "header")) {
        /* if present, the header is where you move the DIV from:*/
        document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
/*        } else {
        / otherwise, move the DIV from anywhere inside the DIV: ****/
//        elmnt.onmousedown = dragMouseDown;
    }

    function dragMouseDown(e) {
        e = e || window.event;
        // get the mouse cursor position at startup:
        pos3 = e.clientX;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        // call a function whenever the cursor moves:
        document.onmousemove = elementDrag;
    }

    function elementDrag(e) {
        e = e || window.event;
        // calculate the new cursor position:
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        pos3 = e.clientX;
        pos4 = e.clientY;
        // set the element's new position:
        elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    }

    function closeDragElement() {
        /* stop moving when mouse button is released: ****/
        document.onmouseup = null;
        document.onmousemove = null;
    }
}

And finally the CSS section:

#helpdiv {
	position: absolute;
	z-index: 9;
	background-color: #f1f1f1;
	border: 1px solid #d3d3d3;
	overflow: auto;
	resize: both;
	opacity: 0.8;
	filter: alpha(opacity=75);
	min-height: 185px;
	max-height: 600px;
	min-width: 220px;
}

#helpdivheader {
	padding: 10px;
	cursor: move;
	z-index: 10;
	background-color: #DC3545;
	color: #fff;
	text-align: center;
}

#noticetxt {
	font-size: x-small;
}

#helpdivbody {
	z-index: 10;
	padding: 15px 15px 8px 15px;
}

#helpdivfooter {
	z-index: 10;
	padding: 8px 15px 15px 15px;
	position: relative;
    bottom: 0px;
}

Great work. Question. How would we go about getting a list for a drop down with all the pagenames? This way you would be able to select the page and then enter the help text just like any other table

There are many ways to “skin this cat”. You could make some minor tweaks to the generated code to achieve what you want to do. All the “pagenames” are already in the “helpinfo” table. Add more fields if required, i.e. “short description” field for the table (which you can display in your dropdown list.
I intend doing something similar to what you ask for, i.e. searching for “tables” and then something like giving the user an option to search for a keyword, and then list those “tables” in which the keyword exist within the “helpinfo text” to guide them directly to the generated forms (tables). What I have done above (based on bobmulder5555 code) is to provide “context help” for the current page.Credit to bobmulder5555.Just by the way, I have created a script that will populate the “helpinfo” table automatically with all the relevant form names. You still have to create the “help text” for each (form: tablenamelist/tablenameAdd/tablenameEdit/…) though.I’m running a PostgreSQL script querying the schema for all my tables, and output that to csv (appending list/edit/… to “tablename”), which I then simply import into my “helpinfo” table. “Quick and dirty” I call it, but it works for me! Not sure how you would do it for MySQL.

Hi
Thanks. Are you able to share the script for the table names?
is anyone else getting the error
Uncaught TypeError: nvbr is null
which is line: nvbr.appendChild(helpLI);thanks

If you are using PostgreSQL, simply run:

COPY (SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name)
to 'c:\yourfile.csv' csv header;

or simply replace “c:\yourfile.csv’” with your path and filename!

@WABez

Thank you so much! This is exactly what I was about to create from scratch. You saved me a ton of work!
The original version was a little overkill, and I didn’t want the help to be constantly floating.A few notes:

  1. Code for Server Events > Global > All Pages > Page_Head must be enclosed within php tags
  2. The tablename field is misleadingly named as it will contain the page name as appears in the URL, not the table name specifically. For example, if you have a table named ‘MyCars’ then the help entry for the list page would use the name MyCarsList
  3. It’s a good idea to turn on “Check duplicate” in PHPMaker for the tablename field to avoid errors, as the ExecuteScalar SQL query assumes only one table record per page.
  4. I’m not sure why you’re using the $Q variable everywhere - in most cases using a single quote works, I only needed it for the onclick close button
    e.g instead of
$helpbox .="<div id=".$Q."helpdivfooter".$Q.">";

use

$helpbox .= "<div id='helpdivfooter'>";

The icon entry in the table wasn’t implemented, so i deleted it from my table - it seemed uneccessaryI added a timestamp field ‘LastUpdated’ so users can see when the help was updated, and I floated it to the right above the main help text contentTable structure for MySQL:

CREATE TABLE `Helpinfo` ( `Helpinfoid` bigint(20) NOT NULL, `Tablename` varchar(255) NOT NULL,  `Instruction` text NOT NULL, `LastUpdated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Code for Server Events > Global > All Pages > Page_Head (place in php tags)
NB: Since I’m using multilanguage I had to replace the text with language phrase vars

$Q='"';
$space="&nbsp;";
$phppage = CurrentPageName(); //PHP Pagename.php
$breadcrumb = CurrentPageHeading(); //MenuDisplayname of PHP page
if ($breadcrumb == "") {$breadcrumb = "Help Function";} //on Homepage breadcrumb is empty, so other text is needed
$HContainer = ExecuteScalar("SELECT Instruction FROM Helpinfo WHERE Tablename = '" . $phppage . "'", "DB");
$HTimestamp = ExecuteScalar("SELECT LastUpdated FROM Helpinfo WHERE Tablename = '" . $phppage . "'", "DB");

$helpbox = "<div id='helpdiv' style='LEFT:70%; TOP:10%; display:none'>";
$helpbox .= "<div id='helpdivheader'><strong>".$breadcrumb." ".Language()->phrase(Help_1')."</strong><br /><div id='noticetxt'>(".Language()->phrase('Help_2').")<br /></div></div>";
$helpbox .= "<div id='helpdivbody'>";

if ($HContainer == "") { //no helptext for this page -->
    $helpbox .= "<strong>".Language()->phrase('Help_3')." ".$breadcrumb."</strong>";
} else {
	$helpbox .= "<span style='float: right;' class='small muted font-italic'>".Language()->phrase('General_Updated').": ".date("d/m/Y H:i:s", strtotime($HTimestamp))."</span>";
    $helpbox .= $HContainer;
}
$helpbox .= "</div>"; //end helpdivbody
$helpbox .= "<div id='helpdivfooter'>";
$helpbox .= "<button class='btn btn-primary ew-btn' name='helpdivbtn' id='helpdivbtn' style='align-items:center; text-align:center;' type='button' onclick=".$Q."document.getElementById('helpdiv').style.display='none'".$Q.">".Language()->phrase('Help_4')."</button></div></div>";
$helpbox .= "</div>";
echo $helpbox;

I modded the CSS a little, rounded the corners of the container and added drop shadow, floated the close button to the right (seemed more logical) - looks nice :slight_smile:

#helpdiv {
	position: absolute;
	z-index: 9;
	background-color: #f1f1f1;
	border: 1px solid #d3d3d3;
	overflow: auto;
	resize: both;
	opacity: 0.8;
	filter: alpha(opacity=75);
	min-height: 185px;
	max-height: 600px;
	min-width: 220px;
	border-radius:4px;
	box-shadow: 5px 5px 5px lightgray;
}

#helpdivheader {
	padding: 10px;
	cursor: move;
	z-index: 10;
	background-color: #9DCEE3;
	color: #000;
	text-align: center;
}

#noticetxt {
	font-size: x-small;
}

#helpdivbody {
	z-index: 10;
	padding: 15px 15px 8px 15px;
}

#helpdivfooter {
	z-index: 10;
	padding: 8px 15px 15px 15px;
	position: relative;
    bottom: 0px;
    float: right;
}