2

Comments icon hi-lite like Attachments.

In another post wrt hiliting the paper clip this code was advised:

if count(files(this)) != 0 then
html("
<style>
.i-light-grey.i-attachment {
background-color: #a9a9a9;
border-radius: 4px;
}
</style>
")
end

So - are there any boffins out there that can tweak this code snippet to do the same for the Comments icon that lives next to the paperclip?

Comments is such a handy feature but I suspect underutilised (apart from developers perhaps) for keeping notes for records.

29 replies

null
    • Mel_Charles
    • 2 yrs ago
    • Reported - view

    Realistically this is not that far away from toying with the attachment tab and one should be able to change the above script easily to reference the count to comments instead of files and accordingly change the ref in the colour line from attachments to comments- However Ninox claims it cannot define the function if this is tried.. From looking at previous posts re comments tab as a function to call it appears that it is on a wish list/do to ...

    Has me defeated at the moment 😥

    • Sean
    • 2 yrs ago
    • Reported - view

    Without a function for comments like there is for file attachments - files(), I don't know how it would be possible using Ninox's built-in comment feature. It would be easy to duplicate the functionality by creating a child Comments table. You could put the child table information in a Tab and hide the built-in comment icon. Is that something you're interested in?

     

    I don't know why Ninox doesn't display attachment count and comment count next to the icons 🤷‍♂️. For what it's worth, I created a simple database, added some comments and downloaded the archive to my laptop. The comments are stored in a separate database file, but they are easy enough to parse and I don't see why a comment() function would be difficult to implement. If they simply displayed the number of comments next to the icon a function wouldn't be needed.

    • Alan_Cooke
    • 2 yrs ago
    • Reported - view

    I agree - creating a comments table would be a solution and I have considered that.  Thing is one can add comments so easily randomly anywhere without any effort via that icon.  Pretty much a 'Post It' note.  So quick and easy....hopefully the idea will be implemented in time.

    • Mel_Charles
    • 2 yrs ago
    • Reported - view

    Yeah I do both colour the tab and tag the files count on most of my forms

    Like Sean's idea. A simple count next to the icon would be great - Even better if Ninox let you colour the tab just like you can with the other tabs

    • Mr_K
    • 2 yrs ago
    • Reported - view

    I cannot make this work. The paper clip is gray even when I have attachments. I have iCloud not Ninox cloud. Is that why, or am I suppose to change the code somewhat for my DB?

    • Ninox developper
    • Jacques_TUR
    • 2 yrs ago
    • Reported - view

    Good evening everyone,

    following an exchange with Alan I made this. It works well, but it uses JavaScript and could become unstable over time if Ninox changes its code.

    The first code proposed by Alan had several flaws:
    - It had to be added to every page and every tab on every page for it to work all the time.
    - The count(files()) usage returns the total number of files in the record, including those linked to image fields. The tab could is highlighted when there were no files in the list.

     

    For comments, the list, add, edit and delete functions exist and are accessible in JavaScript. They are just not linked to NinoxScript.

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR It's not just code in JavaScript that can become unstable if they change their code. The http() function for example. 😉

    • Ninox developper
    • Jacques_TUR
    • 2 yrs ago
    • Reported - view

    Here is the JavaScript code for the file attachments and comments badges

    The code must be placed in a formula. The display of the badges will start after the first execution of the code. It is therefore advisable to place the formula on the first page that is displayed in the application.

    html("
    <script>
        //style base of badges
        var badgeStyle = `
                        position: absolute;
                        display: flex;
                        top: 0px;
                        right: 0px;
                        background-color: red;
                        height: 15px;
                        line-height: 15px;
                        width: 15px;
                        text-align: center;
                        border-radius: 50%;
                        color: white;
                        justify-content: center;
                        font-size: smaller`;
        // color of selection
        var filesColor = '#4970ff';
        var oldCommentColor = '#999999';
        var newCommentColor = 'red';
        // Threshold of new or old comment in ms. For 1 day = 1000ms * 60s * 60mn * 24h = 86400000ms
        var oldCommentThreshold = 1000 * 60 * 60 * 24;
    
        //event function called when tab changeed or popup opened
        function editorTabChanged(e) {
            //recordver the current editor with links to html components
            var editor = ui.getCurrentEditor();
            if (editor && editor.container) {
                var container = editor.container;
    
                //call the original event fonction editorTabChanged
                Object.getPrototypeOf(container).oldeditorTabChanged(e);
    
                //load files of current record (is async function)
                database.loadFiles(container.nid, (e, i) => {
                    // e = error text
                    // i = files array of id record this.id
    
                    // recover the attached files icon on current editor
                    var files = ui.getCurrentEditor().files.elTab[0];
                    if (files) {
                        //recover or create the badge
                        var badge = files.getElementsByTagName('span')[0];
                        if (!badge) {
                            badge = document.createElement('span');
                            files.appendChild(badge);
                        }
    
                        //reading file list en exclude files connected to fields
                        var n = database.typeOf(container.nid);
                        var r = database.loadNodeSync(container.nid);
                        if (n && r) {
                            var s = {},
                                l = n.fields;
                            for (var c in l) {
                                if (l.hasOwnProperty(c))
                                    if ('file' === l[c].base) {
                                        var d = r[c];
                                        d && (s[d] = !0)
                                    }
                            }
                            let f = []
                            for (var u = 0; u < i.length; u++)
                                s[(d = i[u]).name] || f.push(d);
    
                            //number attached files
                            var cnt = f.length;
    
                            //set the badge
                            badge.style.cssText = badgeStyle;
                            badge.innerText = cnt.toString();
                            badge.style.visibility = (cnt > 0) ? 'visible' : 'hidden';
                            badge.style.backgroundColor = filesColor;
                        }
                    };
                });
    
                //load files of current record (is async function)
                database.loadComments(container.nid, (e, i) => {
                    // e = error text
                    // i = comments array of id record this.id
    
                    // recover the comment icon
                    var comments = editor.comments.elTab[0];
                    if (comments) {
    
                        //recover or create the badge
                        var badge = comments.getElementsByTagName('span')[0];
                        if (!badge) {
                            badge = document.createElement('span');
                            comments.appendChild(badge);
    
                        }
    
                        //get durrent time to compare with comment date
                        var ms = Date.now();
    
                        //count the number of new and old comments
                        var cntNew = i.reduce((total, el) => {
                            if (ms - el[0] < oldCommentThreshold) total += 1;
                            return total;
                        }, 0);
                        var cntAll = i.length;
    
                        //set the badge with different color to indicate if there is new comments
                        badge.style.cssText = badgeStyle;
                        badge.innerText = cntNew ? cntNew.toString() : cntAll.toString();
                        badge.style.visibility = (cntAll + cntNew > 0) ? 'visible' : 'hidden';
                        badge.style.backgroundColor = (cntNew > 0) ? newCommentColor : oldCommentColor;
    
                    };
                })
            }
    
        }
    
        // On first call, put this editorTabChanged in place to Ninox function and save the oldest
        var container = ui.getCurrentEditor().container;
        if (container && !Object.getPrototypeOf(container).oldeditorTabChanged) {
            Object.getPrototypeOf(container).oldeditorTabChanged = Object.getPrototypeOf(container).editorTabChanged;
            Object.getPrototypeOf(container).editorTabChanged = editorTabChanged;
        }
    
    </script>
    ")
      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR Fantastic. I'm looking forward to studying this.

      • Alan_Cooke
      • 2 yrs ago
      • Reported - view

      Sean It's such a treat to have this.  THANK YOU Jacques TUR 
       

    • Mr_K
    • 2 yrs ago
    • Reported - view

    I get this error. How do I fix it? Thanks.

      • Ninox developper
      • Jacques_TUR
      • 2 yrs ago
      • Reported - view

      Mr. K. Ninox seems to be trying to interpret the javascript. It is normally enclosed in quotes so that it is not interpreted by Ninox. I guess there must be one too many quotes in the code. 
      Can you copy and paste your code to me privately?

    • Sean
    • 2 yrs ago
    • Reported - view

    I get the same error in the Mac app that Mr. K. got. When I run the code in the browser version, I don't see the badges.

     

    I copied the code using the forum copy button and I tried it using Safari, Firefox and Chrome.

      • Sean
      • 2 yrs ago
      • Reported - view

      Sean I removed the .loadComments method from the editorTabChanged function for the Mac app code since there isn't a Comment tab in the Mac app. The error is gone, but still no badge for attachments.

    • Sean
    • 2 yrs ago
    • Reported - view

    Just an update. I communicated with Jacques and he has a new version that works for me now and I hope that he posts the updated code since it is a great mod. I was also able to make it work in the Mac app for attachments.

    • Ninox developper
    • Jacques_TUR
    • 2 yrs ago
    • Reported - view

    Hello to all, 
    and thanks to Sean, Bruce and Alan who kindly did some testing that allowed me to stabilise the code.

    It is now functional on the web and on the Mac application. 

    var divId := "myDiv" + string(this.ID);
    html("
    <div id='" + divId + "'></div>
    <script>
        debugger;
        //create global object to manage badges.
        if (!window.badges) window.badges = {};
    
        //style base of badges
        badges.style = `
                position: absolute;
                display: flex;
                top: 0px;
                right: 0px;
                background-color: red;
                height: 15px;
                line-height: 15px;
                width: 15px;
                text-align: center;
                border-radius: 50%;
                color: white;
                justify-content: center;
                font-size: smaller`;
        // color of selection
        var filesColor = '#4970ff';
        var oldCommentColor = '#999999';
        var newCommentColor = 'red';
        // Threshold of new or old comment in ms. For 1 day = 1000ms * 60s * 60mn * 24h = 86400000ms
        var oldCommentThreshold = 1000 * 60 * 60 * 24;
    
        //event function called when tab changeed or popup opened
        function selectTab(e) {
            //call the original event fonction selectTab
            if (this.oldSelectTab) this.oldSelectTab(e);
            debugger;
            try {
                //recordver the current badges.editor with links to html components
                if (this.container) {
                    console.log('badges : files load')
                    //load files of current record (is async function)
                    database.loadFiles(this.container.nid, (e, i) => {
                        // e = error text
                        // i = files array of id record this.id
    
                        console.log('badges : files refresh')
    
                        // recover the attached files icon on current badges.editor
                        var files = this.files.elTab[0];
                        if (files) {
                            //recover or create the badge
                            var badge = files.getElementsByTagName('span')[0];
                            if (!badge) {
                                badge = document.createElement('span');
                                files.appendChild(badge);
                            }
    
                            //reading file list en exclude files connected to fields
                            var n = database.typeOf(this.container.nid);
                            var r = database.loadNodeSync(this.container.nid);
                            if (n && r) {
                                var s = {},
                                    l = n.fields;
                                for (var c in l) {
                                    if (l.hasOwnProperty(c))
                                        if ('file' === l[c].base) {
                                            var d = r[c];
                                            d && (s[d] = !0)
                                        }
                                }
                                let f = []
                                for (var u = 0; u < i.length; u++)
                                    s[(d = i[u]).name] || f.push(d);
    
                                //number attached files
                                var cnt = f.length;
    
                                //set the badge
                                badge.style.cssText = badges.style;
                                badge.innerText = cnt.toString();
                                badge.style.visibility = (cnt > 0) ? 'visible' : 'hidden';
                                badge.style.backgroundColor = filesColor;
                            }
                        };
                    });
    
                    // load the comment only for the web application.On the Mac application, comments do not exist
                    if (schemas.envConfig.userEnvName != 'mac') {
                        console.log('badges : comments load')
    
                        //load files of current record (is async function)
                        database.loadComments(this.container.nid, (e, i) => {
                            // e = error text
                            // i = comments array of id record this.id
    
                            console.log('badges : comments refresh')
    
                            // recover the comment icon
                            var comments = this.comments ? this.comments.elTab[0] : null;
                            if (comments) {
    
                                //recover or create the badge
                                var badge = comments.getElementsByTagName('span')[0];
                                if (!badge) {
                                    badge = document.createElement('span');
                                    comments.appendChild(badge);
    
                                }
    
                                //get durrent time to compare with comment date
                                var ms = Date.now();
    
                                //count the number of new and old comments
                                var cntNew = i.reduce((total, el) => {
                                    if (ms - el[0] < oldCommentThreshold) total += 1;
                                    return total;
                                }, 0);
                                var cntAll = i.length;
    
                                //set the badge with different color to indicate if there is new comments
                                badge.style.cssText = badges.style;
                                badge.innerText = cntNew ? cntNew.toString() : cntAll.toString();
                                badge.style.visibility = (cntAll + cntNew > 0) ? 'visible' : 'hidden';
                                badge.style.backgroundColor = (cntNew > 0) ? newCommentColor : oldCommentColor;
    
                            };
                        })
                    }
                }
    
            } catch (err) {
                console.log('badges error : ' + String(err.message));
            }
    
        }
    
        // On first call, put this selectTab in place to Ninox function and save the oldest
        function setHook() {
            try {
                //badges.editor = ui.getCurrentEditor();
                if (!badges.editor) {
                    debugger;
                    var div = document.getElementById('" + divId + "');
                    if (div) {
                        var data = $(div).closest('.component').data('component');
                        if (data) {
                            badges.editor = data.container;
                        }
                    }
    
                }
    
                if (badges.editor && badges.editor.container && !Object.getPrototypeOf(badges.editor).oldSelectTab) {
                    if (!Object.getPrototypeOf(badges.editor).oldSelectTab) {
                        Object.getPrototypeOf(badges.editor).oldSelectTab = Object.getPrototypeOf(badges.editor).selectTab;
                        Object.getPrototypeOf(badges.editor).selectTab = selectTab;
                        console.log('badges initalized');
    
                        badges.initalized = true;
                        badges.editor.selectTab(badges.editor.currentTab.id);
    
    
                        if (ui.getCurrentEditor() && ui.getCurrentEditor().currentTab)
                            ui.getCurrentEditor().selectTab(ui.getCurrentEditor().currentTab.id)
                    }
    
                }
                else if (!badges.editor)
                    setTimeout(setHook, 100);
            } catch (err) {
                alert('badges error : ' + String(err.message));
            }
        }
        setHook();
    
        if (badges.initalized) {
            var component = document.getElementById('" + divId + "');
            if (component)
                component.innerText = 'badges initalized';
        }
    
    </script>
    ")
    
      • Alan_Cooke
      • 2 yrs ago
      • Reported - view

      Jacques TUR This is a brilliant script and makes what is normally an avoided feature (attachments and comments) a useful tool.

      • buy
      • 2 yrs ago
      • Reported - view

      Jacques TUR such a great and smart code....why did you exclude the Mac comments, i have eliminated the Config.userEnvName != 'mac' condition and it works well on the Mac app, the comments are visible.

      • Ninox developper
      • Jacques_TUR
      • 2 yrs ago
      • Reported - view

      buy I'm surprised, because on my Mac application, comments are not visible !?
      Only the attached files appear.

      • buy
      • 2 yrs ago
      • Reported - view

      Jacques TUR It looks like you have made your test on a local database, which is by nature, not having the comments feature. If you do open a Ninox cloud database, the mac app will then show you the comments.

      • Ninox developper
      • Jacques_TUR
      • 2 yrs ago
      • Reported - view

      buy Thanks very much!

      I don't use the Mac application and I didn't see that it was possible to connect to Ninox Cloud and have access to the comments. 

      I just corrected it. Now it checks if the comments are accessible, either from the application or the web cloud. I put this version 1.03 online.

    • Mel_Charles
    • 2 yrs ago
    • Reported - view

    Hi Jaques

    I had a way of listing the files count and colouring the paperclip icon, but of course like many others could not get at the comments area. 

    Your solution is neat and well executed and I have already taken advantage of it (noting that it might fall apart if Nixon do their thing on the software!)

    I'm on cloud version and it works a treat

    Very useful and practical !

      • Ninox developper
      • Jacques_TUR
      • 2 yrs ago
      • Reported - view

      Mel Charles Thank's 😊

      • Mel_Charles
      • 2 yrs ago
      • Reported - view

      Jacques TUR 

      Following on from your excellent idea here.

      I was wondering if it is possible to have a file count on another tab or include files in that tab on your final count..

      ie

      On the attachments tab I add any incidental files. However on my JobBag table forms I have DOCUMENTS tab page with various image boxes whereby I drag in the customers purchase order, our confirmation, the suppliers quote etc.

      I count these by stating - cnt(files(this)) in a formula box

       

      So I am wondering if say the 4 documents could have an icon (4) above the documents tab or the count of the icon in example would say show 5 as per my files count?

      do you thing this is doable?

      • Ninox developper
      • Jacques_TUR
      • 2 yrs ago
      • Reported - view

      Mel Charles to add badge on tab, see this post : https://forum.ninox.com/t/h7hn1sh

      To count the number of files, you need to know that cnt(files(this)) will return all files related to this record. Whether the files are in attachments or in image fields. When I display the number of files in the attached files tab, I only count the files that are in the list.

      If you want to count the files in your Documents tab, you could use this formula : 

      var NbDocuments := number(CustomerOrder != null) + number(OrderConfirmation != null) +
                  number(Misc != null) + number(SupplierOrder != null) +
                  number(SupplierConfirmation != null) + number(SupplierVisual != null);

      Does this answer your questions?

Content aside

  • 2 Likes
  • 1 yr agoLast active
  • 29Replies
  • 893Views
  • 11 Following