/**
 * force load entry content with iframe when view entry
 *
 * @access public
 * @return void
 */
(function()
{
    if(config.defaultView != 'xhtml' && location.hash !== '#_single')
    {
        var redirect = function()
        {
            if(!config) return;
            if(config.currentModule == 'index')
            {
                if(config.currentMethod == 'index' && window.frameElement && window.frameElement.tagName == 'IFRAME') window.top.location.href = location.href;
            }
            else if((!window.frameElement || window.frameElement.tagName != 'IFRAME') && typeof v != 'undefined' && typeof v.entryID != 'undefined' && v.entryID != '')
            {
                location.href = config.webRoot + 'sys/index.php?entryID=' + v.entryID + '&entryUrl=' + encodeURIComponent(window.location.pathname + window.location.search);
            }
        };
        redirect();
        $(redirect);
    }

    $(document).on('click', '.table-actions .dropup button', function()
    {
        if($(this).offset().top < $(this).parent().find('.list-group').find('a').size() * 30)
        {
            $(this).parent().find('.list-group').parent().css({'top': '100%', 'bottom': 'unset'});
        }
    });
}());

$.extend(
{
    setAjaxForm: function(formID, callback, beforeSubmit)
    {
        if($(document).data('setAjaxForm:' + formID)) return;

        form = $(formID);

        var options =
        {
            target  : null,
            timeout : config.timeout,
            dataType:'json',

            success: function(response)
            {
                var submitButton = $(formID).find(':input[type=submit], .submit');

                /* The response is not an object, some error occers, bootbox.alert it. */
                if($.type(response) != 'object')
                {
                    $.enableForm(formID);
                    if(response) return bootbox.alert(response);
                    return bootbox.alert('No response.');
                }

                /* The response.result is success. */
                if(response.result == 'success')
                {
                    if(response.message && response.message.length)
                    {
                        submitButton.popover($.extend(
                        {
                            trigger: 'manual',
                            content: response.message,
                            tipClass: 'popover-success popover-form-result',
                            placement: response.placement ? response.placement : 'right'
                        }, submitButton.data())).popover('show');
                        setTimeout(function(){submitButton.popover('destroy')}, 2000);
                    }

                    if($.isFunction(callback)) return callback(response);

                    if($('#responser').length && response.message && response.message.length)
                    {
                        $('#responser').html(response.message).addClass('red f-12px').show().delay(3000).fadeOut(100);
                    }

                    if(response.closeModal)
                    {
                        setTimeout($.zui.closeModal, 1200);
                    }

                    if(response.callback)
                    {
                        var rcall = window[response.callback];
                        if($.isFunction(rcall))
                        {
                            param = response.callback_params ? response.callback_params : '';
                            if(rcall(param) === false) return;
                        }
                    }

                    if(response.locate)
                    {
                        if(response.locate == 'loadInModal')
                        {
                            var modal = $('.modal');
                            setTimeout(function()
                            {
                                modal.load(modal.attr('ref'), function(){$(this).find('.modal-dialog').css('width', $(this).data('width'));
                                $.zui.ajustModalPosition()})
                            }, 1000);
                        }
                        else
                        {
                            var reloadUrl = response.locate == 'reload' ? location.href : response.locate;
                            setTimeout(function(){location.href = reloadUrl;}, 1200);
                        }
                    }

                    if(response.ajaxReload)
                    {
                        var $target = $(response.ajaxReload);
                        if($target.length === 1)
                        {
                            $target.load(document.location.href + ' ' + response.ajaxReload, function()
                            {
                                // $target.dataTable();
                                $target.find('[data-toggle="modal"]').modalTrigger();
                            });
                        }
                    }

                    return true;
                }

                /**
                 * The response.result is fail.
                 */

                $.enableForm(formID);
                /* The result.message is just a string. */
                if($.type(response.message) == 'string')
                {
                    if($('#responser').length == 0)
                    {
                        submitButton.popover($.extend(
                        {
                            trigger: 'manual',
                            content: response.message,
                            tipClass: 'popover-danger popover-form-result',
                            placement: response.placement ? response.placement : 'right'
                        }, submitButton.data())).popover('show');
                        setTimeout(function(){submitButton.popover('destroy')}, 2000);
                    }
                    $('#responser').html(response.message).addClass('red small text-danger').show().delay(5000).fadeOut(100);
                }

                /* The result.message is just a object. */
                if($.type(response.message) == 'object')
                {
                    $.each(response.message, function(key, value)
                    {
                        /* Define the id of the error objecjt and it's label. */
                        var errorOBJ   = '#' + key;
                        var errorLabel = key + 'Label';

                        /* Create the error message. */
                        var errorMSG = '<span id="' + errorLabel + '" for="' + key  + '"  class="text-error red">';
                        if($.type(value) == 'string')
                        {
                            errorMSG += value;
                        }
                        else
                        {
                            $.each(value, function(subKey, subValue)
                            {
                                errorMSG += subKey != value.length - 1 ? subValue.replace(/[\。|\.]/, v.lang.semicolon) : subValue;
                            })
                        }
                        errorMSG += '</span>';

                        /* Append error message, set style and set the focus events. */
                        $('#' + errorLabel).remove();
                        var $errorOBJ = $(formID).find(errorOBJ);
                        if($errorOBJ.closest('.input-group').length > 0)
                        {
                            $errorOBJ.closest('.input-group').after(errorMSG)
                        }
                        else
                        {
                            $errorOBJ.parent().append(errorMSG);
                        }
                        $errorOBJ.css('margin-bottom', 0);
                        $errorOBJ.css('border-color','#953B39')
                        $errorOBJ.change(function()
                        {
                            $errorOBJ.css('margin-bottom', 0);
                            $errorOBJ.css('border-color','')
                            $('#' + errorLabel).remove();
                        });
                    })

                    /* Focus the first error field thus to nitify the user. */
                    var firstErrorField = $('#' + $('span.red').first().attr('for'));
                    var topOffset;
                    if(firstErrorField.length) topOffset = parseInt(firstErrorField.offset().top) - 20;   // 20px offset more for margin.

                    /* If there's the navbar-fixed-top element, minus it's height. */
                    if($('.navbar-fixed-top').size())
                    {
                        topOffset = topOffset - parseInt($('.navbar-fixed-top').height());
                    }

                    /* Scroll to the error field and foucus it. */
                    $(document).scrollTop(topOffset);
                    if(!firstErrorField.hasClass('form-datetime') && !firstErrorField.hasClass('form-date')) firstErrorField.focus();
                }

                if($.isFunction(callback)) return callback(response);
            },

            /* When error occers, alert the response text, status and error. */
            error: function(jqXHR, textStatus, errorThrown)
            {
                $.enableForm(formID);
                if(textStatus == 'timeout')
                {
                    bootbox.alert(v.lang.timeout);
                    return false;
                }
                bootbox.alert(jqXHR.responseText + textStatus + errorThrown);
            }
        };

        /* Call ajaxSubmit to sumit the form. */
        $(document).on('submit', formID, function()
        {
            $.disableForm(formID);
            if(!beforeSubmit || beforeSubmit() !== false)
            {
                $(this).ajaxSubmit(options);
            }
            else
            {
                $.enableForm(formID);
            }
            return false;    // Prevent the submitting event of the browser.
        }).data('setAjaxForm:' + formID, true);
    },

    /* Switch the label and disabled attribute for the submit button in a form. */
    setSubmitButton: function(formID, action)
    {
        var submitButton = $(formID).find(':submit');

        label    = submitButton.val();
        loading  = submitButton.data('loading');
        disabled = action == 'disable';

        submitButton.attr('disabled', disabled);
        submitButton.val(loading);
        submitButton.data('loading', label);
    },

    /* Disable a form. */
    disableForm: function(formID)
    {
        $.setSubmitButton(formID, 'disable');
    },

    /* Enable a form. */
    enableForm: function(formID)
    {
        $.setSubmitButton(formID, 'enable');
    }
});

$.extend(
{
    /**
     * Set ajax loader.
     *
     * Bind click event for some elements thus when click them,
     * use $.load to load page into target.
     *
     * @param string selector
     * @param string target
     */
    setAjaxLoader: function(selector, target)
    {
        /* Avoid duplication of binding */
        var data = $('body').data('ajaxLoader');
        if(data && data[selector]) return;
        if(!data) data = {};
        data[selector] = true;
        $('body').data('ajaxLoader', data);

        $(document).on('click', selector, function()
        {
            var url = $(this).attr('href');
            if(!url) url = $(this).data('rel');
            if(!url) return false;

            var $target = $(target);
            if(!$target.size()) return false;

            var width = $(this).data('width');
            $target.load(url, function()
            {
                if(width) $target.find('.modal-dialog').css('width', width);
                if($target.hasClass('modal') && $.zui.ajustModalPosition)
                {
                    $.zui.ajustModalPosition();
                    $target.find('.modal-body').on('resize', function()
                    {
                        $.zui.ajustModalPosition();
                    });
                }

                $.zui.initPage($target);
            });

            return false;
        });
    },

    /**
     * Set ajax jsoner.
     *
     * @param string   selector
     * @param object   callback
     */
    setAjaxJSONER: function(selector, callback)
    {
        $(document).on('click', selector, function()
        {
            /* Try to get the href of current element, then try it's data-rel attribute. */
            url = $(this).attr('href');
            if(!url) url = $(this).data('rel');
            if(!url) return false;

            $.getJSON(url, function(response)
            {
                /* If set callback, call it. */
                if($.isFunction(callback)) return callback(response);

                /* If the response has message attribute, show it in #responser or alert it. */
                if(response.message)
                {
                    if($('#responser').length)
                    {
                        $('#responser').html(response.message);
                        $('#responser').addClass('text-info f-12px');
                        $('#responser').show().delay(3000).fadeOut(100);
                    }
                    else
                    {
                        bootbox.alert(response.message);
                    }
                }

                /* If the response has locate param, locate the browse. */
                if(response.locate) return location.href = response.locate;

                /* If target and source returned in reponse, update target with the source. */
                if(response.target && response.source)
                {
                    $(response.target).load(response.source);
                }
            });

            return false;
        });
    },

    /**
     * Set ajax deleter.
     *
     * @param  string $selector
     * @access public
     * @return void
     */
    setAjaxDeleter: function (selector, callback)
    {
        var bindMap = $(document).data('ajaxDeleterBindMap') || {};
        if(bindMap[selector]) return;

        $(document).on('click', selector, function()
        {
            if($(this).parents('.dropdown.open').length) $(this).parents('.dropdown').removeClass('open');

            if(confirm(v.lang.confirmDelete))
            {
                var deleter = $(this);
                deleter.text(v.lang.deleteing);

                $.getJSON(deleter.attr('href'), function(data)
                {
                    if ((callback && callback(data)) === false) {
                        return;
                    }
                    /* The response is not an object, some error occers, bootbox.alert it. */
                    if($.type(data) != 'object')
                    {
                        if(!data) data = 'No response.';
                        return bootbox.alert(data, function(){location.reload();});
                    }
                    if(data.result == 'success')
                    {
                        if($(selector).hasClass('reloadModal')) return $.reloadAjaxModal(1200, deleter.parents('.modal-dialog').width());
                        if(data.locate && data.locate != 'reload') return location.href = data.locate;
                        return location.reload();
                    }
                    else
                    {
                        alert(data.message);
                        return location.reload();
                    }
                });
            }
            return false;
        });

        bindMap[selector] = true;
        $(document).data('ajaxDeleterBindMap', bindMap)
    },

    /**
     * Set ajax confirmer.
     *
     * @param  string $selector
     * @access public
     * @return void
     */
    setAjaxConfirmer: function (selector, callback)
    {
        var bindMap = $(document).data('modalDeleterBindMap') || {};
        if(bindMap[selector]) return;

        $(document).on('click', selector, function()
        {
            if($(this).hasClass('disabled')) return false;
            
            $(this).addClass('confirming');
            if($(this).parents('.dropdown.open').length) $(this).parents('.dropdown').removeClass('open');

            var confirmTitle  = $(this).data('confirmtitle') || v.lang.confirmDelete;
            var confirmDetail = $(this).data('confirmdetail') || v.lang.confirmDeleteDetail;
            var confirmButton = $(this).data('confirmbutton') || v.lang.delete;
            var confirming    = $(this).data('confirming') || v.lang.deleteing;

            $('#confirmModal .modal-title').html(confirmTitle);
            $('#confirmModal .modal-body').html(confirmDetail);
            $('#confirmModal .btn-confirm').text(confirmButton);
            $('#confirmModal .btn-confirm').attr('data-confirming', confirming);
            
            if($(this).parents('.modal').length)
            {
                $('.btn-confirm').addClass('confirming').attr('href', $(this).attr('href'));

                modal = $(this).parents('.modal');
                modal.attr('id', 'confirmModal');
                modal.html($('#confirmModal').html());
                $.zui.ajustModalPosition();
            }
            else
            {
                $('#confirmModal').modal('show');
            }

            return false;
        });

        $('#confirmModal').on('hide.zui.modal', function() {
            $(selector).removeClass('confirming');
        })

        $(document).on('click', '.btn-confirm', function()
        {
            var $confirmer = $('.confirming');
            var confirming = $confirmer.data('confirming') || v.lang.deleteing;
            $confirmer.text(confirming);

            $.getJSON($confirmer.attr('href'), function(response)
            {
                if((callback && callback(response)) === false) {
                    return;
                }
                if(response.callback)
                {
                    var rcall = window[response.callback];
                    if($.isFunction(rcall))
                    {
                        param = response.callback_params ? response.callback_params : '';
                        if(rcall(param) === false) return;
                    }
                    $('#confirmModal').modal('hide');
                    return;
                }
                /* The response is not an object, some error occers, bootbox.alert it. */
                if($.type(response) != 'object')
                {
                    if(!response) response = 'No response.';
                    return bootbox.alert(response, function(){location.reload();});
                }
                if(response.result == 'success')
                {
                    if($(selector).hasClass('reloadModal')) return $.reloadAjaxModal(1200, $confirmer.parents('.modal-dialog').width());
                    if(response.locate) return location.href = response.locate;
                    return location.reload();
                }
                else
                {
                    alert(response.message);
                    return location.reload();
                }
            });
        })

        bindMap[selector] = true;
        $(document).data('modalConfirmBindMap', bindMap);
    },

    /**
     * Set reload deleter.
     *
     * @param  string $selector
     * @access public
     * @return void
     */
    setReloadDeleter: function (selector)
    {
        $(document).on('click', selector, function()
        {
            if(confirm(v.lang.confirmDelete))
            {
                var deleter = $(this);
                deleter.text(v.lang.deleteing);

                $.getJSON(deleter.attr('href'), function(data)
                {
                    var afterDelete = deleter.data('afterDelete');
                    if($.isFunction(afterDelete))
                    {
                        $.proxy(afterDelete, deleter)(data);
                    }

                    if(data.result == 'success')
                    {
                        var table     = $(deleter).closest('table');
                        var replaceID = table.attr('id');

                        table.wrap("<div id='tmpDiv'></div>");
                        var $tmpDiv = $('#tmpDiv');
                        $tmpDiv.load(document.location.href + ' #' + replaceID, function()
                        {
                            $tmpDiv.replaceWith($tmpDiv.html());
                            var $target = $('#' + replaceID);
                            $target.find('.reloadDeleter').data('afterDelete', afterDelete);
                            $target.find('[data-toggle="modal"]').modalTrigger();
                            if(typeof sortTable == 'function')
                            {
                                sortTable();
                            }
                            else
                            {
                                $('tfoot td').css('background', 'white').unbind('click').unbind('hover');
                            }
                        });
                    }
                    else
                    {
                        alert(data.message);
                    }
                });
            }
            return false;
        });
    },

    /**
     * Set reload.
     *
     * @param  string $selector
     * @access public
     * @return void
     */
    setReload: function (selector)
    {
        $(document).on('click', selector, function()
        {
            var reload = $(this);
            $.getJSON(reload.attr('href'), function(data)
            {
                if(data.result == 'success')
                {
                    var table     = $(reload).closest('table');
                    var replaceID = table.attr('id');

                    table.wrap("<div id='tmpDiv'></div>");
                    $('#tmpDiv').load(document.location.href + ' #' + replaceID, function()
                    {
                        $('#tmpDiv').replaceWith($('#tmpDiv').html());
                        if(typeof sortTable == 'function')
                        {
                            sortTable();
                        }
                        else
                        {
                            $('tfoot td').css('background', 'white').unbind('click').unbind('hover');
                        }
                    });
                }
                else
                {
                    alert(data.message);
                }
            });
            return false;
        });
    },

    /**
     * Reload ajax modal.
     *
     * @param int duration
     * @access public
     * @return void
     */
    reloadAjaxModal: function(duration, width)
    {
        if(typeof(duration) == 'undefined') duration = 1000;
        setTimeout(function()
        {
            var modal = $('#ajaxModal');
            modal.load(modal.attr('ref'), function()
            {
                if(typeof(width) == 'undefined') width = $(this).data(width);
                $(this).find('.modal-dialog').css('width', width);
                $.zui.ajustModalPosition()
            })
        }, duration);
    }
});

/**
 * Judge the string is a integer number
 *
 * @access public
 * @return bool
 */
function isNum(s)
{
    if(s!=null)
    {
        var r, re;
        re = /\d*/i;
        r = s.match(re);
        return (r == s) ? true : false;
    }
    return false;
}

/**
 * Create link.
 *
 * @param  string $moduleName
 * @param  string $methodName
 * @param  string $vars
 * @param  string $viewType
 * @access public
 * @return string
 */
function createLink(moduleName, methodName, vars, viewType)
{
    if(!viewType) viewType = config.defaultView;
    if(vars)
    {
        vars = vars.split('&');
        for(i = 0; i < vars.length; i ++) vars[i] = vars[i].split('=');
    }

    appName = config.appName;
    router  = config.router;

    if(moduleName.indexOf('.') >= 0)
    {
        moduleNames = moduleName.split('.');
        appName     = moduleNames[0];
        moduleName  = moduleNames[1];
        router      = router.replace(config.appName, appName);
    }

    var link;
    if(config.requestType == 'PATH_INFO')
    {
        link = config.webRoot + appName + '/' + moduleName + config.requestFix + methodName;
        if(vars)
        {
            if(config.pathType == "full")
            {
                for(i = 0; i < vars.length; i ++) link += config.requestFix + vars[i][0] + config.requestFix + vars[i][1];
            }
            else
            {
                for(i = 0; i < vars.length; i ++) link += config.requestFix + vars[i][1];
            }
        }
        link += '.' + viewType;
    }
    else
    {
        link = router + '?' + config.moduleVar + '=' + moduleName + '&' + config.methodVar + '=' + methodName + '&' + config.viewVar + '=' + viewType;
        if(vars) for(i = 0; i < vars.length; i ++) link += '&' + vars[i][0] + '=' + vars[i][1];
    }
    return link;
}

/**
 * Set required fields, add star class to them.
 *
 * @access public
 * @return void
 */
function setRequiredFields()
{
    if(!config.requiredFields) return false;
    requiredFields = config.requiredFields.split(',');
    for(i = 0; i < requiredFields.length; i++)
    {
        $('#' + requiredFields[i]).closest('td,th').prepend("<div class='required required-wrapper'></div>");
        var colEle = $('#' + requiredFields[i]).closest('[class*="col-"]');
        if(colEle.parent().hasClass('form-group')) colEle.addClass('required');
    }
}

/**
 * Select lang.
 *
 * @param  string $lang
 * @access public
 * @return void
 */
function selectLang(lang)
{
    $.cookie('lang', lang, {expires:config.cookieLife, path:config.webRoot});
    location.href = removeAnchor(location.href);
}

/**
 * Set theme.
 *
 * @param  string theme
 * @access public
 * @return void
 */
function selectTheme(theme)
{
    $.cookie('theme', theme, {expires:config.cookieLife, path:config.webRoot});
    location.href = removeAnchor(location.href);
}

/**
 * Remove anchor from the url.
 *
 * @param  string $url
 * @access public
 * @return string
 */
function removeAnchor(url)
{
    pos = url.indexOf('#');
    if(pos > 0) return url.substring(0, pos);
    return url;
}

/**
 * Ping to keep login
 *
 * @access public
 * @return void
 */
function ping()
{
    /* get showed notice ids. */
    var notice = getShowedNotice().join(',');

    $.get(createLink('misc', 'ping', 'notice=' + notice), function(response)
    {
        if(typeof(response.notices) != 'undefined')
        {
            for(key in response.notices)
            {
                showNotice(response.notices[key]);
            }
        }
    }, 'json');
}

/**
 * get showed notice id.
 *
 * @access public
 * @return array
 */
function getShowedNotice()
{
    var ids = [];
    $('.messager-notification[data-id]').each(function()
    {
        ids.push($(this).data('id'));
    });
    return ids;
}

/**
 * Show a notice.
 *
 * @param  object $notice
 * @access public
 * @return void
 */
function showNotice(notice)
{
    if (notice.app && $.getEntry)
    {
        var entry = $.getEntry(notice.app);
        if (entry)
        {
            var title = entry.name;
            if(notice.title)
            {
                if(notice.title !== title) title += ' - <small>' + notice.title + '</small>';
            }
            $.extend(notice,
            {
                title: title,
            });
        }
    }
    var msg = $.showAppNotification($.extend(
    {
        html: true,
        onHide: function()
        {
            if(this.notice && this.notice.read) $.get(this.notice.read);
        }
    }, notice));
    msg.notice = notice;
    msg.$.attr(
    {
        'data-id': notice.id,
        'data-read': notice.read,
    }).on('click', '.messager-content:not(:has(a[data-toggle=modal]))', function()
    {
        var $a = $(this).find('a');
        var appID = $a.data('id') || $a.data('appid');
        if($a.attr('target') == '_blank')
        {
            window.open($a.attr('href'));
            msg.hide();
            return false;
        }
        if(appID) $.openEntry(appID, $a.attr('href'));
        msg.hide();
        return false;
    }).on('mouseup', '.messager-content a[data-toggle=modal]', function()
    {
        msg.hide();
        return false;
    });
    return msg;
}

/**
 * Make form condensed
 *
 * @access public
 * @return void
 */
function condensedForm()
{
    $('.form-condensed legend').click(function()
    {
        $(this).closest('fieldset').toggleClass('collapsed');
    });
}

/**
 * Set page actions
 *
 * @access public
 * @return void
 */
function setPageActions()
{
    var bar = $('.page-actions'), barTop, barWidth, timeoutFn;
    if(bar.length)
    {
        barTop = bar.offset().top + bar.outerHeight();
        barWidth = bar.width();
        wW = 0;
        $(window).scroll(fixPageActions).resize(function()
        {
            var winW = $(window).width();
            if(Math.abs(wW - winW) < 100) return;
            wW = winW;
            bar = $('.page-actions');
            bar.removeClass('fixed');
            bar.css('width', '100%');
            barTop = bar.offset().top + bar.outerHeight();
            barWidth = bar.width();
            fixPageActions();
        });
        fixPageActions();
    }

    function fixPageActions()
    {
        if(timeoutFn)
        {
            clearTimeout(timeoutFn);
            timeoutFn = null;
        }
        timeoutFn = setTimeout(function()
        {
            var $win = $(window);
            var wH = $win.height();
            var fixed = barTop > wH && $win.scrollTop() < (barTop - wH);
            if(fixed)
            {
                bar.css('width', barWidth);
            }
            $('body').toggleClass('page-actions-fixed', fixed);
            bar.toggleClass('fixed', fixed);
        }, 50);
    }
}

/**
 * Show drop menu.
 *
 * @param  string $objectType product|project
 * @param  int    $objectID
 * @param  string $module
 * @param  string $method
 * @param  string $extra
 * @access public
 * @return void
 */
function showDropMenu(objectType, objectID, module, method, extra)
{
    var li = $('#currentItem').closest('li');
    if(li.hasClass('show')) {li.removeClass('show'); return;}

    if(!li.data('showagain'))
    {
        li.data('showagain', true);
        $(document).click(function() {li.removeClass('show');});
        $('#dropMenu, #currentItem').click(function(e){e.stopPropagation();});
    }
    $.get(createLink(objectType, 'ajaxGetDropMenu', "objectID=" + objectID + "&module=" + module + "&method=" + method + "&extra=" + extra), function(data){ $('#dropMenu').html(data).find('#search').focus();});

    li.addClass('show');
}

/**
 * Search items.
 *
 * @param  string $keywords
 * @param  string $objectType
 * @param  int    $objectID
 * @param  string $module
 * @param  string $method
 * @param  string $extra
 * @access public
 * @return void
 */
function searchItems(keywords, objectType, objectID, module, method, extra)
{
    if(keywords == '')
    {
        showMenu = 0;
        showDropResult(objectType, objectID, module, method, extra);
    }
    else
    {
        keywords = encodeURI(keywords);
        if(keywords != '-') $.get(createLink(objectType, 'ajaxGetMatchedItems', "keywords=" + keywords + "&module=" + module + "&method=" + method + "&extra=" + extra), function(data){$('#searchResult').html(data);});
    }
}

/**
 * Show or hide more items.
 *
 * @access public
 * @return void
 */
function switchFinished()
{
    $('#search').width($('#search').width()).focus();
    $('#finishedMenu').width($('#defaultMenu').outerWidth());
    $('#searchResult').removeClass('show-suspend');
    $('#searchResult').toggleClass('show-finished');
}

/**
 * Show or hide more items.
 *
 * @access public
 * @return void
 */
function switchSuspend()
{
    $('#search').width($('#search').width()).focus();
    $('#suspendMenu').width($('#defaultMenu').outerWidth());
    $('#searchResult').removeClass('show-finished');
    $('#searchResult').toggleClass('show-suspend');
}

/**
 * Set form action and submit.
 *
 * @param  url    $actionLink
 * @param  string $hiddenwin 'hiddenwin'
 * @access public
 * @return void
 */
function setFormAction(actionLink, hiddenwin, obj)
{
    $form = typeof(obj) == 'undefined' ? $('form') : $(obj).closest('form');
    if(hiddenwin) $form.attr('target', hiddenwin);
    else $form.removeAttr('target');

    $form.attr('action', actionLink).submit();
}

let fixNavCount = 0;

/**
 * Fix menus of navbar.
 *
 * @access public
 * @return void
 */
function fixNavbar()
{
    if($('.navbar-nav').length == 0) return false;
    if(fixNavCount > $('.navbar-nav a').length) return false;

    fixNavCount++;

    var $navbar      = $('.navbar-nav');
    var navWidth     = 0;
    $navbar.find('li').each(function()
    {
        navWidth += $(this).outerWidth(true);
    })

    var mainWidth      = $('#mainNavbar').width();
    var containerWidth = $('#mainNavbar .container').width();
    var headingWidth   = $('#mainNavbar .heading').width();
    var leftWidth      = $('#mainNavbar .heading').offset().left + headingWidth;
    var rightWidth     = (mainWidth - containerWidth) / 2;
    var seachWidth     = $('#searchbox').length ? $('#searchbox').width() : 100;
    rightWidth = rightWidth > seachWidth ? 0 : seachWidth;

    var paddingWidth = rightWidth > leftWidth ? rightWidth : leftWidth;

    if(navWidth > (mainWidth - headingWidth - paddingWidth * 2))
    {
        $navbar.find('.moreMenu').removeClass('hidden');
        var lastNav = $('.navbar-nav > li').not('.moreMenu').last();
        $navbar.find('.moreMenu .dropdown-menu').prepend(lastNav);

        fixNavbar();
    }
}

function fixOperateMenu($td)
{
    var aList = $td.children('a').map(function(){return $(this).outerWidth(true);}).get();
    if(!aList.length) return false;

    var $moreMenu = $td.find('.dropdown-menu').parent();
    var tdWidth   = $td.width();
    var aWidth    = aList.reduce(function(a, b){return a + b;});
    var mWidth    = $moreMenu.length ? $moreMenu.outerWidth(true) : 0;

    if(tdWidth < aWidth + mWidth)
    {
        if($moreMenu.length == 0)
        {
            $moreMenu = $("<div id='moreMenu' class='dropdown'><a href='javascript:;' data-toggle='dropdown'>" + v.lang.more + "<span class='caret'></span></a><ul class='dropdown-menu pull-right'></ul></div>");
            $td.append($moreMenu);
        }

        var $lastA = $td.children('a:last');
        if($lastA.hasClass('disabled'))
        {
            $lastA.remove();
        }
        else
        {
            $moreMenu.children('.dropdown-menu').prepend($('<li>').append($lastA));
        }

        fixOperateMenu($td);
    }
}

function round(number, precision)
{
    return Math.round(+number + 'e' + precision) / Math.pow(10, precision);
}
