<commit_before>(function(angular) {
    'use strict';

    function isDnDsSupported() {
        return 'ondrag' in document.createElement('a');
    }

    function determineEffectAllowed(e) {
        if(e.originalEvent) {
          e.dataTransfer = e.originalEvent.dataTransfer;
        }

        // Chrome doesn't set dropEffect, so we have to work it out ourselves
        if (typeof e.dataTransfer !== 'undefined' && e.dataTransfer.dropEffect === 'none') {
            if (e.dataTransfer.effectAllowed === 'copy' ||
                e.dataTransfer.effectAllowed === 'move') {
                e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed;
            } else if (e.dataTransfer.effectAllowed === 'copyMove' || e.dataTransfer.effectAllowed === 'copymove') {
                e.dataTransfer.dropEffect = e.ctrlKey ? 'copy' : 'move';
            }
        }
    }

    if (!isDnDsSupported()) {
        angular.module('ang-drag-drop', []);
        return;
    }

    var module = angular.module('ang-drag-drop', []);

    module.directive('uiDraggable', ['$parse', '$rootScope', '$dragImage', function($parse, $rootScope, $dragImage) {
        return function(scope, element, attrs) {
            var isDragHandleUsed = false,
                dragHandleClass,
                draggingClass = attrs.draggingClass || 'on-dragging',
                dragTarget;

            element.attr('draggable', false);

            scope.$watch(attrs.uiDraggable, function(newValue) {
                if (newValue) {
                    element.attr('draggable', newValue);
                    element.bind('dragend', dragendHandler);
                    element.bind('dragstart', dragstartHandler);
                }
                else {
                    element.removeAttr('draggable');
                    element.unbind('dragend', dragendHandler);
                    element.unbind('dragstart', dragstartHandler);
                }

            });

            if (angular.isString(attrs.dragHandleClass)) {
                isDragHandleUsed = true;
                dragHandleClass = attrs.dragHandleClass.trim() || 'drag-handle';

                element.bind('mousedown', function(e) {
                    dragTarget = e.target;
                });
            }

            function dragendHandler(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                setTimeout(function() {
                    element.unbind('$destroy', dragendHandler);
                }, 0);
                var sendChannel = attrs.dragChannel || 'defaultchannel';
                $rootScope.$broadcast('ANGULAR_DRAG_END', e, sendChannel);

                determineEffectAllowed(e);

                if (e.dataTransfer && e.dataTransfer.dropEffect !== 'none') {
                    if (attrs.onDropSuccess) {
                        var onDropSuccessFn = $parse(attrs.onDropSuccess);
                        scope.$evalAsync(function() {
                            onDropSuccessFn(scope, {$event: e});
                        });
                    }
                }else if (e.dataTransfer && e.dataTransfer.dropEffect === 'none'){
                    if (attrs.onDropFailure) {
                        var onDropFailureFn = $parse(attrs.onDropFailure);
                        scope.$evalAsync(function() {
                            onDropFailureFn(scope, {$event: e});
                        });
                    }
                }
                element.removeClass(draggingClass);
            }

            function setDragElement(e, dragImageElementId) {
                var dragImageElementFn;

                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                dragImageElementFn = $parse(dragImageElementId);

                scope.$apply(function() {
                    var elementId = dragImageElementFn(scope, {$event: e}),
                        dragElement;

                    if (!(elementId && angular.isString(elementId))) {
                        return;
                    }

                    dragElement = document.getElementById(elementId);

                    if (!dragElement) {
                        return;
                    }

                    e.dataTransfer.setDragImage(dragElement, 0, 0);
                });
            }

            function dragstartHandler(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                var isDragAllowed = !isDragHandleUsed || dragTarget.classList.contains(dragHandleClass);

                if (isDragAllowed) {
                    var sendChannel = attrs.dragChannel || 'defaultchannel';
                    var dragData = '';
                    if (attrs.drag) {
                        dragData = scope.$eval(attrs.drag);
                    }

                    var dragImage = attrs.dragImage || null;

                    element.addClass(draggingClass);
                    element.bind('$destroy', dragendHandler);

                    //Code to make sure that the setDragImage is available. IE 10, 11, and Opera do not support setDragImage.
                    var hasNativeDraggable = !(document.uniqueID || window.opera);

                    //If there is a draggable image passed in, then set the image to be dragged.
                    if (dragImage && hasNativeDraggable) {
                        var dragImageFn = $parse(attrs.dragImage);
                        scope.$apply(function() {
                            var dragImageParameters = dragImageFn(scope, {$event: e});
                            if (dragImageParameters) {
                                if (angular.isString(dragImageParameters)) {
                                    dragImageParameters = $dragImage.generate(dragImageParameters);
                                }
                                if (dragImageParameters.image) {
                                    var xOffset = dragImageParameters.xOffset || 0,
                                        yOffset = dragImageParameters.yOffset || 0;
                                    e.dataTransfer.setDragImage(dragImageParameters.image, xOffset, yOffset);
                                }
                            }
                        });
                    } else if (attrs.dragImageElementId) {
                        setDragElement(e, attrs.dragImageElementId);
                    }

                    var offset = {x: e.offsetX, y: e.offsetY};
                    var transferDataObject = {data: dragData, channel: sendChannel, offset: offset};
                    var transferDataText = angular.toJson(transferDataObject);

                    e.dataTransfer.setData('text', transferDataText);
                    e.dataTransfer.effectAllowed = 'copyMove';

                    $rootScope.$broadcast('ANGULAR_DRAG_START', e, sendChannel, transferDataObject);
                }
                else {
                    e.preventDefault();
                }
            }
        };
    }
    ]);

    module.directive('uiOnDrop', ['$parse', '$rootScope', function($parse, $rootScope) {
        return function(scope, element, attr) {
            var dragging = 0; //Ref. http://stackoverflow.com/a/10906204
            var dropChannel = attr.dropChannel || 'defaultchannel';
            var dragChannel = '';
            var dragEnterClass = attr.dragEnterClass || 'on-drag-enter';
            var dragHoverClass = attr.dragHoverClass || 'on-drag-hover';
            var customDragEnterEvent = $parse(attr.onDragEnter);
            var customDragLeaveEvent = $parse(attr.onDragLeave);

            function calculateDropOffset(e) {
                var offset = {
                    x: e.offsetX,
                    y: e.offsetY
                };
                var target = e.target;

                while (target !== element[0]) {
                    offset.x = offset.x + target.offsetLeft;
                    offset.y = offset.y + target.offsetTop;

                    target = target.offsetParent;
                    if (!target) {
                        return null;
                    }
                }

                return offset;
            }

            function onDragOver(e) {
                if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                }

                if (e.stopPropagation) {
                    e.stopPropagation();
                }

                var uiOnDragOverFn = $parse(attr.uiOnDragOver);
                scope.$evalAsync(function() {
                    uiOnDragOverFn(scope, {$event: e, $channel: dropChannel});
                });

                return false;
            }

            function onDragLeave(e) {
                if (e.preventDefault) {
                    e.preventDefault();
                }

                if (e.stopPropagation) {
                    e.stopPropagation();
                }
                dragging--;

                if (dragging === 0) {
                    scope.$evalAsync(function() {
                        customDragLeaveEvent(scope, {$event: e, $channel: dropChannel});
                    });
                    element.addClass(dragEnterClass);
                    element.removeClass(dragHoverClass);
                }

                var uiOnDragLeaveFn = $parse(attr.uiOnDragLeave);
                scope.$evalAsync(function() {
                    uiOnDragLeaveFn(scope, {$event: e, $channel: dropChannel});
                });
            }

            function onDragEnter(e) {
                if (e.preventDefault) {
                    e.preventDefault();
                }

                if (e.stopPropagation) {
                    e.stopPropagation();
                }

                if (dragging === 0) {
                    scope.$evalAsync(function() {
                        customDragEnterEvent(scope, {$event: e, $channel: dropChannel});
                    });
                    element.removeClass(dragEnterClass);
                    element.addClass(dragHoverClass);
                }
                dragging++;

                var uiOnDragEnterFn = $parse(attr.uiOnDragEnter);
                scope.$evalAsync(function() {
                    uiOnDragEnterFn(scope, {$event: e, $channel: dropChannel});
                });

                $rootScope.$broadcast('ANGULAR_HOVER', dragChannel);
            }

            function onDrop(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                }
                if (e.stopPropagation) {
                    e.stopPropagation(); // Necessary. Allows us to drop.
                }

                var sendData = e.dataTransfer.getData('text');
                sendData = angular.fromJson(sendData);

                var dropOffset = calculateDropOffset(e);

                var position = dropOffset ? {
                    x: dropOffset.x - sendData.offset.x,
                    y: dropOffset.y - sendData.offset.y
                } : null;

                determineEffectAllowed(e);

                var uiOnDropFn = $parse(attr.uiOnDrop);
                scope.$evalAsync(function() {
                    uiOnDropFn(scope, {$data: sendData.data, $event: e, $channel: sendData.channel, $position: position});
                });
                element.removeClass(dragEnterClass);
                dragging = 0;
            }

            function isDragChannelAccepted(dragChannel, dropChannel) {
                if (dropChannel === '*') {
                    return true;
                }

                var channelMatchPattern = new RegExp('(\\s|[,])+(' + dragChannel + ')(\\s|[,])+', 'i');

                return channelMatchPattern.test(',' + dropChannel + ',');
            }

            function preventNativeDnD(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                if (e.preventDefault) {
                    e.preventDefault();
                }
                if (e.stopPropagation) {
                    e.stopPropagation();
                }
                e.dataTransfer.dropEffect = 'none';
                return false;
            }

            var deregisterDragStart = $rootScope.$on('ANGULAR_DRAG_START', function(_, e, channel, transferDataObject) {
                dragChannel = channel;

                var valid = true;

                if (!isDragChannelAccepted(channel, dropChannel)) {
                    valid = false;
                }

                if (valid && attr.dropValidate) {
                    var validateFn = $parse(attr.dropValidate);
                    valid = validateFn(scope, {
                        $drop: {scope: scope, element: element},
                        $event: e,
                        $data: transferDataObject.data,
                        $channel: transferDataObject.channel
                    });
                }

                if (valid) {
                    element.bind('dragover', onDragOver);
                    element.bind('dragenter', onDragEnter);
                    element.bind('dragleave', onDragLeave);
                    element.bind('drop', onDrop);

                    element.addClass(dragEnterClass);
                } else {
                    element.bind('dragover', preventNativeDnD);
                    element.bind('dragenter', preventNativeDnD);
                    element.bind('dragleave', preventNativeDnD);
                    element.bind('drop', preventNativeDnD);

                    element.removeClass(dragEnterClass);
                }

            });

            var deregisterDragEnd = $rootScope.$on('ANGULAR_DRAG_END', function() {
                element.unbind('dragover', onDragOver);
                element.unbind('dragenter', onDragEnter);
                element.unbind('dragleave', onDragLeave);

                element.unbind('drop', onDrop);
                element.removeClass(dragHoverClass);
                element.removeClass(dragEnterClass);

                element.unbind('dragover', preventNativeDnD);
                element.unbind('dragenter', preventNativeDnD);
                element.unbind('dragleave', preventNativeDnD);
                element.unbind('drop', preventNativeDnD);
            });

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

            attr.$observe('dropChannel', function(value) {
                if (value) {
                    dropChannel = value;
                }
            });

        };
    }
    ]);

    module.constant('$dragImageConfig', {
        height: 20,
        width: 200,
        padding: 10,
        font: 'bold 11px Arial',
        fontColor: '#eee8d5',
        backgroundColor: '#93a1a1',
        xOffset: 0,
        yOffset: 0
    });

    module.service('$dragImage', ['$dragImageConfig', function(defaultConfig) {
        var ELLIPSIS = '…';

        function fitString(canvas, text, config) {
            var width = canvas.measureText(text).width;
            if (width < config.width) {
                return text;
            }
            while (width + config.padding > config.width) {
                text = text.substring(0, text.length - 1);
                width = canvas.measureText(text + ELLIPSIS).width;
            }
            return text + ELLIPSIS;
        }

        this.generate = function(text, options) {
            var config = angular.extend({}, defaultConfig, options || {});
            var el = document.createElement('canvas');

            el.height = config.height;
            el.width = config.width;

            var canvas = el.getContext('2d');

            canvas.fillStyle = config.backgroundColor;
            canvas.fillRect(0, 0, config.width, config.height);
            canvas.font = config.font;
            canvas.fillStyle = config.fontColor;

            var title = fitString(canvas, text, config);
            canvas.fillText(title, 4, config.padding + 4);

            var image = new Image();
            image.src = el.toDataURL();

            return {
                image: image,
                xOffset: config.xOffset,
                yOffset: config.yOffset
            };
        };
    }
    ]);

}(angular));
<commit_msg>add onDragStart<commit_after>(function(angular) {
    'use strict';

    function isDnDsSupported() {
        return 'ondrag' in document.createElement('a');
    }

    function determineEffectAllowed(e) {
        if(e.originalEvent) {
          e.dataTransfer = e.originalEvent.dataTransfer;
        }

        // Chrome doesn't set dropEffect, so we have to work it out ourselves
        if (typeof e.dataTransfer !== 'undefined' && e.dataTransfer.dropEffect === 'none') {
            if (e.dataTransfer.effectAllowed === 'copy' ||
                e.dataTransfer.effectAllowed === 'move') {
                e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed;
            } else if (e.dataTransfer.effectAllowed === 'copyMove' || e.dataTransfer.effectAllowed === 'copymove') {
                e.dataTransfer.dropEffect = e.ctrlKey ? 'copy' : 'move';
            }
        }
    }

    if (!isDnDsSupported()) {
        angular.module('ang-drag-drop', []);
        return;
    }

    var module = angular.module('ang-drag-drop', []);

    module.directive('uiDraggable', ['$parse', '$rootScope', '$dragImage', function($parse, $rootScope, $dragImage) {
        return function(scope, element, attrs) {
            var isDragHandleUsed = false,
                dragHandleClass,
                draggingClass = attrs.draggingClass || 'on-dragging',
                dragTarget;

            element.attr('draggable', false);

            scope.$watch(attrs.uiDraggable, function(newValue) {
                if (newValue) {
                    element.attr('draggable', newValue);
                    element.bind('dragend', dragendHandler);
                    element.bind('dragstart', dragstartHandler);
                }
                else {
                    element.removeAttr('draggable');
                    element.unbind('dragend', dragendHandler);
                    element.unbind('dragstart', dragstartHandler);
                }

            });

            if (angular.isString(attrs.dragHandleClass)) {
                isDragHandleUsed = true;
                dragHandleClass = attrs.dragHandleClass.trim() || 'drag-handle';

                element.bind('mousedown', function(e) {
                    dragTarget = e.target;
                });
            }

            function dragendHandler(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                setTimeout(function() {
                    element.unbind('$destroy', dragendHandler);
                }, 0);
                var sendChannel = attrs.dragChannel || 'defaultchannel';
                $rootScope.$broadcast('ANGULAR_DRAG_END', e, sendChannel);

                determineEffectAllowed(e);

                if (e.dataTransfer && e.dataTransfer.dropEffect !== 'none') {
                    if (attrs.onDropSuccess) {
                        var onDropSuccessFn = $parse(attrs.onDropSuccess);
                        scope.$evalAsync(function() {
                            onDropSuccessFn(scope, {$event: e});
                        });
                    }
                }else if (e.dataTransfer && e.dataTransfer.dropEffect === 'none'){
                    if (attrs.onDropFailure) {
                        var onDropFailureFn = $parse(attrs.onDropFailure);
                        scope.$evalAsync(function() {
                            onDropFailureFn(scope, {$event: e});
                        });
                    }
                }
                element.removeClass(draggingClass);
            }

            function setDragElement(e, dragImageElementId) {
                var dragImageElementFn;

                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                dragImageElementFn = $parse(dragImageElementId);

                scope.$apply(function() {
                    var elementId = dragImageElementFn(scope, {$event: e}),
                        dragElement;

                    if (!(elementId && angular.isString(elementId))) {
                        return;
                    }

                    dragElement = document.getElementById(elementId);

                    if (!dragElement) {
                        return;
                    }

                    e.dataTransfer.setDragImage(dragElement, 0, 0);
                });
            }

            function dragstartHandler(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                var isDragAllowed = !isDragHandleUsed || dragTarget.classList.contains(dragHandleClass);

                if (isDragAllowed) {
                    var sendChannel = attrs.dragChannel || 'defaultchannel';
                    var dragData = '';
                    if (attrs.drag) {
                        dragData = scope.$eval(attrs.drag);
                    }

                    var dragImage = attrs.dragImage || null;

                    element.addClass(draggingClass);
                    element.bind('$destroy', dragendHandler);

                    //Code to make sure that the setDragImage is available. IE 10, 11, and Opera do not support setDragImage.
                    var hasNativeDraggable = !(document.uniqueID || window.opera);

                    //If there is a draggable image passed in, then set the image to be dragged.
                    if (dragImage && hasNativeDraggable) {
                        var dragImageFn = $parse(attrs.dragImage);
                        scope.$apply(function() {
                            var dragImageParameters = dragImageFn(scope, {$event: e});
                            if (dragImageParameters) {
                                if (angular.isString(dragImageParameters)) {
                                    dragImageParameters = $dragImage.generate(dragImageParameters);
                                }
                                if (dragImageParameters.image) {
                                    var xOffset = dragImageParameters.xOffset || 0,
                                        yOffset = dragImageParameters.yOffset || 0;
                                    e.dataTransfer.setDragImage(dragImageParameters.image, xOffset, yOffset);
                                }
                            }
                        });
                    } else if (attrs.dragImageElementId) {
                        setDragElement(e, attrs.dragImageElementId);
                    }

                    var offset = {x: e.offsetX, y: e.offsetY};
                    var transferDataObject = {data: dragData, channel: sendChannel, offset: offset};
                    var transferDataText = angular.toJson(transferDataObject);

                    e.dataTransfer.setData('text', transferDataText);
                    e.dataTransfer.effectAllowed = 'copyMove';

                    if (attrs.onDragStart) {
                        var onDragStartFn = $parse(attrs.onDragStart);
                        scope.$evalAsync(function () {
                            onDragStartFn(scope, {
                                $event: e
                            });
                        });
                    }

                    $rootScope.$broadcast('ANGULAR_DRAG_START', e, sendChannel, transferDataObject);
                }
                else {
                    e.preventDefault();
                }
            }
        };
    }
    ]);

    module.directive('uiOnDrop', ['$parse', '$rootScope', function($parse, $rootScope) {
        return function(scope, element, attr) {
            var dragging = 0; //Ref. http://stackoverflow.com/a/10906204
            var dropChannel = attr.dropChannel || 'defaultchannel';
            var dragChannel = '';
            var dragEnterClass = attr.dragEnterClass || 'on-drag-enter';
            var dragHoverClass = attr.dragHoverClass || 'on-drag-hover';
            var customDragEnterEvent = $parse(attr.onDragEnter);
            var customDragLeaveEvent = $parse(attr.onDragLeave);

            function calculateDropOffset(e) {
                var offset = {
                    x: e.offsetX,
                    y: e.offsetY
                };
                var target = e.target;

                while (target !== element[0]) {
                    offset.x = offset.x + target.offsetLeft;
                    offset.y = offset.y + target.offsetTop;

                    target = target.offsetParent;
                    if (!target) {
                        return null;
                    }
                }

                return offset;
            }

            function onDragOver(e) {
                if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                }

                if (e.stopPropagation) {
                    e.stopPropagation();
                }

                var uiOnDragOverFn = $parse(attr.uiOnDragOver);
                scope.$evalAsync(function() {
                    uiOnDragOverFn(scope, {$event: e, $channel: dropChannel});
                });

                return false;
            }

            function onDragLeave(e) {
                if (e.preventDefault) {
                    e.preventDefault();
                }

                if (e.stopPropagation) {
                    e.stopPropagation();
                }
                dragging--;

                if (dragging === 0) {
                    scope.$evalAsync(function() {
                        customDragLeaveEvent(scope, {$event: e, $channel: dropChannel});
                    });
                    element.addClass(dragEnterClass);
                    element.removeClass(dragHoverClass);
                }

                var uiOnDragLeaveFn = $parse(attr.uiOnDragLeave);
                scope.$evalAsync(function() {
                    uiOnDragLeaveFn(scope, {$event: e, $channel: dropChannel});
                });
            }

            function onDragEnter(e) {
                if (e.preventDefault) {
                    e.preventDefault();
                }

                if (e.stopPropagation) {
                    e.stopPropagation();
                }

                if (dragging === 0) {
                    scope.$evalAsync(function() {
                        customDragEnterEvent(scope, {$event: e, $channel: dropChannel});
                    });
                    element.removeClass(dragEnterClass);
                    element.addClass(dragHoverClass);
                }
                dragging++;

                var uiOnDragEnterFn = $parse(attr.uiOnDragEnter);
                scope.$evalAsync(function() {
                    uiOnDragEnterFn(scope, {$event: e, $channel: dropChannel});
                });

                $rootScope.$broadcast('ANGULAR_HOVER', dragChannel);
            }

            function onDrop(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                }
                if (e.stopPropagation) {
                    e.stopPropagation(); // Necessary. Allows us to drop.
                }

                var sendData = e.dataTransfer.getData('text');
                sendData = angular.fromJson(sendData);

                var dropOffset = calculateDropOffset(e);

                var position = dropOffset ? {
                    x: dropOffset.x - sendData.offset.x,
                    y: dropOffset.y - sendData.offset.y
                } : null;

                determineEffectAllowed(e);

                var uiOnDropFn = $parse(attr.uiOnDrop);
                scope.$evalAsync(function() {
                    uiOnDropFn(scope, {$data: sendData.data, $event: e, $channel: sendData.channel, $position: position});
                });
                element.removeClass(dragEnterClass);
                dragging = 0;
            }

            function isDragChannelAccepted(dragChannel, dropChannel) {
                if (dropChannel === '*') {
                    return true;
                }

                var channelMatchPattern = new RegExp('(\\s|[,])+(' + dragChannel + ')(\\s|[,])+', 'i');

                return channelMatchPattern.test(',' + dropChannel + ',');
            }

            function preventNativeDnD(e) {
                if(e.originalEvent) {
                  e.dataTransfer = e.originalEvent.dataTransfer;
                }

                if (e.preventDefault) {
                    e.preventDefault();
                }
                if (e.stopPropagation) {
                    e.stopPropagation();
                }
                e.dataTransfer.dropEffect = 'none';
                return false;
            }

            var deregisterDragStart = $rootScope.$on('ANGULAR_DRAG_START', function(_, e, channel, transferDataObject) {
                dragChannel = channel;

                var valid = true;

                if (!isDragChannelAccepted(channel, dropChannel)) {
                    valid = false;
                }

                if (valid && attr.dropValidate) {
                    var validateFn = $parse(attr.dropValidate);
                    valid = validateFn(scope, {
                        $drop: {scope: scope, element: element},
                        $event: e,
                        $data: transferDataObject.data,
                        $channel: transferDataObject.channel
                    });
                }

                if (valid) {
                    element.bind('dragover', onDragOver);
                    element.bind('dragenter', onDragEnter);
                    element.bind('dragleave', onDragLeave);
                    element.bind('drop', onDrop);

                    element.addClass(dragEnterClass);
                } else {
                    element.bind('dragover', preventNativeDnD);
                    element.bind('dragenter', preventNativeDnD);
                    element.bind('dragleave', preventNativeDnD);
                    element.bind('drop', preventNativeDnD);

                    element.removeClass(dragEnterClass);
                }

            });

            var deregisterDragEnd = $rootScope.$on('ANGULAR_DRAG_END', function() {
                element.unbind('dragover', onDragOver);
                element.unbind('dragenter', onDragEnter);
                element.unbind('dragleave', onDragLeave);

                element.unbind('drop', onDrop);
                element.removeClass(dragHoverClass);
                element.removeClass(dragEnterClass);

                element.unbind('dragover', preventNativeDnD);
                element.unbind('dragenter', preventNativeDnD);
                element.unbind('dragleave', preventNativeDnD);
                element.unbind('drop', preventNativeDnD);
            });

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

            attr.$observe('dropChannel', function(value) {
                if (value) {
                    dropChannel = value;
                }
            });

        };
    }
    ]);

    module.constant('$dragImageConfig', {
        height: 20,
        width: 200,
        padding: 10,
        font: 'bold 11px Arial',
        fontColor: '#eee8d5',
        backgroundColor: '#93a1a1',
        xOffset: 0,
        yOffset: 0
    });

    module.service('$dragImage', ['$dragImageConfig', function(defaultConfig) {
        var ELLIPSIS = '…';

        function fitString(canvas, text, config) {
            var width = canvas.measureText(text).width;
            if (width < config.width) {
                return text;
            }
            while (width + config.padding > config.width) {
                text = text.substring(0, text.length - 1);
                width = canvas.measureText(text + ELLIPSIS).width;
            }
            return text + ELLIPSIS;
        }

        this.generate = function(text, options) {
            var config = angular.extend({}, defaultConfig, options || {});
            var el = document.createElement('canvas');

            el.height = config.height;
            el.width = config.width;

            var canvas = el.getContext('2d');

            canvas.fillStyle = config.backgroundColor;
            canvas.fillRect(0, 0, config.width, config.height);
            canvas.font = config.font;
            canvas.fillStyle = config.fontColor;

            var title = fitString(canvas, text, config);
            canvas.fillText(title, 4, config.padding + 4);

            var image = new Image();
            image.src = el.toDataURL();

            return {
                image: image,
                xOffset: config.xOffset,
                yOffset: config.yOffset
            };
        };
    }
    ]);

}(angular));
<|endoftext|>


<commit_before>/*jslint browser: true, devel: true, es5: true, plusplus: false, unparam: true, vars: false */

(function (data, iterations, iframe, document, window, article, button, table) {

    "use strict";

    window.onload = function () {

        if (location.hash !== "") {
            present (json.parse(String.prototype.slice.call(location.hash, 1)));
        }
    }

    // This is a placeholder for the testrunner after it has  binded an
    // eventlistener to the iframe window.
    var testqueue, runner;

    // Return if incompatible with Navigation Timing API

    if(window.performance === undefined) {
        (document.getElementsByTagName('body')[0]).innerHTML = "
Unfortunately," +
            "  your browser does not support the " + "Navigation Timing API.
";
        return;
    }

    // DOM Methods

    function text(string) {
        return document.createTextNode(string);
    }

    function paragraph() {
        var p = document.createElement('p'), i;
        for (i = 0; i < arguments.length; i += 1) {
            if (typeof arguments[i] === "string") {
                p.appendChild(text(arguments[i]));
            }
            else {
                p.appendChild(arguments[i]);
            }
        }
        return p;
    }

    function makeParent(child, typeString) {
        var element = document.createElement(typeString);
        element.appendChild(child);
        return element;
    }

    function appendChildren(element) {
        var i;
        if (arguments.length <= 1) {
            return;
        }

        for (i = 1; i < arguments.length; i += 1) {
            element.appendChild(arguments[i]);
        }

        return element;
    }

    function nodeListToArray(list) {
        var array = [], i;
        for (i = 0; i < list.length; i += 1) {
            array[i] = list[i];
        }
        return array;
    }

    // IE9 does not support forEach, so we define it here.
    // Kudos to StackOverflow user bobince for the standatds-compliant implementation
    if (!Array.prototype.forEach) {
        Array.prototype.forEach = function (fun, that){
            var i, n;
            for (i = 0, n = this.length; i < n; i+= 1) {
                if (this[i] !== undefined) {
                    fun.call(that, this[i], i, this);
                }
            }
        };
    }

    function updateArticle(new_pars){
        var old_pars = nodeListToArray(article.getElementsByTagName('p'));
        old_pars.forEach(function(par){ article.removeChild(par); });
        new_pars.forEach(function(par){ article.appendChild(par); });
    }

    // This function servers as a closure for the actual runner returned to
    // the caller. Helper functions are defined, and an eventlistener is
    // binded to the iframe.

    function createBoundRunner(iframe, window) {

        var counter, // This stores current test number.
            current_test, // This stores the currently running test category (string).
            inner_window = iframe.contentWindow, // Make it easier to access  the iframe's DOM
            finalize, // A placeholder for callback function to be called when testing is complete.
            number_of_tests, // Stores total number of tests
            queue, // The queue of tests
            reporter, // A placeholder for the function(X) used to report 'currently running test X of total'
            result; // A placeholder for the result

        // In order to circumvent Security policies in the browser, we
        // manually set the domain of the iframe to the domain of the
        // parent html.

        inner_window.domain = document.domain;

        // In order to avoid redrawing the article for every iteration,
        // we wrap the article element in a closure and return a function
        // that only replaces the counter text for each iteration.

        function createReport(total_tests){
            var intro = "Running test ",
                countptr = text(""), //A pointer to the text node where we set the currently runing testnumber
                fat_count = makeParent(countptr, 'strong'),
                copula = " of ",
                total = makeParent(text(total_tests), 'strong'),
                period = text("."),
                par = paragraph(intro, fat_count, copula, total, period);

            updateArticle([par]);

            return function(){
                counter += 1;
                countptr.textContent = counter;
            };
        }

        function testNext() {
            reporter();
            current_test = queue.shift();
            iframe.src = "./tests/" + current_test[0]+ "/" + current_test[1] +
                "/index.html";
        }

        function iterate() {
            if (queue.length !== 0) {
                testNext();
            }
            else {
                window.removeEventListener("message", catchMessage, false)
                finalize(result);
            }
        }

        function initializeResultIfEmpty() {

            if (result[current_test[0]] === undefined){
                result[current_test[0]] = {};
            }

            if (result[current_test[0]][current_test[1]] === undefined){
                result[current_test[0]][current_test[1]] = [];
            }
        }

        function catchMessage(message) {
            initializeResultIfEmpty();
            result[current_test[0]][current_test[1]].push(message.data);
            iterate();
        }

        window.addEventListener("message", catchMessage, false);

        function postResult(inner_window) {
            var timing = inner_window.performance.timing,
                difference = timing.loadEventEnd - timing.requestStart;
            inner_window.parent.postMessage(difference, "*");
        }

        function postIfSet() {
            var timing = inner_window.performance.timing;
            if (timing.loadEventEnd === 0){
                setTimeout(postIfSet, 10);
            }
            else {
                postResult(inner_window);
            }
        }

        iframe.onload = postIfSet;

        return function(tests, callback) {
            number_of_tests = tests.length;
            queue = tests;
            counter = 0;
            finalize = callback;
            result = {};
            reporter = createReport(number_of_tests);
            testNext();
        };
    }

    function buildQueueFromProvidedTestObject (data, iterations) {
        var queue = [], i, category;

        function wrapCategory(category){
            return function(member){
                queue.push([category, member]);
            };
        }

        for(i = 0; i < iterations; i+= 1){
            for(category in data){
                if(data.hasOwnProperty(category)) {
                    data[category].forEach(wrapCategory(category));
                }
            }
        }
        return queue;
    }

    function makeResultsObject(data){
        var category_name, category, i,
            results = {};

        for(category_name in data){
            results[category_name] = {};
            category = data[category_name];
            for(i = 0; i < category.length; i += 1){
                results[category_name][category[i]] = [];
            }
        }
        return results;
    }

    // Data presentation methods

    function sum (array) {
        var result = 0, i;
        for(i = 0; i < array.length; i += 1){
            result += (+array[i]); //If the elements are strings, we coerce them to numbers
        }
        return result;
    }

    function findMinMax (array) {
        var max = -Number.MAX_VALUE,
            min = Number.MAX_VALUE;
        array.forEach(function(element) {
            if (element >= max) {
                max = element;
            }
            if (element <= min) {
                min = element;
            }
        });
        return [min, max];
    }

    function makeFilter (smallest, largest) {
        var removals = 0;
        return function (value, index, array) {
            if (value !== smallest && value !== largest) {
                return true;
            }
                removals += 1;
                if (removals <= 2) {
                    return false;
                }
                return true;

        };
    }

    function findFinalNumber (array) {

        var trimmed_array = array.filter(makeFilter.apply(null, findMinMax(array))),
            naive_average = sum(trimmed_array)/trimmed_array.length;
        return Math.round(naive_average);
    }

    function createTestURL(category, test){
        var url = document.createElement('a');
        url.href= './tests/' + category + "/" + test + "/";
        url.appendChild(document.createTextNode(test));
        return url;
    }

    function createTable (result) {

        var category, category_array, final_number, header, result_string,
        results, row, tblbody = document.createElement('tbody'), testname,
        urlfield;

        for(category in result){
            if(result.hasOwnProperty(category)){

            category_array = result[category];
            header = makeParent(text(category), 'th');
            tblbody.appendChild(makeParent(header, 'tr'));

            for(testname in category_array){
                if(category_array.hasOwnProperty(testname)) {
                row = document.createElement('tr');
                urlfield = createTestURL(category, testname);

                results = result[category][testname];
                final_number = findFinalNumber(results);
                result_string = text(final_number+' ms');

                appendChildren(row, makeParent(urlfield, 'td'),
                               makeParent(result_string, 'td'));

                tblbody.appendChild(row);
            }
            }
        }
        }

        table.appendChild(tblbody);
    }

    function finalMessage() {
        var p1 = paragraph('Alright! Testing completed.'),
            p2 = paragraph('Do take the results with a grain of salt.'),
            p3 = paragraph(button);

        button.textContent = "One more time, please";

        return [p1, p2, p3];
    }

    function pushResultToHistory(result){
        window.location.hash = JSON.stringify(result);
        present(result);
    }

    function present (result) {
        iframe.style.display = "none";
        updateArticle(finalMessage());
        createTable(result);
    }

    function resetTableIfSet(){
        if(table.childNodes.length !== 0) {
            table.removeChild(table.childNodes[0]);
        }
    }

    testqueue = buildQueueFromProvidedTestObject(data, iterations);

    function engage () {
        resetTableIfSet();
        iframe.style.display = "block";
        createBoundRunner(iframe, window)(testqueue.slice(), pushResultToHistory);
    }

    button.onclick = engage;

}(TESTRUNNER.data, 12, document.getElementsByTagName('iframe')[0], document, window,
        document.getElementsByTagName('article')[0], document.getElementsByTagName('button')[0],document.getElementsByTagName('table')[0]));
<commit_msg>Moved array.forEach redefinition to a more logical place<commit_after>/*jslint browser: true, devel: true, es5: true, plusplus: false, unparam: true, vars: false */

(function (data, iterations, iframe, document, window, article, button, table) {

    "use strict";

    window.onload = function () {

        if (location.hash !== "")
            present (json.parse(String.prototype.slice.call(location.hash, 1)));
    }

    // This is a placeholder for the testrunner after it has  binded an
    // eventlistener to the iframe window.
    var testqueue, runner;

    // Return if incompatible with Navigation Timing API

    if(window.performance === undefined) {
        (document.getElementsByTagName('body')[0]).innerHTML = "
Unfortunately," +
            "  your browser does not support the " + "Navigation Timing API.
";
        return;
    }

    // IE9 does not support forEach, so we define it here.
    // Kudos to StackOverflow user bobince for the standatds-compliant implementation
    if (!Array.prototype.forEach) {
        Array.prototype.forEach = function (fun, that){
            var i, n;
            for (i = 0, n = this.length; i < n; i+= 1) {
                if (this[i] !== undefined) {
                    fun.call(that, this[i], i, this);
                }
            }
        };
    }

    // DOM Methods

    function text(string) {
        return document.createTextNode(string);
    }

    function paragraph() {
        var p = document.createElement('p'), i;
        for (i = 0; i < arguments.length; i += 1) {
            if (typeof arguments[i] === "string") {
                p.appendChild(text(arguments[i]));
            }
            else {
                p.appendChild(arguments[i]);
            }
        }
        return p;
    }

    function makeParent(child, typeString) {
        var element = document.createElement(typeString);
        element.appendChild(child);
        return element;
    }

    function appendChildren(element) {
        var i;
        if (arguments.length <= 1) {
            return;
        }

        for (i = 1; i < arguments.length; i += 1) {
            element.appendChild(arguments[i]);
        }

        return element;
    }

    function nodeListToArray(list) {
        var array = [], i;
        for (i = 0; i < list.length; i += 1) {
            array[i] = list[i];
        }
        return array;
    }

    function updateArticle(new_pars){
        var old_pars = nodeListToArray(article.getElementsByTagName('p'));
        old_pars.forEach(function(par){ article.removeChild(par); });
        new_pars.forEach(function(par){ article.appendChild(par); });
    }

    // This function servers as a closure for the actual runner returned to
    // the caller. Helper functions are defined, and an eventlistener is
    // binded to the iframe.

    function createBoundRunner(iframe, window) {

        var counter, // This stores current test number.
            current_test, // This stores the currently running test category (string).
            inner_window = iframe.contentWindow, // Make it easier to access  the iframe's DOM
            finalize, // A placeholder for callback function to be called when testing is complete.
            number_of_tests, // Stores total number of tests
            queue, // The queue of tests
            reporter, // A placeholder for the function(X) used to report 'currently running test X of total'
            result; // A placeholder for the result

        // In order to circumvent Security policies in the browser, we
        // manually set the domain of the iframe to the domain of the
        // parent html.

        inner_window.domain = document.domain;

        // In order to avoid redrawing the article for every iteration,
        // we wrap the article element in a closure and return a function
        // that only replaces the counter text for each iteration.

        function createReport(total_tests){
            var intro = "Running test ",
                countptr = text(""), //A pointer to the text node where we set the currently runing testnumber
                fat_count = makeParent(countptr, 'strong'),
                copula = " of ",
                total = makeParent(text(total_tests), 'strong'),
                period = text("."),
                par = paragraph(intro, fat_count, copula, total, period);

            updateArticle([par]);

            return function(){
                counter += 1;
                countptr.textContent = counter;
            };
        }

        function testNext() {
            reporter();
            current_test = queue.shift();
            iframe.src = "./tests/" + current_test[0]+ "/" + current_test[1] +
                "/index.html";
        }

        function iterate() {
            if (queue.length !== 0) {
                testNext();
            }
            else {
                window.removeEventListener("message", catchMessage, false)
                finalize(result);
            }
        }

        function initializeResultIfEmpty() {

            if (result[current_test[0]] === undefined){
                result[current_test[0]] = {};
            }

            if (result[current_test[0]][current_test[1]] === undefined){
                result[current_test[0]][current_test[1]] = [];
            }
        }

        function catchMessage(message) {
            initializeResultIfEmpty();
            result[current_test[0]][current_test[1]].push(message.data);
            iterate();
        }

        window.addEventListener("message", catchMessage, false);

        function postResult(inner_window) {
            var timing = inner_window.performance.timing,
                difference = timing.loadEventEnd - timing.requestStart;
            inner_window.parent.postMessage(difference, "*");
        }

        function postIfSet() {
            var timing = inner_window.performance.timing;
            if (timing.loadEventEnd === 0){
                setTimeout(postIfSet, 10);
            }
            else {
                postResult(inner_window);
            }
        }

        iframe.onload = postIfSet;

        return function(tests, callback) {
            number_of_tests = tests.length;
            queue = tests;
            counter = 0;
            finalize = callback;
            result = {};
            reporter = createReport(number_of_tests);
            testNext();
        };
    }

    function buildQueueFromProvidedTestObject (data, iterations) {
        var queue = [], i, category;

        function wrapCategory(category){
            return function(member){
                queue.push([category, member]);
            };
        }

        for(i = 0; i < iterations; i+= 1){
            for(category in data){
                if(data.hasOwnProperty(category)) {
                    data[category].forEach(wrapCategory(category));
                }
            }
        }
        return queue;
    }

    function makeResultsObject(data){
        var category_name, category, i,
            results = {};

        for(category_name in data){
            results[category_name] = {};
            category = data[category_name];
            for(i = 0; i < category.length; i += 1){
                results[category_name][category[i]] = [];
            }
        }
        return results;
    }

    // Data presentation methods

    function sum (array) {
        var result = 0, i;
        for(i = 0; i < array.length; i += 1){
            result += (+array[i]); //If the elements are strings, we coerce them to numbers
        }
        return result;
    }

    function findMinMax (array) {
        var max = -Number.MAX_VALUE,
            min = Number.MAX_VALUE;
        array.forEach(function(element) {
            if (element >= max) {
                max = element;
            }
            if (element <= min) {
                min = element;
            }
        });
        return [min, max];
    }

    function makeFilter (smallest, largest) {
        var removals = 0;
        return function (value, index, array) {
            if (value !== smallest && value !== largest) {
                return true;
            }
                removals += 1;
                if (removals <= 2) {
                    return false;
                }
                return true;

        };
    }

    function findFinalNumber (array) {

        var trimmed_array = array.filter(makeFilter.apply(null, findMinMax(array))),
            naive_average = sum(trimmed_array)/trimmed_array.length;
        return Math.round(naive_average);
    }

    function createTestURL(category, test){
        var url = document.createElement('a');
        url.href= './tests/' + category + "/" + test + "/";
        url.appendChild(document.createTextNode(test));
        return url;
    }

    function createTable (result) {

        var category, category_array, final_number, header, result_string,
        results, row, tblbody = document.createElement('tbody'), testname,
        urlfield;

        for(category in result){
            if(result.hasOwnProperty(category)){

            category_array = result[category];
            header = makeParent(text(category), 'th');
            tblbody.appendChild(makeParent(header, 'tr'));

            for(testname in category_array){
                if(category_array.hasOwnProperty(testname)) {
                row = document.createElement('tr');
                urlfield = createTestURL(category, testname);

                results = result[category][testname];
                final_number = findFinalNumber(results);
                result_string = text(final_number+' ms');

                appendChildren(row, makeParent(urlfield, 'td'),
                               makeParent(result_string, 'td'));

                tblbody.appendChild(row);
            }
            }
        }
        }

        table.appendChild(tblbody);
    }

    function finalMessage() {
        var p1 = paragraph('Alright! Testing completed.'),
            p2 = paragraph('Do take the results with a grain of salt.'),
            p3 = paragraph(button);

        button.textContent = "One more time, please";

        return [p1, p2, p3];
    }

    function pushResultToHistory(result){
        window.location.hash = JSON.stringify(result);
        present(result);
    }

    function present (result) {
        iframe.style.display = "none";
        updateArticle(finalMessage());
        createTable(result);
    }

    function resetTableIfSet(){
        if(table.childNodes.length !== 0) {
            table.removeChild(table.childNodes[0]);
        }
    }

    testqueue = buildQueueFromProvidedTestObject(data, iterations);

    function engage () {
        resetTableIfSet();
        iframe.style.display = "block";
        createBoundRunner(iframe, window)(testqueue.slice(), pushResultToHistory);
    }

    button.onclick = engage;

}(TESTRUNNER.data, 12, document.getElementsByTagName('iframe')[0], document, window,
        document.getElementsByTagName('article')[0], document.getElementsByTagName('button')[0],document.getElementsByTagName('table')[0]));
<|endoftext|>


<commit_before>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var pg = require('pg');
var favicon = require('serve-favicon');

var port = process.env.PORT || process.env.NODE_PORT || 3000;

var conString = "pg://other_user:u_pick_it@52.2.3.184:5432/ellucian";
var client = new pg.Client(conString);

http.listen(port, function(err) {
	 console.log('listening on ' + port);
});

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/client/index.html');
});

app.use(favicon(__dirname + '/client/favicon.ico'));

io.on('connection', function(socket){
	console.log('a user connected');

	socket.on('create', function(req) {
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.create1);
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				client = new pg.Client(conString);
				error = "Create1 Termination";
				socket.emit('err', error);
			});
			//done(client);
		});
		console.log(req.create1);
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.create2);
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				//client = new pg.Client(conString);
				error = "Create2 Termination";
				socket.emit('err', error);
			});
			//done(client);
		});
		console.log(req.create2);
	});

	socket.on('insert', function(req) {
		var results = [];
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.insert1).on("row", function (row) {
				console.log(row);
				results.push(row);
				done(client);
			});
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				client = new pg.Client(conString);
				error = "Incorrect syntax";
				socket.emit('err', error);
			});
			console.log(req.insert1);
		});
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.insert2).on("row", function (row) {
				results.push(row);
				done(client);
			});
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				//client = new pg.Client(conString);
				error = "Incorrect syntax";
				socket.emit('err', error);
			});
			console.log(req.insert2);
		});
	});

	socket.on('select', function(req) {
		var results = [];
		pg.connect(conString, function(err, client, done) {
			var query = client.query(req, function (err, result) {
				// Write out as HTML output
				if(err) {
					console.log(err);
					done(client);
					//client = new pg.Client(conString);
					error = "Incorrect syntax";
					socket.emit('err', err);
				} else {
					socket.emit('table', result);
					done(client);
				}
			});
		});
	});

	socket.on('put', function(req) {
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req);
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				//client = new pg.Client(conString);
				error = "Incorrect syntax";
				socket.emit('err', error);
			});
			console.log(req);
		});
	});

	socket.on('delete', function(req) {
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req);
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				//client = new pg.Client(conString);
				error = "Incorrect syntax";
				socket.emit('err', error);
			});
			console.log(req);
		});

	});

	socket.on('disconnect', function () {
		pg.end();
		io.emit('user disconnected');
	});
});<commit_msg>New connect architecture<commit_after>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var pg = require('pg');
var favicon = require('serve-favicon');

var port = process.env.PORT || process.env.NODE_PORT || 3000;

pg.defaults.poolSize = 100;

var conString = "pg://other_user:u_pick_it@52.2.3.184:5432/ellucian";
//var client = new pg.Client(conString);
var client;

http.listen(port, function(err) {
	 console.log('listening on ' + port);
});

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/client/index.html');
});

app.use(favicon(__dirname + '/client/favicon.ico'));

io.on('connection', function(socket){
	console.log('a user connected');

	socket.on('create', function(req) {
		client = new pg.Client(conString);
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.create1, function (err, result) {
				// Write out as HTML output
				if(err) {
					console.log(err);
					done(client);
					client = new pg.Client(conString);
					error = "Incorrect syntax";
					socket.emit('err', err);
				} else {
					done(client);
					//client = new pg.Client(conString);
				}
			});
			//done(client);
		});
		console.log(req.create1);
		pg.end();
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.create2, function (err, result) {
				// Write out as HTML output
				if(err) {
					console.log(err);
					done(client);
					//client = new pg.Client(conString);
					error = "Incorrect syntax";
					socket.emit('err', err);
				} else {
					done(client);
				}
			});
			//done(client);
		});
		console.log(req.create2);
		pg.end();
	});

	socket.on('insert', function(req) {
		client = new pg.Client(conString);
		var results = [];
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.insert1).on("row", function (row) {
				console.log(row);
				results.push(row);
				done(client);
			});
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				client = new pg.Client(conString);
				error = "Incorrect syntax";
				socket.emit('err', error);
			});
			console.log(req.insert1);
		});
		pg.end();
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req.insert2).on("row", function (row) {
				results.push(row);
				done(client);
			});
			query.on('error', function(error) {
				//handle the error
				console.log(error);
				done(client);
				//client = new pg.Client(conString);
				error = "Incorrect syntax";
				socket.emit('err', error);
			});
			console.log(req.insert2);
		});
		pg.end();
	});

	socket.on('select', function(req) {
		client = new pg.Client(conString);
		var results = [];
		pg.connect(conString, function(err, client, done) {
			var query = client.query(req, function (err, result) {
				// Write out as HTML output
				if(err) {
					console.log(err);
					done(client);
					//client = new pg.Client(conString);
					error = "Incorrect syntax";
					socket.emit('err', err);
				} else {
					socket.emit('table', result);
					done(client);
				}
			});
		});
		pg.end();
	});

	socket.on('put', function(req) {
		client = new pg.Client(conString);
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req, function (err, result) {
				// Write out as HTML output
				if(err) {
					console.log(err);
					done(client);
					//client = new pg.Client(conString);
					error = "Incorrect syntax";
					socket.emit('err', err);
				} else {
					done(client);
				}
			});
			console.log(req);
		});
		pg.end();
	});

	socket.on('delete', function(req) {
		client = new pg.Client(conString);
		pg.connect(conString, function(error, client, done) {
			var query = client.query(req, function (err, result) {
				// Write out as HTML output
				if(err) {
					console.log(err);
					done(client);
					//client = new pg.Client(conString);
					error = "Incorrect syntax";
					socket.emit('err', err);
				} else {
					done(client);
					//client = new pg.Client(conString);
				}
			});
			console.log(req);
		});
		pg.end();

	});

	socket.on('disconnect', function () {
		io.emit('user disconnected');
	});
});<|endoftext|>


<commit_before>import {connect} from 'react-redux';
import {Component} from 'react';
import PropTypes from 'prop-types';

class DocumentTitle extends Component {
    constructor(props) {
        super(props);
        const {update_title} = props.config;
        this.state = {
            update_title,
        };
    }

    UNSAFE_componentWillReceiveProps(props) {
        if (this.state.update_title && props.isLoading) {
            document.title = this.state.update_title;
        }
    }

    shouldComponentUpdate() {
        return false;
    }

    render() {
        return null;
    }
}

DocumentTitle.propTypes = {
    isLoading: PropTypes.bool.isRequired,
    config: PropTypes.shape({update_title: PropTypes.string}),
};

export default connect(state => ({
    isLoading: state.isLoading,
    config: state.config,
}))(DocumentTitle);
<commit_msg>Revert "don't revert document.title"<commit_after>import {connect} from 'react-redux';
import {Component} from 'react';
import PropTypes from 'prop-types';

class DocumentTitle extends Component {
    constructor(props) {
        super(props);
        const {update_title} = props.config;
        this.state = {
            initialTitle: document.title,
            update_title,
        };
    }

    UNSAFE_componentWillReceiveProps(props) {
        if (this.state.update_title && props.isLoading) {
            document.title = this.state.update_title;
        } else {
            document.title = this.state.initialTitle;
        }
    }

    shouldComponentUpdate() {
        return false;
    }

    render() {
        return null;
    }
}

DocumentTitle.propTypes = {
    isLoading: PropTypes.bool.isRequired,
    config: PropTypes.shape({update_title: PropTypes.string}),
};

export default connect(state => ({
    isLoading: state.isLoading,
    config: state.config,
}))(DocumentTitle);
<|endoftext|>


<commit_before>$(function(){

  Handlebars.registerHelper('md', function(content){
    return markdown.toHTML(content);
  });

  var Person = Backbone.Model.extend({
    idAttribute: '@id',

    initialize: function(){
      _.bindAll(this, 'setAvatar', 'setOembed');
      this.on('change:description', this.save);
      this.on('change:video', this.save);
      this.on('change:video', this.setOembed);
      this.on('change:email', this.setAvatar);
      if(this.get('email')){
        this.setAvatar();
      }
      if(this.get('video')){
        this.setOembed();
      }
    },

    setAvatar: function(){
      this.set('image', 'http://gravatar.com/avatar/' + md5(this.get('email')));
    },

    setOembed: function(){
      if(this.get('video')){
        superagent.post('http://localhost:9000/oembed')
        .send({ url: this.get('video') })
        .end(function(response){
          var scaled = response.text.replace('width="1280"', 'width="640"').replace('height="720"', 'height="360"');
          this.set('oembed', scaled);
        }.bind(this));
      } else {
        this.unset('oembed');
      }
    },

    //FIXME override Backbone.sync
    save: function(){
      superagent.put('http://localhost:9000/' + this.id)
      .withCredentials()
      .send(this.toJSON())
      .end(function(response){ console.log('UPDATE: ', response); });
    }
  });

  // FIXME !!!DRY!!!
  var Crew = Backbone.Collection.extend({
    model: Person,
    url: 'http://localhost:9000/people',

    initialize: function(){
      this.on('reset', function(){ console.log('People loaded!'); });
      this.fetch({ reset: true });
    }
  });

  var crew = new Crew();

  var Project = Backbone.Model.extend({
    idAttribute: '@id',

    initialize: function(){
      _.bindAll(this, 'setAvatar');
      this.on('change:description', this.save);
      this.on('change:email', this.setAvatar);
      if(this.get('email')){
        this.setAvatar();
      }
    },

    setAvatar: function(){
      this.set('image', 'http://gravatar.com/avatar/' + md5(this.get('email')));
    },

    //FIXME override Backbone.sync
    save: function(){
      superagent.put('http://localhost:9000/' + this.id)
      .withCredentials()
      .send(this.toJSON())
      .end(function(response){ console.log('UPDATE: ', response); });
    }
  });

  var Projects = Backbone.Collection.extend({
    model: Project,
    url: 'http://localhost:9000/projects',

    initialize: function(){
      this.on('reset', function(){ console.log('People loaded!'); });
      this.fetch({ reset: true });
    }
  });

  var projects = new Projects();

  var partials = new Array('#profile','#sideNav');

  var Router = Backbone.Router.extend({
    routes: {
      '': 'root',
      'people': 'people',
      'people/:part': 'person',
      'projects': 'projects',
      'projects/:part': 'project'
    },

    people: function(){
      var index = new Index({ collection: crew });
      this.stretchIndex();
    },

    person: function(part){
      var profile = new Profile({ model: crew.findWhere({'@id': 'people/' + part}) });
      var sideNav = new SideNav({ collection: crew });
      this.removeIndex();
    },

    projects: function(){
      var index = new Index({ collection: projects });
      this.stretchIndex();
    },

    project: function(part){
      var profile = new Profile({ model: projects.findWhere({'@id': 'projects/' + part}) });
      var sideNav = new SideNav({ collection: projects });
      this.removeIndex();
    },

    removeIndex: function(){
      $('.main-column').removeClass('col-sm-12').addClass('col-xs-12 col-sm-9');
      $('#index').empty();
    },

    stretchIndex: function(){
      $('.main-column').removeClass('col-xs-12 col-sm-9').addClass('col-sm-12');
      this.clearPartials();
    },

    clearPartials: function(){
      $('#profile').empty();
      $('#sideNav').empty();
      /* for (var i=0;i<partials.length;i++)
            $([i]).empty(); *** Not working yet BUT not necessary if we only have one profile template for people, peers, etc. *** */
    }

  });

  Backbone.history.start({ pushState: true });

  var router = new Router();

  var Nav = Backbone.View.extend({
    el: '.nav',

    events: {
      'click': 'navigate'
    },

    navigate: function(event){
      event.preventDefault();
      if(event.target.attributes.href){
        router.navigate(event.target.attributes.href.value, { trigger: true });
      } else {
        router.navigate('', { trigger: true });
      }
    }
  });

  var nav = new Nav();

  var AgentMenu = Backbone.View.extend({
    el: '#agentMenu',

    events: {
      'click .sign-in': 'login'
    },

    initialize: function(){
      _.bindAll(this, 'render');
      this.model.on('change:authenticated', this.render);
      this.render();
    },

    render: function(){
      var partial = JST.agentMenu(this.model.toJSON());
      this.$el.html(partial);
    },

    login: function(){
      navigator.id.request();
    }
  });

  var SideNav = Backbone.View.extend({
    el: '#sideNav',

    events: {
      'click a': 'showProfile'
    },

    initialize: function(){
      _.bindAll(this, 'render');
      this.render();
    },

    render: function(){
      this.$el.html('');
      this.collection.each(function(resource){
        var data = resource.toJSON();
        data.path = data["@id"]; //FIXME hbs seems not to handle @id / @type
        this.$el.append(JST.nameLink(data));
      }.bind(this));
    },

    showProfile: function(event){
      event.preventDefault();
      router.navigate(event.target.attributes.href.value, { trigger: true });
    }
  });

  var Index = Backbone.View.extend({
    el: '#index',

    events: {
      'click a': 'showProfile'
    },

    initialize: function(){
      _.bindAll(this, 'render');
      this.render();
    },

    render: function(){
      this.$el.html('');
      var row;
      this.collection.each(function(resource, index){
        if(index % 3 === 0){
          row = $('

');
          this.$el.append(row);
          window.foo = row;
        }
        var data = resource.toJSON();
        data.path = data["@id"]; //FIXME hbs seems not to handle @id / @type
        row.append(JST.indexLink(data));
      }.bind(this));
    },

    showProfile: function(event){
      event.preventDefault();
      router.navigate(event.target.attributes.href.value, { trigger: true });
    }
  });

  var Profile = Backbone.View.extend({
    el: '#profile',

    initialize: function(){
      _.bindAll(this, 'render');
      this.model.on('change:oembed remove:oembed', this.render);
      this.render();
    },

    render: function(){
      var partial = JST.profile(this.model.toJSON());
      this.$el.html(partial);
      if(this.model.attributes.email === agent.attributes.email){
        // edit description
        var description = this.$el.find('[property=description]');
        var editor = $('<textarea style="width: 100%; height: 12em;"></textarea>');
        description.bind('click', function(event){
          // ignore clicks on editor
          if($(event.target)[0] === editor[0]){
            return event.stopPropagation();
          }
          $(description).empty();
          $(description).append(editor);
          $(editor).val(this.model.get('description'));
          $(editor).focus();
        }.bind(this));
        editor.bind('blur', function(){
          var marked = editor.val();
          this.model.set('description', marked);
          $(editor).detach();
          $(description).html(markdown.toHTML(marked));
        }.bind(this));
      }
      // edit video
      var video = this.$el.find('.video');
      video.attr('contenteditable', true);
      video.bind('blur', function(){
        var url = video.find('a').attr('href');
        if(url){
          this.model.set('video', url);
        } else {
          this.model.unset('video');
        }
      }.bind(this));
    }
  });

  var agent = new Person();
  var agentMenu = new AgentMenu({ model: agent });

  // debug
  window.un = {
    agent: agent,
    crew: crew,
    router: router
  };

  var login = function(assertion){
    agent.assertion = assertion;
    superagent.post('http://localhost:9000/auth/login')
    .withCredentials()
    .send({ assertion: assertion })
    .end(function(response){
      var data = JSON.parse(response.text);
      console.log('Persona.onlogin()', data);
      agent.set(data);
      agent.set('authenticated', true);
    });
  };

  var logout =  function(){
    // FIXME decide if needs to sent assertion!
    superagent.post('http://localhost:9000/auth/logout')
    .withCredentials()
    .send({ assertion: agent.assertion })
    .end(function(response){
      console.log('Persona.onlogout()', response);
      agent.set('authenticated', false);
    });
  };

  // mozilla persona
  navigator.id.watch({
    loggedInagent: null,
    onlogin: login,
    onlogout: logout
  });

});
<commit_msg>fixed inserting video link for browsers which don't add  tag<commit_after>$(function(){

  Handlebars.registerHelper('md', function(content){
    return markdown.toHTML(content);
  });

  var Person = Backbone.Model.extend({
    idAttribute: '@id',

    initialize: function(){
      _.bindAll(this, 'setAvatar', 'setOembed');
      this.on('change:description', this.save);
      this.on('change:video', this.save);
      this.on('change:video', this.setOembed);
      this.on('change:email', this.setAvatar);
      if(this.get('email')){
        this.setAvatar();
      }
      if(this.get('video')){
        this.setOembed();
      }
    },

    setAvatar: function(){
      this.set('image', 'http://gravatar.com/avatar/' + md5(this.get('email')));
    },

    setOembed: function(){
      if(this.get('video')){
        superagent.post('http://localhost:9000/oembed')
        .send({ url: this.get('video') })
        .end(function(response){
          var scaled = response.text.replace('width="1280"', 'width="640"').replace('height="720"', 'height="360"');
          this.set('oembed', scaled);
        }.bind(this));
      } else {
        this.unset('oembed');
      }
    },

    //FIXME override Backbone.sync
    save: function(){
      superagent.put('http://localhost:9000/' + this.id)
      .withCredentials()
      .send(this.toJSON())
      .end(function(response){ console.log('UPDATE: ', response); });
    }
  });

  // FIXME !!!DRY!!!
  var Crew = Backbone.Collection.extend({
    model: Person,
    url: 'http://localhost:9000/people',

    initialize: function(){
      this.on('reset', function(){ console.log('People loaded!'); });
      this.fetch({ reset: true });
    }
  });

  var crew = new Crew();

  var Project = Backbone.Model.extend({
    idAttribute: '@id',

    initialize: function(){
      _.bindAll(this, 'setAvatar');
      this.on('change:description', this.save);
      this.on('change:email', this.setAvatar);
      if(this.get('email')){
        this.setAvatar();
      }
    },

    setAvatar: function(){
      this.set('image', 'http://gravatar.com/avatar/' + md5(this.get('email')));
    },

    //FIXME override Backbone.sync
    save: function(){
      superagent.put('http://localhost:9000/' + this.id)
      .withCredentials()
      .send(this.toJSON())
      .end(function(response){ console.log('UPDATE: ', response); });
    }
  });

  var Projects = Backbone.Collection.extend({
    model: Project,
    url: 'http://localhost:9000/projects',

    initialize: function(){
      this.on('reset', function(){ console.log('People loaded!'); });
      this.fetch({ reset: true });
    }
  });

  var projects = new Projects();

  var partials = new Array('#profile','#sideNav');

  var Router = Backbone.Router.extend({
    routes: {
      '': 'root',
      'people': 'people',
      'people/:part': 'person',
      'projects': 'projects',
      'projects/:part': 'project'
    },

    people: function(){
      var index = new Index({ collection: crew });
      this.stretchIndex();
    },

    person: function(part){
      var profile = new Profile({ model: crew.findWhere({'@id': 'people/' + part}) });
      var sideNav = new SideNav({ collection: crew });
      this.removeIndex();
    },

    projects: function(){
      var index = new Index({ collection: projects });
      this.stretchIndex();
    },

    project: function(part){
      var profile = new Profile({ model: projects.findWhere({'@id': 'projects/' + part}) });
      var sideNav = new SideNav({ collection: projects });
      this.removeIndex();
    },

    removeIndex: function(){
      $('.main-column').removeClass('col-sm-12').addClass('col-xs-12 col-sm-9');
      $('#index').empty();
    },

    stretchIndex: function(){
      $('.main-column').removeClass('col-xs-12 col-sm-9').addClass('col-sm-12');
      this.clearPartials();
    },

    clearPartials: function(){
      $('#profile').empty();
      $('#sideNav').empty();
      /* for (var i=0;i<partials.length;i++)
            $([i]).empty(); *** Not working yet BUT not necessary if we only have one profile template for people, peers, etc. *** */
    }

  });

  Backbone.history.start({ pushState: true });

  var router = new Router();

  var Nav = Backbone.View.extend({
    el: '.nav',

    events: {
      'click': 'navigate'
    },

    navigate: function(event){
      event.preventDefault();
      if(event.target.attributes.href){
        router.navigate(event.target.attributes.href.value, { trigger: true });
      } else {
        router.navigate('', { trigger: true });
      }
    }
  });

  var nav = new Nav();

  var AgentMenu = Backbone.View.extend({
    el: '#agentMenu',

    events: {
      'click .sign-in': 'login'
    },

    initialize: function(){
      _.bindAll(this, 'render');
      this.model.on('change:authenticated', this.render);
      this.render();
    },

    render: function(){
      var partial = JST.agentMenu(this.model.toJSON());
      this.$el.html(partial);
    },

    login: function(){
      navigator.id.request();
    }
  });

  var SideNav = Backbone.View.extend({
    el: '#sideNav',

    events: {
      'click a': 'showProfile'
    },

    initialize: function(){
      _.bindAll(this, 'render');
      this.render();
    },

    render: function(){
      this.$el.html('');
      this.collection.each(function(resource){
        var data = resource.toJSON();
        data.path = data["@id"]; //FIXME hbs seems not to handle @id / @type
        this.$el.append(JST.nameLink(data));
      }.bind(this));
    },

    showProfile: function(event){
      event.preventDefault();
      router.navigate(event.target.attributes.href.value, { trigger: true });
    }
  });

  var Index = Backbone.View.extend({
    el: '#index',

    events: {
      'click a': 'showProfile'
    },

    initialize: function(){
      _.bindAll(this, 'render');
      this.render();
    },

    render: function(){
      this.$el.html('');
      var row;
      this.collection.each(function(resource, index){
        if(index % 3 === 0){
          row = $('

');
          this.$el.append(row);
          window.foo = row;
        }
        var data = resource.toJSON();
        data.path = data["@id"]; //FIXME hbs seems not to handle @id / @type
        row.append(JST.indexLink(data));
      }.bind(this));
    },

    showProfile: function(event){
      event.preventDefault();
      router.navigate(event.target.attributes.href.value, { trigger: true });
    }
  });

  var Profile = Backbone.View.extend({
    el: '#profile',

    initialize: function(){
      _.bindAll(this, 'render');
      this.model.on('change:oembed remove:oembed', this.render);
      this.render();
    },

    render: function(){
      var partial = JST.profile(this.model.toJSON());
      this.$el.html(partial);
      if(this.model.attributes.email === agent.attributes.email){
        // edit description
        var description = this.$el.find('[property=description]');
        var editor = $('<textarea style="width: 100%; height: 12em;"></textarea>');
        description.bind('click', function(event){
          // ignore clicks on editor
          if($(event.target)[0] === editor[0]){
            return event.stopPropagation();
          }
          $(description).empty();
          $(description).append(editor);
          $(editor).val(this.model.get('description'));
          $(editor).focus();
        }.bind(this));
        editor.bind('blur', function(){
          var marked = editor.val();
          this.model.set('description', marked);
          $(editor).detach();
          $(description).html(markdown.toHTML(marked));
        }.bind(this));
      }
      // edit video
      var video = this.$el.find('.video');
      video.attr('contenteditable', true);
      video.bind('blur', function(){
        var url = video.find('a').attr('href');
        if(url){
          this.model.set('video', url);
        } else {
          url = video.html().replace(/^\s+|\s+$/g, '').replace(/^<.*>|<.*>$/g, '');
          if(url.match(/^http[s]*:\/\//)){
            this.model.set('video', url);
          } else {
            this.model.unset('video');
          }
        }
      }.bind(this));
    }
  });

  var agent = new Person();
  var agentMenu = new AgentMenu({ model: agent });

  // debug
  window.un = {
    agent: agent,
    crew: crew,
    router: router
  };

  var login = function(assertion){
    agent.assertion = assertion;
    superagent.post('http://localhost:9000/auth/login')
    .withCredentials()
    .send({ assertion: assertion })
    .end(function(response){
      var data = JSON.parse(response.text);
      console.log('Persona.onlogin()', data);
      agent.set(data);
      agent.set('authenticated', true);
    });
  };

  var logout =  function(){
    // FIXME decide if needs to sent assertion!
    superagent.post('http://localhost:9000/auth/logout')
    .withCredentials()
    .send({ assertion: agent.assertion })
    .end(function(response){
      console.log('Persona.onlogout()', response);
      agent.set('authenticated', false);
    });
  };

  // mozilla persona
  navigator.id.watch({
    loggedInagent: null,
    onlogin: login,
    onlogout: logout
  });

});
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Component.extend({
  classNames: ['progress-bar-container'],
});
<commit_msg>add documentation for progress-bar-container (#366)<commit_after>import Ember from 'ember';

const {
  Component,
} = Ember;

/**
  `progress-bar-container` is the container for a progress-bar.

  ## default usage

  ```Handlebars
  {{progress-bar-container percentage=percentage}}
  ```

  @class progress-bar-container
  @module Component
  @extends Ember.Component
*/
export default Component.extend({
  classNames: ['progress-bar-container'],
});
<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import _ from 'lodash';
import { Bar } from 'react-chartjs-2';
import moment from 'moment';
import { connect } from 'react-redux';
import datalabels from 'chartjs-plugin-datalabels';

/**
 * @param {State} state
 */
function mapStateToProps(state) {
	const timeInterval = state.graph.compareTimeInterval;
	const barDuration = state.graph.compareDuration;
	const data = { datasets: [] };
	const labels = [];
	// Power used so far this week
	let currentWeek = 0;
	// Last week total usage
	let lastWeek = 0;
	// Power used up to this point last week
	let currentLastWeek = 0;
	const soFar = moment().diff(moment().startOf('week'), 'days');
	const delta = function (change) {
		if (isNaN(change)) {
			return '';
		}
		if (change < 0) {
			return `You have used ${parseInt(change.toFixed(2).replace('.', ''), 10)}% less energy this week.`;
		}
		return `You have used ${parseInt(change.toFixed(2).replace('.', ''), 10)}% more energy this week.`;
	};

	const colorize = function (change) {
		if (change < 0) {
			return 'green';
		}
		return 'red';
	};
	for (const meterID of state.graph.selectedMeters) {
		const readingsData = state.readings.bar.byMeterID[meterID][timeInterval][barDuration];
		if (readingsData !== undefined && !readingsData.isFetching) {
			// Sunday needs special logic
			if (soFar !== 0) {
                // Calculate currentWeek
				for (let i = 1; i <= soFar; i++) {
					currentWeek += readingsData.readings[readingsData.readings.length - i][1];
				}
                // Calculate lastWeek
				for (let i = 0; i < 7; i++) {
					lastWeek += readingsData.readings[readingsData.readings.length - (8 + i) - soFar][1];
				}

                // Calculate currentLastWeek
				for (let i = 1; i <= soFar; i++) {
					currentLastWeek += readingsData.readings[readingsData.readings.length - i - 7][1];
				}
			}			else {
				currentWeek = readingsData.readings[readingsData.readings.length - 1][1];
				// Data is acquired in days so when less than a day has passed we need to estimate
				currentLastWeek = Math.round((readingsData.readings[readingsData.readings.length - 8][1] / 24) * moment().hour());
				for (let i = 0; i < 7; i++) {
					lastWeek += readingsData.readings[readingsData.readings.length - 7][1];
				}
			}
			labels.push('Last week');
			labels.push('This week');
			const color1 = 'rgba(173, 216, 230, 1)';
			const color2 = 'rgba(218, 165, 32, 1)';
			const color3 = 'rgba(173, 216, 230, 0.45)';
			data.datasets.push({
				data: [lastWeek, Math.round((currentWeek / currentLastWeek) * lastWeek)],
				backgroundColor: [color1, color3],
				hoverBackgroundColor: [color1, color3],
				datalabels: {
					anchor: 'end',
					align: 'start',
				}
			},
				{
					data: [currentLastWeek, currentWeek],
					backgroundColor: color2,
					hoverBackgroundColor: color2,
					datalabels: {
						anchor: 'end',
						align: 'start',
					}
				});
			// sorts the data so that one doesn't cover up the other
			data.datasets.sort((a, b) => a.data[0] - b.data[0]);
		}
	}
	data.labels = labels;

	const options = {
		animation: {
			duration: 0
		},
		elements: {
			point: {
				radius: 0
			}
		},
		scales: {
			xAxes: [{
				stacked: true,
				gridLines: {
					display: true
				}
			}],
			yAxes: [{
				stacked: false,
				scaleLabel: {
					display: true,
					labelString: 'kWh'
				},
				ticks: {
					beginAtZero: true
				}
			}]
		},
		legend: {
			display: false
		},
		 tooltips: {
			enabled: false
		 	},
		title: {
			display: true,
			text: delta((-1 + (((currentWeek / currentLastWeek) * lastWeek) / lastWeek))),
			fontColor: colorize((-1 + (((currentWeek / currentLastWeek) * lastWeek) / lastWeek)))
		},
		plugins: {
			datalabels: {
				color: 'black',
				font: {
					weight: 'bold'
				},
				display: true,
				formatter: value => `${value} kWh`
			},
		}
	};

	return {
		data,
		options,
		redraw: true
	};
}

export default connect(mapStateToProps)(Bar);
<commit_msg>Made requested changes<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import _ from 'lodash';
import { Bar } from 'react-chartjs-2';
import moment from 'moment';
import { connect } from 'react-redux';
import datalabels from 'chartjs-plugin-datalabels';

/**
 * @param {State} state
 */
function mapStateToProps(state) {
	const timeInterval = state.graph.compareTimeInterval;
	const barDuration = state.graph.compareDuration;
	const data = { datasets: [] };
	const labels = [];
	// Power used so far this week
	let currentWeek = 0;
	// Last week total usage
	let lastWeek = 0;
	// Power used up to this point last week
	let currentLastWeek = 0;
	const soFar = moment().diff(moment().startOf('week'), 'days');
	const delta = change => {
		if (isNaN(change)) return ''; if (change < 0) return `${state.meters.byMeterID[state.graph.selectedMeters].name} has used ${parseInt(change.toFixed(2).replace('.', '').slice(1), 10)}% less energy this week.`;
		return `${state.meters.byMeterID[state.graph.selectedMeters].name} has used ${parseInt(change.toFixed(2).replace('.', ''), 10)}% more energy this week.`;
	};
	const colorize = change => { if (change < 0) return 'green'; return 'red'; };
	for (const meterID of state.graph.selectedMeters) {
		const readingsData = state.readings.bar.byMeterID[meterID][timeInterval][barDuration];
		if (readingsData !== undefined && !readingsData.isFetching) {
			// Sunday needs special logic
			if (soFar !== 0) {
                // Calculate currentWeek
				for (let i = 1; i <= soFar; i++) {
					currentWeek += readingsData.readings[readingsData.readings.length - i][1];
				}
                // Calculate lastWeek
				for (let i = 0; i < 7; i++) {
					lastWeek += readingsData.readings[readingsData.readings.length - (8 + i) - soFar][1];
				}

                // Calculate currentLastWeek
				for (let i = 1; i <= soFar; i++) {
					currentLastWeek += readingsData.readings[readingsData.readings.length - i - 7][1];
				}
			}			else {
				currentWeek = readingsData.readings[readingsData.readings.length - 1][1];
				// Data is acquired in days so when less than a day has passed we need to estimate
				currentLastWeek = Math.round((readingsData.readings[readingsData.readings.length - 8][1] / 24) * moment().hour());
				for (let i = 0; i < 7; i++) {
					lastWeek += readingsData.readings[readingsData.readings.length - 7][1];
				}
			}
			labels.push('Last week');
			labels.push('This week');
			const color1 = 'rgba(173, 216, 230, 1)';
			const color2 = 'rgba(218, 165, 32, 1)';
			const color3 = 'rgba(173, 216, 230, 0.45)';
			data.datasets.push({
				data: [lastWeek, Math.round((currentWeek / currentLastWeek) * lastWeek)],
				backgroundColor: [color1, color3],
				hoverBackgroundColor: [color1, color3],
				datalabels: {
					anchor: 'end',
					align: 'start',
				}
			},
				{
					data: [currentLastWeek, currentWeek],
					backgroundColor: color2,
					hoverBackgroundColor: color2,
					datalabels: {
						anchor: 'end',
						align: 'start',
					}
				});
			// sorts the data so that one doesn't cover up the other
			data.datasets.sort((a, b) => a.data[0] - b.data[0]);
		}
	}
	data.labels = labels;

	const options = {
		animation: {
			duration: 0
		},
		elements: {
			point: {
				radius: 0
			}
		},
		scales: {
			xAxes: [{
				stacked: true,
				gridLines: {
					display: true
				}
			}],
			yAxes: [{
				stacked: false,
				scaleLabel: {
					display: true,
					labelString: 'kWh'
				},
				ticks: {
					beginAtZero: true
				}
			}]
		},
		legend: {
			display: false
		},
		 tooltips: {
			enabled: false
		 	},
		title: {
			display: true,
			text: delta((-1 + (((currentWeek / currentLastWeek) * lastWeek) / lastWeek))),
			fontColor: colorize((-1 + (((currentWeek / currentLastWeek) * lastWeek) / lastWeek)))
		},
		plugins: {
			datalabels: {
				color: 'black',
				font: {
					weight: 'bold'
				},
				display: true,
				formatter: value => `${value} kWh`
			},
		}
	};

	return {
		data,
		options,
		redraw: true
	};
}

export default connect(mapStateToProps)(Bar);
<|endoftext|>