<commit_before>angular.module('gridshore.c3js.chart')
    .directive('c3chart', ['$timeout', function(timeout) {
        return C3Chart(timeout);
    }]);

/**
 * @ngdoc directive
 * @name C3Chart
 * @description
 *   `c3chart` is the main directive to create the chart. Use it to set the padding properties and include the other directives. You can also register the callback in this directive that receives the initialised chart object.
 *
 *   When using multiple charts in the same page you need to provide unique bind-id parameters.
 *
 * Restrict To:
 *   Element
 *
 * Parent Element:
 *   -
 *
 * @param {Number} padding-top Set the top padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-top| c3js doc}
 *
 * @param {Number} padding-bottom Set the bottom padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-bottom| c3js doc}
 * @param {Number} padding-right Set the right padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-right| c3js doc}
 *
 * @param {Number} padding-left Set the left padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-left| c3js doc}
 *
 * @param {String} empty-label Set text displayed when empty data.
 *
 *   {@link http://c3js.org/reference.html#data-empty-label-text| c3js doc}
 *
 * @param {String} bind-id Id of the chart, needs to be unique when using multiple charts on one page.
 *
 *   {@link http://c3js.org/reference.html#bindto| c3js doc}
 *
 * @param {String} sort-data You can enter three different versions: asc, desc, null. Using this sorting you can change the order of stacking and the order of the pieces of a pie or donut.
 *
 *   {@link http://c3js.org/reference.html#data-order| c3js doc}
 *
 * @param {Boolean} show-labels Configure to show the labels 'true' or not, default is false.
 *
 *   {@link http://c3js.org/reference.html#data-labels| c3js doc}
 *
 * @param {Function} labels-format-function Provide a function to format the labels.
 *
 *   {@link http://c3js.org/reference.html#data-labels-format| c3js doc}
 *
 * @param {Boolean} show-subchart Configure to show the subchart or not (default).
 *
 *   {@link http://c3js.org/reference.html#subchart-show| c3js doc}
 *
 * @param {Boolean} enable-zoom Configure to enable zoom in the chart or not (defaut).
 *
 *   {@link http://c3js.org/reference.html#subchart-show| c3js doc}
 *
 * @param {Array} chart-data Provide a reference to a collection that can contain dynamic data. When providing this attrbiute you also need to provide the chart-columns attribute.
 *
 *   Array consisting of objects with values for the different columns: [{"data1":10,"data2":20},{"data1":50,"data2":60}]
 *
 * @param {Array} chart-columns Provide a reference to a collection that contains the columns. When providing this attrbiute you also need to provide the chart-data attribute.
 *
 *   Array consisting of objects with some properties for the different columns: [{"id": "data1", "type": "line"}, {"id": "data2", "type": "bar"}]
 *
 * @param {Object} chart-x Provide information about the x column. Used when adding dynamic data to specify the field that contains the x data value.
 *
 *   Object containing reference to the id of the x data field: {"id": "x", "name": "My Data points"}
 *
 * @param {Function} callback-function Use this if you want to interact with the chart object using the api
 *
 *   {@link http://c3js.org/reference.html#api-focus| c3js doc}
 *
 * @param {Number} transition-duration Duration of transition (in milliseconds) for chart animation. If you specify 0, transitions will be disabled which is good for large datasets.
 *
 *   {@link http://c3js.org/reference.html#transition-duration| c3js doc}
 *
 * @param {Object} initial-config Provide the initial config object to start the graph with.
 *
 * @example
 * Usage:
 *   <c3chart >
 *
 *   </c3chart>
 *
 * Example:
 *
 *   {@link http://jettro.github.io/c3-angular-directive/#examples}
 *
 * Shows how to use dynamic data points.
 *
 * <c3chart bindto-id="dynamicpie" chart-data="piePoints" chart-columns="pieColumns"/>
 *
 *     $scope.piePoints = [{"data1": 70, "data2": 30, "data3": "100"}];
 *     $scope.pieColumns = [{"id": "data1", "type": "pie"}, {"id": "data2", "type": "pie"}, {
 *       "id": "data3",
 *       "type": "pie"
 *
 * Show how to register a callback function and use it. The screen contains a button to toggle the legend visibility.
 *
 * <c3chart bindto-id="dynamicpie" chart-data="piePoints" chart-columns="pieColumns"
 *        callback-function="handleCallback"/>
 *
 *     $scope.handleCallback = function (chartObj) {
 *       $scope.theChart = chartObj;
 *   };
 *
 *   $scope.legendIsShown = true;
 *   $scope.toggleLegend = function() {
 *       if ($scope.legendIsShown) {
 *           $scope.theChart.legend.hide();
 *       } else {
 *           $scope.theChart.legend.show();
 *       }
 *       $scope.legendIsShown= !$scope.legendIsShown;
 *       $scope.theChart.flush();
 *   };
 */
function C3Chart ($timeout) {
    var chartLinker = function (scope, element, attrs, chartCtrl) {
        var paddingTop = attrs.paddingTop;
        var paddingRight = attrs.paddingRight;
        var paddingBottom = attrs.paddingBottom;
        var paddingLeft = attrs.paddingLeft;
        var sortData = attrs.sortData;
        var transitionDuration = attrs.transitionDuration;
        var initialConfig = attrs.initialConfig;

        if (paddingTop) {
            chartCtrl.addPadding('top', paddingTop);
        }
        if (paddingRight) {
            chartCtrl.addPadding('right', paddingRight);
        }
        if (paddingBottom) {
            chartCtrl.addPadding('bottom', paddingBottom);
        }
        if (paddingLeft) {
            chartCtrl.addPadding('left', paddingLeft);
        }
        if (sortData) {
            chartCtrl.addSorting(sortData);
        }
        if (attrs.labelsFormatFunction) {
            chartCtrl.addDataLabelsFormatFunction(scope.labelsFormatFunction());
        }
        if (attrs.callbackFunction) {
            chartCtrl.addChartCallbackFunction(scope.callbackFunction());
        }
        if (transitionDuration) {
            chartCtrl.addTransitionDuration(transitionDuration);
        }
        if (initialConfig) {
            chartCtrl.addInitialConfig(initialConfig);
        }
        // Trick to wait for all rendering of the DOM to be finished.
        $timeout(function () {
            chartCtrl.showGraph();
        });
    };

    return {
        "restrict": "E",
        "controller": "ChartController",
        "scope": {
            "bindto": "@bindtoId",
            "showLabels": "@showLabels",
            "labelsFormatFunction": "&",
            "showSubchart": "@showSubchart",
            "enableZoom": "@enableZoom",
            "chartData": "=chartData",
            "chartColumns": "=chartColumns",
            "chartX": "=chartX",
            "callbackFunction": "&",
            "emptyLabel": "@emptyLabel"
        },
        "template": "

",
        "replace": true,
        "transclude": true,
        "link": chartLinker
    };
}
<commit_msg>SMall fix in the docs for zoom<commit_after>angular.module('gridshore.c3js.chart')
    .directive('c3chart', ['$timeout', function(timeout) {
        return C3Chart(timeout);
    }]);

/**
 * @ngdoc directive
 * @name C3Chart
 * @description
 *   `c3chart` is the main directive to create the chart. Use it to set the padding properties and include the other directives. You can also register the callback in this directive that receives the initialised chart object.
 *
 *   When using multiple charts in the same page you need to provide unique bind-id parameters.
 *
 * Restrict To:
 *   Element
 *
 * Parent Element:
 *   -
 *
 * @param {Number} padding-top Set the top padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-top| c3js doc}
 *
 * @param {Number} padding-bottom Set the bottom padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-bottom| c3js doc}
 * @param {Number} padding-right Set the right padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-right| c3js doc}
 *
 * @param {Number} padding-left Set the left padding of the chart.
 *
 *   {@link http://c3js.org/reference.html#padding-left| c3js doc}
 *
 * @param {String} empty-label Set text displayed when empty data.
 *
 *   {@link http://c3js.org/reference.html#data-empty-label-text| c3js doc}
 *
 * @param {String} bind-id Id of the chart, needs to be unique when using multiple charts on one page.
 *
 *   {@link http://c3js.org/reference.html#bindto| c3js doc}
 *
 * @param {String} sort-data You can enter three different versions: asc, desc, null. Using this sorting you can change the order of stacking and the order of the pieces of a pie or donut.
 *
 *   {@link http://c3js.org/reference.html#data-order| c3js doc}
 *
 * @param {Boolean} show-labels Configure to show the labels 'true' or not, default is false.
 *
 *   {@link http://c3js.org/reference.html#data-labels| c3js doc}
 *
 * @param {Function} labels-format-function Provide a function to format the labels.
 *
 *   {@link http://c3js.org/reference.html#data-labels-format| c3js doc}
 *
 * @param {Boolean} show-subchart Configure to show the subchart or not (default).
 *
 *   {@link http://c3js.org/reference.html#subchart-show| c3js doc}
 *
 * @param {Boolean} enable-zoom Configure to enable zoom in the chart or not (defaut).
 *
 *   {@link http://c3js.org/reference.html#enable-zoom| c3js doc}
 *
 * @param {Array} chart-data Provide a reference to a collection that can contain dynamic data. When providing this attrbiute you also need to provide the chart-columns attribute.
 *
 *   Array consisting of objects with values for the different columns: [{"data1":10,"data2":20},{"data1":50,"data2":60}]
 *
 * @param {Array} chart-columns Provide a reference to a collection that contains the columns. When providing this attrbiute you also need to provide the chart-data attribute.
 *
 *   Array consisting of objects with some properties for the different columns: [{"id": "data1", "type": "line"}, {"id": "data2", "type": "bar"}]
 *
 * @param {Object} chart-x Provide information about the x column. Used when adding dynamic data to specify the field that contains the x data value.
 *
 *   Object containing reference to the id of the x data field: {"id": "x", "name": "My Data points"}
 *
 * @param {Function} callback-function Use this if you want to interact with the chart object using the api
 *
 *   {@link http://c3js.org/reference.html#api-focus| c3js doc}
 *
 * @param {Number} transition-duration Duration of transition (in milliseconds) for chart animation. If you specify 0, transitions will be disabled which is good for large datasets.
 *
 *   {@link http://c3js.org/reference.html#transition-duration| c3js doc}
 *
 * @param {Object} initial-config Provide the initial config object to start the graph with.
 *
 * @example
 * Usage:
 *   <c3chart >
 *
 *   </c3chart>
 *
 * Example:
 *
 *   {@link http://jettro.github.io/c3-angular-directive/#examples}
 *
 * Shows how to use dynamic data points.
 *
 * <c3chart bindto-id="dynamicpie" chart-data="piePoints" chart-columns="pieColumns"/>
 *
 *     $scope.piePoints = [{"data1": 70, "data2": 30, "data3": "100"}];
 *     $scope.pieColumns = [{"id": "data1", "type": "pie"}, {"id": "data2", "type": "pie"}, {
 *       "id": "data3",
 *       "type": "pie"
 *
 * Show how to register a callback function and use it. The screen contains a button to toggle the legend visibility.
 *
 * <c3chart bindto-id="dynamicpie" chart-data="piePoints" chart-columns="pieColumns"
 *        callback-function="handleCallback"/>
 *
 *     $scope.handleCallback = function (chartObj) {
 *       $scope.theChart = chartObj;
 *   };
 *
 *   $scope.legendIsShown = true;
 *   $scope.toggleLegend = function() {
 *       if ($scope.legendIsShown) {
 *           $scope.theChart.legend.hide();
 *       } else {
 *           $scope.theChart.legend.show();
 *       }
 *       $scope.legendIsShown= !$scope.legendIsShown;
 *       $scope.theChart.flush();
 *   };
 */
function C3Chart ($timeout) {
    var chartLinker = function (scope, element, attrs, chartCtrl) {
        var paddingTop = attrs.paddingTop;
        var paddingRight = attrs.paddingRight;
        var paddingBottom = attrs.paddingBottom;
        var paddingLeft = attrs.paddingLeft;
        var sortData = attrs.sortData;
        var transitionDuration = attrs.transitionDuration;
        var initialConfig = attrs.initialConfig;

        if (paddingTop) {
            chartCtrl.addPadding('top', paddingTop);
        }
        if (paddingRight) {
            chartCtrl.addPadding('right', paddingRight);
        }
        if (paddingBottom) {
            chartCtrl.addPadding('bottom', paddingBottom);
        }
        if (paddingLeft) {
            chartCtrl.addPadding('left', paddingLeft);
        }
        if (sortData) {
            chartCtrl.addSorting(sortData);
        }
        if (attrs.labelsFormatFunction) {
            chartCtrl.addDataLabelsFormatFunction(scope.labelsFormatFunction());
        }
        if (attrs.callbackFunction) {
            chartCtrl.addChartCallbackFunction(scope.callbackFunction());
        }
        if (transitionDuration) {
            chartCtrl.addTransitionDuration(transitionDuration);
        }
        if (initialConfig) {
            chartCtrl.addInitialConfig(initialConfig);
        }
        // Trick to wait for all rendering of the DOM to be finished.
        $timeout(function () {
            chartCtrl.showGraph();
        });
    };

    return {
        "restrict": "E",
        "controller": "ChartController",
        "scope": {
            "bindto": "@bindtoId",
            "showLabels": "@showLabels",
            "labelsFormatFunction": "&",
            "showSubchart": "@showSubchart",
            "enableZoom": "@enableZoom",
            "chartData": "=chartData",
            "chartColumns": "=chartColumns",
            "chartX": "=chartX",
            "callbackFunction": "&",
            "emptyLabel": "@emptyLabel"
        },
        "template": "

",
        "replace": true,
        "transclude": true,
        "link": chartLinker
    };
}
<|endoftext|>


<commit_before>
// fixes for composite field => getFieldValues() doesn't work
// read more here http://www.sencha.com/forum/showthread.php?99021&mode=linear
var _initComponent = Ext.form.CompositeField.prototype.initComponent;
Ext.override(Ext.form.CompositeField, {
    initComponent: function(){
        _initComponent.apply(this, arguments);
        this.innerCt.onwerCt = this;
    },
    bubble : Ext.Container.prototype.bubble,
    cascade : Ext.Container.prototype.cascade,
    findById : Ext.Container.prototype.findById,
    findByType : Ext.Container.prototype.findByType,
    find : Ext.Container.prototype.find,
    findBy : Ext.Container.prototype.findBy,
    get : Ext.Container.prototype.get,
    setValue : undefined
});

// fixes Drag & Drop#
Ext.dd.DragDropMgr.getZIndex = function(element) {
    var body = document.body,
        z,
        zIndex = -1;

    element = Ext.getDom(element);
    while (element !== body) {
        if(!element) break; // this fixes the problem

        if (!isNaN(z = Number(Ext.fly(element).getStyle('zIndex')))) {
            zIndex = z;
        }
        element = element.parentNode;
    }
    return zIndex;
};
<commit_msg>Ext DnD fix<commit_after>
// fixes for composite field => getFieldValues() doesn't work
// read more here http://www.sencha.com/forum/showthread.php?99021&mode=linear
var _initComponent = Ext.form.CompositeField.prototype.initComponent;
Ext.override(Ext.form.CompositeField, {
    initComponent: function(){
        _initComponent.apply(this, arguments);
        this.innerCt.onwerCt = this;
    },
    bubble : Ext.Container.prototype.bubble,
    cascade : Ext.Container.prototype.cascade,
    findById : Ext.Container.prototype.findById,
    findByType : Ext.Container.prototype.findByType,
    find : Ext.Container.prototype.find,
    findBy : Ext.Container.prototype.findBy,
    get : Ext.Container.prototype.get,
    setValue : undefined
});

// fixes Drag & Drop#
Ext.dd.DragDropMgr.getZIndex = function(element) {
    var body = document.body,
        z,
        zIndex = -1;
    var overTargetEl = element;

    element = Ext.getDom(element);
    while (element !== body) {

        // this fixes the problem
        if(!element) {
            this._remove(overTargetEl); // remove the drop target from the manager
            break;
        }
        // fix end

        if (!isNaN(z = Number(Ext.fly(element).getStyle('zIndex')))) {
            zIndex = z;
        }
        element = element.parentNode;
    }
    return zIndex;
};
<|endoftext|>


<commit_before>define(['js/ui/ItemsView', 'js/html/HtmlElement'], function(ItemsView, HtmlElement) {
    return ItemsView.inherit('js.ui.ListView', {
        defaults: {
            tagName: 'ul'
        },

        _createComponentForItem: function (item, i) {
            var attr = {};
            attr[this._getItemKey()] = item;
            attr[this._getIndexKey()] = i;

            var components = this.$templates['item'].createComponents(attr);
            var component = this.createComponent(HtmlElement, {
                tagName: 'li'
            });

            for (var j = 0; j < components.length; j++) {
                component.addChild(components[j]);
            }

            // add to rendered item map
            this.$renderedItems.push({
                item: item,
                component: component
            });
            return component;
        }

    })
});<commit_msg>refactored creating of components for items<commit_after>define(['js/ui/ItemsView', 'js/html/HtmlElement'], function(ItemsView, HtmlElement) {
    return ItemsView.inherit('js.ui.ListView', {
        defaults: {
            tagName: 'ul'
        },

        _createComponentForItem: function (item, i) {
            var attr = {};
            attr[this._getItemKey()] = item;
            attr[this._getIndexKey()] = i;

            var components = this.$templates['item'].createComponents(attr);
            var component = this.createComponent(HtmlElement, {
                tagName: 'li'
            });

            for (var j = 0; j < components.length; j++) {
                component.addChild(components[j]);
            }

            return component;
        }

    })
});<|endoftext|>


<commit_before>var scripts = document.getElementsByTagName('script'),
    script = scripts[scripts.length - 1];

var get_time_display = function(stamp) {
    var dt = new Date(stamp);
    var period = dt.getHours() < 12 ? 'AM' : 'PM';
    var hours = dt.getHours() > 12 ? dt.getHours() - 12 : dt.getHours();
    if (hours === 0) {
        hours = 12;
    }
    var minutes = dt.getMinutes() < 10 ? '0' + dt.getMinutes() : dt.getMinutes();
    return hours + ':' + minutes + ' ' + period;
};

function Timeline(loc, start_time, end_time, width, height) {
    this.loc = loc;
    this.start_time = start_time;
    this.end_time = end_time;
    this.width = width;
    this.height = height;

    this.container = d3.select(this.loc).append('svg');

    // Settings
    this.draw_width = this.width - 40; // Draw inside the svg without clipping
    this.y_offset = 20; // Height offset from time marker
    this.interval = 3600000; // One hour in milliseconds
    this.edge_offset = 20; // Come off the edge
}

Timeline.prototype.draw = function() {
    var dt = this.end_time - this.start_time;

    this.line_offset = this.draw_width / (dt / this.interval);

    for(var i = 0; i <= dt / this.interval; i++) {
        var x_offset = i * this.line_offset + this.edge_offset;

        this.container.append('line')
            .attr('x1', x_offset).attr('x2', x_offset)
            .attr('y1', this.y_offset).attr('y2', this.height - this.y_offset)
            .style('stroke', '#000000');

        var time = get_time_display(new Date(this.start_time + this.interval * i));

        this.container.append('text')
            .attr('x', x_offset - 15).attr('y', 10)
            .style('font-size', '10px')
            .style('fill', '#000000')
            .style('opacity', 1)
            .text(time);
    }
};

function Entry(timeline, entry_data) {
    this.project_name = entry_data['project_name'];
    this.start_time = entry_data['start_time'];
    this.end_time = entry_data['end_time'];
    this.hours = entry_data['hours'];
    this.pk = entry_data['pk'];
    this.update_url = entry_data['update_url'];
    this.active = entry_data['active'];
    this.seconds_paused = entry_data['seconds_paused'];

    this.timeline = timeline;

    this.height = timeline.height - 2 * timeline.y_offset;
}

Entry.prototype.draw = function() {
    var timeline = this.timeline;

    var dt = this.end_time - this.start_time,
        width = timeline.line_offset * (dt / timeline.interval),
        x_offset = timeline.line_offset *
            (this.start_time - timeline.start_time) / timeline.interval  + timeline.edge_offset;

    var entry = timeline.container.append('rect')
        .attr('x', x_offset).attr('y', timeline.y_offset + 5)
        .attr('rx', 10).attr('ry', 10)
        .attr('height', this.height - 10)
        .attr('width', width);

    // Add the attributes for popovers
    var popover_msg = 'You have worked ' + this.hours + ' hours.';
    var start_str = get_time_display(new Date(this.start_time));
    var end_str = get_time_display(new Date(this.end_time));
    popover_msg += '
' + start_str + ' - ' + end_str;
    entry.attr('data-title', this.project_name)
        .attr('data-content', popover_msg);

    entry.transition()
        .delay(100)
        .duration(1500)
        .attr('fill', '#0061AA')
        .attr('stroke', '#333333')
        .attr('stroke-width', '2px')
        .style('opacity', '0.95');

    var text = timeline.container.append('text')
        .attr('font-weight', 'bolder')
        .style('font-size', '14px')
        .text(this.project_name);

    // Get bounding boxes for centering text
    var text_box = text.node().getBBox(),
        entry_box = entry.node().getBBox();

    // Strip project name down if its too large
    if(text_box.width > entry_box.width) {
        var sub = Math.ceil(text_box.width / (text_box.width - entry_box.width)), // Ratio using widths
            name = this.project_name.substring(0, sub) + '...';

        name = sub === 0 || entry_box.width < 30 ? '' : name;

        text.text(name);

        // New bounding box
        text_box = text.node().getBBox();
    }

    // Do some positioning to get the text centered correctly
    var text_xpos = x_offset + width / 2 - text_box.width / 2,
        text_ypos = timeline.y_offset + this.height / 2 + text_box.height / 4;

    text.attr('x', text_xpos)
        .attr('y', text_ypos);

    // Display!
    text.transition()
        .delay(100)
        .duration(1500)
        .attr('fill', '#FFFFFF')
        .style('opacity', '1.0');

    // Handle click
    var that = this;
    $(entry.node()).click(function() {
        location.href = that.update_url;
    });
};

var draw_timeline = function(data) {
    var $timeline = $('#timeline'),
        height = $timeline.height(),
        width = $(window).width();

    var start_time = new Date(data.start_time),
        end_time = new Date(data.end_time);

    // Convert the minutes to milliseconds
    var timezone_offset = start_time.getTimezoneOffset() * 60 * 1000;

    var t = new Timeline($timeline.selector, start_time.getTime() + timezone_offset,
        end_time.getTime() + timezone_offset, width, height);
    t.draw();

    for(var i = 0; i < data.entries.length; i++) {
        var entry = data.entries[i],
            start = new Date(entry.start_time),
            end = new Date(entry.end_time);

        var dt = end - start,
            hours = Math.ceil((dt / (3600 * 1000)) * 100) / 100;

        var e = new Entry(t, {
            'start_time': start.getTime() + timezone_offset,
            'end_time': end.getTime() + timezone_offset,
            'project_name': entry.project,
            'pk': entry.pk,
            'active': entry.active,
            'seconds_paused': entry.seconds_paused,
            'hours': hours,
            'update_url': entry.update_url
        });
        e.draw();
    }

    // Enable popovers
    $('.timeline rect').popover({
        'placement': 'top'
    });
};

(function() {
    var data = JSON.parse(script.getAttribute('data-entries'));
    draw_timeline(data);

    $(window).resize(function() {
        $('#timeline svg').remove();
        draw_timeline(data);
    });
})();
<commit_msg>First pass at making the time intervals change if the browser is too small or too much time has elapsed to show the markers hourly<commit_after>var scripts = document.getElementsByTagName('script'),
    script = scripts[scripts.length - 1];

var get_time_display = function(stamp) {
    var dt = new Date(stamp);
    var period = dt.getHours() < 12 ? 'AM' : 'PM';
    var hours = dt.getHours() > 12 ? dt.getHours() - 12 : dt.getHours();
    if (hours === 0) {
        hours = 12;
    }
    var minutes = dt.getMinutes() < 10 ? '0' + dt.getMinutes() : dt.getMinutes();
    return hours + ':' + minutes + ' ' + period;
};

function Timeline(loc, start_time, end_time, width, height) {
    this.loc = loc;
    this.start_time = start_time;
    this.end_time = end_time;
    this.width = width;
    this.height = height;

    this.container = d3.select(this.loc).append('svg');

    // Settings
    this.draw_width = this.width - 40; // Draw inside the svg without clipping
    this.y_offset = 20; // Height offset from time marker
    var one_hour = 60 * 60 * 1000; // One hour in milliseconds
    this.interval = one_hour;
    var span_in_hours = (this.end_time - this.start_time) / one_hour,
        width_span_ratio = Math.ceil(this.draw_width / span_in_hours);
    /*
    If the browser is small enough or more than a day has elapsed, show six
    time interval markers
    */
    if (width_span_ratio < 60 || span_in_hours > 24) {
        this.interval = Math.floor((span_in_hours * one_hour) / 6);
    }
    this.edge_offset = 20; // Come off the edge
}

Timeline.prototype.draw = function() {
    var dt = this.end_time - this.start_time;

    this.line_offset = this.draw_width / (dt / this.interval);

    for(var i = 0; i <= dt / this.interval; i++) {
        var x_offset = i * this.line_offset + this.edge_offset;

        this.container.append('line')
            .attr('x1', x_offset).attr('x2', x_offset)
            .attr('y1', this.y_offset).attr('y2', this.height - this.y_offset)
            .style('stroke', '#000000');

        var time = get_time_display(new Date(this.start_time + this.interval * i));

        this.container.append('text')
            .attr('x', x_offset - 15).attr('y', 10)
            .style('font-size', '10px')
            .style('fill', '#000000')
            .style('opacity', 1)
            .text(time);
    }
};

function Entry(timeline, entry_data) {
    this.project_name = entry_data['project_name'];
    this.start_time = entry_data['start_time'];
    this.end_time = entry_data['end_time'];
    this.hours = entry_data['hours'];
    this.pk = entry_data['pk'];
    this.update_url = entry_data['update_url'];
    this.active = entry_data['active'];
    this.seconds_paused = entry_data['seconds_paused'];

    this.timeline = timeline;

    this.height = timeline.height - 2 * timeline.y_offset;
}

Entry.prototype.draw = function() {
    var timeline = this.timeline;

    var dt = this.end_time - this.start_time,
        width = timeline.line_offset * (dt / timeline.interval),
        x_offset = timeline.line_offset *
            (this.start_time - timeline.start_time) / timeline.interval  + timeline.edge_offset;

    var entry = timeline.container.append('rect')
        .attr('x', x_offset).attr('y', timeline.y_offset + 5)
        .attr('rx', 10).attr('ry', 10)
        .attr('height', this.height - 10)
        .attr('width', width);

    // Add the attributes for popovers
    var popover_msg = 'You have worked ' + this.hours + ' hours.';
    var start_str = get_time_display(new Date(this.start_time));
    var end_str = get_time_display(new Date(this.end_time));
    popover_msg += '
' + start_str + ' - ' + end_str;
    entry.attr('data-title', this.project_name)
        .attr('data-content', popover_msg);

    entry.transition()
        .delay(100)
        .duration(1500)
        .attr('fill', '#0061AA')
        .attr('stroke', '#333333')
        .attr('stroke-width', '2px')
        .style('opacity', '0.95');

    var text = timeline.container.append('text')
        .attr('font-weight', 'bolder')
        .style('font-size', '14px')
        .text(this.project_name);

    // Get bounding boxes for centering text
    var text_box = text.node().getBBox(),
        entry_box = entry.node().getBBox();

    // Strip project name down if its too large
    if(text_box.width > entry_box.width) {
        var sub = Math.ceil(text_box.width / (text_box.width - entry_box.width)), // Ratio using widths
            name = this.project_name.substring(0, sub) + '...';

        name = sub === 0 || entry_box.width < 30 ? '' : name;

        text.text(name);

        // New bounding box
        text_box = text.node().getBBox();
    }

    // Do some positioning to get the text centered correctly
    var text_xpos = x_offset + width / 2 - text_box.width / 2,
        text_ypos = timeline.y_offset + this.height / 2 + text_box.height / 4;

    text.attr('x', text_xpos)
        .attr('y', text_ypos);

    // Display!
    text.transition()
        .delay(100)
        .duration(1500)
        .attr('fill', '#FFFFFF')
        .style('opacity', '1.0');

    // Handle click
    var that = this;
    $(entry.node()).click(function() {
        location.href = that.update_url;
    });
};

var draw_timeline = function(data) {
    var $timeline = $('#timeline'),
        height = $timeline.height(),
        width = $(window).width();

    var start_time = new Date(data.start_time),
        end_time = new Date(data.end_time);

    // Convert the minutes to milliseconds
    var timezone_offset = start_time.getTimezoneOffset() * 60 * 1000;

    var t = new Timeline($timeline.selector, start_time.getTime() + timezone_offset,
        end_time.getTime() + timezone_offset, width, height);
    t.draw();

    for(var i = 0; i < data.entries.length; i++) {
        var entry = data.entries[i],
            start = new Date(entry.start_time),
            end = new Date(entry.end_time);

        var dt = end - start,
            hours = Math.ceil((dt / (3600 * 1000)) * 100) / 100;

        var e = new Entry(t, {
            'start_time': start.getTime() + timezone_offset,
            'end_time': end.getTime() + timezone_offset,
            'project_name': entry.project,
            'pk': entry.pk,
            'active': entry.active,
            'seconds_paused': entry.seconds_paused,
            'hours': hours,
            'update_url': entry.update_url
        });
        e.draw();
    }

    // Enable popovers
    $('.timeline rect').popover({
        'placement': 'top'
    });
};

(function() {
    var data = JSON.parse(script.getAttribute('data-entries'));
    draw_timeline(data);

    $(window).resize(function() {
        $('#timeline svg').remove();
        draw_timeline(data);
    });
})();
<|endoftext|>


<commit_before>define("ace/snippets/liquid",["require","exports","module"], function(require, exports, module) {
"use strict";

exports.snippetText =undefined;
exports.scope = "liquid";

});
<commit_msg>Update tmp/bower_components/ace-builds/src/snippets/liquid.js<commit_after><|endoftext|>


<commit_before>/**
 * @ngdoc overview
 * @name ui.bootstrap.carousel
 *
 * @description
 * AngularJS version of an image carousel.
 *
 */
angular.module('ui.bootstrap.carousel', [])

.controller('UibCarouselController', ['$scope', '$element', '$interval', '$animate', function($scope, $element, $interval, $animate) {
  var self = this,
    slides = self.slides = $scope.slides = [],
    NEW_ANIMATE = angular.version.minor >= 4,
    NO_TRANSITION = 'uib-noTransition',
    SLIDE_DIRECTION = 'uib-slideDirection',
    currentIndex = -1,
    currentInterval, isPlaying;
  self.currentSlide = null;

  var destroyed = false;
  /* direction: "prev" or "next" */
  self.select = $scope.select = function(nextSlide, direction) {
    var nextIndex = $scope.indexOfSlide(nextSlide);
    //Decide direction if it's not given
    if (direction === undefined) {
      direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
    }
    //Prevent this user-triggered transition from occurring if there is already one in progress
    if (nextSlide && nextSlide !== self.currentSlide && !$scope.$currentTransition) {
      goNext(nextSlide, nextIndex, direction);
    }
  };

  function goNext(slide, index, direction) {
    // Scope has been destroyed, stop here.
    if (destroyed) { return; }

    angular.extend(slide, {direction: direction, active: true});
    angular.extend(self.currentSlide || {}, {direction: direction, active: false});
    if ($animate.enabled() && !$scope.noTransition && !$scope.$currentTransition &&
      slide.$element && self.slides.length > 1) {
      slide.$element.data(SLIDE_DIRECTION, slide.direction);
      if (self.currentSlide && self.currentSlide.$element) {
        self.currentSlide.$element.data(SLIDE_DIRECTION, slide.direction);
      }

      $scope.$currentTransition = true;
      if (NEW_ANIMATE) {
        $animate.on('addClass', slide.$element, function(element, phase) {
          if (phase === 'close') {
            $scope.$currentTransition = null;
            $animate.off('addClass', element);
          }
        });
      } else {
        slide.$element.one('$animate:close', function closeFn() {
          $scope.$currentTransition = null;
        });
      }
    }

    self.currentSlide = slide;
    currentIndex = index;

    //every time you change slides, reset the timer
    restartTimer();
  }

  $scope.$on('$destroy', function() {
    destroyed = true;
  });

  function getSlideByIndex(index) {
    if (angular.isUndefined(slides[index].index)) {
      return slides[index];
    }
    var i, len = slides.length;
    for (i = 0; i < slides.length; ++i) {
      if (slides[i].index == index) {
        return slides[i];
      }
    }
  }

  self.getCurrentIndex = function() {
    if (self.currentSlide && angular.isDefined(self.currentSlide.index)) {
      return +self.currentSlide.index;
    }
    return currentIndex;
  };

  /* Allow outside people to call indexOf on slides array */
  $scope.indexOfSlide = function(slide) {
    return angular.isDefined(slide.index) ? +slide.index : slides.indexOf(slide);
  };

  $scope.next = function() {
    var newIndex = (self.getCurrentIndex() + 1) % slides.length;

    if (newIndex === 0 && $scope.noWrap()) {
      $scope.pause();
      return;
    }

    return self.select(getSlideByIndex(newIndex), 'next');
  };

  $scope.prev = function() {
    var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;

    if ($scope.noWrap() && newIndex === slides.length - 1) {
      $scope.pause();
      return;
    }

    return self.select(getSlideByIndex(newIndex), 'prev');
  };

  $scope.isActive = function(slide) {
     return self.currentSlide === slide;
  };

  $scope.$watch('interval', restartTimer);
  $scope.$on('$destroy', resetTimer);

  function restartTimer() {
    resetTimer();
    var interval = +$scope.interval;
    if (!isNaN(interval) && interval > 0) {
      currentInterval = $interval(timerFn, interval);
    }
  }

  function resetTimer() {
    if (currentInterval) {
      $interval.cancel(currentInterval);
      currentInterval = null;
    }
  }

  function timerFn() {
    var interval = +$scope.interval;
    if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) {
      $scope.next();
    } else {
      $scope.pause();
    }
  }

  $scope.play = function() {
    if (!isPlaying) {
      isPlaying = true;
      restartTimer();
    }
  };
  $scope.pause = function() {
    if (!$scope.noPause) {
      isPlaying = false;
      resetTimer();
    }
  };

  self.addSlide = function(slide, element) {
    slide.$element = element;
    slides.push(slide);
    //if this is the first slide or the slide is set to active, select it
    if(slides.length === 1 || slide.active) {
      self.select(slides[slides.length - 1]);
      if (slides.length === 1) {
        $scope.play();
      }
    } else {
      slide.active = false;
    }
  };

  self.removeSlide = function(slide) {
    if (angular.isDefined(slide.index)) {
      slides.sort(function(a, b) {
        return +a.index > +b.index;
      });
    }
    //get the index of the slide inside the carousel
    var index = slides.indexOf(slide);
    slides.splice(index, 1);
    if (slides.length > 0 && slide.active) {
      if (index >= slides.length) {
        self.select(slides[index - 1]);
      } else {
        self.select(slides[index]);
      }
    } else if (currentIndex > index) {
      currentIndex--;
    }

    //clean the currentSlide when no more slide
    if (slides.length === 0) {
      self.currentSlide = null;
    }
  };

  $scope.$watch('noTransition', function(noTransition) {
    $element.data(NO_TRANSITION, noTransition);
  });

}])

/**
 * @ngdoc directive
 * @name ui.bootstrap.carousel.directive:carousel
 * @restrict EA
 *
 * @description
 * Carousel is the outer container for a set of image 'slides' to showcase.
 *
 * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide.
 * @param {boolean=} noTransition Whether to disable transitions on the carousel.
 * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover).
 *
 * @example
<example module="ui.bootstrap">
  <file name="index.html">
    <uib-carousel>
      <uib-slide>

Beautiful!

      </uib-slide>
      <uib-slide>

D'aww!

      </uib-slide>
    </uib-carousel>
  </file>
  <file name="demo.css">
    .carousel-indicators {
      top: auto;
      bottom: 15px;
    }
  </file>
</example>
 */
.directive('uibCarousel', [function() {
  return {
    restrict: 'EA',
    transclude: true,
    replace: true,
    controller: 'UibCarouselController',
    controllerAs: 'carousel',
    require: 'carousel',
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/carousel.html';
    },
    scope: {
      interval: '=',
      noTransition: '=',
      noPause: '=',
      noWrap: '&'
    }
  };
}])

/**
 * @ngdoc directive
 * @name ui.bootstrap.carousel.directive:slide
 * @restrict EA
 *
 * @description
 * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}.  Must be placed as a child of a carousel element.
 *
 * @param {boolean=} active Model binding, whether or not this slide is currently active.
 * @param {number=} index The index of the slide. The slides will be sorted by this parameter.
 *
 * @example
<example module="ui.bootstrap">
  <file name="index.html">

  <uib-carousel>
    <uib-slide ng-repeat="slide in slides" active="slide.active" index="$index">

Slide {{$index}}

{{slide.text}}

    </uib-slide>
  </uib-carousel>
  Interval, in milliseconds: <input type="number" ng-model="myInterval">

Enter a negative number to stop the interval.

  </file>
  <file name="script.js">
function CarouselDemoCtrl($scope) {
  $scope.myInterval = 5000;
}
  </file>
  <file name="demo.css">
    .carousel-indicators {
      top: auto;
      bottom: 15px;
    }
  </file>
</example>
*/

.directive('uibSlide', function() {
  return {
    require: '^uibCarousel',
    restrict: 'EA',
    transclude: true,
    replace: true,
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/slide.html';
    },
    scope: {
      active: '=?',
      actual: '=?',
      index: '=?'
    },
    link: function (scope, element, attrs, carouselCtrl) {
      carouselCtrl.addSlide(scope, element);
      //when the scope is destroyed then remove the slide from the current slides array
      scope.$on('$destroy', function() {
        carouselCtrl.removeSlide(scope);
      });

      scope.$watch('active', function(active) {
        if (active) {
          carouselCtrl.select(scope);
        }
      });
    }
  };
})

.animation('.item', [
         '$injector', '$animate',
function ($injector, $animate) {
  var NO_TRANSITION = 'uib-noTransition',
    SLIDE_DIRECTION = 'uib-slideDirection',
    $animateCss = null;

  if ($injector.has('$animateCss')) {
    $animateCss = $injector.get('$animateCss');
  }

  function removeClass(element, className, callback) {
    element.removeClass(className);
    if (callback) {
      callback();
    }
  }

  return {
    beforeAddClass: function(element, className, done) {
      // Due to transclusion, noTransition property is on parent's scope
      if (className == 'active' && element.parent() &&
          !element.parent().data(NO_TRANSITION)) {
        var stopped = false;
        var direction = element.data(SLIDE_DIRECTION);
        var directionClass = direction == 'next' ? 'left' : 'right';
        var removeClassFn = removeClass.bind(this, element,
          directionClass + ' ' + direction, done);
        element.addClass(direction);

        if ($animateCss) {
          $animateCss(element, {addClass: directionClass})
            .start()
            .done(removeClassFn);
        } else {
          $animate.addClass(element, directionClass).then(function () {
            if (!stopped) {
              removeClassFn();
            }
            done();
          });
        }

        return function () {
          stopped = true;
        };
      }
      done();
    },
    beforeRemoveClass: function (element, className, done) {
      // Due to transclusion, noTransition property is on parent's scope
      if (className === 'active' && element.parent() &&
          !element.parent().data(NO_TRANSITION)) {
        var stopped = false;
        var direction = element.data(SLIDE_DIRECTION);
        var directionClass = direction == 'next' ? 'left' : 'right';
        var removeClassFn = removeClass.bind(this, element, directionClass, done);

        if ($animateCss) {
          $animateCss(element, {addClass: directionClass})
            .start()
            .done(removeClassFn);
        } else {
          $animate.addClass(element, directionClass).then(function() {
            if (!stopped) {
              removeClassFn();
            }
            done();
          });
        }
        return function() {
          stopped = true;
        };
      }
      done();
    }
  };
}]);

/* deprecated carousel below */

angular.module('ui.bootstrap.carousel')

.value('$carouselSuppressWarning', false)

.directive('carousel', ['$log', '$carouselSuppressWarning', function($log, $carouselSuppressWarning) {
  return {
    restrict: 'EA',
    transclude: true,
    replace: true,
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/carousel.html';
    },
    scope: {
      interval: '=',
      noTransition: '=',
      noPause: '=',
      noWrap: '&'
    },
    link: function() {
      if (!$carouselSuppressWarning) {
        $log.warn('carousel is now deprecated. Use uib-carousel instead.');
      }
    }
  };
}])

.directive('slide', ['$log', '$carouselSuppressWarning', function($log, $carouselSuppressWarning) {
  return {

    restrict: 'EA',
    transclude: true,
    replace: true,
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/slide.html';
    },
    scope: {
      active: '=?',
      actual: '=?',
      index: '=?'
    },
    link: function (scope, element, attrs, carouselCtrl) {
      if (!$carouselSuppressWarning) {
        $log.warn('slide is now deprecated. Use uib-slide instead.');
      }
    }
  };
}]);<commit_msg>fix(carousel): fix reading of `noTransition`<commit_after>/**
 * @ngdoc overview
 * @name ui.bootstrap.carousel
 *
 * @description
 * AngularJS version of an image carousel.
 *
 */
angular.module('ui.bootstrap.carousel', [])

.controller('UibCarouselController', ['$scope', '$element', '$interval', '$animate', function($scope, $element, $interval, $animate) {
  var self = this,
    slides = self.slides = $scope.slides = [],
    NEW_ANIMATE = angular.version.minor >= 4,
    NO_TRANSITION = 'uib-noTransition',
    SLIDE_DIRECTION = 'uib-slideDirection',
    currentIndex = -1,
    currentInterval, isPlaying;
  self.currentSlide = null;

  var destroyed = false;
  /* direction: "prev" or "next" */
  self.select = $scope.select = function(nextSlide, direction) {
    var nextIndex = $scope.indexOfSlide(nextSlide);
    //Decide direction if it's not given
    if (direction === undefined) {
      direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
    }
    //Prevent this user-triggered transition from occurring if there is already one in progress
    if (nextSlide && nextSlide !== self.currentSlide && !$scope.$currentTransition) {
      goNext(nextSlide, nextIndex, direction);
    }
  };

  function goNext(slide, index, direction) {
    // Scope has been destroyed, stop here.
    if (destroyed) { return; }

    angular.extend(slide, {direction: direction, active: true});
    angular.extend(self.currentSlide || {}, {direction: direction, active: false});
    if ($animate.enabled() && !$scope.noTransition && !$scope.$currentTransition &&
      slide.$element && self.slides.length > 1) {
      slide.$element.data(SLIDE_DIRECTION, slide.direction);
      if (self.currentSlide && self.currentSlide.$element) {
        self.currentSlide.$element.data(SLIDE_DIRECTION, slide.direction);
      }

      $scope.$currentTransition = true;
      if (NEW_ANIMATE) {
        $animate.on('addClass', slide.$element, function(element, phase) {
          if (phase === 'close') {
            $scope.$currentTransition = null;
            $animate.off('addClass', element);
          }
        });
      } else {
        slide.$element.one('$animate:close', function closeFn() {
          $scope.$currentTransition = null;
        });
      }
    }

    self.currentSlide = slide;
    currentIndex = index;

    //every time you change slides, reset the timer
    restartTimer();
  }

  $scope.$on('$destroy', function() {
    destroyed = true;
  });

  function getSlideByIndex(index) {
    if (angular.isUndefined(slides[index].index)) {
      return slides[index];
    }
    var i, len = slides.length;
    for (i = 0; i < slides.length; ++i) {
      if (slides[i].index == index) {
        return slides[i];
      }
    }
  }

  self.getCurrentIndex = function() {
    if (self.currentSlide && angular.isDefined(self.currentSlide.index)) {
      return +self.currentSlide.index;
    }
    return currentIndex;
  };

  /* Allow outside people to call indexOf on slides array */
  $scope.indexOfSlide = function(slide) {
    return angular.isDefined(slide.index) ? +slide.index : slides.indexOf(slide);
  };

  $scope.next = function() {
    var newIndex = (self.getCurrentIndex() + 1) % slides.length;

    if (newIndex === 0 && $scope.noWrap()) {
      $scope.pause();
      return;
    }

    return self.select(getSlideByIndex(newIndex), 'next');
  };

  $scope.prev = function() {
    var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;

    if ($scope.noWrap() && newIndex === slides.length - 1) {
      $scope.pause();
      return;
    }

    return self.select(getSlideByIndex(newIndex), 'prev');
  };

  $scope.isActive = function(slide) {
     return self.currentSlide === slide;
  };

  $scope.$watch('interval', restartTimer);
  $scope.$on('$destroy', resetTimer);

  function restartTimer() {
    resetTimer();
    var interval = +$scope.interval;
    if (!isNaN(interval) && interval > 0) {
      currentInterval = $interval(timerFn, interval);
    }
  }

  function resetTimer() {
    if (currentInterval) {
      $interval.cancel(currentInterval);
      currentInterval = null;
    }
  }

  function timerFn() {
    var interval = +$scope.interval;
    if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) {
      $scope.next();
    } else {
      $scope.pause();
    }
  }

  $scope.play = function() {
    if (!isPlaying) {
      isPlaying = true;
      restartTimer();
    }
  };
  $scope.pause = function() {
    if (!$scope.noPause) {
      isPlaying = false;
      resetTimer();
    }
  };

  self.addSlide = function(slide, element) {
    slide.$element = element;
    slides.push(slide);
    //if this is the first slide or the slide is set to active, select it
    if(slides.length === 1 || slide.active) {
      self.select(slides[slides.length - 1]);
      if (slides.length === 1) {
        $scope.play();
      }
    } else {
      slide.active = false;
    }
  };

  self.removeSlide = function(slide) {
    if (angular.isDefined(slide.index)) {
      slides.sort(function(a, b) {
        return +a.index > +b.index;
      });
    }
    //get the index of the slide inside the carousel
    var index = slides.indexOf(slide);
    slides.splice(index, 1);
    if (slides.length > 0 && slide.active) {
      if (index >= slides.length) {
        self.select(slides[index - 1]);
      } else {
        self.select(slides[index]);
      }
    } else if (currentIndex > index) {
      currentIndex--;
    }

    //clean the currentSlide when no more slide
    if (slides.length === 0) {
      self.currentSlide = null;
    }
  };

  $scope.$watch('noTransition', function(noTransition) {
    $element.data(NO_TRANSITION, noTransition);
  });

}])

/**
 * @ngdoc directive
 * @name ui.bootstrap.carousel.directive:carousel
 * @restrict EA
 *
 * @description
 * Carousel is the outer container for a set of image 'slides' to showcase.
 *
 * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide.
 * @param {boolean=} noTransition Whether to disable transitions on the carousel.
 * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover).
 *
 * @example
<example module="ui.bootstrap">
  <file name="index.html">
    <uib-carousel>
      <uib-slide>

Beautiful!

      </uib-slide>
      <uib-slide>

D'aww!

      </uib-slide>
    </uib-carousel>
  </file>
  <file name="demo.css">
    .carousel-indicators {
      top: auto;
      bottom: 15px;
    }
  </file>
</example>
 */
.directive('uibCarousel', [function() {
  return {
    restrict: 'EA',
    transclude: true,
    replace: true,
    controller: 'UibCarouselController',
    controllerAs: 'carousel',
    require: 'carousel',
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/carousel.html';
    },
    scope: {
      interval: '=',
      noTransition: '=',
      noPause: '=',
      noWrap: '&'
    }
  };
}])

/**
 * @ngdoc directive
 * @name ui.bootstrap.carousel.directive:slide
 * @restrict EA
 *
 * @description
 * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}.  Must be placed as a child of a carousel element.
 *
 * @param {boolean=} active Model binding, whether or not this slide is currently active.
 * @param {number=} index The index of the slide. The slides will be sorted by this parameter.
 *
 * @example
<example module="ui.bootstrap">
  <file name="index.html">

  <uib-carousel>
    <uib-slide ng-repeat="slide in slides" active="slide.active" index="$index">

Slide {{$index}}

{{slide.text}}

    </uib-slide>
  </uib-carousel>
  Interval, in milliseconds: <input type="number" ng-model="myInterval">

Enter a negative number to stop the interval.

  </file>
  <file name="script.js">
function CarouselDemoCtrl($scope) {
  $scope.myInterval = 5000;
}
  </file>
  <file name="demo.css">
    .carousel-indicators {
      top: auto;
      bottom: 15px;
    }
  </file>
</example>
*/

.directive('uibSlide', function() {
  return {
    require: '^uibCarousel',
    restrict: 'EA',
    transclude: true,
    replace: true,
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/slide.html';
    },
    scope: {
      active: '=?',
      actual: '=?',
      index: '=?'
    },
    link: function (scope, element, attrs, carouselCtrl) {
      carouselCtrl.addSlide(scope, element);
      //when the scope is destroyed then remove the slide from the current slides array
      scope.$on('$destroy', function() {
        carouselCtrl.removeSlide(scope);
      });

      scope.$watch('active', function(active) {
        if (active) {
          carouselCtrl.select(scope);
        }
      });
    }
  };
})

.animation('.item', [
         '$injector', '$animate',
function ($injector, $animate) {
  var NO_TRANSITION = 'uib-noTransition',
    SLIDE_DIRECTION = 'uib-slideDirection',
    $animateCss = null;

  if ($injector.has('$animateCss')) {
    $animateCss = $injector.get('$animateCss');
  }

  function removeClass(element, className, callback) {
    element.removeClass(className);
    if (callback) {
      callback();
    }
  }

  return {
    beforeAddClass: function(element, className, done) {
      // Due to transclusion, noTransition property is on parent's scope
      if (className == 'active' && element.parent() && element.parent().parent() &&
          !element.parent().parent().data(NO_TRANSITION)) {
        var stopped = false;
        var direction = element.data(SLIDE_DIRECTION);
        var directionClass = direction == 'next' ? 'left' : 'right';
        var removeClassFn = removeClass.bind(this, element,
          directionClass + ' ' + direction, done);
        element.addClass(direction);

        if ($animateCss) {
          $animateCss(element, {addClass: directionClass})
            .start()
            .done(removeClassFn);
        } else {
          $animate.addClass(element, directionClass).then(function () {
            if (!stopped) {
              removeClassFn();
            }
            done();
          });
        }

        return function () {
          stopped = true;
        };
      }
      done();
    },
    beforeRemoveClass: function (element, className, done) {
      // Due to transclusion, noTransition property is on parent's scope
      if (className === 'active' && element.parent() && element.parent().parent() &&
          !element.parent().parent().data(NO_TRANSITION)) {
        var stopped = false;
        var direction = element.data(SLIDE_DIRECTION);
        var directionClass = direction == 'next' ? 'left' : 'right';
        var removeClassFn = removeClass.bind(this, element, directionClass, done);

        if ($animateCss) {
          $animateCss(element, {addClass: directionClass})
            .start()
            .done(removeClassFn);
        } else {
          $animate.addClass(element, directionClass).then(function() {
            if (!stopped) {
              removeClassFn();
            }
            done();
          });
        }
        return function() {
          stopped = true;
        };
      }
      done();
    }
  };
}]);

/* deprecated carousel below */

angular.module('ui.bootstrap.carousel')

.value('$carouselSuppressWarning', false)

.directive('carousel', ['$log', '$carouselSuppressWarning', function($log, $carouselSuppressWarning) {
  return {
    restrict: 'EA',
    transclude: true,
    replace: true,
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/carousel.html';
    },
    scope: {
      interval: '=',
      noTransition: '=',
      noPause: '=',
      noWrap: '&'
    },
    link: function() {
      if (!$carouselSuppressWarning) {
        $log.warn('carousel is now deprecated. Use uib-carousel instead.');
      }
    }
  };
}])

.directive('slide', ['$log', '$carouselSuppressWarning', function($log, $carouselSuppressWarning) {
  return {

    restrict: 'EA',
    transclude: true,
    replace: true,
    templateUrl: function(element, attrs) {
      return attrs.templateUrl || 'template/carousel/slide.html';
    },
    scope: {
      active: '=?',
      actual: '=?',
      index: '=?'
    },
    link: function (scope, element, attrs, carouselCtrl) {
      if (!$carouselSuppressWarning) {
        $log.warn('slide is now deprecated. Use uib-slide instead.');
      }
    }
  };
}]);<|endoftext|>


<commit_before>import React, { Component } from 'react';

import Node from './Node'

class TreeSublist extends Component {

    static propTypes = {
        listData:React.PropTypes.array,
        listTitle:React.PropTypes.string,
        filters:React.PropTypes.object,
        filterFieldName:React.PropTypes.string,
        handleChangeSelectedFilter:React.PropTypes.func,
        searchString:React.PropTypes.string
    };

    constructor(props){
        super(props);
        this.state = {
            isOpen:true
        };
    }

    /**
     * Fire when the user presses the +/- icons.
     *
     * @param event e
     */
    handleOpenClose(e){
        let isOpen = true;
        if(this.state.isOpen){
            isOpen = false;
        }
        this.setState({isOpen});
    }

    render() {
        const { listData, listTitle, filters, filterFieldName, handleChangeSelectedFilter, searchString } = this.props;
        const { isOpen } = this.state;

        let sublist = [];

        listData.map(function(itemName){
            const safeName = itemName.toLowerCase();

            const node = <Node key={itemName}
                               handleChangeSelectedFilter={handleChangeSelectedFilter}
                               filterFieldName={filterFieldName}
                               filters={filters}
                               searchString={searchString}
                               itemName={itemName}
                            />;

            if( searchString !=="" && safeName.includes(searchString)){
                sublist.push(node);
            } else if (searchString===""){
                sublist.push(node);
            }

        });

        let iconClasses = "fa fa-plus-circle khb-treelist-icon";
        let sublistContent = "";
        if(isOpen){
            iconClasses = "fa fa-minus-circle khb-treelist-icon";
            sublistContent = sublist;
        }

        return (

                     {listTitle}

                    {sublistContent}

        );
    }
}

export default TreeSublist;<commit_msg>Migrated PropTypes to prop-types.<commit_after>import React, { Component } from 'react';
import PropTypes from "prop-types";

import Node from './Node'

class TreeSublist extends Component {

    static propTypes = {
        listData: PropTypes.array,
        listTitle: PropTypes.string,
        filters: PropTypes.object,
        filterFieldName: PropTypes.string,
        handleChangeSelectedFilter: PropTypes.func,
        searchString: PropTypes.string
    };

    constructor(props){
        super(props);
        this.state = {
            isOpen:true
        };
    }

    /**
     * Fire when the user presses the +/- icons.
     *
     * @param event e
     */
    handleOpenClose(e){
        let isOpen = true;
        if(this.state.isOpen){
            isOpen = false;
        }
        this.setState({isOpen});
    }

    render() {
        const { listData, listTitle, filters, filterFieldName, handleChangeSelectedFilter, searchString } = this.props;
        const { isOpen } = this.state;

        let sublist = [];

        listData.map(function(itemName){
            const safeName = itemName.toLowerCase();

            const node = <Node key={itemName}
                               handleChangeSelectedFilter={handleChangeSelectedFilter}
                               filterFieldName={filterFieldName}
                               filters={filters}
                               searchString={searchString}
                               itemName={itemName}
                            />;

            if( searchString !=="" && safeName.includes(searchString)){
                sublist.push(node);
            } else if (searchString===""){
                sublist.push(node);
            }

        });

        let iconClasses = "fa fa-plus-circle khb-treelist-icon";
        let sublistContent = "";
        if(isOpen){
            iconClasses = "fa fa-minus-circle khb-treelist-icon";
            sublistContent = sublist;
        }

        return (

                     {listTitle}

                    {sublistContent}

        );
    }
}

export default TreeSublist;<|endoftext|>


<commit_before>(function() {
  var colors = {
    'ORANGE': {
      colour: 'rgb(255,144,47)',
      secondary_colour: ['LIGHT BLUE', 'DARK BLUE'],
      index: 8
    },
    'LIGHT BLUE': {
      colour: 'rgb(51,151,197)',
      secondary_colour: ['YELLOW', 'RED'],
      index: 4
    },
    'DARK BLUE': {
      colour: 'rgb(59,54,182)',
      secondary_colour: ['ORANGE', 'YELLOW'],
      index: 3
    },
    'GREEN': {
      colour: 'rgb(83,119,48)',
      secondary_colour: ['PINK', 'PURPLE'],
      index: 5
    },
    'YELLOW': {
      colour: 'rgb(219,217,37)',
      secondary_colour: ['LIGHT BLUE', 'PURPLE'],
      index: 6
    },
    'BLACK': {
      colour: 'rgb(25,25,25)',
      secondary_colour: ['ORANGE', 'PINK', 'LIGHT BLUE', 'GREEN', 'RED'],
      index: 10
    },
    'PINK': {
      colour: 'rgb(206,51,122)',
      secondary_colour: ['LIGHT BLUE', 'ORANGE'],
      index: 1
    },
    'WHITE': {
      colour: 'rgb(200,200,200)',
      secondary_colour: ['PINK', 'LIGHT BLUE', 'ORANGE', 'RED', 'GREEN'],
      index: 9
    },
    'BROWN': {
      colour: 'rgb(142,107,68)',
      secondary_colour: ['DARK BLUE', 'PINK'],
      index: 7
    },
    'PURPLE': {
      colour: 'rgb(113,52,165)',
      secondary_colour: ['YELLOW', 'GREEN'],
      index: 2
    },
    'RED': {
      colour: 'rgb(210,50,44)',
      secondary_colour: ['GREEN', 'LIGHT BLUE'],
      index: 0
    }
  };
  var colorNames = Object.keys(colors)

  var parseRgb = function(string) {
    return string.replace('rgb(', '').replace(')', '').split(',').map(function(s) {return parseInt(s, 10)})
  }

  var componentFromHue = function(m1, m2, h) {
    h = ((h % 1) + 1) % 1;
    if (h*6 < 1) {
      return m1 + (m2-m1) * h*6;
    }
    if (h*2 < 1) {
      return m2;
    }
    if (h*3 < 2) {
      return m1 + (m2-m1) * (2/3 - h) * 6;
    }
    return m1;
  }

  var rgbFromHsl = function(h, s, l) {
    var m2;
    if (l < 0.5) {
      m2 = l * (s+1);
    } else {
      m2 = l + s - l*s;
    }
    var m1 = l*2 - m2;
    return {
      r: componentFromHue(m1, m2, h + 1/3),
      g: componentFromHue(m1, m2, h),
      b: componentFromHue(m1, m2, h - 1/3)
    };
  }

  var hslFromRgb = function(r, g, b) {
    var m = Math.min(r, g, b)
    var M = Math.max(r, g, b)
    var l = (M+m)/2
    var c = M - m
    var s
    if (l <= 0.0) {
      s = 0
    } else if (l <= 0.5) {
      s = c/(2*l)
    } else {
      s = c/(2 - 2*l)
    }
    var h = 0
    if (c == 0) {
      h = 0
    } else if (M == r) {
      h = ((g - b) / c)
    } else if (M == g) {
      h = ((b - r) / c) + 2
    } else if (M == b) {
      h = ((r - g) / c) + 4
    }
    h = ((h/6) + 1) % 1;

    return {
      h: h,
      s: s,
      l: l
    }
  }

  function hueReplace(from, to, primary, secondary) {
    primary = hslFromRgb(primary[0]/255, primary[1]/255, primary[2]/255)
    secondary = hslFromRgb(secondary[0]/255, secondary[1]/255, secondary[2]/255)
    var canvas = document.createElement("canvas");
    //canvas.width = from.naturalWidth
    //canvas.height = from.naturalHeight
    canvas.width = from.offsetWidth
    canvas.height = from.offsetHeight

    var ctx = canvas.getContext("2d");
    ctx.drawImage(from, 0, 0, canvas.width, canvas.height);

    var map = ctx.getImageData(0, 0, canvas.width, canvas.height)
    var data = map.data;

    var r, g, b
    var hsl, rgb
    var hues = {}
    for(var i = 0, len = data.length;i < len;i += 4) {
      r = data[i]/255
      g = data[i+1]/255
      b = data[i+2]/255
      // alpha channel (p+3) is ignored

      hsl = hslFromRgb(r, g, b)
      if (hsl.h > 0.50 && hsl.h < 0.70) {
        hues[hsl.h] = (hues[hsl.h] || 0) + 1
        if (i % 1000 == 0) {
          console.log('primary', r*255, g*255, b*255, hsl)
        }
        hsl.h = primary.h
        if (hsl.s > 0.1) {
          hsl.s = primary.s
        }
      } else if (hsl.h > 0.05 && hsl.h < 0.18) {
        hues[hsl.h] = (hues[hsl.h] || 0) + 1
        if (i % 1000 == 0) {
          console.log('secondary', r*255, g*255, b*255, hsl)
        }
        hsl.h = secondary.h
        if (hsl.s > 0.1) {
          hsl.s = secondary.s
        }
      }
      rgb = rgbFromHsl(hsl.h, hsl.s, hsl.l)
      if (i % 1000 == 0) {
        //console.log(r, g, b, hsl, rgb)
      }

      data[i] = rgb.r*255
      data[i+1] = rgb.g*255
      data[i+2] = rgb.b*255
      //data[i] = hsl.l*255
      //data[i+1] = hsl.l*255
      //data[i+2] = hsl.l*255
    }

    ctx.putImageData(map,0,0);

    to.src = canvas.toDataURL();
    console.log(hues)
  }

  var baseBlue = [58, 119, 174]
  var baseYellow = [255, 200, 2]

  var $commander = $('[data-bind="visible: true, attr: {src: commanderImg}"]')
  var $clone = $commander.clone()
  $commander.hide()
  $commander.after($clone)
  var colorize = function() {
    var main = colors[colorNames[Math.floor(Math.random() * 11)]]
    var primary = parseRgb(main.colour)
    var choices = main.secondary_colour
    var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

    $commander.off('load', colorize)
    var canvas = hueReplace(
      $commander[0],
      $clone[0],
      primary
      ,
      secondary
    );
    //setTimeout(colorize, 1000)
  }
  $commander.on('load', colorize)

  window.rgbFromHsl = rgbFromHsl
  window.hslFromRgb = hslFromRgb
})()
<commit_msg>adjust lightness to handle black and white<commit_after>(function() {
  var colors = {
    'ORANGE': {
      colour: 'rgb(255,144,47)',
      secondary_colour: ['LIGHT BLUE', 'DARK BLUE'],
      index: 8
    },
    'LIGHT BLUE': {
      colour: 'rgb(51,151,197)',
      secondary_colour: ['YELLOW', 'RED'],
      index: 4
    },
    'DARK BLUE': {
      colour: 'rgb(59,54,182)',
      secondary_colour: ['ORANGE', 'YELLOW'],
      index: 3
    },
    'GREEN': {
      colour: 'rgb(83,119,48)',
      secondary_colour: ['PINK', 'PURPLE'],
      index: 5
    },
    'YELLOW': {
      colour: 'rgb(219,217,37)',
      secondary_colour: ['LIGHT BLUE', 'PURPLE'],
      index: 6
    },
    'BLACK': {
      colour: 'rgb(25,25,25)',
      secondary_colour: ['ORANGE', 'PINK', 'LIGHT BLUE', 'GREEN', 'RED'],
      index: 10
    },
    'PINK': {
      colour: 'rgb(206,51,122)',
      secondary_colour: ['LIGHT BLUE', 'ORANGE'],
      index: 1
    },
    'WHITE': {
      colour: 'rgb(200,200,200)',
      secondary_colour: ['PINK', 'LIGHT BLUE', 'ORANGE', 'RED', 'GREEN'],
      index: 9
    },
    'BROWN': {
      colour: 'rgb(142,107,68)',
      secondary_colour: ['DARK BLUE', 'PINK'],
      index: 7
    },
    'PURPLE': {
      colour: 'rgb(113,52,165)',
      secondary_colour: ['YELLOW', 'GREEN'],
      index: 2
    },
    'RED': {
      colour: 'rgb(210,50,44)',
      secondary_colour: ['GREEN', 'LIGHT BLUE'],
      index: 0
    }
  };
  var colorNames = Object.keys(colors)

  var parseRgb = function(string) {
    return string.replace('rgb(', '').replace(')', '').split(',').map(function(s) {return parseInt(s, 10)})
  }

  var componentFromHue = function(m1, m2, h) {
    h = ((h % 1) + 1) % 1;
    if (h*6 < 1) {
      return m1 + (m2-m1) * h*6;
    }
    if (h*2 < 1) {
      return m2;
    }
    if (h*3 < 2) {
      return m1 + (m2-m1) * (2/3 - h) * 6;
    }
    return m1;
  }

  var rgbFromHsl = function(h, s, l) {
    var m2;
    if (l < 0.5) {
      m2 = l * (s+1);
    } else {
      m2 = l + s - l*s;
    }
    var m1 = l*2 - m2;
    return {
      r: componentFromHue(m1, m2, h + 1/3),
      g: componentFromHue(m1, m2, h),
      b: componentFromHue(m1, m2, h - 1/3)
    };
  }

  var hslFromRgb = function(r, g, b) {
    var m = Math.min(r, g, b)
    var M = Math.max(r, g, b)
    var l = (M+m)/2
    var c = M - m
    var s
    if (l <= 0.0) {
      s = 0
    } else if (l <= 0.5) {
      s = c/(2*l)
    } else {
      s = c/(2 - 2*l)
    }
    var h = 0
    if (c == 0) {
      h = 0
    } else if (M == r) {
      h = ((g - b) / c)
    } else if (M == g) {
      h = ((b - r) / c) + 2
    } else if (M == b) {
      h = ((r - g) / c) + 4
    }
    h = ((h/6) + 1) % 1;

    return {
      h: h,
      s: s,
      l: l
    }
  }

  function hueReplace(from, to, primary, secondary) {
    primary = hslFromRgb(primary[0]/255, primary[1]/255, primary[2]/255)
    secondary = hslFromRgb(secondary[0]/255, secondary[1]/255, secondary[2]/255)

    var canvas = document.createElement("canvas");
    canvas.width = from.offsetWidth
    canvas.height = from.offsetHeight

    var ctx = canvas.getContext("2d");
    ctx.drawImage(from, 0, 0, canvas.width, canvas.height);

    var map = ctx.getImageData(0, 0, canvas.width, canvas.height)
    var data = map.data;

    var r, g, b
    var hsl, rgb
    for(var i = 0, len = data.length;i < len;i += 4) {
      r = data[i]/255
      g = data[i+1]/255
      b = data[i+2]/255
      // alpha channel (p+3) is ignored

      hsl = hslFromRgb(r, g, b)
      if (hsl.h > 0.40 && hsl.h < 0.70) {
        hsl.h = primary.h
        if (hsl.s > 0.1) {
          hsl.s = primary.s
          hsl.l = primary.l*Math.sqrt(hsl.l) + (1-primary.l)*Math.pow(hsl.l, 2)
        }
      } else if (hsl.h > 0.05 && hsl.h < 0.18) {
        hsl.h = secondary.h
        if (hsl.s > 0.2) {
          hsl.s = secondary.s
          hsl.l = primary.l*Math.sqrt(hsl.l) + (1-primary.l)*Math.pow(hsl.l, 2)
        }
      }
      rgb = rgbFromHsl(hsl.h, hsl.s, hsl.l)

      data[i] = rgb.r*255
      data[i+1] = rgb.g*255
      data[i+2] = rgb.b*255
      //data[i] = hsl.l*255
      //data[i+1] = hsl.l*255
      //data[i+2] = hsl.l*255
    }

    ctx.putImageData(map,0,0);

    to.src = canvas.toDataURL();
  }

  var baseBlue = [58, 119, 174]
  var baseYellow = [255, 200, 2]

  var $commander = $('[data-bind="visible: true, attr: {src: commanderImg}"]')
  var $clone = $commander.clone()
  $commander.hide()
  $commander.after($clone)
  var colorize = function() {
    var main = colors[colorNames[Math.floor(Math.random() * 11)]]
    //var main = colors['BLACK']
    var primary = parseRgb(main.colour)
    var choices = main.secondary_colour
    var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

    $commander.off('load', colorize)
    var canvas = hueReplace(
      $commander[0],
      $clone[0],
      primary
      ,
      secondary
    );
    //setTimeout(colorize, 1000)
  }
  $commander.on('load', colorize)

  window.rgbFromHsl = rgbFromHsl
  window.hslFromRgb = hslFromRgb
})()
<|endoftext|>


<commit_before>import _ from 'lodash';
import Entity from './Entity';

class Accounts {

  /**
   * @param {Account[]} accounts
   */
  constructor(accounts) {
    this._accounts = accounts;
  }

  /**
   * @param {Object[]} accountObjects
   * @return {Accounts}
   */
  static fromObjects(accountObjects) {
    const accounts = _.isEmpty(accountObjects)
      ? [Account.dummy]
      : accountObjects.map(obj => Account.fromObject(obj));
    return new Accounts(accounts);
  }

  /**
   * @returns {Account|undefined}
   */
  get primary() {
    return _.chain(this._accounts)
      .filter(account => account.isPrimary)
      .head()
      .value();
  }

  /**
   * @returns {Account[] | []}
   */
  get subAccounts() {
    return _.reject(this._accounts, (a) => a.isPrimary);
  }

  /**
   * @return {Account[]}
   */
  get asArray() {
    return this._accounts;
  }

  /**
   * @returns {boolean}
   */
  get isEmpty() {
    return _.isEmpty(this._accounts) || (this._accounts.length == 1 && this._accounts[0].isDummy);
  }

}

const dummyAccountObject = {
  created_at: null,
  credential: null,
  followers_count: null,
  friends_count: null,
  id_str: null,
  name: null,
  profile_image_url: null,
  protected: null,
  screen_name: null,
  statuses_count: null,
  is_initial_state: true,
  is_primary: true
};

class Account extends Entity {

  /**
   * @param {Object} object
   */
  constructor(object) {
    super(object.id_str);
    this._object = object;
  }

  /**
   * @param {Object} userObject
   * @return {Account}
   */
  static fromObject(userObject) {
    return new Account(userObject);
  }

  /**
   * @return {Account}
   */
  static get dummy() {
    return new Account(dummyAccountObject);
  }

  /**
   * @return {string}
   */
  get id() {
    return this._object.id_str;
  }

  /**
   * @returns {Credential}
   */
  get credential() {
    return this._object.credential;
  }

  /**
   * @return {boolean}
   */
  get isPrimary() {
    return this._object.is_primary;
  }

  /**
   * @return {boolean}
   */
  get isDummy() {
    return this._object.id_str == null;
  }

  /**
   * @return {string}
   */
  get profileImageUrl() {
    return this._object.profile_image_url;
  }

  /**
   * @return {string}
   */
  get screenName() {
    return this._object.screen_name;
  }

  /**
   * @return {number}
   */
  get tweetCount() {
    return this._object.statuses_count;
  }

  /**
   * @return {number}
   */
  get followersCount() {
    return this._object.followers_count;
  }

  /**
   * @return {number}
   */
  get followingCount() {
    return this._object.friends_count;
  }
}

export { Accounts, Account };
<commit_msg>[Refactor] Short code<commit_after>import _ from 'lodash';
import Entity from './Entity';

class Accounts {

  /**
   * @param {Account[]} accounts
   */
  constructor(accounts) {
    this._accounts = accounts;
  }

  /**
   * @param {Object[]} accountObjects
   * @return {Accounts}
   */
  static fromObjects(accountObjects) {
    const accounts = _.isEmpty(accountObjects)
      ? [Account.dummy]
      : accountObjects.map(Account.fromObject);
    return new Accounts(accounts);
  }

  /**
   * @returns {Account|undefined}
   */
  get primary() {
    return _.chain(this._accounts)
      .filter(account => account.isPrimary)
      .head()
      .value();
  }

  /**
   * @returns {Account[] | []}
   */
  get subAccounts() {
    return _.reject(this._accounts, (a) => a.isPrimary);
  }

  /**
   * @return {Account[]}
   */
  get asArray() {
    return this._accounts;
  }

  /**
   * @returns {boolean}
   */
  get isEmpty() {
    return _.isEmpty(this._accounts) || (this._accounts.length == 1 && this._accounts[0].isDummy);
  }

}

const dummyAccountObject = {
  created_at: null,
  credential: null,
  followers_count: null,
  friends_count: null,
  id_str: null,
  name: null,
  profile_image_url: null,
  protected: null,
  screen_name: null,
  statuses_count: null,
  is_initial_state: true,
  is_primary: true
};

class Account extends Entity {

  /**
   * @param {Object} object
   */
  constructor(object) {
    super(object.id_str);
    this._object = object;
  }

  /**
   * @param {Object} userObject
   * @return {Account}
   */
  static fromObject(userObject) {
    return new Account(userObject);
  }

  /**
   * @return {Account}
   */
  static get dummy() {
    return new Account(dummyAccountObject);
  }

  /**
   * @return {string}
   */
  get id() {
    return this._object.id_str;
  }

  /**
   * @returns {Credential}
   */
  get credential() {
    return this._object.credential;
  }

  /**
   * @return {boolean}
   */
  get isPrimary() {
    return this._object.is_primary;
  }

  /**
   * @return {boolean}
   */
  get isDummy() {
    return this._object.id_str == null;
  }

  /**
   * @return {string}
   */
  get profileImageUrl() {
    return this._object.profile_image_url;
  }

  /**
   * @return {string}
   */
  get screenName() {
    return this._object.screen_name;
  }

  /**
   * @return {number}
   */
  get tweetCount() {
    return this._object.statuses_count;
  }

  /**
   * @return {number}
   */
  get followersCount() {
    return this._object.followers_count;
  }

  /**
   * @return {number}
   */
  get followingCount() {
    return this._object.friends_count;
  }
}

export { Accounts, Account };
<|endoftext|>


<commit_before>(function($) {
    "use strict";

    function nvl(val) {
        return val || '';
    }

    var FullNameSuggestions = {
        init: function($options) {

            var self = this;
            self.$surname = $options.surname;
            self.$name = $options.name;
            var fioParts = ["SURNAME", ["NAME", "PATRONYMIC"]];

            $.each([$options.surname, $options.name], function(index, $el) {
                $el.suggestions({
                    serviceUrl: "https://dadata.ru/api/v2",
                    token: $options.token,
                    type: "NAME",
                    triggerSelectOnSpace: ($options.correction == "1"),
                    useDadata: false,
                    hint: "",
                    count: $options.tips,
                    noCache: true,
                    params: {
                        // каждому полю --- соответствующая подсказка
                        parts: [fioParts[index]]
                    },

                    onSearchStart: function(params) {
                        // если пол известен на основании других полей,
                        // используем его
                        var $el = $(this);
                        params.gender = self.isGenderKnown($el) ? self.gender : "UNKNOWN";
                        if (index == 1) {
                            $(".dadata-gender").remove();
                        }
                    },

                    onSelect: function(suggestion) {
                        // определяем пол по выбранной подсказке
                        self.gender = suggestion.data.gender;
                        if ($options.view_gender == "1") {
                            var gender = self.gender === "MALE" ? "Мужской" :
                                         self.gender === "FEMALE" ? "Женский" :
                                         "Неизвестный";
                            if (index == 1) {
                                $(this).next('.suggestions-wrapper').after(
                                    'Пол: ' + gender + '
'
                                );
                            }
                        }
                    }
                });
            });
        },

        isGenderKnown: function($el) {
            var self = this,
                surname = self.$surname.val(),
                name = self.$name.val(),
                nameUnknown = $el.attr('id') == self.$surname.attr('id') && !name,
                surnameUnknown = $el.attr('id') == self.$name.attr('id') && !surname;
            return !(nameUnknown || surnameUnknown);
        }
    };

    var FullAddressSuggestions = {

        init: function($options) {
            var self = this;
            self.$address = $options.address;

            // инициализируем подсказки на всех трех текстовых полях
            // (фамилия, имя, отчество)
            $.each([$options.address], function(index, $el) {
                self.initSuggestions($el, $options);
            });
        },

        initSuggestions: function($el, $options) {
            var self = this;
            $el.suggestions({
                serviceUrl: "https://dadata.ru/api/v2",
                token: $options.token,
                type: "ADDRESS",
                triggerSelectOnSpace: ($options.correction == '1'),
                count: $options.tips,

                onSearchStart: function(params) {
                    $('.dadata-additional').remove();
                },

                onSelect: function(suggestion) {
                    if (!suggestion.data) {
                        return;
                    }
                    $('.dadata-additional').remove();
                    var address = suggestion.data;
                    if ($options.additional == '1') {
                        $(this).next('.suggestions-wrapper').after(
                            self.getAdditional(address)
                        );
                    }
                    $("input[name=\'postcode\']").val(
                        nvl(address.postal_code)
                    );
                    $("input[name='city']").val(
                        self.getCity(address)
                    );
                    $("input[name=\'address_1\']").val(
                        self.getStreetAddress(address)
                    );
                    if (address.region) {
                        self.selectRegion(address, $("select[name='zone_id']"));
                    }
                }

            });
        },

        getCity: function(address) {
            var city = '';
            // города-регионы пишем в город
            if (address.city === null && address.settlement === null && address.area === null) {
                city = address.region_type + '. ' + address.region;
            // район + город + населенный пункт
            } else {
                if (address.area) {
                    city += address.area_type + ' ' + address.area;
                }
                if (address.city) {
                    city += (city ? ', ' : '') + address.city_type + ' ' + address.city;
                }
                if (address.settlement) {
                    city += (city ? ', ' : '') + address.settlement_type + ' ' + address.settlement;
                }
            }
            return city;
        },

        getStreetAddress: function(address) {
            // улица + дом + квартира
            var address_1 = '';
            if (address.street_type && address.street) {
                address_1 += address.street_type + ' ' + address.street;
            }
            if(address.house_type != null && address.house != null) {
                address_1 += (address_1 ? ', ' : '') + address.house_type + ' ' + address.house;
            }
            if(address.flat_type != null && address.flat != null) {
                address_1 += (address_1 ? ', ' : '') + address.flat_type + ' ' + address.flat;
            }
            return address_1;
        },

        getAdditional: function(address) {
            return 'Код КЛАДР: ' + nvl(address.kladr_id) +
                    '
 Код ОКАТО: ' + nvl(address.okato) +
                    '
Код ОКТМО: ' + nvl(address.oktmo) +
                    '
Код ИФНС: ' + nvl(address.ifns) + '
';
        },

        selectRegion: function(address, $el) {
            $el.children("option").each(function() {
                if (this.text.indexOf(address.region) !== -1) {
                    $(this).attr("selected", "selected")
                }
            });
        }

    };

    window.FullNameSuggestions = FullNameSuggestions;
    window.FullAddressSuggestions = FullAddressSuggestions;
})(jQuery);<commit_msg>Suggest both name and patronymic in firstname field<commit_after>(function($) {
    "use strict";

    function nvl(val) {
        return val || '';
    }

    var FullNameSuggestions = {
        init: function($options) {

            var self = this;
            self.$surname = $options.surname;
            self.$name = $options.name;
            var fioParts = [["SURNAME"], ["NAME", "PATRONYMIC"]];

            $.each([$options.surname, $options.name], function(index, $el) {
                $el.suggestions({
                    serviceUrl: "https://dadata.ru/api/v2",
                    token: $options.token,
                    type: "NAME",
                    triggerSelectOnSpace: ($options.correction == "1"),
                    useDadata: false,
                    hint: "",
                    count: $options.tips,
                    noCache: true,
                    params: {
                        // каждому полю --- соответствующая подсказка
                        parts: fioParts[index]
                    },

                    onSearchStart: function(params) {
                        // если пол известен на основании других полей,
                        // используем его
                        var $el = $(this);
                        params.gender = self.isGenderKnown($el) ? self.gender : "UNKNOWN";
                        if (index == 1) {
                            $(".dadata-gender").remove();
                        }
                    },

                    onSelect: function(suggestion) {
                        // определяем пол по выбранной подсказке
                        self.gender = suggestion.data.gender;
                        if ($options.view_gender == "1") {
                            var gender = self.gender === "MALE" ? "Мужской" :
                                         self.gender === "FEMALE" ? "Женский" :
                                         "Неизвестный";
                            if (index == 1) {
                                $(this).next('.suggestions-wrapper').after(
                                    'Пол: ' + gender + '
'
                                );
                            }
                        }
                    }
                });
            });
        },

        isGenderKnown: function($el) {
            var self = this,
                surname = self.$surname.val(),
                name = self.$name.val(),
                nameUnknown = $el.attr('id') == self.$surname.attr('id') && !name,
                surnameUnknown = $el.attr('id') == self.$name.attr('id') && !surname;
            return !(nameUnknown || surnameUnknown);
        }
    };

    var FullAddressSuggestions = {

        init: function($options) {
            var self = this;
            self.$address = $options.address;

            // инициализируем подсказки на всех трех текстовых полях
            // (фамилия, имя, отчество)
            $.each([$options.address], function(index, $el) {
                self.initSuggestions($el, $options);
            });
        },

        initSuggestions: function($el, $options) {
            var self = this;
            $el.suggestions({
                serviceUrl: "https://dadata.ru/api/v2",
                token: $options.token,
                type: "ADDRESS",
                triggerSelectOnSpace: ($options.correction == '1'),
                count: $options.tips,

                onSearchStart: function(params) {
                    $('.dadata-additional').remove();
                },

                onSelect: function(suggestion) {
                    if (!suggestion.data) {
                        return;
                    }
                    $('.dadata-additional').remove();
                    var address = suggestion.data;
                    if ($options.additional == '1') {
                        $(this).next('.suggestions-wrapper').after(
                            self.getAdditional(address)
                        );
                    }
                    $("input[name=\'postcode\']").val(
                        nvl(address.postal_code)
                    );
                    $("input[name='city']").val(
                        self.getCity(address)
                    );
                    $("input[name=\'address_1\']").val(
                        self.getStreetAddress(address)
                    );
                    if (address.region) {
                        self.selectRegion(address, $("select[name='zone_id']"));
                    }
                }

            });
        },

        getCity: function(address) {
            var city = '';
            // города-регионы пишем в город
            if (address.city === null && address.settlement === null && address.area === null) {
                city = address.region_type + '. ' + address.region;
            // район + город + населенный пункт
            } else {
                if (address.area) {
                    city += address.area_type + ' ' + address.area;
                }
                if (address.city) {
                    city += (city ? ', ' : '') + address.city_type + ' ' + address.city;
                }
                if (address.settlement) {
                    city += (city ? ', ' : '') + address.settlement_type + ' ' + address.settlement;
                }
            }
            return city;
        },

        getStreetAddress: function(address) {
            // улица + дом + квартира
            var address_1 = '';
            if (address.street_type && address.street) {
                address_1 += address.street_type + ' ' + address.street;
            }
            if(address.house_type != null && address.house != null) {
                address_1 += (address_1 ? ', ' : '') + address.house_type + ' ' + address.house;
            }
            if(address.flat_type != null && address.flat != null) {
                address_1 += (address_1 ? ', ' : '') + address.flat_type + ' ' + address.flat;
            }
            return address_1;
        },

        getAdditional: function(address) {
            return 'Код КЛАДР: ' + nvl(address.kladr_id) +
                    '
 Код ОКАТО: ' + nvl(address.okato) +
                    '
Код ОКТМО: ' + nvl(address.oktmo) +
                    '
Код ИФНС: ' + nvl(address.ifns) + '
';
        },

        selectRegion: function(address, $el) {
            $el.children("option").each(function() {
                if (this.text.indexOf(address.region) !== -1) {
                    $(this).attr("selected", "selected")
                }
            });
        }

    };

    window.FullNameSuggestions = FullNameSuggestions;
    window.FullAddressSuggestions = FullAddressSuggestions;
})(jQuery);<|endoftext|>


<commit_before>import { bindable, bindingMode, customElement, inject } from 'aurelia-framework';
import { AttributeManager } from '../common/attributeManager';
import { getBooleanFromAttributeValue } from '../common/attributes';

@customElement('md-checkbox')
@inject(Element)
export class MdCheckbox {
  static id = 0;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) mdChecked;
  @bindable() mdDisabled;
  @bindable() mdFilledIn;

  constructor(element) {
    this.element = element;
    this.controlId = `md-checkbox-${MdCheckbox.id++}`;
    this.handleChange = this.handleChange.bind(this);
  }

  attached() {
    this.attributeManager = new AttributeManager(this.checkbox);
    if (getBooleanFromAttributeValue(this.mdFilledIn)) {
      this.attributeManager.addClasses('filled-in');
    }
    if (this.mdChecked === null) {
      this.checkbox.indeterminate = true;
    } else {
      this.checkbox.indeterminate = false;
    }
    if (getBooleanFromAttributeValue(this.mdDisabled)) {
      this.checkbox.disabled = true;
    }
    this.checkbox.checked = getBooleanFromAttributeValue(this.mdChecked);
    this.checkbox.addEventListener('change', this.handleChange);
  }

  detached() {
    this.attributeManager.removeClasses(['filled-in', 'disabled']);
    this.checkbox.removeEventListener('change', this.handleChange);
  }

  handleChange() {
    this.mdChecked = this.checkbox.checked;
  }

  mdDisabledChanged(newValue) {
    if (this.checkbox) {
      this.checkbox.disabled = !!newValue;
    }
  }
}
<commit_msg>fix(checkbox): react to viewmodel change<commit_after>import { bindable, bindingMode, customElement, inject } from 'aurelia-framework';
import { AttributeManager } from '../common/attributeManager';
import { getBooleanFromAttributeValue } from '../common/attributes';

@customElement('md-checkbox')
@inject(Element)
export class MdCheckbox {
  static id = 0;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) mdChecked;
  @bindable() mdDisabled;
  @bindable() mdFilledIn;

  constructor(element) {
    this.element = element;
    this.controlId = `md-checkbox-${MdCheckbox.id++}`;
    this.handleChange = this.handleChange.bind(this);
  }

  attached() {
    this.attributeManager = new AttributeManager(this.checkbox);
    if (getBooleanFromAttributeValue(this.mdFilledIn)) {
      this.attributeManager.addClasses('filled-in');
    }
    if (this.mdChecked === null) {
      this.checkbox.indeterminate = true;
    } else {
      this.checkbox.indeterminate = false;
    }
    if (getBooleanFromAttributeValue(this.mdDisabled)) {
      this.checkbox.disabled = true;
    }
    this.checkbox.checked = getBooleanFromAttributeValue(this.mdChecked);
    this.checkbox.addEventListener('change', this.handleChange);
  }

  detached() {
    this.attributeManager.removeClasses(['filled-in', 'disabled']);
    this.checkbox.removeEventListener('change', this.handleChange);
  }

  handleChange() {
    this.mdChecked = this.checkbox.checked;
  }

  mdCheckedChanged(newValue) {
    if (this.checkbox) {
      this.checkbox.checked = !!newValue;
    }
  }

  mdDisabledChanged(newValue) {
    if (this.checkbox) {
      this.checkbox.disabled = !!newValue;
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Background application.
 * Handles initialization and listening for navigation events.
 */

'use strict';

// If running tests, the Chrome API won't be injected to the global scope.
// This block injects the stubbed out chrome in its place so tests can run.
if (!window.chrome) {
  window.chrome = require('../../test/stubs/chrome');
}

// External Dependencies
var _ = require('lodash');

// Internal Dependencies
var Sessions = require('./session-handler');
var Storage =  require('./storage');
var enums =    require('./enums');

module.exports = {

  /**
   * chrome.webNavigation event types to filter for
   */
  triggers: [
    'link',
    'typed',
    'form_submit'
  ],

  /**
   * Initialize the application
   */
  initialize: function() {
    console.log(_.now() + ': WikiMapper started.');
    this.setupListeners();
  },

  /**
   * Ingest navigation events and filter them by event type.
   * @param {object} details - chrome.webNavigation event details
   */
  eventFilter: function(details) {
    if (_.includes(details.transitionQualifiers, 'forward_back')) {
      Sessions.processForwardBack(details);
    } else if (_.includes(this.triggers, details.transitionType)) {
      Sessions.processNavigation(details);
    }

  },

  /**
   * Setup background event listeners.
   */
  setupListeners: function() {
    var self = this;

    // Navigation Event Listeners
    chrome.webNavigation.onCommitted.addListener(function(details) {
      self.eventFilter(details);
    },
      { url: [
        { urlContains: '.wikipedia.org/wiki' },
        { urlContains: '.wiktionary.org/wiki'}
      ]}
    );

    // Listener for incoming messages
    chrome.runtime.onMessage.addListener(function(request, sender) {
      switch(request.type) {
        case (enums.messageTypes.deleteItem): {
          if (request.sessionId) {
            Storage.deleteItem(request.sessionId);
          } else {
            console.error('Received malformed deleteItem message: ' +
                          JSON.stringify(request) + ', ' + JSON.stringify(sender));
          }
          break;
        }

        case (enums.messageTypes.deleteAll): {
          Storage.deleteAll();
        }
      }
    });

    // Listener for when the user clicks on the Wikimapper button
    chrome.browserAction.onClicked.addListener(function() {
      chrome.tabs.create({'url': chrome.extension.getURL('index.html')}, function() {
      });
    });

    // Listener for first install
    chrome.runtime.onInstalled.addListener(function(details) {
      if(details.reason === 'install') {
        chrome.tabs.create({'url': 'index.html'});
      }
    });
  }

};
<commit_msg>Add support for wikiwand URLs. Closes #84.<commit_after>/**
 * Background application.
 * Handles initialization and listening for navigation events.
 */

'use strict';

// If running tests, the Chrome API won't be injected to the global scope.
// This block injects the stubbed out chrome in its place so tests can run.
if (!window.chrome) {
  window.chrome = require('../../test/stubs/chrome');
}

// External Dependencies
var _ = require('lodash');

// Internal Dependencies
var Sessions = require('./session-handler');
var Storage =  require('./storage');
var enums =    require('./enums');

module.exports = {

  /**
   * chrome.webNavigation event types to filter for
   */
  triggers: [
    'link',
    'typed',
    'form_submit'
  ],

  /**
   * Initialize the application
   */
  initialize: function() {
    console.log(_.now() + ': WikiMapper started.');
    this.setupListeners();
  },

  /**
   * Ingest navigation events and filter them by event type.
   * @param {object} details - chrome.webNavigation event details
   */
  eventFilter: function(details) {
    if (_.includes(details.transitionQualifiers, 'forward_back')) {
      Sessions.processForwardBack(details);
    } else if (_.includes(this.triggers, details.transitionType)) {
      Sessions.processNavigation(details);
    }

  },

  /**
   * Setup background event listeners.
   */
  setupListeners: function() {
    var self = this;

    // Navigation Event Listeners
    chrome.webNavigation.onCommitted.addListener(function(details) {
      self.eventFilter(details);
    },
      { url: [
        { urlContains: '.wikipedia.org/wiki' },
        { urlContains: '.wiktionary.org/wiki'},
        { urlMatches: '.wikiwand.com/[A-Za-z]{2}/'}
      ]}
    );

    // Listener for incoming messages
    chrome.runtime.onMessage.addListener(function(request, sender) {
      switch(request.type) {
        case (enums.messageTypes.deleteItem): {
          if (request.sessionId) {
            Storage.deleteItem(request.sessionId);
          } else {
            console.error('Received malformed deleteItem message: ' +
                          JSON.stringify(request) + ', ' + JSON.stringify(sender));
          }
          break;
        }

        case (enums.messageTypes.deleteAll): {
          Storage.deleteAll();
        }
      }
    });

    // Listener for when the user clicks on the Wikimapper button
    chrome.browserAction.onClicked.addListener(function() {
      chrome.tabs.create({'url': chrome.extension.getURL('index.html')}, function() {
      });
    });

    // Listener for first install
    chrome.runtime.onInstalled.addListener(function(details) {
      if(details.reason === 'install') {
        chrome.tabs.create({'url': 'index.html'});
      }
    });
  }

};
<|endoftext|>