Add a numpad JS

Hi, I can't understand how Nodered handles JS. I'm having a lot of trouble to implement jQuery.numpad.

I really appreciate any help.

You will probably need to add a bunch more context here, what exactly are you trying to do with that library?

Start by looking at these threads on the forum.

In short, you need to host/serve the numbpad js and css files (either by HTTP-IN ~ HTTP-Response nodes OR by setting up httpstatic in your settings.js) then use a ui-template node to import them and use them.

Hi @hardillb, I'm building a SCADA (svg-ui), which receives the speed command from the operator. The input must be pop-up when operator clicks, besides I want it to only be numeric and limit the values. Also, I want to make it looks like the IHM. The jQuery.Numpad seems simple.

Hi @Steve-Mcl, I've read some posts before, and here is my flow:

image

[
    {
        "id": "c876e57260edd2ab",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "f9f9fd3a769e295e",
        "type": "group",
        "z": "c876e57260edd2ab",
        "name": "Teclado",
        "style": {
            "stroke": "#ffC000",
            "fill": "#0070c0",
            "fill-opacity": "0.1",
            "label": true,
            "color": "#000000"
        },
        "nodes": [
            "52cb6335f36092d1",
            "0a76e17f1ec15a14",
            "c89f604af47bb744",
            "1175b398cc60adf0",
            "5bb2c9ec36a028cd",
            "1d5fd7e15823712d",
            "71542b89828892c4"
        ],
        "x": 114,
        "y": 179,
        "w": 552,
        "h": 202
    },
    {
        "id": "52cb6335f36092d1",
        "type": "link in",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "name": "Mouse over",
        "links": [
            "17921c1e445078a0"
        ],
        "x": 155,
        "y": 220,
        "wires": [
            [
                "0a76e17f1ec15a14"
            ]
        ]
    },
    {
        "id": "0a76e17f1ec15a14",
        "type": "function",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "name": "Keypad pop-up",
        "func": "\nif (msg.topic != \"transparency\"){\n    return msg;\n}\n\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 300,
        "y": 220,
        "wires": [
            [
                "c89f604af47bb744",
                "1175b398cc60adf0",
                "1d5fd7e15823712d"
            ]
        ]
    },
    {
        "id": "c89f604af47bb744",
        "type": "debug",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "name": "debug 5",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 520,
        "y": 220,
        "wires": []
    },
    {
        "id": "1175b398cc60adf0",
        "type": "template",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "name": "CSS",
        "field": "payload.style",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": ".nmpd-wrapper {display: none;}\n.nmpd-target {cursor: pointer;}\n.nmpd-grid {position:absolute; left:50px; top:50px; z-index:5000; -khtml-user-select: none; padding:10px; width: initial;}\n.nmpd-overlay {z-index:4999;}\ninput.nmpd-display {text-align: right;}",
        "output": "str",
        "x": 270,
        "y": 280,
        "wires": [
            [
                "5bb2c9ec36a028cd"
            ]
        ]
    },
    {
        "id": "5bb2c9ec36a028cd",
        "type": "template",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "name": "",
        "field": "payload.script",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "/**\n * jQuery.NumPad\n *\n * Copyright (c) 2015 Andrej Kabachnik\n *\n * Licensed under the MIT license:\n * http://www.opensource.org/licenses/mit-license.php\n *\n * Project home:\n * https://github.com/kabachello/jQuery.NumPad\n *\n * Version: 1.4\n *\n */\n(function($){\n\n\t// From https://stackoverflow.com/questions/4963053/focus-to-input-without-scrolling\n\tvar cursorFocus = function(elem) {\n\t\tvar x = window.scrollX, y = window.scrollY;\n\t\telem.focus();\n\t\twindow.scrollTo(x, y);\n\t}\n\t\n    $.fn.numpad=function(options){\n    \t\n    \tif (typeof options == 'string'){\n    \t\tvar nmpd = $.data(this[0], 'numpad');\n    \t\tif (!nmpd) throw \"Cannot perform '\" + options + \"' on a numpad prior to initialization!\";\n    \t\tswitch (options){\n    \t\t\tcase 'open': \n    \t\t\t\tnmpd.open(nmpd.options.target ? nmpd.options.target : this.first());\n    \t\t\t\tbreak;\n    \t\t\tcase 'close':\n    \t\t\t\tnmpd.open(nmpd.options.target ? nmpd.options.target : this.first());\n    \t\t\t\tbreak;\n    \t\t}\n    \t\treturn this;\n    \t} \n    \t\n\t\t// Apply the specified options overriding the defaults\n\t\toptions = $.extend({}, $.fn.numpad.defaults, options);\n\t\t\n\t\t// Create a numpad. One for all elements in this jQuery selector.\n\t\t// Since numpad() can be called on multiple elements on one page, each call will create a unique numpad id.\n\t\tvar id = 'nmpd' + ($('.nmpd-wrapper').length + 1);\n\t\tvar nmpd = {};\n\t\treturn this.each(function(){\n\t\t\t\n\t\t\t// If an element with the generated unique numpad id exists, the numpad had been instantiated already.\n\t\t\t// Otherwise create a new one!\n\t\t\tif ($('#'+id).length == 0) {\n\t\t\t\t/** @var nmpd jQuery object containing the entire numpad */\n\t\t\t\tnmpd = $('<div id=\"' + id + '\"></div>').addClass('nmpd-wrapper');\n\t\t\t\tnmpd.options = options;\n\t\t\t\t/** @var display jQuery object representing the display of the numpad (typically an input field) */\n\t\t\t\tvar display = $(options.displayTpl).addClass('nmpd-display');\n\t\t\t\tnmpd.display = display;\n\t\t\t\t/** @var grid jQuery object containing the grid for the numpad: the display, the buttons, etc. */\n\t\t\t\tvar table = $(options.gridTpl).addClass('nmpd-grid');\n\t\t\t\tnmpd.grid = table;\n\t\t\t\ttable.append($(options.rowTpl).append($(options.displayCellTpl).append(display).append($('<input type=\"hidden\" class=\"dirty\" value=\"0\"></input>'))));\n\t\t\t\t// Create rows and columns of the the grid with appropriate buttons\n\t\t\t\ttable.append(\n\t\t\t\t\t$(options.rowTpl)\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(7).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(8).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(9).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textDelete).addClass('del').click(function(){\n\t\t\t\t\t\t\tnmpd.setValue(nmpd.getValue().toString().substring(0,nmpd.getValue().toString().length - 1));\n\t\t\t\t\t\t})))\n\t\t\t\t\t).append(\n\t\t\t\t\t$(options.rowTpl)\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(4).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(5).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(6).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textClear).addClass('clear').click(function(){\n\t\t\t\t\t\t\tnmpd.setValue('');\n\t\t\t\t\t\t})))\n\t\t\t\t\t).append(\n\t\t\t\t\t$(options.rowTpl)\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(1).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(2).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(3).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textCancel).addClass('cancel').click(function(){\n\t\t\t\t\t\t\tnmpd.close(false);\n\t\t\t\t\t\t})))\n\t\t\t\t\t).append(\n\t\t\t\t\t$(options.rowTpl)\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonFunctionTpl).html('&plusmn;').addClass('neg').click(function(){\n\t\t\t\t\t\t\tnmpd.setValue(nmpd.getValue() * (-1));\n\t\t\t\t\t\t})))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonNumberTpl).html(0).addClass('numero')))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.decimalSeparator).addClass('sep').click(function(){\n\t\t\t\t\t\t\tnmpd.setValue(nmpd.getValue().toString() + options.decimalSeparator);\n\t\t\t\t\t\t})))\n\t\t\t\t\t\t.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textDone).addClass('done')))\n\t\t\t\t\t);\n\t\t\t\t// Create the backdrop of the numpad - an overlay for the main page\n\t\t\t\tnmpd.append($(options.backgroundTpl).addClass('nmpd-overlay').click(function(){nmpd.close(false);}));\n\t\t\t\t// Append the grid table to the nmpd element\n\t\t\t\tnmpd.append(table);\n\t\t\t\t\n\t\t\t\t// Hide buttons to be hidden\n\t\t\t\tif (options.hidePlusMinusButton){\n\t\t\t\t\tnmpd.find('.neg').hide();\n\t\t\t\t}\n\t\t\t\tif (options.hideDecimalButton){\n\t\t\t\t\tnmpd.find('.sep').hide();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Attach events\n\t\t\t\tif (options.onKeypadCreate){\n\t\t\t\t\tnmpd.on('numpad.create', options.onKeypadCreate);\n\t\t\t\t}\n\t\t\t\tif (options.onKeypadOpen){\n\t\t\t\t\tnmpd.on('numpad.open', options.onKeypadOpen);\n\t\t\t\t}\n\t\t\t\tif (options.onKeypadClose){\n\t\t\t\t\tnmpd.on('numpad.close', options.onKeypadClose);\n\t\t\t\t}\n\t\t\t\tif (options.onChange){\n\t\t\t\t\tnmpd.on('numpad.change', options.onChange);\n\t\t\t\t}\n\t\t\t\t(options.appendKeypadTo ? options.appendKeypadTo : $(document.body)).append(nmpd);   \n\t\t\t\t\n\t\t\t\t// Special event for the numeric buttons\n\t\t\t\t$('#'+id+' .numero').bind('click', function(){\n\t\t\t\t\tvar val;\n\t\t\t\t\tif ($('#'+id+' .dirty').val() == '0'){\n\t\t\t\t\t\tval = $(this).text();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = nmpd.getValue() ? nmpd.getValue().toString() + $(this).text() : $(this).text();\n\t\t\t\t\t}\n\t\t\t\t\tnmpd.setValue(val);\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\t// Finally, once the numpad is completely instantiated, trigger numpad.create\n\t\t\t\tnmpd.trigger('numpad.create');\n\t\t\t} else {\n\t\t\t\t// If the numpad was already instantiated previously, just load it into the nmpd variable\n\t\t\t\t//nmpd = $('#'+id);\n\t\t\t\t//nmpd.display = $('#'+id+' input.nmpd-display');\t\n\t\t\t}\n\t\t\t\n\t\t\t$.data(this, 'numpad', nmpd);\n\t\t\t\n\t\t\t// Make the target element readonly and save the numpad id in the data-numpad property. Also add the special nmpd-target CSS class.\n\t\t\t$(this).attr(\"readonly\", true).attr('data-numpad', id).addClass('nmpd-target');\n\t\t\t\n\t\t\t// Register a listener to open the numpad on the event specified in the options\n\t\t\t$(this).bind(options.openOnEvent,function(){\n\t\t\t\tnmpd.open(options.target ? options.target : $(this));\n\t\t\t});\n\t\t\t\n\t\t\t// Define helper functions\n\t\t\t\n\t\t\t/**\n\t\t\t* Gets the current value displayed in the numpad\n\t\t\t* @return string | number\n\t\t\t*/\n\t\t\tnmpd.getValue = function(){\n\t\t\t\treturn isNaN(nmpd.display.val()) ? 0 : nmpd.display.val();\n\t\t\t};\n\t\t\t\n\t\t\t/**\n\t\t\t* Sets the display value of the numpad\n\t\t\t* @param string value\n\t\t\t* @return jQuery object nmpd\n\t\t\t*/\n\t\t\tnmpd.setValue = function(value){\n\t\t\t\tif (nmpd.display.attr('maxLength') < value.toString().length) value = value.toString().substr(0, nmpd.display.attr('maxLength'));\n\t\t\t\tnmpd.display.val(value);\n\t\t\t\tnmpd.find('.dirty').val('1');\n\t\t\t\tnmpd.trigger('numpad.change', [value]);\n\t\t\t\treturn nmpd;\n\t\t\t};\n\t\t\t\n\t\t\t/**\n\t\t\t* Closes the numpad writing it's value to the given target element\n\t\t\t* @param jQuery object target\n\t\t\t* @return jQuery object nmpd\n\t\t\t*/\n\t\t\tnmpd.close = function(target){\n\t\t\t\t// If a target element is given, set it's value to the dipslay value of the numpad. Otherwise just hide the numpad\n\t\t\t\tif (target){\n\t\t\t\t\tif (target.prop(\"tagName\") == 'INPUT'){\n\t\t\t\t\t\ttarget.val(nmpd.getValue().toString().replace('.', options.decimalSeparator));\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttarget.html(nmpd.getValue().toString().replace('.', options.decimalSeparator));\n\t\t\t\t\t}\n\t\t\t\t}\t\n\t\t\t\t// Hide the numpad and trigger numpad.close\n\t\t\t\tnmpd.hide();\n\t\t\t\tnmpd.trigger('numpad.close');\n\t\t\t\t// Trigger a change event on the target element if the value has really been changed\n\t\t\t\t// TODO check if the value has really been changed!\n\t\t\t\tif (target && target.prop(\"tagName\") == 'INPUT'){\n\t\t\t\t\ttarget.trigger('change');\n\t\t\t\t}\n\t\t\t\treturn nmpd;\n\t\t\t};\n\t\t\t\n\t\t\t/**\n\t\t\t* Opens the numpad for a given target element optionally filling it with a given value\n\t\t\t* @param jQuery object target\n\t\t\t* @param string initialValue\n\t\t\t* @return jQuery object nmpd\n\t\t\t*/\n\t\t\tnmpd.open = function(target, initialValue){\n\t\t\t\t// Set the initial value\n\t\t\t\t// Use nmpd.display.val to avoid triggering numpad.change for the initial value\n\t\t\t\tif (initialValue){\n\t\t\t\t\tnmpd.display.val(initialValue);\n\t\t\t\t} else {\n\t\t\t\t\tif (target.prop(\"tagName\") == 'INPUT'){\n\t\t\t\t\t\tnmpd.display.val(target.val());\n\t\t\t\t\t\tnmpd.display.attr('maxLength', target.attr('maxLength'));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnmpd.display.val(isNaN(parseFloat(target.text())) ? '' : parseFloat(target.text()));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Mark the numpad as not dirty initially\n\t\t\t\t$('#'+id+' .dirty').val(0);\n\t\t\t\t// Show the numpad and position it on the page\n\t\t\t\tcursorFocus(nmpd.show().find('.cancel'));\n\t\t\t\tposition(nmpd.find('.nmpd-grid'), options.position, options.positionX, options.positionY);\n\t\t\t\t// Register a click handler on the done button to update the target element\n\t\t\t\t// Make sure all other click handlers get removed. Otherwise some unwanted sideeffects may occur if the numpad is\n\t\t\t\t// opened multiple times for some reason\n\t\t\t\t$('#'+id+' .done').off('click');\n\t\t\t\t$('#'+id+' .done').one('click', function(){ nmpd.close(target); });\n\t\t\t\t// Finally trigger numpad.open\n\t\t\t\tnmpd.trigger('numpad.open');\n\t\t\t\treturn nmpd;\n\t\t\t};\t\t  \n\t\t});\n    };\n    \n\t/**\n\t* Positions any given jQuery element within the page\n\t*/\n    function position(element, mode, posX, posY) {\n    \tvar x = 0;\n    \tvar y = 0;\n    \tif (mode == 'fixed'){\n\t        element.css('position','fixed');\n\t        \n\t        if (posX == 'left'){\n\t        \tx = 0;\n\t        } else if (posX == 'right'){\n\t        \tx = $(window).width() - element.outerWidth();\n\t        } else if (posX == 'center'){\n\t        \tx = ($(window).width() / 2) - (element.outerWidth() / 2);\n\t        } else if ($.type(posX) == 'number'){\n\t        \tx = posX;\n\t        }\n\t        element.css('left', x);\n\t        \t        \n\t        if (posY == 'top'){\n\t        \ty = 0;\n\t        } else if (posY == 'bottom'){\n\t        \ty = $(window).height() - element.outerHeight();\n\t        } else if (posY == 'middle'){\n\t        \ty = ($(window).height() / 2) - (element.outerHeight() / 2);\n\t        } else if ($.type(posY) == 'number'){\n\t        \ty = posY;\n\t        }\n\t        element.css('top', y);\n    \t}\n        return element;\n    }\n\t\n\t// Default values for numpad options\n\t$.fn.numpad.defaults = {\n\t\ttarget: false,\n\t\topenOnEvent: 'click',\n\t\tbackgroundTpl: '<div></div>',\n\t\tgridTpl: '<table></table>',\n\t\tdisplayTpl: '<input type=\"text\" />',\n\t\tdisplayCellTpl: '<td colspan=\"4\"></td>',\n\t\trowTpl: '<tr></tr>',\n\t\tcellTpl: '<td></td>',\n\t\tbuttonNumberTpl: '<button></button>',\n\t\tbuttonFunctionTpl: '<button></button>',\n\t\tgridTableClass: '',\n\t\thidePlusMinusButton: false,\n\t\thideDecimalButton: false,\n\t\ttextDone: 'Done',\n\t\ttextDelete: 'Del',\n\t\ttextClear: 'Clear',\n\t\ttextCancel: 'Cancel',\n\t\tdecimalSeparator: ',',\n\t\tprecision: null,\n\t\tappendKeypadTo: false,\n\t\tposition: 'fixed',\n\t\tpositionX: 'center',\n\t\tpositionY: 'middle',\n\t\tonKeypadCreate: false,\n\t\tonKeypadOpen: false,\n\t\tonKeypadClose: false,\n\t\tonChange: false\n\t};\n})(jQuery);",
        "output": "str",
        "x": 420,
        "y": 280,
        "wires": [
            []
        ]
    },
    {
        "id": "1d5fd7e15823712d",
        "type": "ui_template",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "group": "7c8b36e531dc074b",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "<script type=\"text/javascript\">\n/**\n* jQuery.NumPad\n*\n* Copyright (c) 2015 Andrej Kabachnik\n*\n* Licensed under the MIT license:\n* http://www.opensource.org/licenses/mit-license.php\n*\n* Project home:\n* https://github.com/kabachello/jQuery.NumPad\n*\n* Version: 1.4\n*\n*/\n(function($){\n\n// From https://stackoverflow.com/questions/4963053/focus-to-input-without-scrolling\nvar cursorFocus = function(elem) {\nvar x = window.scrollX, y = window.scrollY;\nelem.focus();\nwindow.scrollTo(x, y);\n}\n\n$.fn.numpad=function(options){\n\nif (typeof options == 'string'){\nvar nmpd = $.data(this[0], 'numpad');\nif (!nmpd) throw \"Cannot perform '\" + options + \"' on a numpad prior to initialization!\";\nswitch (options){\ncase 'open':\nnmpd.open(nmpd.options.target ? nmpd.options.target : this.first());\nbreak;\ncase 'close':\nnmpd.open(nmpd.options.target ? nmpd.options.target : this.first());\nbreak;\n}\nreturn this;\n}\n\n// Apply the specified options overriding the defaults\noptions = $.extend({}, $.fn.numpad.defaults, options);\n\n// Create a numpad. One for all elements in this jQuery selector.\n// Since numpad() can be called on multiple elements on one page, each call will create a unique numpad id.\nvar id = 'nmpd' + ($('.nmpd-wrapper').length + 1);\nvar nmpd = {};\nreturn this.each(function(){\n\n// If an element with the generated unique numpad id exists, the numpad had been instantiated already.\n// Otherwise create a new one!\nif ($('#'+id).length == 0) {\n/** @var nmpd jQuery object containing the entire numpad */\nnmpd = $('<div id=\"' + id + '\"></div>').addClass('nmpd-wrapper');\nnmpd.options = options;\n/** @var display jQuery object representing the display of the numpad (typically an input field) */\nvar display = $(options.displayTpl).addClass('nmpd-display');\nnmpd.display = display;\n/** @var grid jQuery object containing the grid for the numpad: the display, the buttons, etc. */\nvar table = $(options.gridTpl).addClass('nmpd-grid');\nnmpd.grid = table;\ntable.append($(options.rowTpl).append($(options.displayCellTpl).append(display).append($('<input type=\"hidden\" class=\"dirty\" value=\"0\"></input>'))));\n// Create rows and columns of the the grid with appropriate buttons\ntable.append(\n$(options.rowTpl)\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(7).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(8).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(9).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textDelete).addClass('del').click(function(){\nnmpd.setValue(nmpd.getValue().toString().substring(0,nmpd.getValue().toString().length - 1));\n})))\n).append(\n$(options.rowTpl)\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(4).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(5).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(6).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textClear).addClass('clear').click(function(){\nnmpd.setValue('');\n})))\n).append(\n$(options.rowTpl)\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(1).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(2).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(3).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textCancel).addClass('cancel').click(function(){\nnmpd.close(false);\n})))\n).append(\n$(options.rowTpl)\n.append($(options.cellTpl).append($(options.buttonFunctionTpl).html('&plusmn;').addClass('neg').click(function(){\nnmpd.setValue(nmpd.getValue() * (-1));\n})))\n.append($(options.cellTpl).append($(options.buttonNumberTpl).html(0).addClass('numero')))\n.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.decimalSeparator).addClass('sep').click(function(){\nnmpd.setValue(nmpd.getValue().toString() + options.decimalSeparator);\n})))\n.append($(options.cellTpl).append($(options.buttonFunctionTpl).html(options.textDone).addClass('done')))\n);\n// Create the backdrop of the numpad - an overlay for the main page\nnmpd.append($(options.backgroundTpl).addClass('nmpd-overlay').click(function(){nmpd.close(false);}));\n// Append the grid table to the nmpd element\nnmpd.append(table);\n\n// Hide buttons to be hidden\nif (options.hidePlusMinusButton){\nnmpd.find('.neg').hide();\n}\nif (options.hideDecimalButton){\nnmpd.find('.sep').hide();\n}\n\n// Attach events\nif (options.onKeypadCreate){\nnmpd.on('numpad.create', options.onKeypadCreate);\n}\nif (options.onKeypadOpen){\nnmpd.on('numpad.open', options.onKeypadOpen);\n}\nif (options.onKeypadClose){\nnmpd.on('numpad.close', options.onKeypadClose);\n}\nif (options.onChange){\nnmpd.on('numpad.change', options.onChange);\n}\n(options.appendKeypadTo ? options.appendKeypadTo : $(document.body)).append(nmpd);\n\n// Special event for the numeric buttons\n$('#'+id+' .numero').bind('click', function(){\nvar val;\nif ($('#'+id+' .dirty').val() == '0'){\nval = $(this).text();\n} else {\nval = nmpd.getValue() ? nmpd.getValue().toString() + $(this).text() : $(this).text();\n}\nnmpd.setValue(val);\n});\n\n// Finally, once the numpad is completely instantiated, trigger numpad.create\nnmpd.trigger('numpad.create');\n} else {\n// If the numpad was already instantiated previously, just load it into the nmpd variable\n//nmpd = $('#'+id);\n//nmpd.display = $('#'+id+' input.nmpd-display');\n}\n\n$.data(this, 'numpad', nmpd);\n\n// Make the target element readonly and save the numpad id in the data-numpad property. Also add the special nmpd-target\nCSS class.\n$(this).attr(\"readonly\", true).attr('data-numpad', id).addClass('nmpd-target');\n\n// Register a listener to open the numpad on the event specified in the options\n$(this).bind(options.openOnEvent,function(){\nnmpd.open(options.target ? options.target : $(this));\n});\n\n// Define helper functions\n\n/**\n* Gets the current value displayed in the numpad\n* @return string | number\n*/\nnmpd.getValue = function(){\nreturn isNaN(nmpd.display.val()) ? 0 : nmpd.display.val();\n};\n\n/**\n* Sets the display value of the numpad\n* @param string value\n* @return jQuery object nmpd\n*/\nnmpd.setValue = function(value){\nif (nmpd.display.attr('maxLength') < value.toString().length) value=value.toString().substr(0,\n    nmpd.display.attr('maxLength')); nmpd.display.val(value); nmpd.find('.dirty').val('1');\n    nmpd.trigger('numpad.change', [value]); return nmpd; }; /** * Closes the numpad writing it's value to the given\n    target element * @param jQuery object target * @return jQuery object nmpd */ nmpd.close=function(target){ // If a\n    target element is given, set it's value to the dipslay value of the numpad. Otherwise just hide the numpad if\n    (target){ if (target.prop(\"tagName\")=='INPUT' ){ target.val(nmpd.getValue().toString().replace('.',\n    options.decimalSeparator)); } else { target.html(nmpd.getValue().toString().replace('.', options.decimalSeparator));\n    } } // Hide the numpad and trigger numpad.close nmpd.hide(); nmpd.trigger('numpad.close'); // Trigger a change event\n    on the target element if the value has really been changed // TODO check if the value has really been changed! if\n    (target && target.prop(\"tagName\")=='INPUT' ){ target.trigger('change'); } return nmpd; }; /** * Opens the numpad for\n    a given target element optionally filling it with a given value * @param jQuery object target * @param string\n    initialValue * @return jQuery object nmpd */ nmpd.open=function(target, initialValue){ // Set the initial value //\n    Use nmpd.display.val to avoid triggering numpad.change for the initial value if (initialValue){\n    nmpd.display.val(initialValue); } else { if (target.prop(\"tagName\")=='INPUT' ){ nmpd.display.val(target.val());\n    nmpd.display.attr('maxLength', target.attr('maxLength')); } else { nmpd.display.val(isNaN(parseFloat(target.text()))\n    ? '' : parseFloat(target.text())); } } // Mark the numpad as not dirty initially $('#'+id+' .dirty').val(0); // Show\n    the numpad and position it on the page cursorFocus(nmpd.show().find('.cancel')); position(nmpd.find('.nmpd-grid'),\n    options.position, options.positionX, options.positionY); // Register a click handler on the done button to update\n    the target element // Make sure all other click handlers get removed. Otherwise some unwanted sideeffects may occur\n    if the numpad is // opened multiple times for some reason $('#'+id+' .done').off('click'); $('#'+id+'\n    .done').one('click', function(){ nmpd.close(target); }); // Finally trigger numpad.open nmpd.trigger('numpad.open');\n    return nmpd; }; }); }; /** * Positions any given jQuery element within the page */ function position(element, mode,\n    posX, posY) { var x=0; var y=0; if (mode=='fixed' ){ element.css('position','fixed'); if (posX=='left' ){ x=0; }\n    else if (posX=='right' ){ x=$(window).width() - element.outerWidth(); } else if (posX=='center' ){\n    x=($(window).width() / 2) - (element.outerWidth() / 2); } else if ($.type(posX)=='number' ){ x=posX; }\n    element.css('left', x); if (posY=='top' ){ y=0; } else if (posY=='bottom' ){ y=$(window).height() -\n    element.outerHeight(); } else if (posY=='middle' ){ y=($(window).height() / 2) - (element.outerHeight() / 2); } else\n    if ($.type(posY)=='number' ){ y=posY; } element.css('top', y); } return element; } // Default values for numpad\n    options $.fn.numpad.defaults={ target: false, openOnEvent: 'click' , backgroundTpl: '<div></div>' ,\n    gridTpl: '<table></table>' , displayTpl: '<input type=\"text\" />' , displayCellTpl: '<td colspan=\"4\"></td>' ,\n    rowTpl: '<tr></tr>' , cellTpl: '<td></td>' , buttonNumberTpl: '<button></button>' ,\n    buttonFunctionTpl: '<button></button>' , gridTableClass: '' , hidePlusMinusButton: false, hideDecimalButton: false,\n    textDone: 'Done' , textDelete: 'Del' , textClear: 'Clear' , textCancel: 'Cancel' , decimalSeparator: ',' ,\n    precision: null, appendKeypadTo: false, position: 'fixed' , positionX: 'center' , positionY: 'middle' ,\n    onKeypadCreate: false, onKeypadOpen: false, onKeypadClose: false, onChange: false }; })(jQuery);\n    </script>\n\n<link rel=\"stylesheet\">\n<style type=\"text/css\">\n        .nmpd-wrapper {\n            display: none;\n        }\n    \n        .nmpd-target {\n            cursor: pointer;\n        }\n    \n        .nmpd-grid {\n            position: absolute;\n            left: 50px;\n            top: 50px;\n            z-index: 5000;\n            -khtml-user-select: none;\n            padding: 10px;\n            width:\n                initial;\n        }\n    \n        .nmpd-overlay {\n            z-index: 4999;\n        }\n    \n        input.nmpd-display {\n            text-align: right;\n        }\n</link>\n\n<script>\n    function($){\n    $('selector1').numpad();\n    }\n</script>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 420,
        "y": 340,
        "wires": [
            [
                "71542b89828892c4"
            ]
        ]
    },
    {
        "id": "71542b89828892c4",
        "type": "http response",
        "z": "c876e57260edd2ab",
        "g": "f9f9fd3a769e295e",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 590,
        "y": 280,
        "wires": []
    },
    {
        "id": "7c8b36e531dc074b",
        "type": "ui_group",
        "name": "Nkongsamba",
        "tab": "5d63e302a6819fed",
        "order": 1,
        "disp": false,
        "width": "22",
        "collapse": false,
        "className": ""
    },
    {
        "id": "5d63e302a6819fed",
        "type": "ui_tab",
        "name": "SCADA",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

I'm probably missing something obviously here. I will read more. Thanks!

Immediate issue: You are mixing dashboard and DIY (http endpoint) logic.

image

Are you using Dashboard OR building own HTML Web pages using endpoints?

After a lot of try and error, I notice that I'm not understanding what I'm doing. I need some guidance to understand if, what I'm trying to accomplish is factive.

I have a SCADA, I wanna click a motor, and a numpad will appear to show. Data will be filled, information will be sent and motor speed will be adjusted.

This is the best example that I can find:
https://flows.nodered.org/flow/7fb5bc5ae66e6bc1b1c1b8e800bdef51
However, it lack of some functionalities.

After a lot of reading, I get a clear picture of the problem now, which included a lot of jQuery study. However, I need some help now to incorporate the code into NodeRed.

Here is my flow:

[{"id":"a56a36fae8b945af","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"420e9d893c5d0dbb","type":"ui_template","z":"a56a36fae8b945af","group":"4498d26ae459e391","name":"","order":1,"width":0,"height":0,"format":"<script>\n/*\nThis project was forked from https://github.com/kabachello/jQuery.NumPad\nwith the license shown below.\n\nThe fork's home is https://github.com/FeIronMonkey/jQuery.NumPad,\nwith the same license.\n\n----------------------------------------------------------------------------------\n\nThe MIT License (MIT)\n\nOriginal work: Copyright (c) 2014-2015 almasaeed2010\nDerived work: Copyright (c) 2021 FeIronMonkey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n/**\n* jQuery.NumPad\n*\n* Original Work: Copyright (c) 2015 Andrej Kabachnik\n* Derived work: Copyright (c) 2021 FeIronMonkey\n*\n* Licensed under the MIT license:\n* http://www.opensource.org/licenses/mit-license.php\n*\n* Project home:\n* https://github.com/FeIronMonkey/jQuery.NumPad\n*\n* Version: 1.4\n*\n*/\n(function ($) {\n/**\n* @function numpad\n* @param {object} options - The non-default options for the numpad. Instance members should correlate with members of\n`JQueryNumpad.defaults`. Supplied values override the defaults. Undefined values are ignored.\n*/\n$.fn.numpad = function (options) {\noptions = $.extend({}, JQueryNumpad.defaults, options);\n\n// Create a numpad. One for all elements in this jQuery selector.\n// Since numpad() can be called on multiple elements on one page, each call will create a unique numpad id.\nlet id;\nlet numberPadElement = {};\n\n// \"this\" is a jQuery selecton, which might contain many matches.\nreturn this.each((_, numpadTarget) => {\nif ($(`#${id}`).length === 0) {\nnumberPadElement = new JQueryNumpad(options);\nid = numberPadElement.numpad_id;\n}\n\n$.data(numpadTarget, 'numpad', numberPadElement);\n\n$(numpadTarget).attr(\"readonly\", true).attr('data-numpad', id).addClass('nmpd-target');\n\n$(numpadTarget).on(options.openOnEvent, () => {\nnumberPadElement._numpad_open(options.target\n? options.target\n: $(numpadTarget));\n});\n});\n};\n\n$.fn.numpad_open = function (initialValue) {\nthis._numpad_getNumpadElement()._numpad_open(this.first(), initialValue);\nreturn this;\n}\n\n$.fn.numpad_close = function () {\nthis._numpad_getNumpadElement()._numpad_close();\nreturn this;\n}\n\n$.fn.numpad_accept = function () {\nthis._numpad_getNumpadElement()._numpad_accept(this.first());\nreturn this;\n}\n\n$.fn.numpad_unassignNumpadsFromElement = function () {\nreturn this.each((_, numpadTargetAsDomElement) => {\nlet numpadTarget = $(numpadTargetAsDomElement)\n\nif (numpadTarget.attr('data-numpad')) {\nnumpadTarget.removeAttr('data-numpad', '');\nnumpadTarget.removeClass('nmpd-target');\nnumpadTarget.removeData('numpad');\n}\n});\n}\n\n$.fn.numpad_deleteNumpadFromDom = function () {\nthis.each((_, numpadTarget) => {\nlet numpad = $.data(numpadTarget, 'numpad');\nif (numpad) {\nnumpad.remove();\n}\n});\n\nreturn this.numpad_unassignNumpadsFromElement();\n}\n\n$.fn._numpad_getNumpadElement = function () {\nlet numberPadElement = $.data(this[0], 'numpad');\n\nif (!numberPadElement) {\nthrow \"Cannot act on a numpad prior to initialization!\";\n}\n\nreturn numberPadElement;\n}\n})(jQuery);\n\n\n/**\n* non-static functions and methods will be merged in with existing functions on any jquery object this is used to extend\n* conflicting names may be overwritten\n* many of these functions are written as if the constructed object is merged with a jquery object (using find() and\nsuch)\n* */\nclass JQueryNumpad {\nstatic _numpadIdCounter = 0;\n\nconstructor(options) {\nthis.options = options;\nthis.numpad_id = `nmpd${JQueryNumpad._numpadIdCounter++}`;\n\nlet numberPadElement = this._numpad_constructNewNumberPadElement(this.numpad_id, this.options);\n\njQuery.extend(this, numberPadElement);\n\nthis._numpad_initialize();\n\nif (this.options.draggable) {\nJQueryNumpad.makeDraggable(this.find('.nmpd-grid'), this.find('.numpad-header'));\n}\n\nthis.trigger('numpad.create', [this]);\n}\n\n_numpad_initialize = () => {\nthis._numpad_showOrHideButtons();\nthis._numpad_registerEvents();\nthis._numpad_appendToTarget();\n\njQuery('#' + this.numpad_id + ' .numero').bind('click', this._numpad_handleCharacterButtonClick);\n}\n\nnumpad_display = {};\n\n_numpad_handleCharacterButtonClick = (event) => {\nlet newText = this.numpad_display.val().toString() + jQuery(event.target).text();\nthis.numpad_setValue(newText);\n}\n\n_numpad_appendToTarget = () => {\n(this.options.appendKeypadTo\n? this.options.appendKeypadTo\n: jQuery(document.body))\n.append(this);\n}\n\nstatic cursorFocus = (elem) => {\nvar x = window.scrollX, y = window.scrollY;\nelem.focus();\nwindow.scrollTo(x, y);\n}\n\n_numpad_constructNewNumberPadElement = (id, options) => {\nlet newElement = jQuery('<div id=\"' + id + '\"></div>').addClass('nmpd-wrapper');\n\n/** @var grid jQuery object containing the grid for the numpad: the display, the buttons, etc. */\nlet table = jQuery(options.html_table_mainLayout).addClass('nmpd-grid');\nnewElement.grid = table;\n\nconst columnWidthOfGrid = 4;\n\nlet header = jQuery(options.html_label_headerContent);\ntable.append(jQuery(options.html_tr_mainLayoutTableRow)\n.append(jQuery(options.html_td_mainLayoutHeaderCell).append(header).attr('colspan',\ncolumnWidthOfGrid)).addClass('numpad-header'));\n\n/** @var display jQuery object representing the display of the numpad (typically an input field) */\nlet display = jQuery(options.html_input_display).addClass('nmpd-display');\nnewElement.numpad_display = display;\n\ntable.append((options.isDisplayVisible ? jQuery(options.html_tr_mainLayoutTableRow) :\njQuery(options.html_tr_mainLayoutTableRow).css({ display: 'none' }))\n.append(jQuery(options.html_td_mainLayoutDisplayCell).attr('colspan', columnWidthOfGrid)\n.append(display)\n.append(jQuery('<input type=\"hidden\" class=\"dirty\" value=\"0\"></input>'))));\n\n// Create rows and columns of the the grid with appropriate buttons\ntable.append(\njQuery(options.html_tr_mainLayoutTableRow)\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(7).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(8).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(9).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_functionButton).html(options.textDelete).addClass('del').click(()\n=> {\nthis.numpad_setValue(this.numpad_getValue().toString().substring(0, this.numpad_getValue().toString().length - 1));\n})))\n).append(\njQuery(options.html_tr_mainLayoutTableRow)\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(4).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(5).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(6).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_functionButton).html(options.textClear).addClass('clear').click(()\n=> {\nthis.numpad_setValue('');\n})))\n).append(\njQuery(options.html_tr_mainLayoutTableRow)\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(1).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(2).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(3).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_functionButton).html(options.textCancel).addClass('cancel').click(()\n=> {\nthis._numpad_close();\n})))\n).append(\njQuery(options.html_tr_mainLayoutTableRow)\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(this._numpad_getDashOrMinusButton(options)))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_numberButton).html(0).addClass('numero')))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_functionButton).html(options.decimalSeparator).addClass('decimal-separator-button').click(this._numpad_handleCharacterButtonClick)))\n.append(jQuery(options.html_td_mainLayoutButtonCell).append(jQuery(options.html_button_functionButton).html(options.textDone).addClass('done')))\n);\n\n// Create the backdrop of the numpad - an overlay for the main page\nnewElement.append(jQuery(options.html_div_background).addClass('nmpd-overlay').click(() => { this._numpad_close(); }));\n\nnewElement.append(table);\n\nreturn newElement;\n}\n\n_numpad_getDashOrMinusButton = (options) => options.isRequiredNumeric\n?\njQuery(options.html_button_functionButton).html('&plusmn;').addClass('negate-button').click(this._numpad_handleNegateButtonClick)\n:\njQuery(options.html_button_functionButton).html('-').addClass('negate-button').click(this._numpad_handleCharacterButtonClick)\n\n_numpad_handleNegateButtonClick = (event) => {\nlet currentValue = this.numpad_display.val();\nthis.numpad_setValue((currentValue.startsWith('-')\n? currentValue.substring(1, currentValue.length)\n: '-' + currentValue));\n}\n\n_numpad_showOrHideButtons = () => {\nif (!this.options.isPlusMinusButtonVisible) {\nthis.find('.negate-button').hide();\n}\n\nif (!this.options.isDecimalButtonVisible) {\nthis.find('.decimal-separator-button').hide();\n}\n}\n\n_numpad_registerEvents = () => {\nif (this.options.onKeypadCreate) {\nthis.on('numpad.create', this.options.onKeypadCreate);\n}\n\nif (this.options.onKeypadOpen) {\nthis.on('numpad.open', this.options.onKeypadOpen);\n}\n\nif (this.options.onKeypadClose) {\nthis.on('numpad.close', this.options.onKeypadClose);\n}\n\nif (this.options.onChange) {\nthis.on('numpad.change', this.options.onChange);\n}\n}\n\nnumpad_getValue = () => {\nlet currentValue = this.numpad_display.val();\n\nif (currentValue === '') {\nreturn '';\n}\n\nif (this.options.isRequiredNumeric) {\nreturn this._numpad_isValueNumeric(this.numpad_display.val())\n? parseFloat(this._numpad_normalizeDecimalSeparator(this.numpad_display.val())).toString()\n: '0';\n}\n\nreturn this.numpad_display.val();\n};\n\n_numpad_isValueNumeric = (obj) => {\nif (typeof obj === \"string\") {\nobj = this._numpad_normalizeDecimalSeparator(obj);\n}\n\nreturn !isNaN(parseFloat(obj)) && isFinite(obj);\n};\n\n_numpad_normalizeDecimalSeparator = (obj) => {\nreturn obj.replace(this.options.decimalSeparator, '.');\n}\n\n_numpad_localizeDecimalSeparator = (obj) => {\nreturn obj.replace('.', this.options.decimalSeparator);\n}\n\nnumpad_setValue = (value) => {\nvalue = this._numpad_cutStringLengthToMaximumAllowed(value);\nlet nonnumericAllowedValues = ['', '-', this.options.decimalSeparator, `-${this.options.decimalSeparator}`];\n\nif (this.options.isRequiredNumeric && !this._numpad_isValueNumeric(value) && !nonnumericAllowedValues.includes(value)) {\nreturn;\n}\n\nthis.numpad_display.val(value);\nthis.find('.dirty').val('1');\nthis.trigger('numpad.change', [value]);\n\nreturn this;\n};\n\n_numpad_cutStringLengthToMaximumAllowed = (value) => {\nlet maxLengthAttribute = this.numpad_display.attr('maxLength');\n\nif (!maxLengthAttribute) {\nreturn value;\n}\n\nlet maxLength;\n\nif (this.options.isRequiredNumeric) {\nlet specialCharactersCount = 0;\n\nif (value.includes(this.options.decimalSeparator)) {\nspecialCharactersCount++;\n}\n\nif (value.includes('-')) {\nspecialCharactersCount++;\n}\n\nmaxLength = parseInt(maxLengthAttribute) + specialCharactersCount;\n}\nelse {\nmaxLength = parseInt(maxLengthAttribute);\n}\n\nreturn value.toString().substr(0, maxLength)\n}\n\n_numpad_accept = (target) => {\nlet finalValue = this.numpad_getValue().toString().replace('.', this.options.decimalSeparator);\nlet textToWrite = this._numpad_cutStringLengthToMaximumAllowed(finalValue)\n\nif (target.prop(\"tagName\") === 'INPUT') {\ntarget.val(textToWrite);\n}\nelse {\ntarget.html(textToWrite);\n}\n\nthis._numpad_close();\n\nif (target.prop(\"tagName\") === 'INPUT') {\ntarget.trigger('change');\n}\n\nreturn this;\n};\n\n_numpad_close = () => {\nthis.hide();\nthis.trigger('numpad.close');\n}\n\n_numpad_open = (target, initialValue) => {\n// Use nmpd.display.val to avoid triggering numpad.change for the initial value\nif (initialValue) {\nif (!this._numpad_isValueNumeric(initialValue)) {\nconsole.error(\"The initialValue is not numeric. Unable to set value. It must be numeric.\");\nreturn;\n}\n\nthis.numpad_display.val(initialValue);\n}\nelse {\nif (target.prop(\"tagName\") === 'INPUT') {\nthis.numpad_display.val(target.val());\nthis.numpad_display.attr('maxLength', target.attr('maxLength'));\n} else {\nlet targetText = this._numpad_isValueNumeric(target.text())\n? target.text()\n: '';\n\ntargetText = this._numpad_localizeDecimalSeparator(targetText);\n\nthis.numpad_display.val(targetText);\n}\n}\n\njQuery('#' + this.numpad_id + ' .dirty').val(0);\n\nthis.show()\nJQueryNumpad.cursorFocus(this.find('.cancel'));\nthis._numpad_positionElement(target);\n\njQuery('#' + this.numpad_id + ' .done').off('click');\njQuery('#' + this.numpad_id + ' .done').one('click', () => { this._numpad_accept(target); });\n\nthis.trigger('numpad.open');\n\nreturn this;\n};\n\n_numpad_positionElement = (target) => {\nlet position = { top: 0, left: 0 };\nlet grid = this.find('.nmpd-grid');\n\nif (this.options.position === 'fixed') {\nposition = this._numpad_calculateAbsolutePositioning(grid);\n}\nelse if (this.options.position === 'relative') {\nposition = this._numpad_calculateRelativePositioning(target, grid);\n}\n\ngrid.css('position', 'fixed');\ngrid.css('left', position.left);\ngrid.css('top', position.top);\n\nreturn this;\n}\n\n_numpad_calculateAbsolutePositioning = (grid) => {\nlet position = { top: 0, left: 0 };\n\nif (jQuery.type(this.options.positionX) === 'number') {\nposition.left = this.options.positionX;\n}\nelse if (this.options.positionX === 'left') {\nposition.left = (jQuery(window).width() / 4) - (grid.outerWidth() / 2);\n}\nelse if (this.options.positionX === 'right') {\nposition.left = (jQuery(window).width() / 4 * 3) - (grid.outerWidth() / 2);\n}\nelse if (this.options.positionX === 'center') {\nposition.left = (jQuery(window).width() / 2) - (grid.outerWidth() / 2);\n}\n\nif (jQuery.type(this.options.positionY) === 'number') {\nposition.top = this.options.positionY;\n}\nelse if (this.options.positionY === 'top') {\nposition.top = (jQuery(window).height() / 4) - (grid.outerHeight() / 2);\n}\nelse if (this.options.positionY === 'bottom') {\nposition.top = (jQuery(window).height() / 4 * 3) - (grid.outerHeight() / 2);\n}\nelse if (this.options.positionY === 'middle') {\nposition.top = (jQuery(window).height() / 2) - (grid.outerHeight() / 2);\n}\n\nreturn position;\n}\n\n_numpad_calculateRelativePositioning = (target, grid) => {\nconst relativeOffset = this.options.positionRelativeOffset;\nlet position = { top: 0, left: 0 };\n\nif (jQuery.type(this.options.positionX) === 'number') {\nposition.left = target.offset().left + this.options.positionX;\n}\nelse if (this.options.positionX === 'left') {\nposition.left = target.offset().left - grid.outerWidth() - relativeOffset;\n}\nelse if (this.options.positionX === 'right') {\nposition.left = target.offset().left + target.outerWidth() + relativeOffset;\n}\nelse if (this.options.positionX === 'center') {\nposition.left = (target.offset().left + target.outerWidth() / 2) - (grid.outerWidth() / 2);\n}\n\nif (jQuery.type(this.options.positionY) === 'number') {\nposition.top = target.offset().top + this.options.positionY;\n}\nelse if (this.options.positionY === 'top') {\nposition.top = target.offset().top - grid.outerHeight() - relativeOffset;\n}\nelse if (this.options.positionY === 'bottom') {\nposition.top = target.offset().top + target.outerHeight() + relativeOffset;\n}\nelse if (this.options.positionY === 'middle') {\nposition.top = (target.offset().top + target.outerHeight() / 2) - (grid.outerHeight() / 2);\n}\n\nreturn position;\n}\n\n/**\n* Makes an element draggable.\n* @param {object} element - A jQuery object representing the element to drag around.\n* @param {object} dragHandleElement - A jQuery object representing the element the user \"grabs\" to initiate dragging.\n*/\nstatic makeDraggable = (element, dragHandleElement) => {\nlet start = { x: 0, y: 0 };\nlet delta = { x: 0, y: 0 };\n\nlet startDragging = (e) => {\ne = e || window.event;\ne.preventDefault();\n\nstart = { x: e.clientX, y: e.clientY };\ndelta = { x: 0, y: 0 };\n\njQuery(document).on('mouseup', stopDragging);\njQuery(document).on('mousemove', moveElementWithCursor);\n\ndocument.addEventListener('touchend', stopDragging, false);\ndocument.addEventListener('touchmove', moveElementWithTouch, false);\n}\n\nlet moveElementWithCursor = (e) => {\ne = e || window.event;\ne.preventDefault();\n\ndelta.x = e.clientX - start.x;\ndelta.y = e.clientY - start.y;\n\nelement.css({ transform: `translate(${delta.x}px, ${delta.y}px)` });\n}\n\nlet moveElementWithTouch = (e) => {\ne = e || window.event;\ne.preventDefault();\n\ndelta.x = start.x - e.touches[0].pageX;\ndelta.y = start.y - e.touches[0].pageY;\n\nstart.x = e.touches[0].pageX;\nstart.y = e.touches[0].pageY;\n\nelement.css({ top: element.position().top - delta.y, left: element.position().left - delta.x });\n}\n\nlet stopDragging = () => {\njQuery(document).off('mouseup');\njQuery(document).off('mousemove');\n\ndocument.removeEventListener('touchend', stopDragging);\ndocument.removeEventListener('touchmove', moveElementWithTouch);\n\nelement.css('transform', ``);\nelement.css({ top: element.position().top + delta.y, left: element.position().left + delta.x });\n}\n\nif (dragHandleElement && dragHandleElement.length > 0) {\ndragHandleElement.on('mousedown', startDragging);\ndragHandleElement.on('touchstart', startDragging);\n} else {\nelement.on('mousedown', startDragging);\nelement.addEventListener('touchstart', startDragging);\n}\n}\n\nstatic positionModes = {\nfixed: 'fixed',\nrelative: 'relative',\n}\n\n\nstatic defaults = {\n/** @type {object} - A jQuery object representing the HTML element to append the numpad to. If null, the numpad will be\nappended to the document body. */\nappendKeypadTo: null,\n\n/** @type {string} - The character used to indicate the separation between a number's whole and fractional parts. It\nshould match what is expected for the locale of the website (',' in Germany, '.' in the United States, for example).*/\ndecimalSeparator: ',',\n\n/** @type {boolean} - Indicates whether the user should be able to drag the numpad around on the screen. Draggable if\ntrue, statically positioned if false.*/\ndraggable: true,\n\n\n/** @type {string} The template HTML for the function buttons. Add CSS classes or styling to customize the appearance.*/\nhtml_button_functionButton: '<button></button>',\n\n/** @type {string} The template HTML for the number buttons. Add CSS classes or styling to customize the appearance.*/\nhtml_button_numberButton: '<button></button>',\n\n/** @type {string} The template HTML for the background mask. No background mask will appear if left as default. With\nBootstrap, `'<div class=\"modal-backdrop in\"></div>'` turns it into a background mask.*/\nhtml_div_background: '<div></div>',\n\n/** @type {string} The template HTML for the display on the numpad. Add CSS classes or styling to customize the\nappearance.*/\nhtml_input_display: '<input type=\"text\"/>',\n\n\t\t/** @type {string} The template HTML for the header.  HTML element, `<Label>` is expected.  For example, `'<label>Input Field Title</label>'`*/\nhtml_label_headerContent: '<label>Input Field Title</label>', /** null, */\n\n/** @type {string} The template HTML for the table which organizes all visible elements in the numpad. Add CSS classes\nor styling to customize the appearance.*/\nhtml_table_mainLayout: '<table></table>',\n\n/** @type {string} The template HTML for the table cells which house the buttons. Add CSS classes or styling to\ncustomize the appearance.*/\nhtml_td_mainLayoutButtonCell: '<td></td>',\n\n/** @type {string} The template HTML for the table cell which houses the display. Add CSS classes or styling to\ncustomize the appearance.*/\nhtml_td_mainLayoutDisplayCell: '<td></td>',\n\n/** @type {string} The template HTML for the table cell which houses the header. Add CSS classes or styling to customize\nthe appearance.*/\nhtml_td_mainLayoutHeaderCell: '<td class=\"nmpd-table-header-cell\"></td>',\n\n/** @type {string} The template HTML for the rows in the table. Add CSS classes or styling to customize the\nappearance.*/\nhtml_tr_mainLayoutTableRow: '<tr></tr>',\n\n\n/** @type {boolean} */\nisDecimalButtonVisible: true,\n\n/** @type {boolean} */\nisPlusMinusButtonVisible: false,\n\n/** @type {boolean} */\nisDisplayVisible: true,\n\n/** @type {boolean} - If true, only allows input which can be parsed as a number. False allows values like\n'23.3.4-357'*/\nisRequiredNumeric: true,\n\n/** @type {string} - The event on which the numpad should be opened.*/\nopenOnEvent: 'click',\n\n/** @type {string} - Must be one of `JQueryNumpad.positionModes`. If 'fixed', will position the numpad relative to the\ndocument top, left. If 'relative', will position the numpad relative to the target.*/\nposition: JQueryNumpad.positionModes.fixed,\n\n/** @type {(string | number)} - May be 'left', 'right', 'center', or a number */\npositionX: 'center',\n\n/** @type {(string | number)} - May be 'top', 'bottom', 'middle', or a number */\npositionY: 'middle',\n\n/** @type {number} - If `position = JQueryNumpad.positionModes.relative` and `positionX` or `positionY` is set with any\nof the qualitative (ex. 'top' or 'left') options, this is he distance the numpad will be shown from the target. */\npositionRelativeOffset: 5,\n\n/** @type {object} The element which the numpad will set the value of. If null, the target will be the object on which\n`.numpad()` was called.*/\ntarget: null,\n\n\n/** The text for the Cancel button. */\ntextCancel: 'Cancel',\n\n/** The text for the Clear button. */\ntextClear: 'Clear',\n\n/** The text for the Del button. */\ntextDelete: 'Del',\n\n/** The text for the Done button. */\ntextDone: 'Done',\n\n\n/** Triggers immediately after the numpad is created. The first parameter is the triggered event args. The second\nparameter is the numpad as a jQuery object.*/\nonKeypadCreate: () => { },\n\n/** Triggers immediately after the numpad is opened.*/\nonKeypadOpen: () => { },\n\n/** Triggers immediately after the numpad is closed, regardless of how the user closed it.*/\nonKeypadClose: () => { },\n\n/** Triggers immediately after the numpad's value is changed. @param {object} event is the triggered event. @param\n{string} value is the new value after the change.*/\nonChange: (event) => {\n\n},\n};\n}\n</script>\n\n<style>\n/*\nThis project was forked from https://github.com/kabachello/jQuery.NumPad\nwith the license shown below.\n\nThe fork's home is https://github.com/FeIronMonkey/jQuery.NumPad,\nwith the same license.\n\n----------------------------------------------------------------------------------\n\nThe MIT License (MIT)\n\nOriginal work: Copyright (c) 2014-2015 almasaeed2010\nDerived work: Copyright (c) 2021 FeIronMonkey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n\n.nmpd-wrapper {\ndisplay: none;\nz-index: 2147483647;\nposition: absolute;\n}\n\n.nmpd-target {\ncursor: pointer;\n}\n\n.nmpd-grid {\nposition:absolute;\nleft:50px;\ntop:50px;\nz-index:5000;\npadding:10px;\nwidth: initial;\n}\n\n.nmpd-overlay {\nz-index:4999;\n}\n\ninput.nmpd-display {\ntext-align: right;\n}\n\n.nmpd-table-header-cell{\nborder-bottom: 1px solid #ddd;\n}\n</style>\n\n\n<script>\n\t// Set NumPad defaults for jQuery mobile. \n\t// These defaults will be applied to all NumPads within this document!\n\t\n\tJQueryNumpad.defaults.html_table_mainLayout = '<table class=\"table modal-content\"></table>';\n\tJQueryNumpad.defaults.html_div_background = '<div class=\"modal-backdrop in\"></div>';\n\tJQueryNumpad.defaults.html_input_display = '<input type=\"text\" class=\"form-control\" />';\n\tJQueryNumpad.defaults.html_button_numberButton =  '<button type=\"button\" class=\"btn btn-default\"></button>';\n\tJQueryNumpad.defaults.html_button_functionButton = '<button type=\"button\" class=\"btn\" style=\"width: 100%;\"></button>';\n\tJQueryNumpad.defaults.decimalSeparator = '.';\n\tJQueryNumpad.defaults.onKeypadCreate = function(){$(this).find('.done').addClass('btn-primary');};\n\t\n\t// Instantiate NumPad once the page is ready to be shown\n\t$(document).ready(function(){\n\t\talert(\"This isn't executed\");\n\t\t/*\n\t\t$('button_numpad').numpad({\n\t\t\thtml_input_display: '<input class=\"form-control\" type=\"text\" id=\"numpad_input\"/>',\n\t\t\tisPlusMinusButtonVisible: false,\n\t\t\tisDecimalButtonVisible: true,\n\t\t});\n\t\t*/\n\t});\n\n\t// $( \"#numpad_input\" ).change(function() {\n\t// \talert( \"Handler for .change() called.\" );\n\t// });\n\t\n</script>\n\n<script type=\"text/javascript\">\n\t$(document).ready(function(){\n\t\talert(\"This is executed\");\n\t});\n</script>\n\n<style type=\"text/css\">\n\t.nmpd-grid {\n\t\tborder: none;\n\t\tpadding: 20px;\n\t}\n\n\t.nmpd-grid>tbody>tr>td {\n\t\tborder: none;\n\t}\n\n\t/* Some custom styling for Bootstrap */\n\t.qtyInput {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\tpadding: 6px 12px;\n\t\tcolor: #555;\n\t\tbackground-color: white;\n\t\tborder: 1px solid #ccc;\n\t\tborder-radius: 4px;\n\t\t-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n\t\tbox-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n\t\t-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n\t\t-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n\t\ttransition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n\t}\n</style>\n\n<button id=\"button_numpad\"> Numpad </button>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":540,"y":180,"wires":[[]]},{"id":"4498d26ae459e391","type":"ui_group","name":"Group 1","tab":"2273bd472cdf87eb","order":1,"disp":true,"width":6},{"id":"2273bd472cdf87eb","type":"ui_tab","name":"Tab 3","icon":"dashboard","order":1}]

I've put:

<script>my jquery class</script>
<script>can't find the class</script>

Basically, it can't find my jquery class

I finally got it working. Somehow, it only works when

<script src="static.js">

is used.

My last problem:

but it is supposed to be

Same css. Any tip?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.