codenautas/backend-plus

View on GitHub
for-client/my-menu.js

Summary

Maintainability
F
6 days
Test Coverage
"use strict";

// require('lazy-some').bindToPrototypeIn(Array);
var changing = require('best-globals').changing;
myOwn.wScreens={}

myOwn.i18n.messages.en=changing(myOwn.i18n.messages.en, {
    chpass:'change password',
    completed:'completed',
    exit:'exit',
    networkSignal1:'network $1',
    offLine:'off line',
    onLine:'on line',
    proceed:'proceed',
    processing:'processing',
    readyToDownload:'ready to download',
    signIn:'sign in',
    speed1:'speed $1',
    user:'user',
    viewProgress:'view progress',
});

myOwn.i18n.messages.es=changing(myOwn.i18n.messages.es, {
    chpass:'cambiar clave',
    completed:'finalizado',
    exit:'salir',
    networkSignal1:'estado de la red: $1',
    offLine:'fuera de línea',
    onLine:'en línea',
    proceed:'proceder',
    processing:'procesando',
    readyToDownload:'listo para descargar',
    signIn:'login',
    speed1:'velocidad $1',
    user:'usuario',
    viewProgress:'procesando',
});

myOwn.wScreens.table = function(addrParams){
    setTimeout(function(){
        var layout = document.getElementById('main_layout');
        var opts={tableDef: addrParams.td ?? {}};
        if(addrParams.ff){
            if(addrParams.ff instanceof Array){
                opts.fixedFields=addrParams.ff;
            }else{
                opts.fixedFields=likeAr(addrParams.ff).map(function(value, key){ return {fieldName:key, value:value}; }).array();
            }
        }
        if(addrParams.fc){
            opts.tableDef.filterColumns=addrParams.fc;
        }
        if(addrParams.pf){
            opts.parameterFunctions=addrParams.pf;
        }
        if(addrParams.detailing){
            opts.detailing=addrParams.detailing;
        }
        if(addrParams.pick){
            opts.pick=addrParams.pick;
        }
        opts.detailingForUrl=opts.detailing||{};
        opts.detailingPath = [];
        var pageTitle = addrParams.label || addrParams.name || addrParams.table || my.config.config.title;
        document.title = pageTitle;
        var grid = my.tableGrid(addrParams.table||addrParams.name,layout, opts);
    },10);
}

myOwn.wScreens.procAux = {
    showParams:function(formDef, main_layout, addrParams, mainAction){
        var autoproced = addrParams.autoproced || false
        addrParams.up=addrParams.up||addrParams.ff||{};
        var params=addrParams.up;
        // var button = html.button(formDef.proceedLabel||my.messages.proceed).create();
        var label = formDef.proceedLabel||my.messages.proceed;
        var refresUrl = formDef.method != 'post' || formDef.autoproced !== false 
        var buttonOptions = {label}
        if (formDef.method == 'post') {
            buttonOptions.onclick = function(event){ event.preventDefault();  proceed(); }
        }
        var button = my.createForkeableButton({}, buttonOptions);
        var setHref = function(){
            if (refresUrl) {
                button.setForkeableHref({
                    ...addrParams, 
                    autoproced:true, 
                    directUrl:true,
                    ...(formDef && formDef.proceedLabel ? {label} : {}),
                    // ...params
                })
            }
        }
        var divResult = html.div({class:formDef.resultClass||'result-pre'}).create();
        var id='progress'+Math.random();
        var toggleProgress = html.input({type:'checkbox', id:id, checked:true, disabled:true}).create();
        var labelProgress = html.label({for:id, id:id+'msg'},my.messages.viewProgress).create();
        // var divToggleProgress = html.div([toggleProgress, labelProgress]).create();
        var divProgress = html.div().create();
        var divProgressOutside = html.div({class:'result-progress', style:'opacity:0'},[toggleProgress,labelProgress,divProgress]).create();
        var controls = [];
        var parameterForm = html.table({class:"table-param-screen"},formDef.parameters.map(function(parameterDef){
            var control = html.td({"typed-controls-direct-input":true}).create();
            control.style.minWidth='200px';
            control.style.backgroundColor='white';
            TypedControls.adaptElement(control,changing({typeName:'text'}, parameterDef));
            const value = parameterDef.name in params ? params[parameterDef.name] : (
                'defaultValue' in parameterDef ? parameterDef.defaultValue : (
                    'specialDefaultValue' in parameterDef ? my.specialDefaultValue[parameterDef.specialDefaultValue](parameterDef.name, {row:{}}, {row:{}}) : (
                        undefined
                    )
                )
            )
            if(parameterDef.references || parameterDef.options){
                setTimeout(()=>control.ponerLupa(true), 500)
                
            }
            if(value!==undefined){
                params[parameterDef.name] = value;
                control.setTypedValue(value);
            }
            control.addEventListener('update', function(){
                params[parameterDef.name] = control.getTypedValue();
                if (refresUrl) { 
                    myOwn.replaceAddrParams(addrParams);
                }   
                setHref();
            });
            controls.push(control);
            return html.tr({"parameter-name":parameterDef.name},[ 
                html.td(parameterDef.label||parameterDef.name.replace(/_/g,' ')),
                control,
                html.td(parameterDef.description||''),
            ]);
        }).concat(
            html.tr([html.td(), html.td([button])])
        ));
        setHref();
        var proceed = function proceed(){
            button.disabled=true;
            divResult.innerHTML="";
            divProgress.innerHTML="";
            divProgressOutside.style.opacity=0.77;
            labelProgress.textContent=my.messages.processing;
            mainAction(params,divResult,divProgress).then(function(resultOk){
                if(formDef.uniqueUse){
                    controls.forEach(function(c){ c.disable(true) });
                    button.style.visibility='hidden'
                }else{
                    button.disabled=false;
                }
                button.disabled=false;
                divProgressOutside.style.opacity=0.33;
                toggleProgress.disabled=false;
                labelProgress.textContent=typeof resultOk == "string" ? resultOk : resultOk !== false ? my.messages.completed : 'error';
            }).catch(function(err){
                my.log(err);
                divProgress.textContent=err.message;
            });
        }
        if(autoproced){
            proceed();
        }else{
            main_layout.appendChild(parameterForm.create());                
        }
        main_layout.appendChild(divResult);
        main_layout.appendChild(divProgressOutside);
    },
    mainAction:function(){
    },
}

myOwn.wScreens.proc = function(addrParams){
    var procDef=my.config.procedures.find(function(proc){
        return proc.action == (addrParams.proc||addrParams.name);
    });
    myOwn.wScreens.procAux.showParams(procDef, main_layout, addrParams, function(params,divResult,divProgress){
        var my_ajax_actionFun = procDef.action.split('/').reduce(function(o, part){ return o[part]; },my.ajax);
        var opts={};
        if(procDef.progress!==false && divProgress){
            opts.divProgress = divProgress;
        }
        return my_ajax_actionFun(params,opts).then(function(result){
            my.wScreens.proc.result[procDef.resultOk](result,divResult);
            return true;
        },function(err){
            my.wScreens.proc.result[procDef.resultErr](err,divResult);
            return false;
        });
    });
}

myOwn.wScreens.proc.result={
    showText:function(result, divResult){
        if(typeof result=="object"){
            var div = document.createElement('div');
            divResult.appendChild(div);
            myOwn.agregar_json(div, result);
        }else{
            divResult.textContent = result;
            divResult.style.backgroundColor = '#9FA';
        }
    },
    showGrid:function(result, divResult){
        myOwn.tableGrid(result.tableName, divResult, result);
    },
    showError:function(err, divResult){
        divResult.textContent = err.message;
        divResult.style.backgroundColor = 'orange';
    },
    showDownloadUrl:function(result, divResult){
        divResult.innerHTML='';
        divResult.appendChild(html.div([
            html.div([my.messages.readyToDownload]),
            ...result.map(r=>html.div([html.a({href:r.url}, r.label || r.url)]))
        ]).create())
    }
}

myOwn.wScreens.path = function(addrParams){
    window.location.href='.'+addrParams.path;
}

myOwn.preDisplayPage = function preDisplayPage(addrParams, wScreen, w){
    var my = this;
    var pageTitle = wScreen.pageTitle || addrParams.pageTitle || addrParams.title || addrParams.name || my.config.config.title;
    document.title = pageTitle;
    main_layout.setAttribute('my_w',w);
}

myOwn.showPage = function showPage(pageDef){
    my.prepareFloating3dots();
    var newHash;
    if(!location.hash){
        newHash=sessionStorage.getItem('backend-plus-hash-redirect');
        sessionStorage.removeItem('backend-plus-hash-redirect');
        if(newHash){
            history.replaceState(null, null, location.origin+location.pathname+location.search+newHash);
        }
    }
    var addrParams=my.UriSearchToObject(location.hash||location.search||newHash||'');
    if(addrParams.i){
        addrParams.i=addrParams.i.split(',');
    }else{
        addrParams.i=[];
    }
    var totalLayout=document.getElementById('total-layout');
    var rightMenu;
    if(totalLayout.getAttribute('menu-type')!='hidden'){
        var menu = my.displayMainMenu(addrParams);
        var w=addrParams.w;
        if(!w){
            if(!addrParams.i.length && addrParams._firstParameterName && my.wScreens[addrParams._firstParameterName]){
                w=addrParams._firstParameterName;
            }else if(menu && menu.selectedItem){
                addrParams = changing(menu.selectedItem, addrParams);
                w=menu.selectedItem.menuType;
            }
        }
        var wScreen;
        if(typeof my.wScreens[w] === 'function'){
            wScreen={
                mainFunction:my.wScreens[w]
            };
        }else if(typeof my.wScreens[w] === 'object'){
            wScreen = my.wScreens[w];
            if(wScreen.parameters){
                wScreen.mainFunction=wScreen.mainFunction||function(addrParams){
                    my.wScreens.procAux.showParams({
                        parameters:wScreen.parameters,
                        resultClass:wScreen.resultClass,
                        proceedLabel:wScreen.proceedLabel,
                    }, main_layout, addrParams, wScreen.mainAction);
                }
            }
        }else{
            wScreen={
                mainFunction:function(){}
            }
        }
        my.preDisplayPage(addrParams, wScreen, w);
        wScreen.mainFunction.call(my, addrParams);
        rightMenu = document.getElementById('right-menu-icon');
    }else{
        rightMenu = html.span({id: "right-menu"}, [
            html.img({class: "right-menu", src: my.path.img+"three-dot-menu.png",id: "right-menu-icon"}),
        ]).create();
        rightMenu.style.position='fixed';
        rightMenu.style.top='0px';
        rightMenu.style.left=window.innerWidth-40+'px';//screen.width-32
        rightMenu.style.zIndex=300;
        totalLayout.appendChild(rightMenu);
    }
    rightMenu.onclick=function(){
        if(!my.offline.mode){
            my.rightMenu();
        }
    }
};

myOwn.getHRef = function getHRef(menu){
    var href;
    if(!menu.w && menu.menuType){
        if(menu.directUrl){
            href = my.menup + my.paramsToUriPart(changing({w:menu.menuType}, changing(menu,{menuType:null, label:null, button:null},changing.options({deletingValue:undefined}))));
        }else{
            href = my.menup + my.paramsToUriPart(changing({i:menu.name},menu),true);
        }
    }else{
        href = my.menup + my.paramsToUriPart(menu);
    }
    return href;
}

myOwn.gotoAddrParams = function gotoAddrParams(addrParams, pushing){
    var href = my.getHRef(addrParams);
    if(pushing){
        history.pushState(null, null, href);
    }else{
        history.replaceState(null, null, href);
    }
    my.showPage();
}

myOwn.createForkeableButton = function createForkeableButton(menu, opts){
    var my = this;
    if(typeof opts==="string" || opts==null){
        opts = {label:opts};
    }
    var label=opts.label;
    var button=html.a({"class": opts["class"]||menu["class"]||"menu-item", "menu-type":menu.menuType||menu.w, "menu-name":menu.name||'noname'}, label || menu.label || menu.name.replace(/_/g,' ')).create();
    button.setForkeableHref = function setForkeableHref(menu){
        button.href = my.getHRef(menu);
    }
    button.setForkeableHref(menu);
    menu.button = button;
    button.disable=function(disable){
        button.setAttribute('bp-is-disabled',disable);
    }
    button.onmousedown=opts.updateHrefBeforeClick||function(){};
    button.onclick=opts.onclick||function(event){
        if(button.getAttribute('bp-is-disabled')=='true'){
            event.preventDefault();
            return;
        }
        /** @type {null|string} */
        var errorText;
        if(opts.preOnClick){
            errorText=opts.preOnClick();
        }
        if(errorText){
            alertPromise(errorText);
        }else{
            if(!event.ctrlKey && event.button!=1){
                /*
                if(button.parentNode.clientSidePrepared){
                    history.replaceState(null, null, )
                }
                */
                history.pushState(null, null, this.href);
                my.showPage();
                event.preventDefault();
            }
        }
    };
    return button;
};

myOwn.light = function light(name, onclick, opts){
    var skin=((this.config||{}).config||{}).skin;
    var skinUrl=(skin?skin+'/':'');
    var attr={class:"light", id:'light-'+name, src:skinUrl+'img/'+name+'.png'};
    if(opts && opts.attr){
        likeAr(opts.attr).forEach(function(value, key){ attr[key]=value; })
    }
    var img = html.img(attr).create();
    img.result={};
    img.onclick=onclick;
    return img;
}

myOwn.displayMenu = function displayMenu(layout, menu, addrParams, parents){
    var my = this;
    var selectedItem = null;
    var elements=[];
    var depth = parents.length;
    var skin=((this.config||{}).config||{}).skin;
    var skinUrl=(skin?skin+'/':'');
    if(depth===0){
        elements.push(html.img({id: "main-logo", src: skinUrl+"img/logo.png"}));
    }
    var myMenu = my.offline.mode?menu.filter(function(menuItem){return menuItem.showInOfflineMode === true;}):menu;
    elements = elements.concat(myMenu.map(function(menuItem){
        menuItem.parents = parents;
        var wScreen=my.wScreens[menuItem.menuType]||{}
        var opts={}
        if(wScreen.getMenuLabel){
            opts.label=wScreen.getMenuLabel();
        }
        var button = my.createForkeableButton(menuItem, opts);
        if(menuItem.visible === false){
            button.style = 'display:none'
        }
        if(menuItem.name == addrParams.i[depth] || !addrParams.i[depth] && menuItem.selectedByDefault){
            button.setAttribute('menu-selected', 'yes');
            selectedItem = menuItem;
        }
        return button;
    }))
    if(depth===0){
        elements.push(html.img({src: skinUrl+"img/three-dot-menu.png",id: "right-menu-icon"}));
        elements.push(html.span({id: "active-user"}, my.config.username||"user"));
        var loginElement=html.a({id: "not-logged", href:'login'}, my.messages.signIn).create();
        loginElement.onclick=function(){
            this.href='login'+window.location.hash;
        };
        elements.push(loginElement);
        var status=html.span({id: "mini-console"}).create();
        status.addEventListener('click',function(){
            var mensajeDiv=document.createElement('div');
            mensajeDiv.innerHTML=status.innerHTML;
            alertPromise(mensajeDiv,{underElement:status, withCloseButton:true, mainAttrs:{style:'white-space:pre'}});
        });
        elements.push(html.span({class:'right-lights'},[
            my.light('server', function(){
                alertPromise(
                    my.messages.speed1.replace('$1',this.result.speed),
                    {underElement:this}
                );
            }),
            my.light('network-signal', function(){
                alertPromise(
                    my.messages.networkSignal1.replace('$1',this.result.status),
                    {underElement:this}
                );
            }),
            my.light('airplane', function(){
                if(my.ldb && my.offline){
                    if(my.offline.mode && !my.server.connected){
                        promptPromise("Si desea salir del modo avión puede forzarlo").then(function(texto){
                            if (texto == 'forzar') {
                                my.changeOfflineMode();
                            }
                        });
                    }else{
                        my.changeOfflineMode();
                    }
                }
            }, {hidden:true})
        ]));
        elements.push(status);
    }
    var spanElements=html.span(elements).create();
    var menuLine=html.div({id: "main-top-bar"+(depth||''), class: depth?"sub-menu-bar":"top-menu-bar"}, spanElements).create();
    layout.appendChild(menuLine);
    var innerSelectedItem = selectedItem;
    if(selectedItem && selectedItem.menuType === 'menu'){
        var subMenu = my.displayMenu(layout, selectedItem.menuContent, addrParams, parents.concat(selectedItem.name));
        var realign = function(){
            var div=html.div({style:'position:absolute; left:0; top:0; visibility:x-hidden'}).create();
            div.innerHTML=subMenu.spanElements.outerHTML;
            subMenu.spanElements.parentNode.appendChild(div);
            var theWidth=subMenu.spanElements.offsetWidth;
            theWidth=div.childNodes[0].offsetWidth||theWidth;
            subMenu.spanElements.parentNode.removeChild(div);
            var oneLimit=Math.max(1,layout.offsetWidth-theWidth-32);
            if(oneLimit<theWidth){
                subMenu.menuLine.style.textAlign = 'right';
                subMenu.menuLine.style.paddingLeft = null;
            }else{
                subMenu.menuLine.style.textAlign = 'left';
                subMenu.menuLine.style.paddingLeft = Math.min(selectedItem.button.offsetLeft, oneLimit) + 'px';
            }
        };
        innerSelectedItem = subMenu.selectedItem;
    }
    return {menuLine: menuLine, selectedItem: innerSelectedItem, realigns:(subMenu?subMenu.realigns:[]).concat(realign), spanElements:spanElements};
};

myOwn.displayMainMenu = function(addrParams){
    if(window.currentAutofrefresh){
        console.log("borro currentAutoRefresh")
        clearInterval(window.currentAutofrefresh);
        window.currentAutofrefresh=null;
    }
    var my = this;
    var totalLayout=document.getElementById('total-layout');
    totalLayout.innerHTML='';
    var menu = my.displayMenu(totalLayout,my.config.menu,addrParams,[]);
    totalLayout.appendChild(html.div({id:'main_layout'}).create());
    my.doMenuRealigns=function(){
        menu.realigns.reverse().forEach(function(realign){ if(realign){ realign(); }});
        var mtv = document.getElementById('main-top-bar');
        if(mtv){
            if(location.href.match(/^.{0,8}localhost/)){
                mtv.style.backgroundImage='repeating-linear-gradient(-45deg, #FF8, #FF8 8px, #DDD 8px, #DDD 16px)'
                mtv.title = 'Warning! Using system in localhost!'
            }
        }
    }
    setTimeout(my.doMenuRealigns,10);
    setTimeout(function(){
        my.offlineModeRefresh();
    },10);
    return menu;
};

myOwn.rigthMenuDoneFunLocation = function rigthMenuDoneFunLocation(newLocation){
    return function(){
        window.location.href = newLocation;
        return null;
    };
};

myOwn.rightMenuOpts = function rightMenuOpts(){
    return [
        // {label:my.messages.user, startGroud:'true'},
        {id:'right-menu-chpass', img:my.path.img+'chpass.png', label:my.messages.chpass, doneFun:my.rigthMenuDoneFunLocation('chpass')},
    ]
};

myOwn.rightMenu = function rightMenu(){
    return miniMenuPromise(my.rightMenuOpts().concat(
        {img:my.path.img+'exit.png'  , label:my.messages.exit  , doneFun:my.rigthMenuDoneFunLocation('logout')}
    ),{
        underElement:document.getElementById('right-menu-icon'),
        withCloseButton:false,
    });
};

myOwn.informDetectedStatus = function informDetectedStatus(statusCode, logged) {
    var my=this;
    if(my.debuggingStatus){ my.debuggingStatus(statusCode); }
    var status = my["connection-status"][statusCode];
    if(status.id){
        var light = document.getElementById(status.id);
        light.src = my.path.img+status.img+'.png';
        light.title = statusCode;
    }
    if(statusCode==='notLogged'){
        var notLogged = document.getElementById('not-logged');
        notLogged.style.display='inherit';
        var activeUser = document.getElementById('active-user');
        activeUser.style.display='none';
    }
}

myOwn.setOnlineOfflineUrl = function setOnlineOfflineUrl(){
    var actualHref=location.href;
    var hrefSplit = actualHref.split(my.menuSeparator)
    var newHref = my.offline.mode?'ext':my.menuName;
    newHref = (hrefSplit.length > 1)?newHref+my.menuSeparator+hrefSplit[1]:newHref;
    history.pushState(null, null, newHref);
}

myOwn.offlineModeRefresh = function offlineModeRefresh(){
    var my=this;
    /** @type {HTMLImageElement} */
    // @ts-ignore
    var imgLight = document.getElementById('light-airplane');
    var skin=((my.config||{}).config||{}).skin;
    if(my.offline.mode){
        imgLight.src=my.path.img+'airplane-on.png';
    }else{
        imgLight.src=my.path.img+'airplane-off.png';
    }
}

myOwn.changeOfflineMode = function changeOfflineMode(){
    my.offline.mode=!my.offline.mode;
    my.offlineModeRefresh();
    my.setOnlineOfflineUrl();
    if(my.offline.mode){
        var fkToStoreData = [];
        var promiseArray1 = [];
        var promiseChain = my.ldb.getAllStructures().then(function(tablesDef){
            tablesDef.forEach(function(tableDef){
                promiseArray1.push(
                    my.ldb.isEmpty(tableDef.name).then(function(isEmpty){
                        if(!isEmpty){
                            var fkToStoreSearch = tableDef.foreignKeys.filter(function(fk){
                                return fk.fields.find(function(field){
                                    return !tableDef.primaryKey.includes(field.source)
                                })
                            });
                            fkToStoreData = fkToStoreData.concat(fkToStoreSearch);
                        }
                    })
                );
            });
        });
        var promiseArray2 = [];
        promiseChain = promiseChain.then(function(){
            return Promise.all(promiseArray1).then(function(){
                return fkToStoreData.forEach(function(fk){
                    var conn = new my.TableConnector({tableName: fk.references, my:my});
                    var opts = { registerInLocalDB: false };
                    conn.getStructure(opts)
                    promiseArray2.push(
                        Promise.resolve().then(function(){
                            return conn.getData().then(function(rows){
                                return my.ldb.putMany(fk.references, rows)
                            })
                        })
                    );
                });
            });
        });
        promiseChain = promiseChain.then(function(){
            Promise.all(promiseArray2).then(function(){
                location.reload();
            })
        });
    }else{
        my.showPage();
        location.reload();
    }
}

window.addEventListener('popstate', function(){
    if(!my.config){
        my.autoSetup().then(function(){
            my.setOnlineOfflineUrl();
            my.showPage();
        })
    }else{
        my.showPage();
    }
});

window.addEventListener('load', function(){
    window.my = myOwn;
    my.autoSetup().then(function(){
        my.setOnlineOfflineUrl();
        my.showPage();
    })
    document.body.appendChild(html.div({id:'cached-images'},[
        html.img({src:my.path.img+'airplane-on.png'}),
        html.img({src:my.path.img+'airplane-off.png'}),
        html.img({src:my.path.img+'airplane.png'}),
        html.img({src:my.path.img+'server.png'}),
        html.img({src:my.path.img+'network-signal.png'}),
        html.img({src:my.path.img+'server-error.png'}),
        html.img({src:my.path.img+'network-no-signal.png'}),
    ]).create());
    window.addEventListener('resize', function(){
        if(my.doMenuRealigns){
            my.doMenuRealigns();
        }
    })
});

function updateOnlineStatus(){
    if(window.my){
        var networkLight=document.getElementById('light-network-signal');
        var skin=((my.config||{}).config||{}).skin;
        if(networkLight){
            if(window.navigator.onLine){
                networkLight.src=my.path.img+'network-signal-ok.png';
                networkLight.result.status=my.messages.onLine;
            }else{
                networkLight.src=my.path.img+'network-no-signal.png';
                networkLight.result.status=my.messages.offLine;
            }
        }
    }
}

window.addEventListener('online',  updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);

myOwn.messages=myOwn.i18n.messages.en;