<commit_before>(function () {

"use strict";

angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions', 'OpenSlidesApp.motions.lineNumbering'])

.factory('MotionPDFExport', [
    'HTMLValidizer',
    'Motion',
    'User',
    'PdfMakeConverter',
    'PdfMakeDocumentProvider',
    'PdfMakeBallotPaperProvider',
    'MotionContentProvider',
    'PollContentProvider',
    'gettextCatalog',
    '$http',
    function (HTMLValidizer, Motion, User, PdfMakeConverter, PdfMakeDocumentProvider, PdfMakeBallotPaperProvider,
            MotionContentProvider, PollContentProvider, gettextCatalog, $http) {
        var obj = {};

        var $scope;

        obj.createMotion = function() {
            var text = $scope.motion.getTextByMode($scope.viewChangeRecommendations.mode, $scope.version);
            var content = HTMLValidizer.validize(text) + HTMLValidizer.validize($scope.motion.getReason($scope.version));
            var map = Function.prototype.call.bind([].map);
            var image_sources = map($(content).find("img"), function(element) {
                return element.getAttribute("src");
            });

            $http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) {
                var converter = PdfMakeConverter.createInstance(data.images, pdfMake);
                var motionContentProvider = MotionContentProvider.createInstance(converter, $scope.motion, $scope, User, $http);
                var documentProvider = PdfMakeDocumentProvider.createInstance(motionContentProvider);
                var filename = gettextCatalog.getString("Motion") + "-" + $scope.motion.identifier + ".pdf";
                pdfMake.createPdf(documentProvider.getDocument()).download(filename);
            });
        };

        //make PDF for polls
        obj.createPoll = function() {
            var id = $scope.motion.identifier.replace(" ", "");
            var title = $scope.motion.getTitle($scope.version);
            var filename = gettextCatalog.getString("Motion") + "-" + id + "-" + gettextCatalog.getString("ballot-paper") + ".pdf";
            var pollContentProvider = PollContentProvider.createInstance(title, id, gettextCatalog);
            var documentProvider = PdfMakeBallotPaperProvider.createInstance(pollContentProvider);
            pdfMake.createPdf(documentProvider.getDocument()).download(filename);
        };

        obj.init = function (_scope) {
            $scope = _scope;
        };

        return obj;
    }
])

.factory('MotionInlineEditing', [
    'Editor',
    'Motion',
    'Config',
    '$timeout',
    function (Editor, Motion, Config, $timeout) {
        var obj = {
            active: false,
            changed: false,
            trivialChange: false,
            editor: null,
            lineBrokenText: null,
            originalHtml: null
        };

        var $scope, motion;

        obj.init = function (_scope, _motion) {
            $scope = _scope;
            motion = _motion;
            obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
            obj.originalHtml = obj.lineBrokenText;

            if (motion.state.versioning && Config.get('motions_allow_disable_versioning').value) {
                obj.trivialChange = true;
            }
        };

        obj.tinymceOptions = Editor.getOptions(null, true);
        obj.tinymceOptions.readonly = 1;
        obj.tinymceOptions.setup = function (editor) {
            obj.editor = editor;
            editor.on('init', function () {
                obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
                obj.editor.setContent(obj.lineBrokenText);
                obj.originalHtml = obj.editor.getContent();
                obj.changed = false;
            });
            editor.on('change', function () {
                obj.changed = (editor.getContent() != obj.originalHtml);
            });
            editor.on('undo', function () {
                obj.changed = (editor.getContent() != obj.originalHtml);
            });
        };

        obj.setVersion = function (_motion, versionId) {
            motion = _motion; // If this is not updated,
            obj.lineBrokenText = motion.getTextWithLineBreaks(versionId);
            obj.changed = false;
            obj.active = false;
            if (obj.editor) {
                obj.editor.setContent(obj.lineBrokenText);
                obj.editor.setMode('readonly');
                obj.originalHtml = obj.editor.getContent();
            } else {
                obj.originalHtml = obj.lineBrokenText;
            }
        };

        obj.enable = function () {
            obj.editor.setMode('design');
            obj.active = true;
            obj.changed = false;

            obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
            obj.editor.setContent(obj.lineBrokenText);
            obj.originalHtml = obj.editor.getContent();
            $timeout(function () {
                obj.editor.focus();
            }, 100);
        };

        obj.disable = function () {
            obj.editor.setMode('readonly');
            obj.active = false;
            obj.changed = false;
            obj.lineBrokenText = obj.originalHtml;
            obj.editor.setContent(obj.originalHtml);
        };

        obj.save = function () {
            if (!motion.isAllowed('update')) {
                throw 'No permission to update motion';
            }

            motion.setTextStrippingLineBreaks(obj.editor.getContent());
            motion.disable_versioning = (obj.trivialChange && Config.get('motions_allow_disable_versioning').value);

            Motion.inject(motion);
            // save change motion object on server
            Motion.save(motion, {method: 'PATCH'}).then(
                function (success) {
                    $scope.showVersion(motion.getVersion(-1));
                },
                function (error) {
                    // save error: revert all changes by restore
                    // (refresh) original motion object from server
                    Motion.refresh(motion);
                    var message = '';
                    for (var e in error.data) {
                        message += e + ': ' + error.data[e] + ' ';
                    }
                    $scope.alert = {type: 'danger', msg: message, show: true};
                }
            );
        };

        return obj;
    }
])

.factory('ChangeRecommmendationCreate', [
    'ngDialog',
    'ChangeRecommendationForm',
    function(ngDialog, ChangeRecommendationForm) {
        var MODE_INACTIVE = 0,
            MODE_SELECTING_FROM = 1,
            MODE_SELECTING_TO = 2;

        var obj = {
            mode: MODE_INACTIVE,
            lineFrom: 1,
            lineTo: 2,
            html: '',
            reviewingHtml: ''
        };

        var $scope, motion, version;

        obj._getAffectedLineNumbers = function () {
            var changeRecommendations = motion.getChangeRecommendations(version),
                affectedLines = [];
            for (var i = 0; i < changeRecommendations.length; i++) {
                var change = changeRecommendations[i];
                for (var j = change.line_from; j < change.line_to; j++) {
                    affectedLines.push(j);
                }
            }
            return affectedLines;
        };

        obj.startCreating = function () {
            if (obj.mode > MODE_SELECTING_FROM || !motion.isAllowed('can_manage')) {
                return;
            }

            var $lineNumbers = $(".motion-text-original .os-line-number");
            if ($lineNumbers.filter(".selectable").length === 0) {
                obj.mode = MODE_SELECTING_FROM;
                var alreadyAffectedLines = obj._getAffectedLineNumbers();
                $lineNumbers.each(function () {
                    var $this = $(this),
                        lineNumber = $this.data("line-number");
                    if (alreadyAffectedLines.indexOf(lineNumber) == -1) {
                        $(this).addClass("selectable");
                    }
                });
            }
        };

        obj.cancelCreating = function (ev) {
            var $target = $(ev.target),
                query = ".line-numbers-outside .os-line-number.selectable";
            if (!$target.is(query) && $target.parents(query).length === 0) {
                obj.mode = MODE_INACTIVE;
                obj.lineFrom = 0;
                obj.lineTo = 0;
                $(".motion-text-original .os-line-number").removeClass("selected selectable");
                obj.startCreating();
            }
        };

        obj.setFromLine = function (line) {
            obj.mode = MODE_SELECTING_TO;
            obj.lineFrom = line;

            var alreadyAffectedLines = obj._getAffectedLineNumbers(),
                foundCollission = false;

            $(".motion-text-original .os-line-number").each(function () {

                var $this = $(this);
                if ($this.data("line-number") >= line && !foundCollission) {
                    if (alreadyAffectedLines.indexOf($this.data("line-number")) == -1) {
                        $(this).addClass("selectable");
                    } else {
                        $(this).removeClass("selectable");
                        foundCollission = true;
                    }
                } else {
                    $(this).removeClass("selectable");
                }
            });
        };

        obj.setToLine = function (line) {
            if (line < obj.lineFrom) {
                return;
            }
            obj.mode = MODE_INACTIVE;
            obj.lineTo = line + 1;
            ngDialog.open(ChangeRecommendationForm.getCreateDialog(
                motion,
                version,
                obj.lineFrom,
                obj.lineTo
            ));

            obj.lineFrom = 0;
            obj.lineTo = 0;
            $(".motion-text-original .os-line-number").removeClass("selected selectable");
            obj.startCreating();
        };

        obj.lineClicked = function (ev) {
            if (obj.mode == MODE_INACTIVE) {
                return;
            }
            if (obj.mode == MODE_SELECTING_FROM) {
                obj.setFromLine($(ev.target).data("line-number"));
                $(ev.target).addClass("selected");
            } else if (obj.mode == MODE_SELECTING_TO) {
                obj.setToLine($(ev.target).data("line-number"));
            }
        };

        obj.mouseOver = function (ev) {
            if (obj.mode != MODE_SELECTING_TO) {
                return;
            }
            var hoverLine = $(ev.target).data("line-number");
            $(".motion-text-original .os-line-number").each(function () {
                var line = $(this).data("line-number");
                if (line >= obj.lineFrom && line <= hoverLine) {
                    $(this).addClass("selected");
                } else {
                    $(this).removeClass("selected");
                }
            });
        };

        obj.setVersion = function (_motion, _version) {
            motion = _motion;
            version = _version;
        };

        obj.init = function (_scope, _motion) {
            $scope = _scope;
            motion = _motion;
            version = $scope.version;

            var $content = $("#content");
            $content.on("click", ".line-numbers-outside .os-line-number.selectable", obj.lineClicked);
            $content.on("click", obj.cancelCreating);
            $content.on("mouseover", ".line-numbers-outside .os-line-number.selectable", obj.mouseOver);
            $content.on("mouseover", ".motion-text-original", obj.startCreating);

            $scope.$on("$destroy", function () {
                obj.destroy();
            });
        };

        obj.destroy = function () {
            var $content = $("#content");
            $content.off("click", ".line-numbers-outside .os-line-number.selectable", obj.lineClicked);
            $content.off("click", obj.cancelCreating);
            $content.off("mouseover", ".line-numbers-outside .os-line-number.selectable", obj.mouseOver);
            $content.off("mouseover", ".motion-text-original", obj.startCreating);
        };

        return obj;
    }
])

.factory('ChangeRecommmendationView', [
    'Motion',
    'MotionChangeRecommendation',
    'Config',
    'lineNumberingService',
    'diffService',
    '$interval',
    '$timeout',
    function (Motion, MotionChangeRecommendation, Config, lineNumberingService, diffService, $interval, $timeout) {
        var $scope;

        var obj = {
            mode: 'original'
        };

        obj.diffFormatterCb = function (change, oldFragment, newFragment) {
            for (var i = 0; i < oldFragment.childNodes.length; i++) {
                diffService.addCSSClass(oldFragment.childNodes[i], 'delete');
            }
            for (i = 0; i < newFragment.childNodes.length; i++) {
                diffService.addCSSClass(newFragment.childNodes[i], 'insert');
            }
            var mergedFragment = document.createDocumentFragment(),
                diffSection = document.createElement('SECTION'),
                el;

            mergedFragment.appendChild(diffSection);
            diffSection.setAttribute('class', 'diff');
            diffSection.setAttribute('data-change-id', change.id);

            while (oldFragment.firstChild) {
                el = oldFragment.firstChild;
                oldFragment.removeChild(el);
                diffSection.appendChild(el);
            }
            while (newFragment.firstChild) {
                el = newFragment.firstChild;
                newFragment.removeChild(el);
                diffSection.appendChild(el);
            }

            return mergedFragment;
        };

        obj.delete = function (changeId) {
            MotionChangeRecommendation.destroy(changeId);
        };

        obj.repositionOriginalAnnotations = function () {
            var $changeRecommendationList = $('.change-recommendation-list'),
                $lineNumberReference = $('.motion-text-original');

            $changeRecommendationList.children().each(function() {
                var $this = $(this),
                    lineFrom = $this.data('line-from'),
                    lineTo = ($this.data('line-to') - 1),
                    $lineFrom = $lineNumberReference.find('.line-number-' + lineFrom),
                    $lineTo = $lineNumberReference.find('.line-number-' + lineTo),
                    fromTop = $lineFrom.position().top + 3,
                    toTop = $lineTo.position().top + 20,
                    height = (toTop - fromTop);

                if (height < 10) {
                    height = 10;
                }

                // $lineFrom.position().top seems to depend on the scrolling position when the line numbers
                // have position: absolute. Maybe a bug in the used version of jQuery?
                // This cancels the effect.
                /*
                if ($lineNumberReference.hasClass('line-numbers-outside')) {
                    fromTop += window.scrollY;
                }
                */

                $this.css({ 'top': fromTop, 'height': height });
            });
        };

        obj.newVersionIncludingChanges = function (motion, version) {
            if (!motion.isAllowed('update')) {
                throw 'No permission to update motion';
            }

            var newHtml = motion.getTextByMode('agreed');
            motion.setTextStrippingLineBreaks(newHtml);

            Motion.inject(motion);
            // save change motion object on server
            Motion.save(motion, {method: 'PATCH'}).then(
                function (success) {
                    $scope.showVersion(motion.getVersion(-1));
                },
                function (error) {
                    // save error: revert all changes by restore
                    // (refresh) original motion object from server
                    Motion.refresh(motion);
                    var message = '';
                    for (var e in error.data) {
                        message += e + ': ' + error.data[e] + ' ';
                    }
                    $scope.alert = {type: 'danger', msg: message, show: true};
                }
            );
        };

        obj.scrollToDiffBox = function (changeId) {
            obj.mode = 'diff';
            $timeout(function() {
                var $diffBox = $('.diff-box-' + changeId);
                $('html, body').animate({
                    scrollTop: $diffBox.offset().top - 50
                }, 300);
            }, 0, false);
        };

        obj.init = function (_scope, viewMode) {
            $scope = _scope;
            $scope.$evalAsync(function() {
                obj.repositionOriginalAnnotations();
            });
            $scope.$watch(function() {
                return $('.change-recommendation-list').children().length;
            }, obj.repositionOriginalAnnotations);
            $scope.$watch(function () {
                return $scope.change_recommendations.length;
            }, function () {
                if ($scope.change_recommendations.length === 0) {
                    obj.mode = 'original';
                }
            });

            var sizeCheckerLastSize = null,
                sizeCheckerLastClass = null,
                sizeChecker = $interval(function() {
                    var $holder = $(".motion-text-original"),
                        newHeight = $holder.height(),
                        classes = $holder.attr("class");
                    if (newHeight != sizeCheckerLastSize || sizeCheckerLastClass != classes) {
                        sizeCheckerLastSize = newHeight;
                        sizeCheckerLastClass = classes;
                        obj.repositionOriginalAnnotations();
                    }
                }, 100, 0, false);

            $scope.$on('$destroy', function() {
                $interval.cancel(sizeChecker);
            });

            obj.mode = viewMode;
        };

        return obj;
    }
]);

}());
<commit_msg>Bugfix: Affected lines were selectable right after creating a change recommendation<commit_after>(function () {

"use strict";

angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions', 'OpenSlidesApp.motions.lineNumbering'])

.factory('MotionPDFExport', [
    'HTMLValidizer',
    'Motion',
    'User',
    'PdfMakeConverter',
    'PdfMakeDocumentProvider',
    'PdfMakeBallotPaperProvider',
    'MotionContentProvider',
    'PollContentProvider',
    'gettextCatalog',
    '$http',
    function (HTMLValidizer, Motion, User, PdfMakeConverter, PdfMakeDocumentProvider, PdfMakeBallotPaperProvider,
            MotionContentProvider, PollContentProvider, gettextCatalog, $http) {
        var obj = {};

        var $scope;

        obj.createMotion = function() {
            var text = $scope.motion.getTextByMode($scope.viewChangeRecommendations.mode, $scope.version);
            var content = HTMLValidizer.validize(text) + HTMLValidizer.validize($scope.motion.getReason($scope.version));
            var map = Function.prototype.call.bind([].map);
            var image_sources = map($(content).find("img"), function(element) {
                return element.getAttribute("src");
            });

            $http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) {
                var converter = PdfMakeConverter.createInstance(data.images, pdfMake);
                var motionContentProvider = MotionContentProvider.createInstance(converter, $scope.motion, $scope, User, $http);
                var documentProvider = PdfMakeDocumentProvider.createInstance(motionContentProvider);
                var filename = gettextCatalog.getString("Motion") + "-" + $scope.motion.identifier + ".pdf";
                pdfMake.createPdf(documentProvider.getDocument()).download(filename);
            });
        };

        //make PDF for polls
        obj.createPoll = function() {
            var id = $scope.motion.identifier.replace(" ", "");
            var title = $scope.motion.getTitle($scope.version);
            var filename = gettextCatalog.getString("Motion") + "-" + id + "-" + gettextCatalog.getString("ballot-paper") + ".pdf";
            var pollContentProvider = PollContentProvider.createInstance(title, id, gettextCatalog);
            var documentProvider = PdfMakeBallotPaperProvider.createInstance(pollContentProvider);
            pdfMake.createPdf(documentProvider.getDocument()).download(filename);
        };

        obj.init = function (_scope) {
            $scope = _scope;
        };

        return obj;
    }
])

.factory('MotionInlineEditing', [
    'Editor',
    'Motion',
    'Config',
    '$timeout',
    function (Editor, Motion, Config, $timeout) {
        var obj = {
            active: false,
            changed: false,
            trivialChange: false,
            editor: null,
            lineBrokenText: null,
            originalHtml: null
        };

        var $scope, motion;

        obj.init = function (_scope, _motion) {
            $scope = _scope;
            motion = _motion;
            obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
            obj.originalHtml = obj.lineBrokenText;

            if (motion.state.versioning && Config.get('motions_allow_disable_versioning').value) {
                obj.trivialChange = true;
            }
        };

        obj.tinymceOptions = Editor.getOptions(null, true);
        obj.tinymceOptions.readonly = 1;
        obj.tinymceOptions.setup = function (editor) {
            obj.editor = editor;
            editor.on('init', function () {
                obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
                obj.editor.setContent(obj.lineBrokenText);
                obj.originalHtml = obj.editor.getContent();
                obj.changed = false;
            });
            editor.on('change', function () {
                obj.changed = (editor.getContent() != obj.originalHtml);
            });
            editor.on('undo', function () {
                obj.changed = (editor.getContent() != obj.originalHtml);
            });
        };

        obj.setVersion = function (_motion, versionId) {
            motion = _motion; // If this is not updated,
            obj.lineBrokenText = motion.getTextWithLineBreaks(versionId);
            obj.changed = false;
            obj.active = false;
            if (obj.editor) {
                obj.editor.setContent(obj.lineBrokenText);
                obj.editor.setMode('readonly');
                obj.originalHtml = obj.editor.getContent();
            } else {
                obj.originalHtml = obj.lineBrokenText;
            }
        };

        obj.enable = function () {
            obj.editor.setMode('design');
            obj.active = true;
            obj.changed = false;

            obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
            obj.editor.setContent(obj.lineBrokenText);
            obj.originalHtml = obj.editor.getContent();
            $timeout(function () {
                obj.editor.focus();
            }, 100);
        };

        obj.disable = function () {
            obj.editor.setMode('readonly');
            obj.active = false;
            obj.changed = false;
            obj.lineBrokenText = obj.originalHtml;
            obj.editor.setContent(obj.originalHtml);
        };

        obj.save = function () {
            if (!motion.isAllowed('update')) {
                throw 'No permission to update motion';
            }

            motion.setTextStrippingLineBreaks(obj.editor.getContent());
            motion.disable_versioning = (obj.trivialChange && Config.get('motions_allow_disable_versioning').value);

            Motion.inject(motion);
            // save change motion object on server
            Motion.save(motion, {method: 'PATCH'}).then(
                function (success) {
                    $scope.showVersion(motion.getVersion(-1));
                },
                function (error) {
                    // save error: revert all changes by restore
                    // (refresh) original motion object from server
                    Motion.refresh(motion);
                    var message = '';
                    for (var e in error.data) {
                        message += e + ': ' + error.data[e] + ' ';
                    }
                    $scope.alert = {type: 'danger', msg: message, show: true};
                }
            );
        };

        return obj;
    }
])

.factory('ChangeRecommmendationCreate', [
    'ngDialog',
    'ChangeRecommendationForm',
    function(ngDialog, ChangeRecommendationForm) {
        var MODE_INACTIVE = 0,
            MODE_SELECTING_FROM = 1,
            MODE_SELECTING_TO = 2;

        var obj = {
            mode: MODE_INACTIVE,
            lineFrom: 1,
            lineTo: 2,
            html: '',
            reviewingHtml: ''
        };

        var $scope, motion, version;

        obj._getAffectedLineNumbers = function () {
            var changeRecommendations = motion.getChangeRecommendations(version),
                affectedLines = [];
            for (var i = 0; i < changeRecommendations.length; i++) {
                var change = changeRecommendations[i];
                for (var j = change.line_from; j < change.line_to; j++) {
                    affectedLines.push(j);
                }
            }
            return affectedLines;
        };

        obj.startCreating = function () {
            if (obj.mode > MODE_SELECTING_FROM || !motion.isAllowed('can_manage')) {
                return;
            }

            var $lineNumbers = $(".motion-text-original .os-line-number");
            if ($lineNumbers.filter(".selectable").length === 0) {
                obj.mode = MODE_SELECTING_FROM;
                var alreadyAffectedLines = obj._getAffectedLineNumbers();
                $lineNumbers.each(function () {
                    var $this = $(this),
                        lineNumber = $this.data("line-number");
                    if (alreadyAffectedLines.indexOf(lineNumber) == -1) {
                        $(this).addClass("selectable");
                    }
                });
            }
        };

        obj.cancelCreating = function (ev) {
            var $target = $(ev.target),
                query = ".line-numbers-outside .os-line-number.selectable";
            if (!$target.is(query) && $target.parents(query).length === 0) {
                obj.mode = MODE_INACTIVE;
                obj.lineFrom = 0;
                obj.lineTo = 0;
                $(".motion-text-original .os-line-number").removeClass("selected selectable");
                obj.startCreating();
            }
        };

        obj.setFromLine = function (line) {
            obj.mode = MODE_SELECTING_TO;
            obj.lineFrom = line;

            var alreadyAffectedLines = obj._getAffectedLineNumbers(),
                foundCollission = false;

            $(".motion-text-original .os-line-number").each(function () {

                var $this = $(this);
                if ($this.data("line-number") >= line && !foundCollission) {
                    if (alreadyAffectedLines.indexOf($this.data("line-number")) == -1) {
                        $(this).addClass("selectable");
                    } else {
                        $(this).removeClass("selectable");
                        foundCollission = true;
                    }
                } else {
                    $(this).removeClass("selectable");
                }
            });
        };

        obj.setToLine = function (line) {
            if (line < obj.lineFrom) {
                return;
            }
            obj.mode = MODE_INACTIVE;
            obj.lineTo = line + 1;
            ngDialog.open(ChangeRecommendationForm.getCreateDialog(
                motion,
                version,
                obj.lineFrom,
                obj.lineTo
            ));

            obj.lineFrom = 0;
            obj.lineTo = 0;
            $(".motion-text-original .os-line-number").removeClass("selected selectable");
            obj.startCreating();
        };

        obj.lineClicked = function (ev) {
            if (obj.mode == MODE_INACTIVE) {
                return;
            }
            if (obj.mode == MODE_SELECTING_FROM) {
                obj.setFromLine($(ev.target).data("line-number"));
                $(ev.target).addClass("selected");
            } else if (obj.mode == MODE_SELECTING_TO) {
                obj.setToLine($(ev.target).data("line-number"));
            }
        };

        obj.mouseOver = function (ev) {
            if (obj.mode != MODE_SELECTING_TO) {
                return;
            }
            var hoverLine = $(ev.target).data("line-number");
            $(".motion-text-original .os-line-number").each(function () {
                var line = $(this).data("line-number");
                if (line >= obj.lineFrom && line <= hoverLine) {
                    $(this).addClass("selected");
                } else {
                    $(this).removeClass("selected");
                }
            });
        };

        obj.setVersion = function (_motion, _version) {
            motion = _motion;
            version = _version;
        };

        obj.init = function (_scope, _motion) {
            $scope = _scope;
            motion = _motion;
            version = $scope.version;

            var $content = $("#content");
            $content.on("click", ".line-numbers-outside .os-line-number.selectable", obj.lineClicked);
            $content.on("click", obj.cancelCreating);
            $content.on("mouseover", ".line-numbers-outside .os-line-number.selectable", obj.mouseOver);
            $content.on("mouseover", ".motion-text-original", obj.startCreating);

            $scope.$watch(function () {
                return $scope.change_recommendations.length;
            }, function () {
                if (obj.mode == MODE_INACTIVE || obj.mode == MODE_SELECTING_FROM) {
                    // Recalculate the affected lines so we cannot select lines affected by a recommendation
                    // that has just been created
                    $(".motion-text-original .os-line-number").removeClass("selected selectable");
                    obj.startCreating();
                }
            });

            $scope.$on("$destroy", function () {
                obj.destroy();
            });
        };

        obj.destroy = function () {
            var $content = $("#content");
            $content.off("click", ".line-numbers-outside .os-line-number.selectable", obj.lineClicked);
            $content.off("click", obj.cancelCreating);
            $content.off("mouseover", ".line-numbers-outside .os-line-number.selectable", obj.mouseOver);
            $content.off("mouseover", ".motion-text-original", obj.startCreating);
        };

        return obj;
    }
])

.factory('ChangeRecommmendationView', [
    'Motion',
    'MotionChangeRecommendation',
    'Config',
    'lineNumberingService',
    'diffService',
    '$interval',
    '$timeout',
    function (Motion, MotionChangeRecommendation, Config, lineNumberingService, diffService, $interval, $timeout) {
        var $scope;

        var obj = {
            mode: 'original'
        };

        obj.diffFormatterCb = function (change, oldFragment, newFragment) {
            for (var i = 0; i < oldFragment.childNodes.length; i++) {
                diffService.addCSSClass(oldFragment.childNodes[i], 'delete');
            }
            for (i = 0; i < newFragment.childNodes.length; i++) {
                diffService.addCSSClass(newFragment.childNodes[i], 'insert');
            }
            var mergedFragment = document.createDocumentFragment(),
                diffSection = document.createElement('SECTION'),
                el;

            mergedFragment.appendChild(diffSection);
            diffSection.setAttribute('class', 'diff');
            diffSection.setAttribute('data-change-id', change.id);

            while (oldFragment.firstChild) {
                el = oldFragment.firstChild;
                oldFragment.removeChild(el);
                diffSection.appendChild(el);
            }
            while (newFragment.firstChild) {
                el = newFragment.firstChild;
                newFragment.removeChild(el);
                diffSection.appendChild(el);
            }

            return mergedFragment;
        };

        obj.delete = function (changeId) {
            MotionChangeRecommendation.destroy(changeId);
        };

        obj.repositionOriginalAnnotations = function () {
            var $changeRecommendationList = $('.change-recommendation-list'),
                $lineNumberReference = $('.motion-text-original');

            $changeRecommendationList.children().each(function() {
                var $this = $(this),
                    lineFrom = $this.data('line-from'),
                    lineTo = ($this.data('line-to') - 1),
                    $lineFrom = $lineNumberReference.find('.line-number-' + lineFrom),
                    $lineTo = $lineNumberReference.find('.line-number-' + lineTo),
                    fromTop = $lineFrom.position().top + 3,
                    toTop = $lineTo.position().top + 20,
                    height = (toTop - fromTop);

                if (height < 10) {
                    height = 10;
                }

                // $lineFrom.position().top seems to depend on the scrolling position when the line numbers
                // have position: absolute. Maybe a bug in the used version of jQuery?
                // This cancels the effect.
                /*
                if ($lineNumberReference.hasClass('line-numbers-outside')) {
                    fromTop += window.scrollY;
                }
                */

                $this.css({ 'top': fromTop, 'height': height });
            });
        };

        obj.newVersionIncludingChanges = function (motion, version) {
            if (!motion.isAllowed('update')) {
                throw 'No permission to update motion';
            }

            var newHtml = motion.getTextByMode('agreed');
            motion.setTextStrippingLineBreaks(newHtml);

            Motion.inject(motion);
            // save change motion object on server
            Motion.save(motion, {method: 'PATCH'}).then(
                function (success) {
                    $scope.showVersion(motion.getVersion(-1));
                },
                function (error) {
                    // save error: revert all changes by restore
                    // (refresh) original motion object from server
                    Motion.refresh(motion);
                    var message = '';
                    for (var e in error.data) {
                        message += e + ': ' + error.data[e] + ' ';
                    }
                    $scope.alert = {type: 'danger', msg: message, show: true};
                }
            );
        };

        obj.scrollToDiffBox = function (changeId) {
            obj.mode = 'diff';
            $timeout(function() {
                var $diffBox = $('.diff-box-' + changeId);
                $('html, body').animate({
                    scrollTop: $diffBox.offset().top - 50
                }, 300);
            }, 0, false);
        };

        obj.init = function (_scope, viewMode) {
            $scope = _scope;
            $scope.$evalAsync(function() {
                obj.repositionOriginalAnnotations();
            });
            $scope.$watch(function() {
                return $('.change-recommendation-list').children().length;
            }, obj.repositionOriginalAnnotations);
            $scope.$watch(function () {
                return $scope.change_recommendations.length;
            }, function () {
                if ($scope.change_recommendations.length === 0) {
                    obj.mode = 'original';
                }
            });

            var sizeCheckerLastSize = null,
                sizeCheckerLastClass = null,
                sizeChecker = $interval(function() {
                    var $holder = $(".motion-text-original"),
                        newHeight = $holder.height(),
                        classes = $holder.attr("class");
                    if (newHeight != sizeCheckerLastSize || sizeCheckerLastClass != classes) {
                        sizeCheckerLastSize = newHeight;
                        sizeCheckerLastClass = classes;
                        obj.repositionOriginalAnnotations();
                    }
                }, 100, 0, false);

            $scope.$on('$destroy', function() {
                $interval.cancel(sizeChecker);
            });

            obj.mode = viewMode;
        };

        return obj;
    }
]);

}());
<|endoftext|>


<commit_before>/**
 * @providesModule YouTube
 * @flow
 */

'use strict';

import React, { Component, PropTypes } from 'react';
import ReactNative, {
  View,
  StyleSheet,
  requireNativeComponent,
  NativeModules,
} from 'react-native';

const RCTYouTube = requireNativeComponent('RCTYouTube', null);

export default class YouTube extends Component {
  static propTypes = {
    style: View.propTypes.style,
    videoId: PropTypes.string.isRequired,
    playsInline: PropTypes.bool,
    showinfo: PropTypes.bool,
    modestbranding: PropTypes.bool,
    controls: PropTypes.oneOf([0,1,2]),
    origin: PropTypes.string,
    play: PropTypes.bool,
    rel: PropTypes.bool,
    hidden: PropTypes.bool,
    onReady: PropTypes.func,
    onChangeState: PropTypes.func,
    onChangeQuality: PropTypes.func,
    onError: PropTypes.func,
    loop: PropTypes.bool,
  };

  static defaultProps = {
    loop: false
  };

  setNativeProps(nativeProps) {
    this._root.setNativeProps(nativeProps);
  }

  constructor(props) {
    super(props);
    this._exportedProps = NativeModules.YouTubeManager && NativeModules.YouTubeManager.exportedProps;
  }

  _onReady(event) {
    return this.props.onReady && this.props.onReady(event.nativeEvent);
  }

  _onChangeState(event) {
    if(event.nativeEvent.state == 'ended' && this.props.loop) {
      this.seekTo(0);
    }
    return this.props.onChangeState && this.props.onChangeState(event.nativeEvent);
  }

  _onChangeQuality(event) {
    return this.props.onChangeQuality && this.props.onChangeQuality(event.nativeEvent);
  }

  _onError(event) {
    return this.props.onError && this.props.onError(event.nativeEvent);
  }
  _onProgress(event){
      return this.props.onProgress && this.props.onProgress(event.nativeEvent);
  }
  seekTo(seconds){
    NativeModules.YouTubeManager.seekTo(ReactNative.findNodeHandle(this), parseInt(seconds, 10));
  }
  render() {
    var style = [styles.base, this.props.style];
    var nativeProps = Object.assign({}, this.props);
    nativeProps.style = style;
    nativeProps.onYoutubeVideoReady = this._onReady.bind(this);
    nativeProps.onYoutubeVideoChangeState = this._onChangeState.bind(this);
    nativeProps.onYoutubeVideoChangeQuality = this._onChangeQuality.bind(this);
    nativeProps.onYoutubeVideoError = this._onError.bind(this);
    nativeProps.onYoutubeProgress = this._onProgress.bind(this);
    return <RCTYouTube ref={component => this._root = component} {...nativeProps} />;
  }

  componentDidUpdate() {
    var nativeProps = Object.assign({}, this.props);
    /*
     * Try to use `playerParams` instead of settings `playsInline` and
     * `videoId` individually.
     */
    if (this._exportedProps) {
      if (this._exportedProps.playerParams) {
        nativeProps.playerParams = {
          videoId: this.props.videoId,
        };
        // Make sure we leave it in as the nativeProps,
        // since future setNativeProps() calls will depend on it existing.
        //delete nativeProps.videoId;

        nativeProps.playerParams.playerVars = {};

        if (this.props.playsInline) {
          nativeProps.playerParams.playerVars.playsinline = 1;
          delete nativeProps.playsInline;
        };
        if (this.props.modestbranding) {
          nativeProps.playerParams.playerVars.modestbranding = 1;
          delete nativeProps.modestbranding;
        };

        if (this.props.showinfo!==undefined) {
          nativeProps.playerParams.playerVars.showinfo = this.props.showinfo ? 1 : 0;
          delete nativeProps.showinfo;
        };
        if (this.props.controls!==undefined) {
          nativeProps.playerParams.playerVars.controls = this.props.controls;
          delete nativeProps.controls;
        };
        if (this.props.origin!==undefined) {
          nativeProps.playerParams.playerVars.origin = this.props.origin;
          delete nativeProps.origin;
        };
        if (this.props.rel!==undefined) {
          nativeProps.playerParams.playerVars.rel = this.props.rel ? 1 : 0;
          delete nativeProps.rel;
        };
      };
    } else {
      /*
       * For compatibility issues with an older version where setting both
       * `playsInline` and `videoId` in quick succession would cause the video
       * to sometimes not play.
       */
      delete nativeProps.playsInline;
    }
    this._root.setNativeProps(nativeProps);
  }
}

const styles = StyleSheet.create({
  base: {
    overflow: 'hidden',
  },
});
<commit_msg>Fix flow errors.<commit_after>/**
 * @providesModule YouTube
 * @flow
 */

'use strict';

import React, { Component, PropTypes } from 'react';
import ReactNative, {
  View,
  StyleSheet,
  requireNativeComponent,
  NativeModules,
} from 'react-native';

const RCTYouTube = requireNativeComponent('RCTYouTube', null);

export default class YouTube extends Component {
  static propTypes = {
    style: View.propTypes.style,
    videoId: PropTypes.string.isRequired,
    playsInline: PropTypes.bool,
    showinfo: PropTypes.bool,
    modestbranding: PropTypes.bool,
    controls: PropTypes.oneOf([0,1,2]),
    origin: PropTypes.string,
    play: PropTypes.bool,
    rel: PropTypes.bool,
    hidden: PropTypes.bool,
    onReady: PropTypes.func,
    onChangeState: PropTypes.func,
    onChangeQuality: PropTypes.func,
    onError: PropTypes.func,
    loop: PropTypes.bool,
  };

  static defaultProps = {
    loop: false
  };

  _root: any;
  _exportedProps: any;

  setNativeProps(nativeProps: any) {
    this._root.setNativeProps(nativeProps);
  }

  constructor(props: any) {
    super(props);
    this._exportedProps = NativeModules.YouTubeManager && NativeModules.YouTubeManager.exportedProps;
  }

  _onReady(event: SyntheticEvent) {
    return this.props.onReady && this.props.onReady(event.nativeEvent);
  }

  _onChangeState(event: SyntheticEvent) {
    if(event.nativeEvent.state == 'ended' && this.props.loop) {
      this.seekTo(0);
    }
    return this.props.onChangeState && this.props.onChangeState(event.nativeEvent);
  }

  _onChangeQuality(event: SyntheticEvent) {
    return this.props.onChangeQuality && this.props.onChangeQuality(event.nativeEvent);
  }

  _onError(event: SyntheticEvent) {
    return this.props.onError && this.props.onError(event.nativeEvent);
  }
  _onProgress(event: SyntheticEvent){
      return this.props.onProgress && this.props.onProgress(event.nativeEvent);
  }
  seekTo(seconds: number){
    NativeModules.YouTubeManager.seekTo(ReactNative.findNodeHandle(this), parseInt(seconds, 10));
  }
  render() {
    var style = [styles.base, this.props.style];
    var nativeProps = Object.assign({}, this.props);
    nativeProps.style = style;
    nativeProps.onYoutubeVideoReady = this._onReady.bind(this);
    nativeProps.onYoutubeVideoChangeState = this._onChangeState.bind(this);
    nativeProps.onYoutubeVideoChangeQuality = this._onChangeQuality.bind(this);
    nativeProps.onYoutubeVideoError = this._onError.bind(this);
    nativeProps.onYoutubeProgress = this._onProgress.bind(this);
    return <RCTYouTube ref={component => this._root = component} {...nativeProps} />;
  }

  componentDidUpdate() {
    var nativeProps = Object.assign({}, this.props);
    /*
     * Try to use `playerParams` instead of settings `playsInline` and
     * `videoId` individually.
     */
    if (this._exportedProps) {
      if (this._exportedProps.playerParams) {
        nativeProps.playerParams = {
          videoId: this.props.videoId,
          playerVars: {},
        };
        // Make sure we leave it in as the nativeProps,
        // since future setNativeProps() calls will depend on it existing.
        //delete nativeProps.videoId;

        if (this.props.playsInline) {
          nativeProps.playerParams.playerVars.playsinline = 1;
          delete nativeProps.playsInline;
        };
        if (this.props.modestbranding) {
          nativeProps.playerParams.playerVars.modestbranding = 1;
          delete nativeProps.modestbranding;
        };

        if (this.props.showinfo!==undefined) {
          nativeProps.playerParams.playerVars.showinfo = this.props.showinfo ? 1 : 0;
          delete nativeProps.showinfo;
        };
        if (this.props.controls!==undefined) {
          nativeProps.playerParams.playerVars.controls = this.props.controls;
          delete nativeProps.controls;
        };
        if (this.props.origin!==undefined) {
          nativeProps.playerParams.playerVars.origin = this.props.origin;
          delete nativeProps.origin;
        };
        if (this.props.rel!==undefined) {
          nativeProps.playerParams.playerVars.rel = this.props.rel ? 1 : 0;
          delete nativeProps.rel;
        };
      };
    } else {
      /*
       * For compatibility issues with an older version where setting both
       * `playsInline` and `videoId` in quick succession would cause the video
       * to sometimes not play.
       */
      delete nativeProps.playsInline;
    }
    this._root.setNativeProps(nativeProps);
  }
}

const styles = StyleSheet.create({
  base: {
    overflow: 'hidden',
  },
});
<|endoftext|>


<commit_before>module.exports = function utility(bot, info)
{
  'use strict';
  const Datastore = require('nedb');
  const db = {};
  db.servers = new Datastore('./lib/databases/servers.db');
  db.servers.loadDatabase();
  //set autocompaction to compact every 10 minutes
  db.servers.persistence.setAutocompactionInterval(600000);
  function loadCommands()
  {
    return new Promise((resolve, reject) =>
    {
      let commandsArr = [];
      let commands = Object.keys(info.commands).filter((command) =>
      {
        if(info.commands[command].name != undefined)
        {
          return command;
        }
      });
      for(let i = 0; i < commands.length; i++)
      {
        let commandObj = {key: commands[i], name: info.commands[commands[i]].name, enabled: true};
        commandsArr.push(commandObj);

      }
      resolve(commandsArr);
    });

  }

  bot.on('guildCreate', (server) =>
  {
    console.log(server.name);
    db.newServer(server.id);
  });
  bot.on('guildDelete', (server) =>
  {
    console.log(`Left ${server.name}`);
    info.botList.updateBotLists();
  })
  db.newServer = function (serverID)
  {
    loadCommands().then((commands) =>
    {
      let doc = {
        '_id': serverID,
        'prefix': info.config.prefix,
        'commands': commands
      };

      db.servers.insert(doc, (err, newDoc) =>
      {
        //console.log(newDoc);
        if(!err)
        {
          info.botList.updateBotLists();
        }
      });
    });

  };
  db.findServer = function(serverID)
  {
    return new Promise((resolve, reject) =>
    {
      db.servers.findOne({_id: serverID}, (err, doc) =>
      {
        //console.log(doc);
        resolve(doc);
      });
    });
  };
  db.getSettings = function(serverID)
  {
    return new Promise((resolve, reject) =>
    {
      db.servers.findOne({_id: serverID}, (err, doc) =>
      {
        if(err)
        {
          reject(err);
        }
        else
        {
          if(doc === null)
          {
            resolve(null);
          }
          else
          {
            resolve({prefix: doc.prefix});
          }
        }
      });
    });
  };
  db.updateServer = function(serverID, changes)
  {
    db.servers.update({_id: serverID}, {$set: changes}, (err, numReplaced) =>
    {
      if(err)
      {
        console.log(err);
      }
      else
      {
        console.log(numReplaced);
      }
    });
  };
  db.checkEnabled = function(serverID, command)
  {
    return new Promise((resolve, reject) =>
    {
      db.servers.findOne({_id: serverID}, (err, doc) =>
      {
        if(err)
        {
          console.log(err);
        }
        else
        {
          //this should be whether or not a command is enabled or not SHOULD
          let commands = doc.commands;
          for(let i = 0; i < commands.length; i ++)
          {
            if(commands[i].key === command)
            {
              resolve(commands[i].enabled);
            }
          }
          resolve(false);
        }
      });
    });
  };
  db.addCommand = function(commandName, currentSize)
  {
    return new Promise((resolve, reject) =>
    {
      let commandObj = {key: commandName, name: info.commands[commandName].name, enabled: true};
      db.servers.update({commands: {$size: currentSize}}, {$push: {commands: commandObj}}, {multi: true}, (err, numAffected) =>
      {
        if(err)
        {
          reject(err);
        }
        resolve(numAffected);
      });
    });
  };
  db.deleteServer = function(serverID)
  {
    db.servers.remove({_id: serverID}, {}, (err, numRemoved) =>
    {
      if(err)
      {
        console.log(err)
      }
      else
      {
        info.botList.updateBotLists();
      }
    });
  };
  return db;
};<commit_msg>Update db.js<commit_after>module.exports = function utility(bot, info)
{
  'use strict';
  const Datastore = require('nedb');
  const db = {};
  db.servers = new Datastore('./lib/databases/servers.db');
  db.servers.loadDatabase();
  //set autocompaction to compact every 10 minutes
  db.servers.persistence.setAutocompactionInterval(600000);
  function loadCommands()
  {
    return new Promise((resolve, reject) =>
    {
      let commandsArr = [];
      let commands = Object.keys(info.commands).filter((command) =>
      {
        if(info.commands[command].name != undefined)
        {
          return command;
        }
      });
      for(let i = 0; i < commands.length; i++)
      {
        let commandObj = {key: commands[i], name: info.commands[commands[i]].name, enabled: true};
        commandsArr.push(commandObj);

      }
      resolve(commandsArr);
    });

  }

  bot.on('guildCreate', (server) =>
  {
    console.log(server.name);
    db.newServer(server.id);
  });
  bot.on('guildDelete', (server) =>
  {
    console.log(`Left ${server.name}`);
    db.deleteServer(server.id);
  })
  db.newServer = function (serverID)
  {
    loadCommands().then((commands) =>
    {
      let doc = {
        '_id': serverID,
        'prefix': info.config.prefix,
        'commands': commands
      };

      db.servers.insert(doc, (err, newDoc) =>
      {
        //console.log(newDoc);
        if(!err)
        {
          info.botList.updateBotLists();
        }
      });
    });

  };
  db.findServer = function(serverID)
  {
    return new Promise((resolve, reject) =>
    {
      db.servers.findOne({_id: serverID}, (err, doc) =>
      {
        //console.log(doc);
        resolve(doc);
      });
    });
  };
  db.getSettings = function(serverID)
  {
    return new Promise((resolve, reject) =>
    {
      db.servers.findOne({_id: serverID}, (err, doc) =>
      {
        if(err)
        {
          reject(err);
        }
        else
        {
          if(doc === null)
          {
            resolve(null);
          }
          else
          {
            resolve({prefix: doc.prefix});
          }
        }
      });
    });
  };
  db.updateServer = function(serverID, changes)
  {
    db.servers.update({_id: serverID}, {$set: changes}, (err, numReplaced) =>
    {
      if(err)
      {
        console.log(err);
      }
      else
      {
        console.log(numReplaced);
      }
    });
  };
  db.checkEnabled = function(serverID, command)
  {
    return new Promise((resolve, reject) =>
    {
      db.servers.findOne({_id: serverID}, (err, doc) =>
      {
        if(err)
        {
          console.log(err);
        }
        else
        {
          //this should be whether or not a command is enabled or not SHOULD
          let commands = doc.commands;
          for(let i = 0; i < commands.length; i ++)
          {
            if(commands[i].key === command)
            {
              resolve(commands[i].enabled);
            }
          }
          resolve(false);
        }
      });
    });
  };
  db.addCommand = function(commandName, currentSize)
  {
    return new Promise((resolve, reject) =>
    {
      let commandObj = {key: commandName, name: info.commands[commandName].name, enabled: true};
      db.servers.update({commands: {$size: currentSize}}, {$push: {commands: commandObj}}, {multi: true}, (err, numAffected) =>
      {
        if(err)
        {
          reject(err);
        }
        resolve(numAffected);
      });
    });
  };
  db.deleteServer = function(serverID)
  {
    db.servers.remove({_id: serverID}, {}, (err, numRemoved) =>
    {
      if(err)
      {
        console.log(err)
      }
      else
      {
        info.botList.updateBotLists();
      }
    });
  };
  return db;
};
<|endoftext|>


<commit_before>import { latLng, latLngBounds, LatLng, LatLngBounds, Util, DomUtil, GeoJSON } from 'leaflet';
import { jsonp } from './Request';
import { options } from './Options';

import {
  geojsonToArcGIS as g2a,
  arcgisToGeoJSON as a2g
} from '@esri/arcgis-to-geojson-utils';

export function geojsonToArcGIS (geojson, idAttr) {
  return g2a(geojson, idAttr);
}

export function arcgisToGeoJSON (arcgis, idAttr) {
  return a2g(arcgis, idAttr);
}

// convert an extent (ArcGIS) to LatLngBounds (Leaflet)
export function extentToBounds (extent) {
  // "NaN" coordinates from ArcGIS Server indicate a null geometry
  if (extent.xmin !== 'NaN' && extent.ymin !== 'NaN' && extent.xmax !== 'NaN' && extent.ymax !== 'NaN') {
    var sw = latLng(extent.ymin, extent.xmin);
    var ne = latLng(extent.ymax, extent.xmax);
    return latLngBounds(sw, ne);
  } else {
    return null;
  }
}

// convert an LatLngBounds (Leaflet) to extent (ArcGIS)
export function boundsToExtent (bounds) {
  bounds = latLngBounds(bounds);
  return {
    'xmin': bounds.getSouthWest().lng,
    'ymin': bounds.getSouthWest().lat,
    'xmax': bounds.getNorthEast().lng,
    'ymax': bounds.getNorthEast().lat,
    'spatialReference': {
      'wkid': 4326
    }
  };
}

var knownFieldNames = /^(OBJECTID|FID|OID|ID)$/i;

// Attempts to find the ID Field from response
export function _findIdAttributeFromResponse (response) {
  var result;

  if (response.objectIdFieldName) {
    // Find Id Field directly
    result = response.objectIdFieldName;
  } else if (response.fields) {
    // Find ID Field based on field type
    for (var j = 0; j <= response.fields.length - 1; j++) {
      if (response.fields[j].type === 'esriFieldTypeOID') {
        result = response.fields[j].name;
        break;
      }
    }
    if (!result) {
      // If no field was marked as being the esriFieldTypeOID try well known field names
      for (j = 0; j <= response.fields.length - 1; j++) {
        if (response.fields[j].name.match(knownFieldNames)) {
          result = response.fields[j].name;
          break;
        }
      }
    }
  }
  return result;
}

// This is the 'last' resort, find the Id field from the specified feature
export function _findIdAttributeFromFeature (feature) {
  for (var key in feature.attributes) {
    if (key.match(knownFieldNames)) {
      return key;
    }
  }
}

export function responseToFeatureCollection (response, idAttribute) {
  var objectIdField;
  var features = response.features || response.results;
  var count = features.length;

  if (idAttribute) {
    objectIdField = idAttribute;
  } else {
    objectIdField = _findIdAttributeFromResponse(response);
  }

  var featureCollection = {
    type: 'FeatureCollection',
    features: []
  };

  if (count) {
    for (var i = features.length - 1; i >= 0; i--) {
      var feature = arcgisToGeoJSON(features[i], objectIdField || _findIdAttributeFromFeature(features[i]));
      featureCollection.features.push(feature);
    }
  }

  return featureCollection;
}

  // trim url whitespace and add a trailing slash if needed
export function cleanUrl (url) {
  // trim leading and trailing spaces, but not spaces inside the url
  url = Util.trim(url);

  // add a trailing slash to the url if the user omitted it
  if (url[url.length - 1] !== '/') {
    url += '/';
  }

  return url;
}

/* Extract url params if any and store them in requestParams attribute.
   Return the options params updated */
export function getUrlParams (options) {
  if (options.url.indexOf('?') !== -1) {
    options.requestParams = options.requestParams || {};
    var queryString = options.url.substring(options.url.indexOf('?') + 1);
    options.url = options.url.split('?')[0];
    options.requestParams = JSON.parse('{"' + decodeURI(queryString).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}');
  }
  options.url = cleanUrl(options.url.split('?')[0]);
  return options;
}

export function isArcgisOnline (url) {
  /* hosted feature services support geojson as an output format
  utility.arcgis.com services are proxied from a variety of ArcGIS Server vintages, and may not */
  return (/^(?!.*utility\.arcgis\.com).*\.arcgis\.com.*FeatureServer/i).test(url);
}

export function geojsonTypeToArcGIS (geoJsonType) {
  var arcgisGeometryType;
  switch (geoJsonType) {
    case 'Point':
      arcgisGeometryType = 'esriGeometryPoint';
      break;
    case 'MultiPoint':
      arcgisGeometryType = 'esriGeometryMultipoint';
      break;
    case 'LineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'MultiLineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'Polygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
    case 'MultiPolygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
  }

  return arcgisGeometryType;
}

export function warn () {
  if (console && console.warn) {
    console.warn.apply(console, arguments);
  }
}

export function calcAttributionWidth (map) {
  // either crop at 55px or user defined buffer
  return (map.getSize().x - options.attributionWidthOffset) + 'px';
}

export function setEsriAttribution (map) {
  if (map.attributionControl && !map.attributionControl._esriAttributionAdded) {
    map.attributionControl.setPrefix('Leaflet | Powered by Esri');

    var hoverAttributionStyle = document.createElement('style');
    hoverAttributionStyle.type = 'text/css';
    hoverAttributionStyle.innerHTML = '.esri-truncated-attribution:hover {' +
      'white-space: normal;' +
    '}';

    document.getElementsByTagName('head')[0].appendChild(hoverAttributionStyle);
    DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution:hover');

    // define a new css class in JS to trim attribution into a single line
    var attributionStyle = document.createElement('style');
    attributionStyle.type = 'text/css';
    attributionStyle.innerHTML = '.esri-truncated-attribution {' +
      'vertical-align: -3px;' +
      'white-space: nowrap;' +
      'overflow: hidden;' +
      'text-overflow: ellipsis;' +
      'display: inline-block;' +
      'transition: 0s white-space;' +
      'transition-delay: 1s;' +
      'max-width: ' + calcAttributionWidth(map) + ';' +
    '}';

    document.getElementsByTagName('head')[0].appendChild(attributionStyle);
    DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution');

    // update the width used to truncate when the map itself is resized
    map.on('resize', function (e) {
      map.attributionControl._container.style.maxWidth = calcAttributionWidth(e.target);
    });

    // remove injected scripts and style tags
    map.on('unload', function () {
      hoverAttributionStyle.parentNode.removeChild(hoverAttributionStyle);
      attributionStyle.parentNode.removeChild(attributionStyle);
      var nodeList = document.querySelectorAll('.esri-leaflet-jsonp');
      for (var i = 0; i < nodeList.length; i++) {
        nodeList.item(i).parentNode.removeChild(nodeList.item(i));
      }
    });

    map.attributionControl._esriAttributionAdded = true;
  }
}

export function _setGeometry (geometry) {
  var params = {
    geometry: null,
    geometryType: null
  };

  // convert bounds to extent and finish
  if (geometry instanceof LatLngBounds) {
    // set geometry + geometryType
    params.geometry = boundsToExtent(geometry);
    params.geometryType = 'esriGeometryEnvelope';
    return params;
  }

  // convert L.Marker > L.LatLng
  if (geometry.getLatLng) {
    geometry = geometry.getLatLng();
  }

  // convert L.LatLng to a geojson point and continue;
  if (geometry instanceof LatLng) {
    geometry = {
      type: 'Point',
      coordinates: [geometry.lng, geometry.lat]
    };
  }

  // handle L.GeoJSON, pull out the first geometry
  if (geometry instanceof GeoJSON) {
    // reassign geometry to the GeoJSON value  (we are assuming that only one feature is present)
    geometry = geometry.getLayers()[0].feature.geometry;
    params.geometry = geojsonToArcGIS(geometry);
    params.geometryType = geojsonTypeToArcGIS(geometry.type);
  }

  // Handle L.Polyline and L.Polygon
  if (geometry.toGeoJSON) {
    geometry = geometry.toGeoJSON();
  }

  // handle GeoJSON feature by pulling out the geometry
  if (geometry.type === 'Feature') {
    // get the geometry of the geojson feature
    geometry = geometry.geometry;
  }

  // confirm that our GeoJSON is a point, line or polygon
  if (geometry.type === 'Point' || geometry.type === 'LineString' || geometry.type === 'Polygon' || geometry.type === 'MultiPolygon') {
    params.geometry = geojsonToArcGIS(geometry);
    params.geometryType = geojsonTypeToArcGIS(geometry.type);
    return params;
  }

  // warn the user if we havn't found an appropriate object
  warn('invalid geometry passed to spatial query. Should be L.LatLng, L.LatLngBounds, L.Marker or a GeoJSON Point, Line, Polygon or MultiPolygon object');

  return;
}

export function _getAttributionData (url, map) {
  jsonp(url, {}, Util.bind(function (error, attributions) {
    if (error) { return; }
    map._esriAttributions = [];
    for (var c = 0; c < attributions.contributors.length; c++) {
      var contributor = attributions.contributors[c];

      for (var i = 0; i < contributor.coverageAreas.length; i++) {
        var coverageArea = contributor.coverageAreas[i];
        var southWest = latLng(coverageArea.bbox[0], coverageArea.bbox[1]);
        var northEast = latLng(coverageArea.bbox[2], coverageArea.bbox[3]);
        map._esriAttributions.push({
          attribution: contributor.attribution,
          score: coverageArea.score,
          bounds: latLngBounds(southWest, northEast),
          minZoom: coverageArea.zoomMin,
          maxZoom: coverageArea.zoomMax
        });
      }
    }

    map._esriAttributions.sort(function (a, b) {
      return b.score - a.score;
    });

    // pass the same argument as the map's 'moveend' event
    var obj = { target: map };
    _updateMapAttribution(obj);
  }, this));
}

export function _updateMapAttribution (evt) {
  var map = evt.target;
  var oldAttributions = map._esriAttributions;

  if (!map || !map.attributionControl) return;

  var attributionElement = map.attributionControl._container.querySelector('.esri-dynamic-attribution');

  if (attributionElement && oldAttributions) {
    var newAttributions = '';
    var bounds = map.getBounds();
    var wrappedBounds = latLngBounds(
      bounds.getSouthWest().wrap(),
      bounds.getNorthEast().wrap()
    );
    var zoom = map.getZoom();

    for (var i = 0; i < oldAttributions.length; i++) {
      var attribution = oldAttributions[i];
      var text = attribution.attribution;

      if (!newAttributions.match(text) && attribution.bounds.intersects(wrappedBounds) && zoom >= attribution.minZoom && zoom <= attribution.maxZoom) {
        newAttributions += (', ' + text);
      }
    }

    newAttributions = newAttributions.substr(2);
    attributionElement.innerHTML = newAttributions;
    attributionElement.style.maxWidth = calcAttributionWidth(map);

    map.fire('attributionupdated', {
      attribution: newAttributions
    });
  }
}

export var EsriUtil = {
  warn: warn,
  cleanUrl: cleanUrl,
  getUrlParams: getUrlParams,
  isArcgisOnline: isArcgisOnline,
  geojsonTypeToArcGIS: geojsonTypeToArcGIS,
  responseToFeatureCollection: responseToFeatureCollection,
  geojsonToArcGIS: geojsonToArcGIS,
  arcgisToGeoJSON: arcgisToGeoJSON,
  boundsToExtent: boundsToExtent,
  extentToBounds: extentToBounds,
  calcAttributionWidth: calcAttributionWidth,
  setEsriAttribution: setEsriAttribution,
  _setGeometry: _setGeometry,
  _getAttributionData: _getAttributionData,
  _updateMapAttribution: _updateMapAttribution,
  _findIdAttributeFromFeature: _findIdAttributeFromFeature,
  _findIdAttributeFromResponse: _findIdAttributeFromResponse
};

export default EsriUtil;
<commit_msg>dont use jsonp to fetch dynamic attribution<commit_after>import { latLng, latLngBounds, LatLng, LatLngBounds, Util, DomUtil, GeoJSON } from 'leaflet';
import { request } from './Request';
import { options } from './Options';

import {
  geojsonToArcGIS as g2a,
  arcgisToGeoJSON as a2g
} from '@esri/arcgis-to-geojson-utils';

export function geojsonToArcGIS (geojson, idAttr) {
  return g2a(geojson, idAttr);
}

export function arcgisToGeoJSON (arcgis, idAttr) {
  return a2g(arcgis, idAttr);
}

// convert an extent (ArcGIS) to LatLngBounds (Leaflet)
export function extentToBounds (extent) {
  // "NaN" coordinates from ArcGIS Server indicate a null geometry
  if (extent.xmin !== 'NaN' && extent.ymin !== 'NaN' && extent.xmax !== 'NaN' && extent.ymax !== 'NaN') {
    var sw = latLng(extent.ymin, extent.xmin);
    var ne = latLng(extent.ymax, extent.xmax);
    return latLngBounds(sw, ne);
  } else {
    return null;
  }
}

// convert an LatLngBounds (Leaflet) to extent (ArcGIS)
export function boundsToExtent (bounds) {
  bounds = latLngBounds(bounds);
  return {
    'xmin': bounds.getSouthWest().lng,
    'ymin': bounds.getSouthWest().lat,
    'xmax': bounds.getNorthEast().lng,
    'ymax': bounds.getNorthEast().lat,
    'spatialReference': {
      'wkid': 4326
    }
  };
}

var knownFieldNames = /^(OBJECTID|FID|OID|ID)$/i;

// Attempts to find the ID Field from response
export function _findIdAttributeFromResponse (response) {
  var result;

  if (response.objectIdFieldName) {
    // Find Id Field directly
    result = response.objectIdFieldName;
  } else if (response.fields) {
    // Find ID Field based on field type
    for (var j = 0; j <= response.fields.length - 1; j++) {
      if (response.fields[j].type === 'esriFieldTypeOID') {
        result = response.fields[j].name;
        break;
      }
    }
    if (!result) {
      // If no field was marked as being the esriFieldTypeOID try well known field names
      for (j = 0; j <= response.fields.length - 1; j++) {
        if (response.fields[j].name.match(knownFieldNames)) {
          result = response.fields[j].name;
          break;
        }
      }
    }
  }
  return result;
}

// This is the 'last' resort, find the Id field from the specified feature
export function _findIdAttributeFromFeature (feature) {
  for (var key in feature.attributes) {
    if (key.match(knownFieldNames)) {
      return key;
    }
  }
}

export function responseToFeatureCollection (response, idAttribute) {
  var objectIdField;
  var features = response.features || response.results;
  var count = features.length;

  if (idAttribute) {
    objectIdField = idAttribute;
  } else {
    objectIdField = _findIdAttributeFromResponse(response);
  }

  var featureCollection = {
    type: 'FeatureCollection',
    features: []
  };

  if (count) {
    for (var i = features.length - 1; i >= 0; i--) {
      var feature = arcgisToGeoJSON(features[i], objectIdField || _findIdAttributeFromFeature(features[i]));
      featureCollection.features.push(feature);
    }
  }

  return featureCollection;
}

  // trim url whitespace and add a trailing slash if needed
export function cleanUrl (url) {
  // trim leading and trailing spaces, but not spaces inside the url
  url = Util.trim(url);

  // add a trailing slash to the url if the user omitted it
  if (url[url.length - 1] !== '/') {
    url += '/';
  }

  return url;
}

/* Extract url params if any and store them in requestParams attribute.
   Return the options params updated */
export function getUrlParams (options) {
  if (options.url.indexOf('?') !== -1) {
    options.requestParams = options.requestParams || {};
    var queryString = options.url.substring(options.url.indexOf('?') + 1);
    options.url = options.url.split('?')[0];
    options.requestParams = JSON.parse('{"' + decodeURI(queryString).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}');
  }
  options.url = cleanUrl(options.url.split('?')[0]);
  return options;
}

export function isArcgisOnline (url) {
  /* hosted feature services support geojson as an output format
  utility.arcgis.com services are proxied from a variety of ArcGIS Server vintages, and may not */
  return (/^(?!.*utility\.arcgis\.com).*\.arcgis\.com.*FeatureServer/i).test(url);
}

export function geojsonTypeToArcGIS (geoJsonType) {
  var arcgisGeometryType;
  switch (geoJsonType) {
    case 'Point':
      arcgisGeometryType = 'esriGeometryPoint';
      break;
    case 'MultiPoint':
      arcgisGeometryType = 'esriGeometryMultipoint';
      break;
    case 'LineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'MultiLineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'Polygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
    case 'MultiPolygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
  }

  return arcgisGeometryType;
}

export function warn () {
  if (console && console.warn) {
    console.warn.apply(console, arguments);
  }
}

export function calcAttributionWidth (map) {
  // either crop at 55px or user defined buffer
  return (map.getSize().x - options.attributionWidthOffset) + 'px';
}

export function setEsriAttribution (map) {
  if (map.attributionControl && !map.attributionControl._esriAttributionAdded) {
    map.attributionControl.setPrefix('Leaflet | Powered by Esri');

    var hoverAttributionStyle = document.createElement('style');
    hoverAttributionStyle.type = 'text/css';
    hoverAttributionStyle.innerHTML = '.esri-truncated-attribution:hover {' +
      'white-space: normal;' +
    '}';

    document.getElementsByTagName('head')[0].appendChild(hoverAttributionStyle);
    DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution:hover');

    // define a new css class in JS to trim attribution into a single line
    var attributionStyle = document.createElement('style');
    attributionStyle.type = 'text/css';
    attributionStyle.innerHTML = '.esri-truncated-attribution {' +
      'vertical-align: -3px;' +
      'white-space: nowrap;' +
      'overflow: hidden;' +
      'text-overflow: ellipsis;' +
      'display: inline-block;' +
      'transition: 0s white-space;' +
      'transition-delay: 1s;' +
      'max-width: ' + calcAttributionWidth(map) + ';' +
    '}';

    document.getElementsByTagName('head')[0].appendChild(attributionStyle);
    DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution');

    // update the width used to truncate when the map itself is resized
    map.on('resize', function (e) {
      map.attributionControl._container.style.maxWidth = calcAttributionWidth(e.target);
    });

    map.attributionControl._esriAttributionAdded = true;
  }
}

export function _setGeometry (geometry) {
  var params = {
    geometry: null,
    geometryType: null
  };

  // convert bounds to extent and finish
  if (geometry instanceof LatLngBounds) {
    // set geometry + geometryType
    params.geometry = boundsToExtent(geometry);
    params.geometryType = 'esriGeometryEnvelope';
    return params;
  }

  // convert L.Marker > L.LatLng
  if (geometry.getLatLng) {
    geometry = geometry.getLatLng();
  }

  // convert L.LatLng to a geojson point and continue;
  if (geometry instanceof LatLng) {
    geometry = {
      type: 'Point',
      coordinates: [geometry.lng, geometry.lat]
    };
  }

  // handle L.GeoJSON, pull out the first geometry
  if (geometry instanceof GeoJSON) {
    // reassign geometry to the GeoJSON value  (we are assuming that only one feature is present)
    geometry = geometry.getLayers()[0].feature.geometry;
    params.geometry = geojsonToArcGIS(geometry);
    params.geometryType = geojsonTypeToArcGIS(geometry.type);
  }

  // Handle L.Polyline and L.Polygon
  if (geometry.toGeoJSON) {
    geometry = geometry.toGeoJSON();
  }

  // handle GeoJSON feature by pulling out the geometry
  if (geometry.type === 'Feature') {
    // get the geometry of the geojson feature
    geometry = geometry.geometry;
  }

  // confirm that our GeoJSON is a point, line or polygon
  if (geometry.type === 'Point' || geometry.type === 'LineString' || geometry.type === 'Polygon' || geometry.type === 'MultiPolygon') {
    params.geometry = geojsonToArcGIS(geometry);
    params.geometryType = geojsonTypeToArcGIS(geometry.type);
    return params;
  }

  // warn the user if we havn't found an appropriate object
  warn('invalid geometry passed to spatial query. Should be L.LatLng, L.LatLngBounds, L.Marker or a GeoJSON Point, Line, Polygon or MultiPolygon object');

  return;
}

export function _getAttributionData (url, map) {
  request(url, {}, Util.bind(function (error, attributions) {
    if (error) { return; }
    map._esriAttributions = [];
    for (var c = 0; c < attributions.contributors.length; c++) {
      var contributor = attributions.contributors[c];

      for (var i = 0; i < contributor.coverageAreas.length; i++) {
        var coverageArea = contributor.coverageAreas[i];
        var southWest = latLng(coverageArea.bbox[0], coverageArea.bbox[1]);
        var northEast = latLng(coverageArea.bbox[2], coverageArea.bbox[3]);
        map._esriAttributions.push({
          attribution: contributor.attribution,
          score: coverageArea.score,
          bounds: latLngBounds(southWest, northEast),
          minZoom: coverageArea.zoomMin,
          maxZoom: coverageArea.zoomMax
        });
      }
    }

    map._esriAttributions.sort(function (a, b) {
      return b.score - a.score;
    });

    // pass the same argument as the map's 'moveend' event
    var obj = { target: map };
    _updateMapAttribution(obj);
  }, this));
}

export function _updateMapAttribution (evt) {
  var map = evt.target;
  var oldAttributions = map._esriAttributions;

  if (!map || !map.attributionControl) return;

  var attributionElement = map.attributionControl._container.querySelector('.esri-dynamic-attribution');

  if (attributionElement && oldAttributions) {
    var newAttributions = '';
    var bounds = map.getBounds();
    var wrappedBounds = latLngBounds(
      bounds.getSouthWest().wrap(),
      bounds.getNorthEast().wrap()
    );
    var zoom = map.getZoom();

    for (var i = 0; i < oldAttributions.length; i++) {
      var attribution = oldAttributions[i];
      var text = attribution.attribution;

      if (!newAttributions.match(text) && attribution.bounds.intersects(wrappedBounds) && zoom >= attribution.minZoom && zoom <= attribution.maxZoom) {
        newAttributions += (', ' + text);
      }
    }

    newAttributions = newAttributions.substr(2);
    attributionElement.innerHTML = newAttributions;
    attributionElement.style.maxWidth = calcAttributionWidth(map);

    map.fire('attributionupdated', {
      attribution: newAttributions
    });
  }
}

export var EsriUtil = {
  warn: warn,
  cleanUrl: cleanUrl,
  getUrlParams: getUrlParams,
  isArcgisOnline: isArcgisOnline,
  geojsonTypeToArcGIS: geojsonTypeToArcGIS,
  responseToFeatureCollection: responseToFeatureCollection,
  geojsonToArcGIS: geojsonToArcGIS,
  arcgisToGeoJSON: arcgisToGeoJSON,
  boundsToExtent: boundsToExtent,
  extentToBounds: extentToBounds,
  calcAttributionWidth: calcAttributionWidth,
  setEsriAttribution: setEsriAttribution,
  _setGeometry: _setGeometry,
  _getAttributionData: _getAttributionData,
  _updateMapAttribution: _updateMapAttribution,
  _findIdAttributeFromFeature: _findIdAttributeFromFeature,
  _findIdAttributeFromResponse: _findIdAttributeFromResponse
};

export default EsriUtil;
<|endoftext|>


<commit_before>maria.View = function(model, controller) {
    maria.Node.call(this);
    this.setModel(model);
    this.setController(controller);
};

maria.Node.mixin(maria.View.prototype);

maria.View.prototype.destroy = function() {
    maria.purgeEventListener(this);
    this._model = null;
    if (this._controller) {
        this._controller.destroy();
        this._controller = null;
    }
    maria.Node.prototype.destroy.call(this);
};

maria.View.prototype.displayView = function() {
    // to be overridden by concrete view subclasses
};

maria.View.prototype.displayChildViews = function() {
    var node = this.firstChild;
    while (node) {
        node.display();
        node = node.nextSibling;
    }
};

maria.View.prototype.display = function() {
    this.displayView();
    this.displayChildViews();
};

maria.View.prototype.update = function() {
    // to be overridden by concrete view subclasses
};

maria.View.prototype.getModel = function() {
    return this._model;
};

maria.View.prototype.setModel = function(model) {
    this.setModelAndController(model, this._controller);
};

maria.View.prototype.getDefaultControllerConstructor = function() {
    return maria.Controller;
};

maria.View.prototype.getDefaultController = function() {
    var constructor = this.getDefaultControllerConstructor();
    return new constructor();
};

maria.View.prototype.getController = function() {
    if (!this._controller) {
        this.setController(this.getDefaultController());
    }
    return this._controller;
};

maria.View.prototype.setController = function(controller) {
    this.setModelAndController(this._model, controller);
};

maria.View.prototype.setModelAndController = function(model, controller) {
    if (this._model !== model) {
        if (this._model) {
            maria.removeEventListener(this._model, 'change', this, 'update');
        }
        if (model) {
            maria.addEventListener(model, 'change', this, 'update');
        }
        this._model = model;
    }
    if (this._controller !== controller) {
        if (controller) {
            controller.setView(this);
            controller.setModel(model);
        }
        this._controller = controller;
    }
};
<commit_msg>By default a view listens for its model's 'change' event and handles it with the view's 'update' method. Now this is configurable so that a view can easily declare the model event types of interest and which view method should handle each event type. Careful to keep the last map around so that if the model is changed and the map for the new model is different than the map used for the old model, the correct listeners are removed from the old model.<commit_after>maria.View = function(model, controller) {
    maria.Node.call(this);
    this.setModel(model);
    this.setController(controller);
};

maria.Node.mixin(maria.View.prototype);

maria.View.prototype.destroy = function() {
    maria.purgeEventListener(this);
    this._model = null;
    if (this._controller) {
        this._controller.destroy();
        this._controller = null;
    }
    maria.Node.prototype.destroy.call(this);
};

maria.View.prototype.displayView = function() {
    // to be overridden by concrete view subclasses
};

maria.View.prototype.displayChildViews = function() {
    var node = this.firstChild;
    while (node) {
        node.display();
        node = node.nextSibling;
    }
};

maria.View.prototype.display = function() {
    this.displayView();
    this.displayChildViews();
};

maria.View.prototype.update = function() {
    // to be overridden by concrete view subclasses
};

maria.View.prototype.getModel = function() {
    return this._model;
};

maria.View.prototype.setModel = function(model) {
    this.setModelAndController(model, this._controller);
};

maria.View.prototype.getDefaultControllerConstructor = function() {
    return maria.Controller;
};

maria.View.prototype.getDefaultController = function() {
    var constructor = this.getDefaultControllerConstructor();
    return new constructor();
};

maria.View.prototype.getController = function() {
    if (!this._controller) {
        this.setController(this.getDefaultController());
    }
    return this._controller;
};

maria.View.prototype.setController = function(controller) {
    this.setModelAndController(this._model, controller);
};

maria.View.prototype.getModelEventMap = function() {
    return {'change': 'update'};
};

maria.View.prototype.setModelAndController = function(model, controller) {
    var type, eventMap;
    if (this._model !== model) {
        if (this._model) {
            eventMap = this._lastModelEventMap;
            for (type in eventMap) {
                if (Object.prototype.hasOwnProperty.call(eventMap, type)) {
                    maria.removeEventListener(this._model, type, this, eventMap[type]);
                }
            }
            delete this._lastModelEventMap;
        }
        if (model) {
            eventMap = this._lastModelEventMap = this.getModelEventMap() || {};
            for (type in eventMap) {
                if (Object.prototype.hasOwnProperty.call(eventMap, type)) {
                    maria.addEventListener(model, type, this, eventMap[type]);
                }
            }
        }
        this._model = model;
    }
    if (this._controller !== controller) {
        if (controller) {
            controller.setView(this);
            controller.setModel(model);
        }
        this._controller = controller;
    }
};
<|endoftext|>


<commit_before>/*

Indexes
1  - X Axis - Left Thumbstick
3  - Y Axis - Left Thumbstick

5 - X Axis - Right Thumbstick
7 - Y Axis - Right Thumbstick

8 & 9 - Triggers
	= 00 (8) & 128 (9) Neutral
	< 128 (9) Right Trigger
	> 128 (9) Left Trigger
	= 00 (9) & 128 (8) RT + LT

10 - Keys

	Values
	1   - X
	2   - Circle
	4   - Square
	8   - Triangle
	16  - L1
	32  - R1
	64  - Select
	128 - Start

11 - POV Hat, L3 and R3

	Calculation: (INPUT % 4) = L3 and R3 values
				 INT(INPUT / 4) * 4 = POV Hat switch

	Values

	1 	- L3
	2	- R3
	3	- L3 + R3

	POV Hat
	4	- Up
	8	- Up + Right
	12 	- Right
	16 	- Down + Right
	20	- Down
	24	- Down + Left
	28 	- Left
	32	- Up + Left

*/

var Window = require('./Window');

var Logger = require('./Logger');

var HID = require ('node-hid');

var VID = 0x45E; // Microsoft
var PID = [0x28E, 0x28F, 0x2D1]; // Searches for Xbox 360 Controller, Xbox 360 Wifi Controller and Xbox One Controller
								 // http://www.linux-usb.org/usb.ids

var HIDController = null;
var controllerFound = false;

var dialog = require('dialog');

for(var i = 0; i < PID.length && HIDController === null; i++) {
	try {
		HIDController = new HID.HID(VID, PID[i]);
	} catch (e) {
		dialog.warn("hidcontroller: " + e, function(){});
		Logger.warn(e);
	}
}

function addDataListener(cb) {
	if(HIDController !== null) {
		HIDController.addListener('data', cb);
	}
}

function removeDataListener(cb) {
	if(HIDController !== null) {
		HIDController.removeListener('data', cb);
	}
}

if(HIDController !== null) {
	controllerFound = true;
	HIDController.addListener('error', function () {
		Window.quit('[CONTROLLER DISCONNECTED] Error while reading information from the controller. Please ensure it is correctly connected and run PoEController again.');
	});
} else {
	Window.quit("[CONTROLLER NOT FOUND] Error while connecting to xbox 360/one controller driver. Please ensure it is correctly connected and configured.");
}

module.exports = {
	found: controllerFound,
	addDataListener: addDataListener,
	removeDataListener: removeDataListener
};<commit_msg>Added Xbox 360 Wireless Receiver pid<commit_after>/*

Indexes
1  - X Axis - Left Thumbstick
3  - Y Axis - Left Thumbstick

5 - X Axis - Right Thumbstick
7 - Y Axis - Right Thumbstick

8 & 9 - Triggers
	= 00 (8) & 128 (9) Neutral
	< 128 (9) Right Trigger
	> 128 (9) Left Trigger
	= 00 (9) & 128 (8) RT + LT

10 - Keys

	Values
	1   - X
	2   - Circle
	4   - Square
	8   - Triangle
	16  - L1
	32  - R1
	64  - Select
	128 - Start

11 - POV Hat, L3 and R3

	Calculation: (INPUT % 4) = L3 and R3 values
				 INT(INPUT / 4) * 4 = POV Hat switch

	Values

	1 	- L3
	2	- R3
	3	- L3 + R3

	POV Hat
	4	- Up
	8	- Up + Right
	12 	- Right
	16 	- Down + Right
	20	- Down
	24	- Down + Left
	28 	- Left
	32	- Up + Left

*/

var Window = require('./Window');

var Logger = require('./Logger');

var HID = require ('node-hid');

// Searches for Xbox 360 Controller, Xbox 360 Wifi Controller, Xbox One Controller and Xbox 360 Wireless Receiver
// http://www.linux-usb.org/usb.ids
var VID = 0x45E; // Microsoft
var PID = [0x28E, 0x28F, 0x2D1, 0x0719];

var HIDController = null;
var controllerFound = false;

var dialog = require('dialog');

for(var i = 0; i < PID.length && HIDController === null; i++) {
	try {
		HIDController = new HID.HID(VID, PID[i]);
	} catch (e) {
		dialog.warn("hidcontroller: " + e, function(){});
		Logger.warn(e);
	}
}

function addDataListener(cb) {
	if(HIDController !== null) {
		HIDController.addListener('data', cb);
	}
}

function removeDataListener(cb) {
	if(HIDController !== null) {
		HIDController.removeListener('data', cb);
	}
}

if(HIDController !== null) {
	controllerFound = true;
	HIDController.addListener('error', function () {
		Window.quit('[CONTROLLER DISCONNECTED] Error while reading information from the controller. Please ensure it is correctly connected and run PoEController again.');
	});
} else {
	Window.quit("[CONTROLLER NOT FOUND] Error while connecting to xbox 360/one controller driver. Please ensure it is correctly connected and configured.");
}

module.exports = {
	found: controllerFound,
	addDataListener: addDataListener,
	removeDataListener: removeDataListener
};<|endoftext|>


<commit_before>/**
  * @constructor
  */

var host_event_handlers = new function()
{
  var self = this;

  var listeners = {};

  this.handle = function(xml)
  {
    if( window.__times_spotlight__ )
    {
      window.__times_spotlight__[0] =  new Date().getTime();
    }
    var event = {};

    var children = xml.documentElement.childNodes, child=null, i=0;
    for ( ; child = children[i]; i++)
    {
      event[child.nodeName] = child.firstChild.nodeValue;
    }
    if( event['handler-id'] in listeners )
    {
      listeners[ event['handler-id'] ](event);
    }
  }

  this.addListener = function( id, callback )
  {
    if ( !(id in listeners) )
    {
      listeners[id] = callback;
    }
  }

  this.removeListener = function( id, callback )
  {
    delete listeners[id];
  }

}<commit_msg>Added deprecation warning, as no code seems to be using this file<commit_after>/**
 * @fileoverview
 * fixme: Not in use!
 */

/**
  * @constructor
  * @deprecated
  */

var host_event_handlers = new function()
{
  var self = this;

  var listeners = {};

  this.handle = function(xml)
  {
    if( window.__times_spotlight__ )
    {
      window.__times_spotlight__[0] =  new Date().getTime();
    }
    var event = {};

    var children = xml.documentElement.childNodes, child=null, i=0;
    for ( ; child = children[i]; i++)
    {
      event[child.nodeName] = child.firstChild.nodeValue;
    }
    if( event['handler-id'] in listeners )
    {
      listeners[ event['handler-id'] ](event);
    }
  }

  this.addListener = function( id, callback )
  {
    if ( !(id in listeners) )
    {
      listeners[id] = callback;
    }
  }

  this.removeListener = function( id, callback )
  {
    delete listeners[id];
  }

}<|endoftext|>