Open current row in modal

Hi, I’m a novice being on Seatable cloud.

I wonder if there’s a script to open the record on a button click(like a Button column and when you click it opens current row’s record in modal). Like context.current_row and then some method of the regular popup. Enlarge on button click feels more intuitive for non-techy folks, thanks!

Ps Thank you for the insanely powerful tool! Germany rocks :heart::slightly_smiling_face:

You can open the “row details” by hitting “SPACE” on your keyboard. Is this what you are looking for?

1 Like

Not exactly. My situation is a no-keyboard setup for the older folks(tablets), so their fingers and eyes are better adopted to the regular buttons.
Maybe a command of key hitting(in script)?

Tried
var e = new KeyboardEvent(‘keydown’,{‘keyCode’:32,‘which’:32});
Shows success, though no popup. I saw somewhere key list and there was Enter only and no space, may be on tablet it’s Enter?

13 wouldn’t work either :grimacing:

Sorry, I don’t know how to implement your requirement. Maybe somebody else?

1 Like

For the record tried

const e = new KeyboardEvent('keydown',{'keyCode':32,'which':32});
document.dispatchEvent(e);

Maybe should focus a row somehow to make it accept that key event or maybe some other approach, would be like really cool! Thanks :slightly_smiling_face:

1 Like

Hi @Yuliya, here is a javascript script allowing you to open a popup from a button click:

if (typeof modal === 'undefined') {
  var modal = null;
}
if (typeof modalDiv === 'undefined') {
  var modalDiv = null;
}
if (typeof jSuites === 'undefined') {
  var jSuites = {};
}
jSuites.loading = (function() {
    var obj = {};

    var loading = null;

    obj.show = function(timeout) {
        if (! loading) {
            loading = document.createElement('div');
            loading.className = 'jloading';
        }
        document.body.appendChild(loading);

        // Max timeout in seconds
        if (timeout > 0) {
            setTimeout(function() {
                obj.hide();
            }, timeout * 1000)
        }
    }

    obj.hide = function() {
        if (loading && loading.parentNode) {
            document.body.removeChild(loading);
        }
    }

    return obj;
})();

jSuites.modal = (function(el, options) {
    var obj = {};
    obj.options = {};

    // Default configuration
    var defaults = {
        url: null,
        onopen: null,
        onclose: null,
        onload: null,
        closed: false,
        width: null,
        height: null,
        maxWidth: null,
        maxHeight: null,
        title: null,
        padding: null,
        backdrop: true,
        icon: null,
    };

    // Loop through our object
    for (var property in defaults) {
        if (options && options.hasOwnProperty(property)) {
            obj.options[property] = options[property];
        } else {
            obj.options[property] = defaults[property];
        }
    }

    // Title
    if (! obj.options.title && el.getAttribute('title')) {
        obj.options.title = el.getAttribute('title');
    }

    var temp = document.createElement('div');
    while (el.children[0]) {
        temp.appendChild(el.children[0]);
    }

    obj.title = document.createElement('div');
    obj.title.className = 'jmodal_title';
    if (obj.options.icon) {
        obj.title.setAttribute('data-icon', obj.options.icon);
    }

    obj.content = document.createElement('div');
    obj.content.className = 'jmodal_content';
    obj.content.innerHTML = el.innerHTML;

    while (temp.children[0]) {
        obj.content.appendChild(temp.children[0]);
    }

    obj.container = document.createElement('div');
    obj.container.className = 'jmodal';
    obj.container.appendChild(obj.title);
    obj.container.appendChild(obj.content);

    if (obj.options.padding) {
        obj.content.style.padding = obj.options.padding;
    }
    if (obj.options.width) {
        obj.container.style.width = obj.options.width;
    }
    if (obj.options.height) {
        obj.container.style.height = obj.options.height;
    }
    if (obj.options.maxWidth) {
        obj.container.style.maxWidth = obj.options.maxWidth;
    }
    if (obj.options.maxHeight) {
        obj.container.style.maxHeight = obj.options.maxHeight;
    }
    if (obj.options.title) {
        var title = document.createElement('h4');
        title.innerText = obj.options.title;
        obj.title.appendChild(title);
    }

    el.innerHTML = '';
    el.style.display = 'none';
    el.appendChild(obj.container);

    // Backdrop
    if (obj.options.backdrop) {
        var backdrop = document.createElement('div');
        backdrop.className = 'jmodal_backdrop';
        backdrop.onclick = function () {
            obj.close();
        }
        el.appendChild(backdrop);
    }

    obj.open = function() {
        el.style.display = 'block';
        // Fullscreen
        var rect = obj.container.getBoundingClientRect();
        if (jSuites.getWindowWidth() < rect.width) {
            obj.container.style.top = '';
            obj.container.style.left = '';
            obj.container.classList.add('jmodal_fullscreen');
            jSuites.animation.slideBottom(obj.container, 1);
        } else {
            if (obj.options.backdrop) {
                backdrop.style.display = 'block';
            }
        }
        // Event
        if (typeof(obj.options.onopen) == 'function') {
            obj.options.onopen(el, obj);
        }
    }

    obj.resetPosition = function() {
        obj.container.style.top = '';
        obj.container.style.left = '';
    }

    obj.isOpen = function() {
        return el.style.display != 'none' ? true : false;
    }

    obj.close = function() {
        if (obj.isOpen()) {
            el.style.display = 'none';
            if (obj.options.backdrop) {
                // Backdrop
                backdrop.style.display = '';
            }
            // Remove fullscreen class
            obj.container.classList.remove('jmodal_fullscreen');
            // Event
            if (typeof(obj.options.onclose) == 'function') {
                obj.options.onclose(el, obj);
            }
        }
    }

    if (! jSuites.modal.hasEvents) {
        //  Position
        var tracker = null;

        document.addEventListener('keydown', function(e) {
            if (e.which == 27) {
                var modals = document.querySelectorAll('.jmodal');
                for (var i = 0; i < modals.length; i++) {
                    modals[i].parentNode.modal.close();
                }
            }
        });

        document.addEventListener('mouseup', function(e) {
            var item = jSuites.findElement(e.target, 'jmodal');
            if (item) {
                // Get target info
                var rect = item.getBoundingClientRect();

                if (e.changedTouches && e.changedTouches[0]) {
                    var x = e.changedTouches[0].clientX;
                    var y = e.changedTouches[0].clientY;
                } else {
                    var x = e.clientX;
                    var y = e.clientY;
                }

                if (rect.width - (x - rect.left) < 50 && (y - rect.top) < 50) {
                    item.parentNode.modal.close();
                }
            }

            if (tracker) {
                tracker.element.style.cursor = 'auto';
                tracker = null;
            }
        });

        document.addEventListener('mousedown', function(e) {
            var item = jSuites.findElement(e.target, 'jmodal');
            if (item) {
                // Get target info
                var rect = item.getBoundingClientRect();

                if (e.changedTouches && e.changedTouches[0]) {
                    var x = e.changedTouches[0].clientX;
                    var y = e.changedTouches[0].clientY;
                } else {
                    var x = e.clientX;
                    var y = e.clientY;
                }

                if (rect.width - (x - rect.left) < 50 && (y - rect.top) < 50) {
                    // Do nothing
                } else {
                    if (y - rect.top < 50) {
                        if (document.selection) {
                            document.selection.empty();
                        } else if ( window.getSelection ) {
                            window.getSelection().removeAllRanges();
                        }

                        tracker = {
                            left: rect.left,
                            top: rect.top,
                            x: e.clientX,
                            y: e.clientY,
                            width: rect.width,
                            height: rect.height,
                            element: item,
                        }
                    }
                }
            }
        });

        document.addEventListener('mousemove', function(e) {
            if (tracker) {
                e = e || window.event;
                if (e.buttons) {
                    var mouseButton = e.buttons;
                } else if (e.button) {
                    var mouseButton = e.button;
                } else {
                    var mouseButton = e.which;
                }

                if (mouseButton) {
                    tracker.element.style.top = (tracker.top + (e.clientY - tracker.y) + (tracker.height / 2)) + 'px';
                    tracker.element.style.left = (tracker.left + (e.clientX - tracker.x) + (tracker.width / 2)) + 'px';
                    tracker.element.style.cursor = 'move';
                } else {
                    tracker.element.style.cursor = 'auto';
                }
            }
        });

        jSuites.modal.hasEvents = true;
    }

    if (obj.options.url) {
        jSuites.ajax({
            url: obj.options.url,
            method: 'GET',
            dataType: 'text/html',
            success: function(data) {
                obj.content.innerHTML = data;

                if (! obj.options.closed) {
                    obj.open();
                }

                if (typeof(obj.options.onload) === 'function') {
                    obj.options.onload(obj);
                }
            }
        });
    } else {
        if (! obj.options.closed) {
            obj.open();
        }

        if (typeof(obj.options.onload) === 'function') {
            obj.options.onload(obj);
        }
    }

    // Keep object available from the node
    el.modal = obj;

    return obj;
});

jSuites.findElement = function(element, condition) {
    var foundElement = false;

    function path (element) {
        if (element && ! foundElement) {
            if (typeof(condition) == 'function') {
                foundElement = condition(element)
            } else if (typeof(condition) == 'string') {
                if (element.classList && element.classList.contains(condition)) {
                    foundElement = element;
                }
            }
        }

        if (element.parentNode && ! foundElement) {
            path(element.parentNode);
        }
    }

    path(element);

    return foundElement;
}

jSuites.getWindowWidth = function() {
    var w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    x = w.innerWidth || e.clientWidth || g.clientWidth;
    return x;
}

var styles = `
.jmodal .jcolor-content {
    position: fixed;
}

.jmodal {
    position:fixed;
    top:50%;
    left:50%;
    width:60%;
    height:60%;
    -webkit-box-shadow: 0 2px 12px rgba(0,0,0,.2);
    -moz-box-shadow: 0 2px 12px rgba(0,0,0,.2);
    border:1px solid #ccc;
    background-color:#fff;
    transform: translate(-50%, -50%);
    box-sizing: border-box;
    z-index:9002;
    border-radius: 4px;
    display: flex;
    flex-direction: column;
}

.jmodal_title {
    padding: 20px;
    height: 70px;
    box-sizing: border-box;
    font-size: 1.4em;
    background-color: #fff;
    border-radius: 8px 8px 0px 0px;
    pointer-events: none;
    display: flex;
    -webkit-align-items: center;
    -webkit-box-align: center;
    align-items: center;
    border-bottom: 1px solid #eee;
}

.jmodal_title > div {
    font-size: 1.4em;
}

.jmodal_title[data-icon]:before {
    content: attr(data-icon);
    font-family: 'Material Icons' !important;
    width: 24px;
    height: 24px;
    font-size: 24px;
    margin-right: 10px;
    line-height: 24px;
}

.jmodal_content {
    padding: 20px;
    overflow-y: auto;
    height: 100%;
    box-sizing: border-box;
    scrollbar-width: thin;
    scrollbar-color: #333 transparent;
}

.jmodal_title:empty {
    display: none;
}

.jmodal_title:empty + .jmodal_content {
    height: 100%;
}

.jmodal_content::-webkit-scrollbar {
    height: 12px;
}

.jmodal_content::-webkit-scrollbar {
    width: 12px;
}

.jmodal_content::-webkit-scrollbar-track {
    border: 1px solid #fff;
    background: #eee;
}

.jmodal_content::-webkit-scrollbar-thumb {
    border: 1px solid #fff;
    background: #888;
}

.jmodal:after {
    content: '';
    background-image: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2724%27 height=%2724%27 viewBox=%270 0 24 24%27%3E%3Cpath d=%27M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z%27/%3E%3Cpath d=%27M0 0h24v24H0z%27 fill=%27none%27/%3E%3C/svg%3E");
    position: absolute;
    top: 0;
    right: 0;
    margin: 25px;
    font-size: 24px;
    width: 24px;
    height: 24px;
    cursor: pointer;
    text-shadow: 0px 0px 5px #fff;
}

.jmodal_fullscreen {
    width: 100% !important;
    height: 100% !important;
    top: 0px;
    left: 0px;
    transform: none;
    border: 0px;
    border-radius: 0px;
}

.jmodal_backdrop {
    position: fixed;
    top: 0px;
    left: 0px;
    min-width: 100%;
    min-height: 100%;
    background-color: rgba(0,0,0,0.2);
    border: 0px;
    padding: 0px;
    z-index: 8000;
    display: none;

  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}

.jmodal_content .jcalendar .jcalendar-content,
.jmodal_content .jdropdown-container {
    position: fixed;
}
`
if(document.getElementById('myCSS')==null){
    var styleSheet = document.createElement("style")
    styleSheet.id = 'myCSS';
    styleSheet.textContent = styles;
    document.head.appendChild(styleSheet);
}

modalDiv = document.getElementById('basic-modal');
if (modalDiv==null) {
modalDiv = document.createElement("div");
modalDiv.id = "basic-modal";
}
modalDiv.innerHTML="";
const node = document.createTextNode("This is new.");
modalDiv.appendChild(node);
const element = document.getElementById('tables');
element.appendChild(modalDiv);
modal = jSuites.modal(document.getElementById('basic-modal'), {
closed: true,
width: 600,
height: 480
});
modal.open();

It is based on the great Jsuites library and its modal component. I embedded all the JS code needed and the CSS style in the script, which is definitely NOT the cleanest way, but at least it’s working!
Unfortunately I don’t have time to test it farther for now (you’ll see that it just opens a popup containing the “This is new.” TextNode defined on l.494 of the script), but I had two ideas for your needs from that starting point:

  1. Defining in the script a custom HTML display using base.context.currentRow to display the values of the current row (the one that triggered the modal opening).
  2. Create a universal app with one single ‘Single record’ page and format it as you want (don’t forget to hide tool bar to ensure it won’t be possible to navigate through records) . Allow anonymous access to this app and embed it in an iframe in the modal: your universal app page URL should look something like https://MYSERVER/apps/custom/CUSTOMAPPURL/?page_id=PAGEID&record_id=RECORDID so you can make this URL dynamic in the script to embed the current record with something like src="https://MYSERVER/apps/custom/CUSTOMAPPURL/?page_id=PAGEID&record_id="+base.context.currentRow._id (Please note that I DIDN’T TEST the embedding in an iframe, so I’m not sure it will actually work).

Hope this could help you…

Bests,
Benjamin


I love spending time gathering information and explaining solutions to help you solve your problems. I spend… quite a bit of time on it :sweat_smile: .If you feel grateful for the help I’ve given you, please don’t hesitate to support me. I am also available for paid services (scripts, database architecture, custom development, etc.).

2 Likes

That’s kinda scary :slightly_smiling_face:
I didn’t mean to invent the wheel like from scratch entirely, I meant something like

// create a new keyboard event and set the key to "Space"
const event = new KeyboardEvent('keydown', {
  key: 'Space',
  code: 'Space',
  which: 32,
  keyCode: 32,
});

// dispatch the event on our DOM element
document.getElementById('rowID').dispatchEvent(event);

Something

Just happen to solve this: Pass row_id or record_id in the URL

I thought about that at once :slightly_smiling_face: The thing is it opens rather glitchy dialog, like delaying and everything. I thought something more native. When I happen to get at the desktop will investigate the css id formation, who knows, usually it’s like some pattern. At this point I’m still swimming in the sea of docs and enjoying the mind blowing set of features. I got into the developer’s paradise :slightly_smiling_face: