diff --git a/HelpText.js b/HelpText.js
new file mode 100644
index 0000000..4af782b
--- /dev/null
+++ b/HelpText.js
@@ -0,0 +1,144 @@
+/**
+The Help Text Viewer provides the possibility to enhance your forms by adding help buttons.
+These buttons display a help message when clicked or hovered.
+
+Optionally, the buttons can be hidden by default, with a global switch (the Help Text Trigger) to show or hide them.
+*/
+dojo.provide("HelpText.widget.HelpText");
+
+mxui/widget.declare('HelpText.widget.HelpText', {
+
+ inputargs: {
+ text : '',
+ startvisible : false,
+ showonhover : true,
+ width : 300,
+ height : 300,
+ closeClick : false,
+ position : 'popup'
+ },
+
+ //IMPLEMENTATION
+ domNode: null,
+ topic : "CustomWidget/HelpText",
+ imgNode : null,
+ handle : null,
+ helpNode : null,
+ helpvisible: false,
+ windowEvt : null,
+
+ postCreate : function(){
+ logger.debug(this.id + ".postCreate");
+
+ //img node
+ this.imgNode = mxui/dom.div({
+ 'class' : 'HelpTextButton'
+ });
+ this.domNode.appendChild(this.imgNode);
+ this.connect(this.imgNode, 'onclick', dojo.hitch(this, this.toggleHelp, true));
+ if (this.showonhover) {
+ this.connect(this.imgNode, 'onmouseenter', dojo.hitch(this, this.showHelp, true, false));
+ this.connect(this.imgNode, 'onmouseleave', dojo.hitch(this, this.showHelp, false, false));
+ }
+
+ //help node
+ this.createHelp();
+
+ this.stateChange(this.startvisible);
+ this.handle = dojo.subscribe(this.topic, this, this.stateChange);
+
+ this.actLoaded();
+ },
+
+ stateChange : function(newstate) {
+ if (newstate)
+ dojo.style(this.imgNode, "display", "block")
+ else if (!this.startvisible) {
+ this.helpvisible = false;
+ dojo.style(this.imgNode, "display", "none");
+ this.showHelp(false);
+ }
+ },
+
+ createHelp : function () {
+ this.helpNode = mxui.dom.div({'class' : 'HelpTextBox'});
+ var input = this.text.replace(/\n/g, '
');
+ dojo.html.set(this.helpNode, input);
+ dojo.style(this.helpNode, {
+ 'width' : this.width + 'px',
+ 'maxHeight' : this.height + 'px'
+ });
+ this.connect(this.helpNode, 'onclick', dojo.hitch(this, this.toggleHelp, true));
+ //document.body.appendChild(this.helpNode);
+ if (this.position == 'popup')
+ dojo.body().appendChild(this.helpNode);
+ else {
+ this.domNode.appendChild(this.helpNode);
+ dojo.style(this.domNode, 'position', 'relative');
+ }
+ },
+
+ toggleHelp : function(clicked, e) {
+ this.helpvisible = !this.helpvisible;
+ this.showHelp(this.helpvisible, clicked);
+ if (e)
+ dojo.stopEvent(e);
+ },
+
+ windowClick : function () {
+ this.disconnect(this.windowEvt);
+ this.windowEvt = null;
+ this.toggleHelp(true);
+ },
+
+ showHelp : function(show, clicked) {
+ if (show || this.helpvisible) {
+ if (this.closeClick && clicked)
+ this.windowEvt = this.connect(document.body, 'onclick', this.windowClick);
+
+ if (this.position == 'popup') {
+ var coords = dojo.coords(this.imgNode, true);
+ dojo.style(this.helpNode, {
+ 'display' : 'block',
+ 'top' : (coords.y + 30)+'px',
+ 'left': (window.innerWidth < coords.x + 30 + this.width ? coords.x - this.height - 30 : coords.x + 30)+'px'
+ });
+ }
+ else {
+ dojo.style(this.helpNode, {
+ 'display' : 'block',
+ 'top' : '30px',
+ 'left': this.position == 'right' ? '30px' : (-30 - this.width) + 'px'
+ });
+ }
+ }
+ else
+ dojo.style(this.helpNode, 'display', 'none');
+ },
+
+ suspended : function() {
+ if (this.windowEvt != null) {
+ this.disconnect(this.windowEvt);
+ this.windowEvt = null;
+ }
+ this.showHelp(false);
+ },
+
+ uninitialize : function() {
+
+ try {
+ if (this.windowEvt != null) {
+ this.disconnect(this.windowEvt);
+ this.windowEvt = null;
+ logger.debug(this.id + ".uninitialize");
+ }
+ if (this.helpNode != null)
+ document.body.removeChild(this.helpNode);
+ if (this.handle != null)
+ dojo.unsubscribe(this.handle);
+ }
+ catch(e) {
+ logger.warn("error on helptextviewer unload: " + e);
+ }
+ }
+});
diff --git a/HelpTextAttr.js b/HelpTextAttr.js
new file mode 100644
index 0000000..f640aec
--- /dev/null
+++ b/HelpTextAttr.js
@@ -0,0 +1,26 @@
+dojo.provide("HelpText.widget.HelpTextAttr");
+dojo.require("HelpText.widget.HelpText")
+
+mxui/widget.declare('HelpText.widget.HelpTextAttr', {
+ superclass : HelpText.widget.HelpText,
+ addons : [],
+
+ inputargs: {
+ name : '',
+ startvisible : false,
+ showonhover : true,
+ width : 300,
+ height : 300,
+ closeClick : false,
+ position : 'popup'
+ },
+
+ text : '',
+
+ _setValueAttr : function(value) {
+ this.text = mxui/dom.escapeString(value).replace(/\n/g,"
");;
+ if (this.helpNode)
+ dojo.html.set(this.helpNode, this.text);
+ }
+
+});
diff --git a/HelpTextRow.js b/HelpTextRow.js
new file mode 100644
index 0000000..4428156
--- /dev/null
+++ b/HelpTextRow.js
@@ -0,0 +1,123 @@
+dojo.provide("HelpText.widget.HelpTextRow");
+
+mxui/widget.declare('HelpText.widget.HelpTextRow', {
+ addons : [],
+
+ inputargs: {
+ text : '',
+ startvisible : false,
+ height : 300,
+ hideonclick : false,
+ onclickmf : ''
+ },
+
+ //IMPLEMENTATION
+ domNode: null,
+ topic : "CustomWidget/HelpText",
+ handle : null,
+ rowNode : null,
+ targetHeight : 0,
+ anim : null,
+ contextobj : null,
+
+ postCreate : function(){
+ logger.debug(this.id + ".postCreate");
+
+ dojo.addClass(this.domNode, 'HelpTextRow');
+ this.createHelp();
+ this.rowNode = this.findRowNode(this.domNode);
+ dojo.style(this.domNode, 'maxHeight', this.height + 'px');
+ dojo.style(this.rowNode, 'height', 'auto'); //follow the animation
+ this.actRendered();
+ this.addOnLoad(dojo.hitch(this, this.poststartup));
+ },
+
+ update : function (obj, callback) {
+ this.contextobj = obj;
+ callback && callback();
+ },
+
+ poststartup : function() {
+ if (!this.startvisible) {
+ dojo.style(this.rowNode, 'display','none');
+ }
+
+ this.stateChange(this.startvisible);
+ this.handle = dojo.subscribe(this.topic, this, this.stateChange);
+
+ },
+
+ findRowNode : function(parent) {
+ var tag = parent.tagName.toLowerCase();
+ if (tag == 'tr' || tag == 'th')
+ return parent;
+ else if (parent.parentNode != null)
+ return this.findRowNode(parent.parentNode);
+ throw new Exception(this.id + " Did not found a parent row to show or hide");
+ },
+
+ updateHeight : function(height) {
+ if (this.anim != null)
+ this.anim.stop();
+ this.anim = dojo.animateProperty({
+ node : this.domNode,
+ duration : 500,
+ properties : { height : height },
+ onEnd : dojo.hitch(this, function() {
+ if (height == 0)
+ dojo.style(this.rowNode, 'display', 'none');
+ })
+ });
+ this.anim.play();
+ },
+
+ stateChange : function(newstate) {
+ if (newstate) {
+ var boxorig = dojo.marginBox(this.domNode);
+ dojo.style(this.rowNode, { 'display' : '' });
+ dojo.style(this.domNode, {'height' : 'auto'});
+ var box = dojo.marginBox(this.domNode);
+
+ if (boxorig.h == 0) //restart animation
+ dojo.style(this.domNode, { 'height' : '0px'});
+ if (box.h > 0)
+ this.updateHeight(Math.min(this.height, box.h));
+ else
+ dojo.style(this.domNode, 'height', 'auto');
+ }
+ else {
+ this.updateHeight(0);
+ }
+ },
+
+ createHelp : function () {
+ dojo.html.set(this.domNode, this.text);
+ if (this.hideonclick === true)
+ this.connect(this.domNode, 'onclick', this.hideHelp);
+ else if (this.onclickmf != '') {
+ this.connect(this.domNode, 'onclick', this.executeMF);
+ }
+ },
+
+ executeMF : function () {
+ mx.data.action({
+ error : function() {
+ logger.error(this.id + "error: XAS error executing microflow");
+ },
+ callback : dojo.hitch(this, function() {
+ }),
+ actionname : this.onclickmf,
+ applyto : 'selection',
+ guids : [mendix/lib/MxObject#getGuid()]
+ });
+ },
+
+ hideHelp : function() {
+ this.startvisible = false;
+ this.stateChange(false);
+ },
+
+ uninitialize : function() {
+ dojo.unsubscribe(this.handle);
+ }
+});;
diff --git a/HelpTextRowAttr.js b/HelpTextRowAttr.js
new file mode 100644
index 0000000..ed148e3
--- /dev/null
+++ b/HelpTextRowAttr.js
@@ -0,0 +1,24 @@
+dojo.provide("HelpText.widget.HelpTextRowAttr");
+dojo.require("HelpText.widget.HelpTextRow")
+
+mxui/widget.declare('HelpText.widget.HelpTextRowAttr', {
+ superclass : HelpText.widget.HelpTextRow,
+ addons : [],
+
+ inputargs: {
+ name : '',
+ startvisible : false,
+ text : '',
+ startvisible : false,
+ height : 300,
+ hideonclick : false
+ },
+
+ text : '',
+
+ _setValueAttr : function(value) {
+ this.text = mxui/dom.escapeString(value).replace(/\n/g,"
");;
+ dojo.html.set(this.domNode, this.text);
+ }
+
+});
diff --git a/HelpTextTrigger.js b/HelpTextTrigger.js
new file mode 100644
index 0000000..d40bb9f
--- /dev/null
+++ b/HelpTextTrigger.js
@@ -0,0 +1,49 @@
+/**
+
+*/
+dojo.provide("HelpText.widget.HelpTextTrigger");
+
+mxui/widget.declare('HelpText.widget.HelpTextTrigger', {
+ addons : [],
+
+ inputargs: {
+ txton : '',
+ txtoff: ''
+ },
+
+ //IMPLEMENTATION
+ domNode: null,
+ imgNode: null,
+ txtNode: null,
+ topic : "CustomWidget/HelpText",
+ state : false, //current state
+
+ postCreate : function(){
+ logger.debug(this.id + ".postCreate");
+
+ //houskeeping
+ this.imgNode = mxui/dom.div({
+ 'class' : 'HelpTextTrigger'
+ });
+ this.domNode.appendChild(this.imgNode);
+
+ this.txtNode = mxui/dom.label({'class' : 'HelpTextTriggerLabel'}, this.txton);
+ this.domNode.appendChild(this.txtNode);
+
+ this.connect(this.imgNode, 'onclick', this.toggle);
+ this.connect(this.txtNode, 'onclick', this.toggle);
+
+ this.actRendered();
+ },
+
+ toggle : function() {
+ this.state = !this.state;
+ dojo.attr(this.imgNode, 'class', this.state? 'HelpTextTriggerDown' : 'HelpTextTrigger');
+ dojo.html.set(this.txtNode, this.state == true ? this.txtoff : this.txton);
+ dojo.publish(this.topic, [ this.state ]);
+ },
+
+ uninitialize : function() {
+ logger.debug(this.id + ".uninitialize");
+ }
+});