<commit_before>// dialbackclientrequest.js
//
// Keep track of the requests we've made
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var databank = require("databank"),
    _ = require("underscore"),
    DatabankObject = databank.DatabankObject,
    Step = require("step"),
    randomString = require("../randomstring").randomString,
    Stream = require("./stream").Stream,
    NoSuchThingError = databank.NoSuchThingError;

var DialbackRequest = DatabankObject.subClass("dialbackrequest");

DialbackRequest.schema = {
    pkey: "endpoint_id_token_timestamp",
    fields: ["endpoint",
             "id",
             "token",
             "timestamp"]
};

exports.DialbackRequest = DialbackRequest;

DialbackRequest.toKey = function(props) {
    return props.endpoint + "/" + props.id + "/" + props.token + "/" + props.timestamp;
};

DialbackRequest.beforeCreate = function(props, callback) {

    if (!_(props).has("endpoint") ||
        !_(props).has("id") ||
        !_(props).has("token") ||
        !_(props).has("timestamp")) {
        callback(new Error("Wrong properties"), null);
        return;
    }

    props.endpoint_id_token_timestamp = DialbackRequest.toKey(props);

    callback(null, props);
};

// We keep a stream of all requests for cleanup

DialbackRequest.prototype.afterCreate = function(callback) {
    var req = this;

    Step(
        function() {
            DialbackRequest.stream(this);
        },
        function(err, str) {
            if (err) throw err;
            str.deliver(req.endpoint_id_token_timestamp, this);
        },
        callback
    );
};

DialbackRequest.cleanup = function(callback) {

    var cleanupFirst = function(str, callback) {
        var ids, cleaned;
        Step(
            function() {
                str.getIDs(0, 20, this);
            },
            function(err, res) {
                if (err) throw err;
                ids = res;
                if (ids.length == 0) {
                    cb(null);
                } else {
                    cleanupIDs(ids, this);
                }
            },
            function(err, res) {
                if (err) throw err;
                cleaned = res;
                cleanupRest(str, ids[ids.length - 1], this);
            },
            function(err) {
                if (err) throw err;
                removeIDs(str, cleaned, this);
            },
            callback
        );
    },
        cleanupRest = function(str, key, callback) {
            var ids, cleaned;
            Step(
                function() {
                    str.getIDsGreaterThan(key, 20, this);
                },
                function(err, res) {
                    if (err) throw err;
                    ids = res;
                    if (ids.length == 0) {
                        callback(null);
                    } else {
                        cleanupIDs(ids, this);
                    }
                },
                function(err, res) {
                    if (err) throw err;
                    cleaned = res;
                    cleanupRest(str, ids[ids.length - 1], this);
                },
                function(err) {
                    if (err) throw err;
                    removeIDs(str, cleaned, this);
                },
                callback
            );
        },
        maybeCleanup = function(id, callback) {
            Step(
                function() {
                    DialbackRequest.get(id, this);
                },
                function(err, req) {
                    if (err && (err.name == "NoSuchThingError")) {
                        callback(null, true);
                    } else if (err) {
                        callback(err, null);
                    } else {
                        if (Date.now() - req.timestamp > 300000) {
                            req.del(this);
                        } else {
                            callback(null, false);
                        }
                    }
                },
                function(err) {
                    if (err) {
                        callback(err, null);
                    } else {
                        callback(null, true);
                    }
                }
            );
        },
        cleanupIDs = function(ids, callback) {
            Step(
                function() {
                    var i, group = this.group();
                    for (i = 0; i < ids.length; i++) {
                        maybeCleanup(ids[i], group());
                    }
                },
                function(err, cleanedUp) {
                    var i, toRemove = [];
                    if (err) throw err;

                    for (i = 0; i < ids.length; i++) {
                        if (cleanedUp[i]) {
                            toRemove.push(ids[i]);
                        }
                    }

                    callback(null, toRemove);
                },
                callback
            );
        },
        maybeRemove = function(str, id, callback) {
            Step(
                function() {
                    str.remove(id, this);
                },
                function(err) {
                    if (err && err.name == "NotInStreamError") {
                        callback(null);
                    } else if (err) {
                        callback(err);
                    } else {
                        callback(null);
                    }
                }
            );
        },
        removeIDs = function(str, ids, callback) {

            Step(
                function() {
                    var i, group = this.group();
                    for (i = 0; i < ids.length; i++) {
                        maybeRemove(str, ids[i], group());
                    }
                },
                function(err, ids) {
                    if (err) {
                        callback(err);
                    } else {
                        callback(null);
                    }
                }
            );
        };

    Step(
        function() {
            DialbackRequest.stream(this);
        },
        function(err, str) {
            if (err) throw err;
            cleanupFirst(str, this);
        },
        function(err) {
            if (err) {
                callback(err);
            } else {
                callback(null);
            }
        }
    );
};

DialbackRequest.stream = function(callback) {
    var name = "dialbackclientrequest:recent";

    Step(
        function() {
            Stream.get(name, this);
        },
        function(err, str) {
            if (err) {
                if (err.name == "NoSuchThingError") {
                    Stream.create({name: name}, this);
                } else {
                    throw err;
                }
            } else {
                callback(null, str);
            }
        },
        function(err, str) {
            if (err) {
                if (err.name == "AlreadyExistsError") {
                    Stream.get(name, callback);
                } else {
                    callback(err);
                }
            } else {
                callback(null, str);
            }
        }
    );
};

// Clear out old requests every 1 minute

setTimeout(function() {
    // XXX: log errors
    DialbackRequest.cleanup(function(err) {});
}, 60000);
<commit_msg>setTimeout => setInterval<commit_after>// dialbackclientrequest.js
//
// Keep track of the requests we've made
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var databank = require("databank"),
    _ = require("underscore"),
    DatabankObject = databank.DatabankObject,
    Step = require("step"),
    randomString = require("../randomstring").randomString,
    Stream = require("./stream").Stream,
    NoSuchThingError = databank.NoSuchThingError;

var DialbackRequest = DatabankObject.subClass("dialbackrequest");

DialbackRequest.schema = {
    pkey: "endpoint_id_token_timestamp",
    fields: ["endpoint",
             "id",
             "token",
             "timestamp"]
};

exports.DialbackRequest = DialbackRequest;

DialbackRequest.toKey = function(props) {
    return props.endpoint + "/" + props.id + "/" + props.token + "/" + props.timestamp;
};

DialbackRequest.beforeCreate = function(props, callback) {

    if (!_(props).has("endpoint") ||
        !_(props).has("id") ||
        !_(props).has("token") ||
        !_(props).has("timestamp")) {
        callback(new Error("Wrong properties"), null);
        return;
    }

    props.endpoint_id_token_timestamp = DialbackRequest.toKey(props);

    callback(null, props);
};

// We keep a stream of all requests for cleanup

DialbackRequest.prototype.afterCreate = function(callback) {
    var req = this;

    Step(
        function() {
            DialbackRequest.stream(this);
        },
        function(err, str) {
            if (err) throw err;
            str.deliver(req.endpoint_id_token_timestamp, this);
        },
        callback
    );
};

DialbackRequest.cleanup = function(callback) {

    var cleanupFirst = function(str, callback) {
        var ids, cleaned;
        Step(
            function() {
                str.getIDs(0, 20, this);
            },
            function(err, res) {
                if (err) throw err;
                ids = res;
                if (ids.length == 0) {
                    cb(null);
                } else {
                    cleanupIDs(ids, this);
                }
            },
            function(err, res) {
                if (err) throw err;
                cleaned = res;
                cleanupRest(str, ids[ids.length - 1], this);
            },
            function(err) {
                if (err) throw err;
                removeIDs(str, cleaned, this);
            },
            callback
        );
    },
        cleanupRest = function(str, key, callback) {
            var ids, cleaned;
            Step(
                function() {
                    str.getIDsGreaterThan(key, 20, this);
                },
                function(err, res) {
                    if (err) throw err;
                    ids = res;
                    if (ids.length == 0) {
                        callback(null);
                    } else {
                        cleanupIDs(ids, this);
                    }
                },
                function(err, res) {
                    if (err) throw err;
                    cleaned = res;
                    cleanupRest(str, ids[ids.length - 1], this);
                },
                function(err) {
                    if (err) throw err;
                    removeIDs(str, cleaned, this);
                },
                callback
            );
        },
        maybeCleanup = function(id, callback) {
            Step(
                function() {
                    DialbackRequest.get(id, this);
                },
                function(err, req) {
                    if (err && (err.name == "NoSuchThingError")) {
                        callback(null, true);
                    } else if (err) {
                        callback(err, null);
                    } else {
                        if (Date.now() - req.timestamp > 300000) {
                            req.del(this);
                        } else {
                            callback(null, false);
                        }
                    }
                },
                function(err) {
                    if (err) {
                        callback(err, null);
                    } else {
                        callback(null, true);
                    }
                }
            );
        },
        cleanupIDs = function(ids, callback) {
            Step(
                function() {
                    var i, group = this.group();
                    for (i = 0; i < ids.length; i++) {
                        maybeCleanup(ids[i], group());
                    }
                },
                function(err, cleanedUp) {
                    var i, toRemove = [];
                    if (err) throw err;

                    for (i = 0; i < ids.length; i++) {
                        if (cleanedUp[i]) {
                            toRemove.push(ids[i]);
                        }
                    }

                    callback(null, toRemove);
                },
                callback
            );
        },
        maybeRemove = function(str, id, callback) {
            Step(
                function() {
                    str.remove(id, this);
                },
                function(err) {
                    if (err && err.name == "NotInStreamError") {
                        callback(null);
                    } else if (err) {
                        callback(err);
                    } else {
                        callback(null);
                    }
                }
            );
        },
        removeIDs = function(str, ids, callback) {

            Step(
                function() {
                    var i, group = this.group();
                    for (i = 0; i < ids.length; i++) {
                        maybeRemove(str, ids[i], group());
                    }
                },
                function(err, ids) {
                    if (err) {
                        callback(err);
                    } else {
                        callback(null);
                    }
                }
            );
        };

    Step(
        function() {
            DialbackRequest.stream(this);
        },
        function(err, str) {
            if (err) throw err;
            cleanupFirst(str, this);
        },
        function(err) {
            if (err) {
                callback(err);
            } else {
                callback(null);
            }
        }
    );
};

DialbackRequest.stream = function(callback) {
    var name = "dialbackclientrequest:recent";

    Step(
        function() {
            Stream.get(name, this);
        },
        function(err, str) {
            if (err) {
                if (err.name == "NoSuchThingError") {
                    Stream.create({name: name}, this);
                } else {
                    throw err;
                }
            } else {
                callback(null, str);
            }
        },
        function(err, str) {
            if (err) {
                if (err.name == "AlreadyExistsError") {
                    Stream.get(name, callback);
                } else {
                    callback(err);
                }
            } else {
                callback(null, str);
            }
        }
    );
};

// Clear out old requests every 1 minute

setInterval(function() {
    // XXX: log errors
    DialbackRequest.cleanup(function(err) {});
}, 60000);
<|endoftext|>


<commit_before>/**
* @fileOverview
* @author Zoltan Toth
* @version 2.2.0
*/

/**
* @description
* 1Kb (gzipped) pure JavaScript carousel with all the basic features.
*
* @class
* @param {object} options - User defined settings for the carousel.
* @param {string} options.elem - The HTML id of the carousel container.
* @param {(boolean)} [options.circular=false] - Enables circular mode for the slider.
* @param {(boolean)} [options.autoplay=false] - Enables auto play of slides.
* @param {number} [options.interval=3000] - The interval between slide change.
* @param {number} [options.show=0] - Index of the slide to start on. Numeration begins at 0.
* @param {(boolean)} [options.dots=true] - Display navigation dots.
* @param {(boolean)} [options.arrows=true] - Display navigation arrows (PREV/NEXT).
* @param {(boolean)} [options.buttons=true] - Display navigation buttons (STOP/PLAY).
*
* @param {(string)} [options.crslClass=.js-carousel] -  CSS class of the carousel container.
* @param {(string)} [options.crslArrowPrevClass=.arrow_prev] -  CSS class of the _PREV_ arrow.
* @param {(string)} [options.crslArrowNextClass=.arrow_next] -  CSS class of the _NEXT_ arrow.
* @param {(string)} [options.crslDotsClass=.dots] -  CSS class of the nav dots container.
* @param {(string)} [options.crslButtonStopClass=.btn_play] -  CSS class of the _PLAY_ button.
* @param {(string)} [options.crslButtonPlayClass=.btn_stop] -  CSS class of the _STOP_ button.
*
* @param {(string)} [options.btnPlayText=Play] - Text for _PLAY_ button.
* @param {(string)} [options.btnStopText=Stop] - Text for _STOP_ button.
* @param {(string)} [options.arrPrevText=«] - Text for _PREV_ arrow.
* @param {(string)} [options.arrNextText=»] - Text for _NEXT_ arrow.
*/
function Carousel(options) {

    var el = document.getElementById(options.elem || 'carousel'),
        autoplay       = options.autoplay,
        circular       = options.circular,
        interval       = options.interval || 3000,
        controlDots    = options.dots,
        controlArrows  = options.arrows,
        controlButtons = options.buttons,

        crslClass           = options.crslClass           || 'js-carousel',
        crslArrowPrevClass  = options.crslArrowPrevClass  || 'arrow_prev',
        crslArrowNextClass  = options.crslArrowNextClass  || 'arrow_next',
        crslDotsClass       = options.crslDotsClass       || 'dots',
        crslButtonStopClass = options.crslButtonStopClass || 'btn_stop',
        crslButtonPlayClass = options.crslButtonPlayClass || 'btn_play',

        btnPlayText = options.btnPlayText || 'Play',
        btnStopText = options.btnStopText || 'Stop',

        arrNextText = options.arrNextText || '›',
        arrPrevText = options.arrPrevText || '‹',

        count   = el.querySelectorAll('li').length,
        initial = 0 || (options.initial >= count) ? count : options.initial,
        current = 0,
        cycle   = null;

    /**
    * Render the carousel if more than one slide.
    * Otherwise just show the single item.
    */
    if (count > 1) {
        render();
    }

    /**
    * Render the carousel and all the navigation elements (arrows, dots,
    * play/stop buttons) if needed. Start with a particular slide, if set.
    * If circular - move the last item to the very beginning and off the display area.
    */
    function render() {
        if (controlDots) {
            showDots();
        }

        if (controlArrows) {
            showArrows();
        }

        if (controlButtons) {
            showButtons();
        }

        if (autoplay) {
            play();
        }

        if (circular) {
            moveItem(count - 1, -el.offsetWidth + 'px', 'afterBegin');
        }

        if (initial) {
            show(initial);
        }
    }

    /**
    * Helper for moving items - last to be first or first to be the last. Needed
    * for infinite rotation of the carousel.
    *
    * @param {number} i - Position of the list item to move (either first or last).
    * @param {number} marginLeft - Left margin to position the item off-screen
    *        at the beginning or no margin at the end.
    * @param {string} position - Where to insert the item. One of the following -
    *        'afterBegin' or 'beforeEnd'.
    */
    function moveItem(i, marginLeft, position) {
        var itemToMove = el.querySelectorAll('.' + crslClass + ' > ul li')[i];
        itemToMove.style.marginLeft = marginLeft;

        el.querySelector('.' + crslClass + ' > ul')
          .removeChild(itemToMove);

        el.querySelector('.' + crslClass + ' > ul')
          .insertAdjacentHTML(position, itemToMove.outerHTML);
    }

    /**
    * Create the navigation dots and attach to carousel.
    */
    function showDots() {
        var dotContainer = document.createElement('ul');
        dotContainer.classList.add(crslDotsClass);
        dotContainer.addEventListener('click', scrollToImage.bind(this));

        for (var i = 0; i < count; i++) {
            var dotElement = document.createElement('li');
            dotElement.setAttribute('data-position', i);

            dotContainer.appendChild(dotElement);
        }

        el.appendChild(dotContainer);
        currentDot();
    }

    /**
    * Highlight the corresponding dot of the currently visible carousel item.
    */
    function currentDot() {
        [].forEach.call(el.querySelectorAll('.' + crslDotsClass + ' li'), function(item) {
            item.classList.remove('active');
        });

        switch (current) {
            case -1:
                current = count - 1;
                break;
            case count:
                current = 0;
                break;
            default:
                current = current;
        }

        el.querySelectorAll('.' + crslDotsClass + ' li')[current].classList.add('active');
    }

    /**
    * Moves the carousel to the desired slide on a navigation dot click.
    *
    * @param {object} e - The clicked dot element.
    */
    function scrollToImage(e) {
        if (e.target.tagName === 'LI') {
            show(e.target.getAttribute('data-position'));
        }
    }

    /**
    * Create the navigation arrows (prev/next) and attach to carousel.
    */
    function showArrows() {
        var buttonPrev = document.createElement('button');
        buttonPrev.innerHTML = arrPrevText;
        buttonPrev.classList.add(crslArrowPrevClass);

        var buttonNext = document.createElement('button');
        buttonNext.innerHTML = arrNextText;
        buttonNext.classList.add(crslArrowNextClass);

        buttonPrev.addEventListener('click', prev);
        buttonNext.addEventListener('click', next);

        el.appendChild(buttonPrev);
        el.appendChild(buttonNext);
    }

    /**
    * Create the navigation buttons (play/stop) and attach to carousel.
    */
    function showButtons() {
        var buttonPlay = document.createElement('button');
        buttonPlay.innerHTML = btnPlayText;
        buttonPlay.classList.add(crslButtonPlayClass);
        buttonPlay.addEventListener('click', play);

        var buttonStop = document.createElement('button');
        buttonStop.innerHTML = btnStopText;
        buttonStop.classList.add(crslButtonStopClass);
        buttonStop.addEventListener('click', stop);

        el.appendChild(buttonPlay);
        el.appendChild(buttonStop);
    }

    /**
    * Animate the carousel to go back 1 slide. Moves the very first (off-screen)
    * item to the visible area.
    *
    * @param {object} item - The element to move into view.
    */
    function animatePrev(item) {
        item.style.marginLeft = '';
    }

    /**
    * Animate the carousel to go forward 1 slide.
    *
    * @param {object} item - The element to move into view.
    */
    function animateNext(item) {
        item.style.marginLeft = -el.offsetWidth + 'px';
    }

    /**
    * Move the carousel to the desired slide.
    *
    * @param {number} slide - The index of the item.
    * @public
    */
    function show(slide) {
        var delta = current - slide;

        if (delta === 0) {
            return;
        }

        if (delta < 0) {
            for (var i = 0; i < -delta; i++) {
                next();
            }
        } else {
            for (var j = 0; j < delta; j++) {
                prev();
            }
        }
    }

    /**
    * Move the carousel back.
    * Do the sliding, move the last item to the very beginning, highlight the
    * corresponding navigation dot.
    *
    * @public
    */
    function prev() {
        if (circular) {
            animatePrev(el.querySelectorAll('.' + crslClass + ' > ul li')[0]);
            moveItem(count - 1, -el.offsetWidth + 'px', 'afterBegin');
        } else {
            stop();
            if (current === 0) {
                return;
            }
            animatePrev(el.querySelectorAll('.' + crslClass + ' > ul li')[current - 1]);
        }

        current--;

        if (controlDots) {
            currentDot();
        }
    }

    /**
    * Move the carousel forward.
    * Do the sliding, move the second item to the very end, highlight the
    * corresponding navigation dot.
    *
    * @public
    */
    function next() {
        if (circular) {
            animateNext(el.querySelectorAll('.' + crslClass + ' > ul li')[1]);
            moveItem(0, '', 'beforeEnd');
        } else {
            if (current === count - 1) {
                stop();
                return;
            }
            animateNext(el.querySelectorAll('.' + crslClass + ' > ul li')[current]);
        }

        current++;

        if (controlDots) {
            currentDot();
        }
    }

    /**
    * Start the auto play.
    * If already playing do nothing.
    *
    * @public
    */
    function play() {
        if (cycle) {
            return;
        }
        cycle = setInterval(next.bind(this), interval);
    }

    /**
    * Stop the auto play.
    *
    * @public
    */
    function stop() {
        clearInterval(cycle);
        cycle = null;
    }

    /**
    * Returns the current slide index.
    *
    * @public
    */
    function live() {
        return current;
    }

    return {
        'live': live,
        'show': show,
        'prev': prev,
        'next': next,
        'play': play,
        'stop': stop
    };
}<commit_msg>change inner func name<commit_after>/**
* @fileOverview
* @author Zoltan Toth
* @version 2.2.0
*/

/**
* @description
* 1Kb (gzipped) pure JavaScript carousel with all the basic features.
*
* @class
* @param {object} options - User defined settings for the carousel.
* @param {string} options.elem - The HTML id of the carousel container.
* @param {(boolean)} [options.circular=false] - Enables circular mode for the slider.
* @param {(boolean)} [options.autoplay=false] - Enables auto play of slides.
* @param {number} [options.interval=3000] - The interval between slide change.
* @param {number} [options.show=0] - Index of the slide to start on. Numeration begins at 0.
* @param {(boolean)} [options.dots=true] - Display navigation dots.
* @param {(boolean)} [options.arrows=true] - Display navigation arrows (PREV/NEXT).
* @param {(boolean)} [options.buttons=true] - Display navigation buttons (STOP/PLAY).
*
* @param {(string)} [options.crslClass=.js-carousel] -  CSS class of the carousel container.
* @param {(string)} [options.crslArrowPrevClass=.arrow_prev] -  CSS class of the _PREV_ arrow.
* @param {(string)} [options.crslArrowNextClass=.arrow_next] -  CSS class of the _NEXT_ arrow.
* @param {(string)} [options.crslDotsClass=.dots] -  CSS class of the nav dots container.
* @param {(string)} [options.crslButtonStopClass=.btn_play] -  CSS class of the _PLAY_ button.
* @param {(string)} [options.crslButtonPlayClass=.btn_stop] -  CSS class of the _STOP_ button.
*
* @param {(string)} [options.btnPlayText=Play] - Text for _PLAY_ button.
* @param {(string)} [options.btnStopText=Stop] - Text for _STOP_ button.
* @param {(string)} [options.arrPrevText=«] - Text for _PREV_ arrow.
* @param {(string)} [options.arrNextText=»] - Text for _NEXT_ arrow.
*/
function Carousel(options) {

    var el = document.getElementById(options.elem || 'carousel'),
        autoplay       = options.autoplay,
        circular       = options.circular,
        interval       = options.interval || 3000,
        controlDots    = options.dots,
        controlArrows  = options.arrows,
        controlButtons = options.buttons,

        crslClass           = options.crslClass           || 'js-carousel',
        crslArrowPrevClass  = options.crslArrowPrevClass  || 'arrow_prev',
        crslArrowNextClass  = options.crslArrowNextClass  || 'arrow_next',
        crslDotsClass       = options.crslDotsClass       || 'dots',
        crslButtonStopClass = options.crslButtonStopClass || 'btn_stop',
        crslButtonPlayClass = options.crslButtonPlayClass || 'btn_play',

        btnPlayText = options.btnPlayText || 'Play',
        btnStopText = options.btnStopText || 'Stop',

        arrNextText = options.arrNextText || '›',
        arrPrevText = options.arrPrevText || '‹',

        count   = el.querySelectorAll('li').length,
        initial = 0 || (options.initial >= count) ? count : options.initial,
        current = 0,
        cycle   = null;

    /**
    * Render the carousel if more than one slide.
    * Otherwise just show the single item.
    */
    if (count > 1) {
        render();
    }

    /**
    * Render the carousel and all the navigation elements (arrows, dots,
    * play/stop buttons) if needed. Start with a particular slide, if set.
    * If circular - move the last item to the very beginning and off the display area.
    */
    function render() {
        if (controlDots) {
            showDots();
        }

        if (controlArrows) {
            showArrows();
        }

        if (controlButtons) {
            showButtons();
        }

        if (autoplay) {
            play();
        }

        if (circular) {
            moveItem(count - 1, -el.offsetWidth + 'px', 'afterBegin');
        }

        if (initial) {
            show(initial);
        }
    }

    /**
    * Helper for moving items - last to be first or first to be the last. Needed
    * for infinite rotation of the carousel.
    *
    * @param {number} i - Position of the list item to move (either first or last).
    * @param {number} marginLeft - Left margin to position the item off-screen
    *        at the beginning or no margin at the end.
    * @param {string} position - Where to insert the item. One of the following -
    *        'afterBegin' or 'beforeEnd'.
    */
    function moveItem(i, marginLeft, position) {
        var itemToMove = el.querySelectorAll('.' + crslClass + ' > ul li')[i];
        itemToMove.style.marginLeft = marginLeft;

        el.querySelector('.' + crslClass + ' > ul')
          .removeChild(itemToMove);

        el.querySelector('.' + crslClass + ' > ul')
          .insertAdjacentHTML(position, itemToMove.outerHTML);
    }

    /**
    * Create the navigation dots and attach to carousel.
    */
    function showDots() {
        var dotContainer = document.createElement('ul');
        dotContainer.classList.add(crslDotsClass);
        dotContainer.addEventListener('click', scrollToImage.bind(this));

        for (var i = 0; i < count; i++) {
            var dotElement = document.createElement('li');
            dotElement.setAttribute('data-position', i);

            dotContainer.appendChild(dotElement);
        }

        el.appendChild(dotContainer);
        currentDot();
    }

    /**
    * Highlight the corresponding dot of the currently visible carousel item.
    */
    function currentDot() {
        [].forEach.call(el.querySelectorAll('.' + crslDotsClass + ' li'), function(item) {
            item.classList.remove('active');
        });

        switch (current) {
            case -1:
                current = count - 1;
                break;
            case count:
                current = 0;
                break;
            default:
                current = current;
        }

        el.querySelectorAll('.' + crslDotsClass + ' li')[current].classList.add('active');
    }

    /**
    * Moves the carousel to the desired slide on a navigation dot click.
    *
    * @param {object} e - The clicked dot element.
    */
    function scrollToImage(e) {
        if (e.target.tagName === 'LI') {
            show(e.target.getAttribute('data-position'));
        }
    }

    /**
    * Create the navigation arrows (prev/next) and attach to carousel.
    */
    function showArrows() {
        var buttonPrev = document.createElement('button');
        buttonPrev.innerHTML = arrPrevText;
        buttonPrev.classList.add(crslArrowPrevClass);

        var buttonNext = document.createElement('button');
        buttonNext.innerHTML = arrNextText;
        buttonNext.classList.add(crslArrowNextClass);

        buttonPrev.addEventListener('click', showPrev);
        buttonNext.addEventListener('click', showNext);

        el.appendChild(buttonPrev);
        el.appendChild(buttonNext);
    }

    /**
    * Create the navigation buttons (play/stop) and attach to carousel.
    */
    function showButtons() {
        var buttonPlay = document.createElement('button');
        buttonPlay.innerHTML = btnPlayText;
        buttonPlay.classList.add(crslButtonPlayClass);
        buttonPlay.addEventListener('click', play);

        var buttonStop = document.createElement('button');
        buttonStop.innerHTML = btnStopText;
        buttonStop.classList.add(crslButtonStopClass);
        buttonStop.addEventListener('click', stop);

        el.appendChild(buttonPlay);
        el.appendChild(buttonStop);
    }

    /**
    * Animate the carousel to go back 1 slide. Moves the very first (off-screen)
    * item to the visible area.
    *
    * @param {object} item - The element to move into view.
    */
    function animatePrev(item) {
        item.style.marginLeft = '';
    }

    /**
    * Animate the carousel to go forward 1 slide.
    *
    * @param {object} item - The element to move into view.
    */
    function animateNext(item) {
        item.style.marginLeft = -el.offsetWidth + 'px';
    }

    /**
    * Move the carousel to the desired slide.
    *
    * @param {number} slide - The index of the item.
    * @public
    */
    function show(slide) {
        var delta = current - slide;

        if (delta === 0) {
            return;
        }

        if (delta < 0) {
            for (var i = 0; i < -delta; i++) {
                showNext();
            }
        } else {
            for (var j = 0; j < delta; j++) {
                showPrev();
            }
        }
    }

    /**
    * Move the carousel back.
    * Do the sliding, move the last item to the very beginning, highlight the
    * corresponding navigation dot.
    *
    * @public
    */
    function showPrev() {
        if (circular) {
            animatePrev(el.querySelectorAll('.' + crslClass + ' > ul li')[0]);
            moveItem(count - 1, -el.offsetWidth + 'px', 'afterBegin');
        } else {
            stop();
            if (current === 0) {
                return;
            }
            animatePrev(el.querySelectorAll('.' + crslClass + ' > ul li')[current - 1]);
        }

        current--;

        if (controlDots) {
            currentDot();
        }
    }

    /**
    * Move the carousel forward.
    * Do the sliding, move the second item to the very end, highlight the
    * corresponding navigation dot.
    *
    * @public
    */
    function showNext() {
        if (circular) {
            animateNext(el.querySelectorAll('.' + crslClass + ' > ul li')[1]);
            moveItem(0, '', 'beforeEnd');
        } else {
            if (current === count - 1) {
                stop();
                return;
            }
            animateNext(el.querySelectorAll('.' + crslClass + ' > ul li')[current]);
        }

        current++;

        if (controlDots) {
            currentDot();
        }
    }

    /**
    * Start the auto play.
    * If already playing do nothing.
    *
    * @public
    */
    function play() {
        if (cycle) {
            return;
        }
        cycle = setInterval(showNext.bind(this), interval);
    }

    /**
    * Stop the auto play.
    *
    * @public
    */
    function stop() {
        clearInterval(cycle);
        cycle = null;
    }

    /**
    * Returns the current slide index.
    *
    * @public
    */
    function live() {
        return current;
    }

    return {
        'live': live,
        'show': show,
        'prev': showPrev,
        'next': showNext,
        'play': play,
        'stop': stop
    };
}<|endoftext|>


<commit_before>var seaport = require('../');
var test = require('tap').test;

test('resubscribe if connection dies', function(t) {
    var serverPort = Math.floor(Math.random() * 5e4 + 1e4);
    var server = seaport.createServer();
    var client = seaport.connect('localhost:' + serverPort, {reconnect: 10});

    t.plan(6);

    var eventNames = ['allocate', 'assume', 'free'];

    eventNames.forEach(function(eventName) {
        client.subscribe(eventName, function() {
            t.ok(true, eventName + ' emitted');
        });
    });

    function emit() {
        eventNames.forEach(function(eventName) {
            server.emit(eventName, {});
        });
    }

    server.listen(serverPort);

    // Wait for client to connect
    setTimeout(emit, 200)

    // Wait for first tests to finish
    setTimeout(function() {
        client.up.conn.stream.end();
    }, 400);

    // Run second test
    setTimeout(emit, 1600);

    t.on('end', function() {
        server.close();
        client.close();
        t.ok(true, 'closed server');
    });
});
<commit_msg>normalize indents<commit_after>var seaport = require('../');
var test = require('tap').test;

test('resubscribe if connection dies', function(t) {
    var serverPort = Math.floor(Math.random() * 5e4 + 1e4);
    var server = seaport.createServer();
    var client = seaport.connect('localhost:' + serverPort, { reconnect: 10 });

    t.plan(6);

    var eventNames = ['allocate', 'assume', 'free'];

    eventNames.forEach(function(eventName) {
        client.subscribe(eventName, function() {
            t.ok(true, eventName + ' emitted');
        });
    });

    function emit() {
        eventNames.forEach(function(eventName) {
            server.emit(eventName, {});
        });
    }

    server.listen(serverPort);

    // Wait for client to connect
    setTimeout(emit, 200)

    // Wait for first tests to finish
    setTimeout(function() {
        client.up.conn.stream.end();
    }, 400);

    // Run second test
    setTimeout(emit, 1600);

    t.on('end', function() {
        server.close();
        client.close();
        t.ok(true, 'closed server');
    });
});
<|endoftext|>


<commit_before>// d3.tip
// Copyright (c) 2013 Justin Palmer
//
// Tooltips for d3.js SVG visualizations

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module with d3 as a dependency.
    define(['d3'], factory)
  } else {
    // Browser global.
    root.d3.tip = factory(root.d3)
  }
}(this, function (d3) {

  // Public - contructs a new tooltip
  //
  // Returns a tip
  return function() {
    var direction = d3_tip_direction,
        offset    = d3_tip_offset,
        html      = d3_tip_html,
        node      = initNode(),
        svg       = null,
        point     = null,
        target    = null

    function tip(vis) {
      svg = getSVGNode(vis)
      point = svg.createSVGPoint()
      document.body.appendChild(node)
    }

    // Public - show the tooltip on the screen
    //
    // Returns a tip
    tip.show = function() {
      var args = Array.prototype.slice.call(arguments)
      if(args[args.length - 1] instanceof SVGElement) target = args.pop()

      var content = html.apply(this, args),
          poffset = offset.apply(this, args),
          dir     = direction.apply(this, args),
          nodel   = d3.select(node),
          i       = directions.length,
          coords,
          scrollTop  = document.documentElement.scrollTop || document.body.scrollTop,
          scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft

      nodel.html(content)
        .style({ opacity: 1, 'pointer-events': 'all' })

      while(i--) nodel.classed(directions[i], false)
      coords = direction_callbacks.get(dir).apply(this)
      nodel.classed(dir, true).style({
        top: (coords.top +  poffset[0]) + scrollTop + 'px',
        left: (coords.left + poffset[1]) + scrollLeft + 'px'
      })

      return tip
    }

    // Public - hide the tooltip
    //
    // Returns a tip
    tip.hide = function() {
      nodel = d3.select(node)
      nodel.style({ opacity: 0, 'pointer-events': 'none' })
      return tip
    }

    // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
    //
    // n - name of the attribute
    // v - value of the attribute
    //
    // Returns tip or attribute value
    tip.attr = function(n, v) {
      if (arguments.length < 2 && typeof n === 'string') {
        return d3.select(node).attr(n)
      } else {
        var args =  Array.prototype.slice.call(arguments)
        d3.selection.prototype.attr.apply(d3.select(node), args)
      }

      return tip
    }

    // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
    //
    // n - name of the property
    // v - value of the property
    //
    // Returns tip or style property value
    tip.style = function(n, v) {
      if (arguments.length < 2 && typeof n === 'string') {
        return d3.select(node).style(n)
      } else {
        var args =  Array.prototype.slice.call(arguments)
        d3.selection.prototype.style.apply(d3.select(node), args)
      }

      return tip
    }

    // Public: Set or get the direction of the tooltip
    //
    // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
    //     sw(southwest), ne(northeast) or se(southeast)
    //
    // Returns tip or direction
    tip.direction = function(v) {
      if (!arguments.length) return direction
      direction = v == null ? v : d3.functor(v)

      return tip
    }

    // Public: Sets or gets the offset of the tip
    //
    // v - Array of [x, y] offset
    //
    // Returns offset or
    tip.offset = function(v) {
      if (!arguments.length) return offset
      offset = v == null ? v : d3.functor(v)

      return tip
    }

    // Public: sets or gets the html value of the tooltip
    //
    // v - String value of the tip
    //
    // Returns html value or tip
    tip.html = function(v) {
      if (!arguments.length) return html
      html = v == null ? v : d3.functor(v)

      return tip
    }

    function d3_tip_direction() { return 'n' }
    function d3_tip_offset() { return [0, 0] }
    function d3_tip_html() { return ' ' }

    var direction_callbacks = d3.map({
      n:  direction_n,
      s:  direction_s,
      e:  direction_e,
      w:  direction_w,
      nw: direction_nw,
      ne: direction_ne,
      sw: direction_sw,
      se: direction_se
    }),

    directions = direction_callbacks.keys()

    function direction_n() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.n.y - node.offsetHeight,
        left: bbox.n.x - node.offsetWidth / 2
      }
    }

    function direction_s() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.s.y,
        left: bbox.s.x - node.offsetWidth / 2
      }
    }

    function direction_e() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.e.y - node.offsetHeight / 2,
        left: bbox.e.x
      }
    }

    function direction_w() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.w.y - node.offsetHeight / 2,
        left: bbox.w.x - node.offsetWidth
      }
    }

    function direction_nw() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.nw.y - node.offsetHeight,
        left: bbox.nw.x - node.offsetWidth
      }
    }

    function direction_ne() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.ne.y - node.offsetHeight,
        left: bbox.ne.x
      }
    }

    function direction_sw() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.sw.y,
        left: bbox.sw.x - node.offsetWidth
      }
    }

    function direction_se() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.se.y,
        left: bbox.e.x
      }
    }

    function initNode() {
      var node = d3.select(document.createElement('div'))
      node.style({
        position: 'absolute',
        top: 0,
        opacity: 0,
        'pointer-events': 'none',
        'box-sizing': 'border-box'
      })

      return node.node()
    }

    function getSVGNode(el) {
      el = el.node()
      if(el.tagName.toLowerCase() == 'svg')
        return el

      return el.ownerSVGElement
    }

    // Private - gets the screen coordinates of a shape
    //
    // Given a shape on the screen, will return an SVGPoint for the directions
    // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
    // sw(southwest).
    //
    //    +-+-+
    //    |   |
    //    +   +
    //    |   |
    //    +-+-+
    //
    // Returns an Object {n, s, e, w, nw, sw, ne, se}
    function getScreenBBox() {
      var targetel   = target || d3.event.target,
          bbox       = {},
          matrix     = targetel.getScreenCTM(),
          tbbox      = targetel.getBBox(),
          width      = tbbox.width,
          height     = tbbox.height,
          x          = tbbox.x,
          y          = tbbox.y

      point.x = x
      point.y = y
      bbox.nw = point.matrixTransform(matrix)
      point.x += width
      bbox.ne = point.matrixTransform(matrix)
      point.y += height
      bbox.se = point.matrixTransform(matrix)
      point.x -= width
      bbox.sw = point.matrixTransform(matrix)
      point.y -= height / 2
      bbox.w  = point.matrixTransform(matrix)
      point.x += width
      bbox.e = point.matrixTransform(matrix)
      point.x -= width / 2
      point.y -= height / 2
      bbox.n = point.matrixTransform(matrix)
      point.y += height
      bbox.s = point.matrixTransform(matrix)

      return bbox
    }

    return tip
  };

}));<commit_msg>properly export itself in commonjs scenario<commit_after>// d3.tip
// Copyright (c) 2013 Justin Palmer
//
// Tooltips for d3.js SVG visualizations

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module with d3 as a dependency.
    define(['d3'], factory)
  } else if (module && module.exports !== undefined) {
    // CommonJS
    module.exports = factory
  } else {
    // Browser global.
    root.d3.tip = factory(root.d3)
  }
}(this, function (d3) {

  // Public - contructs a new tooltip
  //
  // Returns a tip
  return function() {
    var direction = d3_tip_direction,
        offset    = d3_tip_offset,
        html      = d3_tip_html,
        node      = initNode(),
        svg       = null,
        point     = null,
        target    = null

    function tip(vis) {
      svg = getSVGNode(vis)
      point = svg.createSVGPoint()
      document.body.appendChild(node)
    }

    // Public - show the tooltip on the screen
    //
    // Returns a tip
    tip.show = function() {
      var args = Array.prototype.slice.call(arguments)
      if(args[args.length - 1] instanceof SVGElement) target = args.pop()

      var content = html.apply(this, args),
          poffset = offset.apply(this, args),
          dir     = direction.apply(this, args),
          nodel   = d3.select(node),
          i       = directions.length,
          coords,
          scrollTop  = document.documentElement.scrollTop || document.body.scrollTop,
          scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft

      nodel.html(content)
        .style({ opacity: 1, 'pointer-events': 'all' })

      while(i--) nodel.classed(directions[i], false)
      coords = direction_callbacks.get(dir).apply(this)
      nodel.classed(dir, true).style({
        top: (coords.top +  poffset[0]) + scrollTop + 'px',
        left: (coords.left + poffset[1]) + scrollLeft + 'px'
      })

      return tip
    }

    // Public - hide the tooltip
    //
    // Returns a tip
    tip.hide = function() {
      nodel = d3.select(node)
      nodel.style({ opacity: 0, 'pointer-events': 'none' })
      return tip
    }

    // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
    //
    // n - name of the attribute
    // v - value of the attribute
    //
    // Returns tip or attribute value
    tip.attr = function(n, v) {
      if (arguments.length < 2 && typeof n === 'string') {
        return d3.select(node).attr(n)
      } else {
        var args =  Array.prototype.slice.call(arguments)
        d3.selection.prototype.attr.apply(d3.select(node), args)
      }

      return tip
    }

    // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
    //
    // n - name of the property
    // v - value of the property
    //
    // Returns tip or style property value
    tip.style = function(n, v) {
      if (arguments.length < 2 && typeof n === 'string') {
        return d3.select(node).style(n)
      } else {
        var args =  Array.prototype.slice.call(arguments)
        d3.selection.prototype.style.apply(d3.select(node), args)
      }

      return tip
    }

    // Public: Set or get the direction of the tooltip
    //
    // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
    //     sw(southwest), ne(northeast) or se(southeast)
    //
    // Returns tip or direction
    tip.direction = function(v) {
      if (!arguments.length) return direction
      direction = v == null ? v : d3.functor(v)

      return tip
    }

    // Public: Sets or gets the offset of the tip
    //
    // v - Array of [x, y] offset
    //
    // Returns offset or
    tip.offset = function(v) {
      if (!arguments.length) return offset
      offset = v == null ? v : d3.functor(v)

      return tip
    }

    // Public: sets or gets the html value of the tooltip
    //
    // v - String value of the tip
    //
    // Returns html value or tip
    tip.html = function(v) {
      if (!arguments.length) return html
      html = v == null ? v : d3.functor(v)

      return tip
    }

    function d3_tip_direction() { return 'n' }
    function d3_tip_offset() { return [0, 0] }
    function d3_tip_html() { return ' ' }

    var direction_callbacks = d3.map({
      n:  direction_n,
      s:  direction_s,
      e:  direction_e,
      w:  direction_w,
      nw: direction_nw,
      ne: direction_ne,
      sw: direction_sw,
      se: direction_se
    }),

    directions = direction_callbacks.keys()

    function direction_n() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.n.y - node.offsetHeight,
        left: bbox.n.x - node.offsetWidth / 2
      }
    }

    function direction_s() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.s.y,
        left: bbox.s.x - node.offsetWidth / 2
      }
    }

    function direction_e() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.e.y - node.offsetHeight / 2,
        left: bbox.e.x
      }
    }

    function direction_w() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.w.y - node.offsetHeight / 2,
        left: bbox.w.x - node.offsetWidth
      }
    }

    function direction_nw() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.nw.y - node.offsetHeight,
        left: bbox.nw.x - node.offsetWidth
      }
    }

    function direction_ne() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.ne.y - node.offsetHeight,
        left: bbox.ne.x
      }
    }

    function direction_sw() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.sw.y,
        left: bbox.sw.x - node.offsetWidth
      }
    }

    function direction_se() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.se.y,
        left: bbox.e.x
      }
    }

    function initNode() {
      var node = d3.select(document.createElement('div'))
      node.style({
        position: 'absolute',
        top: 0,
        opacity: 0,
        'pointer-events': 'none',
        'box-sizing': 'border-box'
      })

      return node.node()
    }

    function getSVGNode(el) {
      el = el.node()
      if(el.tagName.toLowerCase() == 'svg')
        return el

      return el.ownerSVGElement
    }

    // Private - gets the screen coordinates of a shape
    //
    // Given a shape on the screen, will return an SVGPoint for the directions
    // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
    // sw(southwest).
    //
    //    +-+-+
    //    |   |
    //    +   +
    //    |   |
    //    +-+-+
    //
    // Returns an Object {n, s, e, w, nw, sw, ne, se}
    function getScreenBBox() {
      var targetel   = target || d3.event.target,
          bbox       = {},
          matrix     = targetel.getScreenCTM(),
          tbbox      = targetel.getBBox(),
          width      = tbbox.width,
          height     = tbbox.height,
          x          = tbbox.x,
          y          = tbbox.y

      point.x = x
      point.y = y
      bbox.nw = point.matrixTransform(matrix)
      point.x += width
      bbox.ne = point.matrixTransform(matrix)
      point.y += height
      bbox.se = point.matrixTransform(matrix)
      point.x -= width
      bbox.sw = point.matrixTransform(matrix)
      point.y -= height / 2
      bbox.w  = point.matrixTransform(matrix)
      point.x += width
      bbox.e = point.matrixTransform(matrix)
      point.x -= width / 2
      point.y -= height / 2
      bbox.n = point.matrixTransform(matrix)
      point.y += height
      bbox.s = point.matrixTransform(matrix)

      return bbox
    }

    return tip
  };

}));<|endoftext|>


<commit_before>/*
 * Copyright 2017 Micro Focus International plc.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

define([
    'underscore',
    'jquery',
    'find/idol/app/model/entitysearch/entity-search-collection',
    'text!find/templates/app/page/loading-spinner.html',
    'i18n!find/nls/bundle'
], function(_, $, EntitySearchCollection, loadingSpinnerTemplate, i18n) {
    'use strict';

    const loadingHtml = _.template(loadingSpinnerTemplate)({i18n: i18n, large: false});

    function SelectionEntitySearch(options) {
        const documentRenderer = options.documentRenderer;
        let element = options.element || document.body;

        let $hover;

        const entityModels = new EntitySearchCollection();
        let lastQueryText, lastFetch;

        function loadModel(text, $summary, bounds) {
            if (lastFetch && lastQueryText !== text) {
                lastFetch.abort();
            }

            lastQueryText = text;

            updateIndicator(loadingHtml, bounds);

            lastFetch = entityModels.fetch({
                data: { text: text }
            }).done(function(){
                if (text === lastQueryText && entityModels.length) {
                    const result = entityModels.first();
                    const html = documentRenderer.renderEntity(result);

                    updateIndicator(html, bounds);
                }
                else {
                    clearIndicator()
                }
            }).fail(function(){
                clearIndicator();
            })
        }

        function clearIndicator() {
            if ($hover) {
                $hover.remove();
                $hover = null;
            }
        }

        function updateIndicator(html, bounds){
            clearIndicator();

            const top = bounds.bottom + 10;

            $hover = $('
').css({
                top: top,
                left: bounds.left
            }).html(html).appendTo(element);

            if ($hover.height() + top > window.innerHeight) {
                $hover.css({
                    top: 'auto',
                    bottom: window.innerHeight - bounds.top + 10
                })
            }
        }

        function onSelectionChange() {
            const sel = window.getSelection();

            if (sel.rangeCount !== 1) {
                return;
            }

            const range = sel.getRangeAt(0);
            const text = range.toString().trim();

            const $selectEnd = $(sel.focusNode);

            if ($selectEnd.closest('.selection-entity').length) {
                // We're doing selection stuff on the selection popup, we don't want to trigger changes
                //  otherwise the selection popup will disappear.
                return;
            }

            if (text && text.length >= 2) {
                const $summary = $selectEnd.closest('.result-summary');

                if ($summary.length && $(sel.anchorNode).closest('.result-summary').is($summary)) {
                    // We're in a summary, try fetching stuff
                    loadModel(text, $summary, range.getBoundingClientRect());
                    return;
                }
            }

            clearIndicator();
        }

        $(document).on('selectionchange', onSelectionChange)

        this.stopListening = function(){
            $(document).off('selectionchange', onSelectionChange);
            clearIndicator();
        }

        this.setElement = function(dom) {
            element = dom;
        }
    }

    return SelectionEntitySearch;
});
<commit_msg>(DEMOS-72, CORE-4439) Debounce the selection change event to avoid spamming the agentstore (and the query audit logs on idol-access.log).<commit_after>/*
 * Copyright 2017 Micro Focus International plc.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

define([
    'underscore',
    'jquery',
    'find/idol/app/model/entitysearch/entity-search-collection',
    'text!find/templates/app/page/loading-spinner.html',
    'i18n!find/nls/bundle'
], function(_, $, EntitySearchCollection, loadingSpinnerTemplate, i18n) {
    'use strict';

    const loadingHtml = _.template(loadingSpinnerTemplate)({i18n: i18n, large: false});

    function SelectionEntitySearch(options) {
        const documentRenderer = options.documentRenderer;
        let element = options.element || document.body;

        let $hover;

        const entityModels = new EntitySearchCollection();
        let lastQueryText, lastFetch;

        function loadModel(text, $summary, bounds) {
            if (lastFetch && lastQueryText !== text) {
                lastFetch.abort();
            }

            lastQueryText = text;

            updateIndicator(loadingHtml, bounds);

            lastFetch = entityModels.fetch({
                data: { text: text }
            }).done(function(){
                if (text === lastQueryText && entityModels.length) {
                    const result = entityModels.first();
                    const html = documentRenderer.renderEntity(result);

                    updateIndicator(html, bounds);
                }
                else {
                    clearIndicator()
                }
            }).fail(function(){
                clearIndicator();
            })
        }

        function clearIndicator() {
            if ($hover) {
                $hover.remove();
                $hover = null;
            }
        }

        function updateIndicator(html, bounds){
            clearIndicator();

            const top = bounds.bottom + 10;

            $hover = $('
').css({
                top: top,
                left: bounds.left
            }).html(html).appendTo(element);

            if ($hover.height() + top > window.innerHeight) {
                $hover.css({
                    top: 'auto',
                    bottom: window.innerHeight - bounds.top + 10
                })
            }
        }

        function onSelectionChange() {
            const sel = window.getSelection();

            if (sel.rangeCount !== 1) {
                return;
            }

            const range = sel.getRangeAt(0);
            const text = range.toString().trim();

            const $selectEnd = $(sel.focusNode);

            if ($selectEnd.closest('.selection-entity').length) {
                // We're doing selection stuff on the selection popup, we don't want to trigger changes
                //  otherwise the selection popup will disappear.
                return;
            }

            if (text && text.length >= 2) {
                const $summary = $selectEnd.closest('.result-summary');

                if ($summary.length && $(sel.anchorNode).closest('.result-summary').is($summary)) {
                    // We're in a summary, try fetching stuff
                    loadModel(text, $summary, range.getBoundingClientRect());
                    return;
                }
            }

            clearIndicator();
        }

        const debounced = _.debounce(onSelectionChange, 300);

        $(document).on('selectionchange', debounced)

        this.stopListening = function(){
            $(document).off('selectionchange', debounced);
            clearIndicator();
        }

        this.setElement = function(dom) {
            element = dom;
        }
    }

    return SelectionEntitySearch;
});
<|endoftext|>


<commit_before>(function(window) {
    var mass;

    function Flick(pk) {
        mass = pk.body.GetMass();
        window.PUCKX = pk;

        // Event listener for the initial touch on the puck
        var mousedown = (function () {
            var d = [],
                offset = {},

            mousemove = function (e) {
                console.log('mousemove', e, pk.body.GetPosition());

                // Move the puck as the finger move
                pk.SetPosition(e.stageX + offset.x,
                               e.stageY + offset.y);

                // Detail of current movement
                d.push({
                    pos: {x: e.rawX, y: e.rawY},
                    timestamp: e.nativeEvent.timeStamp
                });
            },

            mouseup = function(e) {
                console.log('mouseup', e);

                var xVel, yVel, end;
                if (d.length > 2) {
                    // Initial checks on release.
                    if (d.length>20)
                        d.splice(0, (d.length*0.9));
                    else if (d.length>10)
                        d.splice(0, (d.length*0.7));
                    // After checks are complete, calculate array length
                    end = d.length - 1;
                    // Calculate the velocity (in metres per second)
                    xVel = puckt.util.calcVelocity([d[0].pos.x, d[end].pos.x],
                        [d[0].timestamp, d[end].timestamp]);
                    yVel = (puckt.util.calcVelocity([d[0].pos.y, d[end].pos.y],
                        [d[0].timestamp, d[end].timestamp]));

                    // Convert velocity to b2Vec2()
                    var momentumVect = new box2d.b2Vec2(xVel * mass, yVel * mass);
                    console.log('momentumVect', momentumVect);
                    pk.body.SetLinearVelocity(new box2d.b2Vec2(0, 0));
                    pk.body.ApplyImpulse(momentumVect, pk.body.GetWorldCenter());
                }
            },

            mousedown = function (e) {
                console.log('mousedown', e, pk.body, pk.body.GetPosition());

                var pos = pk.body.GetPosition();
                offset = {
                    x: pos.x - e.stageX,
                    y: pos.y - e.stageY
                };

                e.addEventListener('mousemove', mousemove);
                e.addEventListener('mouseup', mouseup);
            };

            return mousedown;
        })();

        pk.shape.addEventListener('mousedown', mousedown);
    }
    window.Flick = Flick;
})(window);<commit_msg>Setting velocity of 0 on mouse down, not mouse up<commit_after>(function(window) {
    var mass;

    function Flick(pk) {
        mass = pk.body.GetMass();
        window.PUCKX = pk;

        // Event listener for the initial touch on the puck
        var mousedown = (function () {
            pk.body.SetLinearVelocity(new box2d.b2Vec2(0, 0));

            var d = [],
                offset = {},

            mousemove = function (e) {
                console.log('mousemove', e, pk.body.GetPosition());

                // Move the puck as the finger move
                pk.SetPosition(e.stageX + offset.x,
                               e.stageY + offset.y);

                // Detail of current movement
                d.push({
                    pos: {x: e.rawX, y: e.rawY},
                    timestamp: e.nativeEvent.timeStamp
                });
            },

            mouseup = function(e) {
                console.log('mouseup', e);

                var xVel, yVel, end;
                if (d.length > 2) {
                    // Initial checks on release.
                    if (d.length>20)
                        d.splice(0, (d.length*0.9));
                    else if (d.length>10)
                        d.splice(0, (d.length*0.7));
                    // After checks are complete, calculate array length
                    end = d.length - 1;
                    // Calculate the velocity (in metres per second)
                    xVel = puckt.util.calcVelocity([d[0].pos.x, d[end].pos.x],
                        [d[0].timestamp, d[end].timestamp]);
                    yVel = (puckt.util.calcVelocity([d[0].pos.y, d[end].pos.y],
                        [d[0].timestamp, d[end].timestamp]));

                    // Convert velocity to b2Vec2()
                    var momentumVect = new box2d.b2Vec2(xVel * mass, yVel * mass);
                    console.log('momentumVect', momentumVect);
                    pk.body.ApplyImpulse(momentumVect, pk.body.GetWorldCenter());
                }
            },

            mousedown = function (e) {
                console.log('mousedown', e, pk.body, pk.body.GetPosition());

                var pos = pk.body.GetPosition();
                offset = {
                    x: pos.x - e.stageX,
                    y: pos.y - e.stageY
                };

                e.addEventListener('mousemove', mousemove);
                e.addEventListener('mouseup', mouseup);
            };

            return mousedown;
        })();

        pk.shape.addEventListener('mousedown', mousedown);
    }
    window.Flick = Flick;
})(window);<|endoftext|>


<commit_before>({

  base_url_now : 'http://api.nhk.or.jp/v1/pg/now',
  base_url_list : 'http://api.nhk.or.jp/v1/pg/list',
  area : '130', //Tokyo
  service : 'g1',
  program: [],

  init : function(){
    var self = this;
    $(function() {
      self.getNowOnair();
      self.getNHKprogram();
      self.pollingProgram();
    });
  },

  pollingProgram: function() {
    var self = this;
    setInterval(function(){ self.noticeProgram(); }, 1000 * 60);
  },

  getNowOnair: function() {
    var self = this;
    var url_now = this.base_url_now + "/" + this.area + "/" + this.service + ".json";
    $("#nhk").click(function(){
      self.callApi(url_now);
    });
  },

  getNHKprogram: function() {
    var self = this;
    var today = self.getToday();
    var list_url = this.base_url_list + "/" + this.area + "/" + this.service + "/" + today + ".json";
    var program = self.callApi(list_url);
  },

  saveNHKprogram: function(program) {
    var program_array = program.list.g1;
    for (var i = 0 ; i < program_array.length; i++) {
      this.program[i] = {};
      this.program[i]["title"] = program_array[i].title;
      this.program[i]["subtitle"] = program_array[i].subtitle;
      this.program[i]["icon"] = program_array[i].service.logo_m.url;
      this.program[i]["start_time"] = Date.parse(program_array[i].start_time);
      this.program[i]["notice"] = 0;
    }
  },

  noticeProgram: function() {
    var self = this;
    var now = new Date();
    for (var i = 0 ; i < this.program.length; i++) {
      var diff = Math.abs(now - this.program[i]["start_time"]);
      if (diff < 1000 * 60 && this.program[i]["notice"] == 0) {
        this.program[i]["notice"] == 1;
        self.sendNotification(this.program[i]["icon"], this.program[i]["title"], this.program[i]["subtitle"]);
      }
    }
  },

  getToday: function() {
    var self = this;
    var date = new Date();
    var hour = date.getHours();
    if (hour < 4) {
      date.setDate(date.getDate()-1);
    }
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var day = date.getDate();
    var hour = date.getHour;
    month = ('0' + month).slice(-2);
    day = ('0' + day).slice(-2);
    return year + "-" + month + "-" + day;
  },

  callApi: function(api_url) {
    var self = this;
    var api_key = localStorage["api_key"];
    var url = api_url + "?key=" + api_key;
    $.ajax ({
      type: "GET",
      url : url.replace(/\s+/g, ""),
      datatype: 'json',
      success: function(msg) {
       for(var key in msg) {
         if (key == "list") {
           self.saveNHKprogram(msg);
         } else if (key == "nowonair_list") {
           var title = msg.nowonair_list.g1.present.title;
           var icon = msg.nowonair_list.g1.present.service.logo_s.url;
           var subtitle = msg.nowonair_list.g1.present.subtitle;
           self.sendNotification(icon, title, subtitle);
         }
       }
      },
      failure: function() {
        console.log("Fairure");
      }
    });
  },

  sendNotification: function(icon, title, subtitle) {
    window.webkitNotifications.createNotification(icon, title, subtitle);
    if ( webkitNotifications.checkPermission() == 0 ) {
      var popup = webkitNotifications.createNotification(icon, title, subtitle);
      popup.ondisplay = function(){
        setTimeout(function(){
          popup.cancel();
        }, 5000);
      };
      popup.show();
    } else {
      webkitNotifications.requestPermission();
    }
  }
}).init();
<commit_msg>Fix notice<commit_after>({

  base_url_now : 'http://api.nhk.or.jp/v1/pg/now',
  base_url_list : 'http://api.nhk.or.jp/v1/pg/list',
  area : '130', //Tokyo
  service : 'g1',
  program: [],

  init : function(){
    var self = this;
    $(function() {
      self.getNowOnair();
      self.getNHKprogram();
      self.pollingProgram();
    });
  },

  pollingProgram: function() {
    var self = this;
    setInterval(function(){ self.noticeProgram(); }, 1000 * 30);
  },

  getNowOnair: function() {
    var self = this;
    var url_now = this.base_url_now + "/" + this.area + "/" + this.service + ".json";
    $("#nhk").click(function(){
      self.callApi(url_now);
    });
  },

  getNHKprogram: function() {
    var self = this;
    var today = self.getToday();
    var list_url = this.base_url_list + "/" + this.area + "/" + this.service + "/" + today + ".json";
    var program = self.callApi(list_url);
  },

  saveNHKprogram: function(program) {
    var program_array = program.list.g1;
    for (var i = 0 ; i < program_array.length; i++) {
      this.program[i] = {};
      this.program[i]["title"] = program_array[i].title;
      this.program[i]["subtitle"] = program_array[i].subtitle;
      this.program[i]["icon"] = program_array[i].service.logo_m.url;
      this.program[i]["start_time"] = Date.parse(program_array[i].start_time);
      this.program[i]["notice"] = 0;
    }
  },

  noticeProgram: function() {
    var self = this;
    var now = new Date();
    for (var i = 0 ; i < this.program.length; i++) {
      var diff = Math.abs(now - this.program[i]["start_time"]);
      if (diff < 1000 * 60 && this.program[i]["notice"] == 0) {
        this.program[i]["notice"] = 1;
        self.sendNotification(this.program[i]["icon"], this.program[i]["title"], this.program[i]["subtitle"]);
      }
    }
  },

  getToday: function() {
    var self = this;
    var date = new Date();
    var hour = date.getHours();
    if (hour < 4) {
      date.setDate(date.getDate()-1);
    }
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var day = date.getDate();
    var hour = date.getHour;
    month = ('0' + month).slice(-2);
    day = ('0' + day).slice(-2);
    return year + "-" + month + "-" + day;
  },

  callApi: function(api_url) {
    var self = this;
    var api_key = localStorage["api_key"];
    var url = api_url + "?key=" + api_key;
    $.ajax ({
      type: "GET",
      url : url.replace(/\s+/g, ""),
      datatype: 'json',
      success: function(msg) {
       for(var key in msg) {
         if (key == "list") {
           self.saveNHKprogram(msg);
         } else if (key == "nowonair_list") {
           var title = msg.nowonair_list.g1.present.title;
           var icon = msg.nowonair_list.g1.present.service.logo_m.url;
           var subtitle = msg.nowonair_list.g1.present.subtitle;
           self.sendNotification(icon, title, subtitle);
         }
       }
      },
      failure: function() {
        console.log("Fairure");
      }
    });
  },

  sendNotification: function(icon, title, subtitle) {
    window.webkitNotifications.createNotification(icon, title, subtitle);
    if ( webkitNotifications.checkPermission() == 0 ) {
      var popup = webkitNotifications.createNotification(icon, title, subtitle);
      popup.ondisplay = function(){
        setTimeout(function(){
          popup.cancel();
        }, 5000);
      };
      popup.show();
    } else {
      webkitNotifications.requestPermission();
    }
  }
}).init();
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');

var template = fs.readFileSync(__dirname + '/process-definitions.html', 'utf8');

module.exports = [ 'ViewsProvider', function(ViewsProvider) {
  ViewsProvider.registerDefaultView('cockpit.processes.dashboard', {
    id: 'process-definition',
    label: 'Deployed Process Definitions',
    template: template,
    controller: [
      '$scope',
      'Views',
      'camAPI',
      'localConf',
      '$translate',
      function($scope, Views, camAPI, localConf, $translate) {

        var processDefinitionService = camAPI.resource('process-definition');

        $scope.processesActions = Views.getProviders({ component: 'cockpit.processes.action'});
        $scope.hasActionPlugin = $scope.processesActions.length > 0;

        var processInstancePlugins = Views.getProviders({ component: 'cockpit.processInstance.view' });
        $scope.hasHistoryPlugin = processInstancePlugins.filter(function(plugin) {
          return plugin.id === 'history';
        }).length > 0;
        $scope.hasReportPlugin = Views.getProviders({ component: 'cockpit.report' }).length > 0;
        $scope.hasSearchPlugin = Views.getProviders( { component: 'cockpit.processes.dashboard', id: 'search-process-instances' }).length > 0;

        $scope.headColumns = [
          { class: 'state',    request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_STATE')},
          { class: 'incidents',request: 'incidentCount', sortable: true,  content: $translate.instant('PLUGIN_PROCESS_DEF_INCIDENTS')},
          { class: 'instances',request: 'instances'    , sortable: true, content: $translate.instant('PLUGIN_PROCESS_DEF_RUNNING_INSTANCES')},
          { class: 'name',     request: 'key'          , sortable: true, content: $translate.instant('PLUGIN_PROCESS_DEF_NAME')},
          { class: 'tenantID', request: 'tenantId'     , sortable: true, content: $translate.instant('PLUGIN_PROCESS_DEF_TENANT_ID')},
          { class: 'history',  request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_HISTORY_VIEW'), condition: $scope.hasReportPlugin},
          { class: 'report',   request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_REPORT'), condition: $scope.hasReportPlugin},
          { class: 'action',   request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_ACTION'), condition: $scope.hasActionPlugin}
        ];

        // Default sorting
        var defaultValue = { sortBy: 'key', sortOrder: 'asc', sortReverse: false};
        $scope.sortObj   = loadLocal(defaultValue);

        // Update Table
        $scope.onSortChange = function(sortObj) {
          sortObj = sortObj || $scope.sortObj;
          // transforms sortOrder to boolean required by anqular-sorting;
          sortObj.sortReverse = sortObj.sortOrder !== 'asc';
          saveLocal(sortObj);
          $scope.sortObj = sortObj;
        };

        var processData = $scope.processData.newChild($scope);

        var getPDIncidentsCount = function(incidents) {
          if(!incidents) { return 0;}
          return incidents.reduce(function(sum, incident) {
            return sum + incident.incidentCount;
          }, 0);
        };

        $scope.loadingState = 'LOADING';

        // only get count of process definitions
        var countProcessDefinitions =  function() {
          processDefinitionService.count({
            latest: true
          }, function(err, count) {
            if (err) {
              $scope.loadingState = 'ERROR';
            }
            $scope.processDefinitionsCount = count;
          });
        };

        // get full list of process definitions and related resources
        var listProcessDefinitions =  function() {
          processDefinitionService.list({
            latest: true
          }, function(err, data) {
            $scope.processDefinitionData = data.items;
            $scope.processDefinitionsCount = data.count;
            if (err) {
              $scope.loadingState = 'ERROR';
            }

            $scope.loadingState = 'LOADED';

            processData.observe('processDefinitionStatistics', function(processDefinitionStatistics) {
              $scope.statistics = processDefinitionStatistics;

              $scope.statistics.forEach(function(statistic) {
                var processDefId = statistic.definition.id;
                var foundIds = $scope.processDefinitionData.filter(function(pd) {
                  return pd.id === processDefId;
                });

                var foundObject = foundIds[0];
                if(foundObject) {
                  foundObject.incidents = statistic.incidents;
                  foundObject.incidentCount = getPDIncidentsCount(foundObject.incidents);
                  foundObject.instances = statistic.instances;
                }
              });
            });
          });
        };

        $scope.definitionVars = { read: [ 'pd' ] };

        var removeActionDeleteListener = $scope.$on('processes.action.delete', function(event, definitionId) {

          var definitions = $scope.processDefinitionData;

          for (var i = 0; i < definitions.length; i++) {
            if (definitions[i].id === definitionId) {
              definitions.splice(i, 1);
              break;
            }
          }

          $scope.processDefinitionsCount = definitions.length;
        });

        $scope.$on('$destroy', function() {
          removeActionDeleteListener();
        });

        $scope.incidentsLink = '#/processes?searchQuery=%5B%7B%22type%22:%22PIincidentStatus%22,%22operator%22:' +
          '%22eq%22,%22value%22:%22open%22,%22name%22:%22%22%7D,%7B%22type%22:%22PIprocessDefinitionKey%22,' +
          '%22operator%22:%22eq%22,%22value%22:%22PD_KEY%22,%22name%22:%22%22%7D%5D#search-section';

        $scope.activeTab = 'list';

        $scope.selectTab = function(tab) {
          $scope.activeTab = tab;
        };

        $scope.activeSection = localConf.get('processesDashboardActive', true);
        // if tab is not active, it's enough to only get the count of process definitions
        $scope.activeSection ? listProcessDefinitions() : countProcessDefinitions();

        $scope.toggleSection = function toggleSection() {
          // if tab is not active, it's enough to only get the count of process definitions
          ($scope.activeSection = !$scope.activeSection) ? listProcessDefinitions() : countProcessDefinitions();
          localConf.set('processesDashboardActive', $scope.activeSection);
        };

        function saveLocal(sortObj) {
          localConf.set('sortProcessDefTab', sortObj);

        }
        function loadLocal(defaultValue) {
          return localConf.get('sortProcessDefTab', defaultValue);
        }

      }],

    priority: 0
  });
}];
<commit_msg>fix(cockpit): change sorting from key to name<commit_after>'use strict';

var fs = require('fs');

var template = fs.readFileSync(__dirname + '/process-definitions.html', 'utf8');

module.exports = [ 'ViewsProvider', function(ViewsProvider) {
  ViewsProvider.registerDefaultView('cockpit.processes.dashboard', {
    id: 'process-definition',
    label: 'Deployed Process Definitions',
    template: template,
    controller: [
      '$scope',
      'Views',
      'camAPI',
      'localConf',
      '$translate',
      function($scope, Views, camAPI, localConf, $translate) {

        var processDefinitionService = camAPI.resource('process-definition');

        $scope.processesActions = Views.getProviders({ component: 'cockpit.processes.action'});
        $scope.hasActionPlugin = $scope.processesActions.length > 0;

        var processInstancePlugins = Views.getProviders({ component: 'cockpit.processInstance.view' });
        $scope.hasHistoryPlugin = processInstancePlugins.filter(function(plugin) {
          return plugin.id === 'history';
        }).length > 0;
        $scope.hasReportPlugin = Views.getProviders({ component: 'cockpit.report' }).length > 0;
        $scope.hasSearchPlugin = Views.getProviders( { component: 'cockpit.processes.dashboard', id: 'search-process-instances' }).length > 0;

        $scope.headColumns = [
          { class: 'state',    request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_STATE')},
          { class: 'incidents',request: 'incidentCount', sortable: true,  content: $translate.instant('PLUGIN_PROCESS_DEF_INCIDENTS')},
          { class: 'instances',request: 'instances'    , sortable: true, content: $translate.instant('PLUGIN_PROCESS_DEF_RUNNING_INSTANCES')},
          { class: 'name',     request: 'name'          , sortable: true, content: $translate.instant('PLUGIN_PROCESS_DEF_NAME')},
          { class: 'tenantID', request: 'tenantId'     , sortable: true, content: $translate.instant('PLUGIN_PROCESS_DEF_TENANT_ID')},
          { class: 'history',  request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_HISTORY_VIEW'), condition: $scope.hasReportPlugin},
          { class: 'report',   request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_REPORT'), condition: $scope.hasReportPlugin},
          { class: 'action',   request: '', sortable: false, content: $translate.instant('PLUGIN_PROCESS_DEF_ACTION'), condition: $scope.hasActionPlugin}
        ];

        // Default sorting
        var defaultValue = { sortBy: 'name', sortOrder: 'asc', sortReverse: false};
        $scope.sortObj   = loadLocal(defaultValue);

        // Update Table
        $scope.onSortChange = function(sortObj) {
          sortObj = sortObj || $scope.sortObj;
          // transforms sortOrder to boolean required by anqular-sorting;
          sortObj.sortReverse = sortObj.sortOrder !== 'asc';
          saveLocal(sortObj);
          $scope.sortObj = sortObj;
        };

        var processData = $scope.processData.newChild($scope);

        var getPDIncidentsCount = function(incidents) {
          if(!incidents) { return 0;}
          return incidents.reduce(function(sum, incident) {
            return sum + incident.incidentCount;
          }, 0);
        };

        $scope.loadingState = 'LOADING';

        // only get count of process definitions
        var countProcessDefinitions =  function() {
          processDefinitionService.count({
            latest: true
          }, function(err, count) {
            if (err) {
              $scope.loadingState = 'ERROR';
            }
            $scope.processDefinitionsCount = count;
          });
        };

        // get full list of process definitions and related resources
        var listProcessDefinitions =  function() {
          processDefinitionService.list({
            latest: true
          }, function(err, data) {
            $scope.processDefinitionData = data.items;
            $scope.processDefinitionsCount = data.count;
            if (err) {
              $scope.loadingState = 'ERROR';
            }

            $scope.loadingState = 'LOADED';

            processData.observe('processDefinitionStatistics', function(processDefinitionStatistics) {
              $scope.statistics = processDefinitionStatistics;

              $scope.statistics.forEach(function(statistic) {
                var processDefId = statistic.definition.id;
                var foundIds = $scope.processDefinitionData.filter(function(pd) {
                  return pd.id === processDefId;
                });

                var foundObject = foundIds[0];
                if(foundObject) {
                  foundObject.incidents = statistic.incidents;
                  foundObject.incidentCount = getPDIncidentsCount(foundObject.incidents);
                  foundObject.instances = statistic.instances;
                }
              });
            });
          });
        };

        $scope.definitionVars = { read: [ 'pd' ] };

        var removeActionDeleteListener = $scope.$on('processes.action.delete', function(event, definitionId) {

          var definitions = $scope.processDefinitionData;

          for (var i = 0; i < definitions.length; i++) {
            if (definitions[i].id === definitionId) {
              definitions.splice(i, 1);
              break;
            }
          }

          $scope.processDefinitionsCount = definitions.length;
        });

        $scope.$on('$destroy', function() {
          removeActionDeleteListener();
        });

        $scope.incidentsLink = '#/processes?searchQuery=%5B%7B%22type%22:%22PIincidentStatus%22,%22operator%22:' +
          '%22eq%22,%22value%22:%22open%22,%22name%22:%22%22%7D,%7B%22type%22:%22PIprocessDefinitionKey%22,' +
          '%22operator%22:%22eq%22,%22value%22:%22PD_KEY%22,%22name%22:%22%22%7D%5D#search-section';

        $scope.activeTab = 'list';

        $scope.selectTab = function(tab) {
          $scope.activeTab = tab;
        };

        $scope.activeSection = localConf.get('processesDashboardActive', true);
        // if tab is not active, it's enough to only get the count of process definitions
        $scope.activeSection ? listProcessDefinitions() : countProcessDefinitions();

        $scope.toggleSection = function toggleSection() {
          // if tab is not active, it's enough to only get the count of process definitions
          ($scope.activeSection = !$scope.activeSection) ? listProcessDefinitions() : countProcessDefinitions();
          localConf.set('processesDashboardActive', $scope.activeSection);
        };

        function saveLocal(sortObj) {
          localConf.set('sortProcessDefTab', sortObj);

        }
        function loadLocal(defaultValue) {
          return localConf.get('sortProcessDefTab', defaultValue);
        }

      }],

    priority: 0
  });
}];
<|endoftext|>


<commit_before>import invariant from 'invariant';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import PT from 'prop-types';
import React, { Fragment } from 'react';
import {
  lifecycle,
  setPropTypes,
  getContext,
  withContext,
} from 'recompose';

import {
  composeComponent,
  composeHOC,
  restoreProps,
  saveProps,
} from 'utils/reactTools';
import { withInitialState } from 'utils/reduxTools';

const scope = 'app/utils/ReducerInjector';

const isValidKey = (key) => isString(key) && !isEmpty(key);

export const createReducerInjector = (onSet) => {
  const innerScope = `${scope}/createReducerInjector`;
  invariant(isFunction(onSet),
    `${innerScope}: Expected 'onSet' to be a function`);

  let reducers = {};

  return (key, reducer) => {
    const innerScope2 = `${scope}/injectReducer`;
    invariant(isValidKey(key),
      `${innerScope2}: Expected 'key' to be a non-empty string`);
    invariant(isFunction(reducer),
      `${innerScope2}: Expected 'reducer' to be a function`);
    // Check `reducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
    if (key in reducers && reducers[key] === reducer) return;

    onSet(reducers = { ...reducers, [key]: reducer });
  };
};

const ReducerInjectorShape = PT.shape({
  inject: PT.func.isRequired,
});

export const ReducerInjector = composeComponent('ReducerInjector',
  setPropTypes({
    inject: PT.func.isRequired,
  }),
  saveProps({ keep: ['inject'] }),
  withContext(
    { reducerInjector: ReducerInjectorShape.isRequired },
    ({ inject }) => ({ reducerInjector: { inject } }),
  ),
  restoreProps(),
  Fragment);

export const InjectReducer = composeComponent('InjectReducer',
  setPropTypes({
    mount: PT.string.isRequired,
    reducer: PT.func.isRequired,
  }),
  saveProps({ keep: ['mount', 'reducer'] }),
  getContext({
    reducerInjector: ReducerInjectorShape.isRequired,
  }),
  lifecycle({
    componentWillMount() {
      this.props.reducerInjector.inject(this.props.mount, this.props.reducer);
    },
  }),
  restoreProps(),
  Fragment);

export const injectReducer = (mount, reducer, initial) =>
  composeHOC(`injectReducer(${mount})`, (Component) => (props) => (
    <InjectReducer
      mount={mount}
      reducer={initial ? withInitialState(initial(props), reducer) : reducer}
    >
      <Component {...props} />
    </InjectReducer>
  ));

export const withInjectableReducers = (createReducer) => (createStore) => (...args) => {
  const store = createStore(...args);
  const inject = createReducerInjector((injected) => {
    store.replaceReducer(createReducer(injected));
  });
  return {
    ...store,
    injectReducer: inject,
  };
};
<commit_msg>utils/ReducerInjector: JSDoc comments (#672)<commit_after>import invariant from 'invariant';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import PT from 'prop-types';
import React, { Fragment } from 'react';
import {
  lifecycle,
  setPropTypes,
  getContext,
  withContext,
} from 'recompose';

import {
  composeComponent,
  composeHOC,
  restoreProps,
  saveProps,
} from 'utils/reactTools';
import { withInitialState } from 'utils/reduxTools';

const scope = 'app/utils/ReducerInjector';

const isValidKey = (key) => isString(key) && !isEmpty(key);

/**
 * Create a reducer injector function.
 *
 * @param {function} onSet
 *   Callback that gets called with the injected reducer map when it gets updated
 *   (a new reducer injected).
 *
 * @returns {function}
 *   A reducer injector function.
 *   Takes a key (mountpoint) and a reducer.
 */
export const createReducerInjector = (onSet) => {
  const innerScope = `${scope}/createReducerInjector`;
  invariant(isFunction(onSet),
    `${innerScope}: Expected 'onSet' to be a function`);

  let reducers = {};

  return (key, reducer) => {
    const innerScope2 = `${scope}/injectReducer`;
    invariant(isValidKey(key),
      `${innerScope2}: Expected 'key' to be a non-empty string`);
    invariant(isFunction(reducer),
      `${innerScope2}: Expected 'reducer' to be a function`);
    // Check `reducers[key] === reducer` for hot reloading
    // when a key is the same but a reducer is different
    if (key in reducers && reducers[key] === reducer) return;

    onSet(reducers = { ...reducers, [key]: reducer });
  };
};

const ReducerInjectorShape = PT.shape({
  inject: PT.func.isRequired,
});

/**
 * Provider component for reducer injection system.
 */
export const ReducerInjector = composeComponent('ReducerInjector',
  setPropTypes({
    /**
     * A reducer injector function.
     */
    inject: PT.func.isRequired,
  }),
  saveProps({ keep: ['inject'] }),
  withContext(
    { reducerInjector: ReducerInjectorShape.isRequired },
    ({ inject }) => ({ reducerInjector: { inject } }),
  ),
  restoreProps(),
  Fragment);

/**
 * Component that injects a given reducer into the store on mount.
 */
export const InjectReducer = composeComponent('InjectReducer',
  setPropTypes({
    /**
     * A key under which the reducer gets injected.
     */
    mount: PT.string.isRequired,
    /**
     * A reducer that gets injected.
     */
    reducer: PT.func.isRequired,
  }),
  saveProps({ keep: ['mount', 'reducer'] }),
  getContext({
    reducerInjector: ReducerInjectorShape.isRequired,
  }),
  lifecycle({
    componentWillMount() {
      this.props.reducerInjector.inject(this.props.mount, this.props.reducer);
    },
  }),
  restoreProps(),
  Fragment);

/**
 * Create a HOC that injects a given reducer into the store on mount.
 * InjectReducer component is used under the hood.
 *
 * @param {string} mount
 *   A key under which the reducer gets injected.
 *
 * @param {reduxTools.Reducer} reducer
 *
 * @param {function} initial
 *   A function to populate the reducer's initial state.
 *   Gets called with the props passed to the resulting component.
 *
 * @returns {reactTools.HOC}
 */
export const injectReducer = (mount, reducer, initial) =>
  composeHOC(`injectReducer(${mount})`, (Component) => (props) => (
    <InjectReducer
      mount={mount}
      reducer={initial ? withInitialState(initial(props), reducer) : reducer}
    >
      <Component {...props} />
    </InjectReducer>
  ));

/**
 * Create a store enhancer that attaches `injectReducer` method to the store.
 *
 * @param {function} createReducer
 *   A function that creates a reducer from the given reducer map.
 *
 * @returns {reduxTools.StoreEnhancer}
 */
export const withInjectableReducers = (createReducer) => (createStore) => (...args) => {
  const store = createStore(...args);
  const inject = createReducerInjector((injected) => {
    store.replaceReducer(createReducer(injected));
  });
  return {
    ...store,
    injectReducer: inject,
  };
};
<|endoftext|>