(function() { // Get application context var app = Sammy.apps['#main']; var store = app.store; /** * Helpers * */ app.helpers({ // Serialize an object serialize : function(obj) { var str = []; for(var p in obj) if (obj.hasOwnProperty(p)) { str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); } return str.join("&"); }, // Flash helper to diplay instant notifications flash: function (level, message) { if (!store.get('flash')) { store.set('flash', true); } // Helper CSS class on main wrapper $('#slider').addClass('with-flashMessage'); // If the line is a bash command if (level === 'info' && message.charAt(0) === '+') { level = 'log'; } // Add message $('#flashMessage .messages') .prepend('
'+ '

'+ message +'

'); // Scroll to top to view new messages $('#flashMessage').scrollTop(0); }, checkInstall: function(callback) { $.ajax({ dataType: "json", url: 'https://'+ store.get('url') +'/installed', timeout: 3000 }) .success(function(data) { callback(data.installed); }) .fail(function() { callback(undefined); }); }, // API call api: function(uri, callback, method, data, websocket) { c = this; call = function(uri, callback, method, data) { method = typeof method !== 'undefined' ? method : 'GET'; data = typeof data !== 'undefined' ? data : {}; if (window.navigator && window.navigator.language && (typeof data.locale === 'undefined')) { data.locale = y18n.locale || window.navigator.language.substr(0, 2); } var args = data; if (uri === '/postinstall') { var installing = false; setInterval(function () { installing = true; }, 1500); } loaded = false; if ($('div.loader').length === 0) { $('#main').append('
'); } jQuery.ajax({ url: 'https://' + store.get('url') + uri, type: method, crossdomain: true, data: data, traditional: true, dataType: 'json' }) .always(function(xhr, ts, error) { }) .done(function(data) { data = data || {}; callback(data); }) .fail(function(xhr) { // Postinstall is a custom case, we have to wait that // operation is done before doing anything if (uri === '/postinstall') { if (installing) { interval = window.location.hostname === args.domain ? 20000 : 5000; checkInstall = setInterval(function () { c.checkInstall(function(isInstalled) { if (isInstalled || typeof isInstalled === 'undefined') { c.flash('success', y18n.t('installation_complete')); clearInterval(checkInstall); window.location.href = 'https://'+ window.location.hostname +'/yunohost/admin/'; } }); }, interval); } else { c.flash('fail', y18n.t('error_occured')); } } // Regular errors else { if (xhr.status == 200) { // Fail with 200, WTF callback({}); } // Unauthorized or wrong password else if (xhr.status == 401) { if (uri === '/login') { c.flash('fail', y18n.t('wrong_password')); } else { c.flash('fail', y18n.t('unauthorized')); c.redirect('#/login'); } } // 502 Bad gateway means API is down else if (xhr.status == 502) { c.flash('fail', y18n.t('api_not_responding')); } // More verbose error messages first else if (typeof xhr.responseText !== 'undefined') { c.flash('fail', xhr.responseText); } // Return HTTP error code at least else { var errorMessage = xhr.status+' '+xhr.statusText; c.flash('fail', y18n.t('error_server_unexpected', [errorMessage])); } // Remove loader if any $('div.loader').remove(); // Force scrollTop on page load $('html, body').scrollTop(0); store.clear('slide'); } }); }; websocket = typeof websocket !== 'undefined' ? websocket : true; if (websocket) { // Open a WebSocket connection to retrieve live messages from the moulinette ws = new WebSocket('wss://'+ store.get('url') +'/messages'); ws.onmessage = function(evt) { // console.log(evt.data); $.each($.parseJSON(evt.data), function(k, v) { c.flash(k, v); }); }; // If not connected, WebSocket connection will raise an error, but we do not want to interrupt API request ws.onerror = ws.onopen; ws.onclose = function() {}; ws.onopen = call(uri, callback, method, data); } else { call(uri, callback, method, data); } }, // Render view (cross-browser) view: function (view, data, callback, enableSlide) { c = this; // Default callback = typeof callback !== 'undefined' ? callback : function() {}; enableSlide = (typeof enableSlide !== 'undefined') ? enableSlide : true; // Change to false to disable animation loaded = true; // Hide loader and modal $('div.loader').remove(); $('#modal').modal('hide'); // Render content rendered = this.render('views/'+ view +'.ms', data); // Update content helper var leSwap = function() { rendered.swap(function() { // Slide direction if (enableSlide) { $('.slide, .btn-breadcrumb a:not(:last-child)').on('click', function() { $(this).addClass('active'); if ($(this).hasClass('back') || $(this).parent('.btn-breadcrumb').length) { store.set('slide', 'back'); } else { store.set('slide', 'to'); } }); } // Paste
 helper
                    c.prePaste();

                    // Run callback
                    callback();

                    // Force scrollTop on page load
                    $('html, body').scrollTop(0);
                });
            };

            // Slide back effect
            if (enableSlide && store.get('slide') == 'back') {
                store.clear('slide');
                $('#slideBack').css('display', 'none');
                $('#slider-container').css('margin-left', '-100%');
                $('#slideTo').show().html($('#main').html());
                leSwap();
                $('#slider-container').css('margin-left', '0px');
            }
            // Slide to effect
            else if (enableSlide && store.get('slide') == 'to') {
                store.clear('slide');
                $('#slideTo').css('display', 'none');
                $('#slider-container').css('margin-left', '0px');
                $('#slideBack').show().html($('#main').html());
                leSwap();
                $('#slider-container').css('margin-left', '-100%');
            }
            // No slideing effect
            else {
                leSwap();
            }
        },

        confirm: function(title, content, confirmCallback, cancelCallback) {
            // Default callbacks
            confirmCallback = typeof confirmCallback !== 'undefined' ? confirmCallback : function() {};
            cancelCallback = typeof cancelCallback !== 'undefined' ? cancelCallback : function() {};

            // Get modal element
            box = $('#modal');

            // Modal title
            if (typeof title === 'string' && title.length) {
                $('.title', box).html(title);
            }
            else {
                box.addClass('no-title');
            }

            // Modal content
            $('.content', box).html(content);

            // Handle buttons
            $('footer button', box)
                .click(function(e){
                    e.preventDefault();

                    $('#modal footer button').unbind( "click" );
                    // Reset & Hide modal
                    box
                        .removeClass('no-title')
                        .modal('hide');

                    // Do corresponding callback
                    if ($(this).data('action') == 'confirm') {
                        confirmCallback();
                    }
                    else {
                        cancelCallback();
                    }
                });

            // Show modal
            return box.modal('show');
        },

        arraySortById: function(arr) {
            arr.sort(function(a, b){
                if (a.id > b.id) {
                    return 1;
                }
                else if (a.id < b.id) {
                    return -1;
                }
                return 0;
            });
        },

        arrayDiff: function(arr1, arr2) {
            arr1 = arr1 || [];
            arr2 = arr2 || [];
            return arr1.filter(function (a) {
                return ((arr2.indexOf(a) == -1) && (a !== ""));
            });
        },

        groupHooks: function(hooks) {
            data={};
            var rules=[
                {
                    id:'configuration',
                    isIn:function (hook) {
                        return hook.indexOf('conf_')==0
                    }
                }
            ];

            $.each(hooks, function(i, hook) {
                var group_id=hook;
                $.each(rules, function(i, rule) {
                    if (rule.isIn(hook)) {
                        group_id = 'adminjs_group_'+rule.id;
                        return false;
                    }
                });

                if(group_id in data) {
                    data[group_id] = {
                        name:y18n.t('hook_'+group_id),
                        value:data[group_id].value+','+hook,
                        description:data[group_id].description+', '+y18n.t('hook_'+hook)
                    };
                }
                else {
                    data[group_id] = {
                        name:y18n.t('hook_'+group_id),
                        value:hook,
                        description:(group_id==hook)?y18n.t('hook_'+hook+'_desc'):y18n.t('hook_'+hook)
                    };
                }
            });         
            return data;
        },
        
        ungroupHooks: function(hooks,apps) {
            var data={};
            data['apps'] = apps || [];
            data['hooks'] = hooks || [];
            
            if (data['hooks'].constructor !== Array) {
                data['hooks'] = [data['hooks']];
            }
            if (data['apps'].constructor !== Array) {
                data['apps'] = [data['apps']];
            }

            if (data['hooks'].length == 0) {
                data['ignore_hooks'] = '';
            }
            if (data['apps'].length == 0) {
                data['ignore_apps'] = '';
            }

            // Some hook value contains multiple hooks separated by commas
            var split_hooks = [];
            $.each(data['hooks'], function(i, hook) {
                split_hooks = split_hooks.concat(hook.split(','));
            });
            data['hooks'] = split_hooks;

            return data;
        },

        // Paste 
        prePaste: function() {
            var pasteButtons = $('button[data-paste-content]');
            pasteButtons.on('click', function(){
                // Get paste content element
                var preElement = $($(this).data('paste-content'));

                // Add pacman loader
                $('#main').append('
'); // Send to paste.yunohost.org $.ajax({ type: "POST", url: 'https://paste.yunohost.org/documents', data: preElement[0].innerHTML, }) .success(function(data, textStatus, jqXHR) { window.open('https://paste.yunohost.org/' + data.key, '_blank'); }) .fail(function() { c.flash('fail', y18n.t('paste_error')); }) .always(function(){ // Remove pacman $('div.loader').remove(); }); }); } }); })();