Welcome to the nuBuilder Forums!

Register and log in to access exclusive forums and content available only to registered users.

Responsive edit form idea

Post your ideas & suggestions for new nuBuilder features or other improvements
nc07
Posts: 118
Joined: Tue Jun 04, 2019 4:05 am
Has thanked: 5 times
Been thanked: 22 times

Responsive edit form idea

Unread post by nc07 »

Hi all,
This is just an idea and maybe helpful to someone who may want to use this code for viewing on smaller screens. Some code is taken from NB itself.
Note that this is not the optimal way to make form responsive and this code has some flows as some objects such as select2 are not respected.
chrome-capture (3).gif
This code should be placed in the header

Code: Select all

function editResp(){
if(nuFormType() == 'edit'){

	columns = 1;

	$('.nuPortraitTab').remove();

	var o = nuSERVERRESPONSE.objects;
	var lw = columns == 1 ? 0 : nuPortraitLabelWidth(o);
	var t = 10;
	var b = -1;
	var W = 0;

	for(var i = 0 ; i < o.length ; i++){

		var I = o[i].id;
		var L = $('#label_' + I).length == 0 ? 0 : $('#label_' + I).outerHeight();
		var O = $('#' + I).outerHeight();

		W= ('85vw');
		if(o[i].tab != b){
			b = o[i].tab;
			
			var l = $('#nuTab' + o[i].tab).html();
			
			var d = '<div class="nuPortraitTab" id="nuPort' + b + '" style="top:' + t + 'px" >'+ l +'</div>';
			$('#nuRECORD').append(d);
			var OH = $('#nuPort' + b ).outerHeight();
            
			t = t + OH + 20;

		}

		if(o[i].read != 2){
           
         
			$('#label_' + o[i].id).css({'top' : t+2 , 'left' : 7, 'text-align' : 'left', 'font-weight' : 700});

			if(columns == 1){
				t = t + L + 5;
			}

			$('#'+o[i].id).css({'top' : t , 'left' : lw + 10, 'width':'90vw'});

			if(o[i].type == 'lookup'){

				var w = $('#'+o[i].id+'code').outerWidth();
				var dis = $('#'+o[i].id+'description').outerWidth();
				W	= Math.max(W, w + dis + 30);
                 var wi =$(this).width();
				$('#'+o[i].id+'code').css({'top' : t , 'width':wi/2, 'left' : lw + 10});
				$('#'+o[i].id+'button').css({'top' : t , 'left' : lw + w + 15});
				// t = t + 25;
				$('#'+o[i].id+'description').css({'top' : t, 'left' : lw +w+ 35});

			}

			t = t + O + 5;

		}

	}

	$("[data-nu-tab!='x'][data-nu-form='']:not([data-nu-lookup-id])").show();
 	$('#nuTabHolder').hide();
 	t		= t + 50;

 	$('#nuRECORD').append('<div id="nuPortEnd" style="left:0px;position:absolute;top:' + t + 'px" >&nbsp;</div>');

	if(columns == 1){
		$('label').css('text-align', 'right').css({'width':W,'text-align':'left','left':15,'border':'1px red'});
	}else{
		$('label').css('text-align', 'left').css('width', lw);
	}

	var objectWidth = W + lw + 50;
	var screenWidth = window.innerWidth;
	var scale		= screenWidth/(objectWidth);

	$('#nubody').css('width', objectWidth)
				.css('transform', 'scale(' + scale + ')');
	$('html,body').scrollTop(0).scrollLeft(0);

}
}

function nonresp(){
    
var o = nuSERVERRESPONSE.objects;

	var t = 10;
	var b = -1;
	var W = 0;

	for(var i = 0 ; i < o.length ; i++){

		var I = o[i].id;
		var L = $('#label_' + I).outerHeight();
		var LW = $('#label_' + I).outerWidth();
		var wi = $('#' + I).outerWidth();
		var O = $('#' + I).outerHeight();
		var d = $('#'+o[i].id+'button').outerWidth();
		var w = Number(o[i].width);
		var T = Number(o[i].top);
		var lft = Number(o[i].left);
		
		t = t+L+20;

		$('#'+o[i].id).css({'top' : T, 'width':w, 'left':lft});
		$('#label_'+o[i].id).css({'top' : T , 'left':lft-w-5,'width':w, 'text-align':'right'});
		$('#'+o[i].id+'code').css({'top' : T , 'width':w,'left' : lft});
        $('#'+o[i].id+'button').css({'top' : T ,'left' : lft+w+5});
		$('#'+o[i].id+'description').css({'top' : T, 'left' :lft+w+d+10});
 	    $('#nuTabHolder').show();
 	    $('.nuPortraitTab').remove();
}
}
the following code should only be placed in forms custom js that you want to be responsive.

Code: Select all

$(document).ready(function(){
  if(nuFormType() == 'edit'){ 
      
  if ($(window).width() < 700) {
  editResp();            
  }
$(window).resize(function() {
 clearTimeout(window.resizedFinished);
    window.resizedFinished = setTimeout(function(){
          if ($(this).width() <700){
            editResp();  
            
          }else {
          
                  nonresp();
                
                  }
    }, 50);
});
}
});
Suggetions and comments are welcomed for improvements.
You do not have the required permissions to view the files attached to this post.
kev1n
nuBuilder Team
Posts: 4292
Joined: Sun Oct 14, 2018 6:43 pm
Has thanked: 71 times
Been thanked: 444 times
Contact:

Re: Responsive edit form idea

Unread post by kev1n »

Hi,

Good job! Maybe the ContentBox should be excluded.
the following code should only be placed in forms custom js that you want to be responsive.
I placed it in one form, then switched to another form. The resize code is also executed for that form.
nc07
Posts: 118
Joined: Tue Jun 04, 2019 4:05 am
Has thanked: 5 times
Been thanked: 22 times

Re: Responsive edit form idea

Unread post by nc07 »

kev1n wrote: Wed Mar 23, 2022 2:47 pm Hi,

Good job! Maybe the ContentBox should be excluded.
the following code should only be placed in forms custom js that you want to be responsive.
I placed it in one form, then switched to another form. The resize code is also executed for that form.
Thanks Kevin, I agree that the ContentBox should be excluded.

I have also noticed that resize code is also executed for other forms, still trying to figure out why?. Still working on updates and other possibilities.
kev1n
nuBuilder Team
Posts: 4292
Joined: Sun Oct 14, 2018 6:43 pm
Has thanked: 71 times
Been thanked: 444 times
Contact:

Re: Responsive edit form idea

Unread post by kev1n »

If you change nuResize() in index.php to this (or pull index.php from Github)

Code: Select all

	function nuResize(){

		if(typeof window['nuOnBeforeResize'] === 'function'){
			if (nuOnBeforeResize() == false) return;
		}

		$('#nuActionHolder').css('width', '100%');
		$('#nuBreadcrumbHolder').css('width', '100%');
		$('#nuTabHolder').css('width', '100%');
		$('.nuTabTitleColumn').css('width', '100%');
		$('body').css('width', '100%');

		if (window.nuVerticalTabs) {
			nuSetVerticalTabs();
		}

		if(typeof window['nuOnResize'] === 'function'){
			nuOnResize();
		}

	}
nuOnResize() is fired on resize.

Then this (untested) code can be used in the header:


Code: Select all

function isResponsive() {
	var f = window.nuFORM.getProperty('form_id');
	return f.containsAny(['5ac14228beed98e', 		// form A
					      '5aac833a3d8c0db'])      // form B
					   
}  

function nuOnResize() {

	 if (isResponsive()) {   

		clearTimeout(window.resizedFinished);
		window.resizedFinished = setTimeout(function() {
			if ($(this).width() < 700) {
				editResp();
			} else {
				nonresp();
			}
		}, 50);

	}

}

 function nuOnLoad() {

    if (nuFormType() == 'edit') {
        // Edit Form loaded
		$(document).ready(function(){
			 if (isResponsive()) {   
				if ($(window).width() < 700) {
					editResp();            
				}
			 }
		 });
    } 

}
nc07
Posts: 118
Joined: Tue Jun 04, 2019 4:05 am
Has thanked: 5 times
Been thanked: 22 times

Re: Responsive edit form idea

Unread post by nc07 »

Thanks, Kevin, The idea of passing form ID as the solution to the execution of responsive code to specific forms only works well. And now code works when only place in the header. Probably we can have some ideas/suggestions from the forum on improvements to give end-users a better experience on smaller screens.
kev1n
nuBuilder Team
Posts: 4292
Joined: Sun Oct 14, 2018 6:43 pm
Has thanked: 71 times
Been thanked: 444 times
Contact:

Re: Responsive edit form idea

Unread post by kev1n »

I combined your editResp() and nonresp() into a function nuSetResponsive(active).
Calling nuSetResponsive() or nuSetResponsive(true) will make the form responsive, nuSetResponsive(false) will set it back to non-responsive.

Now instead of

Code: Select all

if ($(this).width() < 700) {
	editResp();
} else {
	nonresp();
}
we can replace it with

Code: Select all

nuSetResponsive($(this).width() < 700);
I also removed some unused variables and renamed some to give them some more meaningful names (there's still some that could be renamed).

Updated code:

Code: Select all

function nuSetResponsive(active) {

    if (nuFormType() !== 'edit') return;

    var o = nuSERVERRESPONSE.objects;
    $('.nuPortraitTab').remove();

    // Set non-responsive
    if (active === false) {
        let top = 10;

        for (let i = 0; i < o.length; i++) {

            let id = o[i].id;
            let loh = $('#label_' + id).outerHeight();
            let w = Number(o[i].width);
            let t = Number(o[i].top);
            let l = Number(o[i].left);

            top = top + loh + 20;

            $('#' + o[i].id).css({ 'top': t, 'width': w, 'left': l });
            $('#label_' + o[i].id).css({ 'top': t, 'left': l - w - 5, 'width': w, 'text-align': 'right' });
            $('#' + o[i].id + 'code').css({ 'top': t, 'width': w, 'left': l });
            $('#' + o[i].id + 'button').css({ 'top': t, 'left': l + w + 5 });
            $('#' + o[i].id + 'description').css({ 'top': t, 'left': l + w + d + 10 });
            $('#nuTabHolder').show();

        }

        return;

    }

    // Set responsive
    columns = 2;

    var lw = columns == 1 ? 0 : nuPortraitLabelWidth(o);
    var t = 10;
    var b = -1;
    var W = 0;

    for (var i = 0; i < o.length; i++) {

        var I = o[i].id;
        var O = $('#' + I).outerHeight();

        W = ('85vw');
        if (o[i].tab != b) {
            b = o[i].tab;

            var l = $('#nuTab' + o[i].tab).html();

            var d = '<div class="nuPortraitTab" id="nuPort' + b + '" style="top:' + t + 'px" >' + l + '</div>';
            $('#nuRECORD').append(d);
            var OH = $('#nuPort' + b).outerHeight();

            t = t + OH + 20;

        }

        if (o[i].read != 2) {


            $('#label_' + o[i].id).css({ 'top': t + 2, 'left': 7, 'text-align': 'left', 'font-weight': 700 });

            if (columns == 1) {
                let L = $('#label_' + I).length == 0 ? 0 : $('#label_' + I).outerHeight();
                t = t + L + 5;
            }

            $('#' + o[i].id).css({ 'top': t, 'left': lw + 10, 'width': '90vw' });

            if (o[i].type == 'lookup') {

                var w = $('#' + o[i].id + 'code').outerWidth();
                var dis = $('#' + o[i].id + 'description').outerWidth();
                W = Math.max(W, w + dis + 30);
                var wi = $(this).width();
                $('#' + o[i].id + 'code').css({ 'top': t, 'width': wi / 2, 'left': lw + 10 });
                $('#' + o[i].id + 'button').css({ 'top': t, 'left': lw + w + 15 });
                // t = t + 25;
                $('#' + o[i].id + 'description').css({ 'top': t, 'left': lw + w + 35 });

            }

            t = t + O + 5;

        }

    }

    $("[data-nu-tab!='x'][data-nu-form='']:not([data-nu-lookup-id])").show();
    $('#nuTabHolder').hide();
    t = t + 50;

    $('#nuRECORD').append('<div id="nuPortEnd" style="left:0px;position:absolute;top:' + t + 'px" >&nbsp;</div>');

    if (columns == 1) {
        $('label').css({ 'width': W, 'text-align': 'left', 'left': 15, 'border': '1px red' });
    } else {
        $('label').css('text-align', 'left').css('width', lw);
    }

    var objectWidth = W + lw + 50;
    var screenWidth = window.innerWidth;
    var scale = screenWidth / (objectWidth);

    $('#nubody').css('width', objectWidth)
        .css('transform', 'scale(' + scale + ')');
    $('html,body').scrollTop(0).scrollLeft(0);


}


function isResponsive() {

    var f = window.nuFORM.getProperty('form_id');
    return f.containsAny(['5ac14228beed98e', // form A
					      '5aac833a3d8c0db']) // form B

}

function nuOnResize() {

    if (isResponsive()) {

        clearTimeout(window.resizedFinished);
        window.resizedFinished = setTimeout(function() {
            nuSetResponsive($(this).width() < 700);
        }, 50);

    }

}

function nuOnLoad() {

    if (nuFormType() == 'edit') {

        $(document).ready(function() {
            if (isResponsive()) {
                if ($(window).width() < 700) {
                    editResp();
                }
            }
        });
    }

}

An idea I had was to pass a callback function to nuSetResponsive() that is called for every object, before an element's position is set.
In this way a user gets more control when entering the responsive mode: E.g. by hiding certain objects or by setting different dimensions or other positions for objects.
nc07
Posts: 118
Joined: Tue Jun 04, 2019 4:05 am
Has thanked: 5 times
Been thanked: 22 times

Re: Responsive edit form idea

Unread post by nc07 »

the combined version of the code looks much better, one thing i have noticed is that the labels now remain to the left of the field and not on top.

the onload function

Code: Select all

function nuOnLoad() {

    if (nuFormType() == 'edit') {

        $(document).ready(function() {
            if (isResponsive()) {
                if ($(window).width() < 700) {
                    editResp();
                }
            }
        });
    }

}
did not call the responsive function thus should be

Code: Select all

function nuOnLoad() {

    if (nuFormType() == 'edit') {

        $(document).ready(function() {
            if (isResponsive()) {
                if ($(window).width() < 700) {
                    //editResp();
                     nuSetResponsive(true);
                }
            }
        });
    }

}
Also this variable is needed in nonresponsive code block to reset lookup code decription

Code: Select all

var d = $('#'+o[i].id+'button').outerWidth();


I agree with the idea to include callback function because currently all fields via js are shown on ofcouse the developers/users should have controls.
nc07
Posts: 118
Joined: Tue Jun 04, 2019 4:05 am
Has thanked: 5 times
Been thanked: 22 times

Re: Responsive edit form idea

Unread post by nc07 »

a few changes with label issue solved.

Code: Select all

function nuSetResponsive(active) {

    if (nuFormType() !== 'edit') return;

    var o = nuSERVERRESPONSE.objects;
    $('.nuPortraitTab').remove();

    // Set non-responsive
    if (active === false) {
        let top = 10;

        for (let i = 0; i < o.length; i++) {

            let id = o[i].id;
            let loh = $('#label_' + id).outerHeight();
            let d = $('#'+o[i].id+'button').outerWidth();
            let w = Number(o[i].width);
            let t = Number(o[i].top);
            let l = Number(o[i].left);

            top = top + loh + 20;

            $('#' + o[i].id).css({ 'top': t, 'width': w, 'left': l });
            $('#label_' + o[i].id).css({ 'top': t, 'left': l - w - 5, 'width': w, 'text-align': 'right' });
            $('#' + o[i].id + 'code').css({ 'top': t, 'width': w, 'left': l });
            $('#' + o[i].id + 'button').css({ 'top': t, 'left': l + w + 5 });
            $('#' + o[i].id + 'description').css({ 'top': t, 'left': l + w + d + 10 });
            $('#nuTabHolder').show();

        }

        return;

    }

    // Set responsive
    columns = 1;

  var lw = columns == 1 ? 0 : nuPortraitLabelWidth(o);
	var t = 10;
	var b = -1;
	var W = 0;

	for(var i = 0 ; i < o.length ; i++){

		var I = o[i].id;
		let L = $('#label_' + I).length == 0 ? 0 : $('#label_' + I).outerHeight();
		var O = $('#' + I).outerHeight();

		W= ('85vw');
		if(o[i].tab != b){
			b = o[i].tab;
			
			var l = $('#nuTab' + o[i].tab).html();
			
			var d = '<div class="nuPortraitTab" id="nuPort' + b + '" style="top:' + t + 'px" >'+ l +'</div>';
			$('#nuRECORD').append(d);
			var OH = $('#nuPort' + b ).outerHeight();
            
			t = t + OH + 20;

		}

		if(o[i].read != 2){
           
         
			$('#label_' + o[i].id).css({'top' : t+2 , 'left' : 7, 'text-align' : 'left', 'font-weight' : 700});

			if(columns == 1){
				t = t + L + 5;
			}

			$('#'+o[i].id).css({'top' : t , 'left' : lw + 10, 'width':'90vw'});

			if(o[i].type == 'lookup'){

				var cw = $('#'+o[i].id+'code').outerWidth();
				var dis = $('#'+o[i].id+'description').outerWidth();
				W	= Math.max(W, cw + dis + 30);
                 var wi =$(this).width();
                 $('#'+o[i].id+'code').css({'top' : t , 'width':wi/2, 'left' : lw + 10});
				$('#'+o[i].id+'button').css({'top' : t , 'left' : lw + cw + 15});
				$('#'+o[i].id+'description').css({'top' : t, 'left' : lw +cw+ 35});

			}

			t = t + O + 5;

		}

	}

	$("[data-nu-tab!='x'][data-nu-form='']:not([data-nu-lookup-id])").show();
 	$('#nuTabHolder').hide();
 	t		= t + 50;

 	$('#nuRECORD').append('<div id="nuPortEnd" style="left:0px;position:absolute;top:' + t + 'px" >&nbsp;</div>');

	if(columns == 1){
		$('label').css('text-align', 'right').css({'width':W,'text-align':'left','left':15,'border':'1px red'});
	}else{
		$('label').css('text-align', 'left').css('width', lw);
	}

	var objectWidth = W + lw + 50;
	var screenWidth = window.innerWidth;
	var scale		= screenWidth/(objectWidth);

	$('#nubody').css('width', objectWidth)
				.css('transform', 'scale(' + scale + ')');
	$('html,body').scrollTop(0).scrollLeft(0);

}


function isResponsive() {

    var f = window.nuFORM.getProperty('form_id');
    return f.containsAny(['621fdb9842fea17', // form A
					      '6233976caaea6ec']); // form B

}

function nuOnResize() {

    if (isResponsive()) {

        clearTimeout(window.resizedFinished);
        window.resizedFinished = setTimeout(function() {
            nuSetResponsive($(this).width() < 700);
        }, 50);

    }

}

function nuOnLoad() {

    if (nuFormType() == 'edit')  {
        

        $(document).ready(function() {
           
            if (isResponsive()) {
                if ($(window).width() < 700) {
                    //editResp();
                     nuSetResponsive(true);
                }
            }
           
        });
        
    }

}
kev1n
nuBuilder Team
Posts: 4292
Joined: Sun Oct 14, 2018 6:43 pm
Has thanked: 71 times
Been thanked: 444 times
Contact:

Re: Responsive edit form idea

Unread post by kev1n »

Code further improved:

- Hides contentbox in responsive mode
- Fixed lookup overlappings
- Changes a few variable names for better readability

Code: Select all

function nuSetResponsive(active) {

    if (nuFormType() !== 'edit') return;

    var o = nuSERVERRESPONSE.objects;
    $('.nuPortraitTab').remove();

    // Set non-responsive
    if (active === false) {

        let top = 10;

        for (let i = 0; i < o.length; i++) {

            let id = o[i].id;
            let lOh = $('#label_' + id).outerHeight();
            let bOh = $('#' + o[i].id + 'button').outerWidth();
            let w = Number(o[i].width);
            let t = Number(o[i].top);
            let l = Number(o[i].left);

            top = top + lOh + 20;

            $('#' + id).css({ 'top': t, 'width': w, 'left': l });
            $('#label_' + o[i].id).css({ 'top': t, 'left': l - w - 5, 'width': w, 'text-align': 'right' });

            $('#' + id + 'code').css({ 'top': t, 'width': w, 'left': l });
            $('#' + id + 'button').css({ 'top': t, 'left': l + w + 5 });
            $('#' + id + 'description').css({ 'top': t, 'left': l + w + bOh + 10 });
            nuSetLabelText(id, $('#label_' + o[i].id).html(), true);

        }

		$('#nuTabHolder').show();

    } else {

        // Set responsive

        columns = 1;

        var lw = columns == 1 ? 0 : nuPortraitLabelWidth(o);
        var t = 10;
        var b = -1;
        var W = 0;

        for (var i = 0; i < o.length; i++) {

            var id = o[i].id;

            W = ('85vw');
            if (o[i].tab != b) {
                b = o[i].tab;

                var l = $('#nuTab' + o[i].tab).html();

                var d = '<div class="nuPortraitTab" id="nuPort' + b + '" style="top:' + t + 'px" >' + l + '</div>';
                $('#nuRECORD').append(d);
                var OH = $('#nuPort' + b).outerHeight();

                t = t + OH + 20;

            }

            if (o[i].read != 2) {

                let oType = o[i].type;

                if (oType == 'contentbox') {
                    nuHide(id);
                } else {

                    $('#label_' + id).css({ 'top': t + 2, 'left': 7, 'text-align': 'left', 'font-weight': 700 });

                    if (columns == 1) {
                        let oh = $('#label_' + id).length == 0 ? 0 : $('#label_' + id).outerHeight();
                        t = t + oh + 5;
                    }

                    $('#' + id).css({ 'top': t, 'left': lw + 10, 'width': '90vw' });

                    if (oType == 'lookup') {

                        let cw = $('#' + id + 'code').outerWidth();
                        let dis = $('#' + id + 'description').outerWidth();

                        W = Math.max(W, cw + dis + 30);

                        let wi = $(this).width();
                        $('#' + id + 'code').css({ 'top': t, 'width': wi / 3, 'left': lw + 10 });
                        $('#' + id + 'button').css({ 'top': t, 'left': lw + wi / 3 + 15 });
                        $('#' + id + 'description').css({ 'top': t, 'left': lw + wi / 3 + 35 });

                    }

                    let oh = $('#' + id).outerHeight();
                    t = t + oh + 5;

                }

            }

        }

        // is this line necessary?
        //		$("[data-nu-tab!='x'][data-nu-form='']:not([data-nu-lookup-id])").show();

        $('#nuTabHolder').hide();

        t = t + 50;
        $('#nuRECORD').append('<div id="nuPortEnd" style="left:0px;position:absolute;top:' + t + 'px" >&nbsp;</div>');

        if (columns == 1) {
            $('label').css('text-align', 'right').css({ 'width': W, 'text-align': 'left', 'left': 15, 'border': '1px red' });
        } else {
            $('label').css('text-align', 'left').css('width', lw);
        }

        var objectWidth = W + lw + 50;
        var screenWidth = window.innerWidth;
        var scale = screenWidth / (objectWidth);

        $('#nubody').css('width', objectWidth)
            .css('transform', 'scale(' + scale + ')');
        $('html,body').scrollTop(0).scrollLeft(0);

    }

}


function isResponsive() {

    var f = window.nuFORM.getProperty('form_id');
    return f.containsAny(['621fdb9842fea17', // form A
					      '6233976caaea6ec']); // form B

}

function nuOnResize() {

    if (isResponsive()) {

        clearTimeout(window.resizedFinished);
        window.resizedFinished = setTimeout(function() {
            nuSetResponsive($(this).width() < 700);
        }, 50);

    }

}

function nuOnLoad() {

    if (nuFormType() == 'edit') {

        $(document).ready(function() {

            if (isResponsive()) {
                if ($(window).width() < 700) {
                    //editResp();
                    nuSetResponsive(true);
                }
            }

        });

    }

}

nc07
Posts: 118
Joined: Tue Jun 04, 2019 4:05 am
Has thanked: 5 times
Been thanked: 22 times

Re: Responsive edit form idea

Unread post by nc07 »

The latest code solved most of the issues. I think file objects should also be excluded. Also, there are overlapping of labels on Checkbox and auto numbers when in nonresponsive mode. i will have a further look soon.
Post Reply