<commit_before>'use strict';

function FloatingText(width, text, type, scene, current_color) {
    /*   __   __        __  ___  __        __  ___  __   __
        /  ` /  \ |\ | /__`  |  |__) |  | /  `  |  /  \ |__)
        \__, \__/ | \| .__/  |  |  \ \__/ \__,  |  \__/ |  \ */
    this.width         = width;
    this.type          = type;
    // FOR_DEV_START
    if (!is_defined(scene)) {
        l(text);
        l('THE SCENE PASSED IN TO FLOATINGTEXT IS NOT DEFINED!');
    }
    // FOR_DEV_END
    this.scene         = scene;
    this.object3D      = new THREE.Object3D();
    this.current_color = COLOR_DAY_PRESENT;
    this.default_color = COLOR_DAY_PRESENT;
    if (is_defined(current_color)) {
        this.current_color = current_color;
        this.default_color = current_color;
    }
    // Convert to the correct color type.
    if (this.is_2d_text) {
        this.current_color = this.current_color[COLOR_STRING_INDEX];
        this.default_color = this.current_color[COLOR_STRING_INDEX];
    } else {
        this.current_color = this.current_color[COLOR_HEX_INDEX];
        this.default_color = this.current_color[COLOR_HEX_INDEX];
    }

    if (this.type == TYPE_INPUT_PASSWORD) {
        this.text = '';
        for (var c = 0; c < text.length; c++) {
            this.text += '*';
        }
        this.hidden_text = text;
    } else {
        this.text = text;
    }

    // Call the child initialize functions.
    this.initialize();

    /*   ___            __  ___    __        __
        |__  |  | |\ | /  `  |  | /  \ |\ | /__`
        |    \__/ | \| \__,  |  | \__/ | \| .__/ */

    // This is just an alternative name to the function update_color.
    this.set_color = function(color) {
        this.update_color(color);
    };

    // Gets called in constructor so defining this function first.
    this.update_color = function(color) {
        var color_to_set = null;
        if (this.is_2d_text) {
            color_to_set = color[COLOR_STRING_INDEX];
        } else {
            color_to_set = color[COLOR_HEX_INDEX];
        }
        if (this.current_color !== color_to_set) {
            this.current_color = color_to_set;
            this._update_color();
        }
    };

    this.get_height = function() {
        return this.height;
    };

    this.update_text = function(text) {
        // TODO : This is currently assuming this function never gets called on a Password field.
        if (this.text !== text) {
            this.text = text;
            this._update_text();
        }
    };

    this.get_text = function() {
        if (this.type === TYPE_INPUT_PASSWORD) {
            return this.hidden_text;
        }
        return this.text;
    };

    this._add_character = function(character) {
        this.force_update_text(this.text + character);
    };

    this._pop_character = function() {
        this.force_update_text(this.text.slice(0, -1));
    };

    this.parse_keycode = function(event) {
        var keycode = event.keyCode;

        if (keycode === KEY_CODE_DELETE) {
            if (this.text.length > 0) {
                this._pop_character();
                if (this.type === TYPE_INPUT_PASSWORD) {
                    this._hidden_text = this._hidden_text.slice(0, -1);
                }
                MANAGER_AUDIO.play_typing_sound();
            }
        } else if (event.key.length === 1) {
            if (this.type === TYPE_INPUT_PASSWORD) {
                this._hidden_text += event.key;
                this._add_character('*');
            } else if (this.type === TYPE_INPUT_REGULAR) {
                this._add_character(event.key);
            }
            MANAGER_AUDIO.play_typing_sound();
        }

    };

    this.get_position = function() {
        return this.object3D.position;
    };

    this.update_position = function(position_vector) {
        this.object3D.position.x = position_vector.x;
        this.object3D.position.y = position_vector.y;
        this.object3D.position.z = position_vector.z;
    };

    this.update_look_at = function(look_at_position_vector) {
        this.object3D.lookAt(look_at_position_vector);
    };

    this.update_position_and_look_at = function(position_vector, look_at_position) {
        this.object3D.position.x = position_vector.x;
        this.object3D.position.y = position_vector.y;
        this.object3D.position.z = position_vector.z;
        this.object3D.lookAt(look_at_position);
    };

    this.delete_self = function() {
        // TODO : Implement this function!!!
    };

    /* __  ___      ___  ___     __                  __   ___  __
      /__`  |   /\   |  |__     /  ` |__|  /\  |\ | / _` |__  /__`
      .__/  |  /~~\  |  |___    \__, |  | /~~\ | \| \__> |___ .__/ */
    this.state_change_look_at = function(being_looked_at) {
        if (being_looked_at) {
            this.update_color(COLOR_HIGHLIGHT);
        } else {
            this.update_color(this.default_color);
        }
    };

    this.state_change_engage = function(being_engaged_with) {
        if (being_engaged_with) {
            if (this.type !== TYPE_BUTTON && this.type !== TYPE_CHECK_BOX) {
                CURRENT_PLAYER.engage();
            } else {
                this.being_engaged_with = false;
                CURRENT_PLAYER.disengage();
            }
        } else {
            CURRENT_PLAYER.disengage();
        }
    };
}<commit_msg>general updating 98<commit_after>'use strict';

function FloatingText(width, text, type, scene, current_color) {
    /*   __   __        __  ___  __        __  ___  __   __
        /  ` /  \ |\ | /__`  |  |__) |  | /  `  |  /  \ |__)
        \__, \__/ | \| .__/  |  |  \ \__/ \__,  |  \__/ |  \ */
    this.width         = width;
    this.type          = type;
    // FOR_DEV_START
    if (!is_defined(scene)) {
        l(text);
        l('THE SCENE PASSED IN TO FLOATINGTEXT IS NOT DEFINED!');
    }
    // FOR_DEV_END
    this.scene         = scene;
    this.object3D      = new THREE.Object3D();
    this.current_color = COLOR_DAY_PRESENT;
    this.default_color = COLOR_DAY_PRESENT;
    if (is_defined(current_color)) {
        this.current_color = current_color;
        this.default_color = current_color;
    }
    // Convert to the correct color type.
    if (this.is_2d_text) {
        this.current_color = this.current_color[COLOR_STRING_INDEX];
        this.default_color = this.current_color[COLOR_STRING_INDEX];
    } else {
        this.current_color = this.current_color[COLOR_HEX_INDEX];
        this.default_color = this.current_color[COLOR_HEX_INDEX];
    }

    if (this.type == TYPE_INPUT_PASSWORD) {
        this.text = '';
        for (var c = 0; c < text.length; c++) {
            this.text += '*';
        }
        this.hidden_text = text;
    } else {
        this.text = text;
    }

    // Call the child initialize functions.
    this.initialize();

    /*   ___            __  ___    __        __
        |__  |  | |\ | /  `  |  | /  \ |\ | /__`
        |    \__/ | \| \__,  |  | \__/ | \| .__/ */

    // This is just an alternative name to the function update_color.
    this.set_color = function(color) {
        this.update_color(color);
    };

    // Gets called in constructor so defining this function first.
    this.update_color = function(color) {
        var color_to_set = null;
        if (this.is_2d_text) {
            color_to_set = color[COLOR_STRING_INDEX];
        } else {
            color_to_set = color[COLOR_HEX_INDEX];
        }
        if (this.current_color !== color_to_set) {
            this.current_color = color_to_set;
            this._update_color();
        }
    };

    this.get_height = function() {
        return this.height;
    };

    this.update_text = function(text) {
        // TODO : This is currently assuming this function never gets called on a Password field.
        if (this.text !== text) {
            this.text = text;
            this._update_text();
        }
    };

    this.get_text = function() {
        if (this.type === TYPE_INPUT_PASSWORD) {
            return this.hidden_text;
        }
        return this.text;
    };

    this._add_character = function(character) {
        this._update_text(this.text + character);
    };

    this._pop_character = function() {
        this._update_text(this.text.slice(0, -1));
    };

    this.parse_keycode = function(event) {
        var keycode = event.keyCode;

        if (keycode === KEY_CODE_DELETE) {
            if (this.text.length > 0) {
                this._pop_character();
                if (this.type === TYPE_INPUT_PASSWORD) {
                    this._hidden_text = this._hidden_text.slice(0, -1);
                }
                MANAGER_AUDIO.play_typing_sound();
            }
        } else if (event.key.length === 1) {
            if (this.type === TYPE_INPUT_PASSWORD) {
                this._hidden_text += event.key;
                this._add_character('*');
            } else if (this.type === TYPE_INPUT_REGULAR) {
                this._add_character(event.key);
            }
            MANAGER_AUDIO.play_typing_sound();
        }

    };

    this.get_position = function() {
        return this.object3D.position;
    };

    this.update_position = function(position_vector) {
        this.object3D.position.x = position_vector.x;
        this.object3D.position.y = position_vector.y;
        this.object3D.position.z = position_vector.z;
    };

    this.update_look_at = function(look_at_position_vector) {
        this.object3D.lookAt(look_at_position_vector);
    };

    this.update_position_and_look_at = function(position_vector, look_at_position) {
        this.object3D.position.x = position_vector.x;
        this.object3D.position.y = position_vector.y;
        this.object3D.position.z = position_vector.z;
        this.object3D.lookAt(look_at_position);
    };

    this.delete_self = function() {
        // TODO : Implement this function!!!
    };

    /* __  ___      ___  ___     __                  __   ___  __
      /__`  |   /\   |  |__     /  ` |__|  /\  |\ | / _` |__  /__`
      .__/  |  /~~\  |  |___    \__, |  | /~~\ | \| \__> |___ .__/ */
    this.state_change_look_at = function(being_looked_at) {
        if (being_looked_at) {
            this.update_color(COLOR_HIGHLIGHT);
        } else {
            this.current_color = this.default_color;
            this._update_color();
        }
    };

    this.state_change_engage = function(being_engaged_with) {
        if (being_engaged_with) {
            if (this.type !== TYPE_BUTTON && this.type !== TYPE_CHECK_BOX) {
                CURRENT_PLAYER.engage();
            } else {
                this.being_engaged_with = false;
                CURRENT_PLAYER.disengage();
            }
        } else {
            CURRENT_PLAYER.disengage();
        }
    };
}<|endoftext|>


<commit_before>/**
 * @module Core
 */
define([
    'core/modules/GelatoView',
    'core/modules/GelatoDialog',
    'core/modules/GelatoSidebar'
], function(GelatoView, GelatoDialog, GelatoSidebar) {

    /**
     * @class GelatoPage
     * @extends GelatoView
     */
    var GelatoPage = GelatoView.extend({
        /**
         * @property el
         * @type String
         */
        el: '#application',
        /**
         * @property title
         * @type String
         */
        title: app.strings.global.title,
        /**
         * @method renderDialog
         * @returns {GelatoPage}
         */
        renderDialog: function() {
            this.dialog = new GelatoDialog({el: this.$el, page: this});
            return this;
        },
        /**
         * @method renderSidebar
         * @returns {GelatoPage}
         */
        renderSidebar: function() {
            this.sidebar = new GelatoSidebar({el: this.$el, page: this});
            return this;
        },
        /**
         * @method renderTemplate
         * @param {String} template
         * @returns {GelatoPage}
         */
        renderTemplate: function(template) {
            GelatoView.prototype.renderTemplate.call(this, template);
            this.renderDialog();
            this.renderSidebar();
            return this;
        },
        /**
         * @method getName
         * @returns {String}
         */
        getName: function() {
            return this.$('.gelato-page').attr('class').split(/\s/g)[1];
        },
        /**
         * @method remove
         * @returns {GelatoPage}
         */
        remove: function() {
            this.sidebar.remove();
            GelatoView.prototype.remove.call(this);
            return this;
        }
    });

    return GelatoPage;

});<commit_msg>Added enable and disable form methods to gelato page.<commit_after>/**
 * @module Core
 */
define([
    'core/modules/GelatoView',
    'core/modules/GelatoDialog',
    'core/modules/GelatoSidebar'
], function(GelatoView, GelatoDialog, GelatoSidebar) {

    /**
     * @class GelatoPage
     * @extends GelatoView
     */
    var GelatoPage = GelatoView.extend({
        /**
         * @property el
         * @type String
         */
        el: '#application',
        /**
         * @property title
         * @type String
         */
        title: app.strings.global.title,
        /**
         * @method disableForm
         * @param {String} [selector]
         * @returns {GelatoPage}
         */
        disableForm: function(selector) {
            this.$((selector ? selector + ' ': '') + ':input').prop('disabled', true);
            return this;
        },
        /**
         * @method enableForm
         * @param {String} [selector]
         * @returns {GelatoPage}
         */
        enableForm: function(selector) {
            this.$((selector ? selector: ' ') + ':input').prop('disabled', false);
            return this;
        },
        /**
         * @method renderDialog
         * @returns {GelatoPage}
         */
        renderDialog: function() {
            this.dialog = new GelatoDialog({el: this.$el, page: this});
            return this;
        },
        /**
         * @method renderSidebar
         * @returns {GelatoPage}
         */
        renderSidebar: function() {
            this.sidebar = new GelatoSidebar({el: this.$el, page: this});
            return this;
        },
        /**
         * @method renderTemplate
         * @param {String} template
         * @returns {GelatoPage}
         */
        renderTemplate: function(template) {
            GelatoView.prototype.renderTemplate.call(this, template);
            this.renderDialog();
            this.renderSidebar();
            return this;
        },
        /**
         * @method getName
         * @returns {String}
         */
        getName: function() {
            return this.$('.gelato-page').attr('class').split(/\s/g)[1];
        },
        /**
         * @method remove
         * @returns {GelatoPage}
         */
        remove: function() {
            this.sidebar.remove();
            GelatoView.prototype.remove.call(this);
            return this;
        }
    });

    return GelatoPage;

});<|endoftext|>


<commit_before>/**
 * @module Core
 */
define([], function() {

    /**
     * @class GelatoView
     * @extends Backbone.View
     */
    var GelatoView = Backbone.View.extend({
        /**
         * @method renderTemplate
         * @param {String} template
         * @returns {GelatoView}
         */
        renderTemplate: function(template) {
            var self = this;
            var resize = null;
            this.$el.html(Handlebars.compile(template)(app.strings));
            this.$('[data-url]').on('vclick', $.proxy(this.handleNavigateClicked, this));
            $(window).resize(function(event) {
                clearTimeout(resize);
                resize = setTimeout(function() {
                    self.trigger('resize', event);
                }, 100);
            });
            return this;
        },
        /**
         * @method handleNavigateClicked
         * @param {Event} event
         */
        handleNavigateClicked: function(event) {
            event.preventDefault();
            var url = $(event.currentTarget).data('url').replace('#', app.isLocal() ? '/#' : '');
            var replace = $(event.currentTarget).data('replace');
            var trigger = $(event.currentTarget).data('trigger');
            app.router.navigate(url, {
                replace: replace === undefined ? false : replace,
                trigger: trigger === undefined ? true : trigger
            });
        },
        /**
         * @method hide
         * @returns {GelatoView}
         */
        hide: function() {
            this.$el.hide();
            return this;
        },
        /**
         * @method remove
         * @returns {GelatoView}
         */
        remove: function() {
            this.$el.empty();
            this.$el.find('*').off();
            this.stopListening();
            $(window).off('resize');
            return this;
        },
        /**
         * @method resize
         * @returns {GelatoView}
         */
        resize: function() {
            return this;
        },
        /**
         * @method show
         * @returns {GelatoView}
         */
        show: function() {
            this.$el.show();
            return this;
        }
    });

    return GelatoView;

});<commit_msg>Split custom view events rendering into separate function for lazy interfaces.<commit_after>/**
 * @module Core
 */
define([], function() {

    /**
     * @class GelatoView
     * @extends Backbone.View
     */
    var GelatoView = Backbone.View.extend({
        /**
         * @method renderEvents
         * @returns {GelatoView}
         */
        renderEvents: function() {
            this.$('[data-url]').off().on('vclick', $.proxy(this.handleNavigateClicked, this));
            return this;
        },
        /**
         * @method renderTemplate
         * @param {String} template
         * @returns {GelatoView}
         */
        renderTemplate: function(template) {
            var self = this;
            var resize = null;
            this.$el.html(Handlebars.compile(template)(app.strings));
            this.renderEvents();
            $(window).resize(function(event) {
                clearTimeout(resize);
                resize = setTimeout(function() {
                    self.trigger('resize', event);
                }, 100);
            });
            return this;
        },
        /**
         * @method handleNavigateClicked
         * @param {Event} event
         */
        handleNavigateClicked: function(event) {
            event.preventDefault();
            var url = $(event.currentTarget).data('url').replace('#', app.isLocal() ? '/#' : '');
            var replace = $(event.currentTarget).data('replace');
            var trigger = $(event.currentTarget).data('trigger');
            app.router.navigate(url, {
                replace: replace === undefined ? false : replace,
                trigger: trigger === undefined ? true : trigger
            });
        },
        /**
         * @method hide
         * @returns {GelatoView}
         */
        hide: function() {
            this.$el.hide();
            return this;
        },
        /**
         * @method remove
         * @returns {GelatoView}
         */
        remove: function() {
            this.$el.empty();
            this.$el.find('*').off();
            this.stopListening();
            $(window).off('resize');
            return this;
        },
        /**
         * @method resize
         * @returns {GelatoView}
         */
        resize: function() {
            return this;
        },
        /**
         * @method show
         * @returns {GelatoView}
         */
        show: function() {
            this.$el.show();
            return this;
        }
    });

    return GelatoView;

});<|endoftext|>


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

    var app = angular.module('lesson.controllers', []);

    app.controller('MainCtrl', ['$scope', 'LessonData', 'Answer', 'Progress', '$location', 'youtubePlayerApi', 'resolveActivityTemplate',
        function ($scope, LessonData, Answer, Progress, $location, youtubePlayerApi, resolveActivityTemplate) {

            window.ga = window.ga || function(){};

            youtubePlayerApi.events.onStateChange = function(event){
                window.onPlayerStateChange.call($scope.currentUnit, event);
                if (event.data === YT.PlayerState.ENDED) {
                    $scope.nextStep();
                    if(!$scope.$$phase) {
                        $scope.$apply();
                    }
                }
            };

            $scope.section = $scope.section || 'video';

            $scope.selectUnit = function(unit) {
                $scope.currentUnit = unit;
                if(unit.video) {
                    $scope.section = 'video';
                    $scope.play(unit.video.youtube_id);
                } else {
                    $scope.section = 'activity';
                }
                $scope.selectActivity(0);
            };

            $scope.nextUnit = function() {
                var index = $scope.lesson.units.indexOf($scope.currentUnit);
                index++;

                if(index < $scope.lesson.units.length) {
                    $location.path('/{0}'.format(index+1));
                }
                // e se não tiver nextUnit, faz o que?
            };

            $scope.play = function() {
                if($scope.currentUnit.video){
                    var youtube_id = $scope.currentUnit.video.youtube_id;
                    $scope.section = 'video';

                    youtubePlayerApi.loadPlayer().then(function(player){
                            if(player.getVideoData() &&
                                player.getVideoData().video_id === youtube_id) return;
                            player.cueVideoById(youtube_id);
                    });
                } else {
                    $scope.section = 'activity';
                }

            };

            $scope.selectActivity = function(index) {

                if($scope.currentUnit.activities && $scope.currentUnit.activities.length) {
                    $scope.currentActivity = $scope.currentUnit.activities[index];
                    $scope.activityTemplateUrl = resolveActivityTemplate($scope.currentActivity.type);

                    ga("send", "event", "activity", "select", $scope.currentActivity.id);

                    $scope.answer = Answer.get({activityId: $scope.currentActivity.id}, function(answer) {
                        var exp = $scope.currentActivity.expected;
                        var giv = answer.given;
                        // FIXME why this name?
                        // TODO test if professor changes the activity (create a new alternative, the user lost his answer?
                        var shouldUseLastAnswer = (exp !== null && exp !== undefined) &&
                            (angular.isArray(exp) && angular.isArray(giv) && giv.length === exp.length);

                        console.log(exp, giv, shouldUseLastAnswer);
                        if (!shouldUseLastAnswer) {
                            // Initialize empty given answer
                            if(angular.isArray($scope.currentActivity.expected)) {
                                answer.given = $scope.currentActivity.expected.map(function(){});
                            }
                            delete answer.correct;
                        }
                    },
                    function (error) {
                        console.log('answer does not exists or other errors');
                        var answer = {};
                        if(angular.isArray($scope.currentActivity.expected)) {
                            answer.given = $scope.currentActivity.expected.map(function(){});
                        }
                        $scope.answer = new Answer(answer);
                    });
                } else {
                    $scope.currentActivity = null;
                    $scope.activityTemplateUrl = null;
                }
            };

            $scope.sendAnswer = function() {
                console.log('mandando resposta');
                $scope.answer.activity = $scope.currentActivity.id;
                $scope.answer.$update({activityId: $scope.answer.activity}).then(function(d){
                    console.log(d, d.correct);
                    ga('send', 'event', 'activity', 'result', '', d.correct);
                    return Progress.getProgressByUnitId($scope.currentUnit.id);
                }).then(function(progress){
                    $scope.currentUnit.progress = progress;
                });
                ga('send', 'event', 'activity', 'submit');
            };

            $scope.nextStep = function(skipComment) {
                if($scope.section === 'video') {
                    if(angular.isArray($scope.currentUnit.activities) &&
                        $scope.currentUnit.activities.length > 0) {
                        $scope.section = 'activity';
                    } else {
                        var progress = new Progress();
                        progress.complete = new Date();
                        progress.unit = $scope.currentUnit.id;
                        $scope.currentUnit.progress = progress;
                        progress.$save();
                        $scope.nextUnit();
                    }
                } else {
                    if($scope.section === 'activity' && !skipComment && $scope.currentActivity.comment) {
                        $scope.section = 'comment';
                    } else {
                        var index = $scope.currentUnit.activities.indexOf($scope.currentActivity);
                        if(index+1 === $scope.currentUnit.activities.length) {
                            $scope.nextUnit();
                        } else {
                            $scope.selectActivity(index + 1);
                            $scope.section = 'activity';
                        }
                    }
                }
            };

            var start;
            $scope.$watch('currentUnit', function(currentUnit, lastUnit) {
                if(!$scope.lesson) return;
                // Changing Unit means unit starting
                if (start && lastUnit) {
                    var end = new Date().getTime();
                    ga('send', 'event', 'unit', 'time in unit',
                       $scope.lesson.course + ' - "' + $scope.lesson.name + '" - ' + lastUnit.id,
                       end - start);
                }
                ga('send', 'event', 'unit', 'start', $scope.lesson.course + ' - ' + $scope.lesson.name, $scope.currentUnit.id);
                start = new Date().getTime();
            });

            LessonData.then(function(lesson){
                $scope.lesson = lesson;

                var index = /\/(\d+)/.extract($location.path(), 1);
                index = parseInt(index, 10) - 1 || 0;
                $scope.selectUnit(lesson.units[index]);
                $scope.play();

                $scope.$on('$locationChangeSuccess', function (event, newLoc, oldLoc){
                   index = /#\/(\d+)/.extract(document.location.hash, 1);
                   index = parseInt(index, 10) - 1 || 0;
                   $scope.selectUnit(lesson.units[index]);
                });
            });
        }
    ]);

})(angular);

(function() {
    var _pauseFlag = false;
    var start, whole;

    var lastState = -1;

    function  onPlayerStateChange (event) {
        var video_id = event.target.getVideoData().video_id;

        if (event.data == YT.PlayerState.ENDED){
            if(! (lastState === YT.PlayerState.PAUSED ||   // workaround, YT in html5 mode will fire
                  lastState === YT.PlayerState.PLAYING)) { // event with ENDED state after cue video.
                event.data = lastState;
            } else {
                ga('send', 'event', 'videos', 'watch To end', video_id);
                if (whole === 'started') {
                    var stop = new Date().getTime();
                    var delta_s = (stop - start) / 1000;
                    ga('send', 'event', 'videos', 'time tO end', video_id, Math.round(delta_s));
                    whole = 'ended';
                }
            }
        }

        if (event.data == YT.PlayerState.PLAYING){
                ga('send', 'event', 'videos', 'play', video_id);
                _pauseFlag = false;
                if (whole !== 'ended' && whole !== 'started') {
                    start = new Date().getTime();
                    whole = 'started';
                }
        }

        if (event.data == YT.PlayerState.PAUSED && _pauseFlag === false){
            ga('send', 'event', 'videos', 'pause', video_id);
            _pauseFlag = true;
        }
        if (event.data == YT.PlayerState.BUFFERING){
            ga('send', 'event', 'videos', 'bufferIng', video_id);
        }
        if (event.data == YT.PlayerState.CUED){
            ga('send', 'event', 'videos', 'cueing', video_id);
        }

        lastState = event.data;
    }
    window.onPlayerStateChange = onPlayerStateChange;
})();
<commit_msg>Activity: pass change test if activity is markdown<commit_after>(function(angular){
    'use strict';

    var app = angular.module('lesson.controllers', []);

    app.controller('MainCtrl', ['$scope', 'LessonData', 'Answer', 'Progress', '$location', 'youtubePlayerApi', 'resolveActivityTemplate',
        function ($scope, LessonData, Answer, Progress, $location, youtubePlayerApi, resolveActivityTemplate) {

            window.ga = window.ga || function(){};

            youtubePlayerApi.events.onStateChange = function(event){
                window.onPlayerStateChange.call($scope.currentUnit, event);
                if (event.data === YT.PlayerState.ENDED) {
                    $scope.nextStep();
                    if(!$scope.$$phase) {
                        $scope.$apply();
                    }
                }
            };

            $scope.section = $scope.section || 'video';

            $scope.selectUnit = function(unit) {
                $scope.currentUnit = unit;
                if(unit.video) {
                    $scope.section = 'video';
                    $scope.play(unit.video.youtube_id);
                } else {
                    $scope.section = 'activity';
                }
                $scope.selectActivity(0);
            };

            $scope.nextUnit = function() {
                var index = $scope.lesson.units.indexOf($scope.currentUnit);
                index++;

                if(index < $scope.lesson.units.length) {
                    $location.path('/{0}'.format(index+1));
                }
                // e se não tiver nextUnit, faz o que?
            };

            $scope.play = function() {
                if($scope.currentUnit.video){
                    var youtube_id = $scope.currentUnit.video.youtube_id;
                    $scope.section = 'video';

                    youtubePlayerApi.loadPlayer().then(function(player){
                            if(player.getVideoData() &&
                                player.getVideoData().video_id === youtube_id) return;
                            player.cueVideoById(youtube_id);
                    });
                } else {
                    $scope.section = 'activity';
                }

            };

            $scope.selectActivity = function(index) {

                if($scope.currentUnit.activities && $scope.currentUnit.activities.length) {
                    $scope.currentActivity = $scope.currentUnit.activities[index];
                    $scope.activityTemplateUrl = resolveActivityTemplate($scope.currentActivity.type);

                    ga("send", "event", "activity", "select", $scope.currentActivity.id);

                    $scope.answer = Answer.get({activityId: $scope.currentActivity.id}, function(answer) {
                        var exp = $scope.currentActivity.expected;
                        var giv = answer.given;
                        // FIXME why this name?
                        // TODO test if professor changes the activity (create a new alternative, the user lost his answer?
                        var shouldUseLastAnswer = (exp !== null && exp !== undefined) &&
                            (angular.isArray(exp) && angular.isArray(giv) && giv.length === exp.length);

                        console.log(exp, giv, shouldUseLastAnswer);
                        if (!shouldUseLastAnswer && $scope.currentActivity.type !== 'markdown') {
                            // Initialize empty given answer
                            if(angular.isArray($scope.currentActivity.expected)) {
                                answer.given = $scope.currentActivity.expected.map(function(){});
                            }
                            delete answer.correct;
                        }
                    },
                    function (error) {
                        console.log('answer does not exists or other errors');
                        var answer = {};
                        if(angular.isArray($scope.currentActivity.expected)) {
                            answer.given = $scope.currentActivity.expected.map(function(){});
                        }
                        $scope.answer = new Answer(answer);
                    });
                } else {
                    $scope.currentActivity = null;
                    $scope.activityTemplateUrl = null;
                }
            };

            $scope.sendAnswer = function() {
                console.log('mandando resposta');
                $scope.answer.activity = $scope.currentActivity.id;
                $scope.answer.$update({activityId: $scope.answer.activity}).then(function(d){
                    console.log(d, d.correct);
                    ga('send', 'event', 'activity', 'result', '', d.correct);
                    return Progress.getProgressByUnitId($scope.currentUnit.id);
                }).then(function(progress){
                    $scope.currentUnit.progress = progress;
                });
                ga('send', 'event', 'activity', 'submit');
            };

            $scope.nextStep = function(skipComment) {
                if($scope.section === 'video') {
                    if(angular.isArray($scope.currentUnit.activities) &&
                        $scope.currentUnit.activities.length > 0) {
                        $scope.section = 'activity';
                    } else {
                        var progress = new Progress();
                        progress.complete = new Date();
                        progress.unit = $scope.currentUnit.id;
                        $scope.currentUnit.progress = progress;
                        progress.$save();
                        $scope.nextUnit();
                    }
                } else {
                    if($scope.section === 'activity' && !skipComment && $scope.currentActivity.comment) {
                        $scope.section = 'comment';
                    } else {
                        var index = $scope.currentUnit.activities.indexOf($scope.currentActivity);
                        if(index+1 === $scope.currentUnit.activities.length) {
                            $scope.nextUnit();
                        } else {
                            $scope.selectActivity(index + 1);
                            $scope.section = 'activity';
                        }
                    }
                }
            };

            var start;
            $scope.$watch('currentUnit', function(currentUnit, lastUnit) {
                if(!$scope.lesson) return;
                // Changing Unit means unit starting
                if (start && lastUnit) {
                    var end = new Date().getTime();
                    ga('send', 'event', 'unit', 'time in unit',
                       $scope.lesson.course + ' - "' + $scope.lesson.name + '" - ' + lastUnit.id,
                       end - start);
                }
                ga('send', 'event', 'unit', 'start', $scope.lesson.course + ' - ' + $scope.lesson.name, $scope.currentUnit.id);
                start = new Date().getTime();
            });

            LessonData.then(function(lesson){
                $scope.lesson = lesson;

                var index = /\/(\d+)/.extract($location.path(), 1);
                index = parseInt(index, 10) - 1 || 0;
                $scope.selectUnit(lesson.units[index]);
                $scope.play();

                $scope.$on('$locationChangeSuccess', function (event, newLoc, oldLoc){
                   index = /#\/(\d+)/.extract(document.location.hash, 1);
                   index = parseInt(index, 10) - 1 || 0;
                   $scope.selectUnit(lesson.units[index]);
                });
            });
        }
    ]);

})(angular);

(function() {
    var _pauseFlag = false;
    var start, whole;

    var lastState = -1;

    function  onPlayerStateChange (event) {
        var video_id = event.target.getVideoData().video_id;

        if (event.data == YT.PlayerState.ENDED){
            if(! (lastState === YT.PlayerState.PAUSED ||   // workaround, YT in html5 mode will fire
                  lastState === YT.PlayerState.PLAYING)) { // event with ENDED state after cue video.
                event.data = lastState;
            } else {
                ga('send', 'event', 'videos', 'watch To end', video_id);
                if (whole === 'started') {
                    var stop = new Date().getTime();
                    var delta_s = (stop - start) / 1000;
                    ga('send', 'event', 'videos', 'time tO end', video_id, Math.round(delta_s));
                    whole = 'ended';
                }
            }
        }

        if (event.data == YT.PlayerState.PLAYING){
                ga('send', 'event', 'videos', 'play', video_id);
                _pauseFlag = false;
                if (whole !== 'ended' && whole !== 'started') {
                    start = new Date().getTime();
                    whole = 'started';
                }
        }

        if (event.data == YT.PlayerState.PAUSED && _pauseFlag === false){
            ga('send', 'event', 'videos', 'pause', video_id);
            _pauseFlag = true;
        }
        if (event.data == YT.PlayerState.BUFFERING){
            ga('send', 'event', 'videos', 'bufferIng', video_id);
        }
        if (event.data == YT.PlayerState.CUED){
            ga('send', 'event', 'videos', 'cueing', video_id);
        }

        lastState = event.data;
    }
    window.onPlayerStateChange = onPlayerStateChange;
})();
<|endoftext|>


<commit_before>var $ = require('jquery');

module.exports = {
	gracefulWebSocket: function (url, options) {
		// Default properties
		this.defaults = {
			keepAlive: false,		// not implemented - should ping server to keep socket open
			autoReconnect: false,	// not implemented - should try to reconnect silently if socket is closed
			fallback: true,			// not implemented - always use HTTP fallback if native browser support is missing
			fallbackSendURL: url.replace('ws:', 'http:').replace('wss:', 'https:'),
			fallbackSendMethod: 'POST',
			fallbackPollURL: url.replace('ws:', 'http:').replace('wss:', 'https:'),
			fallbackPollMethod: 'GET',
			fallbackOpenDelay: 100,	// number of ms to delay simulated open event
			fallbackPollInterval: 3000,	// number of ms between poll requests
			fallbackPollParams: {}		// optional params to pass with poll requests
		};

		// Override defaults with user properties
		var opts = $.extend({}, this.defaults, options);

		/**
		 * Creates a fallback object implementing the WebSocket interface
		 */
		function FallbackSocket() {

			// WebSocket interface constants
			const CONNECTING = 0;
			const OPEN = 1;
			const CLOSING = 2;
			const CLOSED = 3;

			var pollInterval;
			var openTimout;

			// create WebSocket object
			var fws = {
				// ready state
				readyState: CONNECTING,
				bufferedAmount: 0,
				send: function (data) {
					var success = true;
					$.ajax({
						async: false, // send synchronously
						type: opts.fallbackSendMethod,
						url: opts.fallbackSendURL + '?' + $.param( getFallbackParams() ),
						data: data,
						dataType: 'text',
						contentType : "application/x-www-form-urlencoded; charset=utf-8",
						success: pollSuccess,
						error: function (xhr) {
							success = false;
							$(fws).triggerHandler('error');
						}
					});
					return success;
				},
				close: function () {
					clearTimeout(openTimout);
					clearInterval(pollInterval);
					this.readyState = CLOSED;
					$(fws).triggerHandler('close');
				},
				onopen: function () {},
				onmessage: function () {},
				onerror: function () {},
				onclose: function () {},
				previousRequest: null,
				currentRequest: null
			};

			function getFallbackParams() {

				// update timestamp of previous and current poll request
				fws.previousRequest = fws.currentRequest;
				fws.currentRequest = new Date().getTime();

				// extend default params with plugin options
				return $.extend({"previousRequest": fws.previousRequest, "currentRequest": fws.currentRequest}, opts.fallbackPollParams);
			}

			/**
			 * @param {Object} data
			 */
			function pollSuccess(data) {

				// trigger onmessage
				var messageEvent = {"data" : data};
				fws.onmessage(messageEvent);
			}

			function poll() {

				$.ajax({
					type: opts.fallbackPollMethod,
					url: opts.fallbackPollURL,
					dataType: 'text',
					data: getFallbackParams(),
					success: pollSuccess,
					error: function (xhr) {
						$(fws).triggerHandler('error');
					}
				});
			}

			// simulate open event and start polling
			openTimout = setTimeout(function () {
				fws.readyState = OPEN;
				//fws.currentRequest = new Date().getTime();
				$(fws).triggerHandler('open');
				poll();
				pollInterval = setInterval(poll, opts.fallbackPollInterval);

			}, opts.fallbackOpenDelay);

			// return socket impl
			return fws;
		}

		// create a new websocket or fallback
		var ws = window.WebSocket ? new WebSocket(url) : new FallbackSocket();
 		$(window).unload(function () { ws.close(); ws = null });
		return ws;
	}
};
<commit_msg>Removed const and put vars<commit_after>var $ = require('jquery');

module.exports = {
	gracefulWebSocket: function (url, options) {
		// Default properties
		this.defaults = {
			keepAlive: false,		// not implemented - should ping server to keep socket open
			autoReconnect: false,	// not implemented - should try to reconnect silently if socket is closed
			fallback: true,			// not implemented - always use HTTP fallback if native browser support is missing
			fallbackSendURL: url.replace('ws:', 'http:').replace('wss:', 'https:'),
			fallbackSendMethod: 'POST',
			fallbackPollURL: url.replace('ws:', 'http:').replace('wss:', 'https:'),
			fallbackPollMethod: 'GET',
			fallbackOpenDelay: 100,	// number of ms to delay simulated open event
			fallbackPollInterval: 3000,	// number of ms between poll requests
			fallbackPollParams: {}		// optional params to pass with poll requests
		};

		// Override defaults with user properties
		var opts = $.extend({}, this.defaults, options);

		/**
		 * Creates a fallback object implementing the WebSocket interface
		 */
		function FallbackSocket() {
			var CONNECTING = 0;
			var OPEN = 1;
			var CLOSING = 2;
			var CLOSED = 3;

			var pollInterval;
			var openTimout;

			// create WebSocket object
			var fws = {
				// ready state
				readyState: CONNECTING,
				bufferedAmount: 0,
				send: function (data) {
					var success = true;
					$.ajax({
						async: false, // send synchronously
						type: opts.fallbackSendMethod,
						url: opts.fallbackSendURL + '?' + $.param( getFallbackParams() ),
						data: data,
						dataType: 'text',
						contentType : "application/x-www-form-urlencoded; charset=utf-8",
						success: pollSuccess,
						error: function (xhr) {
							success = false;
							$(fws).triggerHandler('error');
						}
					});
					return success;
				},
				close: function () {
					clearTimeout(openTimout);
					clearInterval(pollInterval);
					this.readyState = CLOSED;
					$(fws).triggerHandler('close');
				},
				onopen: function () {},
				onmessage: function () {},
				onerror: function () {},
				onclose: function () {},
				previousRequest: null,
				currentRequest: null
			};

			function getFallbackParams() {

				// update timestamp of previous and current poll request
				fws.previousRequest = fws.currentRequest;
				fws.currentRequest = new Date().getTime();

				// extend default params with plugin options
				return $.extend({"previousRequest": fws.previousRequest, "currentRequest": fws.currentRequest}, opts.fallbackPollParams);
			}

			/**
			 * @param {Object} data
			 */
			function pollSuccess(data) {

				// trigger onmessage
				var messageEvent = {"data" : data};
				fws.onmessage(messageEvent);
			}

			function poll() {

				$.ajax({
					type: opts.fallbackPollMethod,
					url: opts.fallbackPollURL,
					dataType: 'text',
					data: getFallbackParams(),
					success: pollSuccess,
					error: function (xhr) {
						$(fws).triggerHandler('error');
					}
				});
			}

			// simulate open event and start polling
			openTimout = setTimeout(function () {
				fws.readyState = OPEN;
				//fws.currentRequest = new Date().getTime();
				$(fws).triggerHandler('open');
				poll();
				pollInterval = setInterval(poll, opts.fallbackPollInterval);

			}, opts.fallbackOpenDelay);

			// return socket impl
			return fws;
		}

		// create a new websocket or fallback
		var ws = window.WebSocket ? new WebSocket(url) : new FallbackSocket();
 		$(window).unload(function () { ws.close(); ws = null });
		return ws;
	}
};
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name passmanApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the passmanApp
 * This file is part of passman, licensed under AGPLv3
 */
angular.module('passmanApp')
	.controller('ShareCtrl', ['$scope', 'VaultService', 'CredentialService', 'SettingsService', '$location', '$routeParams', 'ShareService', 'NotificationService', 'SharingACL','EncryptService',
		function ($scope, VaultService, CredentialService, SettingsService, $location, $routeParams, ShareService, NotificationService, SharingACL, EncryptService) {
			$scope.active_vault = VaultService.getActiveVault();

			$scope.tabs = [{
				title: 'Share with users and groups',
				url: 'views/partials/forms/share_credential/basics.html',
			}, {
				title: 'Share link',
				url: 'views/partials/forms/share_credential/link_sharing.html',
				color: 'green'
			}];
			$scope.currentTab = {
				title: 'General',
				url: 'views/partials/forms/share_credential/basics.html'
			};

			$scope.onClickTab = function (tab) {
				$scope.currentTab = tab;
			};

			$scope.isActiveTab = function (tab) {
				return tab.url == $scope.currentTab.url;
			};

			if (!SettingsService.getSetting('defaultVault') || !SettingsService.getSetting('defaultVaultPass')) {
				if (!$scope.active_vault) {
					$location.path('/')
				}
			} else {
				if (SettingsService.getSetting('defaultVault') && SettingsService.getSetting('defaultVaultPass')) {
					var _vault = angular.copy(SettingsService.getSetting('defaultVault'));
					_vault.vaultKey = angular.copy(SettingsService.getSetting('defaultVaultPass'));
					VaultService.setActiveVault(_vault);
					$scope.active_vault = _vault;

				}
			}
			var storedCredential = SettingsService.getSetting('share_credential');

			if(!storedCredential) {
				$location.path('/vault/' + $routeParams.vault_id);
			} else {
				$scope.storedCredential = CredentialService.decryptCredential(angular.copy(storedCredential));
			}

			if ($scope.active_vault) {
				$scope.$parent.selectedVault = true;
			}
			$scope.cancel = function () {
				SettingsService.setSetting('share_credential', null);
				$location.path('/vault/' + $scope.storedCredential.vault_id);
			};

			$scope.default_permissions = new SharingACL(0);
			$scope.default_permissions.addPermission(
				$scope.default_permissions.permissions.READ |
				$scope.default_permissions.permissions.WRITE |
				$scope.default_permissions.permissions.FILES
			);

			var link_acl = angular.copy($scope.default_permissions);
			link_acl.removePermission($scope.default_permissions.permissions.WRITE)

			$scope.share_settings = {
				linkSharing: {
					enabled: false,
					settings: {
						expire_time: new Date("2999-12-31T22:59:59"),
						expire_views: 5,
						acl: link_acl
					}
				},
				credentialSharedWithUserAndGroup: [],
				cypher_progress: {
					done: 0,
					total: 0
				},
				upload_progress: {
					done: 0,
					total: 0
				}
			};

			ShareService.getSharedCredentialACL($scope.storedCredential).then(function (aclList) {

				var enc_key = ($scope.storedCredential.shared_key) ? EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key)) : false;

				for(var i = 0; i < aclList.length; i++){
					var acl = aclList[i];
					if(acl.user_id === null){
						$scope.share_settings.linkSharing ={
							enabled: true,
							settings: {
								expire_time: new Date(acl.expire * 1000),
								expire_views: acl.expire_views,
								acl: new SharingACL(acl.permissions)
							}
						};
						if(enc_key) {
							var hash = window.btoa($scope.storedCredential.guid + '<::>' + enc_key)
							$scope.share_link = $location.$$protocol + '://' + $location.$$host + OC.generateUrl('apps/passman/share/public#') + hash;
						}
					} else {
						var obj = {
							userId: acl.user_id,
							displayName: acl.user_id,
							type: 'user',
							acl: new SharingACL(acl.permissions),
							acl_id: acl.acl_id
						};

						$scope.share_settings.credentialSharedWithUserAndGroup.push(obj);
					}

				}
			});

			var acl = new SharingACL(0);

			$scope.inputSharedWith = [];
			$scope.selectedAccessLevel = '1';

			$scope.searchUsers = function ($query) {
				return ShareService.search($query)
			};

			$scope.hasPermission = function(acl, permission){
				return acl.hasPermission(permission);
			};

			$scope.setPermission = function(acl, permission){
				acl.togglePermission(permission);
			};

			$scope.shareWith = function (shareWith, selectedAccessLevel) {
				//@TODO Improve this so we can add, edit and remove users and permissions.
				$scope.inputSharedWith = [];
				if (shareWith.length > 0) {
					for (var i = 0; i < shareWith.length; i++) {
						var obj = {
							userId: shareWith[i].uid,
							displayName: shareWith[i].text,
							type: shareWith[i].type,
							acl: angular.copy($scope.default_permissions)
						};
						if ($scope.share_settings.credentialSharedWithUserAndGroup.indexOf(obj) === -1) {
							$scope.share_settings.credentialSharedWithUserAndGroup.push(obj)
						}
					}
				}
			};

			$scope.unshareCredential = function (credential) {
				ShareService.unshareCredential(credential);
				var _credential = angular.copy(credential);
				_credential.shared_key = null;
				CredentialService.updateCredential(_credential).then(function () {
					NotificationService.showNotification('Credential unshared', 4000)
				})
			};

			/**
			 * Apply a share to a new user
			 * @param user A user object to who we should share the data
			 * @param enc_key The shared key we are going to ecnrypt with his public rsa key
			 */
			$scope.applyShareToUser = function (user, enc_key) {
				ShareService.getVaultsByUser(user.userId).then(function (data) {
					$scope.share_settings.cypher_progress.total += data.length;

					user.vaults = data;
					var start = new Date().getTime() / 1000;
					console.log('Begin messing with permissions');
					ShareService.cypherRSAStringWithPublicKeyBulkAsync(user.vaults, enc_key)
						.progress(function (data) {
							$scope.share_settings.cypher_progress.done++;
							$scope.share_settings.cypher_progress.percent = $scope.share_settings.cypher_progress.done / $scope.share_settings.cypher_progress.total * 100;
							$scope.$digest();
						})
						.then(function (result) {
							console.log("Took: " + ((new Date().getTime() / 1000) - start) + "s to cypher the string for user [" + data[0].user_id + "]");
							$scope.share_settings.cypher_progress.times.push({
								time: ((new Date().getTime() / 1000) - start),
								user: data[0].user_id
							});
							user.vaults = result;
							console.log(user)
							$scope.uploadChanges(user);
							$scope.$digest();
						});
				});
			};

			$scope.applyShare = function () {
				$scope.share_settings.cypher_progress.percent = 0;
				$scope.share_settings.cypher_progress.done = 0;
				$scope.share_settings.cypher_progress.total = 0;
				$scope.share_settings.cypher_progress.times = [];
				$scope.share_settings.cypher_progress.times_total = [];
				$scope.share_settings.upload_progress.done = 0;
				$scope.share_settings.upload_progress.total = 0;

				console.log($scope.storedCredential);
				//Credential is already shared
				if($scope.storedCredential.shared_key && $scope.storedCredential.shared_key != '' && $scope.storedCredential.shared_key != null){
					console.log('Shared key found');
					if($scope.share_settings.linkSharing.enabled){
						var expire_time = new Date(angular.copy( $scope.share_settings.linkSharing.settings.expire_time)).getTime()/1000;
						var shareObj = {
							item_id: $scope.storedCredential.credential_id,
							item_guid: $scope.storedCredential.guid,
							permissions: $scope.share_settings.linkSharing.settings.acl.getAccessLevel(),
							expire_timestamp: expire_time,
							expire_views: $scope.share_settings.linkSharing.settings.expire_views
						};
						//ShareService.createPublicSharedCredential(shareObj);
					}

					var list = $scope.share_settings.credentialSharedWithUserAndGroup;
					console.log(list);
					var enc_key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
					for (var i = 0; i < list.length; i++) {
						var iterator = i;
						var target_user = list[i];
						console.log(target_user)
						if(target_user.hasOwnProperty('acl_id')){
							var acl = {
								user_id: target_user.userId,
								permission: target_user.acl.getAccessLevel()
							};
							ShareService.updateCredentialAcl($scope.storedCredential, acl);
						} else {
							$scope.applyShareToUser(list[iterator], enc_key);
						}
					}

				} else {

					ShareService.generateSharedKey(20).then(function (key) {

						var encryptedSharedCredential = ShareService.encryptSharedCredential($scope.storedCredential, key);
						CredentialService.updateCredential(encryptedSharedCredential, true);

						var list = $scope.share_settings.credentialSharedWithUserAndGroup;
						console.log(list);
						for (var i = 0; i < list.length; i++) {
							if (list[i].type == "user") {
								$scope.applyShareToUser(list[i], key);
							}
						}

						if($scope.share_settings.linkSharing.enabled){
							var expire_time = new Date(angular.copy( $scope.share_settings.linkSharing.settings.expire_time)).getTime()/1000;
							var shareObj = {
								item_id: $scope.storedCredential.credential_id,
								item_guid: $scope.storedCredential.guid,
								permissions: $scope.share_settings.linkSharing.settings.acl.getAccessLevel(),
								expire_timestamp: expire_time,
								expire_views: $scope.share_settings.linkSharing.settings.expire_views
							};
							ShareService.createPublicSharedCredential(shareObj).then(function(){
								var hash = window.btoa($scope.storedCredential.guid + '<::>'+ key)
								$scope.share_link = $location.$$protocol + '://' + $location.$$host + OC.generateUrl('apps/passman/share/public#') + hash;

							});
						}
						NotificationService.showNotification('Credential shared', 4000)
					})
				}
			};

			$scope.uploadChanges = function (user) {
				$scope.share_settings.upload_progress.total ++;

				user.accessLevel = angular.copy(user.acl.getAccessLevel());
				ShareService.shareWithUser(storedCredential, user)
				.then(function(data){
					$scope.share_settings.upload_progress.done ++;
					$scope.share_settings.upload_progress.percent = $scope.share_settings.upload_progress.done / $scope.share_settings.upload_progress.total * 100;
				});
			};

			$scope.calculate_total_time = function () {
				$scope.share_settings.cypher_progress.times = $scope.share_settings.cypher_progress.times || [];
				var total = 0;
				for (var i = 0; i < $scope.share_settings.cypher_progress.times.length; i++) {
					total += $scope.share_settings.cypher_progress.times[i].time;
				}
				return total;
			}
		}]);
<commit_msg>Fixing stuff<commit_after>'use strict';

/**
 * @ngdoc function
 * @name passmanApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the passmanApp
 * This file is part of passman, licensed under AGPLv3
 */
angular.module('passmanApp')
	.controller('ShareCtrl', ['$scope', 'VaultService', 'CredentialService', 'SettingsService', '$location', '$routeParams', 'ShareService', 'NotificationService', 'SharingACL','EncryptService',
		function ($scope, VaultService, CredentialService, SettingsService, $location, $routeParams, ShareService, NotificationService, SharingACL, EncryptService) {
			$scope.active_vault = VaultService.getActiveVault();

			$scope.tabs = [{
				title: 'Share with users and groups',
				url: 'views/partials/forms/share_credential/basics.html',
			}, {
				title: 'Share link',
				url: 'views/partials/forms/share_credential/link_sharing.html',
				color: 'green'
			}];
			$scope.currentTab = {
				title: 'General',
				url: 'views/partials/forms/share_credential/basics.html'
			};

			$scope.onClickTab = function (tab) {
				$scope.currentTab = tab;
			};

			$scope.isActiveTab = function (tab) {
				return tab.url == $scope.currentTab.url;
			};

			if (!SettingsService.getSetting('defaultVault') || !SettingsService.getSetting('defaultVaultPass')) {
				if (!$scope.active_vault) {
					$location.path('/')
				}
			} else {
				if (SettingsService.getSetting('defaultVault') && SettingsService.getSetting('defaultVaultPass')) {
					var _vault = angular.copy(SettingsService.getSetting('defaultVault'));
					_vault.vaultKey = angular.copy(SettingsService.getSetting('defaultVaultPass'));
					VaultService.setActiveVault(_vault);
					$scope.active_vault = _vault;

				}
			}
			var storedCredential = SettingsService.getSetting('share_credential');

			if(!storedCredential) {
				$location.path('/vault/' + $routeParams.vault_id);
			} else {
				$scope.storedCredential = CredentialService.decryptCredential(angular.copy(storedCredential));
			}

			if ($scope.active_vault) {
				$scope.$parent.selectedVault = true;
			}
			$scope.cancel = function () {
				SettingsService.setSetting('share_credential', null);
				$location.path('/vault/' + $scope.storedCredential.vault_id);
			};

			$scope.default_permissions = new SharingACL(0);
			$scope.default_permissions.addPermission(
				$scope.default_permissions.permissions.READ |
				$scope.default_permissions.permissions.WRITE |
				$scope.default_permissions.permissions.FILES
			);

			var link_acl = angular.copy($scope.default_permissions);
			link_acl.removePermission($scope.default_permissions.permissions.WRITE)

			$scope.share_settings = {
				linkSharing: {
					enabled: false,
					settings: {
						expire_time: new Date("2999-12-31T22:59:59"),
						expire_views: 5,
						acl: link_acl
					}
				},
				credentialSharedWithUserAndGroup: [],
				cypher_progress: {
					done: 0,
					total: 0
				},
				upload_progress: {
					done: 0,
					total: 0
				}
			};

			ShareService.getSharedCredentialACL($scope.storedCredential).then(function (aclList) {

				var enc_key = ($scope.storedCredential.shared_key) ? EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key)) : false;

				for(var i = 0; i < aclList.length; i++){
					var acl = aclList[i];
					if(acl.user_id === null){
						$scope.share_settings.linkSharing ={
							enabled: true,
							settings: {
								expire_time: new Date(acl.expire * 1000),
								expire_views: acl.expire_views,
								acl: new SharingACL(acl.permissions)
							}
						};
						if(enc_key) {
							var hash = window.btoa($scope.storedCredential.guid + '<::>' + enc_key)
							$scope.share_link = $location.$$protocol + '://' + $location.$$host + OC.generateUrl('apps/passman/share/public#') + hash;
						}
					} else {
						var obj = {
							userId: acl.user_id,
							displayName: acl.user_id,
							type: 'user',
							acl: new SharingACL(acl.permissions),
							acl_id: acl.acl_id
						};

						$scope.share_settings.credentialSharedWithUserAndGroup.push(obj);
					}

				}
			});

			var acl = new SharingACL(0);

			$scope.inputSharedWith = [];
			$scope.selectedAccessLevel = '1';

			$scope.searchUsers = function ($query) {
				return ShareService.search($query)
			};

			$scope.hasPermission = function(acl, permission){
				return acl.hasPermission(permission);
			};

			$scope.setPermission = function(acl, permission){
				acl.togglePermission(permission);
			};

			$scope.shareWith = function (shareWith, selectedAccessLevel) {
				//@TODO Improve this so we can add, edit and remove users and permissions.
				$scope.inputSharedWith = [];
				if (shareWith.length > 0) {
					for (var i = 0; i < shareWith.length; i++) {
						var obj = {
							userId: shareWith[i].uid,
							displayName: shareWith[i].text,
							type: shareWith[i].type,
							acl: angular.copy($scope.default_permissions)
						};
						if ($scope.share_settings.credentialSharedWithUserAndGroup.indexOf(obj) === -1) {
							$scope.share_settings.credentialSharedWithUserAndGroup.push(obj)
						}
					}
				}
			};

			$scope.unshareCredential = function (credential) {
				ShareService.unshareCredential(credential);
				var _credential = angular.copy(credential);
				_credential.shared_key = null;
				CredentialService.updateCredential(_credential).then(function () {
					NotificationService.showNotification('Credential unshared', 4000)
				})
			};

			/**
			 * Apply a share to a new user
			 * @param user A user object to who we should share the data
			 * @param enc_key The shared key we are going to ecnrypt with his public rsa key
			 */
			$scope.applyShareToUser = function (user, enc_key) {
				ShareService.getVaultsByUser(user.userId).then(function (data) {
					$scope.share_settings.cypher_progress.total += data.length;

					user.vaults = data;
					var start = new Date().getTime() / 1000;
					console.log('Begin messing with permissions');
					ShareService.cypherRSAStringWithPublicKeyBulkAsync(user.vaults, enc_key)
						.progress(function (data) {
							$scope.share_settings.cypher_progress.done++;
							$scope.share_settings.cypher_progress.percent = $scope.share_settings.cypher_progress.done / $scope.share_settings.cypher_progress.total * 100;
							$scope.$digest();
						})
						.then(function (result) {
							console.log("Took: " + ((new Date().getTime() / 1000) - start) + "s to cypher the string for user [" + data[0].user_id + "]");
							$scope.share_settings.cypher_progress.times.push({
								time: ((new Date().getTime() / 1000) - start),
								user: data[0].user_id
							});
							user.vaults = result;
							if(!user.hasOwnProperty('acl')) {
								$scope.uploadChanges(user);
							}
							$scope.$digest();
						});
				});
			};

			$scope.applyShare = function () {
				$scope.share_settings.cypher_progress.percent = 0;
				$scope.share_settings.cypher_progress.done = 0;
				$scope.share_settings.cypher_progress.total = 0;
				$scope.share_settings.cypher_progress.times = [];
				$scope.share_settings.cypher_progress.times_total = [];
				$scope.share_settings.upload_progress.done = 0;
				$scope.share_settings.upload_progress.total = 0;

				console.log($scope.storedCredential);
				//Credential is already shared
				if($scope.storedCredential.shared_key && $scope.storedCredential.shared_key != '' && $scope.storedCredential.shared_key != null){
					console.log('Shared key found');
					var enc_key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
					if($scope.share_settings.linkSharing.enabled){
						var expire_time = new Date(angular.copy( $scope.share_settings.linkSharing.settings.expire_time)).getTime()/1000;
						var shareObj = {
							item_id: $scope.storedCredential.credential_id,
							item_guid: $scope.storedCredential.guid,
							permissions: $scope.share_settings.linkSharing.settings.acl.getAccessLevel(),
							expire_timestamp: expire_time,
							expire_views: $scope.share_settings.linkSharing.settings.expire_views
						};
						ShareService.createPublicSharedCredential(shareObj).then(function () {
							var hash = window.btoa($scope.storedCredential.guid + '<::>'+ enc_key)
							$scope.share_link = $location.$$protocol + '://' + $location.$$host + OC.generateUrl('apps/passman/share/public#') + hash;
						})
					}

					var list = $scope.share_settings.credentialSharedWithUserAndGroup;
					console.log(list);

					for (var i = 0; i < list.length; i++) {
						var iterator = i;
						var target_user = list[i];
						console.log(target_user)
						if(target_user.hasOwnProperty('acl_id')){
							var acl = {
								user_id: target_user.userId,
								permission: target_user.acl.getAccessLevel()
							};
							ShareService.updateCredentialAcl($scope.storedCredential, acl);
						} else {
							$scope.applyShareToUser(list[iterator], enc_key);
						}
					}

				} else {

					ShareService.generateSharedKey(20).then(function (key) {

						var encryptedSharedCredential = ShareService.encryptSharedCredential($scope.storedCredential, key);
						CredentialService.updateCredential(encryptedSharedCredential, true).then(function(sharedCredential){
							$scope.storedCredential = ShareService.decryptSharedCredential(sharedCredential, key);
						});

						var list = $scope.share_settings.credentialSharedWithUserAndGroup;
						console.log(list);
						for (var i = 0; i < list.length; i++) {
							if (list[i].type == "user") {
								$scope.applyShareToUser(list[i], key);
							}
						}

						if($scope.share_settings.linkSharing.enabled){
							var expire_time = new Date(angular.copy( $scope.share_settings.linkSharing.settings.expire_time)).getTime()/1000;
							var shareObj = {
								item_id: $scope.storedCredential.credential_id,
								item_guid: $scope.storedCredential.guid,
								permissions: $scope.share_settings.linkSharing.settings.acl.getAccessLevel(),
								expire_timestamp: expire_time,
								expire_views: $scope.share_settings.linkSharing.settings.expire_views
							};
							ShareService.createPublicSharedCredential(shareObj).then(function(){
								var hash = window.btoa($scope.storedCredential.guid + '<::>'+ key);
								$scope.share_link = $location.$$protocol + '://' + $location.$$host + OC.generateUrl('apps/passman/share/public#') + hash;

							});
						}
						NotificationService.showNotification('Credential shared', 4000)
					})
				}
			};

			$scope.uploadChanges = function (user) {
				$scope.share_settings.upload_progress.total ++;

				user.accessLevel = angular.copy(user.acl.getAccessLevel());
				ShareService.shareWithUser(storedCredential, user)
				.then(function(data){
					$scope.share_settings.upload_progress.done ++;
					$scope.share_settings.upload_progress.percent = $scope.share_settings.upload_progress.done / $scope.share_settings.upload_progress.total * 100;
				});
			};

			$scope.calculate_total_time = function () {
				$scope.share_settings.cypher_progress.times = $scope.share_settings.cypher_progress.times || [];
				var total = 0;
				for (var i = 0; i < $scope.share_settings.cypher_progress.times.length; i++) {
					total += $scope.share_settings.cypher_progress.times[i].time;
				}
				return total;
			}
		}]);
<|endoftext|>


<commit_before>/*

_____                                                   ______           _   _
|  __ \                                                 |  ____|         | | | |
| |  | | ___ _ __ ___   ___   ___ _ __ __ _  ___ _   _  | |__   __ _ _ __| |_| |__
| |  | |/ _ \ '_ ` _ \ / _ \ / __| '__/ _` |/ __| | | | |  __| / _` | '__| __| '_ \
| |__| |  __/ | | | | | (_) | (__| | | (_| | (__| |_| |_| |___| (_| | |  | |_| | | |
|_____/ \___|_| |_| |_|\___/ \___|_|  \__,_|\___|\__, (_)______\__,_|_|   \__|_| |_/
                                                  __/ |
                                                 |___/

"You never change things by fighting the existing reality. To change something
build a new model that makes the existing model obsolete."
Buckminster Fuller, Great San Francisco Architect.

A Roma, <3

*/

/* global alert */

import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/tap:i18n';
import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { SearchSource } from 'meteor/meteorhacks:search-source';
import { Template } from 'meteor/templating';

import { toggleSidebar } from '/imports/ui/modules/menu';
import { globalObj } from '/lib/global';
import { geo } from '/lib/geo';
import { token } from '/lib/token';
import { gui } from '/lib/const';
import { getCSS } from '/imports/ui/templates/layout/templater';
import { resetSplit } from '/imports/ui/modules/split';

import '/imports/ui/templates/layout/main.html';
import '/imports/ui/templates/widgets/modal/modal';
import '/imports/ui/templates/widgets/popup/popup';
import '/imports/ui/templates/layout/sidebar/sidebar';
import '/imports/ui/templates/layout/navigation/navigation';
import '/imports/ui/templates/layout/response/verifyEmail/verifyEmail';
import '/imports/ui/templates/layout/touchmenu/touchmenu';
import '/imports/ui/templates/components/decision/editor/editor';

/*
* head content
*/
const _head = () => {
  // icons
  const icon = $('<link>', {
    rel: 'shortcut icon',
    type: 'image/x-icon',
    href: `${Meteor.settings.public.Collective.profile.logo}`,
  });
  const mobile = $('<link>', {
    rel: 'apple-touch-icon',
    href: `${Meteor.settings.public.Collective.profile.logo}`,
  });

  $('head').append(icon);
  $('head').append(mobile);

  // design
  getCSS();
};

Meteor.startup(() => {
  // setup language
  Session.set('showLoadingIndicator', true);

  // internationalization library
  TAPi18n.setLanguage(Meteor.settings.public.app.language)
    .done(function () {
      Session.set('showLoadingIndicator', false);
    })
    .fail(function (errorMessage) {
      console.log(errorMessage);
    });

  // scripts
  // $.getScript('js/datepicker.js', () => {});

  // head
  _head();

  // time
  Meteor.setInterval(function () {
    Meteor.call('getServerTime', function (error, result) {
      Session.set('time', result);
    });
  }, 60000);

  // search Engine for Tags
  Session.set('createTag', false);
  globalObj.TagSearch = new SearchSource('tags', ['text', 'url'], {
    keepHistory: 1000 * 60 * 5,
    localSearch: true,
  });

  // search Engine for Proposals
  Session.set('createProposal', false);
  globalObj.ProposalSearch = new SearchSource('contracts', ['title', 'description'], {
    keepHistory: 1000 * 60 * 5,
    localSearch: true,
  });

  // geographical sovereignty
  globalObj.geoJSON = geo;

  // cryptographical sovereignty
  globalObj.tokenJSON = token;
});

const _done = () => {
  $('.preloader-image').velocity({ opacity: 0 }, {
    duration: 350,
    complete: () => {
      resetSplit();
      document.getElementById('preloader-splash').remove();
    },
  });
};

Template.main.onRendered(() => {
  if (document.getElementsByClassName('inhibitor').length > 0) {
    document.getElementsByClassName('inhibitor')[0].addEventListener('touchmove', (e) => { e.preventDefault(); });
  }

  if (!Meteor.Device.isPhone() && $(window).width() < gui.MOBILE_MAX_WIDTH) {
    $('.navbar').css('left', 0);
    Session.set('miniWindow', true);
    if (Meteor.user()) { Session.set('sidebar', true); }
    toggleSidebar();
  } else if (!Meteor.Device.isPhone()) {
    Session.set('sidebar', false);
    toggleSidebar();
  }
});

Template.preloader.onRendered(() => {
  const interval = setInterval(function () {
    if (document.readyState === 'complete') {
      clearInterval(interval);
      document.getElementsByClassName('preloader-image')[0].style.opacity = 1;
      _done();
    }
    const opacity = document.getElementsByClassName('preloader-image')[0].style.opacity.toNumber();
    const newShade = parseFloat(opacity + 0.01, 10);
    if (newShade <= 1) {
      document.getElementsByClassName('preloader-image')[0].style.opacity = newShade;
    }
  }, 100);
});

Template.preloader.helpers({
  appIcon() {
    if (Meteor.settings.public.Collective.profile.logo) {
      return Meteor.settings.public.Collective.profile.logo;
    }
    return 'images/olive.png';
  },
});

Template.main.helpers({
  popupList() {
    return Session.get('popupList');
  },
  showNotice() {
    return Session.get('showNotice');
  },
  landingStyle() {
    if (!Meteor.user()) {
      return 'right-hero';
    }
    return '';
  },
  loggedWithPhone() {
    return (Meteor.Device.isPhone() && Meteor.user());
  },
});

Template.main.events({
  'click .inhibitor'() {
    toggleSidebar();
  },
});

export const head = _head;
<commit_msg>show preloader image with absolute path<commit_after>/*

_____                                                   ______           _   _
|  __ \                                                 |  ____|         | | | |
| |  | | ___ _ __ ___   ___   ___ _ __ __ _  ___ _   _  | |__   __ _ _ __| |_| |__
| |  | |/ _ \ '_ ` _ \ / _ \ / __| '__/ _` |/ __| | | | |  __| / _` | '__| __| '_ \
| |__| |  __/ | | | | | (_) | (__| | | (_| | (__| |_| |_| |___| (_| | |  | |_| | | |
|_____/ \___|_| |_| |_|\___/ \___|_|  \__,_|\___|\__, (_)______\__,_|_|   \__|_| |_/
                                                  __/ |
                                                 |___/

"You never change things by fighting the existing reality. To change something
build a new model that makes the existing model obsolete."
Buckminster Fuller, Great San Francisco Architect.

A Roma, <3

*/

/* global alert */

import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/tap:i18n';
import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { SearchSource } from 'meteor/meteorhacks:search-source';
import { Template } from 'meteor/templating';
import { Router } from 'meteor/iron:router';

import { toggleSidebar } from '/imports/ui/modules/menu';
import { globalObj } from '/lib/global';
import { geo } from '/lib/geo';
import { token } from '/lib/token';
import { gui } from '/lib/const';
import { getCSS } from '/imports/ui/templates/layout/templater';
import { resetSplit } from '/imports/ui/modules/split';

import '/imports/ui/templates/layout/main.html';
import '/imports/ui/templates/widgets/modal/modal';
import '/imports/ui/templates/widgets/popup/popup';
import '/imports/ui/templates/layout/sidebar/sidebar';
import '/imports/ui/templates/layout/navigation/navigation';
import '/imports/ui/templates/layout/response/verifyEmail/verifyEmail';
import '/imports/ui/templates/layout/touchmenu/touchmenu';
import '/imports/ui/templates/components/decision/editor/editor';

/*
* head content
*/
const _head = () => {
  // icons
  const icon = $('<link>', {
    rel: 'shortcut icon',
    type: 'image/x-icon',
    href: `${Meteor.settings.public.Collective.profile.logo}`,
  });
  const mobile = $('<link>', {
    rel: 'apple-touch-icon',
    href: `${Meteor.settings.public.Collective.profile.logo}`,
  });

  $('head').append(icon);
  $('head').append(mobile);

  // design
  getCSS();
};

Meteor.startup(() => {
  // setup language
  Session.set('showLoadingIndicator', true);

  // internationalization library
  TAPi18n.setLanguage(Meteor.settings.public.app.language)
    .done(function () {
      Session.set('showLoadingIndicator', false);
    })
    .fail(function (errorMessage) {
      console.log(errorMessage);
    });

  // scripts
  // $.getScript('js/datepicker.js', () => {});

  // head
  _head();

  // time
  Meteor.setInterval(function () {
    Meteor.call('getServerTime', function (error, result) {
      Session.set('time', result);
    });
  }, 60000);

  // search Engine for Tags
  Session.set('createTag', false);
  globalObj.TagSearch = new SearchSource('tags', ['text', 'url'], {
    keepHistory: 1000 * 60 * 5,
    localSearch: true,
  });

  // search Engine for Proposals
  Session.set('createProposal', false);
  globalObj.ProposalSearch = new SearchSource('contracts', ['title', 'description'], {
    keepHistory: 1000 * 60 * 5,
    localSearch: true,
  });

  // geographical sovereignty
  globalObj.geoJSON = geo;

  // cryptographical sovereignty
  globalObj.tokenJSON = token;
});

const _done = () => {
  $('.preloader-image').velocity({ opacity: 0 }, {
    duration: 350,
    complete: () => {
      resetSplit();
      document.getElementById('preloader-splash').remove();
    },
  });
};

Template.main.onRendered(() => {
  if (document.getElementsByClassName('inhibitor').length > 0) {
    document.getElementsByClassName('inhibitor')[0].addEventListener('touchmove', (e) => { e.preventDefault(); });
  }

  if (!Meteor.Device.isPhone() && $(window).width() < gui.MOBILE_MAX_WIDTH) {
    $('.navbar').css('left', 0);
    Session.set('miniWindow', true);
    if (Meteor.user()) { Session.set('sidebar', true); }
    toggleSidebar();
  } else if (!Meteor.Device.isPhone()) {
    Session.set('sidebar', false);
    toggleSidebar();
  }
});

Template.preloader.onRendered(() => {
  const interval = setInterval(function () {
    if (document.readyState === 'complete') {
      clearInterval(interval);
      document.getElementsByClassName('preloader-image')[0].style.opacity = 1;
      _done();
    }
    const opacity = document.getElementsByClassName('preloader-image')[0].style.opacity.toNumber();
    const newShade = parseFloat(opacity + 0.01, 10);
    if (newShade <= 1) {
      document.getElementsByClassName('preloader-image')[0].style.opacity = newShade;
    }
  }, 100);
});

Template.preloader.helpers({
  appIcon() {
    if (Meteor.settings.public.Collective.profile.logo) {
      return `${Router.path('home')}${Meteor.settings.public.Collective.profile.logo}`;
    }
    return `${Router.path('home')}images/olive.png`;
  },
});

Template.main.helpers({
  popupList() {
    return Session.get('popupList');
  },
  showNotice() {
    return Session.get('showNotice');
  },
  landingStyle() {
    if (!Meteor.user()) {
      return 'right-hero';
    }
    return '';
  },
  loggedWithPhone() {
    return (Meteor.Device.isPhone() && Meteor.user());
  },
});

Template.main.events({
  'click .inhibitor'() {
    toggleSidebar();
  },
});

export const head = _head;
<|endoftext|>