Found a couple of really cool simple time pickers

Are you referring to foundation-datepicker? Did you make it work in dashboard and test it? Does the chromium browser have internet access to use the cdn?

No the built-in dashboard time input and the html example you showed a video of. The browsers picker you called it. Internet access is deliberately blocked on this network.

I asked if you tried the foundation-datepicker & the reason i asked if you had internet was in-case you did try it but it didnt work because you used a CDN - nevermind.

Here is a demo of it. NOTE: as you dont have internet i copied the necessary CSS+JS into a ui_template set for head mode

5dOllhdVor

image

flow (too large to post in the reply)...
foundation-datepicker-demo.json (68.0 KB)

1 Like

Hi @Steve-Mcl sorry for the delay and thank you very much for the foundation control. It looks good but I would have to remove the date stuff to claw back some space. My app has very tight memory and cpu constraints and has no need for a date picker.

It is however useful to have an example of js code but not so much use if it requires modification in order to put it in a ui_template.

The code changes I had to make to get the original table type time picker at the top (not the scroll one) are dreadful. Simply because I do not understand all that is going on in the js code. For instance a class (I think its a class) called 'Protected'. A couple of days searching did not help me understand the syntax so I just had to hack away until I got a result.

What I have created may be a stark example of how NOT to go about things when building a ui_template widget !

Only others with more knowledge than I can shine a light on what is and is not good ui_template code. I would hope someone could comment constructively one way or another so that other not so knowledgeable do not follow and copy a bad way of doing things.

You are saying the node-red server does not have enough room for 68 kilobytes?

I have no idea what you mean here - I gave you a working example. Regardless of your solution, something has to tell an INPUT to become a time picker. The example is clean and all the complexity is hidden in the HEAD template.

PS, you do realise there are 3 examples - the middle one doesnt show you the date picker.

Hi @Steve-Mcl, thanks for a swift reply.

Yes. On pi zero w I have been forced by memory/cpu constraints to strip all unrequired code and nodes that I can. A few k here and a few k there all add up to the last straw and the inevitable connection lost catchup situation.

Sorry my mistake then. Thank you, I will study the code and use it as a model of how it should be done.

Thank you I do realise that you gave three examples.

1 Like

Hi @Steve-Mcl, thank you the code is incredibly clean and concise. I have not tried this on a pi zero (buster light or something like that) yet.

Unfortunately on a pi4 the time picker does not expand beyond the confines of the dashboard grid. Also I have ui space constraints and (when not being used) would ideally like the widget to work within 1x1 grid size.

None the less thank you for a clean working example. It is much appreciated and may deter others from copying my dirty hacks.

1 Like

Surely just play with a bit of styling etc to change the size to fit ? eg

<div>
<font size="-5">
<input type="text" id="time_only" autocomplete="off" class="foundationtimepicker" size=5 style="margin-top:10px;"></input>
</font></div>

image

1 Like

Hi @dceejay, thank you for your input.

I changed the html <input type="time" but unfortunately it does not pop up.

Hi, some confusion here on my part. I was testing against the HTML time input. vis.

<!--
<div>
    <font size="-5">
    <input type="text" id="time_only" autocomplete="off" class="foundationtimepicker" size=5 style="margin-top:10px;">
</font></div>
or
<div>
    <input type="time" id="timeFrom" class="timepicker" >
    <input type="time" id="timeTo" class="timepicker" >
</div>
//-->
<div>
    <font size="-5">
    <input type="time" id="timeFrom" autocomplete="off" class="timepicker" size=5 style="margin-top:10px;">
</font></div>

<script>
(function(scope) {
    var timepicker = $(".timepicker")
    timepicker.on('change', function(evt) {
        scope.send({ topic: this.id, payload: this.value });
    });
})(scope);
</script>

Results in lower left:
image
which unfortunately does not fit and also does not pop up under buster using chromium.

I have had a bit more success with the table popup I started the topic with.
image
Have not figured out persistence yet with browser refresh and redepoly.

The big problem here is my code quality and ignorance. I would like to have kept more of the original code structure but I could not figure how to implement it in ui_template.
The original code structure with @Steve-Mcl clean example:
image

Is it easy to explain how to combine this into a ui_template that has buttons and color pickers ?
What is Protected and root[classname]= f() mean ?

Many thanks for all the help so far!

I have made more progress on the table type Time picker. Here are three CSS sizes (normal-size,bigger and big, wa is a text input field as a baseline metric) for a dashboard cell of 1x1(48x48px, 6px widget spacing). The TP outputs the topic as the html ID and the payload as formatted text(hh:mm) when the value is different on exiting the picker. Initial value can be set (yet to add a watch for initial value and sort out persistence). Also they work with the dashboard theme change.
image
Left Hand is DeskTop RH is Pi.
Using Chromium on the DT and Pi and a browser font size of small results in the Pi showing a little inconsistency on base line for the normal-size font. As @hotNipi suggested, styling basic elements seems limited. One has to consider that the DT is 64-bit and the Pi 32-bit, also the latter has less than svga resolution. One Note is that more consistency with CSS can be obtained by setting the browser font sizes to verry-small.

Since no one has come forward (not a criticism) to answer my previous question about code structure I have hit another wall which raises another bigger question:

Within the context of a ui_template node, if the node contains several widgets e.g. time/date/colour/font/theme etc. what is the preferred coding style for managing the code complexity. I would expect the ability to enable/disable/decorate other widgets within the template based on ui interaction and msg input from node-red. ?

[{"id":"fa55a35.48b4e6","type":"ui_template","z":"e94b4ba2.500028","group":"65bb6bb.2b6e094","name":"ck-button CSS","order":1,"width":0,"height":0,"format":"/!--\nNote: Better accuracy and consistency between desktop and pi\nchromium buster when using font sizes in px.\n-->\n<style>\n    .nr-dashboard-template, .ck-timerscr{\n        padding: 0px;\n        overflow:visible;\n    }\n\n    .md-button {\n        border-radius: 10px;\n    }\n\n    .ck-button:hover {\n        border:1px solid red;\n    }\n\n    .bold {\n        font-weight:bold;\n    }\n    .xx-huge{\n        font-size:3.8em;\n    }\n    .x-huge{\n        font-size:3.0em;\n    }\n    .huge{\n        font-size:2.5em;\n    }\n    .xx-big{\n        font-size:24px;\n    }\n    .x-big{\n        font-size:20px;\n    }\n    .big{\n        font-size:19px;\n    }\n    .bigish{\n        font-size:18px;\n    }\n    .bigger{\n        font-size:16px;\n    }\n    .normal-size{\n        font-size:10px;\n    }\n    .smaller{\n        font-size:7px;\n    }\n    .small{\n        font-size:6px;\n    }\n    .tiny{\n        font-size:4px;\n    }\n\n\n    .ck-button.show + .off{\n        opacity: 1;\n    }\n    .ck-button.flash{\n        animation: flash-animation 0.75s steps(5, start) infinite;\n        animation-timing-function: ease-out;\n        -webkit-animation: flash-animation 0.75s steps(5, start) infinite;\n    }\n    @keyframes flash-animation {\n        to { visibility: hidden; }\n    }\n    @-webkit-keyframes flash-animation {\n        to { visibility: hidden; }\n    }\n    .ck-button.animated .ck-button.warning {\n        -webkit-animation: pulse 0.75s infinite;\n        animation: pulse 0.75s infinite;\n        }\n\n    @-webkit-keyframes pulse {\n      0% {\n        opacity: 0.2\n      }\n\n      30% {\n        opacity: 1.0\n      }\n    \n      100% {\n        opacity: 0.2\n      }\n    }\n\n    @keyframes pulse {\n      0% {\n        opacity: 0.2\n      }\n    \n      30% {\n        opacity: 1.0\n      }\n    \n      100% {\n        opacity: 0.2\n      }\n    }\n    /* New ck-button */    \n    .ck-button.disabled{\n        pointer-events: none;\n        opacity: 0.5;\n    }\n    .ck-button.selected{\n        pointer-events: none;\n    }\n    .ck-switch {\n        position: relative;\n    }\n    \n    .ck-switch input {\n        opacity: 0; /*        display: none;*/\n    }\n    \n    .off {\n        position: absolute;\n        top: 0px;\n        height: 100%;\n        width: 100%;\n        opacity: 1;     /*   display: block;      */\n    }\n    .on {\n        height: 100%;\n    }\n    .ck-button input:checked + .on {\n        opacity: 1;\n    }\n    .ck-button input:checked + div + .off {\n        opacity: 0;     /*  display: none;     */\n    }\n    .ck-button input:checked + span + .off {\n        opacity: 0  /*  display: none;     ;*/\n    }\n    \n    .ck-button {\n        margin: -6px;\n        padding: 6px;\n        width: 100%;\n        height: 100%;\n    }\n    \n    .ck-button label {\n        height: 100%;\n        text-align: center;\n        float: left;\n        width: 100%;\n    }\n    \n    .ck-button label div {\n        margin: -6px;\n        padding: 6px;\n        text-align: center;\n        display: block;\n    }\n    .ck-button label span {\n        margin: -6px;\n        padding: 6px;\n        text-align: center;\n        display: block;\n    }\n    \n    .ck-button label input {\n        position: absolute;\n        top: -20px;\n    }\n    .resize,\n    .ck-button label div {\n        white-space:normal;\n        word-break: break-all;\n        justify-content: center;\n        align-items: center;\n        display: flex;\n        flex-wrap: nowrap;\n        flex-grow: auto;\n/*\n        flex-shrink: 1;\n        display: flex;\nflex-shrink: auto;\n        flex-grow: auto;\n        align-items: center;\n        justify-content: center;\n*/\n    }\n    .ck-button label span {\n        white-space:pre-wrap;\n        word-break: break-word;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n    }\n    \n/*\nHTML\n====\n<div>\n<md-button class=\"md-button ck-button ck-switch on off small\" \n    data-payload=\"1\" \n    data-buttontype=\"radio\"\n    data-radiogroup='group1'\n    data-topic=\"8\"\n    >\n    <div class=\"ck-button\">\n        <label class=\"ck-switch\">\n            <input type=\"checkbox\" unchecked>\n            <div style=\"background-color:#00cc00\" class=\"on\">btn<br>on</div>\n            <div style=\"background-color:#006600\" class=\"off\">btn<br>off</div>\n        </label>\n    </div>\n</md-button>\n</div>\n*/\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"global","x":340,"y":40,"wires":[[]]},{"id":"65bb6bb.2b6e094","type":"ui_group","name":"ck button - dashboard@2.24.1","tab":"485a5637.1779c8","order":1,"disp":true,"width":"4","collapse":false},{"id":"485a5637.1779c8","type":"ui_tab","name":"Pad Port 1999","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Have you considered that you might be pushing Dashboard a little beyond its core comfort zone :rofl:

That's tha most fun part of it :upside_down_face:

No not at all. I really do not want to get that wet. A toe in the water may be just enough to do what I want. Definitely no disrespect to those that do. Just not for my usecase.

Anyway is there a preferred style for anyone writing their first widget containing multiple ui elements ?

Sorry, can't help with that, uibuilder is my thing :wink:

Hi @hotNipi, it feels like I have come a long way from when you first help me out big time. Thank you again.

While being in ui_template context ...
Keep styles and html separated.
Styles should have an id, so you can find the source of rule more easily while debugging. <style id="artist-was-here">
As you can't have post build activities, you may want to have certain parts of styles held in different template.
Avoiding/finding duplicates is manual work.
But ... may be it is time to think about to build the actual ui-contirb-widget ....

Hi @hotNipi, thank you for your response, sorry I was not there to reply immediately.

I think I understand the separation of html, css and code.

Is it the correct approach to capture a reference to all the elements within the ui_template and exert control from within a single

(function(scope){
 ....
    scope.watch('msg', function(msg) {....});
})(scope)

code block and that the 5 line clean code example kindly given by @Steve-Mcl applies only for single independent html elements that do not control the look of other elements within the same u_template ?

Could you please explain a little more about this ?

This looks to me like another mountain to climb and I am not sure I have the legs for it.

P.S. How much higher do you think the ui_contrib-widget mountain is from where I am standing now ?

scope.watch('msg', function(msg)

Having that kind of functionality in ui_template the incoming msg can be read and you can do what ever you want according to what the msg contains. It allows to create dynamics at front-end side (dashboard)

Reaching some html elements which are defined in this template or somewhere else goes always by query the element or group of elements by #id or .class or by some other known property of element(s)

Build-time post-build activities:
Build time and post build activities can combine and structure and do some other fancy things with your code. So you may have small and readable parts of code. Building step makes final code from smaller parts and the outcome is optimized and combined and ... there is many many things.
But all that is not possible here.
If you create many many CSS rules the code in editor has so many lines that reading it will be harder and harder. At one point you may just lose the logic and clear understanding of it. (pretty bad if you don't understand your own work). So you can have more readable structure by breaking it into meaningful parts.

How much higher...
Well that depends. The languages will be practically same. But the tools (code editor) for creating it, will be different. Quite of many to choose... If you are not a developer some kind, it may take some time to get familiar with tools first, cos they help a lot if you are using them right way.

But overall, there will be some forced rules to follow and some tricks to learn but not too many. It takes to examine already made widgets and may be find answers to questions like "why" and "what for this is done that way" questions and then ... just practice.

Thank you for your explanation.

Could you please clarify a situation for me:

  • I have segregated all CSS into one or more ui_template 'head' section nodes

  • I have a single ui_template that contains code to coordinate the collective behaviour of all

  • I have four HTML only ui_templates (one each for text, time, colour and custom_button)

Q1. With this setup would the resulting code sit in a single

(function (scope){
     someControlCode 

     scope.watch('msg', function(msg) { someMoreControlCode });
})(scope)

block ?

Q2. Is it possible or advantageous to have multiple

(function (scope1){
     someControlCode 

     scope1.watch('msg', function(msg) { someMoreControlCode });
})(scope1)
(function (scope2){
     someControlCode 

     scope2.watch('msg', function(msg) { someMoreControlCode });
})(scope2)

blocks ?

Q3. With this setup is it impossible to have any clean code as @Steve-Mcl example showed ?

Many many thanks in advance.
best regards oz.

P.S. It seems easy to wander into a code complexity explosion.