<commit_before>import Controller from '@ember/controller';
import {action} from '@ember/object';
import {getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking';

export default class DashboardController extends Controller {
    @service feature;
    @service session;
    @service membersStats;
    @service store;
    @service settings;
    @service whatsNew;

    @tracked
    eventsData = null;
    @tracked
    eventsError = null;
    @tracked
    eventsLoading = false;

    @tracked
    mrrStatsData = null;
    @tracked
    mrrStatsError = null;
    @tracked
    mrrStatsLoading = false;

    @tracked
    memberCountStatsData = null;
    @tracked
    memberCountStatsError = null;
    @tracked
    memberCountStatsLoading = false;

    @tracked
    topMembersData = null;
    @tracked
    topMembersError = null;
    @tracked
    topMembersLoading = false;

    @tracked
    newsletterOpenRatesData = null;
    @tracked
    newsletterOpenRatesError = null;
    @tracked
    newsletterOpenRatesLoading = false;

    @tracked
    whatsNewEntries = null;
    @tracked
    whatsNewEntriesLoading = null;
    @tracked
    whatsNewEntriesError = null;

    get topMembersDataHasOpenRates() {
        return this.topMembersData && this.topMembersData.find((member) => {
            return member.emailOpenRate !== null;
        });
    }

    initialise() {
        this.loadEvents();
        this.loadTopMembers();
        this.loadCharts();
        this.loadWhatsNew();
    }

    loadMRRStats() {
        this.mrrStatsLoading = true;
        this.membersStats.fetchMRR().then((stats) => {
            this.mrrStatsLoading = false;
            const statsData = stats.data || [];
            const defaultCurrency = this.getDefaultCurrency() || 'usd';
            let currencyStats = statsData.find((stat) => {
                return stat.currency === defaultCurrency;
            });
            currencyStats = currencyStats || {
                data: [],
                currency: defaultCurrency
            };
            if (currencyStats) {
                const currencyStatsData = this.membersStats.fillDates(currencyStats.data) || {};
                const dateValues = Object.values(currencyStatsData).map(val => val / 100);
                const currentMRR = dateValues.length ? dateValues[dateValues.length - 1] : 0;
                const rangeStartMRR = dateValues.length ? dateValues[0] : 0;
                const percentGrowth = rangeStartMRR !== 0 ? ((currentMRR - rangeStartMRR) / rangeStartMRR) * 100 : 0;
                this.mrrStatsData = {
                    currentAmount: currentMRR,
                    currency: getSymbol(currencyStats.currency),
                    percentGrowth: percentGrowth.toFixed(1),
                    percentClass: (percentGrowth > 0 ? 'positive' : (percentGrowth < 0 ? 'negative' : '')),
                    options: {
                        rangeInDays: 30
                    },
                    data: {
                        label: 'MRR',
                        dateLabels: Object.keys(currencyStatsData),
                        dateValues
                    },
                    title: 'MRR',
                    stats: currencyStats
                };
            }
        }, (error) => {
            this.mrrStatsError = error;
            this.mrrStatsLoading = false;
        });
    }

    loadMemberCountStats() {
        this.memberCountStatsLoading = true;
        this.membersStats.fetchCounts().then((stats) => {
            this.memberCountStatsLoading = false;

            if (stats) {
                const statsDateObj = this.membersStats.fillCountDates(stats.data) || {};
                const dateValues = Object.values(statsDateObj);
                const currentAllCount = dateValues.length ? dateValues[dateValues.length - 1].total : 0;
                const currentPaidCount = dateValues.length ? dateValues[dateValues.length - 1].paid : 0;
                const rangeStartAllCount = dateValues.length ? dateValues[0].total : 0;
                const rangeStartPaidCount = dateValues.length ? dateValues[0].paid : 0;
                const allCountPercentGrowth = rangeStartAllCount !== 0 ? ((currentAllCount - rangeStartAllCount) / rangeStartAllCount) * 100 : 0;
                const paidCountPercentGrowth = rangeStartPaidCount !== 0 ? ((currentPaidCount - rangeStartPaidCount) / rangeStartPaidCount) * 100 : 0;

                this.memberCountStatsData = {
                    all: {
                        percentGrowth: allCountPercentGrowth.toFixed(1),
                        percentClass: (allCountPercentGrowth > 0 ? 'positive' : (allCountPercentGrowth < 0 ? 'negative' : '')),
                        total: dateValues.length ? dateValues[dateValues.length - 1].total : 0,
                        options: {
                            rangeInDays: 30
                        },
                        data: {
                            label: 'Members',
                            dateLabels: Object.keys(statsDateObj),
                            dateValues: dateValues.map(d => d.total)
                        },
                        title: 'Total Members',
                        stats: stats
                    },
                    paid: {
                        percentGrowth: paidCountPercentGrowth.toFixed(1),
                        percentClass: (paidCountPercentGrowth > 0 ? 'positive' : (paidCountPercentGrowth < 0 ? 'negative' : '')),
                        total: dateValues.length ? dateValues[dateValues.length - 1].paid : 0,
                        options: {
                            rangeInDays: 30
                        },
                        data: {
                            label: 'Members',
                            dateLabels: Object.keys(statsDateObj),
                            dateValues: dateValues.map(d => d.paid)
                        },
                        title: 'Paid Members',
                        stats: stats
                    }
                };
            }
        }, (error) => {
            this.memberCountStatsError = error;
            this.memberCountStatsLoading = false;
        });
    }

    loadCharts() {
        this.loadMRRStats();
        this.loadMemberCountStats();
        this.loadNewsletterOpenRates();
    }

    loadEvents() {
        this.eventsLoading = true;
        this.membersStats.fetchTimeline({limit: 5}).then(({events}) => {
            this.eventsData = events;
            this.eventsLoading = false;
        }, (error) => {
            this.eventsError = error;
            this.eventsLoading = false;
        });
    }

    loadNewsletterOpenRates() {
        this.newsletterOpenRatesLoading = true;
        this.membersStats.fetchNewsletterStats().then((results) => {
            const rangeStartOpenRate = results.length > 1 ? results[results.length - 2].openRate : 0;
            const rangeEndOpenRate = results.length > 0 ? results[results.length - 1].openRate : 0;
            const percentGrowth = rangeStartOpenRate !== 0 ? ((rangeEndOpenRate - rangeStartOpenRate) / rangeStartOpenRate) * 100 : 0;
            this.newsletterOpenRatesData = {
                percentGrowth: percentGrowth.toFixed(1),
                percentClass: (percentGrowth > 0 ? 'positive' : (percentGrowth < 0 ? 'negative' : '')),
                current: rangeEndOpenRate,
                options: {
                    rangeInDays: 30
                },
                data: {
                    label: 'Open rate',
                    dateLabels: results.map(d => d.subject),
                    dateValues: results.map(d => d.openRate)
                },
                title: 'Open rate',
                stats: results
            };
            this.newsletterOpenRatesLoading = false;
        }, (error) => {
            this.newsletterOpenRatesError = error;
            this.newsletterOpenRatesLoading = false;
        });
    }

    loadTopMembers() {
        this.topMembersLoading = true;
        let query = {
            filter: 'email_open_rate:-null',
            order: 'email_open_rate desc',
            limit: 5
        };
        this.store.query('member', query).then((result) => {
            if (!result.length) {
                return this.store.query('member', {
                    filter: 'status:paid',
                    order: 'created_at asc',
                    limit: 5
                });
            }
            return result;
        }).then((result) => {
            this.topMembersData = result;
            this.topMembersLoading = false;
        }).catch((error) => {
            this.topMembersError = error;
            this.topMembersLoading = false;
        });
    }

    loadWhatsNew() {
        this.whatsNewEntriesLoading = true;
        this.whatsNew.fetchLatest.perform().then(() => {
            this.whatsNewEntriesLoading = false;
            this.whatsNewEntries = this.whatsNew.entries.slice(0, 3);
        }, (error) => {
            this.whatsNewEntriesError = error;
            this.whatsNewEntriesLoading = false;
        });
    }

    getDefaultCurrency() {
        const plans = this.settings.get('stripePlans') || [];
        const monthly = plans.find(plan => plan.interval === 'month');
        return monthly && monthly.currency;
    }

    @action
    dismissLaunchBanner() {
        this.feature.set('launchComplete', true);
    }
}
<commit_msg>Updated MRR display value on dashboard<commit_after>import Controller from '@ember/controller';
import {action} from '@ember/object';
import {getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking';

export default class DashboardController extends Controller {
    @service feature;
    @service session;
    @service membersStats;
    @service store;
    @service settings;
    @service whatsNew;

    @tracked
    eventsData = null;
    @tracked
    eventsError = null;
    @tracked
    eventsLoading = false;

    @tracked
    mrrStatsData = null;
    @tracked
    mrrStatsError = null;
    @tracked
    mrrStatsLoading = false;

    @tracked
    memberCountStatsData = null;
    @tracked
    memberCountStatsError = null;
    @tracked
    memberCountStatsLoading = false;

    @tracked
    topMembersData = null;
    @tracked
    topMembersError = null;
    @tracked
    topMembersLoading = false;

    @tracked
    newsletterOpenRatesData = null;
    @tracked
    newsletterOpenRatesError = null;
    @tracked
    newsletterOpenRatesLoading = false;

    @tracked
    whatsNewEntries = null;
    @tracked
    whatsNewEntriesLoading = null;
    @tracked
    whatsNewEntriesError = null;

    get topMembersDataHasOpenRates() {
        return this.topMembersData && this.topMembersData.find((member) => {
            return member.emailOpenRate !== null;
        });
    }

    initialise() {
        this.loadEvents();
        this.loadTopMembers();
        this.loadCharts();
        this.loadWhatsNew();
    }

    loadMRRStats() {
        this.mrrStatsLoading = true;
        this.membersStats.fetchMRR().then((stats) => {
            this.mrrStatsLoading = false;
            const statsData = stats.data || [];
            const defaultCurrency = this.getDefaultCurrency() || 'usd';
            let currencyStats = statsData.find((stat) => {
                return stat.currency === defaultCurrency;
            });
            currencyStats = currencyStats || {
                data: [],
                currency: defaultCurrency
            };
            if (currencyStats) {
                const currencyStatsData = this.membersStats.fillDates(currencyStats.data) || {};
                const dateValues = Object.values(currencyStatsData).map(val => Math.round((val / 100)));
                const currentMRR = dateValues.length ? dateValues[dateValues.length - 1] : 0;
                const rangeStartMRR = dateValues.length ? dateValues[0] : 0;
                const percentGrowth = rangeStartMRR !== 0 ? ((currentMRR - rangeStartMRR) / rangeStartMRR) * 100 : 0;
                this.mrrStatsData = {
                    currentAmount: currentMRR,
                    currency: getSymbol(currencyStats.currency),
                    percentGrowth: percentGrowth.toFixed(1),
                    percentClass: (percentGrowth > 0 ? 'positive' : (percentGrowth < 0 ? 'negative' : '')),
                    options: {
                        rangeInDays: 30
                    },
                    data: {
                        label: 'MRR',
                        dateLabels: Object.keys(currencyStatsData),
                        dateValues
                    },
                    title: 'MRR',
                    stats: currencyStats
                };
            }
        }, (error) => {
            this.mrrStatsError = error;
            this.mrrStatsLoading = false;
        });
    }

    loadMemberCountStats() {
        this.memberCountStatsLoading = true;
        this.membersStats.fetchCounts().then((stats) => {
            this.memberCountStatsLoading = false;

            if (stats) {
                const statsDateObj = this.membersStats.fillCountDates(stats.data) || {};
                const dateValues = Object.values(statsDateObj);
                const currentAllCount = dateValues.length ? dateValues[dateValues.length - 1].total : 0;
                const currentPaidCount = dateValues.length ? dateValues[dateValues.length - 1].paid : 0;
                const rangeStartAllCount = dateValues.length ? dateValues[0].total : 0;
                const rangeStartPaidCount = dateValues.length ? dateValues[0].paid : 0;
                const allCountPercentGrowth = rangeStartAllCount !== 0 ? ((currentAllCount - rangeStartAllCount) / rangeStartAllCount) * 100 : 0;
                const paidCountPercentGrowth = rangeStartPaidCount !== 0 ? ((currentPaidCount - rangeStartPaidCount) / rangeStartPaidCount) * 100 : 0;

                this.memberCountStatsData = {
                    all: {
                        percentGrowth: allCountPercentGrowth.toFixed(1),
                        percentClass: (allCountPercentGrowth > 0 ? 'positive' : (allCountPercentGrowth < 0 ? 'negative' : '')),
                        total: dateValues.length ? dateValues[dateValues.length - 1].total : 0,
                        options: {
                            rangeInDays: 30
                        },
                        data: {
                            label: 'Members',
                            dateLabels: Object.keys(statsDateObj),
                            dateValues: dateValues.map(d => d.total)
                        },
                        title: 'Total Members',
                        stats: stats
                    },
                    paid: {
                        percentGrowth: paidCountPercentGrowth.toFixed(1),
                        percentClass: (paidCountPercentGrowth > 0 ? 'positive' : (paidCountPercentGrowth < 0 ? 'negative' : '')),
                        total: dateValues.length ? dateValues[dateValues.length - 1].paid : 0,
                        options: {
                            rangeInDays: 30
                        },
                        data: {
                            label: 'Members',
                            dateLabels: Object.keys(statsDateObj),
                            dateValues: dateValues.map(d => d.paid)
                        },
                        title: 'Paid Members',
                        stats: stats
                    }
                };
            }
        }, (error) => {
            this.memberCountStatsError = error;
            this.memberCountStatsLoading = false;
        });
    }

    loadCharts() {
        this.loadMRRStats();
        this.loadMemberCountStats();
        this.loadNewsletterOpenRates();
    }

    loadEvents() {
        this.eventsLoading = true;
        this.membersStats.fetchTimeline({limit: 5}).then(({events}) => {
            this.eventsData = events;
            this.eventsLoading = false;
        }, (error) => {
            this.eventsError = error;
            this.eventsLoading = false;
        });
    }

    loadNewsletterOpenRates() {
        this.newsletterOpenRatesLoading = true;
        this.membersStats.fetchNewsletterStats().then((results) => {
            const rangeStartOpenRate = results.length > 1 ? results[results.length - 2].openRate : 0;
            const rangeEndOpenRate = results.length > 0 ? results[results.length - 1].openRate : 0;
            const percentGrowth = rangeStartOpenRate !== 0 ? ((rangeEndOpenRate - rangeStartOpenRate) / rangeStartOpenRate) * 100 : 0;
            this.newsletterOpenRatesData = {
                percentGrowth: percentGrowth.toFixed(1),
                percentClass: (percentGrowth > 0 ? 'positive' : (percentGrowth < 0 ? 'negative' : '')),
                current: rangeEndOpenRate,
                options: {
                    rangeInDays: 30
                },
                data: {
                    label: 'Open rate',
                    dateLabels: results.map(d => d.subject),
                    dateValues: results.map(d => d.openRate)
                },
                title: 'Open rate',
                stats: results
            };
            this.newsletterOpenRatesLoading = false;
        }, (error) => {
            this.newsletterOpenRatesError = error;
            this.newsletterOpenRatesLoading = false;
        });
    }

    loadTopMembers() {
        this.topMembersLoading = true;
        let query = {
            filter: 'email_open_rate:-null',
            order: 'email_open_rate desc',
            limit: 5
        };
        this.store.query('member', query).then((result) => {
            if (!result.length) {
                return this.store.query('member', {
                    filter: 'status:paid',
                    order: 'created_at asc',
                    limit: 5
                });
            }
            return result;
        }).then((result) => {
            this.topMembersData = result;
            this.topMembersLoading = false;
        }).catch((error) => {
            this.topMembersError = error;
            this.topMembersLoading = false;
        });
    }

    loadWhatsNew() {
        this.whatsNewEntriesLoading = true;
        this.whatsNew.fetchLatest.perform().then(() => {
            this.whatsNewEntriesLoading = false;
            this.whatsNewEntries = this.whatsNew.entries.slice(0, 3);
        }, (error) => {
            this.whatsNewEntriesError = error;
            this.whatsNewEntriesLoading = false;
        });
    }

    getDefaultCurrency() {
        const plans = this.settings.get('stripePlans') || [];
        const monthly = plans.find(plan => plan.interval === 'month');
        return monthly && monthly.currency;
    }

    @action
    dismissLaunchBanner() {
        this.feature.set('launchComplete', true);
    }
}
<|endoftext|>


<commit_before>export default function($stateProvider) {
    this.$get = function() {
        return {
            addState: function(state) {
                var route = state.route || state.url;
                $stateProvider.state(state.name, {
                    url: route,
                    controller: state.controller,
                    templateUrl: state.templateUrl,
                    resolve: state.resolve,
                    params: state.params,
                    data: state.data,
                    ncyBreadcrumb: state.ncyBreadcrumb,
                    onEnter: state.onEnter,
                    onExit: state.onExit,
                    template: state.template,
                    controllerAs: state.controllerAs
                    views: state.views
                });
            }
        };
    };
}
<commit_msg>Updated state extender.<commit_after>export default function($stateProvider) {
    this.$get = function() {
        return {
            addState: function(state) {
                var route = state.route || state.url;
                $stateProvider.state(state.name, {
                    url: route,
                    controller: state.controller,
                    templateUrl: state.templateUrl,
                    resolve: state.resolve,
                    params: state.params,
                    data: state.data,
                    ncyBreadcrumb: state.ncyBreadcrumb,
                    onEnter: state.onEnter,
                    onExit: state.onExit,
                    template: state.template,
                    controllerAs: state.controllerAs,
                    views: state.views
                });
            }
        };
    };
}
<|endoftext|>


<commit_before>/*!
 * Abricos Platform (http://abricos.org)
 * Copyright 2008-2014 Alexander Kuzmin <roosit@abricos.org>
 * Licensed under the MIT license
 */

var Component = new Brick.Component();
Component.requires = {
    yui: ['base'],
    mod: [
        {name: '{C#MODNAME}', files: ['component.js', 'widget.js', 'io.js']},
        {name: 'widget', files: ['notice.js']}
    ]
};
Component.entryPoint = function(NS){

    var Y = Brick.YUI,
        L = Y.Lang,

        WAITING = 'waiting',
        BOUNDING_BOX = 'boundingBox',

        SLICE = Array.prototype.slice;

    NS.Application = Y.Base.create('application', Y.Base, [
        NS.AJAX,
        NS.Language
    ], {
        initializer: function(){
            var ns = this.get('component');
            ns.namespace.appInstance = this;

            this._appCache = {};
        },
        initCallbackFire: function(){
            var initCallback = this.get('initCallback');
            if (Y.Lang.isFunction(initCallback)){
                initCallback(null, this);
            }
        },
        onAJAXError: function(err){
            Brick.mod.widget.notice.show(err.msg);
        },
        ajaxParseResponse: function(data, res){
        },
        _defaultAJAXCallback: function(err, res, details){
            res = res || {};

            var tRes = {},
                data = res.data || {};

            for (var n in data){
                var fName = n + 'ParseResponse';

                if (Y.Lang.isFunction(this[fName])){
                    this[fName](data, tRes);
                }
            }

            this.ajaxParseResponse(data, tRes);

            if (Y.Lang.isFunction(details.callback)){
                details.callback.apply(details.context, [err, tRes]);
            }
        },
        ajaxa: function(rData, callback, context){
            this.ajax(rData, this._defaultAJAXCallback, {
                arguments: {callback: callback, context: context}
            });
        }
    }, {
        ATTRS: {
            initCallback: {
                value: null
            },
            component: {
                value: null
            },
            moduleName: {
                value: null
            }
        }
    });

    NS.Application.build = function(component, ajaxes, px, extensions, sx){
        extensions = extensions || [];
        sx = sx || {};

        var moduleName = component.moduleName;
        var ns = Brick.mod[moduleName];

        for (var n in ajaxes){
            (function(){
                var act = n,
                    info = ajaxes[act];

                if (Y.Lang.isFunction(info.response)){

                    px[act + 'ParseResponse'] = function(data, res){
                        res[act] = info.response(data[act]);

                        if (info.cache){
                            this._appCache[info.cache] = res[act];
                        }
                    };
                }

                px[act] = function(){
                    var funcArgs = SLICE.call(arguments),
                        funcArg,
                        defArgsOffset = 0;

                    var rData = {
                        'do': act
                    };

                    if (Y.Lang.isArray(info.args)){
                        defArgsOffset = info.args.length;
                        for (var i = 0; i < defArgsOffset; i++){
                            funcArg = funcArgs[i];
                            if (Y.Lang.isFunction(funcArg.toJSON)){
                                funcArg = funcArg.toJSON();
                            }
                            rData[info.args[i]] = funcArg;
                        }
                    }

                    var callback, context;
                    if (funcArgs[defArgsOffset]){
                        callback = funcArgs[defArgsOffset];
                    }
                    if (funcArgs[defArgsOffset + 1]){
                        context = funcArgs[defArgsOffset + 1];
                    }

                    if (info.cache && this._appCache[info.cache]){
                        var ret = {};
                        ret[act] = this._appCache[info.cache];
                        return callback.apply(context, [null, ret]);
                    }
                    this.ajaxa(rData, callback, context);
                };
            })();
        }

        sx.ATTRS = Y.merge(sx.ATTRS || {}, {
            component: {
                value: component
            },
            moduleName: {
                value: moduleName
            }
        });

        var appName = moduleName + 'App';
        ns.App = Y.Base.create(appName, NS.Application, extensions, px, sx);

        ns.appInstance = null;
        ns.initApp = function(options){

            if (Y.Lang.isFunction(options)){
                options = {
                    initCallback: options
                }
            }
            options = Y.merge({
                initCallback: function(){
                }
            }, options || {});
            if (ns.appInstance){
                return options.initCallback(null, ns.appInstance);
            }
            new ns.App(options);
        };
    };

    var AppWorkspace = function(){
    };
    AppWorkspace.NAME = 'appWorkspace';
    AppWorkspace.ATTRS = {
        workspacePage: {
            value: null
        },
        workspaceWidget: {
            value: null
        }
    };
    AppWorkspace.prototype = {
        initializer: function(){
            this.on('initAppWidget', function(e, err, appInstance){
                this.showWorkspacePage(this.get('workspacePage'));
            });
        },

        showWorkspacePage: function(page){
            if (!page || !page.component || !page.widget){
                return;
            }
            this.set('workspacePage', page);
            this.set(WAITING, true);

            Brick.use(this.get('component').moduleName, page.component, function(err, ns){
                this.set(WAITING, false);

                var wName = page.widget,
                    widgetClass = ns[wName];

                if (!widgetClass){
                    return;
                }

                var bBox = this.get(BOUNDING_BOX);

                var elBoard = bBox.one('.app-workspace-page');
                if (!elBoard){
                    return;
                }

                var currentWidget = this.get('workspaceWidget');
                if (currentWidget){
                    currentWidget.destroy();
                }
                var elDiv = Y.Node.create('

');
                elBoard.appendChild(elDiv);

                var args = {};
                if (L.isFunction(ns[wName].parseURLParam)){
                    args = ns[wName].parseURLParam(page.args);
                }

                currentWidget = new widgetClass(
                    Y.mix({'boundingBox': elDiv}, args)
                );

                this.set('workspaceWidget', currentWidget)
            }, this);
        }
    };
    AppWorkspace.list = {};
    AppWorkspace.build = function(moduleName, wsWidget, wsConfig){
        wsConfig = Y.merge({
            workspacePage: {}
        }, wsConfig || {});

        var cache = AppWorkspace.list[moduleName] = AppWorkspace.list[moduleName] || [],
            wsName = wsWidget.NAME;

        var initAppFunc = function(config, callback){
            if (!L.isFunction(callback)){
                callback = function(){
                };
            }
            var w = cache[wsName];
            if (w){
                w.showWorkspacePage(config.workspacePage);
                // TODO: событие на установку страницы
                callback(null, w);
            } else {
                if (!config.boundingBox){
                    config.boundingBox = config.getBoundingBox();
                }
                config.workspacePage = Y.merge(wsConfig.workspacePage, config.workspacePage || {});

                cache[wsName] = w = new wsWidget(config);
                callback(null, w);
            }
        };
        return initAppFunc;
    };
    NS.AppWorkspace = AppWorkspace;

    NS.AppWidget = Y.Base.create('appWidget', Y.Widget, [
        NS.Language,
        NS.Template,
        NS.WidgetClick,
        NS.WidgetWaiting
    ], {
        initializer: function(){
            this.publish('initAppWidget');

            this._appWidgetArguments = Y.Array(arguments);

            Y.after(this._syncUIAppWidget, this, 'syncUI');
        },
        _syncUIAppWidget: function(){
            if (!this.get('useExistingWidget')){
                var args = this._appWidgetArguments,
                    tData = {};

                if (Y.Lang.isFunction(this.buildTData)){
                    tData = this.buildTData.apply(this, args);
                }

                var bBox = this.get(BOUNDING_BOX),
                    defTName = this.template.cfg.defTName;

                bBox.setHTML(this.template.replace(defTName, tData));
            }
            this.set(WAITING, true);

            var instance = this;
            this.get('component').namespace.initApp({
                initCallback: function(err, appInstance){
                    instance._initAppWidget(err, appInstance);
                }
            });
        },

        _appURLUpdate: function(){
            var appInstance = this.get('appInstance');
            if (!appInstance){
                return;
            }

            var URL = Brick.mod[appInstance.get('moduleName')]['URL'];
            if (!URL){
                return;
            }

            this.get('boundingBox').all('[data-url]').each(function(node){
                var sURL = node.getData('url');
                if (!sURL){
                    return;
                }
                var arr = sURL.split('.'), s = URL;
                for (var i = 0; i < arr.length; i++){
                    if (!(s = s[arr[i]])){
                        return;
                    }
                }
                s = L.isFunction(s) ? s() : s;
                if (!L.isString(s)){
                    return;
                }
                node.set('href', s);
            }, this);
        },

        _initAppWidget: function(err, appInstance){
            this.set('appInstance', appInstance);
            this.set(WAITING, false);

            this._appURLUpdate();

            var args = this._appWidgetArguments
            this.onInitAppWidget.apply(this, [err, appInstance, {
                arguments: args
            }]);
            this.fire('initAppWidget', err, appInstance, {
                arguments: args
            });
        },
        onInitAppWidget: function(){
        }
    }, {
        ATTRS: {
            component: {
                value: null
            },
            render: {
                value: true
            },
            appInstance: {
                value: null
            },
            useExistingWidget: {
                value: false
            }
        }
    });

};<commit_msg>set data-url with parameters in application widget<commit_after>/*!
 * Abricos Platform (http://abricos.org)
 * Copyright 2008-2014 Alexander Kuzmin <roosit@abricos.org>
 * Licensed under the MIT license
 */

var Component = new Brick.Component();
Component.requires = {
    yui: ['base'],
    mod: [
        {name: '{C#MODNAME}', files: ['component.js', 'widget.js', 'io.js']},
        {name: 'widget', files: ['notice.js']}
    ]
};
Component.entryPoint = function(NS){

    var Y = Brick.YUI,
        L = Y.Lang,

        WAITING = 'waiting',
        BOUNDING_BOX = 'boundingBox',

        SLICE = Array.prototype.slice;

    NS.Application = Y.Base.create('application', Y.Base, [
        NS.AJAX,
        NS.Language
    ], {
        initializer: function(){
            var ns = this.get('component');
            ns.namespace.appInstance = this;

            this._appCache = {};
        },
        initCallbackFire: function(){
            var initCallback = this.get('initCallback');
            if (Y.Lang.isFunction(initCallback)){
                initCallback(null, this);
            }
        },
        onAJAXError: function(err){
            Brick.mod.widget.notice.show(err.msg);
        },
        ajaxParseResponse: function(data, res){
        },
        _defaultAJAXCallback: function(err, res, details){
            res = res || {};

            var tRes = {},
                data = res.data || {};

            for (var n in data){
                var fName = n + 'ParseResponse';

                if (Y.Lang.isFunction(this[fName])){
                    this[fName](data, tRes);
                }
            }

            this.ajaxParseResponse(data, tRes);

            if (Y.Lang.isFunction(details.callback)){
                details.callback.apply(details.context, [err, tRes]);
            }
        },
        ajaxa: function(rData, callback, context){
            this.ajax(rData, this._defaultAJAXCallback, {
                arguments: {callback: callback, context: context}
            });
        }
    }, {
        ATTRS: {
            initCallback: {
                value: null
            },
            component: {
                value: null
            },
            moduleName: {
                value: null
            }
        }
    });

    NS.Application.build = function(component, ajaxes, px, extensions, sx){
        extensions = extensions || [];
        sx = sx || {};

        var moduleName = component.moduleName;
        var ns = Brick.mod[moduleName];

        for (var n in ajaxes){
            (function(){
                var act = n,
                    info = ajaxes[act];

                if (Y.Lang.isFunction(info.response)){

                    px[act + 'ParseResponse'] = function(data, res){
                        res[act] = info.response(data[act]);

                        if (info.cache){
                            this._appCache[info.cache] = res[act];
                        }
                    };
                }

                px[act] = function(){
                    var funcArgs = SLICE.call(arguments),
                        funcArg,
                        defArgsOffset = 0;

                    var rData = {
                        'do': act
                    };

                    if (Y.Lang.isArray(info.args)){
                        defArgsOffset = info.args.length;
                        for (var i = 0; i < defArgsOffset; i++){
                            funcArg = funcArgs[i];
                            if (Y.Lang.isFunction(funcArg.toJSON)){
                                funcArg = funcArg.toJSON();
                            }
                            rData[info.args[i]] = funcArg;
                        }
                    }

                    var callback, context;
                    if (funcArgs[defArgsOffset]){
                        callback = funcArgs[defArgsOffset];
                    }
                    if (funcArgs[defArgsOffset + 1]){
                        context = funcArgs[defArgsOffset + 1];
                    }

                    if (info.cache && this._appCache[info.cache]){
                        var ret = {};
                        ret[act] = this._appCache[info.cache];
                        return callback.apply(context, [null, ret]);
                    }
                    this.ajaxa(rData, callback, context);
                };
            })();
        }

        sx.ATTRS = Y.merge(sx.ATTRS || {}, {
            component: {
                value: component
            },
            moduleName: {
                value: moduleName
            }
        });

        var appName = moduleName + 'App';
        ns.App = Y.Base.create(appName, NS.Application, extensions, px, sx);

        ns.appInstance = null;
        ns.initApp = function(options){

            if (Y.Lang.isFunction(options)){
                options = {
                    initCallback: options
                }
            }
            options = Y.merge({
                initCallback: function(){
                }
            }, options || {});
            if (ns.appInstance){
                return options.initCallback(null, ns.appInstance);
            }
            new ns.App(options);
        };
    };

    var AppWorkspace = function(){
    };
    AppWorkspace.NAME = 'appWorkspace';
    AppWorkspace.ATTRS = {
        workspacePage: {
            value: null
        },
        workspaceWidget: {
            value: null
        }
    };
    AppWorkspace.prototype = {
        initializer: function(){
            this.on('initAppWidget', function(e, err, appInstance){
                this.showWorkspacePage(this.get('workspacePage'));
            });
        },

        showWorkspacePage: function(page){
            if (!page || !page.component || !page.widget){
                return;
            }
            this.set('workspacePage', page);
            this.set(WAITING, true);

            Brick.use(this.get('component').moduleName, page.component, function(err, ns){
                this.set(WAITING, false);

                var wName = page.widget,
                    widgetClass = ns[wName];

                if (!widgetClass){
                    return;
                }

                var bBox = this.get(BOUNDING_BOX);

                var elBoard = bBox.one('.app-workspace-page');
                if (!elBoard){
                    return;
                }

                var currentWidget = this.get('workspaceWidget');
                if (currentWidget){
                    currentWidget.destroy();
                }
                var elDiv = Y.Node.create('

');
                elBoard.appendChild(elDiv);

                var args = {};
                if (L.isFunction(ns[wName].parseURLParam)){
                    args = ns[wName].parseURLParam(page.args);
                }

                currentWidget = new widgetClass(
                    Y.mix({'boundingBox': elDiv}, args)
                );

                this.set('workspaceWidget', currentWidget)
            }, this);
        }
    };
    AppWorkspace.list = {};
    AppWorkspace.build = function(moduleName, wsWidget, wsConfig){
        wsConfig = Y.merge({
            workspacePage: {}
        }, wsConfig || {});

        var cache = AppWorkspace.list[moduleName] = AppWorkspace.list[moduleName] || [],
            wsName = wsWidget.NAME;

        var initAppFunc = function(config, callback){
            if (!L.isFunction(callback)){
                callback = function(){
                };
            }
            var w = cache[wsName];
            if (w){
                w.showWorkspacePage(config.workspacePage);
                // TODO: событие на установку страницы
                callback(null, w);
            } else {
                if (!config.boundingBox){
                    config.boundingBox = config.getBoundingBox();
                }
                config.workspacePage = Y.merge(wsConfig.workspacePage, config.workspacePage || {});

                cache[wsName] = w = new wsWidget(config);
                callback(null, w);
            }
        };
        return initAppFunc;
    };
    NS.AppWorkspace = AppWorkspace;

    NS.AppWidget = Y.Base.create('appWidget', Y.Widget, [
        NS.Language,
        NS.Template,
        NS.WidgetClick,
        NS.WidgetWaiting
    ], {
        initializer: function(){
            this.publish('initAppWidget');

            this._appWidgetArguments = Y.Array(arguments);

            Y.after(this._syncUIAppWidget, this, 'syncUI');
        },
        _syncUIAppWidget: function(){
            if (!this.get('useExistingWidget')){
                var args = this._appWidgetArguments,
                    tData = {};

                if (Y.Lang.isFunction(this.buildTData)){
                    tData = this.buildTData.apply(this, args);
                }

                var bBox = this.get(BOUNDING_BOX),
                    defTName = this.template.cfg.defTName;

                bBox.setHTML(this.template.replace(defTName, tData));
            }
            this.set(WAITING, true);

            var instance = this;
            this.get('component').namespace.initApp({
                initCallback: function(err, appInstance){
                    instance._initAppWidget(err, appInstance);
                }
            });
        },

        _appURLUpdate: function(){
            var appInstance = this.get('appInstance');
            if (!appInstance){
                return;
            }

            var URL = Brick.mod[appInstance.get('moduleName')]['URL'];
            if (!URL){
                return;
            }

            this.get('boundingBox').all('[data-url]').each(function(node){
                var sURL = node.getData('url');
                if (!sURL){
                    return;
                }
                var arr = sURL.split('.'), s = URL, si, aParam = [],
                    rex = /(.*)\((.*)\)/i;
                for (var i = 0; i < arr.length; i++){
                    si = arr[i];
                    if (i === (arr.length - 1) && rex.test(si)){
                        var ex = rex.exec(si);
                        si = ex[1];
                        aParam = ex[2].split(",");
                    }
                    if (!(s = s[si])){
                        return;
                    }
                }

                s = L.isFunction(s) ? s.apply(null, aParam) : s;
                if (!L.isString(s)){
                    return;
                }
                node.set('href', s);
            }, this);
        },

        _initAppWidget: function(err, appInstance){
            this.set('appInstance', appInstance);
            this.set(WAITING, false);

            this._appURLUpdate();

            var args = this._appWidgetArguments
            this.onInitAppWidget.apply(this, [err, appInstance, {
                arguments: args
            }]);
            this.fire('initAppWidget', err, appInstance, {
                arguments: args
            });
        },
        onInitAppWidget: function(){
        }
    }, {
        ATTRS: {
            component: {
                value: null
            },
            render: {
                value: true
            },
            appInstance: {
                value: null
            },
            useExistingWidget: {
                value: false
            }
        }
    });

};<|endoftext|>


<commit_before>var logger  = require('radiodan-client').utils.logger(__filename),
    colours = {
      black  : [0, 0, 0],
      blue   : [0, 0, 255],
      green  : [0, 255, 0],
      red    : [255, 0, 0],
      white  : [255, 255, 255],
      yellow : [255, 255, 0]
    },
    ShutdownState = {
      PENDING: 'pending',
      CONFIRMED: 'confirmed'
    };

module.exports.create = function(radiodan) {
  var nextButton    = radiodan.button.get('next'),
      powerButton   = radiodan.button.get('power'),
      magicButton   = radiodan.button.get('magic'),
      powerLED      = radiodan.RGBLED.get('power'),
      magicLED      = radiodan.RGBLED.get('magic'),
      volumeEncoder = radiodan.rotaryEncoder.get('volume'),
      magicEncoder  = radiodan.rotaryEncoder.get('magic'),
      // TODO: emit shutdown over state machine, not directly
      device        = radiodan.device.get(),
      shutdownState = null;

  var objects = {
    colours: colours,
    buttons: { next: nextButton, power: powerButton, magic: magicButton },
    RGBLEDs: { power: powerLED, magic: magicLED },
    rotaryEncoders: { volume: volumeEncoder, magic: magicEncoder },
  };

  return {
    objects: objects,
    bindToState: bindToState
  };

  function bindToState(state) {
    nextButton.on('release', function(args) {
      logger.info('nextButton', 'pressed', args);
      state.handle('playNext');
    });

    powerButton.on('release', function(args) {
      logger.info('powerButton', 'pressed', args);
      if (shutdownState !== ShutdownState.CONFIRMED) {
        state.handle('power');
      }
    });

    powerButton.on('hold', function(args) {
      logger.info('hold', args.durationMs);
      if (!shutdownState && args.durationMs > 3000) {
        logger.info('SHUTDOWN');
        shutdownState = ShutdownState.PENDING;
        device.shutdown()
          .then(function () {
            logger.info('Shutdown reply');
            shutdownState = ShutdownState.CONFIRMED;
            // Change to yellow
            powerLED.emit({
              emit: true,
              colour: colours.yellow,
              transition: { duration: 200 }
            });
            // Flash yellow
            powerLED.emit({
              emit: true,
              colour: colours.black,
              transition: {
                yoyo: true
              }
            });
          },
          function (err) {
            logger.warn('Error sending shutdown request', err);
            shutdownState = null;
          });
      }
    });

    magicButton.on('release', function(args) {
      logger.info('magicButton', 'pressed', args);
      state.handle('magicButton');
    });

    volumeEncoder.on('turn', function(args) {
      var audioDevice = radiodan.audio.get('default'),
      diff = 10; //args.distance;

      if(args.direction === 'anticlockwise') {
        diff = -diff;
      }

      logger.info('volumeEncoder', 'turned', args);
      audioDevice.volume({diff: diff});
    });

    magicEncoder.on('turn', function(args) {
      logger.info('magicEncoder', 'turned', args);

      // do magic here
    });
  }
};
<commit_msg>Turn power button red when app starts<commit_after>var logger  = require('radiodan-client').utils.logger(__filename),
    colours = {
      black  : [0, 0, 0],
      blue   : [0, 0, 255],
      green  : [0, 255, 0],
      red    : [255, 0, 0],
      white  : [255, 255, 255],
      yellow : [255, 255, 0]
    },
    ShutdownState = {
      PENDING: 'pending',
      CONFIRMED: 'confirmed'
    };

module.exports.create = function(radiodan) {
  var nextButton    = radiodan.button.get('next'),
      powerButton   = radiodan.button.get('power'),
      magicButton   = radiodan.button.get('magic'),
      powerLED      = radiodan.RGBLED.get('power'),
      magicLED      = radiodan.RGBLED.get('magic'),
      volumeEncoder = radiodan.rotaryEncoder.get('volume'),
      magicEncoder  = radiodan.rotaryEncoder.get('magic'),
      // TODO: emit shutdown over state machine, not directly
      device        = radiodan.device.get(),
      shutdownState = null;

  var objects = {
    colours: colours,
    buttons: { next: nextButton, power: powerButton, magic: magicButton },
    RGBLEDs: { power: powerLED, magic: magicLED },
    rotaryEncoders: { volume: volumeEncoder, magic: magicEncoder },
  };

  powerLED.emit({
    emit: true,
    colour: colours.red
  });

  return {
    objects: objects,
    bindToState: bindToState
  };

  function bindToState(state) {
    nextButton.on('release', function(args) {
      logger.info('nextButton', 'pressed', args);
      state.handle('playNext');
    });

    powerButton.on('release', function(args) {
      logger.info('powerButton', 'pressed', args);
      if (shutdownState !== ShutdownState.CONFIRMED) {
        state.handle('power');
      }
    });

    powerButton.on('hold', function(args) {
      logger.info('hold', args.durationMs);
      if (!shutdownState && args.durationMs > 3000) {
        logger.info('SHUTDOWN');
        shutdownState = ShutdownState.PENDING;
        device.shutdown()
          .then(function () {
            logger.info('Shutdown reply');
            shutdownState = ShutdownState.CONFIRMED;
            // Change to yellow
            powerLED.emit({
              emit: true,
              colour: colours.yellow,
              transition: { duration: 200 }
            });
            // Flash yellow
            powerLED.emit({
              emit: true,
              colour: colours.black,
              transition: {
                yoyo: true
              }
            });
          },
          function (err) {
            logger.warn('Error sending shutdown request', err);
            shutdownState = null;
          });
      }
    });

    magicButton.on('release', function(args) {
      logger.info('magicButton', 'pressed', args);
      state.handle('magicButton');
    });

    volumeEncoder.on('turn', function(args) {
      var audioDevice = radiodan.audio.get('default'),
      diff = 10; //args.distance;

      if(args.direction === 'anticlockwise') {
        diff = -diff;
      }

      logger.info('volumeEncoder', 'turned', args);
      audioDevice.volume({diff: diff});
    });

    magicEncoder.on('turn', function(args) {
      logger.info('magicEncoder', 'turned', args);

      // do magic here
    });
  }
};
<|endoftext|>


<commit_before>var _     = require('lodash');
var raspi = require('raspi-io');
var exec  = require('child_process').exec;
var eyesPin = 16, jawPin = 22;
var Reaper = function(){
  var self = this;

  self.connect = function(callback){
    self.board = new raspi();
    self.board.on('ready', function(){
      self.board.pinMode(eyesPin,  self.board.MODES.OUTPUT);
      self.board.pinMode(jawPin, self.board.MODES.OUTPUT);
      if(callback) callback();
    });
  };

  self.eyes = function(on){
    var value = on ? self.board.HIGH : self.board.LOW;
    self.board.pins[eyesPin].value = value;
  };

  self.jaws = function(on){
    var value = on ? self.board.HIGH : self.board.LOW;
    self.board.pins[jawPin].value = value;
  };

  self.say = function(text){
    exec('./voice.sh "'+text+'"');
  };

  return self;
};

module.exports = Reaper;<commit_msg>added animation to reaper<commit_after>var _     = require('lodash');
var raspi = require('raspi-io');
var exec  = require('child_process').exec;
var eyesPin = 16, jawPin = 22;
var Reaper = function(){
  var self = this;

  self.connect = function(callback){
    self.board = new raspi();
    self.board.on('ready', function(){
      self.board.pinMode(eyesPin,  self.board.MODES.OUTPUT);
      self.board.pinMode(jawPin, self.board.MODES.OUTPUT);
      if(callback) callback();
    });
  };

  self.eyes = function(on){
    var value = on ? self.board.HIGH : self.board.LOW;
    self.board.pins[eyesPin].value = value;
  };

  self.jaws = function(on){
    var value = on ? self.board.HIGH : self.board.LOW;
    self.board.pins[jawPin].value = value;
  };

  self.say = function(text){
    self.eyes(true);
    var jawInterval = setInterval(function(){
      if(self.board.pins[jawPin].value === self.board.HIGH) {
        return self.jaws(false);
      }
      return self.jaws(true);
    }, 300);

    exec('./voice.sh "'+text+'"', function(){
      console.log('done talking');
      clearInterval(jawInterval);
      self.jaws(false);
      self.eyes(false);
    });

  };

  return self;
};

module.exports = Reaper;
<|endoftext|>


<commit_before>/**
  Copyright 2018 LNFWebsite
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
**/

// Start Quick Search

function addSearchResult(name, id) {
  searchResultsNameStorage.push(name);
  name = decodeURIComponent(name);
  $("#searchResultsWindow").append("

" + name + "

");
}

function loadSearchResult(element) {
  var iteration = $(".searchResult").index(element);
  var id = quickSearchVideos[iteration];
  console.log("i:" + iteration + ",id:" + id);

  //getVideoData function equivalent without reloading video names
  var videoId = id;
  var videoTime = 0;
  var videoName = searchResultsNameStorage[iteration];
  addVideo(videoName, videoTime, videoId);

  if (searchClose) {
    toggleMenu("searchResults");
  }
}

// * This function loads the video for the Quick Search functionality

function quickSearch(query) {
  //console.log("debug: quickSearch(\"" + query + "\")");

  if (!inBoxSearch) {
    $("#inputBox").val("").attr("placeholder", loadingPlaceholder);
  }
  if (query !== "") {
    $("#searchProgress").css("display", "flex");

    quickSearchQuery = query;
    var searchDataFrame = document.createElement("iframe");
    searchDataFrame.setAttribute("id", "searchDataFrame");
    searchDataFrame.setAttribute("src", "");
    document.getElementById("dataFramesContainer").appendChild(searchDataFrame);
    searchDataPlayer = new YT.Player('searchDataFrame', {
      events: {
        'onReady': onSearchDataPlayerReady,
        'onStateChange': onSearchDataPlayerStateChange
      }
    });
    searchDataFrame.setAttribute("src", "https://www.youtube.com/embed/?enablejsapi=1");
  }
  else if (quickSearchVideos[quickSearchVideosIteration] !== undefined &&
           quickSearchVideos[quickSearchVideosIteration] !== null &&
           quickSearchVideosIteration + 1 < quickSearchVideos.length) {
    quickSearchVideosIteration++;
    getVideoData(quickSearchVideos[quickSearchVideosIteration]);
  }
}

// * This function cues the search results for use in the next function

var searchDataPlayerErrors = 0;
function onSearchDataPlayerReady() {
  try {
    searchDataPlayer.cuePlaylist({listType: "search", list: quickSearchQuery});
  }
  catch(e) {
    searchDataPlayerErrors++;
    console.log(e);
    if (searchDataPlayerErrors <= 5) {
      try {
        searchDataPlayer.destroy();
      } catch(e) {};
      quickSearch(quickSearchQuery);
    }
  }
}

// * This function uses the search results to add the next video

function onSearchDataPlayerStateChange(event) {
  if (event.data === 5) {
    if (!inBoxSearch) {
      $("#inputBox").val("").attr("placeholder", placeholder).blur().focus();
    }
    quickSearchVideosIteration = 0;
    quickSearchVideos = searchDataPlayer.getPlaylist();
    var data = searchDataPlayer.getVideoUrl();

    var id = urlValidate(data);
    if (id) {
      if (id[0] === "playlist") {
        id = id[1][0];
      }
      else if (id[0] === "youtube") {
        id = id[1];
      }
    }

    getVideoName(id, function(name) {
      videoName = name;
      videoName = encodeURIComponent(videoName).replace(/%20/g, " ");
      videoTime = 0;
      searchDataPlayer.destroy();
      if (!inBoxSearch) {
        addVideo(videoName, videoTime, id);
      }
      else {
        $(".searchResult").remove();
        searchResultsIteration = 0;
        searchResultsNameStorage = [];
        addSearchResult(videoName, id);
        quickSearch("");
        //as long as not open already (trying to search twice will close on second)
        if ($("#searchResultsWindow").css("display") !== "block") {
          toggleMenu("searchResults");
        }
      }
      $("#searchProgress").css("display", "none");
    });
  }
}

// End Quick Search
<commit_msg>this is stupid<commit_after>/**
  Copyright 2018 LNFWebsite
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
**/

// Start Quick Search

function addSearchResult(name, id) {
  searchResultsNameStorage.push(name);
  name = decodeURIComponent(name);
  $("#searchResultsWindow").append("

" + name + "

");
}

function loadSearchResult(element) {
  var iteration = $(".searchResult").index(element);
  var id = quickSearchVideos[iteration];
  console.log("i:" + iteration + ",id:" + id);

  //getVideoData function equivalent without reloading video names
  var videoId = id;
  var videoTime = 0;
  var videoName = searchResultsNameStorage[iteration];
  addVideo(videoName, videoTime, videoId);

  if (searchClose) {
    toggleMenu("searchResults");
  }
}

// * This function loads the video for the Quick Search functionality

function quickSearch(query) {
  //console.log("debug: quickSearch(\"" + query + "\")");

  if (!inBoxSearch) {
    $("#inputBox").val("").attr("placeholder", loadingPlaceholder);
  }
  if (query !== "") {
    $("#searchProgress").css("display", "flex");

    quickSearchQuery = query;
    var searchDataFrame = document.createElement("iframe");
    searchDataFrame.setAttribute("id", "searchDataFrame");
    searchDataFrame.setAttribute("src", "");
    document.getElementById("dataFramesContainer").appendChild(searchDataFrame);
    searchDataPlayer = new YT.Player('searchDataFrame', {
      events: {
        'onReady': onSearchDataPlayerReady,
        'onStateChange': onSearchDataPlayerStateChange
      }
    });
    searchDataFrame.setAttribute("src", "https://www.youtube.com/embed/?enablejsapi=1");
  }
  else if (quickSearchVideos[quickSearchVideosIteration] !== undefined &&
           quickSearchVideos[quickSearchVideosIteration] !== null &&
           quickSearchVideosIteration + 1 < quickSearchVideos.length) {
    quickSearchVideosIteration++;
    getVideoData(quickSearchVideos[quickSearchVideosIteration]);
  }
}

// * This function cues the search results for use in the next function

var searchDataPlayerErrors = 0;
function onSearchDataPlayerReady() {
  try {
    searchDataPlayer.cuePlaylist({listType: "search", list: quickSearchQuery});
  }
  catch(e) {
    searchDataPlayerErrors++;
    console.log(e);
    if (searchDataPlayerErrors <= 5) {
      try {
        searchDataPlayer.destroy();
      } catch(e) {};
      quickSearch(quickSearchQuery);
    }
  }
}

// * This function uses the search results to add the next video

function onSearchDataPlayerStateChange(event) {
  if (event.data === 5) {
    if (!inBoxSearch) {
      $("#inputBox").val("").attr("placeholder", placeholder).blur().focus();
    }
    quickSearchVideosIteration = 0;
    quickSearchVideos = searchDataPlayer.getPlaylist();
    var data = searchDataPlayer.getVideoUrl();

    var id = urlValidate(data);
    if (id) {
      if (id[0] === "playlist") {
        id = id[1][0];
      }
      else if (id[0] === "youtube") {
        id = id[1];
      }
    }

    if (inBoxSearch) {
      $(".searchResult").remove();
      searchResultsIteration = 0;
      searchResultsNameStorage = [];
      //as long as not open already (trying to search twice will close on second)
      if ($("#searchResultsWindow").css("display") !== "block") {
        toggleMenu("searchResults");
      }
    }

    getVideoData(id);
    $("#searchProgress").css("display", "none");

/**
    getVideoName(id, function(name) {
      videoName = name;
      videoName = encodeURIComponent(videoName).replace(/%20/g, " ");
      videoTime = 0;
      searchDataPlayer.destroy();
      if (!inBoxSearch) {
        addVideo(videoName, videoTime, id);
      }
      else {
        $(".searchResult").remove();
        searchResultsIteration = 0;
        searchResultsNameStorage = [];
        addSearchResult(videoName, id);
        quickSearch("");
        //as long as not open already (trying to search twice will close on second)
        if ($("#searchResultsWindow").css("display") !== "block") {
          toggleMenu("searchResults");
        }
      }
      $("#searchProgress").css("display", "none");
    });
    **/
  }
}

// End Quick Search
<|endoftext|>


<commit_before>import * as graphql from 'graphql';
import invariant from 'invariant';

import Bridge from 'uniforms/Bridge';
import joinName from 'uniforms/joinName';

const extractFromNonNull = x => (x && x.type instanceof graphql.GraphQLNonNull ? {...x, type: x.type.ofType} : x);

export default class GraphQLBridge extends Bridge {
  constructor(schema, validator, extras = {}) {
    super();

    this.extras = extras;
    this.schema = schema;
    this.validator = validator;
  }

  // This bridge has 3 arguments, so it cannot be constructed implicite in the
  // createSchemaBridge.
  static check(/* schema */) {
    return false;
  }

  getError(name, error) {
    return (error && error.details && error.details.find && error.details.find(error => error.name === name)) || null;
  }

  getErrorMessage(name, error) {
    const scopedError = this.getError(name, error);
    return !scopedError ? '' : scopedError.message;
  }

  getErrorMessages(error) {
    if (error) {
      if (Array.isArray(error.details)) {
        return error.details.map(error => error.message);
      }

      if (error.message) {
        return [error.message];
      }
    }

    if (error !== undefined) {
      return [error];
    }

    return [];
  }

  getField(name, returnExtracted = true) {
    return joinName(null, name).reduce((definition, next, index, array) => {
      if (next === '$' || next === '' + parseInt(next, 10)) {
        invariant(definition.type instanceof graphql.GraphQLList, 'Field not found in schema: "%s"', name);
        definition = {type: extractFromNonNull(definition.type.ofType)};
      } else if (definition.type && definition.type._fields) {
        definition = definition.type._fields[next];
      } else {
        definition = definition[next];
      }

      invariant(definition, 'Field not found in schema: "%s"', name);

      const isLast = array.length - 1 === index;

      if (isLast && !returnExtracted) {
        return definition;
      }

      const extracted = extractFromNonNull(definition);

      if ((isLast && returnExtracted) || !(extracted.type instanceof graphql.GraphQLObjectType)) {
        return extracted;
      }

      invariant(extracted.type.getFields, 'Field not found in schema: "%s"', name);

      return extracted.type.getFields();
    }, this.schema.getFields());
  }

  getInitialValue(name, props = {}) {
    const type = this.getType(name);

    if (type === Array) {
      const item = this.getInitialValue(joinName(name, '0'));
      const items = props.initialCount || 0;

      return [...Array(items)].map(() => item);
    }

    if (type === Object) {
      return {};
    }

    const defaultValue = this.getField(name).defaultValue;

    return defaultValue === undefined ? this.extras[name] && this.extras[name].initialValue : defaultValue;
  }

  // eslint-disable-next-line complexity
  getProps(nameNormal, props = {}) {
    const nameGeneric = nameNormal.replace(/\.\d+/, '.$');

    const field = this.getField(nameGeneric, false);
    const fieldType = extractFromNonNull(field).type;

    const extra = {
      ...this.extras[nameGeneric],
      ...this.extras[nameNormal]
    };

    const ready = {
      label: '',
      required: field.type instanceof graphql.GraphQLNonNull,

      ...extra,
      ...props
    };

    if (props.label === true && extra.label) {
      ready.label = extra.label;
    } else if (props.label !== undefined && !props.label) {
      ready.label = '';
    }

    if (props.placeholder === true && extra.placeholder) {
      ready.placeholder = extra.placeholder;
    } else if (props.placeholder === false || props.placeholder === null) {
      ready.placeholder = '';
    }

    if (fieldType instanceof graphql.GraphQLScalarType && fieldType.name === 'Float') {
      ready.decimal = true;
    }

    if (ready.options) {
      if (!Array.isArray(ready.options)) {
        ready.transform = value => ready.options[value];
        ready.allowedValues = Object.keys(ready.options);
      } else {
        ready.transform = value => ready.options.find(option => option.value === value).label;
        ready.allowedValues = ready.options.map(option => option.value);
      }
    }

    return ready;
  }

  getSubfields(name) {
    if (!name) {
      return Object.keys(this.schema.getFields());
    }

    const fieldType = this.getField(name).type;

    if (fieldType instanceof graphql.GraphQLObjectType || fieldType instanceof graphql.GraphQLInputObjectType) {
      return Object.keys(fieldType.getFields());
    }

    return [];
  }

  getType(name) {
    const fieldType = this.getField(name).type;

    if (fieldType instanceof graphql.GraphQLList) return Array;
    if (fieldType instanceof graphql.GraphQLObjectType) return Object;
    if (fieldType instanceof graphql.GraphQLInputObjectType) return Object;
    if (fieldType instanceof graphql.GraphQLScalarType) {
      if (fieldType.name === 'ID') return String;
      if (fieldType.name === 'Int') return Number;
      if (fieldType.name === 'Float') return Number;
      if (fieldType.name === 'String') return String;
      if (fieldType.name === 'Boolean') return Boolean;
    }

    return fieldType;
  }

  getValidator(/* options */) {
    return this.validator;
  }
}
<commit_msg>Fixed nesting arrays in GraphQLBridge (fixes #536).<commit_after>import * as graphql from 'graphql';
import invariant from 'invariant';

import Bridge from 'uniforms/Bridge';
import joinName from 'uniforms/joinName';

const extractFromNonNull = x => (x && x.type instanceof graphql.GraphQLNonNull ? {...x, type: x.type.ofType} : x);

export default class GraphQLBridge extends Bridge {
  constructor(schema, validator, extras = {}) {
    super();

    this.extras = extras;
    this.schema = schema;
    this.validator = validator;
  }

  // This bridge has 3 arguments, so it cannot be constructed implicite in the
  // createSchemaBridge.
  static check(/* schema */) {
    return false;
  }

  getError(name, error) {
    return (error && error.details && error.details.find && error.details.find(error => error.name === name)) || null;
  }

  getErrorMessage(name, error) {
    const scopedError = this.getError(name, error);
    return !scopedError ? '' : scopedError.message;
  }

  getErrorMessages(error) {
    if (error) {
      if (Array.isArray(error.details)) {
        return error.details.map(error => error.message);
      }

      if (error.message) {
        return [error.message];
      }
    }

    if (error !== undefined) {
      return [error];
    }

    return [];
  }

  getField(name, returnExtracted = true) {
    return joinName(null, name).reduce((definition, next, index, array) => {
      if (next === '$' || next === '' + parseInt(next, 10)) {
        invariant(definition.type instanceof graphql.GraphQLList, 'Field not found in schema: "%s"', name);
        definition = {type: extractFromNonNull(definition.type.ofType)};
      } else if (definition.type && definition.type._fields) {
        definition = definition.type._fields[next];
      } else {
        definition = definition[next];
      }

      invariant(definition, 'Field not found in schema: "%s"', name);

      const isLast = array.length - 1 === index;

      if (isLast && !returnExtracted) {
        return definition;
      }

      const extracted = extractFromNonNull(definition);

      if ((isLast && returnExtracted) || !(extracted.type instanceof graphql.GraphQLObjectType)) {
        return extracted;
      }

      invariant(extracted.type.getFields, 'Field not found in schema: "%s"', name);

      return extracted.type.getFields();
    }, this.schema.getFields());
  }

  getInitialValue(name, props = {}) {
    const type = this.getType(name);

    if (type === Array) {
      const item = this.getInitialValue(joinName(name, '0'));
      const items = props.initialCount || 0;

      return [...Array(items)].map(() => item);
    }

    if (type === Object) {
      return {};
    }

    const defaultValue = this.getField(name).defaultValue;

    return defaultValue === undefined ? this.extras[name] && this.extras[name].initialValue : defaultValue;
  }

  // eslint-disable-next-line complexity
  getProps(nameNormal, props = {}) {
    const nameGeneric = nameNormal.replace(/\.\d+/g, '.$');

    const field = this.getField(nameGeneric, false);
    const fieldType = extractFromNonNull(field).type;

    const extra = {
      ...this.extras[nameGeneric],
      ...this.extras[nameNormal]
    };

    const ready = {
      label: '',
      required: field.type instanceof graphql.GraphQLNonNull,

      ...extra,
      ...props
    };

    if (props.label === true && extra.label) {
      ready.label = extra.label;
    } else if (props.label !== undefined && !props.label) {
      ready.label = '';
    }

    if (props.placeholder === true && extra.placeholder) {
      ready.placeholder = extra.placeholder;
    } else if (props.placeholder === false || props.placeholder === null) {
      ready.placeholder = '';
    }

    if (fieldType instanceof graphql.GraphQLScalarType && fieldType.name === 'Float') {
      ready.decimal = true;
    }

    if (ready.options) {
      if (!Array.isArray(ready.options)) {
        ready.transform = value => ready.options[value];
        ready.allowedValues = Object.keys(ready.options);
      } else {
        ready.transform = value => ready.options.find(option => option.value === value).label;
        ready.allowedValues = ready.options.map(option => option.value);
      }
    }

    return ready;
  }

  getSubfields(name) {
    if (!name) {
      return Object.keys(this.schema.getFields());
    }

    const fieldType = this.getField(name).type;

    if (fieldType instanceof graphql.GraphQLObjectType || fieldType instanceof graphql.GraphQLInputObjectType) {
      return Object.keys(fieldType.getFields());
    }

    return [];
  }

  getType(name) {
    const fieldType = this.getField(name).type;

    if (fieldType instanceof graphql.GraphQLList) return Array;
    if (fieldType instanceof graphql.GraphQLObjectType) return Object;
    if (fieldType instanceof graphql.GraphQLInputObjectType) return Object;
    if (fieldType instanceof graphql.GraphQLScalarType) {
      if (fieldType.name === 'ID') return String;
      if (fieldType.name === 'Int') return Number;
      if (fieldType.name === 'Float') return Number;
      if (fieldType.name === 'String') return String;
      if (fieldType.name === 'Boolean') return Boolean;
    }

    return fieldType;
  }

  getValidator(/* options */) {
    return this.validator;
  }
}
<|endoftext|>


<commit_before>"use strict";

const addGroup = function() {
    let newName = $('#new-group-name').val()
    const newChoices = $('#new-group-choices')
        .val()
        .split(/[\r\n]+/)
        .map(function(element) {
            return element.trim()
        })
        .filter(function(element) {
            return element
        })

    if (!newName) {
        console.log('Name required')
        return
    }
    newName = createGroupName(newName)
    if (newChoices.length == 0) {
        console.log('Non-empty lines required')
        return
    }

    const newGroup = {}
    newGroup.name = newName
    newGroup.proportional = false
    newGroup.choices = []
    newChoices.forEach(function(choice) {
        newGroup.choices.push({
            name: choice,
            points: 0
        })
    })
    group = newGroup
    updateGroup().then(populateGroups).then(function() {
        $('#groups').val(newName)
    }).then(reloadGroup).then(setColors).then(drawGroup)
}

const createGroupName = function(name) {
    while ($('#groups').find('option').filter(function() {
            return $(this).val() == name
        }).length > 0) {
        name += '_'
    }
    return name
}

const editGroup = function() {
    const data = $('#group-display table')
    const newGroup = {}
    const oldName = group.name

    let newName = data.find('thead').find('td').eq(0).text().trim()
    if (newName == '') {
        newName = oldName
    }

    $('#groups option').filter(function() {
        return $(this).val() == oldName
    }).remove()
    newGroup.name = createGroupName(newName)

    newGroup.choices = []
    data.find('tbody tr').each(function(id, line) {
        const name = $(line).find('td').eq(0).text().trim()

        const pointsFromField = Number($(line).find('td').eq(1).text())
        const points = isNaN(pointsFromField) ? 0 : pointsFromField

        const disabled = $(line).find('td').eq(2).find('input').prop('checked')
        if (name.trim() != '') {
            newGroup.choices.push({
                name: name,
                points,
                points,
                disabled: disabled
            })
        }
    })

    if (newGroup.choices.length == 0) {
        newGroup.choices = group.choices
    }

    newGroup.last = group.last

    newGroup.proportional = group.proportional

    group = newGroup

    updateGroup().then(function() {
        if (oldName != group.name) {
            deleteGroup(oldName)
        }
    }).then(populateGroups).then(function() {
        $('#groups').val(newGroup.name)
    }).then(reloadGroup).then(updateGroupDisplay).then(drawGroup)
}

const updateGroupDisplay = function() {
    $('#group-display').text('')
    if (group === undefined) {
        return
    }
    const table = $('
')
    table.append(`<thead><tr></tr><tr><td>${i18n.__('Name')}</td><td>${i18n.__('Points')}</td><td>${i18n.__('Disabled')}</td></tr></thead><tbody></tbody>`)
    const title = $('', {
        contenteditable: true,
        blur: editGroup,
        colspan: 3,
        text: group.name
    })
    table.find('thead').find('tr').eq(0).append(title)
    $('#group-display').append(table)
    for (let i = 0; i < group.choices.length; i++) {
        const choice = group.choices[i]

        const name = $('', {
            contenteditable: true,
            blur: editGroup
        })
        name.append(choice.name)

        const points = $('', {
            contenteditable: true,
            blur: editGroup
        })
        points.append(choice.points)

        const disabled = $('')
        disabled.append($('<input>', {
            type: 'checkbox',
            checked: choice.disabled,
            change: editGroup
        }))

        const row = $('
')
        row.append(name)
        row.append(points)
        row.append(disabled)
        table.find('tbody').append(row)
    }
    table.find('tbody').append('
		<input type="checkbox">
')
}

const reset = function() {
    group.choices.forEach(function(choice) {
        choice.points = 0
    })
    group.last = undefined
}
<commit_msg>Validate changes with enter<commit_after>"use strict";

const addGroup = function() {
    let newName = $('#new-group-name').val()
    const newChoices = $('#new-group-choices')
        .val()
        .split(/[\r\n]+/)
        .map(function(element) {
            return element.trim()
        })
        .filter(function(element) {
            return element
        })

    if (!newName) {
        console.log('Name required')
        return
    }
    newName = createGroupName(newName)
    if (newChoices.length == 0) {
        console.log('Non-empty lines required')
        return
    }

    const newGroup = {}
    newGroup.name = newName
    newGroup.proportional = false
    newGroup.choices = []
    newChoices.forEach(function(choice) {
        newGroup.choices.push({
            name: choice,
            points: 0
        })
    })
    group = newGroup
    updateGroup().then(populateGroups).then(function() {
        $('#groups').val(newName)
    }).then(reloadGroup).then(setColors).then(drawGroup)
}

const createGroupName = function(name) {
    while ($('#groups').find('option').filter(function() {
            return $(this).val() == name
        }).length > 0) {
        name += '_'
    }
    return name
}

const editGroup = function() {
    const data = $('#group-display table')
    const newGroup = {}
    const oldName = group.name

    let newName = data.find('thead').find('td').eq(0).text().trim()
    if (newName == '') {
        newName = oldName
    }

    $('#groups option').filter(function() {
        return $(this).val() == oldName
    }).remove()
    newGroup.name = createGroupName(newName)

    newGroup.choices = []
    data.find('tbody tr').each(function(id, line) {
        const name = $(line).find('td').eq(0).text().trim()

        const pointsFromField = Number($(line).find('td').eq(1).text())
        const points = isNaN(pointsFromField) ? 0 : pointsFromField

        const disabled = $(line).find('td').eq(2).find('input').prop('checked')
        if (name.trim() != '') {
            newGroup.choices.push({
                name: name,
                points,
                points,
                disabled: disabled
            })
        }
    })

    if (newGroup.choices.length == 0) {
        newGroup.choices = group.choices
    }

    newGroup.last = group.last

    newGroup.proportional = group.proportional

    group = newGroup

    updateGroup().then(function() {
        if (oldName != group.name) {
            deleteGroup(oldName)
        }
    }).then(populateGroups).then(function() {
        $('#groups').val(newGroup.name)
    }).then(reloadGroup).then(updateGroupDisplay).then(drawGroup)
}

const updateGroupDisplay = function() {
    const validateWithEnter = function(event) {
        if (event.which == 13) {
            event.preventDefault()
            $(this).blur()
        }
    }

    $('#group-display').text('')
    if (group === undefined) {
        return
    }
    const table = $('
')
    table.append(`<thead><tr></tr><tr><td>${i18n.__('Name')}</td><td>${i18n.__('Points')}</td><td>${i18n.__('Disabled')}</td></tr></thead><tbody></tbody>`)
    const title = $('', {
        contenteditable: true,
        colspan: 3,
        text: group.name,
        blur: editGroup,
        keydown: validateWithEnter
    })
    table.find('thead').find('tr').eq(0).append(title)
    $('#group-display').append(table)
    for (let i = 0; i < group.choices.length; i++) {
        const choice = group.choices[i]

        const name = $('', {
            contenteditable: true,
            blur: editGroup,
            keydown: validateWithEnter
        })
        name.append(choice.name)

        const points = $('', {
            contenteditable: true,
            blur: editGroup,
            keydown: validateWithEnter
        })
        points.append(choice.points)

        const disabled = $('')
        disabled.append($('<input>', {
            type: 'checkbox',
            checked: choice.disabled,
            change: editGroup
        }))

        const row = $('
')
        row.append(name)
        row.append(points)
        row.append(disabled)
        table.find('tbody').append(row)
    }

    const row = $('
')
    row.append($('', {
        contenteditable: true,
        blur: editGroup,
        keydown: validateWithEnter
    }))
    row.append('-	<input type="checkbox" disabled>	')
    table.find('tbody').append(row)
}

const reset = function() {
    group.choices.forEach(function(choice) {
        choice.points = 0
    })
    group.last = undefined
}
<|endoftext|>