<commit_before>var Participants = (function(){
    var participantsDatagrid = {};
    var participantFollowControl = {};
    var participants = {};
    var newParticipant = {
        inks:0,
        highlighters:0,
        texts:{},
        images:0,
        quizResponses:0,
        submissions:0,
        following:true
    };
    var reRenderParticipants = function(){
        updateParticipantsListing();
    };
    var onHistoryReceived = function(history){
        var newParticipants = {};
        Analytics.word.reset();
        var ensure = function(author){
            return newParticipants[author] || _.cloneDeep(newParticipant);
        }
        _.each(_.groupBy(history.attendances,"author"),function(authorAttendances){
            var author = authorAttendances[0].author;
            var itemToEdit = ensure(newParticipant);
            itemToEdit.name = author;
            itemToEdit.attendances = authorAttendances;
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.inks,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.inks = itemToEdit.inks + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.highlighters,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.highlighters = itemToEdit.highlighters + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.images,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.images = itemToEdit.images + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.multiWordTexts,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            _.each(authorStanzas,function(stanza){
                var total = countTexts(stanza);
                newParticipants[author].texts[stanza.identity] = total;
            });
        });
        _.each(_.groupBy(history.quizResponses,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.quizResponses = itemToEdit.quizResponses + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });

        participants = newParticipants;

        updateParticipantsListing();
    };
    var countTexts = function(stanza){
        return _.reduce(stanza.words,function(acc,v,k){
            return acc + v.text.length;
        },0);
    }
    var onStanzaReceived = function(stanza){
        var act = false;
        if ("type" in stanza && "author" in stanza){
            var author = stanza.author;
            if(!(author in participants)){
                var np = _.clone(newParticipant);
                np.name = author;
                participants[author] = np;
            }
            var itemToEdit = participants[author];
            switch (stanza.type) {
            case "ink":
                itemToEdit.inks = itemToEdit.inks + 1;
                act = true;
                break;
            case "image":
                itemToEdit.images = itemToEdit.images + 1;
                act = true;
                break;
            case "highlighter":
                itemToEdit.highlighters = itemToEdit.highlighters + 1;
                act = true;
                break;
            case "multiWordText":
                itemToEdit.texts[stanza.identity] = countTexts(stanza);
                act = true;
                break;
            case "submission":
                itemToEdit.submissions = itemToEdit.submissions + 1;
                act = true;
                break;
            case "quizResponse":
                itemToEdit.quizResponses = itemToEdit.quizResponses + 1;
                act = true;
                break;
            }
            participants[author] = itemToEdit;
        }
        if(act){
            updateParticipantsListing();
        }
    };
    var fontSizes = d3.scaleLinear().range([9,30]);
    var themeCloud;
    var updateThemes = function(data){
        if(!themeCloud) themeCloud = d3.select("#lang")
            .style("margin-left","1em");
        fontSizes.domain(d3.extent(_.map(data,"value")));
	$("#lang .word").remove();
        var words = themeCloud.selectAll(".word")
                .data(data,function(d){
                    return d.key;
                });
        words.enter()
            .append("div")
            .attr("class","word")
            .style("margin-right","1em")
            .style("display","inline-block")
            .style("vertical-align","middle")
            .text(function(d){
                return d.key;
            })
            .style("font-size",function(d){
		console.log(d,fontSizes(d.value));
                return fontSizes(d.value)+"px";
            })
            .merge(words)
            .sort(function(a,b){
                return d3.ascending(b.value, a.value);
            });
        words.exit()
            .remove();
    }
    var contextFilters = {
        keyboarding:true,
        handwriting:true,
        imageRecognition:true,
        imageTranscription:true,
	conjugate:true
    };
    var updateParticipantsListing = function(){
        participantsDatagrid.jsGrid("loadData");
        var sortObj = participantsDatagrid.jsGrid("getSorting");
        if ("field" in sortObj){
            participantsDatagrid.jsGrid("sort",sortObj);
        }
        Analytics.word.reset();
        var contexts = {};
        _.each(boardContent.themes,function(theme){
            _.each(theme.text.split(" "),function(t){
                if(t.length > 0){//It will come back with empty strings
                    t = t.toLowerCase();
		    if(contextFilters.conjugate){
			t = nlp_compromise.text(t).root();
		    }
                    var context = theme.origin;
                    if(contextFilters[context] == true){
                        Analytics.word.incorporate(t);
                        if(!(t in contexts)){
                            contexts[t] = {};
                        }
                        if(!(context in contexts[t])){
                            contexts[t][context] = 0;
                        }
                        contexts[t][context]++;
                    }
                }
            });
        });
        updateThemes(Analytics.word.cloudData());
    };
    var openParticipantsMenuFunction = function(){
        showBackstage("participants");
        updateActiveMenu(this);
        updateFilters();
        updateParticipantsListing();
    };
    var updateButtons = function(){
        if (Conversations.shouldModifyConversation()){
            $("#menuParticipants").off().on("click",openParticipantsMenuFunction);
            $("#menuParticipants").show();
        } else {
            $("#menuParticipants").unbind("click");
            $("#menuParticipants").hide();
        }
    };
    var onDetailsReceived = function(){
        updateButtons();
    };
    var updateFilters = function(){
        _.each(contextFilters,function(val,filter){
            var el = $(sprintf("#%s",filter));
            el.attr("checked",contextFilters[filter]);
            el.off("click").on("click",function(){
                contextFilters[filter] = !contextFilters[filter];
                updateParticipantsListing();
            });
        });
    }
    $(function(){
        updateButtons();
        participantsDatagrid = $("#participantsDatagrid");
        participantFollowControl = participantsDatagrid.find(".followControls").clone();
        participantsDatagrid.empty();
        var DateField = function(config){
            jsGrid.Field.call(this,config);
        };
        DateField.prototype = new jsGrid.Field({
            sorter: function(a,b){
                return new Date(a) - new Date(b);
            },
            itemTemplate: function(i){
                return new Date(i).toLocaleString();
            },
            insertTemplate: function(i){return ""},
            editTemplate: function(i){return ""},
            insertValue: function(){return ""},
            editValue: function(){return ""}
        });
        jsGrid.fields.dateField = DateField;

        var gridFields = [
            {
                name:"name",
                type:"text",
                title:"Follow",
                readOnly:true,
                sorting:true,
                itemTemplate:function(username,participant){
                    var rootElem = participantFollowControl.clone();
                    var elemId = sprintf("participant_%s",participant.name);
                    rootElem.find(".followValue").attr("id",elemId).prop("checked",participant.following).on("change",function(){
                        participants[participant.name].following = $(this).is(":checked");
                        blit();
                        updateParticipantsListing();
                    });
                    rootElem.find(".followLabel").attr("for",elemId).text(participant.name);
                    return rootElem;
                }
            },
            {name:"attendances",type:"number",title:"Attendances",readOnly:true},
            {name:"images",type:"number",title:"Images",readOnly:true},
            {name:"inks",type:"number",title:"Inks",readOnly:true},
            {name:"highlighters",type:"number",title:"Highlighters",readOnly:true},
            {name:"texts",type:"number",title:"Texts",readOnly:true},
            {name:"quizResponses",type:"number",title:"Poll responses",readOnly:true},
            {name:"submissions",type:"number",title:"Submissions",readOnly:true},
        ];
        participantsDatagrid.jsGrid({
            width:"100%",
            height:"auto",
            inserting:false,
            editing:false,
            sorting:true,
            paging:true,
            noDataContent: "No participants",
            controller: {
                loadData: function(filter){
                    var sorted = _.map(_.keys(participants),function(k){
                        var v = participants[k];
                        return {
                            name:k,
                            following:v.following,
                            attendances:_.size(v.attendances),
                            images:v.images,
                            inks:v.inks,
                            texts:_.reduce(v.texts,function(acc,item){return acc + item},0),
                            quizResponses:v.quizResponses,
                            submissions:v.submissions,
                            highlighters:v.highlighters
                        };
                    });
                    if ("sortField" in filter){
                        sorted = _.sortBy(sorted,function(sub){
                            return sub[filter.sortField];
                        });
                        if ("sortOrder" in filter && filter.sortOrder == "desc"){
                            sorted = _.reverse(sorted);
                        }
                    }
                    return sorted;
                }
            },
            pageLoading:false,
            fields: gridFields
        });
        participantsDatagrid.jsGrid("sort",{
            field:"name",
            order:"desc"
        });
        updateParticipantsListing();
    });
    Progress.stanzaReceived["participants"] = onStanzaReceived;
    Progress.themeReceived["participants"] = function(){
        if(window.currentBackstage == "participants"){
            updateParticipantsListing();
        }
    }
    Progress.historyReceived["participants"] = onHistoryReceived;
    Progress.conversationDetailsReceived["participants"] = onDetailsReceived;
    Progress.newConversationDetailsReceived["participants"] = onDetailsReceived;
    return {
        getParticipants:function(){return Conversations.shouldModifyConversation() ? participants : {};},
        reRender:function(){
            reRenderParticipants();
        },
        code:function(author){
            return _.keys(participants).indexOf(author);
        }
    };
})();
<commit_msg>267: Disable console<commit_after>var Participants = (function(){
    var participantsDatagrid = {};
    var participantFollowControl = {};
    var participants = {};
    var newParticipant = {
        inks:0,
        highlighters:0,
        texts:{},
        images:0,
        quizResponses:0,
        submissions:0,
        following:true
    };
    var reRenderParticipants = function(){
        updateParticipantsListing();
    };
    var onHistoryReceived = function(history){
        var newParticipants = {};
        Analytics.word.reset();
        var ensure = function(author){
            return newParticipants[author] || _.cloneDeep(newParticipant);
        }
        _.each(_.groupBy(history.attendances,"author"),function(authorAttendances){
            var author = authorAttendances[0].author;
            var itemToEdit = ensure(newParticipant);
            itemToEdit.name = author;
            itemToEdit.attendances = authorAttendances;
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.inks,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.inks = itemToEdit.inks + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.highlighters,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.highlighters = itemToEdit.highlighters + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.images,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.images = itemToEdit.images + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });
        _.each(_.groupBy(history.multiWordTexts,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            _.each(authorStanzas,function(stanza){
                var total = countTexts(stanza);
                newParticipants[author].texts[stanza.identity] = total;
            });
        });
        _.each(_.groupBy(history.quizResponses,"author"),function(authorStanzas,author){
            var itemToEdit = ensure(author);
            itemToEdit.quizResponses = itemToEdit.quizResponses + _.size(authorStanzas);
            newParticipants[author] = itemToEdit;
        });

        participants = newParticipants;

        updateParticipantsListing();
    };
    var countTexts = function(stanza){
        return _.reduce(stanza.words,function(acc,v,k){
            return acc + v.text.length;
        },0);
    }
    var onStanzaReceived = function(stanza){
        var act = false;
        if ("type" in stanza && "author" in stanza){
            var author = stanza.author;
            if(!(author in participants)){
                var np = _.clone(newParticipant);
                np.name = author;
                participants[author] = np;
            }
            var itemToEdit = participants[author];
            switch (stanza.type) {
            case "ink":
                itemToEdit.inks = itemToEdit.inks + 1;
                act = true;
                break;
            case "image":
                itemToEdit.images = itemToEdit.images + 1;
                act = true;
                break;
            case "highlighter":
                itemToEdit.highlighters = itemToEdit.highlighters + 1;
                act = true;
                break;
            case "multiWordText":
                itemToEdit.texts[stanza.identity] = countTexts(stanza);
                act = true;
                break;
            case "submission":
                itemToEdit.submissions = itemToEdit.submissions + 1;
                act = true;
                break;
            case "quizResponse":
                itemToEdit.quizResponses = itemToEdit.quizResponses + 1;
                act = true;
                break;
            }
            participants[author] = itemToEdit;
        }
        if(act){
            updateParticipantsListing();
        }
    };
    var fontSizes = d3.scaleLinear().range([9,30]);
    var themeCloud;
    var updateThemes = function(data){
        if(!themeCloud) themeCloud = d3.select("#lang")
            .style("margin-left","1em");
        fontSizes.domain(d3.extent(_.map(data,"value")));
	$("#lang .word").remove();
        var words = themeCloud.selectAll(".word")
                .data(data,function(d){
                    return d.key;
                });
        words.enter()
            .append("div")
            .attr("class","word")
            .style("margin-right","1em")
            .style("display","inline-block")
            .style("vertical-align","middle")
            .text(function(d){
                return d.key;
            })
            .style("font-size",function(d){
                return fontSizes(d.value)+"px";
            })
            .merge(words)
            .sort(function(a,b){
                return d3.ascending(b.value, a.value);
            });
        words.exit()
            .remove();
    }
    var contextFilters = {
        keyboarding:true,
        handwriting:true,
        imageRecognition:true,
        imageTranscription:true,
	conjugate:true
    };
    var updateParticipantsListing = function(){
        participantsDatagrid.jsGrid("loadData");
        var sortObj = participantsDatagrid.jsGrid("getSorting");
        if ("field" in sortObj){
            participantsDatagrid.jsGrid("sort",sortObj);
        }
        Analytics.word.reset();
        var contexts = {};
        _.each(boardContent.themes,function(theme){
            _.each(theme.text.split(" "),function(t){
                if(t.length > 0){//It will come back with empty strings
                    t = t.toLowerCase();
		    if(contextFilters.conjugate){
			t = nlp_compromise.text(t).root();
		    }
                    var context = theme.origin;
                    if(contextFilters[context] == true){
                        Analytics.word.incorporate(t);
                        if(!(t in contexts)){
                            contexts[t] = {};
                        }
                        if(!(context in contexts[t])){
                            contexts[t][context] = 0;
                        }
                        contexts[t][context]++;
                    }
                }
            });
        });
        updateThemes(Analytics.word.cloudData());
    };
    var openParticipantsMenuFunction = function(){
        showBackstage("participants");
        updateActiveMenu(this);
        updateFilters();
        updateParticipantsListing();
    };
    var updateButtons = function(){
        if (Conversations.shouldModifyConversation()){
            $("#menuParticipants").off().on("click",openParticipantsMenuFunction);
            $("#menuParticipants").show();
        } else {
            $("#menuParticipants").unbind("click");
            $("#menuParticipants").hide();
        }
    };
    var onDetailsReceived = function(){
        updateButtons();
    };
    var updateFilters = function(){
        _.each(contextFilters,function(val,filter){
            var el = $(sprintf("#%s",filter));
            el.attr("checked",contextFilters[filter]);
            el.off("click").on("click",function(){
                contextFilters[filter] = !contextFilters[filter];
                updateParticipantsListing();
            });
        });
    }
    $(function(){
        updateButtons();
        participantsDatagrid = $("#participantsDatagrid");
        participantFollowControl = participantsDatagrid.find(".followControls").clone();
        participantsDatagrid.empty();
        var DateField = function(config){
            jsGrid.Field.call(this,config);
        };
        DateField.prototype = new jsGrid.Field({
            sorter: function(a,b){
                return new Date(a) - new Date(b);
            },
            itemTemplate: function(i){
                return new Date(i).toLocaleString();
            },
            insertTemplate: function(i){return ""},
            editTemplate: function(i){return ""},
            insertValue: function(){return ""},
            editValue: function(){return ""}
        });
        jsGrid.fields.dateField = DateField;

        var gridFields = [
            {
                name:"name",
                type:"text",
                title:"Follow",
                readOnly:true,
                sorting:true,
                itemTemplate:function(username,participant){
                    var rootElem = participantFollowControl.clone();
                    var elemId = sprintf("participant_%s",participant.name);
                    rootElem.find(".followValue").attr("id",elemId).prop("checked",participant.following).on("change",function(){
                        participants[participant.name].following = $(this).is(":checked");
                        blit();
                        updateParticipantsListing();
                    });
                    rootElem.find(".followLabel").attr("for",elemId).text(participant.name);
                    return rootElem;
                }
            },
            {name:"attendances",type:"number",title:"Attendances",readOnly:true},
            {name:"images",type:"number",title:"Images",readOnly:true},
            {name:"inks",type:"number",title:"Inks",readOnly:true},
            {name:"highlighters",type:"number",title:"Highlighters",readOnly:true},
            {name:"texts",type:"number",title:"Texts",readOnly:true},
            {name:"quizResponses",type:"number",title:"Poll responses",readOnly:true},
            {name:"submissions",type:"number",title:"Submissions",readOnly:true},
        ];
        participantsDatagrid.jsGrid({
            width:"100%",
            height:"auto",
            inserting:false,
            editing:false,
            sorting:true,
            paging:true,
            noDataContent: "No participants",
            controller: {
                loadData: function(filter){
                    var sorted = _.map(_.keys(participants),function(k){
                        var v = participants[k];
                        return {
                            name:k,
                            following:v.following,
                            attendances:_.size(v.attendances),
                            images:v.images,
                            inks:v.inks,
                            texts:_.reduce(v.texts,function(acc,item){return acc + item},0),
                            quizResponses:v.quizResponses,
                            submissions:v.submissions,
                            highlighters:v.highlighters
                        };
                    });
                    if ("sortField" in filter){
                        sorted = _.sortBy(sorted,function(sub){
                            return sub[filter.sortField];
                        });
                        if ("sortOrder" in filter && filter.sortOrder == "desc"){
                            sorted = _.reverse(sorted);
                        }
                    }
                    return sorted;
                }
            },
            pageLoading:false,
            fields: gridFields
        });
        participantsDatagrid.jsGrid("sort",{
            field:"name",
            order:"desc"
        });
        updateParticipantsListing();
    });
    Progress.stanzaReceived["participants"] = onStanzaReceived;
    Progress.themeReceived["participants"] = function(){
        if(window.currentBackstage == "participants"){
            updateParticipantsListing();
        }
    }
    Progress.historyReceived["participants"] = onHistoryReceived;
    Progress.conversationDetailsReceived["participants"] = onDetailsReceived;
    Progress.newConversationDetailsReceived["participants"] = onDetailsReceived;
    return {
        getParticipants:function(){return Conversations.shouldModifyConversation() ? participants : {};},
        reRender:function(){
            reRenderParticipants();
        },
        code:function(author){
            return _.keys(participants).indexOf(author);
        }
    };
})();
<|endoftext|>


<commit_before>'use strict';

// external deps
var ObjectId = require('mongodb').ObjectId;

// internal deps
require('mongodb-toolkit');
var BateeqModels = require('bateeq-models');
var map = BateeqModels.map;

var Storage = BateeqModels.inventory.Storage;

module.exports = class StorageManager {
    constructor(db, user) {
        this.db = db;
        this.user = user;
        this.storageCollection = this.db.use(map.inventory.Storage);
    }

    read() {
        return new Promise((resolve, reject) => {
            this.storageCollection
                .execute()
                .then(storages => {
                    resolve(storages);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getById(id) {
        return new Promise((resolve, reject) => {
            var query = {
                _id: new ObjectId(id)
            };
            this.getSingleByQuery(query)
                .then(storage => {
                    resolve(storage);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getSingleByQuery(query) {
        return new Promise((resolve, reject) => {
            this.storageCollection
                .single(query)
                .then(storage => {
                    resolve(storage);
                })
                .catch(e => {
                    reject(e);
                });
        })
    }

    create(storage) {
        return new Promise((resolve, reject) => {
            this._validate(storage)
                .then(validStorage => {

                    this.storageCollection.insert(validStorage)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    update(storage) {
        return new Promise((resolve, reject) => {
            this._validate(storage)
                .then(validStorage => {
                    this.storageCollection.update(validStorage)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    delete(storage) {
        return new Promise((resolve, reject) => {
            this._validate(storage)
                .then(validStorage => {
                    validStorage._deleted = true;
                    this.storageCollection.update(validStorage)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    _validate(storage) {
        return new Promise((resolve, reject) => {
            var valid = new Storage(storage);
            valid.stamp(this.user.username,'manager');
            resolve(valid);
        });
    }
};<commit_msg>1.0.0<commit_after>'use strict';

// external deps
var ObjectId = require('mongodb').ObjectId;

// internal deps
require('mongodb-toolkit');
var BateeqModels = require('bateeq-models');
var map = BateeqModels.map;

var Storage = BateeqModels.inventory.Storage;

module.exports = class StorageManager {
    constructor(db, user) {
        this.db = db;
        this.user = user;
        this.storageCollection = this.db.use(map.inventory.Storage);
    }

    read(paging) {
        var _paging = Object.assign({
            page: 1,
            size: 20,
            order: '_id',
            asc: true
        }, paging);

        return new Promise((resolve, reject) => {
            this.storageCollection
                .where({_deleted:false})
                .page(_paging.page, _paging.size)
                .orderBy(_paging.order, _paging.asc)
                .execute()
                .then(storages => {
                    resolve(storages);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getById(id) {
        return new Promise((resolve, reject) => {
            var query = {
                _id: new ObjectId(id)
            };
            this.getSingleByQuery(query)
                .then(storage => {
                    resolve(storage);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getSingleByQuery(query) {
        return new Promise((resolve, reject) => {
            this.storageCollection
                .single(query)
                .then(storage => {
                    resolve(storage);
                })
                .catch(e => {
                    reject(e);
                });
        })
    }

    create(storage) {
        return new Promise((resolve, reject) => {
            this._validate(storage)
                .then(validStorage => {

                    this.storageCollection.insert(validStorage)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    update(storage) {
        return new Promise((resolve, reject) => {
            this._validate(storage)
                .then(validStorage => {
                    this.storageCollection.update(validStorage)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    delete(storage) {
        return new Promise((resolve, reject) => {
            this._validate(storage)
                .then(validStorage => {
                    validStorage._deleted = true;
                    this.storageCollection.update(validStorage)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    _validate(storage) {
        return new Promise((resolve, reject) => {
            var valid = new Storage(storage);
            valid.stamp(this.user.username,'manager');
            resolve(valid);
        });
    }
};<|endoftext|>


<commit_before>!function(seine, exports) {
  'use strict';

  var Component = seine.Component,
      keyboard = demo.keyboard;

  var PositionLogger = Component.extend();

  PositionLogger.prototype.update = function(delta, x, y, z) {
    if(keyboard.pressed(keyboard.key.BACKTICK)) {
      console.log('position: (' + x + ', ' + y + ', ' + z + ')');
    }
  };

  exports.PositionLogger = PositionLogger;

}(seine, demo);
<commit_msg>Use tilde, not backtick, for logging.<commit_after>!function(seine, exports) {
  'use strict';

  var Component = seine.Component,
      keyboard = demo.keyboard;

  var KEY = keyboard.key.BACKTICK,
      MOD = keyboard.key.SHIFT;

  var PositionLogger = Component.extend();

  PositionLogger.prototype.update = function(delta, x, y, z) {
    if(modifier() && pressed()) {
      console.log('position: (' + x + ', ' + y + ', ' + z + ')');
    }
  };

  function modifier() { return keyboard.down(MOD); }
  function pressed() { return keyboard.pressed(KEY); }

  exports.PositionLogger = PositionLogger;

}(seine, demo);
<|endoftext|>


<commit_before>class CommentTags extends HTMLElement {
  constructor(tags, playbackEngine) {
    super();
    this.playbackEngine = playbackEngine;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(this.getTemplate());

    const permanentCommentTags = ['all-tests-pass', 'successful-run', 'version-control-commit'];

    //create and add tag to tagsDiv
    const allTagsInComment = this.formatArrayOfTags(tags);
    allTagsInComment.forEach(tag => {
      this.addTag(tag);
    })

    let arrayTesting = permanentCommentTags.concat(this.playbackEngine.commentInfo.allTags);
    arrayTesting = this.formatArrayOfTags(arrayTesting);

    this.masterTagList = new Set(arrayTesting);

    //TODO change ids/classes of divs

    this.masterTagList.forEach(tagToAvoid => {
      if (!tags.includes(tagToAvoid)) {
        this.addTagToDropdown(tagToAvoid)
      }
    })
  }

  getTemplate() {
    const template = document.createElement('template');
    template.innerHTML = `

              <button class="dropdown_button" title='Expand tag options'></button>

          <input type="text" id='tagInput' placeholder='Enter a tag...'>
          <input type='button' id='addTagButton' value='Add tag'>

    `;
    return template.content.cloneNode(true);
  }

  connectedCallback() {
    const tagInput = this.shadowRoot.querySelector('#tagInput');
    const addTagButton = this.shadowRoot.querySelector('#addTagButton');

    addTagButton.addEventListener('click', () => {
      const tagValue = tagInput.value;

      if (tagValue.length) {
        this.addTag(tagValue);
      }
      tagInput.value = '';
    })

    tagInput.addEventListener('keydown', event => {
      //add a key down listener to stop keys from affecting the playback
      event.stopImmediatePropagation();

      if (event.key === 'Enter') {
        addTagButton.click();
      }
    });
    var tags = this.shadowRoot.getElementById("tags-div");

    tags.style.height = '0px';
    const dropDownButton = this.shadowRoot.querySelector('.dropdown_button');
    dropDownButton.addEventListener('click', (event) => {
      event.stopImmediatePropagation();
      dropDownButton.classList.toggle('expanded');

      if (dropDownButton.classList.contains('expanded')) {
        dropDownButton.setAttribute('title', 'Collapse tag options');
      } else {
        dropDownButton.setAttribute('title', 'Expand tag options');
      }

      tags.classList.toggle('hidden');

      if (!tags.classList.contains('hidden')) {
        //tags.style.display = 'block'
        tags.style.height = tags.scrollHeight + 'px';
      } else {
        // tags.style.display = 'none';
        tags.style.height = '0px';
      }
    });

    const blah = this.shadowRoot.querySelector('#tags-div').getElementsByTagName('li');

    for (let i = 0; i < blah.length; i++) {
      //const thisBlah = blah[i];
      this.addEventListenerToDropdownItem(blah[i]);
    }

    //prevent the click event from bubbling higher to avoid click listeners in other components
    this.shadowRoot.addEventListener('click', (event) => {
      event.stopImmediatePropagation();
      this.closeDropDown();
    })
  }

  addEventListenerToDropdownItem(thisBlah) {
    thisBlah.addEventListener('click', (event) => {
      event.stopImmediatePropagation();

      event.preventDefault();
      this.addTag(thisBlah.innerText);
      thisBlah.remove();
      var tags = this.shadowRoot.getElementById("tags-div");

      tags.style.height = 'fit-content';

    });
  }

  formatArrayOfTags(arrayOfTags) {
    for (let i = 0; i < arrayOfTags.length; i++) {
      arrayOfTags[i] = this.formatTag(arrayOfTags[i]);
    }
    return arrayOfTags.sort();
  }

  formatTag(tag) {
    return tag.trim().toLowerCase().replaceAll(' ', '-');
  }

  addTagToDropdown(tag) {
    const tagsDiv = this.shadowRoot.getElementById('tags-div');
    const dropDownTagsDiv = this.shadowRoot.querySelectorAll('.dropDownTag');
    const tagsArray = [tag];

    dropDownTagsDiv.forEach(dropDownTag => {
      tagsArray.push(dropDownTag.innerText);
    });
    tagsArray.sort();

    tagsDiv.innerHTML = '';
    tagsArray.forEach(dropDownTag => {
      const newTag = this.createTag(dropDownTag, false);
      tagsDiv.appendChild(newTag);
    });
  }

  addTag(tag) {
    tag = this.formatTag(tag);
    let allTags = this.getAllTags();

    if (!allTags.includes(tag)) {
      allTags.push(tag);
      allTags.sort();

      //TODO come up with an algorithm to drop the new tag in it's right place alphabetically
      const tagDiv = this.shadowRoot.querySelector('#tagsDiv');
      tagDiv.innerHTML = '';
      allTags.forEach(tag => {
        const newTag = this.createTag(tag);
        tagDiv.appendChild(newTag);
      });
    }
  }

  createTag(tag, isCommentTag = true) {
    const newTag = document.createElement("div");
    newTag.appendChild(document.createTextNode(tag));
    newTag.classList.add('tag');

    if (isCommentTag) {
      const removeTagButton = document.createElement('button');
      removeTagButton.innerHTML = '✕';
      removeTagButton.classList.add('removeTag');
      removeTagButton.title = 'Remove tag';

      removeTagButton.addEventListener('click', () => {
        newTag.remove();
        if (this.masterTagList.has(tag)) {
          this.addTagToDropdown(tag);
        }
      });
      newTag.appendChild(removeTagButton);
    } else { //tag in the dropdown list
      newTag.classList.add('dropDownTag');
      newTag.setAttribute('title', 'Add tag to comment');
      this.addEventListenerToDropdownItem(newTag);
    }
    return newTag;
  }

  getAllTags() {
    const retVal = [];
    const allTags = this.shadowRoot.querySelectorAll('.tag:not(.dropDownTag)');
    allTags.forEach(tag => {
      retVal.push(tag.firstChild.textContent);
    });
    return retVal;
  }

  closeDropDown() {
    const tags = this.shadowRoot.getElementById("tags-div");

    if (!tags.classList.contains('hidden')) {
      const dropDownButton = this.shadowRoot.querySelector('.dropdown_button');
      dropDownButton.click();
    }
  }
}
window.customElements.define('st-comment-tags', CommentTags);
<commit_msg>Changed styling on addTag button and on the tag drop down div<commit_after>class CommentTags extends HTMLElement {
  constructor(tags, playbackEngine) {
    super();
    this.playbackEngine = playbackEngine;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(this.getTemplate());

    const permanentCommentTags = ['all-tests-pass', 'successful-run', 'version-control-commit'];

    //create and add tag to tagsDiv
    const allTagsInComment = this.formatArrayOfTags(tags);
    allTagsInComment.forEach(tag => {
      this.addTag(tag);
    })

    let arrayTesting = permanentCommentTags.concat(this.playbackEngine.commentInfo.allTags);
    arrayTesting = this.formatArrayOfTags(arrayTesting);

    this.masterTagList = new Set(arrayTesting);

    //TODO change ids/classes of divs

    this.masterTagList.forEach(tagToAvoid => {
      if (!tags.includes(tagToAvoid)) {
        this.addTagToDropdown(tagToAvoid)
      }
    })
  }

  getTemplate() {
    const template = document.createElement('template');
    template.innerHTML = `

          <button class="dropdown_button" title="Expand tag options"></button>
          <input type="text" id="tagInput" placeholder="Enter a tag..." />
          <input type="button" id="addTagButton" value="Add tag" />

              <button id="closeDropDown" title='Collapse tag options'>X</button>

    `;
    return template.content.cloneNode(true);
  }

  connectedCallback() {
    const tagInput = this.shadowRoot.querySelector('#tagInput');
    const addTagButton = this.shadowRoot.querySelector('#addTagButton');

    addTagButton.addEventListener('click', () => {
      const tagValue = tagInput.value;

      if (tagValue.length) {
        this.addTag(tagValue);
      }
      tagInput.value = '';
    })

    tagInput.addEventListener('keydown', event => {
      //add a key down listener to stop keys from affecting the playback
      event.stopImmediatePropagation();

      if (event.key === 'Enter') {
        addTagButton.click();
      }
    });
    var tags = this.shadowRoot.getElementById("tags-div");

    tags.style.height = '0px';

    const test = this.shadowRoot.querySelector('#dropdownControls');
    test.style.height = '0px';

    const dropDownButton = this.shadowRoot.querySelector('.dropdown_button');
    dropDownButton.addEventListener('click', (event) => {
      event.stopImmediatePropagation();
      dropDownButton.classList.toggle('expanded');

      if (dropDownButton.classList.contains('expanded')) {
        dropDownButton.setAttribute('title', 'Collapse tag options');
      } else {
        dropDownButton.setAttribute('title', 'Expand tag options');
      }

      const test = this.shadowRoot.querySelector('#dropdownControls');
      test.classList.toggle('hidden');
      tags.classList.toggle('hidden');

      if (!tags.classList.contains('hidden')) {
        //tags.style.display = 'block'
        tags.style.height = tags.scrollHeight - 15 + 'px';
        test.style.height = test.scrollHeight  + tags.scrollHeight - 15+ 'px';

      } else {
        // tags.style.display = 'none';
        tags.style.height = '0px';
        test.style.height = '0px';

      }
    });

    //prevent the click event from bubbling higher to avoid click listeners in other components
    this.shadowRoot.addEventListener('click', (event) => {
      event.stopImmediatePropagation();
      //this.closeDropDown();
    })
  }

  addEventListenerToDropdownItem(tag) {
    tag.addEventListener('click', (event) => {
      event.stopImmediatePropagation();

      event.preventDefault();
      this.addTag(tag.innerText);
      tag.remove();
      var tags = this.shadowRoot.getElementById("tags-div");

      const testing = this.shadowRoot.querySelector('#dropdownControls');
      if (!testing.classList.contains('hidden')){
        testing.style.height = 'fit-content';
        tags.style.height = 'fit-content ';
      }

    });
  }

  formatArrayOfTags(arrayOfTags) {
    for (let i = 0; i < arrayOfTags.length; i++) {
      arrayOfTags[i] = this.formatTag(arrayOfTags[i]);
    }
    return arrayOfTags.sort();
  }

  formatTag(tag) {
    return tag.trim().toLowerCase().replaceAll(' ', '-');
  }

  addTagToDropdown(tag) {
    const tagsDiv = this.shadowRoot.querySelector('#tags-div');
    const dropDownTagsDiv = this.shadowRoot.querySelectorAll('.dropDownTag');
    const tagsArray = [tag];

    dropDownTagsDiv.forEach(dropDownTag => {
      tagsArray.push(dropDownTag.innerText);
    });
    tagsArray.sort();

    tagsDiv.innerHTML = '';
    tagsArray.forEach(dropDownTag => {
      const newTag = this.createTag(dropDownTag, false);
      tagsDiv.appendChild(newTag);

      const testing = this.shadowRoot.querySelector('#dropdownControls');

      if (!tagsDiv.classList.contains('hidden'))
        tagsDiv.style.height = 'fit-content';
        testing.style.height = 'fit-content';
    });
  }

  addTag(tag) {
    tag = this.formatTag(tag);
    let allTags = this.getAllTags();

    if (!allTags.includes(tag)) {

      //if the tag is not in the comment but it is in the masterTagList
      if (this.masterTagList.has(tag)){
        const dropdownItems = [...this.shadowRoot.querySelectorAll('.dropDownTag')];
        dropdownItems.forEach(dropdownItem => {
          if (dropdownItem.innerText === tag){
            dropdownItem.click();
            return;
          }
        });
        //console.log('teting');
      }

      allTags.push(tag);
      allTags.sort();

      //TODO come up with an algorithm to drop the new tag in it's right place alphabetically
      const tagDiv = this.shadowRoot.querySelector('#tagsDiv');
      tagDiv.innerHTML = '';
      allTags.forEach(tag => {
        const newTag = this.createTag(tag);
        tagDiv.appendChild(newTag);
      });
    }
  }

  createTag(tag, isCommentTag = true) {
    const newTag = document.createElement("div");
    newTag.appendChild(document.createTextNode(tag));
    newTag.classList.add('tag');

    if (isCommentTag) {
      const removeTagButton = document.createElement('button');
      removeTagButton.innerHTML = '✕';
      removeTagButton.classList.add('removeTag');
      removeTagButton.title = 'Remove tag';

      removeTagButton.addEventListener('click', () => {
        newTag.remove();
        if (this.masterTagList.has(tag)) {
          this.addTagToDropdown(tag);
        }
      });
      newTag.appendChild(removeTagButton);
    } else { //tag in the dropdown list
      newTag.classList.add('dropDownTag');
      newTag.setAttribute('title', 'Add tag to comment');
      this.addEventListenerToDropdownItem(newTag);
    }
    return newTag;
  }

  getAllTags() {
    const retVal = [];
    const allTags = this.shadowRoot.querySelectorAll('.tag:not(.dropDownTag)');
    allTags.forEach(tag => {
      retVal.push(tag.firstChild.textContent);
    });
    return retVal;
  }

  closeDropDown() {
    const tags = this.shadowRoot.getElementById("tags-div");

    if (!tags.classList.contains('hidden')) {
      const dropDownButton = this.shadowRoot.querySelector('.dropdown_button');
      dropDownButton.click();
    }
  }
}
window.customElements.define('st-comment-tags', CommentTags);
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2016 Actor LLC. <https://actor.im>
 */

import { isFunction, noop } from 'lodash';
import React, { Component, PropTypes } from 'react';
import { Container } from 'flux/utils';
import classnames from 'classnames';
import { escapeWithEmoji } from '../../../utils/EmojiUtils';
import PeerUtils from '../../../utils/PeerUtils';
import { MessageContentTypes } from '../../../constants/ActorAppConstants';

import DialogActionCreators from '../../../actions/DialogActionCreators';
import ActivityActionCreators from '../../../actions/ActivityActionCreators';
import DropdownActionCreators from '../../../actions/DropdownActionCreators';

import DropdownStore from '../../../stores/DropdownStore';
import GroupStore from '../../../stores/GroupStore';

import SvgIcon from '../../common/SvgIcon.react';
import AvatarItem from '../../common/AvatarItem.react';
import State from './State.react';
import Reactions from './Reactions.react';
import MessageEdit from './MessageEdit.react';

// Default message content components
import DefaultService from './Service.react';
import DefaultText from './Text.react';
import DefaultPhoto from './Photo.react';
import DefaultDocument from './Document.react';
import DefaultVoice from './Voice.react';
import DefaultContact from './Contact.react';
import DefaultLocation from './Location.react';
import DefaultModern from './Modern.react';
import DefaultSticker from './Sticker.react';

class MessageItem extends Component {
  static contextTypes = {
    delegate: PropTypes.object,
    isExperimental: PropTypes.bool
  }

  static propTypes = {
    peer: PropTypes.object.isRequired,
    message: PropTypes.object.isRequired,
    state: PropTypes.string.isRequired,
    isShort: PropTypes.bool.isRequired,
    isEditing: PropTypes.bool.isRequired,
    onEdit: PropTypes.func.isRequired,
    isSelected: PropTypes.bool.isRequired,
    onSelect: PropTypes.func.isRequired
  }

  static defaultProps = {
    isSelected: false,
    onSelect: noop
  };

  static getStores() {
    return [DropdownStore];
  }

  static calculateState(prevState, props) {
    return {
      isHighlighted: props && props.message ? DropdownStore.isMessageDropdownOpen(props.message.rid) : false
    }
  }

  constructor(props, context) {
    super(props, context);

    this.onClick = this.onClick.bind(this);
  }

  componentWillMount() {
    const { dialog } = this.context.delegate.components;
    if (dialog && dialog.messages) {
      this.components = {
        Service: isFunction(dialog.messages.service) ? dialog.messages.service : DefaultService,
        Text: isFunction(dialog.messages.text) ? dialog.messages.text : DefaultText,
        Modern: isFunction(dialog.messages.modern) ? dialog.messages.modern : DefaultModern,
        Photo: isFunction(dialog.messages.photo) ? dialog.messages.photo : DefaultPhoto,
        Document: isFunction(dialog.messages.document) ? dialog.messages.document : DefaultDocument,
        Voice: isFunction(dialog.messages.voice) ? dialog.messages.voice : DefaultVoice,
        Contact: isFunction(dialog.messages.contact) ? dialog.messages.contact : DefaultContact,
        Location: isFunction(dialog.messages.location) ? dialog.messages.location : DefaultLocation,
        Sticker:  isFunction(dialog.messages.sticker) ? dialog.messages.sticker : DefaultSticker
      };
    } else {
      this.components = {
        Service: DefaultService,
        Text: DefaultText,
        Modern: DefaultModern,
        Photo: DefaultPhoto,
        Document: DefaultDocument,
        Voice: DefaultVoice,
        Contact: DefaultContact,
        Location: DefaultLocation,
        Sticker: DefaultSticker
      };
    }
  }

  shouldComponentUpdate(nextProps) {
    return this.props.message !== nextProps.message ||
           this.props.isShort !== nextProps.isShort;
  }

  onClick() {
    const { message, peer } = this.props;

    if (PeerUtils.equals(peer, message.sender.peer)) {
      ActivityActionCreators.show();
    } else {
      DialogActionCreators.selectDialogPeerUser(message.sender.peer.id);
    }
  }

  showActions = (event) => {
    const { message } = this.props;
    DropdownActionCreators.openMessageActions(event.target.getBoundingClientRect(), message);
  };

  toggleMessageSelection = () => {
    const { message, onSelect } = this.props;
    onSelect(message.rid);
  };

  renderTitle() {
    const { message, peer } = this.props;

    if (PeerUtils.isGroupBot(message.sender)) {
      const group = GroupStore.getGroup(peer.id);
      return (

      );
    } else {
      return (

      );
    }
  }

  renderHeader() {
    const { isShort, message, state } = this.props;

    if (isShort) {
      return null;
    }

    return (

            {this.renderTitle()}
            {
              message.sender.userName
                ? @{message.sender.userName}
                : null
            }

        <time className="message__timestamp">{message.date}</time>
        <State state={state} />

    );
  }

  renderLeftBlock() {
    const { isShort, message, state, peer } = this.props

    if (isShort) {
      return (

          <time className="message__timestamp">{message.date}</time>
          <State state={state} />

      );
    } else {
      if (PeerUtils.isGroupBot(message.sender)) {
        const group = GroupStore.getGroup(peer.id);
        return (

            <AvatarItem
              className="message__avatar"
              image={group.avatar}
              placeholder={group.placeholder}
              title={group.title}
              onClick={this.onClick}
            />

        )
      } else {
        return (

            <AvatarItem
              className="message__avatar"
              image={message.sender.avatar}
              placeholder={message.sender.placeholder}
              title={message.sender.title}
              onClick={this.onClick}
            />

        )
      }
    }
  }

  renderContent() {
    const { message } = this.props;
    if (this.props.isEditing) {
      return (
        <MessageEdit message={message} onSubmit={this.props.onEdit} />
      );
    }

    const { Service, Text, Photo, Document, Voice, Contact, Location, Modern, Sticker } = this.components;

    switch (message.content.content) {
      case MessageContentTypes.SERVICE:
        return (
          <Service
            {...message.content}
            className="message__content message__content--service"
          />
        );
      case MessageContentTypes.TEXT:
        return (
          <Text
            {...message.content}
            className="message__content message__content--text"
          />
        );
      case MessageContentTypes.PHOTO:
        return (
          <Photo
            {...message.content}
            className="message__content message__content--photo"
            loadedClassName="message__content--photo--loaded"
          />
        );
      case MessageContentTypes.DOCUMENT:
        return (
          <Document
            {...message.content}
            className="message__content message__content--document"
          />
        );
      case MessageContentTypes.VOICE:
        return (
          <Voice
            {...message.content}
            className="message__content message__content--voice"
          />
        );
      case MessageContentTypes.CONTACT:
        return (
          <Contact
            {...message.content}
            className="message__content message__content--contact"
          />
        );
      case MessageContentTypes.LOCATION:
        return (
          <Location
            {...message.content}
            className="message__content message__content--location"
          />
        );
      case MessageContentTypes.TEXT_MODERN:
        return (
          <Modern
            {...message.content}
            className="message__content message__content--modern"
          />
        );
      case MessageContentTypes.STICKER:
        return (
          <Sticker
            {...message.content}
            className="message__content message__content--sticker"
          />
        );
      default:
        return null;
    }
  }

  renderActions() {
    const { peer, message } = this.props;
    const { isHighlighted } = this.state;
    const { isExperimental } = this.context;

    const messageActionsMenuClassName = classnames('message__actions__menu', {
      'message__actions__menu--opened': isHighlighted
    });

    return (

        <Reactions peer={peer} message={message}/>

          <SvgIcon className="icon icon--dropdown" glyph="cog" />

        {
          isExperimental
            ?

            : null
        }

    );
  }

  render() {
    const { isShort, isSelected } = this.props;
    const { isHighlighted } = this.state;

    const messageClassName = classnames('message', {
      'message--short': isShort,
      'message--active': isHighlighted,
      'message--selected': isSelected
    });

    return (

        {this.renderLeftBlock()}

          {this.renderHeader()}
          {this.renderContent()}

        {this.renderActions()}

    );
  }
}

export default Container.create(MessageItem, { withProps: true });
<commit_msg>fix(web): fix group name sended to avatar item<commit_after>/*
 * Copyright (C) 2015-2016 Actor LLC. <https://actor.im>
 */

import { isFunction, noop } from 'lodash';
import React, { Component, PropTypes } from 'react';
import { Container } from 'flux/utils';
import classnames from 'classnames';
import { escapeWithEmoji } from '../../../utils/EmojiUtils';
import PeerUtils from '../../../utils/PeerUtils';
import { MessageContentTypes } from '../../../constants/ActorAppConstants';

import DialogActionCreators from '../../../actions/DialogActionCreators';
import ActivityActionCreators from '../../../actions/ActivityActionCreators';
import DropdownActionCreators from '../../../actions/DropdownActionCreators';

import DropdownStore from '../../../stores/DropdownStore';
import GroupStore from '../../../stores/GroupStore';

import SvgIcon from '../../common/SvgIcon.react';
import AvatarItem from '../../common/AvatarItem.react';
import State from './State.react';
import Reactions from './Reactions.react';
import MessageEdit from './MessageEdit.react';

// Default message content components
import DefaultService from './Service.react';
import DefaultText from './Text.react';
import DefaultPhoto from './Photo.react';
import DefaultDocument from './Document.react';
import DefaultVoice from './Voice.react';
import DefaultContact from './Contact.react';
import DefaultLocation from './Location.react';
import DefaultModern from './Modern.react';
import DefaultSticker from './Sticker.react';

class MessageItem extends Component {
  static contextTypes = {
    delegate: PropTypes.object,
    isExperimental: PropTypes.bool
  }

  static propTypes = {
    peer: PropTypes.object.isRequired,
    message: PropTypes.object.isRequired,
    state: PropTypes.string.isRequired,
    isShort: PropTypes.bool.isRequired,
    isEditing: PropTypes.bool.isRequired,
    onEdit: PropTypes.func.isRequired,
    isSelected: PropTypes.bool.isRequired,
    onSelect: PropTypes.func.isRequired
  }

  static defaultProps = {
    isSelected: false,
    onSelect: noop
  };

  static getStores() {
    return [DropdownStore];
  }

  static calculateState(prevState, props) {
    return {
      isHighlighted: props && props.message ? DropdownStore.isMessageDropdownOpen(props.message.rid) : false
    }
  }

  constructor(props, context) {
    super(props, context);

    this.onClick = this.onClick.bind(this);
  }

  componentWillMount() {
    const { dialog } = this.context.delegate.components;
    if (dialog && dialog.messages) {
      this.components = {
        Service: isFunction(dialog.messages.service) ? dialog.messages.service : DefaultService,
        Text: isFunction(dialog.messages.text) ? dialog.messages.text : DefaultText,
        Modern: isFunction(dialog.messages.modern) ? dialog.messages.modern : DefaultModern,
        Photo: isFunction(dialog.messages.photo) ? dialog.messages.photo : DefaultPhoto,
        Document: isFunction(dialog.messages.document) ? dialog.messages.document : DefaultDocument,
        Voice: isFunction(dialog.messages.voice) ? dialog.messages.voice : DefaultVoice,
        Contact: isFunction(dialog.messages.contact) ? dialog.messages.contact : DefaultContact,
        Location: isFunction(dialog.messages.location) ? dialog.messages.location : DefaultLocation,
        Sticker:  isFunction(dialog.messages.sticker) ? dialog.messages.sticker : DefaultSticker
      };
    } else {
      this.components = {
        Service: DefaultService,
        Text: DefaultText,
        Modern: DefaultModern,
        Photo: DefaultPhoto,
        Document: DefaultDocument,
        Voice: DefaultVoice,
        Contact: DefaultContact,
        Location: DefaultLocation,
        Sticker: DefaultSticker
      };
    }
  }

  shouldComponentUpdate(nextProps) {
    return this.props.message !== nextProps.message ||
           this.props.isShort !== nextProps.isShort;
  }

  onClick() {
    const { message, peer } = this.props;

    if (PeerUtils.equals(peer, message.sender.peer)) {
      ActivityActionCreators.show();
    } else {
      DialogActionCreators.selectDialogPeerUser(message.sender.peer.id);
    }
  }

  showActions = (event) => {
    const { message } = this.props;
    DropdownActionCreators.openMessageActions(event.target.getBoundingClientRect(), message);
  };

  toggleMessageSelection = () => {
    const { message, onSelect } = this.props;
    onSelect(message.rid);
  };

  renderTitle() {
    const { message, peer } = this.props;

    if (PeerUtils.isGroupBot(message.sender)) {
      const group = GroupStore.getGroup(peer.id);
      return (

      );
    } else {
      return (

      );
    }
  }

  renderHeader() {
    const { isShort, message, state } = this.props;

    if (isShort) {
      return null;
    }

    return (

            {this.renderTitle()}
            {
              message.sender.userName
                ? @{message.sender.userName}
                : null
            }

        <time className="message__timestamp">{message.date}</time>
        <State state={state} />

    );
  }

  renderLeftBlock() {
    const { isShort, message, state, peer } = this.props

    if (isShort) {
      return (

          <time className="message__timestamp">{message.date}</time>
          <State state={state} />

      );
    } else {
      if (PeerUtils.isGroupBot(message.sender)) {
        const group = GroupStore.getGroup(peer.id);
        return (

            <AvatarItem
              className="message__avatar"
              image={group.avatar}
              placeholder={group.placeholder}
              title={group.name}
              onClick={this.onClick}
            />

        )
      } else {
        return (

            <AvatarItem
              className="message__avatar"
              image={message.sender.avatar}
              placeholder={message.sender.placeholder}
              title={message.sender.title}
              onClick={this.onClick}
            />

        )
      }
    }
  }

  renderContent() {
    const { message } = this.props;
    if (this.props.isEditing) {
      return (
        <MessageEdit message={message} onSubmit={this.props.onEdit} />
      );
    }

    const { Service, Text, Photo, Document, Voice, Contact, Location, Modern, Sticker } = this.components;

    switch (message.content.content) {
      case MessageContentTypes.SERVICE:
        return (
          <Service
            {...message.content}
            className="message__content message__content--service"
          />
        );
      case MessageContentTypes.TEXT:
        return (
          <Text
            {...message.content}
            className="message__content message__content--text"
          />
        );
      case MessageContentTypes.PHOTO:
        return (
          <Photo
            {...message.content}
            className="message__content message__content--photo"
            loadedClassName="message__content--photo--loaded"
          />
        );
      case MessageContentTypes.DOCUMENT:
        return (
          <Document
            {...message.content}
            className="message__content message__content--document"
          />
        );
      case MessageContentTypes.VOICE:
        return (
          <Voice
            {...message.content}
            className="message__content message__content--voice"
          />
        );
      case MessageContentTypes.CONTACT:
        return (
          <Contact
            {...message.content}
            className="message__content message__content--contact"
          />
        );
      case MessageContentTypes.LOCATION:
        return (
          <Location
            {...message.content}
            className="message__content message__content--location"
          />
        );
      case MessageContentTypes.TEXT_MODERN:
        return (
          <Modern
            {...message.content}
            className="message__content message__content--modern"
          />
        );
      case MessageContentTypes.STICKER:
        return (
          <Sticker
            {...message.content}
            className="message__content message__content--sticker"
          />
        );
      default:
        return null;
    }
  }

  renderActions() {
    const { peer, message } = this.props;
    const { isHighlighted } = this.state;
    const { isExperimental } = this.context;

    const messageActionsMenuClassName = classnames('message__actions__menu', {
      'message__actions__menu--opened': isHighlighted
    });

    return (

        <Reactions peer={peer} message={message}/>

          <SvgIcon className="icon icon--dropdown" glyph="cog" />

        {
          isExperimental
            ?

            : null
        }

    );
  }

  render() {
    const { isShort, isSelected } = this.props;
    const { isHighlighted } = this.state;

    const messageClassName = classnames('message', {
      'message--short': isShort,
      'message--active': isHighlighted,
      'message--selected': isSelected
    });

    return (

        {this.renderLeftBlock()}

          {this.renderHeader()}
          {this.renderContent()}

        {this.renderActions()}

    );
  }
}

export default Container.create(MessageItem, { withProps: true });
<|endoftext|>


<commit_before>import isEqual from 'lodash.isequal';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import diffMentionState from '../utils/diffMentionState';
import last from '../utils/last';
import renderComponent from '../utils/renderComponent';
import EditorMention from '../components/EditorMention';

@connect(state => ({
  editor: state.mention.editor,
  mentions: state.mention.mentions
}))
export default class TinyMCEDelegate extends Component {

  static propTypes = {
    customRTEMention: PropTypes.func,
    editor: PropTypes.object,
    mentions: PropTypes.array,
    onAdd: PropTypes.func,
    onRemove: PropTypes.func
  }

  static defaultProps = {
    mentions: []
  }

  state = {
    shouldRender: false
  }

  shouldComponentUpdate(nextProps) {
    const nextEditorId = nextProps.editor && nextProps.editor.id;
    const editorId = this.props.editor && this.props.editor.id;

    return nextEditorId !== editorId
      || !isEqual(nextProps.mentions, this.props.mentions);
  }

  componentWillReceiveProps(nextProps) {
    const { mentions, onAdd, onRemove } = this.props;
    const nextMentions = nextProps.mentions;
    const currLength = mentions.length;
    const nextLength = nextMentions.length;
    const shouldAdd = currLength < nextLength;
    const shouldRemove = currLength > nextLength;

    if (shouldAdd && onAdd) {
      onAdd({
        mentions: nextMentions,
        changed: [last(nextMentions)]
      });
    }

    if (shouldRemove && onRemove) {
      onRemove(diffMentionState(mentions, nextMentions));
    }

    this.setState({
      shouldRender: shouldAdd
    });
  }

  componentDidUpdate() {
    const { shouldRender } = this.state;
    const { editor, mentions } = this.props;
    const mentionsValid = mentions && mentions.length;

    if (editor && mentionsValid && shouldRender) {
      this._renderMentionIntoEditor();
    }
  }

  _renderMentionIntoEditor() {
    const { customRTEMention, delimiter, editor, mentions } = this.props;
    const mention = last(mentions);
    const markup = customRTEMention
      ? customRTEMention({...mention, delimiter })
      : <EditorMention {...mention}
          delimiter={delimiter}
        />;

    editor.insertContent('____PLACEHOLDER____');

    const bm = editor.selection.getBookmark(2, false);
    const re = new RegExp(delimiter + '\\w+____PLACEHOLDER____');

    editor.setContent(
      editor
        .getContent()
        .replace(re, renderComponent(markup)));

    setTimeout(() => {
      editor.getBody().focus();
      editor.selection.moveToBookmark(bm);
    });
  }

  render() {
    return null;
  }
}
<commit_msg>replace built-in bookmark with temporary span instead<commit_after>import isEqual from 'lodash.isequal';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import diffMentionState from '../utils/diffMentionState';
import last from '../utils/last';
import renderComponent from '../utils/renderComponent';
import EditorMention from '../components/EditorMention';

@connect(state => ({
  editor: state.mention.editor,
  mentions: state.mention.mentions
}))
export default class TinyMCEDelegate extends Component {

  static propTypes = {
    customRTEMention: PropTypes.func,
    editor: PropTypes.object,
    mentions: PropTypes.array,
    onAdd: PropTypes.func,
    onRemove: PropTypes.func
  }

  static defaultProps = {
    mentions: []
  }

  state = {
    shouldRender: false
  }

  shouldComponentUpdate(nextProps) {
    const nextEditorId = nextProps.editor && nextProps.editor.id;
    const editorId = this.props.editor && this.props.editor.id;

    return nextEditorId !== editorId
      || !isEqual(nextProps.mentions, this.props.mentions);
  }

  componentWillReceiveProps(nextProps) {
    const { mentions, onAdd, onRemove } = this.props;
    const nextMentions = nextProps.mentions;
    const currLength = mentions.length;
    const nextLength = nextMentions.length;
    const shouldAdd = currLength < nextLength;
    const shouldRemove = currLength > nextLength;

    if (shouldAdd && onAdd) {
      onAdd({
        mentions: nextMentions,
        changed: [last(nextMentions)]
      });
    }

    if (shouldRemove && onRemove) {
      onRemove(diffMentionState(mentions, nextMentions));
    }

    this.setState({
      shouldRender: shouldAdd
    });
  }

  componentDidUpdate() {
    const { shouldRender } = this.state;
    const { editor, mentions } = this.props;
    const mentionsValid = mentions && mentions.length;

    if (editor && mentionsValid && shouldRender) {
      this._renderMentionIntoEditor();
    }
  }

  _renderMentionIntoEditor() {
    const { customRTEMention, delimiter, editor, mentions } = this.props;
    const mention = last(mentions);
    const markup = customRTEMention
      ? customRTEMention({...mention, delimiter })
      : <EditorMention {...mention}
          delimiter={delimiter}
        />;

    editor.insertContent('insertionplaceholder');

    editor.setContent(
      editor
        .getContent()
        .replace(re, renderComponent(markup)));

    setTimeout(() => {
      editor.getBody().focus();
      editor.selection.select(editor.dom.select('#cursor')[0]);
      editor.selection.collapse(true);
      editor.dom.remove(editor.dom.select('#cursor')[0]);
    });
  }

  render() {
    return null;
  }
}
<|endoftext|>


<commit_before>import EventEmitter from 'sk/core/EventEmitter'
import Game from 'sk/Game'

const DEFAULT_LAYER = '~default'

/**
 * Scenes are the base containers for your games, and represent the independent
 * parts of the game, like a menu, score screen, or the level itself.
 *
 * Every scene uses stacked layers to help you organize the entities in the
 * screen. The layers are containers and can be declared in the {@link scene}
 * function. The use of layers is totally optional and may be completely
 * ignored if you want.
 *
 * Systems are used to process the scene entities and update the game logic,
 * while event sheets helps you to organize the game logic by providing a
 * direct interface to the scene events. You may add multiple event sheets in
 * the scene and also share the same sheet with other scenes.
 */
export default class Scene extends EventEmitter {

  constructor(game, layers, systems, eventSheets) {
    super()

    // Inserted by the `sk.scene` function:
    // - _$name
    // - _$layers
    // - _$systems
    // - _$eventSheets
    // - _$data
    // - _$methods
    // - _$attributes

    this._game = game
    this._world = new PIXI.Container()
    this._entities = []
    this._layers = {}
    this._systems = systems
    this._eventSheets = eventSheets

    // Create the list of entities for each system
    this._mapSystemToEntities = {}
    for (let i=0; i<this._$systems.length; i++) {
      this._mapSystemToEntities[this._$systems[i]] = []
    }

    // Create the layers
    this._layers[DEFAULT_LAYER] = new PIXI.Container()
    this._world.addChild(this._layers[DEFAULT_LAYER])
    for (let k in this._$layers) {
      this._layers[k] = new PIXI.Container()
      this._world.addChild(this._layers[k])
    }
    this._layers = Object.freeze(this._layers)

    // Other internal values
    this._tweens = []
    this._jobs = []

    // This is the only exception in the engine of calling `initialize` on the
    // constructor. We don't call it here due to circular reference to the
    // systems and event sheets. The create manager will call the initialize
    // during the creation of the object.
  }

  /**
   * The scene name. Readonly.
   * @type {String}
   */
  get name() { return this._name }

  /**
   * The game instance. Readonly.
   * @type {Game}
   */
  get game() { return this._game }

  /**
   * The scene general container. Readonly.
   * @type {PIXI.Container}
   */
  get world() { return this._world }

  /**
   * The scene layer objects. Readonly.
   * @type {Object}
   */
  get layers() { return this._layers }

  /**
   * The scene system objects. Readonly.
   * @type {Object}
   */
  get systems() { return this._systems }

  /**
   * The scene event sheets objects. Readonly.
   * @type {Object}
   */
  get eventSheets() { return this._eventSheets }

  /**
   * Initialize function.
   */
  initialize() {}

  /**
   * Enter function, called when the scene enters the canvas.
   */
  enter() {}

  /**
   * Start function, called when the transition ends and the scene starts
   * working.
   */
  start() {}

  /**
   * Pause function, called when the engine is paused (e.g, when the game loses
   * focus or when its paused manually).
   */
  pause() {}

  /**
   * Resume function, called when the engine resumes after a pause.
   */
  resume() {}

  /**
   * Called every tick the scene is running.
   */
  update(delta) {}

  /**
   * Stop function, called when the scene starts a transition to leave the
   * canvas.
   */
  stop() {}

  /**
   * Called when the scene leaves the canvas.
   */
  leave() {}

  /**
   * Called when the scene is destroyed.
   */
  destroy() {}

  /**
   * Adds an entity to the scene.
   *
   * @param {String} entityName - The entity ID.
   * @param {String} layerName - The layer name.
   */
  addEntity(entity, layerName) {
    // Uses default layer if layer is not provided
    layerName = layerName||DEFAULT_LAYER

    // Creates the entity
    if (typeof entity === 'string') {
      entity = this.game.create.entity(entity)
    }

    // Validate layer name
    let layer = this._layers[layerName]
    if (!layer) {
      throw new Error(`Invalid layer "${layerName}".`)
    }

    // Add entity to the system-entity map
    for (let key in this._systems) {
      if (this._systems[key].check(entity)) {
        this._mapSystemToEntities[key].push(entity)
      }
    }

    // Add layer info to the entity
    entity._$layer = layerName

    // Add entity to the layer
    layer.addChild(entity.display)

    // Add entity to the general list
    this._entities.push(entity)

    // Return the entity
    return entity
  }

  /**
   * Removes an entity from the scene.
   *
   * @param {Entity} entity - The entity object.
   */
  removeEntity(entity) {
    let layer = this._layers[entity._$layer]
    layer.removeChild(entity.display)
    this._entities.splice(this._entities.indexOf(entity))

    for (let key in this._systems) {
      if (this._systems[key].check(entity)) {
        let list = this._mapSystemToEntities[key]
        list.splice(list.indexOf(entity))
      }
    }
  }

  /**
   * Adds a static display object to the scene.
   *
   * @param {PIXI.DisplayObject} displayObject - The display object.
   * @param {String} [layerName] - The layer.
   * @return {PIXI.DisplayObject} The input display object.
   */
  addStatic(displayObject, layerName) {
    // Uses default layer if layer is not provided
    layerName = layerName||DEFAULT_LAYER

    // Create the display object if needed
    if (typeof displayObject === 'string') {
      displayObject = this.game.create.displayObject(displayObject)
    }

    // Validate layer name
    let layer = this._layers[layerName]
    if (!layer) {
      throw new Error(`Invalid layer "${layerName}".`)
    }

    console.log(displayObject, layer)
    // Add layer info to the entity
    displayObject._$layer = layerName

    // Add entity to the layer
    layer.addChild(displayObject)

    // Return the entity
    return displayObject
  }

  /**
   * Removes a static texture
   */
  removeStatic(displayObject) {
    let layer = this._layers[displayObject._$layer]
    layer.removeChild(displayObject)
  }

  /**
   * Adds a tween to the scene.
   *
   * The scene will control the update and completition of the tweens.
   *
   * @param {Tween} tween - The tween object.
   * @param {Boolean} override - If true, it will remove all tween registered
   *        on the same object. Defaults to false.
   */
  addTween(tween, override=false) {
    if (!tween) throw new Error(`Trying to add an invalid tween.`)

    // Reset the tween
    tween.reset()

    // Shortcut for the target
    let target = tween.target

    // Creates the tween ist at the target
    if (!target._$tweens) {
      target._$tweens = []
    }

    // Remove the tweens from the target if override is true
    if (override) {
      for (let i=0; i<target._$tweens.length; i++) {
        let t = target._$tweens[i]
        t.stop()
        this._tweens.splice(this._tweens.indexOf(t), 1)
      }
      target._$tweens = []
    }

    // Add the tween to the scene and target
    this._tweens.push(tween)
    tween.target._$tweens.push(tween)
  }

  /**
   * Removes a tween from this scene (and the object).
   *
   * @param {Tween} tween - The tween object.
   */
  removeTween(tween) {
    if (!tween) throw new Error(`Trying to remove an invalid tween.`)

    // Stops the tween
    tween.stop()

    // Shortcut for the target
    let target = tween.target

    // Removes the tween from the target
    if (target._$tweens) {
      target._$tweens.splice(target._$tweens.indexOf(tween), 1)
    }

    // Removes the tween from the scene
    this._tweens.splice(this._tweens.indexOf(tween), 1)
  }

  /**
   * Same as update, but for internal uses.
   */
  _update(delta) {
    for (let k in this.systems) {
      this.systems[k].update(delta, this._mapSystemToEntities[k])
    }

    for (let i=this._tweens.length-1; i>=0; i--) {
      let t = this._tweens[i]
      t.update(delta)

      if (t.hasFinished()) {
        this._tweens.splice(i, 0)
      }
    }
  }
}<commit_msg>Removing console.log<commit_after>import EventEmitter from 'sk/core/EventEmitter'
import Game from 'sk/Game'

const DEFAULT_LAYER = '~default'

/**
 * Scenes are the base containers for your games, and represent the independent
 * parts of the game, like a menu, score screen, or the level itself.
 *
 * Every scene uses stacked layers to help you organize the entities in the
 * screen. The layers are containers and can be declared in the {@link scene}
 * function. The use of layers is totally optional and may be completely
 * ignored if you want.
 *
 * Systems are used to process the scene entities and update the game logic,
 * while event sheets helps you to organize the game logic by providing a
 * direct interface to the scene events. You may add multiple event sheets in
 * the scene and also share the same sheet with other scenes.
 */
export default class Scene extends EventEmitter {

  constructor(game, layers, systems, eventSheets) {
    super()

    // Inserted by the `sk.scene` function:
    // - _$name
    // - _$layers
    // - _$systems
    // - _$eventSheets
    // - _$data
    // - _$methods
    // - _$attributes

    this._game = game
    this._world = new PIXI.Container()
    this._entities = []
    this._layers = {}
    this._systems = systems
    this._eventSheets = eventSheets

    // Create the list of entities for each system
    this._mapSystemToEntities = {}
    for (let i=0; i<this._$systems.length; i++) {
      this._mapSystemToEntities[this._$systems[i]] = []
    }

    // Create the layers
    this._layers[DEFAULT_LAYER] = new PIXI.Container()
    this._world.addChild(this._layers[DEFAULT_LAYER])
    for (let k in this._$layers) {
      this._layers[k] = new PIXI.Container()
      this._world.addChild(this._layers[k])
    }
    this._layers = Object.freeze(this._layers)

    // Other internal values
    this._tweens = []
    this._jobs = []

    // This is the only exception in the engine of calling `initialize` on the
    // constructor. We don't call it here due to circular reference to the
    // systems and event sheets. The create manager will call the initialize
    // during the creation of the object.
  }

  /**
   * The scene name. Readonly.
   * @type {String}
   */
  get name() { return this._name }

  /**
   * The game instance. Readonly.
   * @type {Game}
   */
  get game() { return this._game }

  /**
   * The scene general container. Readonly.
   * @type {PIXI.Container}
   */
  get world() { return this._world }

  /**
   * The scene layer objects. Readonly.
   * @type {Object}
   */
  get layers() { return this._layers }

  /**
   * The scene system objects. Readonly.
   * @type {Object}
   */
  get systems() { return this._systems }

  /**
   * The scene event sheets objects. Readonly.
   * @type {Object}
   */
  get eventSheets() { return this._eventSheets }

  /**
   * Initialize function.
   */
  initialize() {}

  /**
   * Enter function, called when the scene enters the canvas.
   */
  enter() {}

  /**
   * Start function, called when the transition ends and the scene starts
   * working.
   */
  start() {}

  /**
   * Pause function, called when the engine is paused (e.g, when the game loses
   * focus or when its paused manually).
   */
  pause() {}

  /**
   * Resume function, called when the engine resumes after a pause.
   */
  resume() {}

  /**
   * Called every tick the scene is running.
   */
  update(delta) {}

  /**
   * Stop function, called when the scene starts a transition to leave the
   * canvas.
   */
  stop() {}

  /**
   * Called when the scene leaves the canvas.
   */
  leave() {}

  /**
   * Called when the scene is destroyed.
   */
  destroy() {}

  /**
   * Adds an entity to the scene.
   *
   * @param {String} entityName - The entity ID.
   * @param {String} layerName - The layer name.
   */
  addEntity(entity, layerName) {
    // Uses default layer if layer is not provided
    layerName = layerName||DEFAULT_LAYER

    // Creates the entity
    if (typeof entity === 'string') {
      entity = this.game.create.entity(entity)
    }

    // Validate layer name
    let layer = this._layers[layerName]
    if (!layer) {
      throw new Error(`Invalid layer "${layerName}".`)
    }

    // Add entity to the system-entity map
    for (let key in this._systems) {
      if (this._systems[key].check(entity)) {
        this._mapSystemToEntities[key].push(entity)
      }
    }

    // Add layer info to the entity
    entity._$layer = layerName

    // Add entity to the layer
    layer.addChild(entity.display)

    // Add entity to the general list
    this._entities.push(entity)

    // Return the entity
    return entity
  }

  /**
   * Removes an entity from the scene.
   *
   * @param {Entity} entity - The entity object.
   */
  removeEntity(entity) {
    let layer = this._layers[entity._$layer]
    layer.removeChild(entity.display)
    this._entities.splice(this._entities.indexOf(entity))

    for (let key in this._systems) {
      if (this._systems[key].check(entity)) {
        let list = this._mapSystemToEntities[key]
        list.splice(list.indexOf(entity))
      }
    }
  }

  /**
   * Adds a static display object to the scene.
   *
   * @param {PIXI.DisplayObject} displayObject - The display object.
   * @param {String} [layerName] - The layer.
   * @return {PIXI.DisplayObject} The input display object.
   */
  addStatic(displayObject, layerName) {
    // Uses default layer if layer is not provided
    layerName = layerName||DEFAULT_LAYER

    // Create the display object if needed
    if (typeof displayObject === 'string') {
      displayObject = this.game.create.displayObject(displayObject)
    }

    // Validate layer name
    let layer = this._layers[layerName]
    if (!layer) {
      throw new Error(`Invalid layer "${layerName}".`)
    }

    // Add layer info to the entity
    displayObject._$layer = layerName

    // Add entity to the layer
    layer.addChild(displayObject)

    // Return the entity
    return displayObject
  }

  /**
   * Removes a static texture
   */
  removeStatic(displayObject) {
    let layer = this._layers[displayObject._$layer]
    layer.removeChild(displayObject)
  }

  /**
   * Adds a tween to the scene.
   *
   * The scene will control the update and completition of the tweens.
   *
   * @param {Tween} tween - The tween object.
   * @param {Boolean} override - If true, it will remove all tween registered
   *        on the same object. Defaults to false.
   */
  addTween(tween, override=false) {
    if (!tween) throw new Error(`Trying to add an invalid tween.`)

    // Reset the tween
    tween.reset()

    // Shortcut for the target
    let target = tween.target

    // Creates the tween ist at the target
    if (!target._$tweens) {
      target._$tweens = []
    }

    // Remove the tweens from the target if override is true
    if (override) {
      for (let i=0; i<target._$tweens.length; i++) {
        let t = target._$tweens[i]
        t.stop()
        this._tweens.splice(this._tweens.indexOf(t), 1)
      }
      target._$tweens = []
    }

    // Add the tween to the scene and target
    this._tweens.push(tween)
    tween.target._$tweens.push(tween)
  }

  /**
   * Removes a tween from this scene (and the object).
   *
   * @param {Tween} tween - The tween object.
   */
  removeTween(tween) {
    if (!tween) throw new Error(`Trying to remove an invalid tween.`)

    // Stops the tween
    tween.stop()

    // Shortcut for the target
    let target = tween.target

    // Removes the tween from the target
    if (target._$tweens) {
      target._$tweens.splice(target._$tweens.indexOf(tween), 1)
    }

    // Removes the tween from the scene
    this._tweens.splice(this._tweens.indexOf(tween), 1)
  }

  /**
   * Same as update, but for internal uses.
   */
  _update(delta) {
    for (let k in this.systems) {
      this.systems[k].update(delta, this._mapSystemToEntities[k])
    }

    for (let i=this._tweens.length-1; i>=0; i--) {
      let t = this._tweens[i]
      t.update(delta)

      if (t.hasFinished()) {
        this._tweens.splice(i, 0)
      }
    }
  }
}<|endoftext|>


<commit_before>'use strict';

import {S3FSDriver} from '../../lib/Driver/S3FSDriver';
import FSMock from './FSMock';

export class S3FSDriverMock extends S3FSDriver {

  /**
   * Returns mock of s3fs
   * @returns {s3fs}
   * @private
   */
  get _fs() {
    return FSMock();
  }
}
<commit_msg>Fix hound issue<commit_after>'use strict';

import {S3FSDriver} from '../../lib/Driver/S3FSDriver';
import FSMock from './FSMock';

export class S3FSDriverMock extends S3FSDriver {

  /**
   * Returns mock of s3fs
   * @returns {s3fs}
   * @private
   */
  get _fs() {
    return new FSMock();
  }
}
<|endoftext|>


<commit_before>var _ = require('./utils');

/**
 * A module of methods related to listening. This module is consumed by `createStore`,
 * `listenerMixin` and the `listenTo` mixin factory.
 */
module.exports = {

    /**
     * An internal utility function used by `validateListening`
     *
     * @param {Action|Store} listenable The listenable we want to search for
     * @returns {Boolean} The result of a recursive search among `this.subscriptions`
     */
    hasListener: function(listenable) {
        var i = 0,
            listener;
        for (;i < (this.subscriptions||[]).length; ++i) {
            listener = this.subscriptions[i].listenable;
            if (listener === listenable || listener.hasListener && listener.hasListener(listenable)) {
                return true;
            }
        }
        return false;
    },

    /**
     * A convenience method that listens to all listenables in the given object.
     *
     * @param {Object} listenables An object of listenables. Keys will be used as callback method names.
     */
    listenToMany: function(listenables){
        for(var key in listenables){
            var cbname = _.callbackName(key),
                localname = this[cbname] ? cbname : this[key] ? key : undefined;
            if (localname){
                this.listenTo(listenables[key],localname,this[cbname+"Default"]||this[localname+"Default"]||localname);
            }
        }
    },

    /**
     * Checks if the current context can listen to the supplied listenable
     *
     * @param {Action|Store} listenable An Action or Store that should be
     *  listened to.
     * @returns {String|Undefined} An error message, or undefined if there was no problem.
     */
    validateListening: function(listenable){
    	if (listenable === this) {
            return "Listener is not able to listen to itself";
        }
        if (!_.isFunction(listenable.listen)) {
            return listenable + " is missing a listen method";
        }
        if (this.hasListener(listenable)) {
            return "Listener cannot listen to this listenable because of circular loop";
        }
    },

    /**
     * Sets up a subscription to the given listenable for the context object
     *
     * @param {Action|Store} listenable An Action or Store that should be
     *  listened to.
     * @param {Function|String} callback The callback to register as event handler
     * @param {Function|String} defaultCallback The callback to register as default handler
     * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is the object being listened to
     */
    listenTo: function(listenable, callback, defaultCallback) {
    	var err = this.validateListening(listenable),
            self = this;
    	if (err){
    		throw Error(err);
    	}
        this.fetchDefaultData(listenable, defaultCallback);
        if (!this.subscriptions) { this.subscriptions = [];}
        var desub = listenable.listen(this[callback]||callback, this),
            unsubscriber = function (dontupdatearr) {
                desub();
                if (!dontupdatearr) {
                    self.subscriptions.splice(self.subscriptions.indexOf(listenable), 1);
                }
            },
            subscriptionobj = {
                stop: unsubscriber,
                listenable: listenable
            };
        this.subscriptions.push(subscriptionobj);
        return subscriptionobj;
    },

    /**
     * Stops listening to a single listenable
     *
     * @param {Action|Store} listenable The action or store we no longer want to listen to
     * @param {Boolean} dontupdatearr If true, we don't remove the subscription object from this.subscriptions
     * @returns {Boolean} True if a subscription was found and removed, otherwise false.
     */
    stopListeningTo: function(listenable,dontupdatearr){
        for(var i=0; i<(this.subscriptions||[]).length;i++){
            if (this.subscriptions[i].listenable === listenable){
                this.subscriptions[i].stop(dontupdatearr);
                return true;
            }
        }
        return false;
    },

    /**
     * Stops all subscriptions and empties subscriptions array
     *
     */
    stopListeningToAll: function(){
        (this.subscriptions||[]).forEach(function(subscription) {
            subscription.stop(true);
        });
        this.subscriptions = [];
    },

    /**
     * Used in `listenTo`. Fetches initial data from a publisher if it has a `getDefaultData` method.
     * @param {Action|Store} listenable The publisher we want to get default data from
     * @param {Function|String} defaultCallback The method to receive the data
     */
    fetchDefaultData: function (listenable, defaultCallback) {
        defaultCallback = (defaultCallback && this[defaultCallback]) || defaultCallback;
        var me = this;
        if (defaultCallback && _.isFunction(defaultCallback)) {
            if (listenable.getDefaultData && _.isFunction(listenable.getDefaultData)) {
                data = listenable.getDefaultData();
                if (data && data.then && _.isFunction(data.then)) {
                    data.then(function() {
                        defaultCallback.apply(me, arguments);
                    });
                } else {
                    defaultCallback.call(this, data);
                }
            }
        }
    }
}

<commit_msg>flattened fetchDefaultData, added semicolon<commit_after>var _ = require('./utils');

/**
 * A module of methods related to listening. This module is consumed by `createStore`,
 * `listenerMixin` and the `listenTo` mixin factory.
 */
module.exports = {

    /**
     * An internal utility function used by `validateListening`
     *
     * @param {Action|Store} listenable The listenable we want to search for
     * @returns {Boolean} The result of a recursive search among `this.subscriptions`
     */
    hasListener: function(listenable) {
        var i = 0,
            listener;
        for (;i < (this.subscriptions||[]).length; ++i) {
            listener = this.subscriptions[i].listenable;
            if (listener === listenable || listener.hasListener && listener.hasListener(listenable)) {
                return true;
            }
        }
        return false;
    },

    /**
     * A convenience method that listens to all listenables in the given object.
     *
     * @param {Object} listenables An object of listenables. Keys will be used as callback method names.
     */
    listenToMany: function(listenables){
        for(var key in listenables){
            var cbname = _.callbackName(key),
                localname = this[cbname] ? cbname : this[key] ? key : undefined;
            if (localname){
                this.listenTo(listenables[key],localname,this[cbname+"Default"]||this[localname+"Default"]||localname);
            }
        }
    },

    /**
     * Checks if the current context can listen to the supplied listenable
     *
     * @param {Action|Store} listenable An Action or Store that should be
     *  listened to.
     * @returns {String|Undefined} An error message, or undefined if there was no problem.
     */
    validateListening: function(listenable){
    	if (listenable === this) {
            return "Listener is not able to listen to itself";
        }
        if (!_.isFunction(listenable.listen)) {
            return listenable + " is missing a listen method";
        }
        if (this.hasListener(listenable)) {
            return "Listener cannot listen to this listenable because of circular loop";
        }
    },

    /**
     * Sets up a subscription to the given listenable for the context object
     *
     * @param {Action|Store} listenable An Action or Store that should be
     *  listened to.
     * @param {Function|String} callback The callback to register as event handler
     * @param {Function|String} defaultCallback The callback to register as default handler
     * @returns {Object} A subscription obj where `stop` is an unsub function and `listenable` is the object being listened to
     */
    listenTo: function(listenable, callback, defaultCallback) {
    	var err = this.validateListening(listenable),
            self = this;
    	if (err){
    		throw Error(err);
    	}
        this.fetchDefaultData(listenable, defaultCallback);
        if (!this.subscriptions) { this.subscriptions = [];}
        var desub = listenable.listen(this[callback]||callback, this),
            unsubscriber = function (dontupdatearr) {
                desub();
                if (!dontupdatearr) {
                    self.subscriptions.splice(self.subscriptions.indexOf(listenable), 1);
                }
            },
            subscriptionobj = {
                stop: unsubscriber,
                listenable: listenable
            };
        this.subscriptions.push(subscriptionobj);
        return subscriptionobj;
    },

    /**
     * Stops listening to a single listenable
     *
     * @param {Action|Store} listenable The action or store we no longer want to listen to
     * @param {Boolean} dontupdatearr If true, we don't remove the subscription object from this.subscriptions
     * @returns {Boolean} True if a subscription was found and removed, otherwise false.
     */
    stopListeningTo: function(listenable,dontupdatearr){
        for(var i=0; i<(this.subscriptions||[]).length;i++){
            if (this.subscriptions[i].listenable === listenable){
                this.subscriptions[i].stop(dontupdatearr);
                return true;
            }
        }
        return false;
    },

    /**
     * Stops all subscriptions and empties subscriptions array
     *
     */
    stopListeningToAll: function(){
        (this.subscriptions||[]).forEach(function(subscription) {
            subscription.stop(true);
        });
        this.subscriptions = [];
    },

    /**
     * Used in `listenTo`. Fetches initial data from a publisher if it has a `getDefaultData` method.
     * @param {Action|Store} listenable The publisher we want to get default data from
     * @param {Function|String} defaultCallback The method to receive the data
     */
    fetchDefaultData: function (listenable, defaultCallback) {
        defaultCallback = (defaultCallback && this[defaultCallback]) || defaultCallback;
        var me = this;
        if (_.isFunction(defaultCallback) && _.isFunction(listenable.getDefaultData)) {
            data = listenable.getDefaultData();
            if (data && _.isFunction(data.then)) {
                data.then(function() {
                    defaultCallback.apply(me, arguments);
                });
            } else {
                defaultCallback.call(this, data);
            }
        }
    }
};

<|endoftext|>