<commit_before>define( 'providers/colabs', [
    'providers',
    'jquery',
    'gizmo/superdesk',
    config.guiJs('livedesk', 'models/blog'),
    config.guiJs('livedesk', 'models/collaborator'),
    config.guiJs('superdesk/user', 'models/person'),
    config.guiJs('livedesk', 'action'),
    config.guiJs('superdesk/user', 'jquery/avatar'),
    config.guiJs('livedesk', 'providers-templates'),
    'tmpl!livedesk>items/item',
    'tmpl!livedesk>items/implementors/collaborators',
    'providers/colabs/adaptor',
    'tmpl!livedesk>providers/colabs',
    'tmpl!livedesk>providers/colabs/items' ],

function(providers, $, giz, Blog, Collaborator, Person, BlogAction)
{
    var config = { updateInterval: 10 },
        colabsList = [],
        colabsHidden = {},
        updateInterval = 0,
        intervalRunning = false,
        updateItemCount = 0,
        postDateList = [],
        userImages = [];

    var addUserImages = function()
    {
        for(var i=0; i<userImages.length; i++)
            colabView.el.find('[data-colab-id="'+userImages[i].UserId+'"] figure')
                .html('');
    },

    getDraggableHelper = function(evt)
    {
        var listItem = $(evt.currentTarget),
            helperElem = $('
').css('max-width', '38%');
        listItem.clone().appendTo(helperElem);
        return helperElem;
    },

    // single post item view
    PostView = giz.View.extend
    ({
        init: function(opts)
        {
            this.model.on('update', this.render, this);
			this.model.on('read', this.render, this);
			this.model.on('delete', this.remove, this); // TODO should remove from ColabView?
        },
        render: function(evt)
        {
            /*!
             * @TODO implement this with IsCollectionDeleted Method
             * Ugly hack to remove published posts.
             */
            if(this.model.get('PublishedOn') || (this.model.get('IsPublished') === 'True'))
            {
                this.remove();
                return;
            }

            var self = this,
                post = this.model.feed(true);
			if($.type(post.Meta) === 'string')
				post.Meta = JSON.parse(post.Meta);
			$.avatar.setImage(post, { needle: 'AuthorPerson.EMail', size: 36});

			$.tmpl('livedesk>items/item', { Post: post, Base: 'implementors/collaborators' },
                function(e,o)
                {
                    self.setElement(o);

                    /*!
                     * need to check if collaborator was previously hidden
                     * because update events are triggered from all over the place and will
                     * render this again and show the element regardless of prev. status
                     */
                    if( colabsHidden[parseInt(post.Creator.Id)] ) self.el.addClass('hide');

                    BlogAction.get('modules.livedesk.blog-post-publish')
                    .done(function(action)
                    {
                        self.el.hasClass('draggable') && self.el.draggable
                        ({
                            addClasses: false,
                            revert: 'invalid',
                            containment:'document',
                            helper: getDraggableHelper, //'clone',
                            appendTo: 'body',
                            zIndex: 2700,
                            clone: true,
                            start: function(evt, ui) { $(this).data('post', self.model); }
                        });
                    })
                    .fail(function(){ el.removeClass('draggable'); });
                });
			//dynamically get size of header and set top space for list
            var top_space = $('.collaborators-header').outerHeight() + 20;
            $('.post-list.collabs').css({'top': top_space});

            return self;
        },

        remove: function()
        {
            var pos = this.colab.get('PostUnpublished')._list.indexOf(this.model),
                pos2 = this.colab._viewModels.indexOf(this.model.get('Id'));
            if( pos !== -1 )
                this.colab.get('PostUnpublished')._list.splice(pos,1);
            if( pos2 !== -1 )
                this.colab._viewModels.splice(pos2,1);
            this.el.remove();
        }
    }),
    // main view
    ColabView = giz.View.extend
    ({
        namespace: 'livedesk',
        events:
        {
            //'.collaborators-header .feed-info .label': {'click': 'toggleHeader'},
            '.new-results': {'update': 'showNewResults'}
        },

        toggleHeader: function()
        {
            var colabId = $(this).attr('data-colab-id'),
                posts = $(this).parents('.collaborators-header')
                            .nextAll('.post-list').find('li[data-colab-id='+colabId+']');

            if($(this).data('is-off'))
            {
                delete colabsHidden[colabId];
                posts.removeClass('hide');
                $(this).addClass('label-info').data('is-off', false);
            }
            else
            {
                colabsHidden[parseInt(colabId)] = true;
                posts.addClass('hide');
                $(this).removeClass('label-info').data('is-off', true);
            }
        },
        /*!
         * @param e event
         * @param count
         * @param callback
         * @param wether to do update auto. or add a click-to-show button
         */
        showNewResults: function(e, count, callback, auto)
        {
            if( !$('.'+providers.colabs.className).parents('li:eq(0)').hasClass('active') )
                this.notifications.removeClass('hide').text(count);

            var self = $('.new-results', this.el),
                notifications = this.notifications,
                cb = function()
                {
                    notifications.addClass('hide');
                    self.addClass('hide');
                    callback.apply(this);
                };
            auto ? cb() : self.removeClass('hide').text( count+" "+_('new items! Update') ).one('click.livedesk', cb);
        },

        init: function()
        {
            this.notifications = $('.'+providers.colabs.className).parents('li:eq(0)').find('.notifications');
            this.notifications.addClass('hide');
            localStorage.setItem('superdesk.config.providers.colabs.notify', 0);

            $('.post-list', this.el).html('');

            $(this.el).on('click', '.collaborators-header .feed-info .label', this.toggleHeader);

            var blog = giz.Auth(new Blog(this.blogUrl)), // authenticated blog model
                self = this;

            self.el.html('
'+_('Loading collaborators...')+'
');

            self.colabsList = [];

            blog.sync().done(function()
            {
                var collaborators = blog.get('Collaborator');
                collaborators.on('read', function()
                {
                    self.colabsList = this;
                    self.setupHeader.call(self, this);
                    self.setupColabStream.call(self, this);
                });
                collaborators.xfilter('User.Id', 'User.FullName', 'User.EMail', 'PostUnpublished').sync();
            });

            $('.'+providers.colabs.className)
                .parents('li:eq(0)').find('.config-notif').off('click').on('click', self.configNotif);

            $('.'+providers.colabs.className)
                .parents('li:eq(0)').find('.config-notif')
                .attr('title',_('Click to turn notifications on or off
while this tab is hidden'))
                .tooltip({placement: 'right'});
        },

        /*!
         * update posts from collaborators,
         * call sync with cId.since parameter
         */
        update: function()
        {
            var self = this;
            this.colabsList.each(function()
            {
                var colab = this,
                    post = colab.get('PostUnpublished');
                // get post list and sync it with the server
                this.get('PostUnpublished')
                    .xfilter('*,Author.Source.*,Creator.*')
                    .sync({data: {'cId.since': this._latestPost}})
                    .done(function(data){ colab._latestPost = parseInt(data.lastCId);self.readPostsHandle.call(post, colab, $.noop, self); });
            });
        },
        /*!
         * display list header
         */
        setupHeader: function(colabs)
        {
            $(this.el).tmpl('livedesk>providers/colabs', {Colabs: colabs.feed('json', true)});
        },
        /*!
         * initial - initial count of collaborators
         */
        readPostsHandle: function(colab, initColabHandle, view )
        {
            // list of new posts to append
            var appendPosts = [],
                self = this;
            this.each(function()
            {
                //console.log('Id',this.get('Id'));
                if( $.inArray( this.get('Id'), colab._viewModels ) === -1 && !this.get('DeletedOn'))
                {
                    appendPosts.push(this);
                    colab._viewModels.push(this.get('Id'));
                }
                var pCId = parseInt(this.get('CId'));
                // store last id
                if(!isNaN(pCId)) colab._latestPost = Math.max(colab._latestPost, pCId);
            });
            updateItemCount += appendPosts.length;

            appendPosts.length &&
            $('.new-results', view.el).trigger('update.livedesk', [updateItemCount, function()
            {
                $(appendPosts.reverse()).each(function()
                {
                    // TODO very inefficient, refactoring on server needed
                    postDateList.push({ Date: this.get('CreatedOn'), Timestamp: (new Date(this.get('CreatedOn'))).getTime(), Id: this.get('Id') });
                    postDateList.sort(function(x, y){ return x.Timestamp >  y.Timestamp; });
                    for(var i=0; i<postDateList.length; i++)
                    {
                        if( parseInt(postDateList[i].Id) == parseInt(this.get('Id')) )
                        {
                            if( postDateList[i-1] )
                            {
                                (new PostView({ model: this, colab: colab })).render().el.insertBefore($('[data-post-id="'+postDateList[i-1].Id+'"]', view.el));
                                break;
                            }
                            else if( postDateList[i+1] )
                            {
                                (new PostView({ model: this, colab: colab })).render().el.insertAfter($('[data-post-id="'+postDateList[i+1].Id+'"]', view.el));
                                break;
                            }
                            else
                            {
                                $('.post-list', view.el).append( (new PostView({ model: this, colab: colab })).render().el );
                                break;
                            }
                        }
                    }
                    //if(this.get('IsPublished') !== 'True')
                    //    $('.post-list', view.el).prepend( (new PostView({ model: this, colab: colab })).render().el );
                });
                updateItemCount -= appendPosts.length;
            }, initColabHandle()]);
        },
        /*!
         * setup post list
         */
        setupColabStream: function(colabs)
        {
            var self = this,
                initColabCnt = colabs.count(),
                /*!
                 * used for breaking init. action, decrementing until 0
                 */
                initColabHandle = function()
                {
                    var ret = initColabCnt ? true : false;
                    initColabCnt -= 1; // decrement initial until 0 so we know when init is over and do not send
                    if(initColabCnt <= 0) initColabHandle = function(){ return false; }
                    return ret;
                };

            // collaboratos list
            colabs.each(function()
            {
                var colab = this;
                colab._latestPost = 0;
                colab._viewModels = [];
                colab.sync().done(function()
                {
                    // hacking user image
                    (new Person(Person.prototype.url.get()+'/'+colab.get('User').get('Id')))
                    .on('read', function()
                    {
                        var meta = this.get('MetaDataIcon')
                        meta.sync({data:{ thumbSize: 'medium' }}).done(function()
                        {
                            userImages.push({UserId: colab.get('User').get('Id'), Thumbnail: meta.get('Thumbnail').href});
                        });
                    })
                    .sync();

                    // get posts for each collaborator
                    var post = colab.get('PostUnpublished');
                    post.xfilter('*,Author.Source.*,Creator.*')
                        .sync()
                        .done(function(data){
                            //console.log('data:',data);
                            colab._latestPost = parseInt(data.lastCId)
                            self.readPostsHandle.call(post, colab, initColabHandle, self);
                        });
                    // start the auto update timers
                    self.startAutoUpdate();
                });

            });
        },
        startAutoUpdate: function()
        {
            var self = this;
            clearInterval(updateInterval);
            updateInterval = setInterval(function()
            {
                var cnfNotif = localStorage.getItem('superdesk.config.providers.colabs.notify');
                if(!$('.post-list:visible', self.el).length && !parseFloat(cnfNotif))
                {
                    clearInterval(updateInterval);
                    return;
                }
                self.update();
            }, config.updateInterval*1000);

            return self;
        },
        render: function(){},
        /*!
         * configure notifications on/off
         */
        configNotif: function()
        {
            var cnfNotif = localStorage.getItem('superdesk.config.providers.colabs.notify');
            if( !parseFloat(cnfNotif) )
            {
                localStorage.setItem('superdesk.config.providers.colabs.notify', 1);
                $(this).removeClass('badge-info').addClass('badge-warning');
            }
            else
            {
                localStorage.setItem('superdesk.config.providers.colabs.notify', 0);
                $(this).removeClass('badge-warning').addClass('badge-info');
            }
        }

    });

    var colabView = null;
    $.extend( providers.colabs, { init: function(blogUrl)
    {
        if( !colabView || (this.el.get(0) != colabView.el.get(0)) )
        {
            colabView = new ColabView({ el: this.el, blogUrl: blogUrl });
            return colabView.startAutoUpdate();
        }
        if( colabView ){  colabView.startAutoUpdate(); }
    }});

    return providers;
});<commit_msg>LB-772: Collaborator posts show only after reload<commit_after>define( 'providers/colabs', [
    'providers',
    'jquery',
    'gizmo/superdesk',
    config.guiJs('livedesk', 'models/blog'),
    config.guiJs('livedesk', 'models/collaborator'),
    config.guiJs('superdesk/user', 'models/person'),
    config.guiJs('livedesk', 'action'),
    config.guiJs('superdesk/user', 'jquery/avatar'),
    config.guiJs('livedesk', 'providers-templates'),
    'tmpl!livedesk>items/item',
    'tmpl!livedesk>items/implementors/collaborators',
    'providers/colabs/adaptor',
    'tmpl!livedesk>providers/colabs',
    'tmpl!livedesk>providers/colabs/items' ],

function(providers, $, giz, Blog, Collaborator, Person, BlogAction)
{
    var config = { updateInterval: 10 },
        colabsList = [],
        colabsHidden = {},
        updateInterval = 0,
        intervalRunning = false,
        updateItemCount = 0,
        postDateList = [],
        userImages = [];

    var addUserImages = function()
    {
        for(var i=0; i<userImages.length; i++)
            colabView.el.find('[data-colab-id="'+userImages[i].UserId+'"] figure')
                .html('');
    },

    getDraggableHelper = function(evt)
    {
        var listItem = $(evt.currentTarget),
            helperElem = $('
').css('max-width', '38%');
        listItem.clone().appendTo(helperElem);
        return helperElem;
    },

    // single post item view
    PostView = giz.View.extend
    ({
        init: function(opts)
        {
            this.model.on('update', this.render, this);
			this.model.on('read', this.render, this);
			this.model.on('delete', this.remove, this); // TODO should remove from ColabView?
        },
        render: function(evt)
        {
            /*!
             * @TODO implement this with IsCollectionDeleted Method
             * Ugly hack to remove published posts.
             */
            if(this.model.get('PublishedOn') || (this.model.get('IsPublished') === 'True'))
            {
                this.remove();
                return;
            }

            var self = this,
                post = this.model.feed(true);
			if($.type(post.Meta) === 'string')
				post.Meta = JSON.parse(post.Meta);
			$.avatar.setImage(post, { needle: 'AuthorPerson.EMail', size: 36});

			$.tmpl('livedesk>items/item', { Post: post, Base: 'implementors/collaborators' },
                function(e,o)
                {
                    self.setElement(o);

                    /*!
                     * need to check if collaborator was previously hidden
                     * because update events are triggered from all over the place and will
                     * render this again and show the element regardless of prev. status
                     */
                    if( colabsHidden[parseInt(post.Creator.Id)] ) self.el.addClass('hide');

                    BlogAction.get('modules.livedesk.blog-post-publish')
                    .done(function(action)
                    {
                        self.el.hasClass('draggable') && self.el.draggable
                        ({
                            addClasses: false,
                            revert: 'invalid',
                            containment:'document',
                            helper: getDraggableHelper, //'clone',
                            appendTo: 'body',
                            zIndex: 2700,
                            clone: true,
                            start: function(evt, ui) { $(this).data('post', self.model); }
                        });
                    })
                    .fail(function(){ el.removeClass('draggable'); });
                });
			//dynamically get size of header and set top space for list
            var top_space = $('.collaborators-header').outerHeight() + 20;
            $('.post-list.collabs').css({'top': top_space});

            return self;
        },

        remove: function()
        {
            var pos = this.colab.get('PostUnpublished')._list.indexOf(this.model),
                pos2 = this.colab._viewModels.indexOf(this.model.get('Id'));
            if( pos !== -1 )
                this.colab.get('PostUnpublished')._list.splice(pos,1);
            if( pos2 !== -1 )
                this.colab._viewModels.splice(pos2,1);
            this.el.remove();
        }
    }),
    // main view
    ColabView = giz.View.extend
    ({
        namespace: 'livedesk',
        events:
        {
            //'.collaborators-header .feed-info .label': {'click': 'toggleHeader'},
            '.new-results': {'update': 'showNewResults'}
        },

        toggleHeader: function()
        {
            var colabId = $(this).attr('data-colab-id'),
                posts = $(this).parents('.collaborators-header')
                            .nextAll('.post-list').find('li[data-colab-id='+colabId+']');

            if($(this).data('is-off'))
            {
                delete colabsHidden[colabId];
                posts.removeClass('hide');
                $(this).addClass('label-info').data('is-off', false);
            }
            else
            {
                colabsHidden[parseInt(colabId)] = true;
                posts.addClass('hide');
                $(this).removeClass('label-info').data('is-off', true);
            }
        },
        /*!
         * @param e event
         * @param count
         * @param callback
         * @param wether to do update auto. or add a click-to-show button
         */
        showNewResults: function(e, count, callback, auto)
        {
            if( !$('.'+providers.colabs.className).parents('li:eq(0)').hasClass('active') )
                this.notifications.removeClass('hide').text(count);

            var self = $('.new-results', this.el),
                notifications = this.notifications,
                cb = function()
                {
                    notifications.addClass('hide');
                    self.addClass('hide');
                    callback.apply(this);
                };
            auto ? cb() : self.removeClass('hide').text( count+" "+_('new items! Update') ).one('click.livedesk', cb);
        },

        init: function()
        {
            this.notifications = $('.'+providers.colabs.className).parents('li:eq(0)').find('.notifications');
            this.notifications.addClass('hide');
            localStorage.setItem('superdesk.config.providers.colabs.notify', 0);

            $('.post-list', this.el).html('');

            $(this.el).on('click', '.collaborators-header .feed-info .label', this.toggleHeader);

            var blog = giz.Auth(new Blog(this.blogUrl)), // authenticated blog model
                self = this;

            self.el.html('
'+_('Loading collaborators...')+'
');

            self.colabsList = [];

            blog.sync().done(function()
            {
                var collaborators = blog.get('Collaborator');
                collaborators.on('read', function()
                {
                    self.colabsList = this;
                    self.setupHeader.call(self, this);
                    self.setupColabStream.call(self, this);
                });
                collaborators.xfilter('User.Id', 'User.FullName', 'User.EMail', 'PostUnpublished').sync();
            });

            $('.'+providers.colabs.className)
                .parents('li:eq(0)').find('.config-notif').off('click').on('click', self.configNotif);

            $('.'+providers.colabs.className)
                .parents('li:eq(0)').find('.config-notif')
                .attr('title',_('Click to turn notifications on or off
while this tab is hidden'))
                .tooltip({placement: 'right'});

            postDateList = [];
        },

        /*!
         * update posts from collaborators,
         * call sync with cId.since parameter
         */
        update: function()
        {
            var self = this;
            this.colabsList.each(function()
            {
                var colab = this,
                    post = colab.get('PostUnpublished');
                // get post list and sync it with the server
                this.get('PostUnpublished')
                    .xfilter('*,Author.Source.*,Creator.*')
                    .sync({data: {'cId.since': this._latestPost}})
                    .done(function(data){ colab._latestPost = parseInt(data.lastCId);self.readPostsHandle.call(post, colab, $.noop, self); });
            });
        },
        /*!
         * display list header
         */
        setupHeader: function(colabs)
        {
            $(this.el).tmpl('livedesk>providers/colabs', {Colabs: colabs.feed('json', true)});
        },
        /*!
         * initial - initial count of collaborators
         */
        readPostsHandle: function(colab, initColabHandle, view )
        {
            // list of new posts to append
            var appendPosts = [],
                self = this;
            this.each(function()
            {
                if( $.inArray( this.get('Id'), colab._viewModels ) === -1 && !this.get('DeletedOn'))
                {
                    appendPosts.push(this);
                    colab._viewModels.push(this.get('Id'));
                }
                var pCId = parseInt(this.get('CId'));
                // store last id
                if(!isNaN(pCId)) colab._latestPost = Math.max(colab._latestPost, pCId);
            });
            updateItemCount += appendPosts.length;

            appendPosts.length &&
            $('.new-results', view.el).trigger('update.livedesk', [updateItemCount, function()
            {
                $(appendPosts.reverse()).each(function()
                {
                    // TODO very inefficient, refactoring on server needed
                    postDateList.push({ Date: this.get('CreatedOn'), Timestamp: (new Date(this.get('CreatedOn'))).getTime(), Id: this.get('Id') });
                    postDateList.sort(function(x, y){ return x.Timestamp >  y.Timestamp; });

                    for(var i=0; i<postDateList.length; i++)
                    {
                        if( parseInt(postDateList[i].Id) == parseInt(this.get('Id')) )
                        {
                            if( postDateList[i-1] )
                            {
                                (new PostView({ model: this, colab: colab })).render().el.insertBefore($('[data-post-id="'+postDateList[i-1].Id+'"]', view.el));
                                break;
                            }
                            else if( postDateList[i+1] )
                            {
                                (new PostView({ model: this, colab: colab })).render().el.insertAfter($('[data-post-id="'+postDateList[i+1].Id+'"]', view.el));
                                break;
                            }
                            else
                            {
                                $('.post-list', view.el).append( (new PostView({ model: this, colab: colab })).render().el );
                                break;
                            }
                        }
                    }
                    //if(this.get('IsPublished') !== 'True')
                    //    $('.post-list', view.el).prepend( (new PostView({ model: this, colab: colab })).render().el );
                });
                updateItemCount -= appendPosts.length;
            }, initColabHandle()]);
        },
        /*!
         * setup post list
         */
        setupColabStream: function(colabs)
        {
            var self = this,
                initColabCnt = colabs.count(),
                /*!
                 * used for breaking init. action, decrementing until 0
                 */
                initColabHandle = function()
                {
                    var ret = initColabCnt ? true : false;
                    initColabCnt -= 1; // decrement initial until 0 so we know when init is over and do not send
                    if(initColabCnt <= 0) initColabHandle = function(){ return false; }
                    return ret;
                };

            // collaboratos list
            colabs.each(function()
            {
                var colab = this;
                colab._latestPost = 0;
                colab._viewModels = [];
                colab.sync().done(function()
                {
                    // hacking user image
                    (new Person(Person.prototype.url.get()+'/'+colab.get('User').get('Id')))
                    .on('read', function()
                    {
                        var meta = this.get('MetaDataIcon')
                        meta.sync({data:{ thumbSize: 'medium' }}).done(function()
                        {
                            userImages.push({UserId: colab.get('User').get('Id'), Thumbnail: meta.get('Thumbnail').href});
                        });
                    })
                    .sync();

                    // get posts for each collaborator
                    var post = colab.get('PostUnpublished');
                    post.xfilter('*,Author.Source.*,Creator.*')
                        .sync()
                        .done(function(data){
                            colab._latestPost = parseInt(data.lastCId)
                            self.readPostsHandle.call(post, colab, initColabHandle, self);
                        });
                    // start the auto update timers
                    self.startAutoUpdate();
                });

            });
        },
        startAutoUpdate: function()
        {
            var self = this;
            clearInterval(updateInterval);
            updateInterval = setInterval(function()
            {
                var cnfNotif = localStorage.getItem('superdesk.config.providers.colabs.notify');
                if(!$('.post-list:visible', self.el).length && !parseFloat(cnfNotif))
                {
                    clearInterval(updateInterval);
                    return;
                }
                self.update();
            }, config.updateInterval*1000);

            return self;
        },
        render: function(){},
        /*!
         * configure notifications on/off
         */
        configNotif: function()
        {
            var cnfNotif = localStorage.getItem('superdesk.config.providers.colabs.notify');
            if( !parseFloat(cnfNotif) )
            {
                localStorage.setItem('superdesk.config.providers.colabs.notify', 1);
                $(this).removeClass('badge-info').addClass('badge-warning');
            }
            else
            {
                localStorage.setItem('superdesk.config.providers.colabs.notify', 0);
                $(this).removeClass('badge-warning').addClass('badge-info');
            }
        }

    });

    var colabView = null;
    $.extend( providers.colabs, { init: function(blogUrl)
    {
        if( !colabView || (this.el.get(0) != colabView.el.get(0)) )
        {
            colabView = new ColabView({ el: this.el, blogUrl: blogUrl });
            return colabView.startAutoUpdate();
        }
        if( colabView ){  colabView.startAutoUpdate(); }
    }});

    return providers;
});
<|endoftext|>


<commit_before>/**
 * Responsive media query callbacks
 * @see https://developer.mozilla.org/en-US/docs/DOM/Using_media_queries_from_code
 */
define(['nbd/util/extend', 'nbd/trait/pubsub'], function(extend, pubsub) {
  'use strict';

  var queries = {},
  mqChange, mediaCheck,
  matchMedia = window.matchMedia || window.msMatchMedia;

  function bindMedia( breakpoint, query ) {
    var match = window.matchMedia( query );
    queries[breakpoint] = match;
    match.addListener( mqChange.bind(match, breakpoint) );
    if (match.matches) { mqChange.call(match, breakpoint); }
  }

  mediaCheck = function media( options, query ) {
    var breakpoint;

    // No matchMedia support
    if ( !matchMedia ) {
      throw new Error('Media queries not supported.');
    }

    // Has matchMedia support
    if ( typeof options === 'string' ) {
      bindMedia( options, query );
      return media;
    }

    if ( typeof options === 'object' ) {
      for (breakpoint in options) {
        if (options.hasOwnProperty(breakpoint)) {
          query = options[breakpoint];
          bindMedia( breakpoint, query );
        }
      }
    }
    return media;

  };

  extend(mediaCheck, pubsub);

  mqChange = function(breakpoint) {
    mediaCheck.trigger(breakpoint + (this.matches ? ':enter' : ':exit'));
    mediaCheck.trigger(breakpoint);
  };

  mediaCheck.getState = function(breakpoint) {
    return queries[breakpoint] && queries[breakpoint].matches;
  };

  return mediaCheck;

});
<commit_msg>media: the plain breakpoint event fires with state<commit_after>/**
 * Responsive media query callbacks
 * @see https://developer.mozilla.org/en-US/docs/DOM/Using_media_queries_from_code
 */
define(['nbd/util/extend', 'nbd/trait/pubsub'], function(extend, pubsub) {
  'use strict';

  var queries = {},
  mqChange, mediaCheck,
  matchMedia = window.matchMedia || window.msMatchMedia;

  function bindMedia( breakpoint, query ) {
    var match = window.matchMedia( query );
    queries[breakpoint] = match;
    match.addListener( mqChange.bind(match, breakpoint) );
    if (match.matches) { mqChange.call(match, breakpoint); }
  }

  mediaCheck = function media( options, query ) {
    var breakpoint;

    // No matchMedia support
    if ( !matchMedia ) {
      throw new Error('Media queries not supported.');
    }

    // Has matchMedia support
    if ( typeof options === 'string' ) {
      bindMedia( options, query );
      return media;
    }

    if ( typeof options === 'object' ) {
      for (breakpoint in options) {
        if (options.hasOwnProperty(breakpoint)) {
          query = options[breakpoint];
          bindMedia( breakpoint, query );
        }
      }
    }
    return media;

  };

  extend(mediaCheck, pubsub);

  mqChange = function(breakpoint) {
    mediaCheck.trigger(breakpoint + (this.matches ? ':enter' : ':exit'));
    mediaCheck.trigger(breakpoint, this.matches);
  };

  mediaCheck.getState = function(breakpoint) {
    return queries[breakpoint] && queries[breakpoint].matches;
  };

  return mediaCheck;

});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import './App.css';

import Vms from './vms'
import Header from './header'
import AuditLog from './auditlog'
import VmDetail from './VmDetail'

import { takeEvery, takeLatest } from 'redux-saga'
import {fetchAllVms, getConsoleVm, restartVm, shutdownVm, startVm, fetchVmIcons, login} from './sagas'

// import {logDebug} from './helpers'
// import Playground from './playground'

export function *rootSaga () {
    yield [
        takeEvery("LOGIN", login),
        takeLatest("GET_ALL_VMS", fetchAllVms),
        takeEvery("GET_VM_ICONS", fetchVmIcons),
        takeEvery("SHUTDOWN_VM", shutdownVm),
        takeEvery("RESTART_VM", restartVm),
        takeEvery("START_VM", startVm),
        takeEvery("GET_CONSOLE_VM", getConsoleVm)
    ]
}

class App extends Component {
  render () {
    const store = this.props.store

    const {vms, config, auditLog} = store.getState()
    const dispatch = store.dispatch

    const selectedVmId = vms.get('selected')
    const selectedVm = selectedVmId ? vms.get('vms').find( vm => vm.get('id') === selectedVmId) : undefined

    return (

            <AuditLog auditLog={auditLog} config={config} dispatch={dispatch}/>

                <Vms vms={vms} config={config} dispatch={dispatch}/>
                <VmDetail vm={selectedVm} dispatch={dispatch}/>

)

    // return (
 <Playground />
)
  }
}

App.propTypes = {
  store: React.PropTypes.object.isRequired
}

export default App<commit_msg>Remove unused <commit_after>import React, { Component } from 'react';
import './App.css';

import Vms from './vms'
import Header from './header'
import AuditLog from './auditlog'
import VmDetail from './VmDetail'

import { takeEvery, takeLatest } from 'redux-saga'
import {fetchAllVms, getConsoleVm, restartVm, shutdownVm, startVm, fetchVmIcons, login} from './sagas'

// import {logDebug} from './helpers'
// import Playground from './playground'

export function *rootSaga () {
    yield [
        takeEvery("LOGIN", login),
        takeLatest("GET_ALL_VMS", fetchAllVms),
        takeEvery("GET_VM_ICONS", fetchVmIcons),
        takeEvery("SHUTDOWN_VM", shutdownVm),
        takeEvery("RESTART_VM", restartVm),
        takeEvery("START_VM", startVm),
        takeEvery("GET_CONSOLE_VM", getConsoleVm)
    ]
}

class App extends Component {
  render () {
    const store = this.props.store

    const {vms, config, auditLog} = store.getState()
    const dispatch = store.dispatch

    const selectedVmId = vms.get('selected')
    const selectedVm = selectedVmId ? vms.get('vms').find( vm => vm.get('id') === selectedVmId) : undefined

    return (

            <AuditLog auditLog={auditLog} config={config} dispatch={dispatch}/>
                <Vms vms={vms} config={config} dispatch={dispatch}/>
                <VmDetail vm={selectedVm} dispatch={dispatch}/>

)

    // return (
 <Playground />
)
  }
}

App.propTypes = {
  store: React.PropTypes.object.isRequired
}

export default App<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  VictoryPie, VictoryLabel, VictoryChart, VictoryGroup,
  VictoryStack, VictoryBar, VictoryTooltip
} from 'victory';
import './App.css';

function ProfileCard(props) {
  return (

{props.playerName}

{props.team}

{props.position}

  );
}

class StatCard extends React.Component {
  constructor() {
    super();
    this.state = {
      value: 0,
      leagueLeaderValue: 1
    };
  }

  componentDidMount() {
    let value = this.props.value;
    let leagueLeaderValue = this.props.leagueLeaderValue;
    this.setState({value, leagueLeaderValue});
  }

  render() {
    return (
      <svg viewBox="0 0 400 400">

        <VictoryPie
          animate={{duration: 1000}}
          width={400} height={400}
          data={[
            {idx: 0, statValue: this.state.value},
            {
              idx: 1,
              statValue: this.state.leagueLeaderValue - this.state.value
            },
          ]}
          x="idx" y="statValue"
          innerRadius={120}
          labelRadius={150}
          labels={() => null}
        />

        <VictoryLabel
          textAnchor="middle"
          x={200} y={200}
          text={this.props.statName}
        />

      </svg>
    );
  }
}

function PlayerAvatar(props) {
  return (

{props.playerName}

{props.ppg}

PPG

{props.apg}

APG

{props.rpg}

BPG

  );
}

function SimilarPlayersCard(props) {
  return (

Similar Players

      <PlayerAvatar
        playerName='Stephen Curry' ppg='22.3' apg='6.6' rpg='2.1'
      />
      <PlayerAvatar
        playerName='John Wall' ppg='22.3' apg='6.6' rpg='2.1'
      />
      <PlayerAvatar
        playerName='Russell Westbrook' ppg='22.3' apg='6.6' rpg='2.1'
      />
      <PlayerAvatar
        playerName='Isaiah Thomas' ppg='22.3' apg='6.6' rpg='2.1'
      />

  );
}

function LeagueComparisonCard(props) {
  const statList = [
    {
      'statType': 'ppg',
      'leagueLeaderName': props.ppgLeaderName,
      'leagueLeaderValue': props.leaderPpg,
      'leagueAverageValue': props.averagePpg,
      'playerValue': props.playerPpg
    },
    {
      'statType': 'apg',
      'leagueLeaderName': props.apgLeaderName,
      'leagueLeaderValue': props.leaderApg,
      'leagueAverageValue': props.averageApg,
      'playerValue': props.playerApg
    },
    {
      'statType': 'rpg',
      'leagueLeaderName': props.rpgLeaderName,
      'leagueLeaderValue': props.leaderRpg,
      'leagueAverageValue': props.averageRpg,
      'playerValue': props.playerRpg
    },
  ]

  const groupOfBarsList = statList.map((stat, idx) =>
    <VictoryGroup
      key={stat.statType} offset={20} style={{ data: {width: 15}}}
      labelComponent={<VictoryTooltip/>}
    >

      <VictoryBar data={[
        {
          x: idx + 1, y: stat.playerValue,
          label: props.playerName + ' - ' + stat.playerValue + stat.statType
        }
      ]} />

      <VictoryStack>
        <VictoryBar
          data={[
            {
              x: idx + 1, y: stat.leagueAverageValue,
              label: 'League Average - ' + stat.leagueAverageValue
                      + stat.statType
            }
          ]}
        />
        <VictoryBar
          data={[
            {
              x: idx + 1,
              y: stat.leagueLeaderValue - stat.leagueAverageValue,
              label: stat.leagueLeaderName + ' - ' +
                      stat.leagueLeaderValue + stat.statType
            }
          ]}
        />
      </VictoryStack>

    </VictoryGroup>
  );

  return (

Vs. League

      <VictoryChart domain={{x: [0, 4], y: [0, 35]}}>
        {groupOfBarsList}
      </VictoryChart>

  );
}

class App extends Component {
  render() {
    return (

NBA Player Dashboard

        <ProfileCard
          playerName='Kyrie Irving'
          team='Cleveland Cavaliers'
          position='point guard'
        />

          <StatCard statName='ppg' value={21.4} leagueLeaderValue={30} />
          <StatCard statName='apg' value={8.4} leagueLeaderValue={12} />
          <StatCard statName='rpg' value={2.1} leagueLeaderValue={15} />

        <SimilarPlayersCard playerName='Kyrie Irving'/>

        <LeagueComparisonCard
          playerName='Kyrie Irving'

          ppgLeaderName='Russell Westbrook'
          leaderPpg={30} playerPpg={21.4} averagePpg={5.4}

          apgLeaderName='James Harden'
          leaderApg={11} playerApg={8.4} averageApg={2.4}

          rpgLeaderName='Hassan Whiteside'
          leaderRpg={15} playerRpg={2.1} averageRpg={5.4}
        />

    );
  }
}

export default App;
<commit_msg>Use the stat type as the x value on league comparison barchart<commit_after>import React, { Component } from 'react';
import {
  VictoryPie, VictoryLabel, VictoryChart, VictoryGroup,
  VictoryStack, VictoryBar, VictoryTooltip, VictoryAxis
} from 'victory';
import './App.css';

function ProfileCard(props) {
  return (

{props.playerName}

{props.team}

{props.position}

  );
}

class StatCard extends React.Component {
  constructor() {
    super();
    this.state = {
      value: 0,
      leagueLeaderValue: 1
    };
  }

  componentDidMount() {
    let value = this.props.value;
    let leagueLeaderValue = this.props.leagueLeaderValue;
    this.setState({value, leagueLeaderValue});
  }

  render() {
    return (
      <svg viewBox="0 0 400 400">

        <VictoryPie
          animate={{duration: 1000}}
          width={400} height={400}
          data={[
            {idx: 0, statValue: this.state.value},
            {
              idx: 1,
              statValue: this.state.leagueLeaderValue - this.state.value
            },
          ]}
          x="idx" y="statValue"
          innerRadius={120}
          labelRadius={150}
          labels={() => null}
        />

        <VictoryLabel
          textAnchor="middle"
          x={200} y={200}
          text={this.props.statName}
        />

      </svg>
    );
  }
}

function PlayerAvatar(props) {
  return (

{props.playerName}

{props.ppg}

PPG

{props.apg}

APG

{props.rpg}

BPG

  );
}

function SimilarPlayersCard(props) {
  return (

Similar Players

      <PlayerAvatar
        playerName='Stephen Curry' ppg='22.3' apg='6.6' rpg='2.1'
      />
      <PlayerAvatar
        playerName='John Wall' ppg='22.3' apg='6.6' rpg='2.1'
      />
      <PlayerAvatar
        playerName='Russell Westbrook' ppg='22.3' apg='6.6' rpg='2.1'
      />
      <PlayerAvatar
        playerName='Isaiah Thomas' ppg='22.3' apg='6.6' rpg='2.1'
      />

  );
}

function LeagueComparisonCard(props) {
  const statList = [
    {
      'statType': 'ppg',
      'leagueLeaderName': props.ppgLeaderName,
      'leagueLeaderValue': props.leaderPpg,
      'leagueAverageValue': props.averagePpg,
      'playerValue': props.playerPpg
    },
    {
      'statType': 'apg',
      'leagueLeaderName': props.apgLeaderName,
      'leagueLeaderValue': props.leaderApg,
      'leagueAverageValue': props.averageApg,
      'playerValue': props.playerApg
    },
    {
      'statType': 'rpg',
      'leagueLeaderName': props.rpgLeaderName,
      'leagueLeaderValue': props.leaderRpg,
      'leagueAverageValue': props.averageRpg,
      'playerValue': props.playerRpg
    },
  ]

  const groupOfBarsList = statList.map((stat, idx) =>
    <VictoryGroup
      key={stat.statType} offset={20} style={{ data: {width: 15}}}
      labelComponent={<VictoryTooltip/>}
    >

      <VictoryBar data={[
        {
          x: idx + 1, y: stat.playerValue,
          label: props.playerName + ' - ' + stat.playerValue + stat.statType
        }
      ]} />

      <VictoryStack>
        <VictoryBar
          data={[
            {
              x: idx + 1, y: stat.leagueAverageValue,
              label: 'League Average - ' + stat.leagueAverageValue
                      + stat.statType
            }
          ]}
        />
        <VictoryBar
          data={[
            {
              x: idx + 1,
              y: stat.leagueLeaderValue - stat.leagueAverageValue,
              label: stat.leagueLeaderName + ' - ' +
                      stat.leagueLeaderValue + stat.statType
            }
          ]}
        />
      </VictoryStack>

    </VictoryGroup>
  );

  return (

Vs. League

      <VictoryChart domain={{x: [0, 4], y: [0, 35]}}>
        {groupOfBarsList}
        <VictoryAxis tickValues={statList.map((stat) => stat['statType'])} />
      </VictoryChart>

  );
}

class App extends Component {
  render() {
    return (

NBA Player Dashboard

        <ProfileCard
          playerName='Kyrie Irving'
          team='Cleveland Cavaliers'
          position='point guard'
        />

          <StatCard statName='ppg' value={21.4} leagueLeaderValue={30} />
          <StatCard statName='apg' value={8.4} leagueLeaderValue={12} />
          <StatCard statName='rpg' value={2.1} leagueLeaderValue={15} />

        <SimilarPlayersCard playerName='Kyrie Irving'/>

        <LeagueComparisonCard
          playerName='Kyrie Irving'

          ppgLeaderName='Russell Westbrook'
          leaderPpg={30} playerPpg={21.4} averagePpg={5.4}

          apgLeaderName='James Harden'
          leaderApg={11} playerApg={8.4} averageApg={2.4}

          rpgLeaderName='Hassan Whiteside'
          leaderRpg={15} playerRpg={2.1} averageRpg={5.4}
        />

    );
  }
}

export default App;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {extendObservable, action, autorun, toJS, transaction} from 'mobx';
import {observer} from 'mobx-react';

var colors = ['#8dd3c7','#ffffb3','#bebada','#fb8072','#80b1d3','#fdb462','#b3de69','#fccde5','#d9d9d9','#bc80bd']; // colorbrewer set3

class Topic {
  constructor(name, color, ranges) {
    extendObservable(this, {
      name: name,
      color: color,
      ranges: ranges || []
    });
  }
}

function makeEmptyRanges(n) {
  let ranges = [];
  for (let i=0; i<n; i++) ranges.push([]);
  return ranges;
}

class Question {
  constructor(id, text) {
    this.id = id;
    this.text = text;
    extendObservable(this, {
      responses: []
    });
  }
}

class AnnotationStore {
  constructor() {
    extendObservable(this, {
      texts: [],
      topics: [],
      questions: [],
      lastColorIdx: 0,
    });
  };

  fromJson(json) {
    transaction(() => {
      this.texts = json.texts;
      this.topics = json.topics || [];
      this.questions = json.questions;
      this.lastColorIdx = json.lastColorIdx || 0;
      this.questions.forEach(question => {
        question.responses = question.responses || Array(this.texts.length);
      });
    });
  };

  toJson() {
    return toJS(this);
  };

  nextColor() {
    var idx = this.lastColorIdx;
    this.lastColorIdx = idx + 1;
    return colors[idx % colors.length];
  };
}

var annotationsStore = new AnnotationStore();
window.annotationsStore = annotationsStore;
if (window.localStorage.annotations){
  annotationsStore.fromJson(JSON.parse(window.localStorage.annotations));
}

class UiState {
  constructor(annotationsStore) {
    this.annotationsStore = annotationsStore;
    extendObservable(this, {
      curTextIdx: 0,
      get curText() {return this.annotationsStore.texts[this.curTextIdx];},
      activeTopic: 0,
      setActiveTopic: action(function(i) {
        this.activeTopic = i;
      })
    });
  }
}

var uistate = new UiState(annotationsStore);
window.uistate = uistate;

autorun(function() {
  var json = JSON.stringify(annotationsStore.toJson());
  window.localStorage.annotations = json;
});

function formattedRanges(ranges) {
  var offset = 0;
  return ranges.map(({text, style}, i) => {text});
}

function joinStyle(a, b) { return {...a, ...b};}

function addFormatting(existingRanges, start, end, fmt) {
  let res = [];
  for (let existingRangeIdx = 0; existingRangeIdx < existingRanges.length; existingRangeIdx++) {
    let range = existingRanges[existingRangeIdx];
    let textLen = range.text.length;
    if (start > 0) {
      // before start.
      if (textLen <= start) {
        // Pass through unchanged text.
        res.push(range);
      } else {
        // Break apart this range.
        res.push({text: range.text.slice(0, start), style: range.style});
        if (end < textLen) {
          // Range also ends within this block.
          res.push({text: range.text.slice(start, end), style: joinStyle(range.style, fmt)});
          res.push({text: range.text.slice(end), style: range.style});
        } else {
          res.push({text: range.text.slice(start), style: joinStyle(range.style, fmt)});
        }
      }
    } else if (end > 0) {
      // within range.
      if (textLen <= end) {
        res.push({text: range.text, style: joinStyle(range.style, fmt)});
      } else {
        // Break apart.
        if (end > 0) {
          res.push({text: range.text.slice(0, end), style: joinStyle(range.style, fmt)});
        }
        res.push({text: range.text.slice(end), style: range.style});
      }
    } else {
      // Pass through remaining text.
      res.push(range);
    }
    start -= textLen;
    end -= textLen;
  }
  return res;
}

const TopicInstance = observer(class TopicInstance extends Component {
  render() {
    return
<button onClick={this.props.onRemove}>x</button> {this.props.text}
;
  }
});

const SidebarTopic = observer(class SidebarTopic extends Component {
  handleClick = () => {
    uistate.setActiveTopic(this.props.idx);
  };

  handleEditTitle = () => {
    let newName = prompt('New name for this topic', this.props.topic.name);
    if (newName.length)
      this.props.topic.name = newName;
  };

  handleRemove = (evt) => {
    if (uistate.activeTopic >= this.props.idx) {
      uistate.setActiveTopic(uistate.activeTopic - 1);
    }
    annotationsStore.topics.splice(this.props.idx, 1);
    evt.stopPropagation();
  };

  render() {
    let {isActive, topic, curTextIdx} = this.props;
    return (

          {topic.name}
          <button onClick={this.handleEditTitle}>{FA('edit')}</button>
          <button onClick={this.handleRemove}>{FA('remove')}</button>

        {topic.ranges[curTextIdx].map(([start, end], i) => <TopicInstance
          key={i}
          onRemove={() => topic.ranges[curTextIdx].splice(i, 1)}
          text={uistate.curText.slice(start, end)} />)}

);
  }
});

const Sidebar = observer(class Sidebar extends Component {
  handleAddTopic = () => {
    this.props.topics.push(new Topic(prompt("Name for this topic?"), annotationsStore.nextColor(), makeEmptyRanges(annotationsStore.texts.length)));
    uistate.setActiveTopic(this.props.topics.length - 1);
  };

  render() {
    let {activeTopic, topics, curTextIdx} = this.props;
    return

Topics:

      {topics.map((topic, i) => <SidebarTopic
      key={i}
      idx={i} isActive={i === activeTopic}
      topic={topic} curTextIdx={curTextIdx} />)}
      <button onClick={this.handleAddTopic}>{FA('plus')} Add Topic</button>

;
  }
});

function FA(name) {
  return ;
}

const MainText = observer(class MainText extends Component {
  render() {
    var annotated = [{text: uistate.curText, style: {}}];
    annotationsStore.topics.forEach(function({name, color, ranges}) {
        ranges[uistate.curTextIdx].forEach(function([start, end]) {
          annotated = addFormatting(annotated, start, end, {background: color});
        });
      });
    return
{formattedRanges(annotated)}
;
  }
});

function handleFiles(files) {
  var file = files[0];
  var reader = new FileReader();
  reader.onload = evt => {
    console.log("got data");
    var data = JSON.parse(reader.result);
    annotationsStore.fromJson(data);
  };
  reader.readAsText(file);
}

const RequestDatafile = observer(class RequestDatafile extends Component {
  render() {
    return
Select the data file: <input type="file" onChange={evt => handleFiles(evt.target.files)} />

  }
})

function simplifyRanges(text, ranges) {
  var annotated = [{text: uistate.curText, style: {}}];
  ranges.forEach(function([start, end]) {
    annotated = addFormatting(annotated, start, end, {marked: true});
  });
  var newRanges = [], offset = 0;
  annotated.forEach(({text, style}) => {
    if (style.marked) {
      if (newRanges.length && newRanges[newRanges.length - 1][1] == offset) {
        // extend the existing range
        newRanges[newRanges.length - 1][1] = offset + text.length;
      } else {
        newRanges.push([offset, offset + text.length]);
      }
    }
    offset += text.length;
  });
  return newRanges;
}

const App = observer(class App extends Component {
  onMouseUp(evt) {
    var range = window.getSelection().getRangeAt(0);
    var startTextOffset = +range.startContainer.parentNode.getAttribute('data-offset') + range.startOffset;
    var endTextOffset = +range.endContainer.parentNode.getAttribute('data-offset') + range.endOffset;
    if (startTextOffset === range.endOffset) return;
    if (uistate.activeTopic >= annotationsStore.topics.length) {
      alert("Create a topic first, then select some text.")
      return;
    }
    var ranges = annotationsStore.topics[uistate.activeTopic].ranges[uistate.curTextIdx];
    ranges.push([startTextOffset, endTextOffset]);
    annotationsStore.topics[uistate.activeTopic].ranges[uistate.curTextIdx] = simplifyRanges(uistate.curText, ranges);
    window.getSelection().removeAllRanges();
  }

  render() {
    let {curTextIdx} = uistate;
    if (annotationsStore.texts.length === 0) {
      return <RequestDatafile />;
    }
    return (

          <button onClick={() => {uistate.curTextIdx = uistate.curTextIdx - 1}} disabled={uistate.curTextIdx === 0}><</button>
          Text {uistate.curTextIdx + 1} of {annotationsStore.texts.length}
          <button onClick={() => {uistate.curTextIdx = uistate.curTextIdx + 1}} disabled={uistate.curTextIdx === annotationsStore.texts.length - 1}>></button>

<MainText />

            <Sidebar topics={annotationsStore.topics} activeTopic={uistate.activeTopic} curTextIdx={uistate.curTextIdx} />

Overall questions:

            {annotationsStore.questions.map((question, i) =>

              {question.text + " "}

                <input onChange={evt => {question.responses[curTextIdx] = +evt.target.value}} type="number" min={question.min} max={question.max} value={question.responses[curTextIdx] || ""} />

)}

        <textarea id="results" readOnly="readOnly" value={JSON.stringify(annotationsStore.toJson())} />
        <button style={{position: 'fixed', right: 0, bottom: 0}} onClick={evt => {if (prompt("Type RESET to reset") === "RESET") {
          window.localStorage.clear(); window.location.reload();
        }}}>Reset</button>

    );
  }
});

export default App;
<commit_msg>Fix bug of the ratings not getting observed.<commit_after>import React, { Component } from 'react';
import {extendObservable, observable, action, autorun, toJS, transaction} from 'mobx';
import {observer} from 'mobx-react';

var colors = ['#8dd3c7','#ffffb3','#bebada','#fb8072','#80b1d3','#fdb462','#b3de69','#fccde5','#d9d9d9','#bc80bd']; // colorbrewer set3

class Topic {
  constructor(name, color, ranges) {
    extendObservable(this, {
      name: name,
      color: color,
      ranges: ranges || []
    });
  }
}

function makeEmptyRanges(n) {
  let ranges = [];
  for (let i=0; i<n; i++) ranges.push([]);
  return ranges;
}

class Question {
  constructor(id, text) {
    this.id = id;
    this.text = text;
    extendObservable(this, {
      responses: []
    });
  }
}

class AnnotationStore {
  constructor() {
    extendObservable(this, {
      texts: [],
      topics: [],
      questions: [],
      lastColorIdx: 0,
    });
  };

  fromJson(json) {
    transaction(() => {
      this.texts = json.texts;
      this.topics = json.topics || [];
      this.questions = json.questions;
      this.lastColorIdx = json.lastColorIdx || 0;
      this.questions.forEach(question => {
        question.responses = question.responses || observable(Array(this.texts.length));
      });
    });
  };

  toJson() {
    return toJS(this);
  };

  nextColor() {
    var idx = this.lastColorIdx;
    this.lastColorIdx = idx + 1;
    return colors[idx % colors.length];
  };
}

var annotationsStore = new AnnotationStore();
window.annotationsStore = annotationsStore;
if (window.localStorage.annotations){
  annotationsStore.fromJson(JSON.parse(window.localStorage.annotations));
}

class UiState {
  constructor(annotationsStore) {
    this.annotationsStore = annotationsStore;
    extendObservable(this, {
      curTextIdx: 0,
      get curText() {return this.annotationsStore.texts[this.curTextIdx];},
      activeTopic: 0,
      setActiveTopic: action(function(i) {
        this.activeTopic = i;
      })
    });
  }
}

var uistate = new UiState(annotationsStore);
window.uistate = uistate;

autorun(function() {
  var json = JSON.stringify(annotationsStore.toJson());
  window.localStorage.annotations = json;
});

function formattedRanges(ranges) {
  var offset = 0;
  return ranges.map(({text, style}, i) => {text});
}

function joinStyle(a, b) { return {...a, ...b};}

function addFormatting(existingRanges, start, end, fmt) {
  let res = [];
  for (let existingRangeIdx = 0; existingRangeIdx < existingRanges.length; existingRangeIdx++) {
    let range = existingRanges[existingRangeIdx];
    let textLen = range.text.length;
    if (start > 0) {
      // before start.
      if (textLen <= start) {
        // Pass through unchanged text.
        res.push(range);
      } else {
        // Break apart this range.
        res.push({text: range.text.slice(0, start), style: range.style});
        if (end < textLen) {
          // Range also ends within this block.
          res.push({text: range.text.slice(start, end), style: joinStyle(range.style, fmt)});
          res.push({text: range.text.slice(end), style: range.style});
        } else {
          res.push({text: range.text.slice(start), style: joinStyle(range.style, fmt)});
        }
      }
    } else if (end > 0) {
      // within range.
      if (textLen <= end) {
        res.push({text: range.text, style: joinStyle(range.style, fmt)});
      } else {
        // Break apart.
        if (end > 0) {
          res.push({text: range.text.slice(0, end), style: joinStyle(range.style, fmt)});
        }
        res.push({text: range.text.slice(end), style: range.style});
      }
    } else {
      // Pass through remaining text.
      res.push(range);
    }
    start -= textLen;
    end -= textLen;
  }
  return res;
}

const TopicInstance = observer(class TopicInstance extends Component {
  render() {
    return
<button onClick={this.props.onRemove}>x</button> {this.props.text}
;
  }
});

const SidebarTopic = observer(class SidebarTopic extends Component {
  handleClick = () => {
    uistate.setActiveTopic(this.props.idx);
  };

  handleEditTitle = () => {
    let newName = prompt('New name for this topic', this.props.topic.name);
    if (newName.length)
      this.props.topic.name = newName;
  };

  handleRemove = (evt) => {
    if (uistate.activeTopic >= this.props.idx) {
      uistate.setActiveTopic(uistate.activeTopic - 1);
    }
    annotationsStore.topics.splice(this.props.idx, 1);
    evt.stopPropagation();
  };

  render() {
    let {isActive, topic, curTextIdx} = this.props;
    return (

          {topic.name}
          <button onClick={this.handleEditTitle}>{FA('edit')}</button>
          <button onClick={this.handleRemove}>{FA('remove')}</button>

        {topic.ranges[curTextIdx].map(([start, end], i) => <TopicInstance
          key={i}
          onRemove={() => topic.ranges[curTextIdx].splice(i, 1)}
          text={uistate.curText.slice(start, end)} />)}

);
  }
});

const Sidebar = observer(class Sidebar extends Component {
  handleAddTopic = () => {
    this.props.topics.push(new Topic(prompt("Name for this topic?"), annotationsStore.nextColor(), makeEmptyRanges(annotationsStore.texts.length)));
    uistate.setActiveTopic(this.props.topics.length - 1);
  };

  render() {
    let {activeTopic, topics, curTextIdx} = this.props;
    return

Topics:

      {topics.map((topic, i) => <SidebarTopic
      key={i}
      idx={i} isActive={i === activeTopic}
      topic={topic} curTextIdx={curTextIdx} />)}
      <button onClick={this.handleAddTopic}>{FA('plus')} Add Topic</button>

;
  }
});

function FA(name) {
  return ;
}

const MainText = observer(class MainText extends Component {
  render() {
    var annotated = [{text: uistate.curText, style: {}}];
    annotationsStore.topics.forEach(function({name, color, ranges}) {
        ranges[uistate.curTextIdx].forEach(function([start, end]) {
          annotated = addFormatting(annotated, start, end, {background: color});
        });
      });
    return
{formattedRanges(annotated)}
;
  }
});

function handleFiles(files) {
  var file = files[0];
  var reader = new FileReader();
  reader.onload = evt => {
    console.log("got data");
    var data = JSON.parse(reader.result);
    annotationsStore.fromJson(data);
  };
  reader.readAsText(file);
}

const RequestDatafile = observer(class RequestDatafile extends Component {
  render() {
    return
Select the data file: <input type="file" onChange={evt => handleFiles(evt.target.files)} />

  }
})

function simplifyRanges(text, ranges) {
  var annotated = [{text: uistate.curText, style: {}}];
  ranges.forEach(function([start, end]) {
    annotated = addFormatting(annotated, start, end, {marked: true});
  });
  var newRanges = [], offset = 0;
  annotated.forEach(({text, style}) => {
    if (style.marked) {
      if (newRanges.length && newRanges[newRanges.length - 1][1] == offset) {
        // extend the existing range
        newRanges[newRanges.length - 1][1] = offset + text.length;
      } else {
        newRanges.push([offset, offset + text.length]);
      }
    }
    offset += text.length;
  });
  return newRanges;
}

const App = observer(class App extends Component {
  onMouseUp(evt) {
    var range = window.getSelection().getRangeAt(0);
    var startTextOffset = +range.startContainer.parentNode.getAttribute('data-offset') + range.startOffset;
    var endTextOffset = +range.endContainer.parentNode.getAttribute('data-offset') + range.endOffset;
    if (startTextOffset === range.endOffset) return;
    if (uistate.activeTopic >= annotationsStore.topics.length) {
      alert("Create a topic first, then select some text.")
      return;
    }
    var ranges = annotationsStore.topics[uistate.activeTopic].ranges[uistate.curTextIdx];
    ranges.push([startTextOffset, endTextOffset]);
    annotationsStore.topics[uistate.activeTopic].ranges[uistate.curTextIdx] = simplifyRanges(uistate.curText, ranges);
    window.getSelection().removeAllRanges();
  }

  render() {
    let {curTextIdx} = uistate;
    if (annotationsStore.texts.length === 0) {
      return <RequestDatafile />;
    }
    return (

          <button onClick={() => {uistate.curTextIdx = uistate.curTextIdx - 1}} disabled={uistate.curTextIdx === 0}><</button>
          Text {uistate.curTextIdx + 1} of {annotationsStore.texts.length}
          <button onClick={() => {uistate.curTextIdx = uistate.curTextIdx + 1}} disabled={uistate.curTextIdx === annotationsStore.texts.length - 1}>></button>

<MainText />

            <Sidebar topics={annotationsStore.topics} activeTopic={uistate.activeTopic} curTextIdx={uistate.curTextIdx} />

Overall questions:

            {annotationsStore.questions.map((question, i) =>

              {question.text + " "}

                <input onChange={evt => {question.responses[curTextIdx] = +evt.target.value}} type="number" min={question.min} max={question.max} value={question.responses[curTextIdx] || ""} />

)}

        <textarea id="results" readOnly="readOnly" value={JSON.stringify(annotationsStore.toJson())} />
        <button style={{position: 'fixed', right: 0, bottom: 0}} onClick={evt => {if (prompt("Type RESET to reset") === "RESET") {
          window.localStorage.clear(); window.location.reload();
        }}}>Reset</button>

    );
  }
});

export default App;
<|endoftext|>


<commit_before>var landingPagesApp = angular.module('landingPagesApp',['angular-parallax','thumbnailModule','mediaPlayer','popupSupport','htmlGenerator','sticky','headerModule', 'djds4rce.angular-socialshare']);

landingPagesApp.config(resourceUrlWhiteList);
landingPagesApp.factory('contentService', ['$http', contentService]);

landingPagesApp.run(function($FB){
  $FB.init('714039208665351');
});

landingPagesApp.config(function($locationProvider){
    $locationProvider.html5Mode(true).hashPrefix('!');
});

landingPagesApp.directive('bindDynamicHtml', ['$compile', bindDynamicHtml]);<commit_msg>Removing the code specific for social media functionality on main langing page. <Jaideep><commit_after>var landingPagesApp = angular.module('landingPagesApp',['angular-parallax','thumbnailModule','mediaPlayer','popupSupport','htmlGenerator','sticky','headerModule', 'djds4rce.angular-socialshare']);

landingPagesApp.config(resourceUrlWhiteList);
landingPagesApp.factory('contentService', ['$http', contentService]);

landingPagesApp.run(function($FB){
  $FB.init('714039208665351');
});

landingPagesApp.directive('bindDynamicHtml', ['$compile', bindDynamicHtml]);<|endoftext|>


<commit_before>'use strict';

angular.module('ui.dashboard', ['ui.bootstrap', 'ui.sortable']);

angular.module('ui.dashboard')
  .directive('dashboard', ['WidgetModel', 'WidgetDefCollection', '$modal', 'DashboardState', function (WidgetModel, WidgetDefCollection, $modal, DashboardState) {
    return {
      restrict: 'A',
      templateUrl: 'template/dashboard.html',
      scope: true,
      controller: function ($scope) {
        $scope.sortableOptions = {
          stop: function () {
            //TODO store active widgets in local storage on add/remove/reorder
            $scope.dashboardState.save($scope.widgets);
          },
          handle: '.widget-header'
        };
      },
      link: function (scope, element, attrs) {
        scope.options = scope.$eval(attrs.dashboard);
        scope.defaultWidgets = scope.options.defaultWidgets; // save widgets for reset
        //scope.widgetDefs = scope.options.widgetDefinitions;
        scope.widgetDefs = new WidgetDefCollection(scope.options.widgetDefinitions);

        var count = 1;
        var dashboardState = scope.dashboardState = new DashboardState(
          !!scope.options.useLocalStorage,
          scope.defaultWidgets
        );

        scope.addWidget = function (widgetDef) {
          var wDef = scope.widgetDefs.getByName(widgetDef.name);
          if (!wDef) {
            throw 'Widget ' + widgetDef.name + ' is not found.';
          }

          var title;
          if (widgetDef.title) {
            title = widgetDef.title;
          } else if (wDef.title) {
            title = wDef.title;
          } else {
            title = 'Widget ' + count++;
          }

          var w = angular.copy(wDef);
          angular.extend(w, widgetDef); //TODO deep extend

          var widget = new WidgetModel(w, {
            title: title
          });

          scope.widgets.push(widget);
          scope.saveDashboard();
        };

        scope.removeWidget = function (widget) {
          scope.widgets.splice(_.indexOf(scope.widgets, widget), 1);
          scope.saveDashboard();
        };

        scope.openWidgetDialog = function (widget) {
          var options = widget.editModalOptions;

          // use default options when none are supplied by widget
          if (!options) {
            options = {
              templateUrl: 'template/widget-template.html',
              resolve: {
                widget: function () {
                  return widget;
                },
                optionsTemplateUrl: function () {
                  return scope.options.optionsTemplateUrl;
                }
              },
              controller: 'WidgetDialogCtrl'
            };
          }
          var modalInstance = $modal.open(options);

          // Set resolve and reject callbacks for the result promise
          modalInstance.result.then(
            function (result) {
              console.log('widget dialog closed');
              console.log('result: ', result);
              widget.title = result.title;
            },
            function (reason) {
              console.log('widget dialog dismissed: ', reason);

            }
          );

        };

        scope.clear = function () {
          scope.widgets = [];
        };

        scope.addWidgetInternal = function (event, widgetDef) {
          event.preventDefault();
          scope.addWidget(widgetDef);
        };

        scope.saveDashboard = function () {
          dashboardState.save(scope.widgets);
        };

        scope.loadWidgets = function (widgets) {
          scope.defaultWidgets = widgets; // save widgets for reset
          scope.clear();
          _.each(widgets, function (widgetDef) {
            scope.addWidget(widgetDef);
          });
        };

        scope.resetWidgetsToDefault = function () {
          scope.loadWidgets(scope.defaultWidgets);
        };

        // Set default widgets array
        var savedWidgets = dashboardState.load();

        if (savedWidgets) {
          scope.widgets = savedWidgets;
        } else if (scope.defaultWidgets) {
          scope.resetWidgetsToDefault();
        }

        // allow adding widgets externally
        scope.options.addWidget = scope.addWidget;
        scope.options.loadWidgets = scope.loadWidgets;

        // save state
        scope.$on('widgetChanged', function (event) {
          event.stopPropagation();
          scope.saveDashboard();
        });
      }
    };
  }]);<commit_msg>Added some comments to dashboard.js<commit_after>'use strict';

angular.module('ui.dashboard', ['ui.bootstrap', 'ui.sortable']);

angular.module('ui.dashboard')
  .directive('dashboard', ['WidgetModel', 'WidgetDefCollection', '$modal', 'DashboardState', function (WidgetModel, WidgetDefCollection, $modal, DashboardState) {
    return {
      restrict: 'A',
      templateUrl: 'template/dashboard.html',
      scope: true,
      controller: function ($scope) {
        $scope.sortableOptions = {
          stop: function () {
            //TODO store active widgets in local storage on add/remove/reorder
            $scope.dashboardState.save($scope.widgets);
          },
          handle: '.widget-header'
        };
      },
      link: function (scope, element, attrs) {
        // Extract options the dashboard="" attribute
        scope.options = scope.$eval(attrs.dashboard);

        // Save default widget config for reset
        scope.defaultWidgets = scope.options.defaultWidgets;

        //scope.widgetDefs = scope.options.widgetDefinitions;
        scope.widgetDefs = new WidgetDefCollection(scope.options.widgetDefinitions);
        var count = 1;

        // Instantiate new instance of dashboard state
        var dashboardState = scope.dashboardState = new DashboardState(
          !!scope.options.useLocalStorage,
          scope.defaultWidgets
        );

        /**
         * Instantiates a new widget on the dashboard
         * @param {Object} widgetDef The definition object of the widget
         */
        scope.addWidget = function (widgetDef) {
          var wDef = scope.widgetDefs.getByName(widgetDef.name);
          if (!wDef) {
            throw 'Widget ' + widgetDef.name + ' is not found.';
          }

          var title;
          if (widgetDef.title) {
            title = widgetDef.title;
          } else if (wDef.title) {
            title = wDef.title;
          } else {
            title = 'Widget ' + count++;
          }

          var w = angular.copy(wDef);
          angular.extend(w, widgetDef); //TODO deep extend

          var widget = new WidgetModel(w, {
            title: title
          });

          scope.widgets.push(widget);
          scope.saveDashboard();
        };

        /**
         * Removes a widget instance from the dashboard
         * @param  {Object} widget The widget instance object (not a definition object)
         */
        scope.removeWidget = function (widget) {
          scope.widgets.splice(_.indexOf(scope.widgets, widget), 1);
          scope.saveDashboard();
        };

        /**
         * Opens a dialog for setting and changing widget properties
         * @param  {Object} widget The widget instance object
         */
        scope.openWidgetDialog = function (widget) {
          var options = widget.editModalOptions;

          // use default options when none are supplied by widget
          if (!options) {
            options = {
              templateUrl: 'template/widget-template.html',
              resolve: {
                widget: function () {
                  return widget;
                },
                optionsTemplateUrl: function () {
                  return scope.options.optionsTemplateUrl;
                }
              },
              controller: 'WidgetDialogCtrl'
            };
          }
          var modalInstance = $modal.open(options);

          // Set resolve and reject callbacks for the result promise
          modalInstance.result.then(
            function (result) {
              console.log('widget dialog closed');
              console.log('result: ', result);
              widget.title = result.title;
            },
            function (reason) {
              console.log('widget dialog dismissed: ', reason);

            }
          );

        };

        /**
         * Remove all widget instances from dashboard
         */
        scope.clear = function () {
          scope.widgets = [];
        };

        /**
         * Used for preventing default on click event
         * @param {Object} event     A click event
         * @param {Object} widgetDef A widget definition object
         */
        scope.addWidgetInternal = function (event, widgetDef) {
          event.preventDefault();
          scope.addWidget(widgetDef);
        };

        /**
         * Uses dashboardState service to save state
         */
        scope.saveDashboard = function () {
          dashboardState.save(scope.widgets);
        };

        /**
         * Clears current dash and instantiates widget definitions
         * @param  {Array} widgets Array of definition objects
         */
        scope.loadWidgets = function (widgets) {
          scope.defaultWidgets = widgets; // save widgets for reset
          scope.clear();
          _.each(widgets, function (widgetDef) {
            scope.addWidget(widgetDef);
          });
        };

        /**
         * Resets widget instances to default config
         * @return {[type]} [description]
         */
        scope.resetWidgetsToDefault = function () {
          scope.loadWidgets(scope.defaultWidgets);
        };

        // Set default widgets array
        var savedWidgets = dashboardState.load();

        if (savedWidgets) {
          scope.widgets = savedWidgets;
        } else if (scope.defaultWidgets) {
          scope.resetWidgetsToDefault();
        }

        // allow adding widgets externally
        scope.options.addWidget = scope.addWidget;
        scope.options.loadWidgets = scope.loadWidgets;

        // save state
        scope.$on('widgetChanged', function (event) {
          event.stopPropagation();
          scope.saveDashboard();
        });
      }
    };
  }]);<|endoftext|>


<commit_before>import React from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router';
import NotificationSystem from 'react-notification-system';
import {FormattedMessage, injectIntl, intlShape} from 'react-intl';
import {updateIntl} from 'react-intl-redux';
import {Grid, Icon, Image, Menu, Segment, Sidebar} from 'semantic-ui-react';
import {init} from '../utils/PopupManager';
import {hasUserRole} from '../utils/CurrentUserManager';
import {customStyle, pureStyle, rePaginationStyle, selectizeStyle} from '../../style/index';
import {ADMIN_ROLE, USER_ROLE} from '../../actions/constants';
import {get} from '../../apis/CurrentUserApi';
import {getStore} from '../../store';
import {getCurrentUserSuccess} from '../../actions/currentUser';
import eni18n from '../../i18n/en-US';
import fri18n from '../../i18n/fr-FR';

/*eslint-disable no-unused-vars*/
// prevent optimize import auto removal
//noinspection JSUnusedLocalSymbols
const customStyleImport = customStyle;
//noinspection JSUnusedLocalSymbols
const pureStyleImport = pureStyle;
//noinspection JSUnusedLocalSymbols
const rePaginationStyleImport = rePaginationStyle;
//noinspection JSUnusedLocalSymbols
const selectizeStyleImport = selectizeStyle;

class Global extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isMenuExpanded: false,
            menuActiveItem: ''
        };
    }

    componentDidMount() {
        init(this.refs.notificationSystem, this.props.intl);
        get((user) => {
            const language = [eni18n, fri18n].find((item) => item.language === user.language);
            getStore().dispatch(updateIntl(language));
            getStore().dispatch(getCurrentUserSuccess(user));
        });
    }

    componentWillReceiveProps(nextProps) {
        this.setState(Object.assign({}, this.state, {currentUser: nextProps.currentUser}));
    }

    render() {
        return (

                <Sidebar.Pushable as={Segment} attached='bottom'>
                    <Sidebar width={this.state.isMenuExpanded ? 'thin' : 'very thin'} as={Menu} animation='push' visible icon vertical inverted>
                        <Menu.Item onClick={() => this.setState({isMenuExpanded: !this.state.isMenuExpanded})}>
                            <Icon name='sidebar' size='large'/>
                        </Menu.Item>
                        <Menu.Item name='enterprise' active={this.state.menuActiveItem === 'enterprise'}
                                   onClick={() => this.setState({menuActiveItem: 'enterprise'})}>
                            <Link to='/enterprise/list'>
                                <Icon name='industry' size='large'/>

                                    <FormattedMessage id='menu.enterprises.link' defaultMessage='Enterprises'/>

                            </Link>
                        </Menu.Item>
                        <Menu.Item name='person' active={this.state.menuActiveItem === 'person'}
                                   onClick={() => this.setState({menuActiveItem: 'person'})}>
                            <Link to='/person/list'>
                                <Icon name='address book' size='large'/>

                                    <FormattedMessage id='menu.persons.link' defaultMessage='Persons'/>

                            </Link>
                        </Menu.Item>
                        <Menu.Item name='user' active={this.state.menuActiveItem === 'user'} className={!hasUserRole(ADMIN_ROLE) ? 'hidden' : ''}
                                   onClick={() => this.setState({menuActiveItem: 'user'})}>
                            <Link to='/user/list'>
                                <Icon name='users' size='large'/>

                                    <FormattedMessage id='menu.users.link' defaultMessage='Users'/>

                            </Link>
                        </Menu.Item>
                    </Sidebar>
                    <Sidebar.Pusher>
                        <Menu secondary attached='top'>
                            <Menu.Menu position='right'>
                                <Menu.Item name='avatar' style={{paddingRight: this.state.isMenuExpanded ? '170px' : '70px'}}>
                                    <Image src={this.props.avatarUrl} avatar/>
                                    <Link to='/profile'>{this.props.currentUser !== undefined ? this.props.currentUser.username : ''}</Link>
                                     <FormattedMessage id='menu.logout.alt.message' defaultMessage='Logout'/>
                                </Menu.Item>
                            </Menu.Menu>
                        </Menu>

                        <Grid className='grid-padded' style={{'paddingLeft': '10px'}}>
                            <Grid.Row>
                                <Grid.Column width={this.state.isMenuExpanded ? 14 : 15}>
                                    <Segment>{this.props.children}</Segment>
                                </Grid.Column>
                                <Grid.Column width={this.state.isMenuExpanded ? 2 : 1}/>
                            </Grid.Row>
                        </Grid>
                    </Sidebar.Pusher>
                </Sidebar.Pushable>
                <NotificationSystem ref='notificationSystem'/>

        );
    }
}

Global.propTypes = {
    intl:        intlShape.isRequired,
    currentUser: React.PropTypes.shape({
        id:       React.PropTypes.number.isRequired,
        username: React.PropTypes.string.isRequired,
        email:    React.PropTypes.string.isRequired,
        roles:    React.PropTypes.arrayOf(React.PropTypes.oneOf([ADMIN_ROLE, USER_ROLE]))
    }),
    avatarUrl:   React.PropTypes.string.isRequired
};

Global.propTypes = {
    avatarUrl: React.PropTypes.string,
    children:  React.PropTypes.object
};

Global.defaultProps = {
    avatarUrl: '/api/avatars/-1'
};

const mapStateToProps = (state) => {
    return {
        currentUser: state.currentUserReducer.get('currentUser'),
        avatarUrl:   state.currentUserReducer.get('avatarUrl')
    };
};

export default injectIntl(connect(mapStateToProps)(Global));

<commit_msg>Update user for semantic<commit_after>import React from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router';
import NotificationSystem from 'react-notification-system';
import {FormattedMessage, injectIntl, intlShape} from 'react-intl';
import {updateIntl} from 'react-intl-redux';
import {Grid, Icon, Image, Menu, Segment, Sidebar} from 'semantic-ui-react';
import {init} from '../utils/PopupManager';
import {hasUserRole} from '../utils/CurrentUserManager';
import {customStyle, pureStyle, rePaginationStyle, selectizeStyle} from '../../style/index';
import {ADMIN_ROLE, USER_ROLE} from '../../actions/constants';
import {get} from '../../apis/CurrentUserApi';
import {getStore} from '../../store';
import {getCurrentUserSuccess} from '../../actions/currentUser';
import eni18n from '../../i18n/en-US';
import fri18n from '../../i18n/fr-FR';

/*eslint-disable no-unused-vars*/
// prevent optimize import auto removal
//noinspection JSUnusedLocalSymbols
const customStyleImport = customStyle;
//noinspection JSUnusedLocalSymbols
const pureStyleImport = pureStyle;
//noinspection JSUnusedLocalSymbols
const rePaginationStyleImport = rePaginationStyle;
//noinspection JSUnusedLocalSymbols
const selectizeStyleImport = selectizeStyle;

class Global extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isMenuExpanded: false,
            menuActiveItem: ''
        };
    }

    componentDidMount() {
        init(this.refs.notificationSystem, this.props.intl);
        get((user) => {
            const language = [eni18n, fri18n].find((item) => item.language === user.language);
            getStore().dispatch(updateIntl(language));
            getStore().dispatch(getCurrentUserSuccess(user));
        });
    }

    componentWillReceiveProps(nextProps) {
        this.setState(Object.assign({}, this.state, {currentUser: nextProps.currentUser}));
    }

    render() {
        return (

                <Sidebar.Pushable as={Segment} attached='bottom'>
                    <Sidebar width={this.state.isMenuExpanded ? 'thin' : 'very thin'} as={Menu} animation='push' visible icon vertical inverted>
                        <Menu.Item onClick={() => this.setState({isMenuExpanded: !this.state.isMenuExpanded})}>
                            <Icon name='sidebar' size='large'/>
                        </Menu.Item>
                        <Menu.Item name='enterprise' active={this.state.menuActiveItem === 'enterprise'}
                                   onClick={() => this.setState({menuActiveItem: 'enterprise'})}>
                            <Link to='/enterprise/list'>
                                <Icon name='industry' size='large'/>

                                    <FormattedMessage id='menu.enterprises.link' defaultMessage='Enterprises'/>

                            </Link>
                        </Menu.Item>
                        <Menu.Item name='person' active={this.state.menuActiveItem === 'person'}
                                   onClick={() => this.setState({menuActiveItem: 'person'})}>
                            <Link to='/person/list'>
                                <Icon name='address book' size='large'/>

                                    <FormattedMessage id='menu.persons.link' defaultMessage='Persons'/>

                            </Link>
                        </Menu.Item>
                        <Menu.Item name='user' active={this.state.menuActiveItem === 'user'} className={!hasUserRole(ADMIN_ROLE) ? 'hidden' : ''}
                                   onClick={() => this.setState({menuActiveItem: 'user'})}>
                            <Link to='/user/list'>
                                <Icon name='users' size='large'/>

                                    <FormattedMessage id='menu.users.link' defaultMessage='Users'/>

                            </Link>
                        </Menu.Item>
                    </Sidebar>
                    <Sidebar.Pusher>
                        <Menu secondary attached='top'>
                            <Menu.Menu position='right'>
                                <Menu.Item name='avatar' style={{paddingRight: this.state.isMenuExpanded ? '170px' : '70px'}}>
                                    <Image src={this.props.avatarUrl} avatar/>
                                    <Link to='/profile'>{this.props.currentUser !== undefined ? this.props.currentUser.username : ''}</Link>
                                     /
                                    <FormattedMessage id='menu.logout.alt.message' defaultMessage='Logout'/>
                                </Menu.Item>
                            </Menu.Menu>
                        </Menu>

                        <Grid className='grid-padded' style={{'paddingLeft': '10px'}}>
                            <Grid.Row>
                                <Grid.Column width={this.state.isMenuExpanded ? 14 : 15}>
                                    <Segment>{this.props.children}</Segment>
                                </Grid.Column>
                                <Grid.Column width={this.state.isMenuExpanded ? 2 : 1}/>
                            </Grid.Row>
                        </Grid>
                    </Sidebar.Pusher>
                </Sidebar.Pushable>
                <NotificationSystem ref='notificationSystem'/>

        );
    }
}

Global.propTypes = {
    intl:        intlShape.isRequired,
    currentUser: React.PropTypes.shape({
        id:       React.PropTypes.number.isRequired,
        username: React.PropTypes.string.isRequired,
        email:    React.PropTypes.string.isRequired,
        roles:    React.PropTypes.arrayOf(React.PropTypes.oneOf([ADMIN_ROLE, USER_ROLE]))
    }),
    avatarUrl:   React.PropTypes.string.isRequired
};

Global.propTypes = {
    avatarUrl: React.PropTypes.string,
    children:  React.PropTypes.object
};

Global.defaultProps = {
    avatarUrl: '/api/avatars/-1'
};

const mapStateToProps = (state) => {
    return {
        currentUser: state.currentUserReducer.get('currentUser'),
        avatarUrl:   state.currentUserReducer.get('avatarUrl')
    };
};

export default injectIntl(connect(mapStateToProps)(Global));

<|endoftext|>


<commit_before>var _toInteger = function(n) {
        n = +n;
        if (n !== n) { // isNaN
            n = 0;
        } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
            n = (n > 0 || -1) * Math.floor(Math.abs(n));
        }
        return n;
    },
    _boxedString = Object('a'),
    _splitString = _boxedString[0] !== 'a' || !(0 in _boxedString),
    _toString = (function(toString) {

        return function(obj) {
            return toString.call(obj);
        };

    }(Object.prototype.toString));

// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) !== -1)) {
    Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
        var self = _splitString && _toString(this) === '[object String]' ?
                this.split('') :
                toObject(this),
            length = self.length >>> 0;

        if (!length) {
            return -1;
        }

        var i = 0;
        if (arguments.length > 1) {
            i = _toInteger(arguments[1]);
        }

        // handle negative indices
        i = i >= 0 ? i : Math.max(0, length + i);
        for (; i < length; i++) {
            if (i in self && self[i] === sought) {
                return i;
            }
        }
        return -1;
    };
}<commit_msg>Add missing toObject function<commit_after>// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) !== -1)) {

    var _toInteger = function(n) {
            n = +n;
            if (n !== n) { // isNaN
                n = 0;
            } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
            return n;
        },
        _boxedString = Object('a'),
        _splitString = _boxedString[0] !== 'a' || !(0 in _boxedString),
        _toString = (function(toString) {

            return function(obj) {
                return toString.call(obj);
            };

        }(Object.prototype.toString)),

        _toObject = function(o) {
            if (o == null) { // this matches both null and undefined
                throw new TypeError("can't convert "+o+" to object");
            }
            return Object(o);
        };

    Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
        var self = _splitString && _toString(this) === '[object String]' ?
                this.split('') :
                _toObject(this),
            length = self.length >>> 0;

        if (!length) {
            return -1;
        }

        var i = 0;
        if (arguments.length > 1) {
            i = _toInteger(arguments[1]);
        }

        // handle negative indices
        i = i >= 0 ? i : Math.max(0, length + i);
        for (; i < length; i++) {
            if (i in self && self[i] === sought) {
                return i;
            }
        }
        return -1;
    };
}<|endoftext|>