<commit_before>// function completer.
//
// completer should be a class that takes an cell instance
var IPython = (function (IPython) {
    // that will prevent us from misspelling
    "use strict";

    // easier key mapping
    var keycodes = IPython.keyboard.keycodes;

    function prepend_n_prc(str, n) {
        for( var i =0 ; i< n ; i++){
            str = '%'+str ;
        }
        return str;
    }

    function _existing_completion(item, completion_array){
        for( var c in completion_array ) {
            if(completion_array[c].trim().substr(-item.length) == item)
            { return true; }
        }
       return false;
    }

    // what is the common start of all completions
    function shared_start(B, drop_prct) {
        if (B.length == 1) {
            return B[0];
        }
        var A = [];
        var common;
        var min_lead_prct = 10;
        for (var i = 0; i < B.length; i++) {
            var str = B[i].str;
            var localmin = 0;
            if(drop_prct === true){
                while ( str.substr(0, 1) == '%') {
                    localmin = localmin+1;
                    str = str.substring(1);
                }
            }
            min_lead_prct = Math.min(min_lead_prct, localmin);
            A.push(str);
        }

        if (A.length > 1) {
            var tem1, tem2, s;
            A = A.slice(0).sort();
            tem1 = A[0];
            s = tem1.length;
            tem2 = A.pop();
            while (s && tem2.indexOf(tem1) == -1) {
                tem1 = tem1.substring(0, --s);
            }
            if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
                return {
                    str:prepend_n_prc('', min_lead_prct),
                    type: "computed",
                    from: B[0].from,
                    to: B[0].to
                    };
            }
            return {
                str: prepend_n_prc(tem1, min_lead_prct),
                type: "computed",
                from: B[0].from,
                to: B[0].to
            };
        }
        return null;
    }

    var Completer = function (cell) {
        this.cell = cell;
        this.editor = cell.code_mirror;
        var that = this;
        $([IPython.events]).on('status_busy.Kernel', function () {
            that.skip_kernel_completion = true;
        });
        $([IPython.events]).on('status_idle.Kernel', function () {
            that.skip_kernel_completion = false;
        });
    };

    Completer.prototype.startCompletion = function () {
        // call for a 'first' completion, that will set the editor and do some
        // special behavior like autopicking if only one completion available.
        if (this.editor.somethingSelected()) return;
        this.done = false;
        // use to get focus back on opera
        this.carry_on_completion(true);
    };

    // easy access for julia to monkeypatch
    //
    Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;

    Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
        return Completer.reinvoke_re.test(pre_cursor);
    };

    /**
     *
     * pass true as parameter if this is the first invocation of the completer
     * this will prevent the completer to dissmiss itself if it is not on a
     * word boundary like pressing tab after a space, and make it autopick the
     * only choice if there is only one which prevent from popping the UI.  as
     * well as fast-forwarding the typing if all completion have a common
     * shared start
     **/
    Completer.prototype.carry_on_completion = function (first_invocation) {
        // Pass true as parameter if you want the completer to autopick when
        // only one completion. This function is automatically reinvoked at
        // each keystroke with first_invocation = false
        var cur = this.editor.getCursor();
        var line = this.editor.getLine(cur.line);
        var pre_cursor = this.editor.getRange({
            line: cur.line,
            ch: cur.ch - 1
        }, cur);

        // we need to check that we are still on a word boundary
        // because while typing the completer is still reinvoking itself
        // so dismiss if we are on a "bad" caracter
        if (!this.reinvoke(pre_cursor) && !first_invocation) {
            this.close();
            return;
        }

        this.autopick = false;
        if (first_invocation) {
            this.autopick = true;
        }

        // We want a single cursor position.
        if (this.editor.somethingSelected()) {
            return;
        }

        // one kernel completion came back, finish_completing will be called with the results
        // we fork here and directly call finish completing if kernel is busy
        if (this.skip_kernel_completion) {
            this.finish_completing({
                'matches': [],
                matched_text: ""
            });
        } else {
            this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
        }
    };

    Completer.prototype.finish_completing = function (msg) {
        // let's build a function that wrap all that stuff into what is needed
        // for the new completer:
        var content = msg.content;
        var matched_text = content.matched_text;
        var matches = content.matches;

        var cur = this.editor.getCursor();
        var results = CodeMirror.contextHint(this.editor);
        var filtered_results = [];
        //remove results from context completion
        //that are already in kernel completion
        for (var elm in results) {
            if (!_existing_completion(results[elm].str, matches)) {
                filtered_results.push(results[elm]);
            }
        }

        // append the introspection result, in order, at at the beginning of
        // the table and compute the replacement range from current cursor
        // positon and matched_text length.
        for (var i = matches.length - 1; i >= 0; --i) {
            filtered_results.unshift({
                str: matches[i],
                type: "introspection",
                from: {
                    line: cur.line,
                    ch: cur.ch - matched_text.length
                },
                to: {
                    line: cur.line,
                    ch: cur.ch
                }
            });
        }

        // one the 2 sources results have been merge, deal with it
        this.raw_result = filtered_results;

        // if empty result return
        if (!this.raw_result || !this.raw_result.length) return;

        // When there is only one completion, use it directly.
        if (this.autopick && this.raw_result.length == 1) {
            this.insert(this.raw_result[0]);
            return;
        }

        if (this.raw_result.length == 1) {
            // test if first and only completion totally matches
            // what is typed, in this case dismiss
            var str = this.raw_result[0].str;
            var pre_cursor = this.editor.getRange({
                line: cur.line,
                ch: cur.ch - str.length
            }, cur);
            if (pre_cursor == str) {
                this.close();
                return;
            }
        }

        if (!this.visible) {
            console.log('add div');
            this.complete = $('<div/>').addClass('completions');
            this.complete.attr('id', 'complete');

            // Currently webkit doesn't use the size attr correctly. See:
            // https://code.google.com/p/chromium/issues/detail?id=4579
            this.sel = $('<select style="width: auto"/>')
                .attr('tabindex', -1)
                .attr('multiple', 'true');
            this.complete.append(this.sel);
            this.visible = true;
            $('body').append(this.complete);

            //build the container
            var that = this;
            this.sel.dblclick(function () {
                that.pick();
            });
            this.sel.focus(function () {
                that.editor.focus();
            });
            this._handle_keydown = function (cm, event) {
                that.keydown(event);
            };
            this.editor.on('keydown', this._handle_keydown);
            this._handle_keypress = function (cm, event) {
                that.keypress(event);
            };
            this.editor.on('keypress', this._handle_keypress);
        }
        this.sel.attr('size', Math.min(10, this.raw_result.length));

        // After everything is on the page, compute the postion.
        // We put it above the code if it is too close to the bottom of the page.
        cur.ch = cur.ch-matched_text.length;
        var pos = this.editor.cursorCoords(cur);
        var left = pos.left-3;
        var top;
        var cheight = this.complete.height();
        var wheight = $(window).height();
        if (pos.bottom+cheight+5 > wheight) {
            top = pos.top-cheight-4;
        } else {
            top = pos.bottom+1;
        }
        this.complete.css('left', left + 'px');
        this.complete.css('top', top + 'px');

        // Clear and fill the list.
        this.sel.text('');
        this.build_gui_list(this.raw_result);
        return true;
    };

    Completer.prototype.insert = function (completion) {
        this.editor.replaceRange(completion.str, completion.from, completion.to);
    };

    Completer.prototype.build_gui_list = function (completions) {
        for (var i = 0; i < completions.length; ++i) {
            var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
            this.sel.append(opt);
        }
        this.sel.children().first().attr('selected', 'true');
        this.sel.scrollTop(0);
    };

    Completer.prototype.close = function () {
        this.done = true;
        $('#complete').remove();
        if (this._handle_keydown) {
            this.editor.off('keydown', this._handle_keydown);
            this._handle_keydown = undefined;
        }
        if (this._handle_keypress) {
            this.editor.off('keypress', this._handle_keypress);
            this._handle_keypress = undefined;
        }
        this.visible = false;
    };

    Completer.prototype.pick = function () {
        this.insert(this.raw_result[this.sel[0].selectedIndex]);
        this.close();
    };

    Completer.prototype.keydown = function (event) {
        var code = event.keyCode;
        var that = this;

        // Enter
        if (code == keycodes.enter) {
            CodeMirror.e_stop(event);
            this.pick();
        // Escape or backspace
        } else if (code == keycodes.esc || code == keycodes.backspace) {
            CodeMirror.e_stop(event);
            this.close();
        } else if (code == keycodes.tab) {
            //all the fastforwarding operation,
            //Check that shared start is not null which can append with prefixed completion
            // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
            // to erase py
            var sh = shared_start(this.raw_result, true);
            if (sh) {
                this.insert(sh);
            }
            this.close();
            // event.codemirrorIgnore = true;
            // event.stopPropagation();
            //reinvoke self
            setTimeout(function () {
                that.carry_on_completion();
            }, 50);
        } else if (code == keycodes.up || code == keycodes.down) {
            // need to do that to be able to move the arrow
            // when on the first or last line ofo a code cell
            CodeMirror.e_stop(event);

            var options = this.sel.find('option');
            var index = this.sel[0].selectedIndex;
            if (code == keycodes.up) {
                index--;
            }
            if (code == keycodes.down) {
                index++;
            }
            index = Math.min(Math.max(index, 0), options.length-1);
            this.sel[0].selectedIndex = index;
        } else if (code == keycodes.left || code == keycodes.right) {
            this.close();
        }
    };

    Completer.prototype.keypress = function (event) {
        // FIXME: This is a band-aid.
        // on keypress, trigger insertion of a single character.
        // This simulates the old behavior of completion as you type,
        // before events were disconnected and CodeMirror stopped
        // receiving events while the completer is focused.

        var that = this;
        var code = event.keyCode;

        // don't handle keypress if it's not a character (arrows on FF)
        // or ENTER/TAB
        if (event.charCode === 0 ||
            code == keycodes.tab ||
            code == keycodes.enter
        ) return;

        var cur = this.editor.getCursor();
        var completion = {
            str: String.fromCharCode(event.which),
            type: "introspection",
            from: cur,
            to: cur,
        };
        // this.insert(completion);

        this.close();
        this.editor.focus();
        setTimeout(function () {
            that.carry_on_completion();
        }, 50);
    };
    IPython.Completer = Completer;

    return IPython;
}(IPython));
<commit_msg>Remove commented line<commit_after>// function completer.
//
// completer should be a class that takes an cell instance
var IPython = (function (IPython) {
    // that will prevent us from misspelling
    "use strict";

    // easier key mapping
    var keycodes = IPython.keyboard.keycodes;

    function prepend_n_prc(str, n) {
        for( var i =0 ; i< n ; i++){
            str = '%'+str ;
        }
        return str;
    }

    function _existing_completion(item, completion_array){
        for( var c in completion_array ) {
            if(completion_array[c].trim().substr(-item.length) == item)
            { return true; }
        }
       return false;
    }

    // what is the common start of all completions
    function shared_start(B, drop_prct) {
        if (B.length == 1) {
            return B[0];
        }
        var A = [];
        var common;
        var min_lead_prct = 10;
        for (var i = 0; i < B.length; i++) {
            var str = B[i].str;
            var localmin = 0;
            if(drop_prct === true){
                while ( str.substr(0, 1) == '%') {
                    localmin = localmin+1;
                    str = str.substring(1);
                }
            }
            min_lead_prct = Math.min(min_lead_prct, localmin);
            A.push(str);
        }

        if (A.length > 1) {
            var tem1, tem2, s;
            A = A.slice(0).sort();
            tem1 = A[0];
            s = tem1.length;
            tem2 = A.pop();
            while (s && tem2.indexOf(tem1) == -1) {
                tem1 = tem1.substring(0, --s);
            }
            if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
                return {
                    str:prepend_n_prc('', min_lead_prct),
                    type: "computed",
                    from: B[0].from,
                    to: B[0].to
                    };
            }
            return {
                str: prepend_n_prc(tem1, min_lead_prct),
                type: "computed",
                from: B[0].from,
                to: B[0].to
            };
        }
        return null;
    }

    var Completer = function (cell) {
        this.cell = cell;
        this.editor = cell.code_mirror;
        var that = this;
        $([IPython.events]).on('status_busy.Kernel', function () {
            that.skip_kernel_completion = true;
        });
        $([IPython.events]).on('status_idle.Kernel', function () {
            that.skip_kernel_completion = false;
        });
    };

    Completer.prototype.startCompletion = function () {
        // call for a 'first' completion, that will set the editor and do some
        // special behavior like autopicking if only one completion available.
        if (this.editor.somethingSelected()) return;
        this.done = false;
        // use to get focus back on opera
        this.carry_on_completion(true);
    };

    // easy access for julia to monkeypatch
    //
    Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;

    Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
        return Completer.reinvoke_re.test(pre_cursor);
    };

    /**
     *
     * pass true as parameter if this is the first invocation of the completer
     * this will prevent the completer to dissmiss itself if it is not on a
     * word boundary like pressing tab after a space, and make it autopick the
     * only choice if there is only one which prevent from popping the UI.  as
     * well as fast-forwarding the typing if all completion have a common
     * shared start
     **/
    Completer.prototype.carry_on_completion = function (first_invocation) {
        // Pass true as parameter if you want the completer to autopick when
        // only one completion. This function is automatically reinvoked at
        // each keystroke with first_invocation = false
        var cur = this.editor.getCursor();
        var line = this.editor.getLine(cur.line);
        var pre_cursor = this.editor.getRange({
            line: cur.line,
            ch: cur.ch - 1
        }, cur);

        // we need to check that we are still on a word boundary
        // because while typing the completer is still reinvoking itself
        // so dismiss if we are on a "bad" caracter
        if (!this.reinvoke(pre_cursor) && !first_invocation) {
            this.close();
            return;
        }

        this.autopick = false;
        if (first_invocation) {
            this.autopick = true;
        }

        // We want a single cursor position.
        if (this.editor.somethingSelected()) {
            return;
        }

        // one kernel completion came back, finish_completing will be called with the results
        // we fork here and directly call finish completing if kernel is busy
        if (this.skip_kernel_completion) {
            this.finish_completing({
                'matches': [],
                matched_text: ""
            });
        } else {
            this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
        }
    };

    Completer.prototype.finish_completing = function (msg) {
        // let's build a function that wrap all that stuff into what is needed
        // for the new completer:
        var content = msg.content;
        var matched_text = content.matched_text;
        var matches = content.matches;

        var cur = this.editor.getCursor();
        var results = CodeMirror.contextHint(this.editor);
        var filtered_results = [];
        //remove results from context completion
        //that are already in kernel completion
        for (var elm in results) {
            if (!_existing_completion(results[elm].str, matches)) {
                filtered_results.push(results[elm]);
            }
        }

        // append the introspection result, in order, at at the beginning of
        // the table and compute the replacement range from current cursor
        // positon and matched_text length.
        for (var i = matches.length - 1; i >= 0; --i) {
            filtered_results.unshift({
                str: matches[i],
                type: "introspection",
                from: {
                    line: cur.line,
                    ch: cur.ch - matched_text.length
                },
                to: {
                    line: cur.line,
                    ch: cur.ch
                }
            });
        }

        // one the 2 sources results have been merge, deal with it
        this.raw_result = filtered_results;

        // if empty result return
        if (!this.raw_result || !this.raw_result.length) return;

        // When there is only one completion, use it directly.
        if (this.autopick && this.raw_result.length == 1) {
            this.insert(this.raw_result[0]);
            return;
        }

        if (this.raw_result.length == 1) {
            // test if first and only completion totally matches
            // what is typed, in this case dismiss
            var str = this.raw_result[0].str;
            var pre_cursor = this.editor.getRange({
                line: cur.line,
                ch: cur.ch - str.length
            }, cur);
            if (pre_cursor == str) {
                this.close();
                return;
            }
        }

        if (!this.visible) {
            console.log('add div');
            this.complete = $('<div/>').addClass('completions');
            this.complete.attr('id', 'complete');

            // Currently webkit doesn't use the size attr correctly. See:
            // https://code.google.com/p/chromium/issues/detail?id=4579
            this.sel = $('<select style="width: auto"/>')
                .attr('tabindex', -1)
                .attr('multiple', 'true');
            this.complete.append(this.sel);
            this.visible = true;
            $('body').append(this.complete);

            //build the container
            var that = this;
            this.sel.dblclick(function () {
                that.pick();
            });
            this.sel.focus(function () {
                that.editor.focus();
            });
            this._handle_keydown = function (cm, event) {
                that.keydown(event);
            };
            this.editor.on('keydown', this._handle_keydown);
            this._handle_keypress = function (cm, event) {
                that.keypress(event);
            };
            this.editor.on('keypress', this._handle_keypress);
        }
        this.sel.attr('size', Math.min(10, this.raw_result.length));

        // After everything is on the page, compute the postion.
        // We put it above the code if it is too close to the bottom of the page.
        cur.ch = cur.ch-matched_text.length;
        var pos = this.editor.cursorCoords(cur);
        var left = pos.left-3;
        var top;
        var cheight = this.complete.height();
        var wheight = $(window).height();
        if (pos.bottom+cheight+5 > wheight) {
            top = pos.top-cheight-4;
        } else {
            top = pos.bottom+1;
        }
        this.complete.css('left', left + 'px');
        this.complete.css('top', top + 'px');

        // Clear and fill the list.
        this.sel.text('');
        this.build_gui_list(this.raw_result);
        return true;
    };

    Completer.prototype.insert = function (completion) {
        this.editor.replaceRange(completion.str, completion.from, completion.to);
    };

    Completer.prototype.build_gui_list = function (completions) {
        for (var i = 0; i < completions.length; ++i) {
            var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
            this.sel.append(opt);
        }
        this.sel.children().first().attr('selected', 'true');
        this.sel.scrollTop(0);
    };

    Completer.prototype.close = function () {
        this.done = true;
        $('#complete').remove();
        if (this._handle_keydown) {
            this.editor.off('keydown', this._handle_keydown);
            this._handle_keydown = undefined;
        }
        if (this._handle_keypress) {
            this.editor.off('keypress', this._handle_keypress);
            this._handle_keypress = undefined;
        }
        this.visible = false;
    };

    Completer.prototype.pick = function () {
        this.insert(this.raw_result[this.sel[0].selectedIndex]);
        this.close();
    };

    Completer.prototype.keydown = function (event) {
        var code = event.keyCode;
        var that = this;

        // Enter
        if (code == keycodes.enter) {
            CodeMirror.e_stop(event);
            this.pick();
        // Escape or backspace
        } else if (code == keycodes.esc || code == keycodes.backspace) {
            CodeMirror.e_stop(event);
            this.close();
        } else if (code == keycodes.tab) {
            //all the fastforwarding operation,
            //Check that shared start is not null which can append with prefixed completion
            // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
            // to erase py
            var sh = shared_start(this.raw_result, true);
            if (sh) {
                this.insert(sh);
            }
            this.close();
            // event.codemirrorIgnore = true;
            // event.stopPropagation();
            //reinvoke self
            setTimeout(function () {
                that.carry_on_completion();
            }, 50);
        } else if (code == keycodes.up || code == keycodes.down) {
            // need to do that to be able to move the arrow
            // when on the first or last line ofo a code cell
            CodeMirror.e_stop(event);

            var options = this.sel.find('option');
            var index = this.sel[0].selectedIndex;
            if (code == keycodes.up) {
                index--;
            }
            if (code == keycodes.down) {
                index++;
            }
            index = Math.min(Math.max(index, 0), options.length-1);
            this.sel[0].selectedIndex = index;
        } else if (code == keycodes.left || code == keycodes.right) {
            this.close();
        }
    };

    Completer.prototype.keypress = function (event) {
        // FIXME: This is a band-aid.
        // on keypress, trigger insertion of a single character.
        // This simulates the old behavior of completion as you type,
        // before events were disconnected and CodeMirror stopped
        // receiving events while the completer is focused.

        var that = this;
        var code = event.keyCode;

        // don't handle keypress if it's not a character (arrows on FF)
        // or ENTER/TAB
        if (event.charCode === 0 ||
            code == keycodes.tab ||
            code == keycodes.enter
        ) return;

        var cur = this.editor.getCursor();
        var completion = {
            str: String.fromCharCode(event.which),
            type: "introspection",
            from: cur,
            to: cur,
        };

        this.close();
        this.editor.focus();
        setTimeout(function () {
            that.carry_on_completion();
        }, 50);
    };
    IPython.Completer = Completer;

    return IPython;
}(IPython));
<|endoftext|>


<commit_before>// function completer.
//
// completer should be a class that take an cell instance
var IPython = (function (IPython) {
    // that will prevent us from misspelling
    "use strict";

    // easyier key mapping
    var key = IPython.utils.keycodes;

    function prepend_n_prc(str, n) {
        for( var i =0 ; i< n ; i++)
        { str = '%'+str }
        return str;
    }

    function _existing_completion(item, completion_array){
        for( var c in completion_array ) {
            if(completion_array[c].trim().substr(-item.length) == item)
            { return true; }
        }
       return false;
    }

    // what is the common start of all completions
    function shared_start(B, drop_prct) {
        if (B.length == 1) {
            return B[0];
        }
        var A = new Array();
        var common;
        var min_lead_prct = 10;
        for (var i = 0; i < B.length; i++) {
            var str = B[i].str;
            var localmin = 0;
            if(drop_prct == true){
                while ( str.substr(0, 1) == '%') {
                    localmin = localmin+1;
                    str = str.substring(1);
                }
            }
            min_lead_prct = Math.min(min_lead_prct, localmin);
            A.push(str);
        }

        if (A.length > 1) {
            var tem1, tem2, s;
            A = A.slice(0).sort();
            tem1 = A[0];
            s = tem1.length;
            tem2 = A.pop();
            while (s && tem2.indexOf(tem1) == -1) {
                tem1 = tem1.substring(0, --s);
            }
            if (tem1 == "" || tem2.indexOf(tem1) != 0) {
                return {
                    str:prepend_n_prc('', min_lead_prct),
                    type: "computed",
                    from: B[0].from,
                    to: B[0].to
                    }
            }
            return {
                str: prepend_n_prc(tem1, min_lead_prct),
                type: "computed",
                from: B[0].from,
                to: B[0].to
            };
        }
        return null;
    }

    var Completer = function (cell) {
        this.cell = cell;
        this.editor = cell.code_mirror;
        var that = this;
        $([IPython.events]).on('status_busy.Kernel', function () {
            that.skip_kernel_completion = true;
        });
        $([IPython.events]).on('status_idle.Kernel', function () {
            that.skip_kernel_completion = false;
        });
    };

    Completer.prototype.startCompletion = function () {
        // call for a 'first' completion, that will set the editor and do some
        // special behaviour like autopicking if only one completion availlable
        //
        if (this.editor.somethingSelected()) return;
        this.done = false;
        // use to get focus back on opera
        this.carry_on_completion(true);
    };

    Completer.prototype.carry_on_completion = function (ff) {
        // Pass true as parameter if you want the commpleter to autopick when
        // only one completion. This function is automatically reinvoked at
        // each keystroke with ff = false
        var cur = this.editor.getCursor();
        var line = this.editor.getLine(cur.line);
        var pre_cursor = this.editor.getRange({
            line: cur.line,
            ch: cur.ch - 1
        }, cur);

        // we need to check that we are still on a word boundary
        // because while typing the completer is still reinvoking itself
        if (!/[%0-9a-z._/\\:~-]/i.test(pre_cursor)) {
            this.close();
            return;
        }

        this.autopick = false;
        if (ff != 'undefined' && ff == true) {
            this.autopick = true;
        }

        // We want a single cursor position.
        if (this.editor.somethingSelected()) return;

        // one kernel completion came back, finish_completing will be called with the results
        // we fork here and directly call finish completing if kernel is busy
        if (this.skip_kernel_completion == true) {
            this.finish_completing({
                'matches': [],
                matched_text: ""
            })
        } else {
            var callbacks = {
                'complete_reply': $.proxy(this.finish_completing, this)
            };
            this.cell.kernel.complete(line, cur.ch, callbacks);
        }
    };

    Completer.prototype.finish_completing = function (content) {
        // let's build a function that wrap all that stuff into what is needed
        // for the new completer:
        var matched_text = content.matched_text;
        var matches = content.matches;

        var cur = this.editor.getCursor();
        var results = CodeMirror.contextHint(this.editor);
        var filterd_results = Array();
        //remove results from context completion
        //that are already in kernel completion
        for(var elm in results) {
            if(_existing_completion(results[elm]['str'], matches) == false)
            { filterd_results.push(results[elm]); }
        }

        // append the introspection result, in order, at at the beginning of
        // the table and compute the replacement range from current cursor
        // positon and matched_text length.
        for (var i = matches.length - 1; i >= 0; --i) {
            filterd_results.unshift({
                str: matches[i],
                type: "introspection",
                from: {
                    line: cur.line,
                    ch: cur.ch - matched_text.length
                },
                to: {
                    line: cur.line,
                    ch: cur.ch
                }
            });
        }

        // one the 2 sources results have been merge, deal with it
        this.raw_result = filterd_results;

        // if empty result return
        if (!this.raw_result || !this.raw_result.length) return;

        // When there is only one completion, use it directly.
        if (this.autopick == true && this.raw_result.length == 1) {
            this.insert(this.raw_result[0]);
            return;
        }

        if (this.raw_result.length == 1) {
            // test if first and only completion totally matches
            // what is typed, in this case dismiss
            var str = this.raw_result[0].str;
            var pre_cursor = this.editor.getRange({
                line: cur.line,
                ch: cur.ch - str.length
            }, cur);
            if (pre_cursor == str) {
                this.close();
                return;
            }
        }

        this.complete = $('<div/>').addClass('completions');
        this.complete.attr('id', 'complete');

        this.sel = $('<select style="width: auto"/>').attr('multiple', 'true').attr('size', Math.min(10, this.raw_result.length));
        //var pos = this.editor.cursorCoords();
		var cur = this.editor.getCursor();
		cur.ch = cur.ch-matched_text.length;
		var pos = this.editor.cursorCoords(cur);
        this.complete.css('left', pos.left-3 + 'px');
        this.complete.css('top', pos.bottom+1 + 'px');
        this.complete.append(this.sel);

        $('body').append(this.complete);
        //build the container
        var that = this;
        this.sel.dblclick(function () {
            that.pick();
        });
        this.sel.blur(this.close);
        this.sel.keydown(function (event) {
            that.keydown(event);
        });

        this.build_gui_list(this.raw_result);

        this.sel.focus();
        // Opera sometimes ignores focusing a freshly created node
        if (window.opera) setTimeout(function () {
            if (!this.done) this.sel.focus();
        }, 100);
        return true;
    }

    Completer.prototype.insert = function (completion) {
        this.editor.replaceRange(completion.str, completion.from, completion.to);
    }

    Completer.prototype.build_gui_list = function (completions) {
        // Need to clear the all list
        for (var i = 0; i < completions.length; ++i) {
            var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
            this.sel.append(opt);
        }
        this.sel.children().first().attr('selected', 'true');
    }

    Completer.prototype.close = function () {
        if (this.done) return;
        this.done = true;
        $('.completions').remove();
    }

    Completer.prototype.pick = function () {
        this.insert(this.raw_result[this.sel[0].selectedIndex]);
        this.close();
        var that = this;
        setTimeout(function () {
            that.editor.focus();
        }, 50);
    }

    Completer.prototype.keydown = function (event) {
        var code = event.keyCode;
        var that = this;
        var special_key = false;

        // detect special keys like SHIFT,PGUP,...
        for( var _key in key ) {
            if (code == key[_key] ) {
                special_key = true;
            }
        };

        // Enter
        if (code == key.ENTER) {
            CodeMirror.e_stop(event);
            this.pick();
        }
        // Escape or backspace
        else if (code == key.ESC) {
            CodeMirror.e_stop(event);
            this.close();
            this.editor.focus();
        } else if (code == key.SPACE || code == key.BACKSPACE) {
            this.close();
            this.editor.focus();
        } else if (code == key.TAB) {
            //all the fastforwarding operation,
            //Check that shared start is not null which can append with prefixed completion
            // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
            // to erase py
            var sh = shared_start(this.raw_result, true);
            if (sh) {
                this.insert(sh);
            }
            this.close();
            CodeMirror.e_stop(event);
            this.editor.focus();
            //reinvoke self
            setTimeout(function () {
                that.carry_on_completion();
            }, 50);
        } else if (code == key.UPARROW || code == key.DOWNARROW) {
            // need to do that to be able to move the arrow
            // when on the first or last line ofo a code cell
            event.stopPropagation();
        } else if (special_key != true) {
            this.close();
            this.editor.focus();
            //we give focus to the editor immediately and call sell in 50 ms
            setTimeout(function () {
                that.carry_on_completion();
            }, 50);
        }
    }

    IPython.Completer = Completer;

    return IPython;
}(IPython));
<commit_msg>Adjust tab completion widget if too close to bottom of page.<commit_after>// function completer.
//
// completer should be a class that take an cell instance
var IPython = (function (IPython) {
    // that will prevent us from misspelling
    "use strict";

    // easyier key mapping
    var key = IPython.utils.keycodes;

    function prepend_n_prc(str, n) {
        for( var i =0 ; i< n ; i++)
        { str = '%'+str }
        return str;
    }

    function _existing_completion(item, completion_array){
        for( var c in completion_array ) {
            if(completion_array[c].trim().substr(-item.length) == item)
            { return true; }
        }
       return false;
    }

    // what is the common start of all completions
    function shared_start(B, drop_prct) {
        if (B.length == 1) {
            return B[0];
        }
        var A = new Array();
        var common;
        var min_lead_prct = 10;
        for (var i = 0; i < B.length; i++) {
            var str = B[i].str;
            var localmin = 0;
            if(drop_prct == true){
                while ( str.substr(0, 1) == '%') {
                    localmin = localmin+1;
                    str = str.substring(1);
                }
            }
            min_lead_prct = Math.min(min_lead_prct, localmin);
            A.push(str);
        }

        if (A.length > 1) {
            var tem1, tem2, s;
            A = A.slice(0).sort();
            tem1 = A[0];
            s = tem1.length;
            tem2 = A.pop();
            while (s && tem2.indexOf(tem1) == -1) {
                tem1 = tem1.substring(0, --s);
            }
            if (tem1 == "" || tem2.indexOf(tem1) != 0) {
                return {
                    str:prepend_n_prc('', min_lead_prct),
                    type: "computed",
                    from: B[0].from,
                    to: B[0].to
                    }
            }
            return {
                str: prepend_n_prc(tem1, min_lead_prct),
                type: "computed",
                from: B[0].from,
                to: B[0].to
            };
        }
        return null;
    }

    var Completer = function (cell) {
        this.cell = cell;
        this.editor = cell.code_mirror;
        var that = this;
        $([IPython.events]).on('status_busy.Kernel', function () {
            that.skip_kernel_completion = true;
        });
        $([IPython.events]).on('status_idle.Kernel', function () {
            that.skip_kernel_completion = false;
        });
    };

    Completer.prototype.startCompletion = function () {
        // call for a 'first' completion, that will set the editor and do some
        // special behaviour like autopicking if only one completion availlable
        //
        if (this.editor.somethingSelected()) return;
        this.done = false;
        // use to get focus back on opera
        this.carry_on_completion(true);
    };

    Completer.prototype.carry_on_completion = function (ff) {
        // Pass true as parameter if you want the commpleter to autopick when
        // only one completion. This function is automatically reinvoked at
        // each keystroke with ff = false
        var cur = this.editor.getCursor();
        var line = this.editor.getLine(cur.line);
        var pre_cursor = this.editor.getRange({
            line: cur.line,
            ch: cur.ch - 1
        }, cur);

        // we need to check that we are still on a word boundary
        // because while typing the completer is still reinvoking itself
        if (!/[%0-9a-z._/\\:~-]/i.test(pre_cursor)) {
            this.close();
            return;
        }

        this.autopick = false;
        if (ff != 'undefined' && ff == true) {
            this.autopick = true;
        }

        // We want a single cursor position.
        if (this.editor.somethingSelected()) return;

        // one kernel completion came back, finish_completing will be called with the results
        // we fork here and directly call finish completing if kernel is busy
        if (this.skip_kernel_completion == true) {
            this.finish_completing({
                'matches': [],
                matched_text: ""
            })
        } else {
            var callbacks = {
                'complete_reply': $.proxy(this.finish_completing, this)
            };
            this.cell.kernel.complete(line, cur.ch, callbacks);
        }
    };

    Completer.prototype.finish_completing = function (content) {
        // let's build a function that wrap all that stuff into what is needed
        // for the new completer:
        var matched_text = content.matched_text;
        var matches = content.matches;

        var cur = this.editor.getCursor();
        var results = CodeMirror.contextHint(this.editor);
        var filterd_results = Array();
        //remove results from context completion
        //that are already in kernel completion
        for(var elm in results) {
            if(_existing_completion(results[elm]['str'], matches) == false)
            { filterd_results.push(results[elm]); }
        }

        // append the introspection result, in order, at at the beginning of
        // the table and compute the replacement range from current cursor
        // positon and matched_text length.
        for (var i = matches.length - 1; i >= 0; --i) {
            filterd_results.unshift({
                str: matches[i],
                type: "introspection",
                from: {
                    line: cur.line,
                    ch: cur.ch - matched_text.length
                },
                to: {
                    line: cur.line,
                    ch: cur.ch
                }
            });
        }

        // one the 2 sources results have been merge, deal with it
        this.raw_result = filterd_results;

        // if empty result return
        if (!this.raw_result || !this.raw_result.length) return;

        // When there is only one completion, use it directly.
        if (this.autopick == true && this.raw_result.length == 1) {
            this.insert(this.raw_result[0]);
            return;
        }

        if (this.raw_result.length == 1) {
            // test if first and only completion totally matches
            // what is typed, in this case dismiss
            var str = this.raw_result[0].str;
            var pre_cursor = this.editor.getRange({
                line: cur.line,
                ch: cur.ch - str.length
            }, cur);
            if (pre_cursor == str) {
                this.close();
                return;
            }
        }

        this.complete = $('<div/>').addClass('completions');
        this.complete.attr('id', 'complete');

        this.sel = $('<select style="width: auto"/>').attr('multiple', 'true').attr('size', Math.min(10, this.raw_result.length));
        this.complete.append(this.sel);
        $('body').append(this.complete);

        // After everything is on the page compute the postion.
        // We invert the completion list and put it above the code if it is too
        // close to the bottom of the page.
        var cur = this.editor.getCursor();
        cur.ch = cur.ch-matched_text.length;
        var pos = this.editor.cursorCoords(cur);
        var invert = false;
        var left = pos.left-3;
        var top;
        var cheight = this.complete.height();
        var wheight = $(window).height();
        console.log(pos.bottom, cheight, wheight)
        if (pos.bottom+cheight+5 > wheight) {
            invert = true;
            top = pos.top-cheight-4;
        } else {
            invert = false;
            top = pos.bottom+1;
        }
        this.complete.css('left', left + 'px');
        this.complete.css('top', top + 'px');

        //build the container
        var that = this;
        this.sel.dblclick(function () {
            that.pick();
        });
        this.sel.blur(this.close);
        this.sel.keydown(function (event) {
            that.keydown(event);
        });

        this.build_gui_list(this.raw_result, invert);

        this.sel.focus();
        // Opera sometimes ignores focusing a freshly created node
        if (window.opera) setTimeout(function () {
            if (!this.done) this.sel.focus();
        }, 100);
        return true;
    }

    Completer.prototype.insert = function (completion) {
        this.editor.replaceRange(completion.str, completion.from, completion.to);
    }

    Completer.prototype.build_gui_list = function (completions, invert) {
        invert = invert || false;
        if (!invert) {
            for (var i = 0; i < completions.length; ++i) {
                var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
                this.sel.append(opt);
            }
            this.sel.children().first().attr('selected', 'true');
            this.sel.scrollTop(0);
        } else {
            for (var i = (completions.length-1); i > -1; --i) {
                var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
                this.sel.append(opt);
            }
            this.sel.children().last().attr('selected', 'true');
            this.sel.scrollTop(this.sel[0].scrollHeight);
        }
    }

    Completer.prototype.close = function () {
        if (this.done) return;
        this.done = true;
        $('.completions').remove();
    }

    Completer.prototype.pick = function () {
        this.insert(this.raw_result[this.sel[0].selectedIndex]);
        this.close();
        var that = this;
        setTimeout(function () {
            that.editor.focus();
        }, 50);
    }

    Completer.prototype.keydown = function (event) {
        var code = event.keyCode;
        var that = this;
        var special_key = false;

        // detect special keys like SHIFT,PGUP,...
        for( var _key in key ) {
            if (code == key[_key] ) {
                special_key = true;
            }
        };

        // Enter
        if (code == key.ENTER) {
            CodeMirror.e_stop(event);
            this.pick();
        }
        // Escape or backspace
        else if (code == key.ESC) {
            CodeMirror.e_stop(event);
            this.close();
            this.editor.focus();
        } else if (code == key.SPACE || code == key.BACKSPACE) {
            this.close();
            this.editor.focus();
        } else if (code == key.TAB) {
            //all the fastforwarding operation,
            //Check that shared start is not null which can append with prefixed completion
            // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
            // to erase py
            var sh = shared_start(this.raw_result, true);
            if (sh) {
                this.insert(sh);
            }
            this.close();
            CodeMirror.e_stop(event);
            this.editor.focus();
            //reinvoke self
            setTimeout(function () {
                that.carry_on_completion();
            }, 50);
        } else if (code == key.UPARROW || code == key.DOWNARROW) {
            // need to do that to be able to move the arrow
            // when on the first or last line ofo a code cell
            event.stopPropagation();
        } else if (special_key != true) {
            this.close();
            this.editor.focus();
            //we give focus to the editor immediately and call sell in 50 ms
            setTimeout(function () {
                that.carry_on_completion();
            }, 50);
        }
    }

    IPython.Completer = Completer;

    return IPython;
}(IPython));
<|endoftext|>


<commit_before>import * as style from "./style"

const render = Object.create(null), renderStyle = Object.create(null)

let doc = null

export default function toDOM(node, options) {
  doc = options.document
  return renderNodes(node.content, options)
}

toDOM.renderNode = renderNode

function elt(name, ...children) {
  let dom = doc.createElement(name)
  for (let i = 0; i < children.length; i++) {
    let child = children[i]
    dom.appendChild(typeof child == "string" ? doc.createTextNode(child) : child)
  }
  return dom
}

function wrap(node, options, type) {
  let dom = elt(type || node.type.name)
  if (node.type.contains != "inline")
    renderNodesInto(node.content, dom, options)
  else if (options.renderInlineFlat)
    renderInlineContentFlat(node.content, dom, options)
  else
    renderInlineContent(node.content, dom, options)
  return dom
}

function wrapIn(type) {
  return function(node, options) { return wrap(node, options, type) }
}

function renderNodes(nodes, options) {
  let frag = doc.createDocumentFragment()
  renderNodesInto(nodes, frag, options)
  return frag
}

function renderNode(node, options, offset) {
  let dom = render[node.type.name](node, options)
  if (options.onRender)
    dom = options.onRender(node, dom, offset) || dom
  return dom
}

function renderNodesInto(nodes, where, options) {
  for (let i = 0; i < nodes.length; i++)
    where.appendChild(renderNode(nodes[i], options, i))
}

function renderInlineContent(nodes, where, options) {
  let top = where
  let active = []
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i], styles = node.styles
    let keep = 0
    for (; keep < Math.min(active.length, styles.length); ++keep)
      if (!style.same(active[keep], styles[keep])) break
    while (keep < active.length) {
      active.pop()
      top = top.parentNode
    }
    while (active.length < styles.length) {
      let add = styles[active.length]
      active.push(add)
      top = top.appendChild(renderStyle[add.type](add))
    }
    top.appendChild(renderNode(node, options, i))
  }
}

function renderInlineContentFlat(nodes, where, options) {
  let offset = 0
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i], styles = node.styles
    let dom = renderNode(node, options, i)
    for (let j = styles.length - 1; j >= 0; j--) {
      let wrap = renderStyle[styles[j].type](styles[j])
      wrap.appendChild(dom)
      dom = wrap
    }
    dom = options.renderInlineFlat(node, dom, offset) || dom
    where.appendChild(dom)
    offset += node.size
  }
}

// Block nodes

render.blockquote = wrap

render.code_block = (node, options) => {
  let code = wrap(node, options, "code")
  if (node.attrs.params != null)
    code.className = "fence " + node.attrs.params.replace(/(^|\s+)/g, "$&lang-")
  return elt("pre", code)
}

render.heading = (node, options) => wrap(node, options, "h" + node.attrs.level)

render.horizontal_rule = node => elt("hr")

render.bullet_list = (node, options) => {
  let dom = wrap(node, options, "ul")
  let bul = node.attrs.bullet
  dom.setAttribute("class", bul == "+" ? "bullet_plus" : bul == "-" ? "bullet_dash" : "bullet_star")
  if (node.attrs.tight) dom.setAttribute("class", "tight")
  return dom
}

render.ordered_list = (node, options) => {
  let dom = wrap(node, options, "ol")
  if (node.attrs.order > 1) dom.setAttribute("start", node.attrs.order)
  if (node.attrs.tight) dom.setAttribute("class", "tight")
  return dom
}

render.list_item = wrapIn("li")

render.paragraph = wrapIn("p")

render.html_block = node => {
  let dom = elt("div")
  dom.innerHTML = node.attrs.html
  dom.setAttribute("mm-html", "html_block")
  return dom
}

// Inline content

render.text = node => doc.createTextNode(node.text)

render.image = node => {
  let dom = elt("img")
  dom.setAttribute("src", node.attrs.src)
  if (node.attrs.title) dom.setAttribute("title", node.attrs.title)
  if (node.attrs.alt) dom.setAttribute("alt", node.attrs.alt)
  return dom
}

render.hard_break = node => elt("br")

render.html_tag = node => {
  let dom = elt("span")
  dom.innerHTML = node.attrs.html
  dom.setAttribute("mm-html", "html_tag")
  return dom
}

// Inline styles

renderStyle.em = () => elt("em")

renderStyle.strong = () => elt("strong")

renderStyle.code = () => elt("code")

renderStyle.link = style => {
  let dom = elt("a")
  dom.setAttribute("href", style.href)
  if (style.title) dom.setAttribute("title", style.title)
  return dom
}
<commit_msg>Minimally update inline content when redrawing<commit_after>import * as style from "./style"

const render = Object.create(null), renderStyle = Object.create(null)

let doc = null

export default function toDOM(node, options) {
  doc = options.document
  return renderNodes(node.content, options)
}

toDOM.renderNode = function(node, options, offset) {
  let dom = renderNode(node, options, offset)
  if (options.renderInlineFlat && node.type.type == "inline") {
    dom = wrapInlineFlat(node, dom)
    dom = options.renderInlineFlat(node, dom, offset) || dom
  }
  return dom
}

function elt(name, ...children) {
  let dom = doc.createElement(name)
  for (let i = 0; i < children.length; i++) {
    let child = children[i]
    dom.appendChild(typeof child == "string" ? doc.createTextNode(child) : child)
  }
  return dom
}

function wrap(node, options, type) {
  let dom = elt(type || node.type.name)
  if (node.type.contains != "inline")
    renderNodesInto(node.content, dom, options)
  else if (options.renderInlineFlat)
    renderInlineContentFlat(node.content, dom, options)
  else
    renderInlineContent(node.content, dom, options)
  return dom
}

function wrapIn(type) {
  return function(node, options) { return wrap(node, options, type) }
}

function renderNodes(nodes, options) {
  let frag = doc.createDocumentFragment()
  renderNodesInto(nodes, frag, options)
  return frag
}

function renderNode(node, options, offset) {
  let dom = render[node.type.name](node, options)
  if (options.onRender)
    dom = options.onRender(node, dom, offset) || dom
  return dom
}

function renderNodesInto(nodes, where, options) {
  for (let i = 0; i < nodes.length; i++)
    where.appendChild(renderNode(nodes[i], options, i))
}

function renderInlineContent(nodes, where, options) {
  let top = where
  let active = []
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i], styles = node.styles
    let keep = 0
    for (; keep < Math.min(active.length, styles.length); ++keep)
      if (!style.same(active[keep], styles[keep])) break
    while (keep < active.length) {
      active.pop()
      top = top.parentNode
    }
    while (active.length < styles.length) {
      let add = styles[active.length]
      active.push(add)
      top = top.appendChild(renderStyle[add.type](add))
    }
    top.appendChild(renderNode(node, options, i))
  }
}

function wrapInlineFlat(node, dom) {
  let styles = node.styles
  for (let i = styles.length - 1; i >= 0; i--) {
    let wrap = renderStyle[styles[i].type](styles[i])
    wrap.appendChild(dom)
    dom = wrap
  }
  return dom
}

function renderInlineContentFlat(nodes, where, options) {
  let offset = 0
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i]
    let dom = wrapInlineFlat(node, renderNode(node, options, i))
    dom = options.renderInlineFlat(node, dom, offset) || dom
    where.appendChild(dom)
    offset += node.size
  }
}

// Block nodes

render.blockquote = wrap

render.code_block = (node, options) => {
  let code = wrap(node, options, "code")
  if (node.attrs.params != null)
    code.className = "fence " + node.attrs.params.replace(/(^|\s+)/g, "$&lang-")
  return elt("pre", code)
}

render.heading = (node, options) => wrap(node, options, "h" + node.attrs.level)

render.horizontal_rule = node => elt("hr")

render.bullet_list = (node, options) => {
  let dom = wrap(node, options, "ul")
  let bul = node.attrs.bullet
  dom.setAttribute("class", bul == "+" ? "bullet_plus" : bul == "-" ? "bullet_dash" : "bullet_star")
  if (node.attrs.tight) dom.setAttribute("class", "tight")
  return dom
}

render.ordered_list = (node, options) => {
  let dom = wrap(node, options, "ol")
  if (node.attrs.order > 1) dom.setAttribute("start", node.attrs.order)
  if (node.attrs.tight) dom.setAttribute("class", "tight")
  return dom
}

render.list_item = wrapIn("li")

render.paragraph = wrapIn("p")

render.html_block = node => {
  let dom = elt("div")
  dom.innerHTML = node.attrs.html
  dom.setAttribute("mm-html", "html_block")
  return dom
}

// Inline content

render.text = node => doc.createTextNode(node.text)

render.image = node => {
  let dom = elt("img")
  dom.setAttribute("src", node.attrs.src)
  if (node.attrs.title) dom.setAttribute("title", node.attrs.title)
  if (node.attrs.alt) dom.setAttribute("alt", node.attrs.alt)
  return dom
}

render.hard_break = node => elt("br")

render.html_tag = node => {
  let dom = elt("span")
  dom.innerHTML = node.attrs.html
  dom.setAttribute("mm-html", "html_tag")
  return dom
}

// Inline styles

renderStyle.em = () => elt("em")

renderStyle.strong = () => elt("strong")

renderStyle.code = () => elt("code")

renderStyle.link = style => {
  let dom = elt("a")
  dom.setAttribute("href", style.href)
  if (style.title) dom.setAttribute("title", style.title)
  return dom
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

import {StyledDnD, StyledTableHead, StyledTableHeaderCell, StyledTableRow} from './StyledTable'
import SortingState from './SortingState'
import ResizingController from './ResizingController'
import {columnPropType, dataPropType} from './propTypes'
import useDnD from './useDnD'
import useResize from './useResize'

const ThContent = ({column, data}) =>
  column.HeaderRenderer
    ? <column.HeaderRenderer column={column} data={data} />
    :

ThContent.propTypes = {
  data: dataPropType,
  column: columnPropType
}

const TableHeader = ({columns, data, onColumnPositionChange, onSortingChange, tableEl, resizeCallback}) => {
  const {dndEvents, dndState} = useDnD(onColumnPositionChange, columns)

  const {resizingColumn, startResize} = useResize(tableEl, resizeCallback)

  const thOnClick = column => e => {
    if (!resizingColumn && column.sorting.sortable) {
      onSortingChange(column.id, e.shiftKey)
    }
  }

  return (

            {column.resizable && <ResizingController column={column} startResize={startResize}/>}
          </StyledTableHeaderCell>
        }
        )}
      </StyledTableRow>
    </StyledTableHead>
  )
}

TableHeader.propTypes = {
  columns: PropTypes.arrayOf(columnPropType).isRequired,
  data: dataPropType,
  onColumnPositionChange: PropTypes.func,
  onSortingChange: PropTypes.func,
  tableEl: PropTypes.shape({current: PropTypes.object}),
  resizeCallback: PropTypes.func
}

export default TableHeader
<commit_msg>refactor(tocco-ui): check sorting for undefined<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import {StyledDnD, StyledTableHead, StyledTableHeaderCell, StyledTableRow} from './StyledTable'
import SortingState from './SortingState'
import ResizingController from './ResizingController'
import {columnPropType, dataPropType} from './propTypes'
import useDnD from './useDnD'
import useResize from './useResize'

const ThContent = ({column, data}) =>
  column.HeaderRenderer
    ? <column.HeaderRenderer column={column} data={data} />
    :

ThContent.propTypes = {
  data: dataPropType,
  column: columnPropType
}

const TableHeader = ({columns, data, onColumnPositionChange, onSortingChange, tableEl, resizeCallback}) => {
  const {dndEvents, dndState} = useDnD(onColumnPositionChange, columns)

  const {resizingColumn, startResize} = useResize(tableEl, resizeCallback)

  const thOnClick = column => e => {
    if (!resizingColumn && column.sorting && column.sorting.sortable) {
      onSortingChange(column.id, e.shiftKey)
    }
  }

  return (

            {column.resizable && <ResizingController column={column} startResize={startResize}/>}
          </StyledTableHeaderCell>
        }
        )}
      </StyledTableRow>
    </StyledTableHead>
  )
}

TableHeader.propTypes = {
  columns: PropTypes.arrayOf(columnPropType).isRequired,
  data: dataPropType,
  onColumnPositionChange: PropTypes.func,
  onSortingChange: PropTypes.func,
  tableEl: PropTypes.shape({current: PropTypes.object}),
  resizeCallback: PropTypes.func
}

export default TableHeader
<|endoftext|>


<commit_before>var command = {
  command: 'exec',
  description: 'Execute a JS module within this Truffle environment',
  builder: {
    file: {
      type: "string"
    }
  },
  run: function (options, done) {
    var Config = require("truffle-config");
    var ConfigurationError = require("../errors/configurationerror");
    var Require = require("truffle-require");
    var Environment = require("../environment");
    var path = require("path");
    var OS = require("os");

    var config = Config.detect(options);

    var file = options.file;

    if (file == null && options._.length > 0) {
      file = options._[0];
    }

    if (file == null) {
      done(new ConfigurationError("Please specify a file, passing the path of the script you'd like the run. Note that all scripts *must* call process.exit() when finished."));
      return;
    }

    if (path.isAbsolute(file) == false) {
      file = path.join(process.cwd(), file);
    }

    Environment.detect(config, function(err) {
      if (err) return done(err);

      if (config.networkHint !== false) {
        config.logger.log("Using network '" + config.network + "'." + OS.EOL);
      }

      Require.exec(config.with({
        file: file
      }), done);
    });
  }
}

module.exports = command;
<commit_msg>Compile contracts before running exec<commit_after>var command = {
  command: 'exec',
  description: 'Execute a JS module within this Truffle environment',
  builder: {
    file: {
      type: "string"
    }
  },
  run: function (options, done) {
    var Config = require("truffle-config");
    var Contracts = require("truffle-workflow-compile");
    var ConfigurationError = require("../errors/configurationerror");
    var Require = require("truffle-require");
    var Environment = require("../environment");
    var path = require("path");
    var OS = require("os");

    var config = Config.detect(options);

    var file = options.file;

    if (file == null && options._.length > 0) {
      file = options._[0];
    }

    if (file == null) {
      done(new ConfigurationError("Please specify a file, passing the path of the script you'd like the run. Note that all scripts *must* call process.exit() when finished."));
      return;
    }

    if (path.isAbsolute(file) == false) {
      file = path.join(process.cwd(), file);
    }

    Environment.detect(config, function(err) {
      if (err) return done(err);

      if (config.networkHint !== false) {
        config.logger.log("Using network '" + config.network + "'." + OS.EOL);
      }

      Contracts.compile(config, function(err){
        if(err) return done(err);

        Require.exec(config.with({
          file: file
        }), done);
      });
    });
  }
}

module.exports = command;
<|endoftext|>


<commit_before>function buildTypedUrlList() {
  // this function is largely unchanged from the google example
  var microsecondsPerWeek = 1000 * 60 * 60 * 24 * 7;
  var oneWeekAgo = (new Date).getTime() - microsecondsPerWeek;

  // Track the number of callbacks from chrome.history.getVisits()
  // that we expect to get.  When it reaches zero, we have all results.
  var numRequestsOutstanding = 0;

  chrome.history.search({
    'text': '',              // Return every history item...
    'startTime': oneWeekAgo  // that was accessed less than one week ago.
    },
   function(historyItems) {
    // For each history item, get details on all visits.

    for (var i = 0; i < historyItems.length; ++i) {
      var url = historyItems[i].url;
      var processVisitsWithUrl = function(url) {
        // We need the url of the visited item to process the visit.
        // Use a closure to bind the  url into the callback's args.
        return function(visitItems) {
          processVisits(url, visitItems); // call function defined below
        };
      };
      chrome.history.getVisits({url: url}, processVisitsWithUrl(url));
      numRequestsOutstanding++;
    }
    if (!numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  });

  // Maps URLs to a count of the number of times the user typed that URL into
  // the omnibox.
  var urlToCount = {};

  // Callback for chrome.history.getVisits().  Counts the number of
  // times a user visited a URL.
  var processVisits = function(url, visitItems) {
    for (var i = 0, ie = visitItems.length; i < ie; ++i) {

      if (!urlToCount[url]) {
        urlToCount[url] = 0;
      }

      urlToCount[url]++;
    }

    // If this is the final outstanding call to processVisits(),
    // then we have the final results.  Use them to build the list
    // of URLs to show in the popup.
    if (!--numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  };

  // This function is called when we have the final list of URls to display.
  var onAllVisitsProcessed = function() {
   // Get the top scorring urls.
   urlArray = [];
   for (var url in urlToCount) {
     urlArray.push(url);
   }

   // Sort the URLs by the number of times the user typed them.
   urlArray.sort(function(a, b) {
     return urlToCount[b] - urlToCount[a];
   });

   printTopResults(urlArray, urlToCount);
  };
}

var printTopResults = function(topResults, allResults) {
  top_results_array = new Array(); // object to store pie chart data

  // print the top 10 urls w/counts:
  for (var i in topResults.slice(0, 10)) {
    url = topResults[i];
    count = allResults[topResults[i]];

    // grab the hostname from the url with this hack
    var link_element = document.createElement('a');
    link_element.href = url;
    link_element.text = link_element.hostname;
    link_element.title = url; // set hover text

    // create an li for each site, and append the link created above
    var line_item = document.createElement('li');
    line_item.appendChild(link_element);
    // add the count to the li
    var count_text = document.createTextNode(', ' + count + ' times.');
    line_item.appendChild(count_text);

    // append each line item to the appropriate ol element
    var ordered_list = document.getElementById('top-sites-list');
    ordered_list.appendChild(line_item);

    // this is massaged data for the pie chart
    var tmp = new Object();
    tmp.label = link_element.hostname;
    tmp.value = count;
    top_results_array.push(tmp);
  }
  createPieChart(top_results_array);
}

var createPieChart = function(allResults) {
  var data = allResults

  nv.addGraph(function() {
  var chart = nv.models.pieChart()
    .x(function(d) { return d.label })
    .y(function(d) { return d.value })
    .showLegend(false)
    .labelType("percent")
    .showLabels(true);

  d3.select("#pie-chart-content svg")
    .datum(data)
    .transition().duration(350)
    .call(chart);

    return chart;
  });
}

var addButtonListeners = function(){
  var top_sites_button = document.getElementById('top-sites-button');
  top_sites_button.addEventListener('click', function(){
    console.log('clicked top-sites');
    showHiddenContent('pie-chart-content', 'top-sites-content');
  });

  var pie_chart_button = document.getElementById('pie-chart-button');
  pie_chart_button.addEventListener('click', function() {
    showHiddenContent('top-sites-content', 'pie-chart-content');
  })
}

var showHiddenContent = function(currentContent, targetContent) {
  // currentContent is the content that is displayed right now
  // targetContent is the element that we want to show

  hideContent(currentContent);

  var to_show = document.getElementById(targetContent);
  to_show.style.display = 'block';

}

var hideContent = function(currentContent) {
  var to_hide = document.getElementById(currentContent);
  to_hide.style.display = 'none';
}

document.addEventListener('DOMContentLoaded', function () {
  // Function to add event listener to buttons
  addButtonListeners();

  // entry point into history api stuff
  buildTypedUrlList();
});
<commit_msg>This commit adds binning url's by domain.<commit_after>function buildTypedUrlList() {
  // this function is largely unchanged from the google example
  var microsecondsPerWeek = 1000 * 60 * 60 * 24 * 7;
  var oneWeekAgo = (new Date).getTime() - microsecondsPerWeek;

  // Track the number of callbacks from chrome.history.getVisits()
  // that we expect to get.  When it reaches zero, we have all results.
  var numRequestsOutstanding = 0;

  chrome.history.search({
    'text': '',              // Return every history item...
    'startTime': oneWeekAgo  // that was accessed less than one week ago.
    },
   function(historyItems) {
    // For each history item, get details on all visits.

    for (var i = 0; i < historyItems.length; ++i) {
      var url = historyItems[i].url;
      var processVisitsWithUrl = function(url) {
        // We need the url of the visited item to process the visit.
        // Use a closure to bind the  url into the callback's args.
        return function(visitItems) {
          processVisits(url, visitItems); // call function defined below
        };
      };
      chrome.history.getVisits({url: url}, processVisitsWithUrl(url));
      numRequestsOutstanding++;
    }
    if (!numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  });

  // Maps URLs to a count of the number of times the user visited that URL
  var urlToCount = {};

  // Callback for chrome.history.getVisits().  Counts the number of
  // times a user visited a URL.
  var processVisits = function(url, visitItems) {
    for (var i = 0, ie = visitItems.length; i < ie; ++i) {
      var link_element = document.createElement('a');
      link_element.href = url;

      if (!urlToCount[link_element.hostname]) {
        urlToCount[link_element.hostname] = 0;
      }

      urlToCount[link_element.hostname]++;
    }

    // If this is the final outstanding call to processVisits(),
    // then we have the final results.  Use them to build the list
    // of URLs to show in the popup.
    if (!--numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  };

  // This function is called when we have the final list of URls to display.
  var onAllVisitsProcessed = function() {
   // Get the top scoring urls.
   urlArray = [];
   for (var url in urlToCount) {
     urlArray.push(url);
   }

   // Sort the URLs by the number of times the user typed them.
   urlArray.sort(function(a, b) {
     return urlToCount[b] - urlToCount[a];
   });

   // urlArray-> sorted array
   // urlToCount-> full object
   printTopResults(urlArray, urlToCount);
  };
}

var printTopResults = function(topResults, allResults) {
  top_results_array = new Array(); // object to store pie chart data

  for (var i in topResults) {
    url = topResults[i];
    count = allResults[topResults[i]];

    // grab the hostname from the url with this hack
    var link_element = document.createElement('a');
    link_element.href = 'http://' + url;
    link_element.text = url;
    link_element.target = 'blank';

    // create an li for each site, and append the link created above
    var line_item = document.createElement('li');
    line_item.appendChild(link_element);
    // add the count to the li
    var count_text = document.createTextNode(', ' + count + ' times.');
    line_item.appendChild(count_text);

    if (i <= 9) { // print the top 10 urls w/counts:
      // append each line item to the appropriate ol element
      var ordered_list = document.getElementById('top-sites-list');
      ordered_list.appendChild(line_item);
    }

    // this is massaged data for the pie chart
    var tmp = new Object();
    tmp.label = url;
    tmp.value = count;
    top_results_array.push(tmp);
  }
  createPieChart(top_results_array);
}

var createPieChart = function(top_results_array) {
  var data = top_results_array

  nv.addGraph(function() {
  var chart = nv.models.pieChart()
    .x(function(d) { return d.label })
    .y(function(d) { return d.value })
    .showLegend(false)
    .labelType("percent")
    .showLabels(true);

  d3.select("#pie-chart-content svg")
    .datum(data)
    .transition().duration(350)
    .call(chart);

    return chart;
  });
}

var addButtonListeners = function(){
  var top_sites_button = document.getElementById('top-sites-button');
  top_sites_button.addEventListener('click', function(){
    showHiddenContent('pie-chart-content', 'top-sites-content');
  });

  var pie_chart_button = document.getElementById('pie-chart-button');
  pie_chart_button.addEventListener('click', function() {
    showHiddenContent('top-sites-content', 'pie-chart-content');
  })
}

var showHiddenContent = function(currentContent, targetContent) {
  // currentContent is the content that is displayed right now
  // targetContent is the element that we want to show

  hideContent(currentContent);

  var to_show = document.getElementById(targetContent);
  to_show.style.display = 'block';

}

var hideContent = function(currentContent) {
  var to_hide = document.getElementById(currentContent);
  to_hide.style.display = 'none';
}

document.addEventListener('DOMContentLoaded', function () {
  // Function to add event listener to buttons
  addButtonListeners();

  // entry point into history api stuff
  buildTypedUrlList();
});
<|endoftext|>


<commit_before>// document identifiers
var TOP_SITES_CONTENT_ID = 'top-sites-content';
var PIE_CHART_CONTENT_ID = 'pie-chart-content';
var TOP_SITES_BUTTON_ID = 'top-sites-button';
var PIE_CHART_BUTTON_ID = 'pie-chart-button';
var TIMESLICE_SELECT_ID = 'timesliceSelectBox';
var TOP_SITES_LIST_ID = 'top-sites-list';
var TIME_LABEL_ID = 'time-label-span';

// default coloring
var ACTIVE_BACKGROUND_COLOR = '#FCFCFC';
var DORMANT_BACKGROUND_COLOR = 'white';
var BORDER_COLOR = 'black';

// time slice identifiers
var WEEK = '1'
var MONTH = '2'
var YEAR = '3'

function buildHistoryItemList(timeslice) {
  // set default value
  if (typeof timeslice === 'undefined') { timeslice = WEEK; }
  var searchDepth = 0

  // determine how far back to go
  if (timeslice == WEEK) {
    var microsecondsPerWeek = 1000 * 60 * 60 * 24 * 7;
    searchDepth = (new Date).getTime() - microsecondsPerWeek;
  } else if (timeslice == MONTH) {
    var microsecondsPerMonth = 1000 * 60 * 60 * 24 * 30;
    searchDepth = (new Date).getTime() - microsecondsPerMonth;
  } else {
    var microsecondsPerYear = 1000 * 60 * 60 * 24 * 360;
    searchDepth = (new Date).getTime() - microsecondsPerYear;
  }

  console.log(timeslice);

  // Track the number of callbacks from chrome.history.getVisits()
  // that we expect to get.  When it reaches zero, we have all results.
  var numRequestsOutstanding = 0;

  chrome.history.search({
    'text': '',              // Return every history item...
    'startTime': searchDepth,  // accessed less than x time ago.
    'maxResults': 0 // 0 == all results
    },
   function(historyItems) {
    // For each history item, get details on all visits.

    for (var i = 0; i < historyItems.length; ++i) {
      var url = historyItems[i].url;
      var processVisitsWithUrl = function(url) {
        // We need the url of the visited item to process the visit.
        // Use a closure to bind the  url into the callback's args.
        return function(visitItems) {
          processVisits(url, visitItems); // call function defined below
        };
      };
      chrome.history.getVisits({url: url}, processVisitsWithUrl(url));
      numRequestsOutstanding++;
    }
    if (!numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  });

  // Maps URLs to a count of the number of times the user visited that URL
  var urlCountObject = {};

  // Callback for chrome.history.getVisits().  Counts the number of
  // times a user visited a URL.
  var processVisits = function(url, visitItems) {
    for (var i = 0, ie = visitItems.length; i < ie; ++i) {
      // hack to get simple domains from a given url
      var rootDomain = new URL(url).hostname

      if (!urlCountObject[rootDomain]) {
        urlCountObject[rootDomain] = 0;
      }

      urlCountObject[rootDomain]++;
    }

    // If this is the final outstanding call to processVisits(),
    // then we have the final results.  Use them to build the list
    // of URLs to show in the popup.
    if (!--numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  };

  // This function is called when we have the final list of URls to display.
  var onAllVisitsProcessed = function() {
   sortedUrlArray = [];
   for (var url in urlCountObject) {
     sortedUrlArray.push(url);
   }

   // Sort the URLs by the number of times the user typed them.
   sortedUrlArray.sort(function(a, b) {
     return urlCountObject[b] - urlCountObject[a];
   });

   printTopResults(sortedUrlArray, urlCountObject);
  };
}

var printTopResults = function(sortedUrlArray, urlCountObject) {
  pieChartData = new Array(); // object to store pie chart data

  for (var i in sortedUrlArray) {
    url = sortedUrlArray[i];
    count = urlCountObject[sortedUrlArray[i]];

    // grab the hostname from the url with this hack
    var linkElement = document.createElement('a');
    linkElement.href = 'http://' + url;
    linkElement.text = url;
    linkElement.target = 'blank';

    // create an li for each site, and append the link created above
    var lineItemElement = document.createElement('li');
    lineItemElement.appendChild(linkElement);
    // add the count to the li
    var countText = document.createTextNode(', ' + count + ' times.');
    lineItemElement.appendChild(countText);

    if (i <= 9) { // print the top 10 urls w/counts:
      // append each line item to the appropriate ol element
      var orderedListElement = document.getElementById('top-sites-list');
      orderedListElement.appendChild(lineItemElement);
    }

    // this is massaged data for the pie chart
    var tmp = new Object();
    tmp.label = url;
    tmp.value = count;
    pieChartData.push(tmp);
  }
  createPieChart(pieChartData);
}

var createDropShadowFilter = function() {
  var svg = d3.select('svg');
  var defs = svg.append("defs");

  var filter = defs.append("filter")
      .attr("id", "dropshadow")

  filter.append("feGaussianBlur")
      .attr("in", "SourceAlpha")
      .attr("stdDeviation", 4)
      .attr("result", "blur");
  filter.append("feOffset")
      .attr("in", "blur")
      .attr("dx", 2)
      .attr("dy", 2)
      .attr("result", "offsetBlur");

  var feMerge = filter.append("feMerge");

  feMerge.append("feMergeNode")
      .attr("in", "offsetBlur")
  feMerge.append("feMergeNode")
      .attr("in", "SourceGraphic");
}

var createPieChart = function(pieChartData) {
  var data = pieChartData;

  nv.addGraph(function() {
  var chart = nv.models.pieChart()
    .x(function(d) { return d.label })
    .y(function(d) { return d.value })
    .showLegend(false)
    .labelType("percent")
    .tooltipContent(function(key, y, e, graph) { return key + ', ' +
      e.value + ' visits.' })
    .labelThreshold(.05)
    .showLabels(true);

  createDropShadowFilter();

  d3.selectAll("svg")
  .attr("class", "shadow")
  .attr("filter", "url(#dropshadow)");

  d3.select("#chart svg")
    .datum(data)
    .transition().duration(1200)
    .call(chart);

  return chart;
  });
}

var addListeners = function() {
  addTabChangeListeners();
  addTimesliceListeners();
}

var addTabChangeListeners = function(){
  var topSitesButton = document.getElementById(TOP_SITES_BUTTON_ID);
  var pieChartButton = document.getElementById(PIE_CHART_BUTTON_ID);

  topSitesButton.addEventListener('click', function(){
    showHiddenContent(PIE_CHART_CONTENT_ID, TOP_SITES_CONTENT_ID,
      topSitesButton, pieChartButton);
  });

  pieChartButton.addEventListener('click', function() {
    showHiddenContent(TOP_SITES_CONTENT_ID, PIE_CHART_CONTENT_ID,
      pieChartButton, topSitesButton);
  })
}

var clearCurrentContents = function(targetNode) {
  // clears the content of a node
  var node = document.getElementById(targetNode);
  if (node) {
    while (node.firstChild) {
      node.removeChild(node.firstChild);
    }
  }
}

var addTimesliceListeners = function() {
  // listen to onchange events and rebuild the display using new data
  var timesliceSelectBox = document.getElementById(TIMESLICE_SELECT_ID);
  timesliceSelectBox.onchange = function (e) {
    var selectedOption = this[this.selectedIndex];
    var selectedValue = selectedOption.value;
    var timesliceLabelDisplay = document.getElementById(TIME_LABEL_ID);
    timesliceLabelDisplay.innerHTML = selectedOption.innerText;
    console.log(selectedOption)
    targetNode = TOP_SITES_LIST_ID;
    clearCurrentContents(targetNode);
    buildHistoryItemList(selectedValue);
  }
}

var showHiddenContent = function(currentContent, targetContent, callingButton,
  currentButton) {
  // currentContent is the content that is displayed right now
  // targetContent is the element that we want to show
  // callingButton is the button that was clicked to fire the event
  var displayStyle = 'block';

  hideContent(currentContent, currentButton);

  var toShow = document.getElementById(targetContent);
  toShow.style.display = displayStyle;
  callingButton.style.borderBottomColor = ACTIVE_BACKGROUND_COLOR;
  callingButton.style.backgroundColor = ACTIVE_BACKGROUND_COLOR;
}

var hideContent = function(currentContent, currentButton) {
  // set styling to default
  var toHide = document.getElementById(currentContent);

  toHide.style.display = 'none';
  currentButton.style.borderBottomColor = BORDER_COLOR;
  currentButton.style.backgroundColor = DORMANT_BACKGROUND_COLOR;
}

document.addEventListener('DOMContentLoaded', function () {
  // add event listeners to elements
 addListeners();

  // entry point
  buildHistoryItemList();
});
<commit_msg>Display only the top 10 sites a user has visited.<commit_after>// document identifiers
var TOP_SITES_CONTENT_ID = 'top-sites-content';
var PIE_CHART_CONTENT_ID = 'pie-chart-content';
var TOP_SITES_BUTTON_ID = 'top-sites-button';
var PIE_CHART_BUTTON_ID = 'pie-chart-button';
var TIMESLICE_SELECT_ID = 'timesliceSelectBox';
var TOP_SITES_LIST_ID = 'top-sites-list';
var TIME_LABEL_ID = 'time-label-span';

// default coloring
var ACTIVE_BACKGROUND_COLOR = '#FCFCFC';
var DORMANT_BACKGROUND_COLOR = 'white';
var BORDER_COLOR = 'black';

// time slice identifiers
var WEEK = '1';
var MONTH = '2';
var YEAR = '3';
var TOP_X = 10; // top X items to show to the user

function buildHistoryItemList(timeslice) {
  // set default value
  if (typeof timeslice === 'undefined') { timeslice = WEEK; }
  var searchDepth = 0

  // determine how far back to go
  if (timeslice == WEEK) {
    var microsecondsPerWeek = 1000 * 60 * 60 * 24 * 7;
    searchDepth = (new Date).getTime() - microsecondsPerWeek;
  } else if (timeslice == MONTH) {
    var microsecondsPerMonth = 1000 * 60 * 60 * 24 * 30;
    searchDepth = (new Date).getTime() - microsecondsPerMonth;
  } else {
    var microsecondsPerYear = 1000 * 60 * 60 * 24 * 360;
    searchDepth = (new Date).getTime() - microsecondsPerYear;
  }

  // Track the number of callbacks from chrome.history.getVisits()
  // that we expect to get.  When it reaches zero, we have all results.
  var numRequestsOutstanding = 0;

  chrome.history.search({
    'text': '',              // Return every history item...
    'startTime': searchDepth,  // accessed less than x time ago.
    'maxResults': 0 // 0 == all results
    },
   function(historyItems) {
    // For each history item, get details on all visits.

    for (var i = 0; i < historyItems.length; ++i) {
      var url = historyItems[i].url;
      var processVisitsWithUrl = function(url) {
        // We need the url of the visited item to process the visit.
        // Use a closure to bind the  url into the callback's args.
        return function(visitItems) {
          processVisits(url, visitItems); // call function defined below
        };
      };
      chrome.history.getVisits({url: url}, processVisitsWithUrl(url));
      numRequestsOutstanding++;
    }
    if (!numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  });

  // Maps URLs to a count of the number of times the user visited that URL
  var urlCountObject = {};

  // Callback for chrome.history.getVisits().  Counts the number of
  // times a user visited a URL.
  var processVisits = function(url, visitItems) {
    for (var i = 0, ie = visitItems.length; i < ie; ++i) {
      // get simple domains from a given url
      var rootDomain = new URL(url).hostname;

      if (!urlCountObject[rootDomain]) {
        urlCountObject[rootDomain] = 0;
      }

      urlCountObject[rootDomain]++;
    }

    // If this is the final outstanding call to processVisits(),
    // then we have the final results.  Use them to build the list
    // of URLs to show in the popup.
    if (!--numRequestsOutstanding) {
      onAllVisitsProcessed();
    }
  };

  // This function is called when we have the final list of URls to display.
  var onAllVisitsProcessed = function() {
   sortedUrlArray = [];
   for (var url in urlCountObject) {
     // add every url entry in the object to an array for sorting
     sortedUrlArray.push(url);
   }

   // Sort the URLs by the number of times the user typed them.
   sortedUrlArray.sort(function(a, b) {
     return urlCountObject[b] - urlCountObject[a];
   });

   printTopResults(sortedUrlArray, urlCountObject);
  };
}

var printTopResults = function(sortedUrlArray, urlCountObject) {
  pieChartData = new Array(); // object to store pie chart data

  // for (var i in sortedUrlArray) {
  for (var i =0; i < TOP_X; i++) {
    url = sortedUrlArray[i];
    count = urlCountObject[sortedUrlArray[i]];

    // grab the hostname from the url with this hack
    var linkElement = document.createElement('a');
    linkElement.href = 'http://' + url;
    linkElement.text = url;
    linkElement.target = 'blank';

    // create an li for each site, and append the link created above
    var lineItemElement = document.createElement('li');
    lineItemElement.appendChild(linkElement);
    // add the count to the li
    var countText = document.createTextNode(', ' + count + ' times.');
    lineItemElement.appendChild(countText);

    if (i <= 9) { // print the top 10 urls w/counts:
      // append each line item to the appropriate ol element
      var orderedListElement = document.getElementById('top-sites-list');
      orderedListElement.appendChild(lineItemElement);
    }

    // this is massaged data for the pie chart
    var tmp = new Object();
    tmp.label = url;
    tmp.value = count;
    pieChartData.push(tmp);
  }
  createPieChart(pieChartData);
}

var createDropShadowFilter = function() {
  var svg = d3.select('svg');
  var defs = svg.append("defs");

  var filter = defs.append("filter")
      .attr("id", "dropshadow")

  filter.append("feGaussianBlur")
      .attr("in", "SourceAlpha")
      .attr("stdDeviation", 4)
      .attr("result", "blur");
  filter.append("feOffset")
      .attr("in", "blur")
      .attr("dx", 2)
      .attr("dy", 2)
      .attr("result", "offsetBlur");

  var feMerge = filter.append("feMerge");

  feMerge.append("feMergeNode")
      .attr("in", "offsetBlur")
  feMerge.append("feMergeNode")
      .attr("in", "SourceGraphic");
}

var createPieChart = function(pieChartData) {
  var data = pieChartData;

  nv.addGraph(function() {
  var chart = nv.models.pieChart()
    .x(function(d) { return d.label })
    .y(function(d) { return d.value })
    .showLegend(false)
    .labelType("percent")
    .tooltipContent(function(key, y, e, graph) { return key + ', ' +
      e.value + ' visits.' })
    .labelThreshold(.05)
    .showLabels(true);

  createDropShadowFilter();

  d3.selectAll("svg")
  .attr("class", "shadow")
  .attr("filter", "url(#dropshadow)");

  d3.select("#chart svg")
    .datum(data)
    .transition().duration(1200)
    .call(chart);

  return chart;
  });
}

var addListeners = function() {
  addTabChangeListeners();
  addTimesliceListeners();
}

var addTabChangeListeners = function(){
  var topSitesButton = document.getElementById(TOP_SITES_BUTTON_ID);
  var pieChartButton = document.getElementById(PIE_CHART_BUTTON_ID);

  topSitesButton.addEventListener('click', function(){
    showHiddenContent(PIE_CHART_CONTENT_ID, TOP_SITES_CONTENT_ID,
      topSitesButton, pieChartButton);
  });

  pieChartButton.addEventListener('click', function() {
    showHiddenContent(TOP_SITES_CONTENT_ID, PIE_CHART_CONTENT_ID,
      pieChartButton, topSitesButton);
  })
}

var clearCurrentContents = function(targetNode) {
  // clears the content of a node
  var node = document.getElementById(targetNode);
  if (node) {
    while (node.firstChild) {
      node.removeChild(node.firstChild);
    }
  }
}

var addTimesliceListeners = function() {
  // listen to onchange events and rebuild the display using new data
  var timesliceSelectBox = document.getElementById(TIMESLICE_SELECT_ID);
  timesliceSelectBox.onchange = function (e) {
    var selectedOption = this[this.selectedIndex];
    var selectedValue = selectedOption.value;
    var timesliceLabelDisplay = document.getElementById(TIME_LABEL_ID);
    timesliceLabelDisplay.innerHTML = selectedOption.innerText;
    targetNode = TOP_SITES_LIST_ID;
    clearCurrentContents(targetNode);
    buildHistoryItemList(selectedValue);
  }
}

var showHiddenContent = function(currentContent, targetContent, callingButton,
  currentButton) {
  // currentContent is the content that is displayed right now
  // targetContent is the element that we want to show
  // callingButton is the button that was clicked to fire the event
  var displayStyle = 'block';

  hideContent(currentContent, currentButton);

  var toShow = document.getElementById(targetContent);
  toShow.style.display = displayStyle;
  callingButton.style.borderBottomColor = ACTIVE_BACKGROUND_COLOR;
  callingButton.style.backgroundColor = ACTIVE_BACKGROUND_COLOR;
}

var hideContent = function(currentContent, currentButton) {
  // set styling to default
  var toHide = document.getElementById(currentContent);

  toHide.style.display = 'none';
  currentButton.style.borderBottomColor = BORDER_COLOR;
  currentButton.style.backgroundColor = DORMANT_BACKGROUND_COLOR;
}

document.addEventListener('DOMContentLoaded', function () {
  // add event listeners to elements
 addListeners();

  // entry point
  buildHistoryItemList();
});
<|endoftext|>


<commit_before>import { initiateAutoUpdater } from './auto-updater';

const { app, dialog }  = require('electron');
const { autoUpdater } = require('electron-updater');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const expect = chai.expect;

chai.use(sinonChai);

describe('AutoUpdater', () => {
  it('should check for updates on app ready', done => {
    sinon.stub(autoUpdater, 'checkForUpdates');

    app.on('ready', () => {
      setTimeout(() => {

        expect(autoUpdater.checkForUpdates).to.have.been.called;
        done();
      });
    });

    initiateAutoUpdater();
    app.emit('ready');
  });

  it('should show a dialog when an error occurs', () => {
    sinon.stub(dialog, 'showMessageBox');

    initiateAutoUpdater();
    autoUpdater.emit('error');

    expect(dialog.showMessageBox).to.have.been.called;
    dialog.showMessageBox.restore();
  });

  it('should show adialog when a new update has downloaded', () => {
    sinon.stub(dialog, 'showMessageBox');

    initiateAutoUpdater();
    autoUpdater.emit('update-downloaded', {});

    expect(dialog.showMessageBox).to.have.been.called;
    dialog.showMessageBox.restore();
  });
});
<commit_msg>autoupdate: restore autoUpdater stub after unit test<commit_after>import { initiateAutoUpdater } from './auto-updater';

const { app, dialog }  = require('electron');
const { autoUpdater } = require('electron-updater');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const expect = chai.expect;

chai.use(sinonChai);

describe('AutoUpdater', () => {
  it('should check for updates on app ready', done => {
    sinon.stub(autoUpdater, 'checkForUpdates');

    initiateAutoUpdater();

    app.emit('ready');

    setTimeout(() => {

      expect(autoUpdater.checkForUpdates).to.have.been.called;
      autoUpdater.checkForUpdates.restore();
      done();
    });
  });

  it('should show a dialog when an error occurs', () => {
    sinon.stub(dialog, 'showMessageBox');

    initiateAutoUpdater();
    autoUpdater.emit('error');

    expect(dialog.showMessageBox).to.have.been.called;
    dialog.showMessageBox.restore();
  });

  it('should show adialog when a new update has downloaded', () => {
    sinon.stub(dialog, 'showMessageBox');

    initiateAutoUpdater();
    autoUpdater.emit('update-downloaded', {});

    expect(dialog.showMessageBox).to.have.been.called;
    dialog.showMessageBox.restore();
  });
});
<|endoftext|>