<commit_before>/*
* @Author: hanjiyun
* @Date:   2013-11-02 18:53:14
* @Last Modified by:   hanjiyun
* @Last Modified time: 2014-01-31 22:12:28
*/

$(function() {
    var windowStatus,
        afkDeliveredMessages = 0;

    // First update the title with room's name
    updateTitle();

    focusInput();

/*
=================
    Socket.io
=================
*/

    var socket = io.connect("", {
        "connect timeout": 1000
    });

    socket.on('error', function (reason){
        console.error('Unable to connect Socket.IO !!', reason);
    });

    socket.on('connect', function (){
        // console.info('successfully established a working connection');

        if($('.chat .chat-box').length === 0) {
            socket.emit('history request');
        }
    });

/*
history respinse
*/
    socket.on('history response', function(data) {

        $('.chat').append(ich.loading());

        setTimeout(function(){
            if(data.history && data.history.length) {

                var $lastInput,
                    lastInputUser;

                data.history.forEach(function(historyLine) {
                    var lang;
                    if(isChinese(historyLine.message)){
                        lang = 'en';
                    } else {
                        lang = 'cn';
                    }

                    var time = new Date(historyLine.creation_ts),
                        chatBoxData = {
                            id: historyLine.id,
                            msg: historyLine.message,
                            lang : lang,
                            time: time.format("yyyy-MM-dd hh:mm:ss")
                        };

                    $('.chat').append(parseChatBox(ich.chat_box(chatBoxData)));
                });

                // bindDeleteMes();
                $('.time').timeago();
                masonryHistory($('.chat'));
                hideLoading();
            } else {
                hideLoading();
                $('.chat').append(ich.nullbox());
            }
        }, 1000)
    });

/*
new msg
*/
    socket.on('new msg', function(data) {
        var time = new Date();
        data.time = time;

        if(isChinese(data.msg)){
            data.lang = 'en';
        } else {
            data.lang = 'cn';
        }

        var $boxes = parseChatBox(ich.chat_box(data));

        if($('.chat .chat-box').length == 0) {
            $('.chat').prepend( $boxes )
        } else {
            $('.chat').prepend( $boxes ).masonry('prepended', $boxes)
        }

        masonryHistory($('.chat'));
        // bindDeleteMes();
        $(".time").timeago();
        hideNull();

        //update title if window is hidden
        if(windowStatus === "hidden") {
            afkDeliveredMessages +=1;
            updateTitle();
            $('#chatAudio')[0].play();
        }
    });

/*
delete msg
*/
    socket.on('message deleted', function(data) {

        var chat = $('.chat-box');

        chat.each(function(){
            var el = $(this);

            if(el.data('id') === data.id){
                // todo maybe no need to clear?
                if(el.find('.progressWrapper').size() > 0){
                    clearTimeout(el.delTime)
                }
                $('.chat').masonry( 'remove', el);
                $('.chat').masonry();

                if(windowStatus === "hidden") {
                    $('#deletedAudio')[0].play();
                }
            }
        });

        // todo
        // 判断是否删光了. ps: 上面的 masonry 不支持回调，只好在这里 setTimeout 了 :(
        // 这里的处理还不是很完善
        var sadTime = setTimeout(function(){
            // console.log(chat.size())
            if(chat.size() === 0){
                // console.log('空k')
                $('.chat .nullbox').show();
                $('.chat').masonry('destroy');
            }
            clearTimeout(sadTime);
        }, 500)
    })

/*
upload image
*/

// todo

// ========================

/*
=================
   Delete msg
=================
*/
    $('.chat-list').hammer({
        hold_timeout: 1000, // hold time setting
        stop_browser_behavior: { userSelect: "" }
    }).on('hold', '.chat-box', function(event) {
        if($(this).hasClass('waiting')) return;

        // 显示删除按钮
        var $e = $(this);
        $e.append(ich.confirm_template());
        $e.addClass('waiting animate');

        // 绑定 删除事件
        $e.find('.delete').click(function(){
            showProgress($e);
            $del = $(this);
            $del.hide();

            // 10秒动画后向socket发出删除命令
            // 这里的时间需要和css那边的动画时间一致
            $e.delTime = setTimeout(function(){
                var id = $e.data('id');
                socket.emit('delete message', {
                    id: id
                });
                $('.chat').masonry( 'remove', $e);
                $('.chat').masonry();
                clearTimeout($e.delTime)
            }, 10000)
        })

        // 绑定 取消删除事件
        $e.find('.cancel').click(function(){
            $e.removeClass('waiting animate');
            $e.find('.confirm').remove();
            $e.find('.progressWrapper').remove();
            clearTimeout($e.delTime)
        })
    })

/*
=================
   drop upload image
=================
*/

// upload image to qiniu
    // imagesBucket.putFile(
    //     'exampleKey2', // new file name
    //     '/Users/hanjiyun/Google Drive/Project/Perber/perber/public/apple-touch-icon-114x114-precomposed.png' // file path
    // ).then(
    //     function(reply){
    //         // 上传成功
    //         console.dir(reply);
    //     },
    //     function(err){
    //         console.log(err);
    //     }
    // )

/*
=================
   Say
=================
*/

    $(".chat-input textarea").keypress(function(event) {
        // nl2br
        var inputText = $(this).val().trim().replace(/\r\n/gi, '');//.replace('\n', '').replace('\r','').replace(' ','');

        switch (event.keyCode) {
            case 13:
                if (!event.shiftKey && inputText){
                    socket.emit('my msg', {
                        msg: inputText
                    });
                    $(this).val('');

                    return false;
                }
                break;
            case 8:
            case 46:
        }
    });

    var textParser = function(text) {

        // replace emoticons
        // text = injectEmoticons(text);

        // replace img
        var sinaImgReg = /(http:\/\/ww[0-9]{1}.sinaimg.cn\/[a-zA-Z0-9]+\/[a-zA-Z0-9]+.[a-z]{3})/g,
            linkReg = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;

        // replace link and image
        text = text.replace(linkReg, function(e){
            var result;
            if(sinaImgReg.test(e)){
                result = '

';
            } else {
                result = ''+ e +'';
            }
            return result;
        })

        //replace @ twitter
        text = text.replace(/(@)([a-zA-Z0-9_]+)/g, "$1$2");

        return text;
    };

    var parseChatBox = function(chatBox) {
        var chatBoxMsg = chatBox.find('p');
        parseChatBoxMsg(chatBoxMsg);
        return chatBox;
    };

    var parseChatBoxMsg = function(chatBoxMsg) {
        var msg = chatBoxMsg.html();
        return chatBoxMsg.html(textParser(msg));
    };

    var patterns = {
        angry: /\>:-o|\>:o|\>:-O|\>:O|\>:-\(|\>:\(/g,
        naughty: /\>:-\)|\>:\)|\>:-\>|\>:\>/g,
        sick: /:-\&|:\&|=\&|=-\&|:-@|:@|=@|=-@/g,
        smile: /:-\)|:\)|=-\)|=\)/g,
        wink: /;-\)|;\)/g,
        frown: /:-\(|:\(|=\(|=-\(/g,
        ambivalent: /:-\||:\|/g,
        gasp: /:-O|:O|:-o|:o|=-O|=O|=-o|=o/g,
        laugh: /:-D|:D|=-D|=D/g,
        kiss: /:-\*|:\*|=-\*|=\*/g,
        yuck: /:-P|:-p|:-b|:P|:p|:b|=-P|=-p|=-b|=P|=p|=b/g,
        yum: /:-d|:d/g,
        grin: /\^_\^|\^\^|\^-\^/g,
        sarcastic: /:-\>|:\>|\^o\)/g,
        cry: /:'\(|='\(|:'-\(|='-\(/g,
        cool: /8-\)|8\)|B-\)|B\)/g,
        nerd: /:-B|:B|8-B|8B/g,
        innocent: /O:-\)|o:-\)|O:\)|o:\)/g,
        sealed: /:-X|:X|=X|=-X/g,
        footinmouth: /:-!|:!/g,
        embarrassed: /:-\[|:\[|=\[|=-\[/g,
        crazy: /%-\)|%\)/g,
        confused: /:-S|:S|:-s|:s|%-\(|%\(|X-\(|X\(/g,
        moneymouth: /:-\$|:\$|=\$|=-\$/g,
        heart: /\(L\)|\(l\)/g,
        thumbsup: /\(Y\)|\(y\)/g,
        thumbsdown: /\(N\)|\(n\)/g,
        "not-amused": /-.-\"|-.-|-_-\"|-_-/g,
        "mini-smile": /c:|C:|c-:|C-:/g,
        "mini-frown": /:c|:C|:-c|:-C/g,
        content: /:j|:J/g,
        hearteyes: /\<3/g
    };

    var emoticHTML = "";

    var injectEmoticons = function(text) {
        for(var emotic in patterns) {
            text = text.replace(patterns[emotic], emoticHTML.replace("$emotic", "emoticon-" + emotic));
        }
        return text;
    }

    var isChinese = function(text){
        if(/.*[\u4e00-\u9fa5]+.*$/.test(text)){
            return false;
        } else {
            return true;
        }
    }

    // time.format("yyyy-MM-dd hh:mm:ss")
    Date.prototype.format = function(format){
        var o = {
            "M+" : this.getMonth()+1, //month
            "d+" : this.getDate(), //day
            "h+" : this.getHours(), //hour
            "m+" : this.getMinutes(), //minute
            "s+" : this.getSeconds(), //second
            "q+" : Math.floor((this.getMonth()+3)/3), //quarter
            "S" : this.getMilliseconds() //millisecond
        }

        if(/(y+)/.test(format)) format=format.replace(RegExp.$1,(this.getFullYear()+"").substr(4- RegExp.$1.length));
        for(var k in o)if(new RegExp("("+ k +")").test(format))
            format = format.replace(RegExp.$1,RegExp.$1.length==1? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
        return format;
    }

    // Simplified Chinese
    $.timeago.settings = {
        refreshMillis : 1000,
        allowFuture: false,
        localeTitle: true,
        cutoff:0,
        // strings: {
        //     prefixAgo: null,
        //     prefixFromNow: "从现在开始",
        //     suffixAgo: "之前",
        //     suffixFromNow: null,
        //     seconds: "刚刚",
        //     minute: "大约 1 分钟",
        //     minutes: "%d 分钟",
        //     hour: "大约 1 小时",
        //     hours: "大约 %d 小时",
        //     day: "1 天",
        //     days: "%d 天",
        //     month: "大约 1 个月",
        //     months: "%d 月",
        //     year: "大约 1 年",
        //     years: "%d 年",
        //     numbers: [],
        //     wordSeparator: ""
        // }
        strings: {
            prefixAgo: null,
            prefixFromNow: null,
            suffixAgo: "ago",
            suffixFromNow: "from now",
            seconds: "less than a minute",
            minute: "about a minute",
            minutes: "%d minutes",
            hour: "about an hour",
            hours: "about %d hours",
            day: "a day",
            days: "%d days",
            month: "about a month",
            months: "%d months",
            year: "about a year",
            years: "%d years",
            wordSeparator: " ",
            numbers: []
          }
    }

/*
=================
    TITLE notifications
=================
*/

    var hidden,
        change,
        vis = {
            hidden: "visibilitychange",
            mozHidden: "mozvisibilitychange",
            webkitHidden: "webkitvisibilitychange",
            msHidden: "msvisibilitychange",
            oHidden: "ovisibilitychange" /* not currently supported */
        };

    for (var hidden in vis) {
        if (vis.hasOwnProperty(hidden) && hidden in document) {
            change = vis[hidden];
            break;
        }
    }

    if (change) {
        document.addEventListener(change, onchange);
    } else if (/*@cc_on!@*/false) { // IE 9 and lower
        document.onfocusin = document.onfocusout = onchange
    } else {
        window.onfocus = window.onblur = onchange;
    }

    function onchange (evt) {
        var body = document.body;
            evt = evt || window.event;

        if (evt.type == "focus" || evt.type == "focusin") {
            windowStatus = "visible";
        } else if (evt.type == "blur" || evt.type == "focusout") {
            windowStatus = "hidden";
        } else {
            windowStatus = this[hidden] ? "hidden" : "visible";
        }

        if(windowStatus == "visible" && afkDeliveredMessages) {
            afkDeliveredMessages = 0;
            updateTitle();
        }

        if (windowStatus == "visible") {
            focusInput();
        }
    }

    function updateTitle() {
        // On chrome, we have to add a timer for updating the title after the focus event
        // else the title will not update

        // console.log('updateTitle!!')

        window.setTimeout(function () {
            $('title').html(ich.title_template({
                count: afkDeliveredMessages,
            }, true));
        },100);
    }

//===============

    function focusInput() {
        $(".chat-input textarea").focus();
    }

    //masonry history
    function masonryHistory(wrap){
        wrap.masonry({
            // columnWidth: 290,
            'itemSelector': '.chat-box',
            // 'gutter': 5,
            // isResizeBound: false,
            visibleStyle: { opacity: 1, transform: 'scale(1)' },
            isAnimated: true,
            animationOptions: {
                duration: 750,
                easing: 'linear',
                queue: false
            }
        });
    }

    function hideLoading(){
        $('.chat-list .loading').hide();
    }

    function hideNull(){
        $('.chat .nullbox').hide();
    }

    function showProgress($e){
        $e.find('p').append(ich.progress());
    }

});

<commit_msg> add douban image regex.<commit_after>/*
* @Author: hanjiyun
* @Date:   2013-11-02 18:53:14
* @Last Modified by:   hanjiyun
* @Last Modified time: 2014-01-31 22:45:35
*/

$(function() {
    var windowStatus,
        afkDeliveredMessages = 0;

    // First update the title with room's name
    updateTitle();

    focusInput();

/*
=================
    Socket.io
=================
*/

    var socket = io.connect("", {
        "connect timeout": 1000
    });

    socket.on('error', function (reason){
        console.error('Unable to connect Socket.IO !!', reason);
    });

    socket.on('connect', function (){
        // console.info('successfully established a working connection');

        if($('.chat .chat-box').length === 0) {
            socket.emit('history request');
        }
    });

/*
history respinse
*/
    socket.on('history response', function(data) {

        $('.chat').append(ich.loading());

        setTimeout(function(){
            if(data.history && data.history.length) {

                var $lastInput,
                    lastInputUser;

                data.history.forEach(function(historyLine) {
                    var lang;
                    if(isChinese(historyLine.message)){
                        lang = 'en';
                    } else {
                        lang = 'cn';
                    }

                    var time = new Date(historyLine.creation_ts),
                        chatBoxData = {
                            id: historyLine.id,
                            msg: historyLine.message,
                            lang : lang,
                            time: time.format("yyyy-MM-dd hh:mm:ss")
                        };

                    $('.chat').append(parseChatBox(ich.chat_box(chatBoxData)));
                });

                // bindDeleteMes();
                $('.time').timeago();
                masonryHistory($('.chat'));
                hideLoading();
            } else {
                hideLoading();
                $('.chat').append(ich.nullbox());
            }
        }, 1000)
    });

/*
new msg
*/
    socket.on('new msg', function(data) {
        var time = new Date();
        data.time = time;

        if(isChinese(data.msg)){
            data.lang = 'en';
        } else {
            data.lang = 'cn';
        }

        var $boxes = parseChatBox(ich.chat_box(data));

        if($('.chat .chat-box').length == 0) {
            $('.chat').prepend( $boxes )
        } else {
            $('.chat').prepend( $boxes ).masonry('prepended', $boxes)
        }

        masonryHistory($('.chat'));
        // bindDeleteMes();
        $(".time").timeago();
        hideNull();

        //update title if window is hidden
        if(windowStatus === "hidden") {
            afkDeliveredMessages +=1;
            updateTitle();
            $('#chatAudio')[0].play();
        }
    });

/*
delete msg
*/
    socket.on('message deleted', function(data) {

        var chat = $('.chat-box');

        chat.each(function(){
            var el = $(this);

            if(el.data('id') === data.id){
                // todo maybe no need to clear?
                if(el.find('.progressWrapper').size() > 0){
                    clearTimeout(el.delTime)
                }
                $('.chat').masonry( 'remove', el);
                $('.chat').masonry();

                if(windowStatus === "hidden") {
                    $('#deletedAudio')[0].play();
                }
            }
        });

        // todo
        // 判断是否删光了. ps: 上面的 masonry 不支持回调，只好在这里 setTimeout 了 :(
        // 这里的处理还不是很完善
        var sadTime = setTimeout(function(){
            // console.log(chat.size())
            if(chat.size() === 0){
                // console.log('空k')
                $('.chat .nullbox').show();
                $('.chat').masonry('destroy');
            }
            clearTimeout(sadTime);
        }, 500)
    })

/*
upload image
*/

// todo

// ========================

/*
=================
   Delete msg
=================
*/
    $('.chat-list').hammer({
        hold_timeout: 1000, // hold time setting
        stop_browser_behavior: { userSelect: "" }
    }).on('hold', '.chat-box', function(event) {
        if($(this).hasClass('waiting')) return;

        // 显示删除按钮
        var $e = $(this);
        $e.append(ich.confirm_template());
        $e.addClass('waiting animate');

        // 绑定 删除事件
        $e.find('.delete').click(function(){
            showProgress($e);
            $del = $(this);
            $del.hide();

            // 10秒动画后向socket发出删除命令
            // 这里的时间需要和css那边的动画时间一致
            $e.delTime = setTimeout(function(){
                var id = $e.data('id');
                socket.emit('delete message', {
                    id: id
                });
                $('.chat').masonry( 'remove', $e);
                $('.chat').masonry();
                clearTimeout($e.delTime)
            }, 10000)
        })

        // 绑定 取消删除事件
        $e.find('.cancel').click(function(){
            $e.removeClass('waiting animate');
            $e.find('.confirm').remove();
            $e.find('.progressWrapper').remove();
            clearTimeout($e.delTime)
        })
    })

/*
=================
   drop upload image
=================
*/

// upload image to qiniu
    // imagesBucket.putFile(
    //     'exampleKey2', // new file name
    //     '/Users/hanjiyun/Google Drive/Project/Perber/perber/public/apple-touch-icon-114x114-precomposed.png' // file path
    // ).then(
    //     function(reply){
    //         // 上传成功
    //         console.dir(reply);
    //     },
    //     function(err){
    //         console.log(err);
    //     }
    // )

/*
=================
   Say
=================
*/

    $(".chat-input textarea").keypress(function(event) {
        // nl2br
        var inputText = $(this).val().trim().replace(/\r\n/gi, '');//.replace('\n', '').replace('\r','').replace(' ','');

        switch (event.keyCode) {
            case 13:
                if (!event.shiftKey && inputText){
                    socket.emit('my msg', {
                        msg: inputText
                    });
                    $(this).val('');

                    return false;
                }
                break;
            case 8:
            case 46:
        }
    });

    var textParser = function(text) {

        // replace emoticons
        // text = injectEmoticons(text);

        // replace img
        var sinaImgReg = /(http:\/\/ww[0-9]{1}.sinaimg.cn\/[a-zA-Z0-9]+\/[a-zA-Z0-9]+.[a-z]{3})/g,
            doubanImgReg = /(http:\/\/img[0-9]{1}.douban.com\/view\/[a-zA-Z0-9]+\/[a-zA-Z0-9]+\/public\/[a-zA-Z0-9]+.[a-z]{3})/g
            linkReg = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;

        // replace link and image
        text = text.replace(linkReg, function(e){
            var result;
            if(sinaImgReg.test(e) || doubanImgReg.test(e)){
                result = '

';
            } else {
                result = ''+ e +'';
            }
            return result;
        })

        //replace @ twitter
        text = text.replace(/(@)([a-zA-Z0-9_]+)/g, "$1$2");

        return text;
    };

    var parseChatBox = function(chatBox) {
        var chatBoxMsg = chatBox.find('p');
        parseChatBoxMsg(chatBoxMsg);
        return chatBox;
    };

    var parseChatBoxMsg = function(chatBoxMsg) {
        var msg = chatBoxMsg.html();
        return chatBoxMsg.html(textParser(msg));
    };

    var patterns = {
        angry: /\>:-o|\>:o|\>:-O|\>:O|\>:-\(|\>:\(/g,
        naughty: /\>:-\)|\>:\)|\>:-\>|\>:\>/g,
        sick: /:-\&|:\&|=\&|=-\&|:-@|:@|=@|=-@/g,
        smile: /:-\)|:\)|=-\)|=\)/g,
        wink: /;-\)|;\)/g,
        frown: /:-\(|:\(|=\(|=-\(/g,
        ambivalent: /:-\||:\|/g,
        gasp: /:-O|:O|:-o|:o|=-O|=O|=-o|=o/g,
        laugh: /:-D|:D|=-D|=D/g,
        kiss: /:-\*|:\*|=-\*|=\*/g,
        yuck: /:-P|:-p|:-b|:P|:p|:b|=-P|=-p|=-b|=P|=p|=b/g,
        yum: /:-d|:d/g,
        grin: /\^_\^|\^\^|\^-\^/g,
        sarcastic: /:-\>|:\>|\^o\)/g,
        cry: /:'\(|='\(|:'-\(|='-\(/g,
        cool: /8-\)|8\)|B-\)|B\)/g,
        nerd: /:-B|:B|8-B|8B/g,
        innocent: /O:-\)|o:-\)|O:\)|o:\)/g,
        sealed: /:-X|:X|=X|=-X/g,
        footinmouth: /:-!|:!/g,
        embarrassed: /:-\[|:\[|=\[|=-\[/g,
        crazy: /%-\)|%\)/g,
        confused: /:-S|:S|:-s|:s|%-\(|%\(|X-\(|X\(/g,
        moneymouth: /:-\$|:\$|=\$|=-\$/g,
        heart: /\(L\)|\(l\)/g,
        thumbsup: /\(Y\)|\(y\)/g,
        thumbsdown: /\(N\)|\(n\)/g,
        "not-amused": /-.-\"|-.-|-_-\"|-_-/g,
        "mini-smile": /c:|C:|c-:|C-:/g,
        "mini-frown": /:c|:C|:-c|:-C/g,
        content: /:j|:J/g,
        hearteyes: /\<3/g
    };

    var emoticHTML = "";

    var injectEmoticons = function(text) {
        for(var emotic in patterns) {
            text = text.replace(patterns[emotic], emoticHTML.replace("$emotic", "emoticon-" + emotic));
        }
        return text;
    }

    var isChinese = function(text){
        if(/.*[\u4e00-\u9fa5]+.*$/.test(text)){
            return false;
        } else {
            return true;
        }
    }

    // time.format("yyyy-MM-dd hh:mm:ss")
    Date.prototype.format = function(format){
        var o = {
            "M+" : this.getMonth()+1, //month
            "d+" : this.getDate(), //day
            "h+" : this.getHours(), //hour
            "m+" : this.getMinutes(), //minute
            "s+" : this.getSeconds(), //second
            "q+" : Math.floor((this.getMonth()+3)/3), //quarter
            "S" : this.getMilliseconds() //millisecond
        }

        if(/(y+)/.test(format)) format=format.replace(RegExp.$1,(this.getFullYear()+"").substr(4- RegExp.$1.length));
        for(var k in o)if(new RegExp("("+ k +")").test(format))
            format = format.replace(RegExp.$1,RegExp.$1.length==1? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
        return format;
    }

    // Simplified Chinese
    $.timeago.settings = {
        refreshMillis : 1000,
        allowFuture: false,
        localeTitle: true,
        cutoff:0,
        // strings: {
        //     prefixAgo: null,
        //     prefixFromNow: "从现在开始",
        //     suffixAgo: "之前",
        //     suffixFromNow: null,
        //     seconds: "刚刚",
        //     minute: "大约 1 分钟",
        //     minutes: "%d 分钟",
        //     hour: "大约 1 小时",
        //     hours: "大约 %d 小时",
        //     day: "1 天",
        //     days: "%d 天",
        //     month: "大约 1 个月",
        //     months: "%d 月",
        //     year: "大约 1 年",
        //     years: "%d 年",
        //     numbers: [],
        //     wordSeparator: ""
        // }
        strings: {
            prefixAgo: null,
            prefixFromNow: null,
            suffixAgo: "ago",
            suffixFromNow: "from now",
            seconds: "less than a minute",
            minute: "about a minute",
            minutes: "%d minutes",
            hour: "about an hour",
            hours: "about %d hours",
            day: "a day",
            days: "%d days",
            month: "about a month",
            months: "%d months",
            year: "about a year",
            years: "%d years",
            wordSeparator: " ",
            numbers: []
          }
    }

/*
=================
    TITLE notifications
=================
*/

    var hidden,
        change,
        vis = {
            hidden: "visibilitychange",
            mozHidden: "mozvisibilitychange",
            webkitHidden: "webkitvisibilitychange",
            msHidden: "msvisibilitychange",
            oHidden: "ovisibilitychange" /* not currently supported */
        };

    for (var hidden in vis) {
        if (vis.hasOwnProperty(hidden) && hidden in document) {
            change = vis[hidden];
            break;
        }
    }

    if (change) {
        document.addEventListener(change, onchange);
    } else if (/*@cc_on!@*/false) { // IE 9 and lower
        document.onfocusin = document.onfocusout = onchange
    } else {
        window.onfocus = window.onblur = onchange;
    }

    function onchange (evt) {
        var body = document.body;
            evt = evt || window.event;

        if (evt.type == "focus" || evt.type == "focusin") {
            windowStatus = "visible";
        } else if (evt.type == "blur" || evt.type == "focusout") {
            windowStatus = "hidden";
        } else {
            windowStatus = this[hidden] ? "hidden" : "visible";
        }

        if(windowStatus == "visible" && afkDeliveredMessages) {
            afkDeliveredMessages = 0;
            updateTitle();
        }

        if (windowStatus == "visible") {
            focusInput();
        }
    }

    function updateTitle() {
        // On chrome, we have to add a timer for updating the title after the focus event
        // else the title will not update

        // console.log('updateTitle!!')

        window.setTimeout(function () {
            $('title').html(ich.title_template({
                count: afkDeliveredMessages,
            }, true));
        },100);
    }

//===============

    function focusInput() {
        $(".chat-input textarea").focus();
    }

    //masonry history
    function masonryHistory(wrap){
        wrap.masonry({
            // columnWidth: 290,
            'itemSelector': '.chat-box',
            // 'gutter': 5,
            // isResizeBound: false,
            visibleStyle: { opacity: 1, transform: 'scale(1)' },
            isAnimated: true,
            animationOptions: {
                duration: 750,
                easing: 'linear',
                queue: false
            }
        });
    }

    function hideLoading(){
        $('.chat-list .loading').hide();
    }

    function hideNull(){
        $('.chat .nullbox').hide();
    }

    function showProgress($e){
        $e.find('p').append(ich.progress());
    }

});

<|endoftext|>


<commit_before>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Aria = require("../Aria");
var ariaUtilsDom = require("../utils/Dom");
var ariaCoreTimer = require("../core/Timer");
var ariaCoreBrowser = require("../core/Browser");

/**
 * This class contains an implementation of the aria.jsunit.IRobot interface which uses the Selenium Java Robot tool.
 * For this implementation to be usable, the browser must have been started with the Selenium Java Robot tool, which is
 * available at the following address: https://github.com/ariatemplates/selenium-java-robot
 */
module.exports = Aria.classDefinition({
    $classpath : 'aria.jsunit.RobotJavaSelenium',
    $extends : require("./RobotJava"),
    $implements : [require("./IRobot")],
    $singleton : true,
    $constructor : function () {
        this.$RobotJava.constructor.call(this);

        this._robotInitialized = false;

        /**
         * Offset to add to the X coordinates.
         * @type Number
         */
        this.offsetX = 0;

        /**
         * Offset to add to the Y coordinates.
         * @type Number
         */
        this.offsetY = 0;

        if (Aria.$frameworkWindow.top.attester && Aria.$frameworkWindow.top.location !== Aria.$frameworkWindow.location) {
            // Aria.$frameworkWindow.top.location === Aria.$frameworkWindow.location means we are not running
            // in the attester iframe, so there is no need to apply the extra offset.
            // Otherwise, we are running in an iframe. Let's apply the offset:
            this.offsetY = 32; // height of the header in attester
        }

        // This is updated in _offsetRecevied
        this._offset = {
            x : NaN,
            y : NaN
        };
    },
    $events : {
        "robotInitialized" : "Raised when the robot initialization has been done."
    },
    $statics : {
        ROBOT_ERROR : "An error occurred in the robot: %1"
    },
    $prototype : {

        /**
         * Return true if the robot is most likely usable.
         */
        isUsable : function () {
            return !!Aria.$frameworkWindow.top.SeleniumJavaRobot;
        },

        /**
         * Initialize the robot, if not already done. This must be called before any other method on the robot.
         * @param {aria.core.CfgBeans:Callback} callback callback to be called when the robot is ready to be used.
         */
        initRobot : function (cb) {
            if (!this._robot) {
                this._robot = Aria.$frameworkWindow.top.SeleniumJavaRobot;
                this._robot.getOffset({
                    fn : this._offsetReceived,
                    scope : this
                });
            }
            if (cb) {
                if (this._robotInitialized) {
                    this.$callback(cb);
                } else {
                    this.$onOnce({
                        "robotInitialized" : cb
                    });
                }
            }
        },

        _getScreenPos : function () {
            var window = Aria.$frameworkWindow;
            return {
                x : window.screenX != null ? window.screenX : window.screenLeft,
                y : window.screenY != null ? window.screenY : window.screenTop
            };
        },

        _offsetReceived : function (response) {
            if (response.success) {
                var res = response.result;
                var screenPos = this._getScreenPos();
                // Removes the current position on the screen so that, if the window is moved,
                // adding later the new position on the screen will give the correct coordinates.
                this._offset.x = res.x - screenPos.x;
                this._offset.y = res.y - screenPos.y;
            } else {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            if (!this._robotInitialized) {
                this._robotInitialized = true;
                this.$raiseEvent("robotInitialized");
            }
        },

        _callCallback : function (response, cb) {
            if (!response.success) {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            this.$callback(cb);
        },

        viewportToAbsolute : function (position) {
            var screenPos = this._getScreenPos();
            var offset = this._offset;
            return {
                x : screenPos.x + offset.x + this.offsetX + position.x,
                y : screenPos.y + offset.y + this.offsetY + position.y
            };
        },

        absoluteMouseMove : function (position, cb) {
            this._robot.mouseMove(position.x, position.y, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        absoluteSmoothMouseMove : function (from, to, duration, cb) {
            this._robot.smoothMouseMove(from.x, from.y, to.x, to.y, duration, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseMove : function (position, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (position.x < 0 || position.y < 0 || position.x > viewport.width || position.y > viewport.height) {
                // FIXME: log error correctly
                this.$logWarn("MouseMove position outside of the viewport.");
                // return;
            }
            this.absoluteMouseMove(this.viewportToAbsolute(position), cb);
        },

        smoothMouseMove : function (from, to, duration, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (from.x < 0 || from.y < 0 || from.x > viewport.width || from.y > viewport.height || to.x < 0 || to.y < 0
                    || to.x > viewport.width || to.y > viewport.height) {
                // FIXME: log error correctly
                this.$logWarn("smoothMouseMove from or to position outside of the viewport.");
                // return;
            }
            this.absoluteSmoothMouseMove(this.viewportToAbsolute(from), this.viewportToAbsolute(to), duration, cb);
        },

        mousePress : function (buttons, cb) {
            this._robot.mousePress(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseRelease : function (buttons, cb) {
            this._robot.mouseRelease(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseWheel : function (wheelAmt, cb) {
            this._robot.mouseWheel(wheelAmt, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        keyPress : function (keyCode, cb) {
            // IE sometimes miss some keystrokes, that's why we are adding a 100 ms
            // delay before each keypress (which experimentally seems to help...)
            // http://answers.microsoft.com/en-us/ie/forum/ie8-windows_other/internet-explorer-missing-keystroke-problem/1bee2ec3-828c-4a3d-8b05-638e44baf0a8
            ariaCoreTimer.addCallback({
                fn : this._keyPress,
                scope : this,
                args : {
                    keyCode : keyCode,
                    cb : cb
                },
                delay : ariaCoreBrowser.isIE ? 100 : 1
            });
        },

        _keyPress : function (args) {
            this._robot.keyPress(args.keyCode, {
                scope : this,
                fn : this._callCallback,
                args : args.cb
            });
        },

        keyRelease : function (keycode, cb) {
            this._robot.keyRelease(keycode, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        }
    }
});
<commit_msg>feat/test: now log an error when moving the mouse with the robot outside of the viewport<commit_after>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Aria = require("../Aria");
var ariaUtilsDom = require("../utils/Dom");
var ariaCoreTimer = require("../core/Timer");
var ariaCoreBrowser = require("../core/Browser");

/**
 * This class contains an implementation of the aria.jsunit.IRobot interface which uses the Selenium Java Robot tool.
 * For this implementation to be usable, the browser must have been started with the Selenium Java Robot tool, which is
 * available at the following address: https://github.com/ariatemplates/selenium-java-robot
 */
module.exports = Aria.classDefinition({
    $classpath : 'aria.jsunit.RobotJavaSelenium',
    $extends : require("./RobotJava"),
    $implements : [require("./IRobot")],
    $singleton : true,
    $constructor : function () {
        this.$RobotJava.constructor.call(this);

        this._robotInitialized = false;

        /**
         * Offset to add to the X coordinates.
         * @type Number
         */
        this.offsetX = 0;

        /**
         * Offset to add to the Y coordinates.
         * @type Number
         */
        this.offsetY = 0;

        if (Aria.$frameworkWindow.top.attester && Aria.$frameworkWindow.top.location !== Aria.$frameworkWindow.location) {
            // Aria.$frameworkWindow.top.location === Aria.$frameworkWindow.location means we are not running
            // in the attester iframe, so there is no need to apply the extra offset.
            // Otherwise, we are running in an iframe. Let's apply the offset:
            this.offsetY = 32; // height of the header in attester
        }

        // This is updated in _offsetRecevied
        this._offset = {
            x : NaN,
            y : NaN
        };
    },
    $events : {
        "robotInitialized" : "Raised when the robot initialization has been done."
    },
    $statics : {
        ROBOT_ERROR : "An error occurred in the robot: %1",
        POSITION_OUTSIDE_VIEWPORT_ERROR: "Position outside of the viewport"
    },
    $prototype : {

        /**
         * Return true if the robot is most likely usable.
         */
        isUsable : function () {
            return !!Aria.$frameworkWindow.top.SeleniumJavaRobot;
        },

        /**
         * Initialize the robot, if not already done. This must be called before any other method on the robot.
         * @param {aria.core.CfgBeans:Callback} callback callback to be called when the robot is ready to be used.
         */
        initRobot : function (cb) {
            if (!this._robot) {
                this._robot = Aria.$frameworkWindow.top.SeleniumJavaRobot;
                this._robot.getOffset({
                    fn : this._offsetReceived,
                    scope : this
                });
            }
            if (cb) {
                if (this._robotInitialized) {
                    this.$callback(cb);
                } else {
                    this.$onOnce({
                        "robotInitialized" : cb
                    });
                }
            }
        },

        _getScreenPos : function () {
            var window = Aria.$frameworkWindow;
            return {
                x : window.screenX != null ? window.screenX : window.screenLeft,
                y : window.screenY != null ? window.screenY : window.screenTop
            };
        },

        _offsetReceived : function (response) {
            if (response.success) {
                var res = response.result;
                var screenPos = this._getScreenPos();
                // Removes the current position on the screen so that, if the window is moved,
                // adding later the new position on the screen will give the correct coordinates.
                this._offset.x = res.x - screenPos.x;
                this._offset.y = res.y - screenPos.y;
            } else {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            if (!this._robotInitialized) {
                this._robotInitialized = true;
                this.$raiseEvent("robotInitialized");
            }
        },

        _callCallback : function (response, cb) {
            if (!response.success) {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            this.$callback(cb);
        },

        viewportToAbsolute : function (position) {
            var screenPos = this._getScreenPos();
            var offset = this._offset;
            return {
                x : screenPos.x + offset.x + this.offsetX + position.x,
                y : screenPos.y + offset.y + this.offsetY + position.y
            };
        },

        absoluteMouseMove : function (position, cb) {
            this._robot.mouseMove(position.x, position.y, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        absoluteSmoothMouseMove : function (from, to, duration, cb) {
            this._robot.smoothMouseMove(from.x, from.y, to.x, to.y, duration, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseMove : function (position, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (position.x < 0 || position.y < 0 || position.x > viewport.width || position.y > viewport.height) {
                this.$logError(this.POSITION_OUTSIDE_VIEWPORT_ERROR);
                this.$callback(cb);
                return;
            }
            this.absoluteMouseMove(this.viewportToAbsolute(position), cb);
        },

        smoothMouseMove : function (from, to, duration, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (from.x < 0 || from.y < 0 || from.x > viewport.width || from.y > viewport.height || to.x < 0 || to.y < 0
                    || to.x > viewport.width || to.y > viewport.height) {
                this.$logError(this.POSITION_OUTSIDE_VIEWPORT_ERROR);
                this.$callback(cb);
                return;
            }
            this.absoluteSmoothMouseMove(this.viewportToAbsolute(from), this.viewportToAbsolute(to), duration, cb);
        },

        mousePress : function (buttons, cb) {
            this._robot.mousePress(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseRelease : function (buttons, cb) {
            this._robot.mouseRelease(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseWheel : function (wheelAmt, cb) {
            this._robot.mouseWheel(wheelAmt, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        keyPress : function (keyCode, cb) {
            // IE sometimes miss some keystrokes, that's why we are adding a 100 ms
            // delay before each keypress (which experimentally seems to help...)
            // http://answers.microsoft.com/en-us/ie/forum/ie8-windows_other/internet-explorer-missing-keystroke-problem/1bee2ec3-828c-4a3d-8b05-638e44baf0a8
            ariaCoreTimer.addCallback({
                fn : this._keyPress,
                scope : this,
                args : {
                    keyCode : keyCode,
                    cb : cb
                },
                delay : ariaCoreBrowser.isIE ? 100 : 1
            });
        },

        _keyPress : function (args) {
            this._robot.keyPress(args.keyCode, {
                scope : this,
                fn : this._callCallback,
                args : args.cb
            });
        },

        keyRelease : function (keycode, cb) {
            this._robot.keyRelease(keycode, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        }
    }
});
<|endoftext|>


<commit_before>"use strict";

function ArethusaMocks() {
  var self = this;

  function mockFn() {}
  function mockFnWithObject() { return {}; }

  function initOnly(customizations) {
    return withCustomizations({
      init: mockFn
    }, customizations);
  }

  function withCustomizations(obj, overrides) {
    return angular.extend(obj, overrides);
  }

  this.configurator = function(customizations) {
    return withCustomizations({
      getConfAndDelegate: mockFn,
      delegateConf: mockFn,
      getStickyConf: mockFn,
      provideResource: mockFnWithObject,
      configurationFor: mockFnWithObject,
      getRetrievers: mockFnWithObject
    }, customizations);
  };

  this.keyCapture = function(customizations) {
    return withCustomizations({
      initCaptures: mockFnWithObject
    }, customizations);
  };

  this.saver = initOnly;
  this.history = initOnly;

  this.notifier = function(customizations) {
    return withCustomizations({
      init: mockFn,
      success: mockFn,
      info: mockFn,
      error: mockFn,
      wait: mockFn,
      warning: mockFn
    }, customizations);
  };

  this.navigator = function(customizations) {
    return withCustomizations({
      init: mockFn,
      reset: mockFn,
      addToken: mockFn,
      removeToken: mockFn
    });
  };

  this.idHandler = function(customizations) {
    return withCustomizations({
      unassignSourceId: mockFn
    });
  };

  this.plugins = function(customizations) {
    return withCustomizations({
      startUp: mockFn,
      init: mockFn,
      all: {},
      main: [],
      sub: [],
      withMenu: [],
      declareReady: mockFn
    });
  };

  this.globalSettings = function(customizations) {
    return withCustomizations({
      // more to come
      init: mockFn
    });
  };

  this.resolvedConfirmationDialog = function(customizations) {
    return withCustomizations({
      ask: function() {
        return {
          then: function(success) {
            success();
          }
        };
      }
    });
  };

  this.rejectedConfirmationDialog = function(customizations) {
    return withCustomizations({
      ask: function() {
        return {
          then: function(success, error) {
            error();
          }
        };
      }
    });
  };

  this.tokens = function() {
    return {
      '01': {
        id: '01',
        string: 'Arma',
        relation: {
          label: "OBJ_CO"
        },
        head: {
          id: '03'
        },
        morphology: {
          lemma: 'lemma1',
          postag: 'n'
        }
      },
      '02': {
        id: '02',
        string: 'virum',
        relation: {
          label: "OBJ_CO"
        },
        head: {
          id: '03'
        },
        morphology: {
          lemma: 'lemma2',
          postag: 'a1'
        }
      },
      '03': {
        id: '03',
        string: '-que',
        relation: {
          label: "COORD"
        },
        head: {
          id: '04'
        }
      },
      '04': {
        id: '04',
        string: 'cano',
        head: {
          id: '00'
        },
        relation: {
          label: "PRED"
        }
      }
    };
  };
}

var arethusaMocks = new ArethusaMocks();
<commit_msg>adding comments to explain behavior reported in #673<commit_after>"use strict";

function ArethusaMocks() {
  var self = this;

  function mockFn() {}
  function mockFnWithObject() { return {}; }

  function initOnly(customizations) {
    return withCustomizations({
      init: mockFn
    }, customizations);
  }

  function withCustomizations(obj, overrides) {
    return angular.extend(obj, overrides);
  }

  this.configurator = function(customizations) {
    return withCustomizations({
      getConfAndDelegate: mockFn,
      delegateConf: mockFn,
      getStickyConf: mockFn,
      provideResource: mockFnWithObject,
      configurationFor: mockFnWithObject,
      getRetrievers: mockFnWithObject
    }, customizations);
  };

  this.keyCapture = function(customizations) {
    return withCustomizations({
      initCaptures: mockFnWithObject
    }, customizations);
  };

  this.saver = initOnly;
  this.history = initOnly;

  this.notifier = function(customizations) {
    return withCustomizations({
      init: mockFn,
      success: mockFn,
      info: mockFn,
      error: mockFn,
      wait: mockFn,
      warning: mockFn
    }, customizations);
  };

  this.navigator = function(customizations) {
    return withCustomizations({
      init: mockFn,
      reset: mockFn,
      addToken: mockFn,
      removeToken: mockFn
    });
  };

  this.idHandler = function(customizations) {
    return withCustomizations({
      unassignSourceId: mockFn
    });
  };

  this.plugins = function(customizations) {
    return withCustomizations({
      startUp: mockFn,
      init: mockFn,
      all: {},
      main: [],
      sub: [],
      withMenu: [],
      declareReady: mockFn
    });
  };

  this.globalSettings = function(customizations) {
    return withCustomizations({
      // more to come
      init: mockFn
    });
  };

  this.resolvedConfirmationDialog = function(customizations) {
    return withCustomizations({
      ask: function() {
        return {
          then: function(success) {
            success();
          }
        };
      }
    });
  };

  this.rejectedConfirmationDialog = function(customizations) {
    return withCustomizations({
      ask: function() {
        return {
          then: function(success, error) {
            error();
          }
        };
      }
    });
  };

  this.tokens = function() {
    return {
      '01': {
        id: '01',
        string: 'Arma',
        relation: {
          label: "OBJ_CO"
        },
        head: {
          id: '03'
        },
        morphology: {
          lemma: 'lemma1',
          postag: 'n-' // explicitly using an empty postag component here to test behavior
        }
      },
      '02': {
        id: '02',
        string: 'virum',
        relation: {
          label: "OBJ_CO"
        },
        head: {
          id: '03'
        },
        morphology: {
          lemma: 'lemma2',
          postag: 'a1'
        }
      },
      '03': {
        id: '03',
        string: '-que',
        relation: {
          label: "COORD"
        },
        head: {
          id: '04'
        }
      },
      '04': {
        id: '04',
        string: 'cano',
        head: {
          id: '00'
        },
        relation: {
          label: "PRED"
        }
      }
    };
  };
}

var arethusaMocks = new ArethusaMocks();
<|endoftext|>


<commit_before>/*eslint-env browser */
/*global $, Modernizr, hopscotch */

$(document).ready(function() {
    // 'use strict'; // uncomment later on after full cleanup
    var citedGreaterThan = $('#id_cited_gt');
    var citedLessThan = $('#id_cited_lt');

    function makeSearchPath(tabSwitch) {
        // Empty the sliders if they are both at their max
        if (citedGreaterThan.val() === 0 && citedLessThan.val() === 20000) {
        // see https://github.com/freelawproject/courtlistener/issues/303
            citedGreaterThan.val('');
            citedLessThan.val('');
        }

        // Gather all form fields that are necessary
        var gathered = $();

        // If the user is switching tabs, then make sure their ordering is
        // valid for the tab they're headed to.
        var dropDown = $('#id_order_by');
        if (tabSwitch){
            var value;
            switch (dropDown.val()) {
                case 'dateFiled desc':
                    value = 'dateArgued desc';
                    break;
                case 'dateFiled asc':
                    value = 'dateArgued asc';
                    break;
                case 'dateArgued desc':
                    value = 'dateFiled desc';
                    break;
                case 'dateArgued asc':
                    value = 'dateFiled asc';
                    break;
                default:
                    value = 'score desc';
                    break;
            }
            var el = $('<input type="hidden" name="order_by" />').val(value);
            gathered = gathered.add(el);
        } else {
            // Not a tab switch; make sure to gather the element regardless.
            gathered = gathered.add(dropDown);
        }

        // Add the input boxes that aren't empty
        var selector = '.external-input[type=text]';
        gathered = gathered.add($(selector).filter(function () {
            return this.value !== '';
        }));

        // Add selected radio buttons
        gathered = gathered.add($('.external-input[type=radio]:checked'));

        // Add the court checkboxes that are selected as a single input element
        var checkedCourts = $('.court-checkbox:checked');
        if (checkedCourts.length !== $('.court-checkbox').length) {
            // Only do this if all courts aren't checked to keep URLs short.
            var values = [];
            for (var i = 0; i < checkedCourts.length; i++) {
                values.push(checkedCourts[i].id.split('_')[1]);
            }
            var courtString = values.join(' ');
            var el = jQuery('<input/>', {
                value: courtString,
                name: 'court'
            });
        }
        gathered = gathered.add(el);

        if ($('.status-checkbox:checked').length <= $('.status-checkbox').length) {
            // Add the status checkboxes that are selected
            gathered = gathered.add($('.status-checkbox:checked'));
        }

        // Remove any inputs that are direct children of the form. These are
        // pernicious leftovers caused by the evils of the back button.
        $('#search-form > input').remove();

        gathered.each(function () {
            // Make and submit a hidden input element for all gathered fields
            var el = $(this);
            $('<input type="hidden" name="' + el.attr('name') + '" />')
                .val(el.val())
                .appendTo('#search-form');
        });
        var path = '/?' + $('#search-form').serialize();
        return path;
    }

    //////////////
    // Homepage //
    //////////////
    function showAdvancedHomepage() {
        $('#homepage #advanced-search-starter, #homepage #search-container td > i').hide();
        $('#homepage #advanced-search-inputs').show('fast').removeClass('hidden');
        $('#main-query-box').addClass('wide');
        $('#id_q').focus();
    }
    $('#homepage #advanced-search-starter a').click(function (event) {
        event.preventDefault();
        showAdvancedHomepage();
    });

    ///////////////////////
    // Search submission //
    ///////////////////////
    $('#search-form, ' +
      '#sidebar-search-form, ' +
      '.search-page #court-picker-search-form').submit(function (e) {
        e.preventDefault();

        // Ensure that the correct value is set in the radio button (correct
        // is defined by the label that is .selected). This is needed because
        // the "wrong" value will be selected after a user presses the back
        // button in their browser.
        $('#type-switcher .selected input').prop('checked', true);

        document.location = makeSearchPath(false);
    });

    $('#id_order_by').change(function () {
        $('#search-form').submit();
    });

    $('#homepage #court-picker-search-form').submit(function(e){
        e.preventDefault();

        // Indicate the count of selected jurisdictions when switching to
        // advanced search page.
        $('#jurisdiction-count').text($(this).find('input:checked').length);
        $('#court-picker').modal('hide');
        showAdvancedHomepage();
        $('#jurisdiction-count').css({
            'background-color': 'yellow',
            'font-weight': 'bold'
        });
        setTimeout(function () {
            $('#jurisdiction-count').css({
                'background-color': 'transparent',
                'font-weight': 'normal'
            });
        }, 1500);
    });

    //////////////////////////
    // Source Tab Switching //
    //////////////////////////
    $('#type-switcher label:not(.selected) input[name=type]').click(function () {
        // Note that we can't do submit here, because that'd trigger a
        // switching of the the checked radio button, and nothing would happen.
        document.location = makeSearchPath(true);
    });

    ////////////
    // Slider //
    ////////////
    /*
    if (cited_gt.val() == "") {
        cited_gt.val(0);
    }
    if (cited_lt.val() == ""){
        cited_lt.val(20000);
    }
    $(function() {
        // Load up the slider in the UI
        $("#slider-range").slider({
            range: true,
            min: 0,
            max: 20000,
            step: 10,
            values: [cited_gt.val(),
                     cited_lt.val()],
            slide: function(event, ui) {
                // Update the text
                if (ui.values[0] == 0 && ui.values[1] == 20000){
                    $('#citation-count').text("(Any)");
                } else {
                    $("#citation-count").text( "(" + ui.values[0] + " - " + ui.values[1] + ")");
                }
                cited_gt.val(ui.values[0]);
                cited_lt.val(ui.values[1]);
            }
        });
    });
    if (cited_gt.val() != 0 || cited_lt.val() != 20000) {
        $('#citation-count').text("(" + $("#id_cited_gt").val() + " - " + $("#id_cited_lt").val() + ")")
    }
    */

    //////////////////
    // Court Picker //
    //////////////////
    function listFilter(list, input) {
        var checkboxSections = list.find('.sidebar-checkbox');
        function filter() {
            var regex = new RegExp('\\b' + this.value, 'i');
            var $els = checkboxSections.filter(function () {
                return regex.test($(this).find('label').text());
            });
            checkboxSections.not($els).find('input').prop('checked', false);
            $els.find('input').prop('checked', true);
        }
        input.keyup(filter).change(filter);
    }
    jQuery(function ($) {
        listFilter($('.tab-content'), $('#court-filter'));
    });

    // Check/clear the tab/everything
    $('#check-all').click(function() {
        $('#modal-court-picker .tab-pane input').prop('checked', true);
    });
    $('#clear-all').click(function () {
        $('#modal-court-picker .tab-pane input').prop('checked', false);
    });
    $('#check-current').click(function () {
        $('#modal-court-picker .tab-pane.active input').prop('checked', true);
    });
    $('#clear-current').click(function () {
        $('#modal-court-picker .tab-pane.active input').prop('checked', false);
    });

    ////////////////
    // Auto Focus //
    ////////////////
    $('.auto-focus:first').focus();

    //////////
    // Tour //
    //////////
    var tour = {
        id: 'feature-tour',
        showPrevButton: true,
        steps: [
            {//0
                target: '#id_q',
                placement: 'bottom',
                xOffset: 'center',
                arrowOffset: 'center',
                title: 'Welcome to the Tour!',
                content: 'Broad queries can be a great way to start a ' +
                    'research task. Our search box can understand ' +
                    'everything you might expect… terms, concepts, ' +
                    'citations, you name it.',
                // If the advanced page is already shown, we skip to step 2.
                onNext: function(){
                    if (!$('#advanced-search-starter').is(':visible')){
                        hopscotch.showStep(2);
                    }
                }
            },
            {//1
                target: '#advanced-search-starter',
                placement: 'bottom',
                xOffset: 'center',
                arrowOffset: 'center',
                nextOnTargetClick: true,
                title: 'More Power Please!',
                content: 'If you are the kind of person that wants more ' +
                    'power, you\'ll love the advanced search box. ' +
                    'Click on \"Advanced Search\" to turn it on.',
                onNext: function(){
                    showAdvancedHomepage();
                }
            },
            {//2
                target: '#extra-sidebar-fields',
                placement: 'right',
                arrowOffset: 'center',
                title: 'Sophisticated Search',
                content: 'In the Advanced Search area, you can make ' +
                    'sophisticated searches against many fields. ' +
                    'Press \"Next\" and we\'ll make a query for you.',
                multipage: true,
                showPrevButton: false,
                onNext: function(){
                    window.location = '/?q=roe+v.+wade&order_by=score+desc&stat_Precedential=on&court=scotus';
                },
                delay: 250 // let advanced search area get exposed.
            },
            {//3
                // This step will be skipped if on a dev machine with no
                // results. Be not alarmed!
                target: document.querySelector('.search-page article'),
                placement: 'top',
                arrowOffset: 'center',
                title: 'Detailed Results',
                content: 'Here you can see the results for the query "Roe ' +
                    'v. Wade" sorted by relevance and filtered to only one ' +
                    'jurisdiction, the Supreme Court.',
                showPrevButton: false
            },
            {//4
                target: '#type-switcher',
                placement: 'right',
                arrowOffset: 'top',
                title: 'What are you Looking For?',
                content: 'By default you\'ll get opinion results, but use ' +
                    'this to work with oral arguments instead.'
            },
            {//5
                target: '#create-alert-header',
                placement: 'right',
                arrowOffset: 'center',
                title: 'Make Alerts',
                content: '
Once you have placed a query, you can create ' +
                    'an alert. If there are ever any new results for your ' +
                    'query, CourtListener will send you an email to keep ' +
                    'you up to date.

Hit next to check out Roe ' +
                    'v. Wade.
',
                multipage: true,
                onNext: function(){
                    window.location = '/opinion/108713/roe-v-wade/';
                }
            },
            {//6
                target: '#cited-by',
                placement: 'right',
                arrowOffset: 'center',
                title: 'The Power of Citation',
                content: 'Roe v. Wade has been cited hundreds of times since ' +
                    'it was issued in 1973. Looking at these citations can ' +
                    'be a good way to see related cases.'
            },
            {//7
                target: '#authorities',
                placement: 'right',
                arrowOffset: 'center',
                title: 'Authorities',
                content: '
The Authorities section lists all of the ' +
                    'opinions that Roe v. Wade references. These can be ' +
                    'thought of as the principles it rests on.
' +
                    '
That\'s everything for now! Let us know if ' +
                    'you have any questions.
',
                onNext: function(){
                    hopscotch.endTour();
                }
            }
        ]
    };

    $('.tour-link').click(function (event) {
        event.preventDefault();
        var loc = location.pathname + location.search;
        if (loc !== '/') {
            sessionStorage.setItem('hopscotch.tour.state', 'feature-tour:0');
            window.location = '/';
        } else {
            hopscotch.startTour(tour, 0);
        }
    });
    // Start it automatically for certain steps.
    if (hopscotch.getState() === 'feature-tour:0') {
        hopscotch.startTour(tour);
    }
    if (hopscotch.getState() === 'feature-tour:3') {
        hopscotch.startTour(tour);
    }
    if (hopscotch.getState() === 'feature-tour:6') {
        hopscotch.startTour(tour);
    }
});

Modernizr.load({
    // Sets up HTML5 input placeholders in browsers that don't support them.
    test: Modernizr.placeholder,
    nope: '/static/js/placeholder-1.8.6.min.js',
    complete: function () {
        $('input, textarea').placeholder();
    }
});
<commit_msg>restored functionality to court-filter input, cleaned up in the process<commit_after>/*eslint-env browser */
/*global $, Modernizr, hopscotch */

$(document).ready(function() {
    // 'use strict'; // uncomment later on after full cleanup
    var citedGreaterThan = $('#id_cited_gt');
    var citedLessThan = $('#id_cited_lt');

    function makeSearchPath(tabSwitch) {
        // Empty the sliders if they are both at their max
        if (citedGreaterThan.val() === 0 && citedLessThan.val() === 20000) {
        // see https://github.com/freelawproject/courtlistener/issues/303
            citedGreaterThan.val('');
            citedLessThan.val('');
        }

        // Gather all form fields that are necessary
        var gathered = $();

        // If the user is switching tabs, then make sure their ordering is
        // valid for the tab they're headed to.
        var dropDown = $('#id_order_by');
        if (tabSwitch){
            var value;
            switch (dropDown.val()) {
                case 'dateFiled desc':
                    value = 'dateArgued desc';
                    break;
                case 'dateFiled asc':
                    value = 'dateArgued asc';
                    break;
                case 'dateArgued desc':
                    value = 'dateFiled desc';
                    break;
                case 'dateArgued asc':
                    value = 'dateFiled asc';
                    break;
                default:
                    value = 'score desc';
                    break;
            }
            var el = $('<input type="hidden" name="order_by" />').val(value);
            gathered = gathered.add(el);
        } else {
            // Not a tab switch; make sure to gather the element regardless.
            gathered = gathered.add(dropDown);
        }

        // Add the input boxes that aren't empty
        var selector = '.external-input[type=text]';
        gathered = gathered.add($(selector).filter(function () {
            return this.value !== '';
        }));

        // Add selected radio buttons
        gathered = gathered.add($('.external-input[type=radio]:checked'));

        // Add the court checkboxes that are selected as a single input element
        var checkedCourts = $('.court-checkbox:checked');
        if (checkedCourts.length !== $('.court-checkbox').length) {
            // Only do this if all courts aren't checked to keep URLs short.
            var values = [];
            for (var i = 0; i < checkedCourts.length; i++) {
                values.push(checkedCourts[i].id.split('_')[1]);
            }
            var courtString = values.join(' ');
            var el = jQuery('<input/>', {
                value: courtString,
                name: 'court'
            });
        }
        gathered = gathered.add(el);

        if ($('.status-checkbox:checked').length <= $('.status-checkbox').length) {
            // Add the status checkboxes that are selected
            gathered = gathered.add($('.status-checkbox:checked'));
        }

        // Remove any inputs that are direct children of the form. These are
        // pernicious leftovers caused by the evils of the back button.
        $('#search-form > input').remove();

        gathered.each(function () {
            // Make and submit a hidden input element for all gathered fields
            var el = $(this);
            $('<input type="hidden" name="' + el.attr('name') + '" />')
                .val(el.val())
                .appendTo('#search-form');
        });
        var path = '/?' + $('#search-form').serialize();
        return path;
    }

    //////////////
    // Homepage //
    //////////////
    function showAdvancedHomepage() {
        $('#homepage #advanced-search-starter, #homepage #search-container td > i').hide();
        $('#homepage #advanced-search-inputs').show('fast').removeClass('hidden');
        $('#main-query-box').addClass('wide');
        $('#id_q').focus();
    }
    $('#homepage #advanced-search-starter a').click(function (event) {
        event.preventDefault();
        showAdvancedHomepage();
    });

    ///////////////////////
    // Search submission //
    ///////////////////////
    $('#search-form, ' +
      '#sidebar-search-form, ' +
      '.search-page #court-picker-search-form').submit(function (e) {
        e.preventDefault();

        // Ensure that the correct value is set in the radio button (correct
        // is defined by the label that is .selected). This is needed because
        // the "wrong" value will be selected after a user presses the back
        // button in their browser.
        $('#type-switcher .selected input').prop('checked', true);

        document.location = makeSearchPath(false);
    });

    $('#id_order_by').change(function () {
        $('#search-form').submit();
    });

    $('#homepage #court-picker-search-form').submit(function(e){
        e.preventDefault();

        // Indicate the count of selected jurisdictions when switching to
        // advanced search page.
        $('#jurisdiction-count').text($(this).find('input:checked').length);
        $('#court-picker').modal('hide');
        showAdvancedHomepage();
        $('#jurisdiction-count').css({
            'background-color': 'yellow',
            'font-weight': 'bold'
        });
        setTimeout(function () {
            $('#jurisdiction-count').css({
                'background-color': 'transparent',
                'font-weight': 'normal'
            });
        }, 1500);
    });

    //////////////////////////
    // Source Tab Switching //
    //////////////////////////
    $('#type-switcher label:not(.selected) input[name=type]').click(function () {
        // Note that we can't do submit here, because that'd trigger a
        // switching of the the checked radio button, and nothing would happen.
        document.location = makeSearchPath(true);
    });

    ////////////
    // Slider //
    ////////////
    /*
    if (cited_gt.val() == "") {
        cited_gt.val(0);
    }
    if (cited_lt.val() == ""){
        cited_lt.val(20000);
    }
    $(function() {
        // Load up the slider in the UI
        $("#slider-range").slider({
            range: true,
            min: 0,
            max: 20000,
            step: 10,
            values: [cited_gt.val(),
                     cited_lt.val()],
            slide: function(event, ui) {
                // Update the text
                if (ui.values[0] == 0 && ui.values[1] == 20000){
                    $('#citation-count').text("(Any)");
                } else {
                    $("#citation-count").text( "(" + ui.values[0] + " - " + ui.values[1] + ")");
                }
                cited_gt.val(ui.values[0]);
                cited_lt.val(ui.values[1]);
            }
        });
    });
    if (cited_gt.val() != 0 || cited_lt.val() != 20000) {
        $('#citation-count').text("(" + $("#id_cited_gt").val() + " - " + $("#id_cited_lt").val() + ")")
    }
    */

    //////////////////
    // Court Picker //
    //////////////////
    function courtFilter () {
        var tabs = $('.tab-content'),
            checkboxes = tabs.find('.checkbox'),
            regex = new RegExp('\\b' + this.value, 'i'),
            matches = checkboxes.filter(function () {
                return regex.test($(this).find('label').text());
            });
        checkboxes.not(matches).find('input').prop('checked', false);
        matches.find('input').prop('checked', true);
    }

    $('#court-filter').keyup(courtFilter).change(courtFilter);

    // Check/clear the tab/everything
    $('#check-all').click(function() {
        $('#modal-court-picker .tab-pane input').prop('checked', true);
    });
    $('#clear-all').click(function () {
        $('#modal-court-picker .tab-pane input').prop('checked', false);
    });
    $('#check-current').click(function () {
        $('#modal-court-picker .tab-pane.active input').prop('checked', true);
    });
    $('#clear-current').click(function () {
        $('#modal-court-picker .tab-pane.active input').prop('checked', false);
    });

    ////////////////
    // Auto Focus //
    ////////////////
    $('.auto-focus:first').focus();

    //////////
    // Tour //
    //////////
    var tour = {
        id: 'feature-tour',
        showPrevButton: true,
        steps: [
            {//0
                target: '#id_q',
                placement: 'bottom',
                xOffset: 'center',
                arrowOffset: 'center',
                title: 'Welcome to the Tour!',
                content: 'Broad queries can be a great way to start a ' +
                    'research task. Our search box can understand ' +
                    'everything you might expect… terms, concepts, ' +
                    'citations, you name it.',
                // If the advanced page is already shown, we skip to step 2.
                onNext: function(){
                    if (!$('#advanced-search-starter').is(':visible')){
                        hopscotch.showStep(2);
                    }
                }
            },
            {//1
                target: '#advanced-search-starter',
                placement: 'bottom',
                xOffset: 'center',
                arrowOffset: 'center',
                nextOnTargetClick: true,
                title: 'More Power Please!',
                content: 'If you are the kind of person that wants more ' +
                    'power, you\'ll love the advanced search box. ' +
                    'Click on \"Advanced Search\" to turn it on.',
                onNext: function(){
                    showAdvancedHomepage();
                }
            },
            {//2
                target: '#extra-sidebar-fields',
                placement: 'right',
                arrowOffset: 'center',
                title: 'Sophisticated Search',
                content: 'In the Advanced Search area, you can make ' +
                    'sophisticated searches against many fields. ' +
                    'Press \"Next\" and we\'ll make a query for you.',
                multipage: true,
                showPrevButton: false,
                onNext: function(){
                    window.location = '/?q=roe+v.+wade&order_by=score+desc&stat_Precedential=on&court=scotus';
                },
                delay: 250 // let advanced search area get exposed.
            },
            {//3
                // This step will be skipped if on a dev machine with no
                // results. Be not alarmed!
                target: document.querySelector('.search-page article'),
                placement: 'top',
                arrowOffset: 'center',
                title: 'Detailed Results',
                content: 'Here you can see the results for the query "Roe ' +
                    'v. Wade" sorted by relevance and filtered to only one ' +
                    'jurisdiction, the Supreme Court.',
                showPrevButton: false
            },
            {//4
                target: '#type-switcher',
                placement: 'right',
                arrowOffset: 'top',
                title: 'What are you Looking For?',
                content: 'By default you\'ll get opinion results, but use ' +
                    'this to work with oral arguments instead.'
            },
            {//5
                target: '#create-alert-header',
                placement: 'right',
                arrowOffset: 'center',
                title: 'Make Alerts',
                content: '
Once you have placed a query, you can create ' +
                    'an alert. If there are ever any new results for your ' +
                    'query, CourtListener will send you an email to keep ' +
                    'you up to date.

Hit next to check out Roe ' +
                    'v. Wade.
',
                multipage: true,
                onNext: function(){
                    window.location = '/opinion/108713/roe-v-wade/';
                }
            },
            {//6
                target: '#cited-by',
                placement: 'right',
                arrowOffset: 'center',
                title: 'The Power of Citation',
                content: 'Roe v. Wade has been cited hundreds of times since ' +
                    'it was issued in 1973. Looking at these citations can ' +
                    'be a good way to see related cases.'
            },
            {//7
                target: '#authorities',
                placement: 'right',
                arrowOffset: 'center',
                title: 'Authorities',
                content: '
The Authorities section lists all of the ' +
                    'opinions that Roe v. Wade references. These can be ' +
                    'thought of as the principles it rests on.
' +
                    '
That\'s everything for now! Let us know if ' +
                    'you have any questions.
',
                onNext: function(){
                    hopscotch.endTour();
                }
            }
        ]
    };

    $('.tour-link').click(function (event) {
        event.preventDefault();
        var loc = location.pathname + location.search;
        if (loc !== '/') {
            sessionStorage.setItem('hopscotch.tour.state', 'feature-tour:0');
            window.location = '/';
        } else {
            hopscotch.startTour(tour, 0);
        }
    });
    // Start it automatically for certain steps.
    if (hopscotch.getState() === 'feature-tour:0') {
        hopscotch.startTour(tour);
    }
    if (hopscotch.getState() === 'feature-tour:3') {
        hopscotch.startTour(tour);
    }
    if (hopscotch.getState() === 'feature-tour:6') {
        hopscotch.startTour(tour);
    }
});

Modernizr.load({
    // Sets up HTML5 input placeholders in browsers that don't support them.
    test: Modernizr.placeholder,
    nope: '/static/js/placeholder-1.8.6.min.js',
    complete: function () {
        $('input, textarea').placeholder();
    }
});
<|endoftext|>


<commit_before>/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
ABOUT THIS NODE.JS EXAMPLE: This example works with the AWS SDK for JavaScript version 3 (v3),
which is available at https://github.com/aws/aws-sdk-js-v3. This example is in the 'AWS SDK for JavaScript v3 Developer Guide' at
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-examples.html.

Purpose:
ddbDocClient.js is a helper function that creates an Amazon DynamoDB service document client.

INPUTS:
- REGION

*/
// snippet-start:[dynamodb.JavaScript.tables.createdocclientv3]
// Create service client module using ES6 syntax.
import { DynamoDBDocumentClient} from "@aws-sdk/lib-dynamodb";
import {ddbClient} from "./ddbClient";
// Set the AWS Region.
const REGION = "REGION"; //e.g. "us-east-1"

const marshallOptions = {
    // Whether to automatically convert empty strings, blobs, and sets to `null`.
    convertEmptyValues: false, // false, by default.
    // Whether to remove undefined values while marshalling.
    removeUndefinedValues: false, // false, by default.
    // Whether to convert typeof object to map attribute.
    convertClassInstanceToMap: false, // false, by default.
};

const unmarshallOptions = {
    // Whether to return numbers as a string instead of converting them to native JavaScript numbers.
    wrapNumbers: false, // false, by default.
};

const translateConfig = { marshallOptions, unmarshallOptions };

// Create the DynamoDB Document client.
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig);

export { ddbDocClient };
// snippet-end:[dynamodb.JavaScript.tables.createdocclientv3]

<commit_msg>Removed unused REGION<commit_after>/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
ABOUT THIS NODE.JS EXAMPLE: This example works with the AWS SDK for JavaScript version 3 (v3),
which is available at https://github.com/aws/aws-sdk-js-v3. This example is in the 'AWS SDK for JavaScript v3 Developer Guide' at
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-examples.html.

Purpose:
ddbDocClient.js is a helper function that creates an Amazon DynamoDB service document client.

*/
// snippet-start:[dynamodb.JavaScript.tables.createdocclientv3]
// Create service client module using ES6 syntax.
import { DynamoDBDocumentClient} from "@aws-sdk/lib-dynamodb";
import {ddbClient} from "./ddbClient";

const marshallOptions = {
    // Whether to automatically convert empty strings, blobs, and sets to `null`.
    convertEmptyValues: false, // false, by default.
    // Whether to remove undefined values while marshalling.
    removeUndefinedValues: false, // false, by default.
    // Whether to convert typeof object to map attribute.
    convertClassInstanceToMap: false, // false, by default.
};

const unmarshallOptions = {
    // Whether to return numbers as a string instead of converting them to native JavaScript numbers.
    wrapNumbers: false, // false, by default.
};

const translateConfig = { marshallOptions, unmarshallOptions };

// Create the DynamoDB Document client.
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig);

export { ddbDocClient };
// snippet-end:[dynamodb.JavaScript.tables.createdocclientv3]

<|endoftext|>


<commit_before>export default {
  props: {
    autofocus: [Boolean, String],
    maxHeight: Number,
    loading: Boolean
  },
  data () {
    return {
      focused: false,
      timer: null,
      isNumberError: false,
      isNegZero: false
    }
  },
  methods: {
    focus () {
      if (!this.disable) {
        this.$refs.input.focus()
      }
    },
    blur () {
      this.$refs.input && this.$refs.input.blur()
    },
    select () {
      this.$refs.input.select()
    },

    __onFocus (e) {
      clearTimeout(this.timer)
      if (this.focused) {
        return
      }
      this.focused = true
      this.$refs.input && this.$refs.input.focus()
      this.$emit('focus', e)
    },
    __onInputBlur (e) {
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.__onBlur(e)
      }, 200)
    },
    __onBlur (e, destroy) {
      if (this.focused) {
        this.focused = false
        this.$emit('blur', e)
      }
      this.__emit(destroy)
    },
    __emit (destroy) {
      const isNumberError = this.isNumber && this.isNumberError
      const value = isNumberError ? (this.isNegZero ? -0 : null) : this.model
      if (this.isNumber) {
        this.model = this.value
      }
      if (isNumberError) {
        this.$emit('input', value)
      }
      const emit = () => {
        if (this.isNumber) {
          if (String(1 / value) !== String(1 / this.value)) {
            this.$emit('change', value)
          }
        }
        else if (JSON.stringify(value) !== JSON.stringify(this.value)) {
          this.$emit('change', value)
        }
      }
      destroy ? emit() : this.$nextTick(emit)
    },
    __onKeydown (e) {
      if (e.keyCode === 13) {
        if (this.type === 'textarea') {
          e.stopPropagation()
        }
        else {
          this.__emit()
        }
      }
      this.$emit('keydown', e)
    },
    __onKeyup (e) {
      this.$emit('keyup', e)
    },
    __onClick (e) {
      this.focus()
      this.$emit('click', e)
    },
    __onPaste (e) {
      this.$emit('paste', e)
    }
  },
  mounted () {
    this.$nextTick(() => {
      const input = this.$refs.input
      if (this.autofocus && input) {
        input.focus()
        if (this.autofocus === 'select') {
          input.select()
        }
      }
    })
  },
  beforeDestroy () {
    clearTimeout(this.timer)
    this.focused && this.__onBlur(void 0, true)
  }
}
<commit_msg>QInput: add forgotten cast to number when type is number in __emit (#2605)<commit_after>export default {
  props: {
    autofocus: [Boolean, String],
    maxHeight: Number,
    loading: Boolean
  },
  data () {
    return {
      focused: false,
      timer: null,
      isNumberError: false,
      isNegZero: false
    }
  },
  methods: {
    focus () {
      if (!this.disable) {
        this.$refs.input.focus()
      }
    },
    blur () {
      this.$refs.input && this.$refs.input.blur()
    },
    select () {
      this.$refs.input.select()
    },

    __onFocus (e) {
      clearTimeout(this.timer)
      if (this.focused) {
        return
      }
      this.focused = true
      this.$refs.input && this.$refs.input.focus()
      this.$emit('focus', e)
    },
    __onInputBlur (e) {
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.__onBlur(e)
      }, 200)
    },
    __onBlur (e, destroy) {
      if (this.focused) {
        this.focused = false
        this.$emit('blur', e)
      }
      this.__emit(destroy)
    },
    __emit (destroy) {
      const isNumberError = this.isNumber && this.isNumberError
      let value = isNumberError ? (this.isNegZero ? -0 : null) : this.model
      if (this.isNumber) {
        this.model = this.value
      }
      if (isNumberError) {
        this.$emit('input', value)
      }
      const emit = () => {
        if (this.isNumber) {
          value = parseFloat(value)
          if (Number.isInteger(this.decimals)) {
            value = parseFloat(value.toFixed(this.decimals))
          }
          if (String(1 / value) !== String(1 / this.value)) {
            this.$emit('change', value)
          }
        }
        else if (JSON.stringify(value) !== JSON.stringify(this.value)) {
          this.$emit('change', value)
        }
      }
      destroy ? emit() : this.$nextTick(emit)
    },
    __onKeydown (e) {
      if (e.keyCode === 13) {
        if (this.type === 'textarea') {
          e.stopPropagation()
        }
        else {
          this.__emit()
        }
      }
      this.$emit('keydown', e)
    },
    __onKeyup (e) {
      this.$emit('keyup', e)
    },
    __onClick (e) {
      this.focus()
      this.$emit('click', e)
    },
    __onPaste (e) {
      this.$emit('paste', e)
    }
  },
  mounted () {
    this.$nextTick(() => {
      const input = this.$refs.input
      if (this.autofocus && input) {
        input.focus()
        if (this.autofocus === 'select') {
          input.select()
        }
      }
    })
  },
  beforeDestroy () {
    clearTimeout(this.timer)
    this.focused && this.__onBlur(void 0, true)
  }
}
<|endoftext|>


<commit_before>/**
 * Adds support for events to any Object prototype.
 *
 * Example:
 *
 *   var MyClass = function() {}
 *   Eventable(MyClass, ['something']);
 *
 *   MyClass.prototype.doSomething = function()
 *   {
 *     var event = this.createEvent('something');
 *     this.dispatchEvent(event);
 *   }
 *
 *   MyClass.addEventListener('something', function(event) {});
 *   MyClass.onsomething = function(event) {};
 *
 *   MyClass.doSomething();
 */
var Eventable = function(object, types)
{
  types.forEach(function(type)
  {
    if (typeof object.prototype['on' + type] != 'undefined') {
      throw new Error("Event type '" + type + "' already defined.");
    }
    object.prototype['on' + type] = function(event) {}
  });

  if (typeof object.prototype.addEventListener == 'undefined')
  {
    // Adds an event listener to this object.
    object.prototype.addEventListener = function(type, callback)
    {
      if (typeof this['on' + type] == 'undefined') {
        throw new Error("No such event type '" + type + "'");
      }
      if (typeof this._eventListeners == 'undefined') {
        this._eventListeners = {};
      }
      if (typeof this._eventListeners[type] == 'undefined') {
        this._eventListeners[type] = [];
      }
      this._eventListeners[type].push(callback)
    }
  }

  if (typeof object.prototype.removeEventListener == 'undefined')
  {
    // Removes an event listener from this object.
    object.prototype.removeEventListener = function(type, callback)
    {
      if (typeof this['on' + type] == 'undefined') {
        throw new Error("No such event type '" + type + "'");
      }
      var pos = this._eventListeners[type].indexOf(callback);
      if (pos != -1) {
        this._eventListeners[type].splice(pos, 1)
      }
    }
  }

  if (typeof object.prototype.createEvent == 'undefined')
  {
    /**
     * Simple wrapper to create and initialize a basic Event, to leverage the
     * hassle of manually creating and initializing an event object each and
     * every time you need to dispatch an event.
     *
     * You may overwrite it to return your own custom event objects.
     */
    object.prototype.createEvent = function(type, cancelable)
    {
      if (typeof cancelable == 'undefined') {
        cancelable = true
      }

      var event = new Eventable.Event();
      event.initEvent(type, cancelable);
      return event;
    }
  }

  if (typeof object.prototype.dispatchEvent == 'undefined')
  {
    /**
     * Dispatches an event on this object.
     *
     * Examples:
     *
     *   // actually calls this.createEvent('something')
     *   this.dispatchEvent('something');
     *
     *   // manual call to this.createEvent
     *   this.dispatchEvent(this.createEvent('something', false));
     *
     *   // manual creation and initialization of event:
     *   var event = new Eventable.Event();
     *   event.initEvent('something', true);
     *   this.dispatchEvent(event);
     *
     * FIXME: A callback throwing an exception shouldn't break the chain.
     */
    object.prototype.dispatchEvent = function(event_or_type)
    {
      var event = (typeof event_or_type == 'string') ?
        this.createEvent(event_or_type) : event_or_type;

      if (typeof this['on' + event.type] == 'undefined') {
        throw new Error("No such event type '" + event.type + "'");
      }

      if (this['on' + event.type](event) === true) {
        event.preventDefault();
      }

      if (this._eventListeners && this._eventListeners[event.type])
      {
        for (var i=0, len = this._eventListeners[event.type].length; i<len; i++)
        {
          if (event.propagationStopped === true) {
            break;
          }
          this._eventListeners[event.type][i](event);
        }
      }
      return event.defaultPrevented;
    }
  }
}

/**
 * Basic Event object. Any custom Event object for Eventable must inheritate
 * from it.
 *
 * Example:
 *
 *   var MyEvent = function() {}
 *   MyEvent.prototype = new Eventable.Event();
 *
 *   MyEvent.prototype.initMyEvent = function(type, cancelable, target)
 *   {
 *     Eventable.Event.initEvent.call(this, type, cancelable);
 *     this.target = target;
 *   }
 *
 *   var event = new MyEvent();
 *   event.initMyEvent('type', true, element);
 */
Eventable.Event = function() {}
Eventable.Event.prototype = {
  initEvent: function(type, cancelable)
  {
    this.type = type;
    this.cancelable = cancelable;
    this.defaultPrevented   = null;
    this.propagationStopped = null;
  },

  preventDefault: function()
  {
    if (this.cancelable) {
      this.defaultPrevented = true;
    }
  },

  stopPropagation: function() {
    this.propagationpropagationStopped = true;
  }
}

<commit_msg>Eventable.prototype.dispatchEvent now sets the target to the current object.<commit_after>/**
 * Adds support for events to any Object prototype.
 *
 * Example:
 *
 *   var MyClass = function() {}
 *   Eventable(MyClass, ['something']);
 *
 *   MyClass.prototype.doSomething = function()
 *   {
 *     var event = this.createEvent('something');
 *     this.dispatchEvent(event);
 *   }
 *
 *   MyClass.addEventListener('something', function(event) {});
 *   MyClass.onsomething = function(event) {};
 *
 *   MyClass.doSomething();
 */
var Eventable = function(object, types)
{
  types.forEach(function(type)
  {
    if (typeof object.prototype['on' + type] != 'undefined') {
      throw new Error("Event type '" + type + "' already defined.");
    }
    object.prototype['on' + type] = function(event) {}
  });

  if (typeof object.prototype.addEventListener == 'undefined')
  {
    // Adds an event listener to this object.
    object.prototype.addEventListener = function(type, callback)
    {
      if (typeof this['on' + type] == 'undefined') {
        throw new Error("No such event type '" + type + "'");
      }
      if (typeof this._eventListeners == 'undefined') {
        this._eventListeners = {};
      }
      if (typeof this._eventListeners[type] == 'undefined') {
        this._eventListeners[type] = [];
      }
      this._eventListeners[type].push(callback)
    }
  }

  if (typeof object.prototype.removeEventListener == 'undefined')
  {
    // Removes an event listener from this object.
    object.prototype.removeEventListener = function(type, callback)
    {
      if (typeof this['on' + type] == 'undefined') {
        throw new Error("No such event type '" + type + "'");
      }
      var pos = this._eventListeners[type].indexOf(callback);
      if (pos != -1) {
        this._eventListeners[type].splice(pos, 1)
      }
    }
  }

  if (typeof object.prototype.createEvent == 'undefined')
  {
    /**
     * Simple wrapper to create and initialize a basic Event, to leverage the
     * hassle of manually creating and initializing an event object each and
     * every time you need to dispatch an event.
     *
     * You may overwrite it to return your own custom event objects.
     */
    object.prototype.createEvent = function(type, cancelable)
    {
      if (typeof cancelable == 'undefined') {
        cancelable = true
      }

      var event = new Eventable.Event();
      event.initEvent(type, cancelable);
      return event;
    }
  }

  if (typeof object.prototype.dispatchEvent == 'undefined')
  {
    /**
     * Dispatches an event on this object.
     *
     * Examples:
     *
     *   // actually calls this.createEvent('something')
     *   this.dispatchEvent('something');
     *
     *   // manual call to this.createEvent
     *   this.dispatchEvent(this.createEvent('something', false));
     *
     *   // manual creation and initialization of event:
     *   var event = new Eventable.Event();
     *   event.initEvent('something', true);
     *   this.dispatchEvent(event);
     *
     * FIXME: A callback throwing an exception shouldn't break the chain.
     */
    object.prototype.dispatchEvent = function(event_or_type)
    {
      var event = (typeof event_or_type == 'string') ? this.createEvent(event_or_type) : event_or_type;
      event.target = this;

      if (typeof this['on' + event.type] == 'undefined') {
        throw new Error("No such event type '" + event.type + "'");
      }

      if (this['on' + event.type](event) === true) {
        event.preventDefault();
      }

      if (this._eventListeners && this._eventListeners[event.type])
      {
        for (var i=0, len = this._eventListeners[event.type].length; i<len; i++)
        {
          if (event.propagationStopped === true) {
            break;
          }
          this._eventListeners[event.type][i](event);
        }
      }
      return event.defaultPrevented;
    }
  }
}

/**
 * Basic Event object. Any custom Event object for Eventable must inheritate
 * from it.
 *
 * Example:
 *
 *   var MyEvent = function() {}
 *   MyEvent.prototype = new Eventable.Event();
 *
 *   MyEvent.prototype.initMyEvent = function(type, cancelable, target)
 *   {
 *     Eventable.Event.initEvent.call(this, type, cancelable);
 *     this.target = target;
 *   }
 *
 *   var event = new MyEvent();
 *   event.initMyEvent('type', true, element);
 */
Eventable.Event = function() {}
Eventable.Event.prototype = {
  initEvent: function(type, cancelable)
  {
    this.type = type;
    this.cancelable = cancelable;
    this.defaultPrevented   = null;
    this.propagationStopped = null;
  },

  preventDefault: function()
  {
    if (this.cancelable) {
      this.defaultPrevented = true;
    }
  },

  stopPropagation: function() {
    this.propagationpropagationStopped = true;
  }
}

<|endoftext|>