<commit_before>App = Em.Application.create({
    VERSION: '1.0.0',

    // TODO: Remove this in production builds.
    LOG_TRANSITIONS: true,

    // We store language & locale here because they need to be available before loading templates.
    language: 'en',
    locale: 'en-GB',
    interfaceLanguages: [
        Em.Object.create({name:'English', code: 'en'}),
        Em.Object.create({name:'Nederlands', code: 'nl'})
    ],

    ready: function() {
        // Read language string from url.
        var language = window.location.pathname.split('/')[1];
        App.CurrentUser.find('current').then(function(user){
            var primaryLanguage = user.get('primary_language');
            if (primaryLanguage && primaryLanguage != language) {
                document.location = '/' + primaryLanguage + document.location.hash;
            }
        });
        // We don't have to check if it's one of the languages available. Django will have thrown an error before this.
        this.set('language', language);

        // Now that we know the language we can load the handlebars templates.
        //this.loadTemplates(this.templates);

        // Read locale from browser with fallback to default.
        var locale = navigator.language || navigator.userLanguage || this.get('locale');
        if (locale.substr(0, 2) != language) {
            // Some overrides to have a sound experience, at least for dutch speaking and dutch based users.

            if (language == 'nl') {
                // For dutch language always overwrite locale. Always use dutch locale.
                locale = 'nl';
            }
            if (language == 'en' && locale.substr(0, 2) == 'nl') {
                // For dutch browser viewing english site overwrite locale.
                // We don't want to have dutch fuzzy dates.
                // If fuzzy dates are translated in other languages we should decide if we want to show those.
                locale = 'en';
            }
        }

        /* COMMENTED FOR MODULARIZATION
         *
        App.Page.reopen({
            url: 'pages/' + language + '/pages'
        });
        *
        */

        this.initSelectViews();
        this.setLocale(locale);
        this.initSelectViews();
    },

    initSelectViews: function() {
        // Pre-load these lists so we avoid race conditions when displaying forms
        App.Theme.find().then(function(list) {
            App.ThemeSelectView.reopen({
                content: list
            });
        });

        /* COMMENTED FOR MODULARIZATION
        App.Skill.find().then(function(list) {
            App.SkillSelectView.reopen({
                content: list
            });
        });
        *
        */

        App.Country.find().then(function(list) {
            App.CountrySelectView.reopen({
                content: list
            });
            App.CountryCodeSelectView.reopen({
                content: list
            });
        });
        // Get a filtered list of countries that can apply for a project ('oda' countries).
        var filteredList = App.Country.filter(function(item) {return item.get('oda')});

        App.ProjectCountrySelectView.reopen({
            content: filteredList
        });
    },

    setLocale: function(locale) {
        if (!locale) {
            locale = this.get('locale');
        }

        if (locale != 'en-US') {
            // Try to load locale specifications.
            $.getScript('/static/assets/js/vendor/globalize-cultures/globalize.culture.' + locale + '.js')
                .fail(function() {
                    if (window.console) {
                        console.log("No globalize culture file for : "+ locale);
                    }
                    // Specified locale file not available. Use default locale.
                    locale = App.get('locale');
                    Globalize.culture(locale);
                    App.set('locale', locale);
                })
                .success(function() {
                    // Specs loaded. Enable locale.
                    Globalize.culture(locale);
                    App.set('locale', locale);
                });
            $.getScript('/static/assets/js/vendor/jquery-ui/i18n/jquery.ui.datepicker-' + locale.substr(0, 2) + '.js')
                .fail(function() {
                    if (window.console) {
                        console.log("No jquery.ui.datepicker file for : "+ locale);
                    }
                    // Specified locale file not available. Use default locale.
                    locale = App.get('locale');
                    Globalize.culture(locale);
                    App.set('locale', locale);
                })
                .success(function() {
                    // Specs loaded. Enable locale.
                    App.set('locale', locale);
                });
        } else {
            Globalize.culture(locale);
            App.set('locale', locale);
        }
    }
});

/**
 * The Ember Data Adapter and Store configuration.
 */
App.Adapter = DS.DRF2Adapter.extend({
    namespace: "api",

    plurals: {
        "projects/manage": "projects/manage",
        "projects/pitches/manage": "projects/pitches/manage",
        "projects/plans/manage": "projects/plans/manage",
        "projects/campaigns/manage": "projects/campaigns/manage",
        "projects/wallposts/media": "projects/wallposts/media",
        "projects/wallposts/text": "projects/wallposts/text",
        "organizations/manage": "organizations/manage",
        "organizations/addresses/manage": "organizations/addresses/manage",
        "organizations/documents/manage": "organizations/documents/manage",
        "projects/ambassadors/manage": "projects/ambassadors/manage",
        "projects/budgetlines/manage": "projects/budgetlines/manage",
        "users/activate": "users/activate",
        "users/passwordset": "users/passwordset",
        "homepage": "homepage",
        "pages/contact": "pages/contact"
    }
});

// Assigning plurals for model properties doesn't seem to work with extend, it does this way:
App.Adapter.configure("plurals", {
    "address": "addresses"
});

/* COMMENTED FOR MODULARIZATION
 * This code needs to be conditioned, since it impedes the normal loading of the homepage
 * in a standard BlueBottle-based website.

App.Adapter.map(
    'App.Payment', {
        availablePaymentMethods: { readOnly: true }
    },
    'App.Order', {
        total: { readOnly: true }
    }
);
*/

App.ApplicationController = Ember.Controller.extend({
    needs: ['currentUser'],// COMMENTED FOR MODULARIZATION 'currentOrder', 'myProjectList'],
    display_message: false,

    /* COMMENTED FOR MODULARIZATION
     *
    news: function() {
        return App.NewsPreview.find({language: App.get('language')});
    }.property(),
    *
    */

    displayMessage: (function() {
        if (this.get('display_message') == true) {
            Ember.run.later(this, function() {
                this.hideMessage();
            }, 10000);
        }
    }).observes('display_message'),

    hideMessage: function() {
        this.set('display_message', false);
    }
});

// Embedded Model Mapping
//
// http://stackoverflow.com/questions/14320925/how-to-make-embedded-hasmany-relationships-work-with-ember-data/14324532#14324532
// The two possible values of embedded are:
//   load: The child records are embedded when loading, but should be saved as standalone records. In order
//         for this to work, the child records must have an ID.
//   always: The child records are embedded when loading, and are saved embedded in the same record. This,
//           of course, affects the dirtiness of the records (if the child record changes, the adapter will
//           mark the parent record as dirty).

/* COMMENTED FOR MODULARIZATION
 *
App.Adapter.map('App.Quote', {
    user: {embedded: 'load'}
});
App.Adapter.map('App.ContactMessage', {
    author: {embedded: 'load'}
});
*
*/

App.Store = DS.Store.extend({
    adapter: 'App.Adapter'
});

/* Routing */

App.SlugRouter = Em.Mixin.create({
    serialize: function(model, params) {
        if (params.length !== 1) { return {}; }

        var name = params[0], object = {};
        object[name] = get(model, 'slug');

        return object;
    }
});

App.Router.reopen({
    location: 'hashbang'
});

App.Router.reopen({
    /**
     * Tracks pageviews if google analytics is used
     * Source: http://www.randomshouting.com/2013/05/04/Ember-and-Google-Analytics.html
     */
    didTransition: function(infos) {
        this._super(infos);
        if (window._gaq === undefined) { return; }

        Ember.run.next(function(){
            _gaq.push(['_trackPageview', window.location.hash.substr(1)]);
        });
    }
});

App.Router.reopen({
    didTransition: function(infos) {
        this._super(infos);
        Ember.run.next(function() {
            // the meta module will now go trough the routes and look for data
            App.meta.trigger('reloadDataFromRoutes');
        });
    }
});

DS.Model.reopen({
    meta: DS.attr('object'),
});

Em.Route.reopen({
    meta_data: function(){
        return this.get('context.meta_data');
    }.property('context.meta_data')
});

App.Router.map(function() {

    this.resource('language', {path:'/:lang'});

    // Fix for Facebook login
    this.route("home", { path: "_=_" });

    this.route("home", { path: "/" });

    this.resource('error', {path: '/error'}, function() {
        this.route('notFound', {path: '/not-found'});
        this.route('notAllowed', {path: '/not-allowed'});
    });

    this.resource('page', {path: '/pages/:page_id'});
    this.resource('contactMessage', {path: '/contact'});

});

App.ApplicationRoute = Em.Route.extend({
    needs: ['currentUser'],

//    setupController: function(controller, model) {
//        this.controllerFor('myProjectList').set('model', App.MyProject.find());
//        this._super(controller, model);
//    },

    actions: {
        selectLanguage: function(language) {
            var user = App.CurrentUser.find('current');
            if (!user.get('id_for_ember')) {
                if (language == App.get('language')) {
                    // Language already set. Don't do anything;
                    return true;
                }
                document.location = '/' + language + document.location.hash;
            }

            App.UserSettings.find(App.CurrentUser.find('current').get('id_for_ember')).then(function(settings){
                if (language == App.get('language')) {
                    // Language already set. Don't do anything;
                    return true;
                }

                if (settings.get('id')) {
                    settings.save();
                }
                var languages = App.get('interfaceLanguages');
                for (i in languages) {
                    // Check if the selected language is available.
                    if (languages[i].code == language) {
                        if (settings.get('id')) {
                            settings.set('primary_language', language);
                        }
                        settings.on('didUpdate', function(){
                            document.location = '/' + language + document.location.hash;
                        });
                        settings.save();
                        return true;
                    }
                }
                language = 'en';
                if (settings.get('id')) {
                    settings.set('primary_language', language);
                }

                settings.on('didUpdate', function(){
                    document.location = '/' + language + document.location.hash;
                });
                settings.save();
                return true;
            });
            return true;
        },

        openInBigBox: function(name, context) {
            // Close all other modals.
            $('.close-modal').click();

            // Get the controller or create one
            var controller = this.controllerFor(name);
            controller.set('model', context);

            // Get the view. This should be defined.
            var view = App[name.classify() + 'View'].create();
            view.set('controller', controller);

            var modalPaneTemplate = ['
×{{view view.bodyViewClass}}
'].join("\n");

            Bootstrap.ModalPane.popup({
                classNames: ['modal', 'large'],
                defaultTemplate: Em.Handlebars.compile(modalPaneTemplate),
                bodyViewClass: view,
                secondary: 'Close'
            });

        },
        openInBox: function(name, context) {
            // Close all other modals.
            $('.close-modal').click();

            // Get the controller or create one
            var controller = this.controllerFor(name);
            if (context) {
                controller.set('model', context);
            }

            // Get the view. This should be defined.
            var view = App[name.classify() + 'View'].create();
            view.set('controller', controller);

            var modalPaneTemplate = ['
×{{view view.bodyViewClass}}
'].join("\n");

            Bootstrap.ModalPane.popup({
                classNames: ['modal'],
                defaultTemplate: Em.Handlebars.compile(modalPaneTemplate),
                bodyViewClass: view
            });

        },
        closeAllModals: function(){
            $('.close-modal').click();
        },
        showProject: function(project_id) {
            var route = this;
            App.Project.find(project_id).then(function(project) {
                route.transitionTo('project', project);
            });
        },
        showProjectTaskList: function(project_id) {
            var route = this;
            App.Project.find(project_id).then(function(project) {
                route.transitionTo('project', project);
                route.transitionTo('projectTaskList');
            });
        },
        showTask: function(task) {
            var route = this;
            App.Task.find(task.get('id')).then(function(task) {
                App.Project.find(task.get('project.id')).then(function(project) {
                    route.transitionTo('project', project);
                    route.transitionTo('projectTask', task);
                });
            });
        },
        showNews: function(news_id) {
            var route = this;
            App.News.find(news_id).then(function(news) {
                route.transitionTo('newsItem', news);
                window.scrollTo(0, 0);
            });
        },
        showPage: function(page_id) {
            var route = this;
            App.Page.find(page_id).then(function(page) {
                route.transitionTo('page', page);
                window.scrollTo(0, 0);
            });
        },

        addDonation: function (project) {
            var route = this;
            App.CurrentOrder.find('current').then(function(order) {
                var store = route.get('store');
                var donation = store.createRecord(App.CurrentOrderDonation);
                donation.set('project', project);
                donation.set('order', order);
                donation.save();
                route.transitionTo('currentOrder.donationList');
            });
        }
    },

    urlForEvent: function(actionName, context) {
        return "/nice/stuff"
    }
});

App.UserIndexRoute = Em.Route.extend({
    beforeModel: function() {
        this.transitionTo('userProfile');
    }
});

// TODO Delete this Route when we implement Order history.
App.UserRoute = Em.Route.extend({
    setupController: function(controller, model) {
        this._super(controller, model);

        return App.RecurringDirectDebitPayment.find({}).then(function(recurringPayments) {
            controller.set('showPaymentsTab', recurringPayments.get('length') > 0)
        });
    }
});

/* Home Page */

App.HomeRoute = Em.Route.extend({

    /* COMMENTED FOR MODULARIZATION
     *
    model: function(params) {
        return App.HomePage.find(App.get('language'));
    },

    setupController: function(controller, model) {
        this._super(controller, model);
        controller.set('projectIndex', 0).loadProject();
        controller.set('quoteIndex', 0).loadQuote();
    }
    *
    */
});

/* Views */

App.LanguageView = Em.View.extend({
    templateName: 'language',
    classNameBindings: ['isSelected:active'],
    isSelected: function(){
        if (this.get('content.code') == App.language) {
            return true;
        }
        return false;
    }.property('content.code')

});

App.LanguageSwitchView = Em.CollectionView.extend({
    tagName: 'ul',
    classNames: ['nav-language'],
    content: App.interfaceLanguages,
    itemViewClass: App.LanguageView
});

App.ApplicationView = Em.View.extend({
    elementId: 'site'
});

<commit_msg>General `apps` cleaning.<commit_after>App = Em.Application.create({
    VERSION: '1.0.0',

    // TODO: Remove this in production builds.
    LOG_TRANSITIONS: true,

    // We store language & locale here because they need to be available before loading templates.
    language: 'en',
    locale: 'en-GB',
    interfaceLanguages: [
        Em.Object.create({name:'English', code: 'en'}),
        Em.Object.create({name:'Nederlands', code: 'nl'})
    ],

    ready: function() {
        // Read language string from url.
        var language = window.location.pathname.split('/')[1];
        App.CurrentUser.find('current').then(function(user){
            var primaryLanguage = user.get('primary_language');
            if (primaryLanguage && primaryLanguage != language) {
                document.location = '/' + primaryLanguage + document.location.hash;
            }
        });
        // We don't have to check if it's one of the languages available. Django will have thrown an error before this.
        this.set('language', language);

        // Now that we know the language we can load the handlebars templates.
        //this.loadTemplates(this.templates);

        // Read locale from browser with fallback to default.
        var locale = navigator.language || navigator.userLanguage || this.get('locale');
        if (locale.substr(0, 2) != language) {
            // Some overrides to have a sound experience, at least for dutch speaking and dutch based users.

            if (language == 'nl') {
                // For dutch language always overwrite locale. Always use dutch locale.
                locale = 'nl';
            }
            if (language == 'en' && locale.substr(0, 2) == 'nl') {
                // For dutch browser viewing english site overwrite locale.
                // We don't want to have dutch fuzzy dates.
                // If fuzzy dates are translated in other languages we should decide if we want to show those.
                locale = 'en';
            }
        }

        this.initSelectViews();
        this.setLocale(locale);
        this.initSelectViews();
    },

    initSelectViews: function() {
        // Pre-load these lists so we avoid race conditions when displaying forms
        App.Theme.find().then(function(list) {
            App.ThemeSelectView.reopen({
                content: list
            });
        });

        App.Country.find().then(function(list) {
            App.CountrySelectView.reopen({
                content: list
            });
            App.CountryCodeSelectView.reopen({
                content: list
            });
        });
        // Get a filtered list of countries that can apply for a project ('oda' countries).
        var filteredList = App.Country.filter(function(item) {return item.get('oda')});

        App.ProjectCountrySelectView.reopen({
            content: filteredList
        });
    },

    setLocale: function(locale) {
        if (!locale) {
            locale = this.get('locale');
        }

        if (locale != 'en-US') {
            // Try to load locale specifications.
            $.getScript('/static/assets/js/vendor/globalize-cultures/globalize.culture.' + locale + '.js')
                .fail(function() {
                    if (window.console) {
                        console.log("No globalize culture file for : "+ locale);
                    }
                    // Specified locale file not available. Use default locale.
                    locale = App.get('locale');
                    Globalize.culture(locale);
                    App.set('locale', locale);
                })
                .success(function() {
                    // Specs loaded. Enable locale.
                    Globalize.culture(locale);
                    App.set('locale', locale);
                });
            $.getScript('/static/assets/js/vendor/jquery-ui/i18n/jquery.ui.datepicker-' + locale.substr(0, 2) + '.js')
                .fail(function() {
                    if (window.console) {
                        console.log("No jquery.ui.datepicker file for : "+ locale);
                    }
                    // Specified locale file not available. Use default locale.
                    locale = App.get('locale');
                    Globalize.culture(locale);
                    App.set('locale', locale);
                })
                .success(function() {
                    // Specs loaded. Enable locale.
                    App.set('locale', locale);
                });
        } else {
            Globalize.culture(locale);
            App.set('locale', locale);
        }
    }
});

/**
 * The Ember Data Adapter and Store configuration.
 */
App.Adapter = DS.DRF2Adapter.extend({
    namespace: "api",

    plurals: {
        "projects/manage": "projects/manage",
        "projects/pitches/manage": "projects/pitches/manage",
        "projects/plans/manage": "projects/plans/manage",
        "projects/campaigns/manage": "projects/campaigns/manage",
        "projects/wallposts/media": "projects/wallposts/media",
        "projects/wallposts/text": "projects/wallposts/text",
        "organizations/manage": "organizations/manage",
        "organizations/addresses/manage": "organizations/addresses/manage",
        "organizations/documents/manage": "organizations/documents/manage",
        "projects/ambassadors/manage": "projects/ambassadors/manage",
        "projects/budgetlines/manage": "projects/budgetlines/manage",
        "users/activate": "users/activate",
        "users/passwordset": "users/passwordset",
        "homepage": "homepage",
        "pages/contact": "pages/contact"
    }
});

// Assigning plurals for model properties doesn't seem to work with extend, it does this way:
App.Adapter.configure("plurals", {
    "address": "addresses"
});

App.ApplicationController = Ember.Controller.extend({
    needs: ['currentUser'],
    display_message: false,

    displayMessage: (function() {
        if (this.get('display_message') == true) {
            Ember.run.later(this, function() {
                this.hideMessage();
            }, 10000);
        }
    }).observes('display_message'),

    hideMessage: function() {
        this.set('display_message', false);
    }
});

// Embedded Model Mapping
//
// http://stackoverflow.com/questions/14320925/how-to-make-embedded-hasmany-relationships-work-with-ember-data/14324532#14324532
// The two possible values of embedded are:
//   load: The child records are embedded when loading, but should be saved as standalone records. In order
//         for this to work, the child records must have an ID.
//   always: The child records are embedded when loading, and are saved embedded in the same record. This,
//           of course, affects the dirtiness of the records (if the child record changes, the adapter will
//           mark the parent record as dirty).

App.Store = DS.Store.extend({
    adapter: 'App.Adapter'
});

/* Routing */

App.SlugRouter = Em.Mixin.create({
    serialize: function(model, params) {
        if (params.length !== 1) { return {}; }

        var name = params[0], object = {};
        object[name] = get(model, 'slug');

        return object;
    }
});

App.Router.reopen({
    location: 'hashbang'
});

App.Router.reopen({
    /**
     * Tracks pageviews if google analytics is used
     * Source: http://www.randomshouting.com/2013/05/04/Ember-and-Google-Analytics.html
     */
    didTransition: function(infos) {
        this._super(infos);
        if (window._gaq === undefined) { return; }

        Ember.run.next(function(){
            _gaq.push(['_trackPageview', window.location.hash.substr(1)]);
        });
    }
});

App.Router.reopen({
    didTransition: function(infos) {
        this._super(infos);
        Ember.run.next(function() {
            // the meta module will now go trough the routes and look for data
            App.meta.trigger('reloadDataFromRoutes');
        });
    }
});

DS.Model.reopen({
    meta: DS.attr('object')
});

Em.Route.reopen({
    meta_data: function(){
        return this.get('context.meta_data');
    }.property('context.meta_data')
});

App.Router.map(function() {

    this.resource('language', {path:'/:lang'});

    // Fix for Facebook login
    this.route("home", { path: "_=_" });

    this.route("home", { path: "/" });

    this.resource('error', {path: '/error'}, function() {
        this.route('notFound', {path: '/not-found'});
        this.route('notAllowed', {path: '/not-allowed'});
    });

    this.resource('page', {path: '/pages/:page_id'});
    this.resource('contactMessage', {path: '/contact'});

});

App.ApplicationRoute = Em.Route.extend({
    needs: ['currentUser'],

    actions: {
        selectLanguage: function(language) {
            var user = App.CurrentUser.find('current');
            if (!user.get('id_for_ember')) {
                if (language == App.get('language')) {
                    // Language already set. Don't do anything;
                    return true;
                }
                document.location = '/' + language + document.location.hash;
            }

            App.UserSettings.find(App.CurrentUser.find('current').get('id_for_ember')).then(function(settings){
                if (language == App.get('language')) {
                    // Language already set. Don't do anything;
                    return true;
                }

                if (settings.get('id')) {
                    settings.save();
                }
                var languages = App.get('interfaceLanguages');
                for (i in languages) {
                    // Check if the selected language is available.
                    if (languages[i].code == language) {
                        if (settings.get('id')) {
                            settings.set('primary_language', language);
                        }
                        settings.on('didUpdate', function(){
                            document.location = '/' + language + document.location.hash;
                        });
                        settings.save();
                        return true;
                    }
                }
                language = 'en';
                if (settings.get('id')) {
                    settings.set('primary_language', language);
                }

                settings.on('didUpdate', function(){
                    document.location = '/' + language + document.location.hash;
                });
                settings.save();
                return true;
            });
            return true;
        },

        openInBigBox: function(name, context) {
            // Close all other modals.
            $('.close-modal').click();

            // Get the controller or create one
            var controller = this.controllerFor(name);
            controller.set('model', context);

            // Get the view. This should be defined.
            var view = App[name.classify() + 'View'].create();
            view.set('controller', controller);

            var modalPaneTemplate = ['
×{{view view.bodyViewClass}}
'].join("\n");

            Bootstrap.ModalPane.popup({
                classNames: ['modal', 'large'],
                defaultTemplate: Em.Handlebars.compile(modalPaneTemplate),
                bodyViewClass: view,
                secondary: 'Close'
            });

        },
        openInBox: function(name, context) {
            // Close all other modals.
            $('.close-modal').click();

            // Get the controller or create one
            var controller = this.controllerFor(name);
            if (context) {
                controller.set('model', context);
            }

            // Get the view. This should be defined.
            var view = App[name.classify() + 'View'].create();
            view.set('controller', controller);

            var modalPaneTemplate = ['
×{{view view.bodyViewClass}}
'].join("\n");

            Bootstrap.ModalPane.popup({
                classNames: ['modal'],
                defaultTemplate: Em.Handlebars.compile(modalPaneTemplate),
                bodyViewClass: view
            });

        },
        closeAllModals: function(){
            $('.close-modal').click();
        },
        showProject: function(project_id) {
            var route = this;
            App.Project.find(project_id).then(function(project) {
                route.transitionTo('project', project);
            });
        },
        showProjectTaskList: function(project_id) {
            var route = this;
            App.Project.find(project_id).then(function(project) {
                route.transitionTo('project', project);
                route.transitionTo('projectTaskList');
            });
        },
        showTask: function(task) {
            var route = this;
            App.Task.find(task.get('id')).then(function(task) {
                App.Project.find(task.get('project.id')).then(function(project) {
                    route.transitionTo('project', project);
                    route.transitionTo('projectTask', task);
                });
            });
        },
        showNews: function(news_id) {
            var route = this;
            App.News.find(news_id).then(function(news) {
                route.transitionTo('newsItem', news);
                window.scrollTo(0, 0);
            });
        },
        showPage: function(page_id) {
            var route = this;
            App.Page.find(page_id).then(function(page) {
                route.transitionTo('page', page);
                window.scrollTo(0, 0);
            });
        },

        addDonation: function (project) {
            var route = this;
            App.CurrentOrder.find('current').then(function(order) {
                var store = route.get('store');
                var donation = store.createRecord(App.CurrentOrderDonation);
                donation.set('project', project);
                donation.set('order', order);
                donation.save();
                route.transitionTo('currentOrder.donationList');
            });
        }
    },

    urlForEvent: function(actionName, context) {
        return "/nice/stuff"
    }
});

App.UserIndexRoute = Em.Route.extend({
    beforeModel: function() {
        this.transitionTo('userProfile');
    }
});

// TODO Delete this Route when we implement Order history.
App.UserRoute = Em.Route.extend({
    setupController: function(controller, model) {
        this._super(controller, model);

        return App.RecurringDirectDebitPayment.find({}).then(function(recurringPayments) {
            controller.set('showPaymentsTab', recurringPayments.get('length') > 0)
        });
    }
});

/* Views */

App.LanguageView = Em.View.extend({
    templateName: 'language',
    classNameBindings: ['isSelected:active'],
    isSelected: function(){
        if (this.get('content.code') == App.language) {
            return true;
        }
        return false;
    }.property('content.code')

});

App.LanguageSwitchView = Em.CollectionView.extend({
    tagName: 'ul',
    classNames: ['nav-language'],
    content: App.interfaceLanguages,
    itemViewClass: App.LanguageView
});

App.ApplicationView = Em.View.extend({
    elementId: 'site'
});

<|endoftext|>


<commit_before>export default class DomainMap {

    constructor(width, height, accessibilityFn) {
        this._width = width;
        this._height = height;
        this._accessibilityFn = accessibilityFn;
        this._domains = [];
        this._domainMap = [];
        this._domainMappings = {};

        this._buildDomainMap();
    }

    getDomains() {
        return this._domains;
    }

    /*
     * Build the domain map.
     */
    _buildDomainMap() {
        let idx = 1;

        this._domainMappings[-1] = -1;

        for (let x = 0; x < this._width; x++) {
            this._domainMap[x] = [];
            for (let y = 0; y < this._height; y++) {
                let domain = -1;

                // Nothing to do if the field is not accessible
                if (this._accessibilityFn(x, y)) {
                    let otherDomain;

                    // Has the field left of us a domain assigned?
                    otherDomain = this.getDomain(x - 1, y);
                    if (x > 0 && otherDomain > 0) {
                        // -> Inherit the domain
                        domain = otherDomain;
                    }

                    // Has the field above us a domain assigned?
                    otherDomain = this.getDomain(x, y - 1);
                    if (y > 0 && otherDomain > 0) {
                        // We still have no domain -> inherit from above
                        if (domain < 0) {
                            domain = otherDomain;
                        // We have a domain -> conflict?
                    } else if (domain !== otherDomain) {
                            // Conflict! -> identify the two domains
                            this._identifyDomains(domain, otherDomain);
                        }
                    }
                    // Still no domain? Start a new one
                    if (domain < 0) {
                        domain = idx++;
                        this._addDomain(domain);
                    }
                }
                this._domainMap[x][y] = domain;
            }
        }
    }

    /**
     * Get the domain of a given position. Recursively resolves all mapping relations and stores the result
     * back in the map --- this improves lookup speed.
     */
    getDomain(x, y) {
        let domain = this._domainMap[x][y];

        while (this._domainMappings[domain] !== domain) {
            domain = this._domainMappings[domain];
        }
        this._domainMap[x][y] = domain;

        return domain;
    }

    /**
     * Add a new domain.
     */
    _addDomain(domain) {
        this._domains.push(domain);
        this._domainMappings[domain] = domain;
    }

    /**
     * Identify two domains by removing domain2 from the domain list and setting up a mapping between the two.
     */
    _identifyDomains(domain1, domain2) {
        this._domains = this._domains.filter(d => d !==domain2);
        this._domainMappings[domain2] = domain1;
    }

    /**
     * Find a field in a given domain.
     */
    findFieldInDomain(domain) {
        for (let x = 0; x < this._width; x++) {
            for (let y = 0; y < this._height; y++) {
                if (this.getDomain(x, y) === domain) {
                    return {x: x, y: y};
                }
            }
        }

        return null;
    }

}
<commit_msg>Whitespace.<commit_after>export default class DomainMap {

    constructor(width, height, accessibilityFn) {
        this._width = width;
        this._height = height;
        this._accessibilityFn = accessibilityFn;
        this._domains = [];
        this._domainMap = [];
        this._domainMappings = {};

        this._buildDomainMap();
    }

    getDomains() {
        return this._domains;
    }

    /*
     * Build the domain map.
     */
    _buildDomainMap() {
        let idx = 1;

        this._domainMappings[-1] = -1;

        for (let x = 0; x < this._width; x++) {
            this._domainMap[x] = [];
            for (let y = 0; y < this._height; y++) {
                let domain = -1;

                // Nothing to do if the field is not accessible
                if (this._accessibilityFn(x, y)) {
                    let otherDomain;

                    // Has the field left of us a domain assigned?
                    otherDomain = this.getDomain(x - 1, y);
                    if (x > 0 && otherDomain > 0) {
                        // -> Inherit the domain
                        domain = otherDomain;
                    }

                    // Has the field above us a domain assigned?
                    otherDomain = this.getDomain(x, y - 1);
                    if (y > 0 && otherDomain > 0) {
                        // We still have no domain -> inherit from above
                        if (domain < 0) {
                            domain = otherDomain;
                        // We have a domain -> conflict?
                    } else if (domain !== otherDomain) {
                            // Conflict! -> identify the two domains
                            this._identifyDomains(domain, otherDomain);
                        }
                    }
                    // Still no domain? Start a new one
                    if (domain < 0) {
                        domain = idx++;
                        this._addDomain(domain);
                    }
                }
                this._domainMap[x][y] = domain;
            }
        }
    }

    /**
     * Get the domain of a given position. Recursively resolves all mapping relations and stores the result
     * back in the map --- this improves lookup speed.
     */
    getDomain(x, y) {
        let domain = this._domainMap[x][y];

        while (this._domainMappings[domain] !== domain) {
            domain = this._domainMappings[domain];
        }
        this._domainMap[x][y] = domain;

        return domain;
    }

    /**
     * Add a new domain.
     */
    _addDomain(domain) {
        this._domains.push(domain);
        this._domainMappings[domain] = domain;
    }

    /**
     * Identify two domains by removing domain2 from the domain list and setting up a mapping between the two.
     */
    _identifyDomains(domain1, domain2)  {
        this._domains = this._domains.filter(d => d !== domain2);
        this._domainMappings[domain2] = domain1;
    }

    /**
     * Find a field in a given domain.
     */
    findFieldInDomain(domain) {
        for (let x = 0; x < this._width; x++) {
            for (let y = 0; y < this._height; y++) {
                if (this.getDomain(x, y) === domain) {
                    return {x: x, y: y};
                }
            }
        }

        return null;
    }

}
<|endoftext|>


<commit_before>$(function() {

	// Initialize pager
	var pager = $('#pager');
	pager.pager('init', [ 'Description', 'Submitted on', 'Status', 'Progress', 'Result' ], function(job) {
		var status, progress, result = '';
		if (!job.scheduled) {
			status = 'Queued for execution';
			progress = 0;
		} else if (!job.done) {
			status = 'Execution in progress';
			progress = 0//job.generation / job.num_generations;
		} else {
			status = 'Done on ' + $.format.date(new Date(job.done), 'yyyy/MM/dd HH:mm:ss');
			progress = 1;
			result += '';
		}
		return [
			job.description,
			$.format.date(new Date(job.submitted), 'yyyy/MM/dd HH:mm:ss'),
			status,
			(100 * progress).toFixed(5) + '%',
			result
		];
	});

	// Refresh the table of jobs and its pager every second
	var jobs = [], skip = 0;
	var tick = function() {
		$.get('jobs', { skip: skip, count: jobs.length }, function(res) {
			if (res.length) {
				for (var i = skip; i < jobs.length; ++i) {
					var job = res[i - skip];
					jobs[i].done = job.done;
				}
				pager.pager('refresh', skip, jobs.length, 2, 5, false);
				if (res.length > jobs.length - skip) {
					var len = jobs.length;
					jobs = jobs.concat(res.slice(jobs.length - skip));
					pager.pager('source', jobs);
					pager.pager('refresh', len, jobs.length, 0, 5, true);
				}
				for (; skip < jobs.length && jobs[skip].done; ++skip);
			}
			setTimeout(tick, 1000);
		});
	};
	tick();

	// Initialize sliders
	$('#mms').slider({
		range: true,
		min: 0,
		max: 1000,
		values: [ 300, 500 ]
	});
	$('#nrb').slider({
		range: true,
		min: 0,
		max: 35,
		values: [ 4, 6 ]
	});
	$('#hbd').slider({
		range: true,
		min: 0,
		max: 20,
		values: [ 2, 4 ]
	});
	$('#hba').slider({
		range: true,
		min: 0,
		max: 18,
		values: [ 4, 6 ]
	});
	['mms', 'nrb', 'hbd', 'hba'].forEach(function(key) {
		var values = $('#' + key).slider('option', 'values');
		$('#' + key + '_lb').text(values[0]);
		$('#' + key + '_ub').text(values[1]);
	});
	$('.slider').slider({
		slide: function(event, ui) {
			$('#' + this.id + '_lb').text(ui.values[0]);
			$('#' + this.id + '_ub').text(ui.values[1]);
		},
	});

	// Initialize tooltips
	$('.form-group a').tooltip();

	// Process submission
	var submit = $('#submit');
	submit.click(function() {
		// Hide tooltips
		$('.form-group a').tooltip('hide');
		// Disable the submit button for a while
		submit.prop('disabled', true);
		// Post a new job with server side validation
		$.post('jobs', {
			idock: idockJobId,
		}, function(res) {
			var keys = Object.keys(res);
			// If server side validation fails, show the tooltips
			if (keys.length) {
				keys.forEach(function(key) {
					$('#' + key + '_label').tooltip('show');
				});
			} else {
				$('html, body').animate({ scrollTop: pager.offset().top });
//				window.scrollTo(pager.offset().left, pager.offset().top);
			}
		}, 'json').always(function() {
			submit.prop('disabled', false);
		});
	});

	// Apply accordion to tutorials
	$('.ui-accordion').accordion({
		collapsible: true,
		active: false,
		heightStyle: 'content',
		activate: function(event, ui) {
			$('img', this).trigger('expand');
		}
	});
	$('.ui-accordion img').lazyload({
		event: 'expand',
		effect: 'fadeIn',
	});

	var idockJobId = location.search.substr(1);
	var v = new validator({ id: idockJobId });
	if (v
		.field('id').message('must be a valid object id').objectid().copy()
		.failed()) {
		// Disable the submit button
		submit.prop('disabled', true);
		return;
	};
	$.get('/idock/job', {
		id: idockJobId,
	}, function(res) {
		var keys = Object.keys(res);
		if (keys.length) {
			keys.forEach(function(key) {
				$('#' + key).val(res[key]);
			});
		} else {
			submit.prop('disabled', false);
		}
	}, 'json');
});
<commit_msg>Added stub fields to $.post('jobs')<commit_after>$(function() {

	// Initialize pager
	var pager = $('#pager');
	pager.pager('init', [ 'Description', 'Submitted on', 'Status', 'Progress', 'Result' ], function(job) {
		var status, progress, result = '';
		if (!job.scheduled) {
			status = 'Queued for execution';
			progress = 0;
		} else if (!job.done) {
			status = 'Execution in progress';
			progress = 0//job.generation / job.num_generations;
		} else {
			status = 'Done on ' + $.format.date(new Date(job.done), 'yyyy/MM/dd HH:mm:ss');
			progress = 1;
			result += '';
		}
		return [
			job.description,
			$.format.date(new Date(job.submitted), 'yyyy/MM/dd HH:mm:ss'),
			status,
			(100 * progress).toFixed(5) + '%',
			result
		];
	});

	// Refresh the table of jobs and its pager every second
	var jobs = [], skip = 0;
	var tick = function() {
		$.get('jobs', { skip: skip, count: jobs.length }, function(res) {
			if (res.length) {
				for (var i = skip; i < jobs.length; ++i) {
					var job = res[i - skip];
					jobs[i].done = job.done;
				}
				pager.pager('refresh', skip, jobs.length, 2, 5, false);
				if (res.length > jobs.length - skip) {
					var len = jobs.length;
					jobs = jobs.concat(res.slice(jobs.length - skip));
					pager.pager('source', jobs);
					pager.pager('refresh', len, jobs.length, 0, 5, true);
				}
				for (; skip < jobs.length && jobs[skip].done; ++skip);
			}
			setTimeout(tick, 1000);
		});
	};
	tick();

	// Initialize sliders
	$('#mms').slider({
		range: true,
		min: 0,
		max: 1000,
		values: [ 300, 500 ]
	});
	$('#nrb').slider({
		range: true,
		min: 0,
		max: 35,
		values: [ 4, 6 ]
	});
	$('#hbd').slider({
		range: true,
		min: 0,
		max: 20,
		values: [ 2, 4 ]
	});
	$('#hba').slider({
		range: true,
		min: 0,
		max: 18,
		values: [ 4, 6 ]
	});
	['mms', 'nrb', 'hbd', 'hba'].forEach(function(key) {
		var values = $('#' + key).slider('option', 'values');
		$('#' + key + '_lb').text(values[0]);
		$('#' + key + '_ub').text(values[1]);
	});
	$('.slider').slider({
		slide: function(event, ui) {
			$('#' + this.id + '_lb').text(ui.values[0]);
			$('#' + this.id + '_ub').text(ui.values[1]);
		},
	});

	// Initialize tooltips
	$('.form-group a').tooltip();

	// Process submission
	var submit = $('#submit');
	submit.click(function() {
		// Hide tooltips
		$('.form-group a').tooltip('hide');
		// Disable the submit button for a while
		submit.prop('disabled', true);
		// Post a new job with server side validation
		$.post('jobs', {
			idock_id: idockJobId,
			description: '',
			email: '',
			mms_lb: '',
			mms_ub: '',
			nrb_lb: '',
			nrb_ub: '',
			hbd_lb: '',
			hbd_ub: '',
			hba_lb: '',
			hba_ub: '',
		}, function(res) {
			var keys = Object.keys(res);
			// If server side validation fails, show the tooltips
			if (keys.length) {
				keys.forEach(function(key) {
					$('#' + key + '_label').tooltip('show');
				});
			} else {
				$('html, body').animate({ scrollTop: pager.offset().top });
//				window.scrollTo(pager.offset().left, pager.offset().top);
			}
		}, 'json').always(function() {
			submit.prop('disabled', false);
		});
	});

	// Apply accordion to tutorials
	$('.ui-accordion').accordion({
		collapsible: true,
		active: false,
		heightStyle: 'content',
		activate: function(event, ui) {
			$('img', this).trigger('expand');
		}
	});
	$('.ui-accordion img').lazyload({
		event: 'expand',
		effect: 'fadeIn',
	});

	var idockJobId = location.search.substr(1);
	var v = new validator({ id: idockJobId });
	if (v
		.field('id').message('must be a valid object id').objectid().copy()
		.failed()) {
		// Disable the submit button
		submit.prop('disabled', true);
		return;
	};
	$.get('/idock/job', {
		id: idockJobId,
	}, function(res) {
		var keys = Object.keys(res);
		if (keys.length) {
			keys.forEach(function(key) {
				$('#' + key).val(res[key]);
			});
		} else {
			submit.prop('disabled', false);
		}
	}, 'json');
});
<|endoftext|>


<commit_before>mi2JS.listen(window,'load',function(evt){
	mi2JS.listen(document.body,'mousedown',function(evt){
		if(evt.ctrlKey){
			var p = evt.target;

			console.log('...........');
			console.log('dump component path from ', p);
			console.log('...........');

			var hasComp, idx;
			var lines = [];
			var path = '';
			// collect components from child clicked to MAIN_APP
			while(p){
				var comp = p.getAttribute('as');
				var prop = p.__propPath || p.getAttribute('p');
				if(comp == 'MainApp') prop = "MAIN_APP"; // the top

				// compose path to access the component via global MAIN_APP
				if(prop && (comp || !hasComp)){
					// simple binding is allowed only once and only as top level
					if(!comp && ! hasComp) path = '';

					idx = prop.indexOf('.');// conver aa.1 to aa[1]

					if(path) path = '.'+path;
					if(idx != -1){
						var left = prop.substring(0,idx);
						var right = prop.substring(idx+1);
						prop = left +'.items';
						if(mi2JS.num(right))
							prop +='['+right+']';
						else
							prop += '.'+right;
					}
					path = prop+path;
					hasComp = hasComp || comp;
				}

				if(comp || prop){
					if(!comp) prop = '    '+prop;
					lines.push([prop ||'', comp || '', p]);
				}

				if(p.tagName == 'BODY' || prop == 'MAIN_APP') break;
				p=p.parentNode;
			}
			var max = [0,0];
			var len = 0, i,c;
			for(i=0; i<lines.length; i++){
				for(c=0; c<2; c++){
					max[c] = Math.max(max[c], lines[i][c].length);
				}
			}

			for(i=0; i<lines.length; i++){
				for(c=0; c<2; c++){
					len = lines[i][c].length;
					if(len < max[c]){
						for(var fill=len; fill<max[c]; fill ++) lines[i][c] +=' ';
					}
				}
				console.log(lines[i][0], lines[i][1], lines[i][2]);
			}
			console.log(path);
			console.log('...........');
		}
	});
});
<commit_msg>fix comp dump property path generated<commit_after>mi2JS.listen(window,'load',function(evt){
	mi2JS.listen(document.body,'mousedown',function(evt){
		if(evt.ctrlKey){
			var p = evt.target;

			console.log('...........');
			console.log('dump component path from ', p);
			console.log('...........');

			var hasComp, idx;
			var lines = [];
			var path = '';
			// collect components from child clicked to MAIN_APP
			while(p){
				var comp = p.getAttribute('as');
				var prop = p.__propPath || p.getAttribute('p');
				if(comp == 'MainApp') prop = "MAIN_APP"; // the top

				// compose path to access the component via global MAIN_APP
				if(prop && (comp || !hasComp)){
					// simple binding is allowed only once and only as top level
					if(!comp && ! hasComp) path = '';

					idx = prop.indexOf('.');// conver aa.1 to aa[1]

					if(path) path = '.'+path;
					if(idx != -1){
						var left = prop.substring(0,idx);
						var right = prop.substring(idx+1);
						prop = left;
						if(mi2JS.num(right))
							prop +='['+right+']';
						else
							prop += '.'+right;
					}
					path = prop+path;
					hasComp = hasComp || comp;
				}

				if(comp || prop){
					if(!comp) prop = '    '+prop;
					lines.push([prop ||'', comp || '', p]);
				}

				if(p.tagName == 'BODY' || prop == 'MAIN_APP') break;
				p=p.parentNode;
			}
			var max = [0,0];
			var len = 0, i,c;
			for(i=0; i<lines.length; i++){
				for(c=0; c<2; c++){
					max[c] = Math.max(max[c], lines[i][c].length);
				}
			}

			for(i=0; i<lines.length; i++){
				for(c=0; c<2; c++){
					len = lines[i][c].length;
					if(len < max[c]){
						for(var fill=len; fill<max[c]; fill ++) lines[i][c] +=' ';
					}
				}
				console.log(lines[i][0], lines[i][1], lines[i][2]);
			}
			console.log(path);
			console.log('...........');
		}
	});
});
<|endoftext|>


<commit_before>import { desiredPropMap } from './design-properties'

export const getStyle = (el, name) => {
  if (document.defaultView && document.defaultView.getComputedStyle) {
    name = name.replace(/([A-Z])/g, '-$1')
    name = name.toLowerCase()
    let s = document.defaultView.getComputedStyle(el, '')
    return s && s.getPropertyValue(name)
  }
}

export const getStyles = el => {
  const elStyleObject = el.style
  const computedStyle = window.getComputedStyle(el, null)
  const vettedStyles = []
  const borders = []

  for (const prop in el.style) {
    const is_desired = desiredPropMap[prop]

    if (is_desired && is_desired != computedStyle[prop])
      vettedStyles.push({
        prop: prop,
        value: computedStyle[prop],
      })

    if (prop === 'borderColor' || prop === 'borderWidth' || prop === 'borderStyle')
      borders[prop] = computedStyle[prop].replace(/, rgba/g, '\rrgba')
  }

  const { borderColor, borderWidth, borderStyle } = borders

  if (parseInt(borderWidth) > 0) {
    vettedStyles.push({
      prop: 'borderColor',
      value: borderColor,
    })

    vettedStyles.push({
      prop: 'borderStyle',
      value: borderStyle,
    })
  }

  return vettedStyles.sort(function({prop:propA}, {prop:propB}) {
    if (propA < propB) return -1
    if (propA > propB) return 1
    return 0
  })
}

export const getComputedBackgroundColor = el => {
  let background = getStyle(el, 'background-color')

  if (background === 'rgba(0, 0, 0, 0)') {
    let node  = findNearestParentElement(el)
      , found = false

    if (node.nodeName === 'HTML') {
      found = true
      background = 'white'
    }

    while(!found) {
      let bg  = getStyle(node, 'background-color')

      if (bg !== 'rgba(0, 0, 0, 0)') {
        found = true
        background = bg
      }

      node = findNearestParentElement(node)
    }
  }

  return background
}

export const findNearestParentElement = el =>
  el.parentNode && el.parentNode.nodeType === 1
    ? el.parentNode
    : el.parentNode.nodeName === '#document-fragment'
      ? el.parentNode.host
      : el.parentNode.parentNode.host

export const findNearestChildElement = el => {
  if (el.shadowRoot && el.shadowRoot.children.length) {
    return [...el.shadowRoot.children]
      .filter(({nodeName}) =>
        !['LINK','STYLE','SCRIPT','HTML','HEAD'].includes(nodeName)
      )[0]
  }
  else if (el.children.length)
    return el.children[0]
}

export const loadStyles = async stylesheets => {
  const fetches = await Promise.all(stylesheets.map(url => fetch(url)))
  const texts   = await Promise.all(fetches.map(url => url.text()))
  const style   = document.createElement('style')

  style.textContent = texts.reduce((styles, fileContents) =>
    styles + fileContents
  , '')

  document.head.appendChild(style)
}

// returns [full, color, x, y, blur, spread]
export const getShadowValues = shadow =>
  /([^\)]+\)) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)/.exec(shadow)

// returns [full, color, x, y, blur]
export const getTextShadowValues = shadow =>
  /([^\)]+\)) ([^\s]+) ([^\s]+) ([^\s]+)/.exec(shadow)
<commit_msg>fixed #488<commit_after>import { desiredPropMap } from './design-properties'

export const getStyle = (el, name) => {
  if (document.defaultView && document.defaultView.getComputedStyle) {
    name = name.replace(/([A-Z])/g, '-$1')
    name = name.toLowerCase()
    let s = document.defaultView.getComputedStyle(el, '')
    return s && s.getPropertyValue(name)
  }
}

export const getStyles = el => {
  const elStyleObject = el.style
  const computedStyle = window.getComputedStyle(el, null)
  const vettedStyles = []
  const borders = []

  for (const prop in el.style) {
    const is_desired = desiredPropMap[prop]

    if (is_desired && is_desired != computedStyle[prop])
      vettedStyles.push({
        prop: prop,
        value: computedStyle[prop],
      })

    if (prop === 'borderColor' || prop === 'borderWidth' || prop === 'borderStyle')
      borders[prop] = computedStyle[prop].replace(/, rgba/g, '\rrgba')
  }

  const { borderColor, borderWidth, borderStyle } = borders

  if (parseInt(borderWidth) > 0) {
    vettedStyles.push({
      prop: 'borderColor',
      value: borderColor,
    })

    vettedStyles.push({
      prop: 'borderStyle',
      value: borderStyle,
    })
  }

  return vettedStyles.sort(function({prop:propA}, {prop:propB}) {
    if (propA < propB) return -1
    if (propA > propB) return 1
    return 0
  })
}

export const getComputedBackgroundColor = el => {
  let background = getStyle(el, 'background-color')

  if (background === 'rgba(0, 0, 0, 0)') {
    let node  = findNearestParentElement(el)
      , found = false

    while(!found) {
      let bg  = getStyle(node, 'background-color')

      if (node.nodeName === 'HTML') {
        found = true
        background = 'white'
      }

      if (bg !== 'rgba(0, 0, 0, 0)') {
        found = true
        background = bg
      }

      node = findNearestParentElement(node)
    }
  }

  return background
}

export const findNearestParentElement = el => {
  if (el.nodeName === 'HTML') return el

  return el.parentNode && el.parentNode.nodeType === 1
    ? el.parentNode
    : el.parentNode.nodeName === '#document-fragment'
      ? el.parentNode.host
      : el.parentNode.parentNode.host
}

export const findNearestChildElement = el => {
  if (el.shadowRoot && el.shadowRoot.children.length) {
    return [...el.shadowRoot.children]
      .filter(({nodeName}) =>
        !['LINK','STYLE','SCRIPT','HTML','HEAD'].includes(nodeName)
      )[0]
  }
  else if (el.children.length)
    return el.children[0]
}

export const loadStyles = async stylesheets => {
  const fetches = await Promise.all(stylesheets.map(url => fetch(url)))
  const texts   = await Promise.all(fetches.map(url => url.text()))
  const style   = document.createElement('style')

  style.textContent = texts.reduce((styles, fileContents) =>
    styles + fileContents
  , '')

  document.head.appendChild(style)
}

// returns [full, color, x, y, blur, spread]
export const getShadowValues = shadow =>
  /([^\)]+\)) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)/.exec(shadow)

// returns [full, color, x, y, blur]
export const getTextShadowValues = shadow =>
  /([^\)]+\)) ([^\s]+) ([^\s]+) ([^\s]+)/.exec(shadow)
<|endoftext|>


<commit_before>import fs from 'fs'
import mkdirp from 'mkdirp'
import each from 'lodash/each'
import partial from 'lodash/partial'
import some from 'lodash/some'
import reject from 'lodash/reject'
import assign from 'lodash/assign'
import once from 'lodash/once'
import {parallel} from 'async'
import request from 'request'
import urlUtils from 'url'
import debug from './debug'
import urlToPath from './urlToPath'

const debugApi = debug('api')
const debugJson = debug('json')
const debugMedia = debug('media')

const stripUrlParts = (url, ...rejects) => {
  const rejector = (part) => some(rejects, (r) => part.match(r))
  const parsed = urlUtils.parse(url)
  const newUrl = urlUtils.format(assign(parsed, {
    pathname: reject(parsed.pathname.split('/'), rejector).join('/')
  }))
  return url !== newUrl ? newUrl : null
}

const shouldWrite = ({debug, filepath, overwrite}, no, yes) => {
  fs.exists(filepath, (exists) => {
    if (exists && !overwrite) {
      debug(`Exists, skipping ${filepath}`)
      no()
    } else if (exists && overwrite) {
      debug(`Exists, overwriting ${filepath}`)
      yes()
    } else {
      debug(`Does not exist, writing ${filepath}`)
      yes()
    }
  })
}

export const saveJson = ({ig, jsonDir, refresh, full}) => (json, saveDone) => {
  const id = json.id
  const filepath = jsonDir(`${id}.json`)

  const writeIfNeeded = partial(shouldWrite, {debug: debugJson, filepath, overwrite: refresh}, saveDone)
  const writeFile = (data) => fs.writeFile(filepath, JSON.stringify(data), {encoding: 'utf8'}, saveDone)

  const fetchForPost = (fetch) => (cb) => ig[fetch](id, (err, res, remaining) => {
    debugApi(`API calls left ${remaining}`)
    if (err) {
      debugApi(`${fetch} API error ${err}`)
      return cb(err)
    }
    cb(null, res)
  })

  writeIfNeeded(() => {
    if (full) {
      // Full means we fetch likes and comments separately and add those
      // to the json payload that gets saved
      parallel({
        likes: fetchForPost('likes'),
        comments: fetchForPost('comments')
      }, (err, {likes, comments}) => {
        if (err) return saveDone(err)
        json.likes.data = likes
        json.comments.data = comments
        debugJson(`${id} likes count:${json.likes.count} data:${likes.length}`)
        debugJson(`${id} comments count:${json.comments.count} data:${comments.length}`)
        writeFile(json)
      })
    } else {
      writeFile(json)
    }
  })
}

export const saveMedia = ({mediaDir}) => (url, saveDone) => {
  // Make sure callback is always called once since we need both error and close events
  // https://github.com/caolan/async/issues/614#issuecomment-55045730
  const saveDoneOnce = once(saveDone)

  // The Instagram media files get saved to a location on disk that matches the
  // urls domain+path, so we need to make that directory and then save the file
  const {filepath, dirname} = urlToPath({mediaDir, url})

  // An Instagram media at a url should never change so we shouldn't ever
  // need to download it more than once
  const writeIfNeeded = partial(shouldWrite, {debug: debugMedia, filepath, overwrite: false}, saveDoneOnce)

  writeIfNeeded(() => {
    mkdirp(dirname, (err) => {
      if (err) {
        debugMedia(`Error creating dir ${dirname}: ${err}`)
        return saveDoneOnce(err)
      }
      request(url)
      .on('error', (err) => {
        debugMedia(`Error fetching media ${url}: ${err}`)
        saveDoneOnce(err)
      })
      .pipe(fs.createWriteStream(filepath))
      .on('close', saveDoneOnce)
    })
  })
}

export const fetchAndSave = ({jsonQueue, mediaQueue}, cb) => {
  let COUNT = 0

  // The callback passed to the function will be executed once
  // both json and media queues have been drained
  const onDrain = () => {
    if (mediaQueue.running() === 0 && jsonQueue.running() === 0) {
      cb()
    }
  }

  jsonQueue.drain = () => {
    debugJson('queue drain')
    onDrain()
  }

  mediaQueue.drain = () => {
    debugMedia('queue drain')
    onDrain()
  }

  const fetchMedia = (err, medias, pagination, remaining) => {
    debugApi(`API calls left ${remaining}`)

    if (err) {
      debugApi(`API error ${err}`)
      debugApi(err)
      debugApi(err.body)
      if (err.error_type === 'APINotAllowedError' || err.error_type === 'APINotFoundError') {
        debugApi('Its possible the user\'s account you are trying to download is private')
        debugApi('If you are running your Instagram client in Sandbox mode, make sure the user is added as a Sandbox user')
      }
    } else if (medias && medias.length) {
      COUNT += medias.length
      debugApi(`Fetched media ${medias.length}`)
      debugApi(`Fetched total ${COUNT}`)
      medias.forEach((media) => {
        // Special stuff for https://github.com/lukekarrys/instagram-download/issues/3
        if (media.images) {
          const {thumbnail, standard_resolution: standardResolution} = media.images
          if (thumbnail) {
            // high res uncropped
            // remove s150x150 and c0.134.1080.1080 from
            // t51.2885-15/s150x150/e35/c0.134.1080.1080/12725175_958336534244864_1369827234_n.jpg
            const highRes = stripUrlParts(thumbnail.url, /^s\d+x\d+$/, /^c\d+\.\d+\.\d+\.\d+$/)
            if (highRes) media.images.high_resolution = { url: highRes }
          }
          // high res cropped
          // remove s640x640 from
          // t51.2885-15/s640x640/sh0.08/e35/12502019_964211777003492_661892888_n.jpg
          if (standardResolution) {
            const highResCropped = stripUrlParts(standardResolution.url, /^s\d+x\d+$/)
            if (highResCropped) media.images.high_resolution_cropped = { url: highResCropped }
          }
        }
        jsonQueue.push(media)
        each(media.images, (img) => mediaQueue.push(img.url))
        each(media.videos, (video) => mediaQueue.push(video.url))
      })
    } else if (medias.length === 0 && COUNT === 0 && !pagination.next) {
      debugApi('No media')
      cb()
    }

    if (pagination) {
      debugApi(`Has next page ${!!pagination.next}`)
      pagination.next && pagination.next(fetchMedia)
    }
  }

  return fetchMedia
}
<commit_msg>use fs.access instead of fs.exists<commit_after>import fs from 'fs'
import mkdirp from 'mkdirp'
import each from 'lodash/each'
import partial from 'lodash/partial'
import some from 'lodash/some'
import reject from 'lodash/reject'
import assign from 'lodash/assign'
import once from 'lodash/once'
import {parallel} from 'async'
import request from 'request'
import urlUtils from 'url'
import debug from './debug'
import urlToPath from './urlToPath'

const debugApi = debug('api')
const debugJson = debug('json')
const debugMedia = debug('media')

const stripUrlParts = (url, ...rejects) => {
  const rejector = (part) => some(rejects, (r) => part.match(r))
  const parsed = urlUtils.parse(url)
  const newUrl = urlUtils.format(assign(parsed, {
    pathname: reject(parsed.pathname.split('/'), rejector).join('/')
  }))
  return url !== newUrl ? newUrl : null
}

const shouldWrite = ({debug, filepath, overwrite}, no, yes) => {
  fs.access(filepath, (err) => {
    if (!err && !overwrite) {
      debug(`Exists, skipping ${filepath}`)
      no()
    } else if (!err && overwrite) {
      debug(`Exists, overwriting ${filepath}`)
      yes()
    } else {
      debug(`Does not exist, writing ${filepath}`)
      yes()
    }
  })
}

export const saveJson = ({ig, jsonDir, refresh, full}) => (json, saveDone) => {
  const id = json.id
  const filepath = jsonDir(`${id}.json`)

  const writeIfNeeded = partial(shouldWrite, {debug: debugJson, filepath, overwrite: refresh}, saveDone)
  const writeFile = (data) => fs.writeFile(filepath, JSON.stringify(data), {encoding: 'utf8'}, saveDone)

  const fetchForPost = (fetch) => (cb) => ig[fetch](id, (err, res, remaining) => {
    debugApi(`API calls left ${remaining}`)
    if (err) {
      debugApi(`${fetch} API error ${err}`)
      return cb(err)
    }
    cb(null, res)
  })

  writeIfNeeded(() => {
    if (full) {
      // Full means we fetch likes and comments separately and add those
      // to the json payload that gets saved
      parallel({
        likes: fetchForPost('likes'),
        comments: fetchForPost('comments')
      }, (err, {likes, comments}) => {
        if (err) return saveDone(err)
        json.likes.data = likes
        json.comments.data = comments
        debugJson(`${id} likes count:${json.likes.count} data:${likes.length}`)
        debugJson(`${id} comments count:${json.comments.count} data:${comments.length}`)
        writeFile(json)
      })
    } else {
      writeFile(json)
    }
  })
}

export const saveMedia = ({mediaDir}) => (url, saveDone) => {
  // Make sure callback is always called once since we need both error and close events
  // https://github.com/caolan/async/issues/614#issuecomment-55045730
  const saveDoneOnce = once(saveDone)

  // The Instagram media files get saved to a location on disk that matches the
  // urls domain+path, so we need to make that directory and then save the file
  const {filepath, dirname} = urlToPath({mediaDir, url})

  // An Instagram media at a url should never change so we shouldn't ever
  // need to download it more than once
  const writeIfNeeded = partial(shouldWrite, {debug: debugMedia, filepath, overwrite: false}, saveDoneOnce)

  writeIfNeeded(() => {
    mkdirp(dirname, (err) => {
      if (err) {
        debugMedia(`Error creating dir ${dirname}: ${err}`)
        return saveDoneOnce(err)
      }
      request(url)
      .on('error', (err) => {
        debugMedia(`Error fetching media ${url}: ${err}`)
        saveDoneOnce(err)
      })
      .pipe(fs.createWriteStream(filepath))
      .on('close', saveDoneOnce)
    })
  })
}

export const fetchAndSave = ({jsonQueue, mediaQueue}, cb) => {
  let COUNT = 0

  // The callback passed to the function will be executed once
  // both json and media queues have been drained
  const onDrain = () => {
    if (mediaQueue.running() === 0 && jsonQueue.running() === 0) {
      cb()
    }
  }

  jsonQueue.drain = () => {
    debugJson('queue drain')
    onDrain()
  }

  mediaQueue.drain = () => {
    debugMedia('queue drain')
    onDrain()
  }

  const fetchMedia = (err, medias, pagination, remaining) => {
    debugApi(`API calls left ${remaining}`)

    if (err) {
      debugApi(`API error ${err}`)
      debugApi(err)
      debugApi(err.body)
      if (err.error_type === 'APINotAllowedError' || err.error_type === 'APINotFoundError') {
        debugApi('Its possible the user\'s account you are trying to download is private')
        debugApi('If you are running your Instagram client in Sandbox mode, make sure the user is added as a Sandbox user')
      }
    } else if (medias && medias.length) {
      COUNT += medias.length
      debugApi(`Fetched media ${medias.length}`)
      debugApi(`Fetched total ${COUNT}`)
      medias.forEach((media) => {
        // Special stuff for https://github.com/lukekarrys/instagram-download/issues/3
        if (media.images) {
          const {thumbnail, standard_resolution: standardResolution} = media.images
          if (thumbnail) {
            // high res uncropped
            // remove s150x150 and c0.134.1080.1080 from
            // t51.2885-15/s150x150/e35/c0.134.1080.1080/12725175_958336534244864_1369827234_n.jpg
            const highRes = stripUrlParts(thumbnail.url, /^s\d+x\d+$/, /^c\d+\.\d+\.\d+\.\d+$/)
            if (highRes) media.images.high_resolution = { url: highRes }
          }
          // high res cropped
          // remove s640x640 from
          // t51.2885-15/s640x640/sh0.08/e35/12502019_964211777003492_661892888_n.jpg
          if (standardResolution) {
            const highResCropped = stripUrlParts(standardResolution.url, /^s\d+x\d+$/)
            if (highResCropped) media.images.high_resolution_cropped = { url: highResCropped }
          }
        }
        jsonQueue.push(media)
        each(media.images, (img) => mediaQueue.push(img.url))
        each(media.videos, (video) => mediaQueue.push(video.url))
      })
    } else if (medias.length === 0 && COUNT === 0 && !pagination.next) {
      debugApi('No media')
      cb()
    }

    if (pagination) {
      debugApi(`Has next page ${!!pagination.next}`)
      pagination.next && pagination.next(fetchMedia)
    }
  }

  return fetchMedia
}
<|endoftext|>


<commit_before>import * as RepDataMap from 'app/utility/RepDataMap';

// no data and no active reps
export const isEmpty = (set) => {
    return hasEmptyData(set) && hasEmptyReps(set);
};

// no data and no reps at all
export const isUntouched = (set) => {
    return hasEmptyData(set) && hasNoReps(set);
};

export const hasAllFields = (set) => {
    if (set.exercise && set.weight && set.rpe && set.tags && set.tags.length > 0) {
        return true;
    }
    return false;
};

export const hasEmptyFields = (set) => {
    return !set.exercise && (!set.weight || set.weight === '') && (!set.rpe || set.rpe === '') && (!set.tags || set.tags === undefined || set.tags.length === 0);
};

export const hasEmptyData = (set) => {
    return hasEmptyFields(set) && !set.videoFileURL;
};

export const hasNoReps = (set) => {
    if (set.reps === null || set.reps === undefined) {
        return true;
    }
    return set.reps.length === 0;
};

export const hasEmptyReps = (set) => {
    if (hasNoReps(set)) {
        return true;
    }

    let activeRep = set.reps.find((rep) => { return rep.removed === false; });
    return activeRep === undefined;
};

// NOTE: this considers infinity / 0 invalid
export const usableReps = (set) => {
    return set.reps.filter(rep => !rep.removed && isRepUsable(rep));
};

export const hasUnremovedRep = (set) => {
    return set.reps.some(rep => !rep.removed);
};

// NOTE: this does not consider infinity / 0 invalid
export const validUnremovedReps = (set) => {
    return set.reps.filter(rep => rep.isValid && !rep.removed);
};

export const weightInLBs = (set) => {
    if (!set.hasOwnProperty('weight') || set.weight === null || !Number(set.weight)) {
        return null;
    } else if (set.metric === 'lbs') {
        return Number(set.weight);
    } else if (set.metric === 'kgs') {
        return Number(set.weight) * 2.20462262;
    } else {
        // should never reach here
        return null;
    }
};

export const weightInKGs = (set) => {
    if (!set.hasOwnProperty('weight') || set.weight === null || !Number(set.weight)) {
        return null;
    } else if (set.metric === 'kgs') {
        return Number(set.weight);
    } else if (set.metric === 'lbs') {
        return Number(set.weight) * 0.45359237;
    } else {
        // should never reach here
        return null;
    }
};

export const numFieldsEntered = (set) => {
    let fields = [set.exercise, set.weight, set.rpe, set.tags.length];
    let num_fields_entered = 0;

    fields.forEach((field) => {
        if (Boolean(field)) {
            num_fields_entered++;
        }
    });

    return num_fields_entered;
};

// NOTE: this does not consider infinity / 0 invalid
export const numValidUnremovedReps = (set) => validUnremovedReps(set).length;

// NOTE: this considers infinity / 0 invalid
export const numUsableReps = (set) => usableReps(set).length;

// NOTE: this considers infinity / 0 invalid
export const isRepUsable = (rep) => {
    if (!rep.isValid || !rep.data) {
        return false;
    }
    const velocity = RepDataMap.averageVelocity(rep.data); // this should always return a string
    const peakVelocity = RepDataMap.peakVelocity(rep.data);
    return isVelocityUsable(velocity) && isVelocityUsable(peakVelocity);
};

const isVelocityUsable = (velocity) => {
    return !(!velocity || isNaN(velocity) || velocity.toLowerCase().includes('nf') || Number(velocity) < 0 || Number(velocity) >= 10);
};

// NOTE: this considers infinity / 0 invalid
export const hasUnusableReps = (set) => {
    return set.reps.some(rep => !isRepUsable(rep));
};

// NOTE: this considers infinity / 0 invalid
export const getFastestUsableAvgVelocity = (set) => {
    const reps = usableReps(set);
    if (!reps || reps.length === 0) {
        return null;
    }

    return Math.max.apply(Math, reps.map(rep => Number(RepDataMap.averageVelocity(rep.data))));
};

// this is here because of legacy issues
// originally, sets saved their start and end times
// however, once rep deletion was added, the rest calculation is off

export const startTime = (set) => {
    if (!set) {
        return null;
    } else if (set.startTime === undefined) {
        // time of first rep
        let validReps = validUnremovedReps(set);
        if (validReps.length > 0 && validReps[0].time !== undefined) {
            return validReps[0].time;
        } else if (set.initialStartTime !== undefined) {
            return set.initialStartTime;
        } else {
            return null;
        }
    } else {
        // legacy time of set itself
        return set.startTime;
    }
};

export const endTime = (set) => {
    if (set.endTime === undefined) {
        // time of last rep
        let validReps = validUnremovedReps(set);
        if (validReps.length > 0) {
            return validReps[validReps.length-1].time;
        } else {
            return null;
        }
    } else {
        // legacy time of set itself
        return set.endTime;
    }
};
<commit_msg>Switched not number into isNaN check<commit_after>import * as RepDataMap from 'app/utility/RepDataMap';

// no data and no active reps
export const isEmpty = (set) => {
    return hasEmptyData(set) && hasEmptyReps(set);
};

// no data and no reps at all
export const isUntouched = (set) => {
    return hasEmptyData(set) && hasNoReps(set);
};

export const hasAllFields = (set) => {
    if (set.exercise && set.weight && set.rpe && set.tags && set.tags.length > 0) {
        return true;
    }
    return false;
};

export const hasEmptyFields = (set) => {
    return !set.exercise && (!set.weight || set.weight === '') && (!set.rpe || set.rpe === '') && (!set.tags || set.tags === undefined || set.tags.length === 0);
};

export const hasEmptyData = (set) => {
    return hasEmptyFields(set) && !set.videoFileURL;
};

export const hasNoReps = (set) => {
    if (set.reps === null || set.reps === undefined) {
        return true;
    }
    return set.reps.length === 0;
};

export const hasEmptyReps = (set) => {
    if (hasNoReps(set)) {
        return true;
    }

    let activeRep = set.reps.find((rep) => { return rep.removed === false; });
    return activeRep === undefined;
};

// NOTE: this considers infinity / 0 invalid
export const usableReps = (set) => {
    return set.reps.filter(rep => !rep.removed && isRepUsable(rep));
};

export const hasUnremovedRep = (set) => {
    return set.reps.some(rep => !rep.removed);
};

// NOTE: this does not consider infinity / 0 invalid
export const validUnremovedReps = (set) => {
    return set.reps.filter(rep => rep.isValid && !rep.removed);
};

export const weightInLBs = (set) => {
    if (!set.hasOwnProperty('weight') || set.weight === null || isNaN(set.weight)) {
        return null;
    } else if (set.metric === 'lbs') {
        return Number(set.weight);
    } else if (set.metric === 'kgs') {
        return Number(set.weight) * 2.20462262;
    } else {
        // should never reach here
        return null;
    }
};

export const weightInKGs = (set) => {
    if (!set.hasOwnProperty('weight') || set.weight === null || isNaN(set.weight)) {
        return null;
    } else if (set.metric === 'kgs') {
        return Number(set.weight);
    } else if (set.metric === 'lbs') {
        return Number(set.weight) * 0.45359237;
    } else {
        // should never reach here
        return null;
    }
};

export const numFieldsEntered = (set) => {
    let fields = [set.exercise, set.weight, set.rpe, set.tags.length];
    let num_fields_entered = 0;

    fields.forEach((field) => {
        if (Boolean(field)) {
            num_fields_entered++;
        }
    });

    return num_fields_entered;
};

// NOTE: this does not consider infinity / 0 invalid
export const numValidUnremovedReps = (set) => validUnremovedReps(set).length;

// NOTE: this considers infinity / 0 invalid
export const numUsableReps = (set) => usableReps(set).length;

// NOTE: this considers infinity / 0 invalid
export const isRepUsable = (rep) => {
    if (!rep.isValid || !rep.data) {
        return false;
    }
    const velocity = RepDataMap.averageVelocity(rep.data); // this should always return a string
    const peakVelocity = RepDataMap.peakVelocity(rep.data);
    return isVelocityUsable(velocity) && isVelocityUsable(peakVelocity);
};

const isVelocityUsable = (velocity) => {
    return !(!velocity || isNaN(velocity) || velocity.toLowerCase().includes('nf') || Number(velocity) < 0 || Number(velocity) >= 10);
};

// NOTE: this considers infinity / 0 invalid
export const hasUnusableReps = (set) => {
    return set.reps.some(rep => !isRepUsable(rep));
};

// NOTE: this considers infinity / 0 invalid
export const getFastestUsableAvgVelocity = (set) => {
    const reps = usableReps(set);
    if (!reps || reps.length === 0) {
        return null;
    }

    return Math.max.apply(Math, reps.map(rep => Number(RepDataMap.averageVelocity(rep.data))));
};

// this is here because of legacy issues
// originally, sets saved their start and end times
// however, once rep deletion was added, the rest calculation is off

export const startTime = (set) => {
    if (!set) {
        return null;
    } else if (set.startTime === undefined) {
        // time of first rep
        let validReps = validUnremovedReps(set);
        if (validReps.length > 0 && validReps[0].time !== undefined) {
            return validReps[0].time;
        } else if (set.initialStartTime !== undefined) {
            return set.initialStartTime;
        } else {
            return null;
        }
    } else {
        // legacy time of set itself
        return set.startTime;
    }
};

export const endTime = (set) => {
    if (set.endTime === undefined) {
        // time of last rep
        let validReps = validUnremovedReps(set);
        if (validReps.length > 0) {
            return validReps[validReps.length-1].time;
        } else {
            return null;
        }
    } else {
        // legacy time of set itself
        return set.endTime;
    }
};
<|endoftext|>


<commit_before>/* Snap shot Testing - renders out component and compares the last snapshot */
import React from 'react'
import Search from './12C'
// need this module for Jest
// import renderer from 'react-test-renderer'
import { shallow } from 'enzyme'
import { shallowToJson } from 'enzyme-to-json'

// Jest is the test runner being used
// Jest is similar to Jasmine

// commandline run run npm run test or npm test or npm t

// Jest Testing
// test('Search snapshot test', () => {
//   const component = renderer.create(<Search />)
//   const tree = component.toJSON()
//   expect(tree).toMatchSnapshot()
// })

// Enzyme test
test('Search snapshot test', () => {
  const component = shallow(<Search />)
  const tree = shallowToJson(component)
  expect(tree).toMatchSnapshot()
})
<commit_msg>Unit test number of showcards<commit_after>/* Snap shot Testing - renders out component and compares the last snapshot */
import React from 'react'
import Search from './12C'
// need this module for Jest
// import renderer from 'react-test-renderer'
import ShowCard from './12D'
import { shallow } from 'enzyme'
import { shallowToJson } from 'enzyme-to-json'
import preload from '../../public/data.json'

// Jest is the test runner being used
// Jest is similar to Jasmine

// commandline run run npm run test or npm test or npm t

// Jest Testing
// test('Search snapshot test', () => {
//   const component = renderer.create(<Search />)
//   const tree = component.toJSON()
//   expect(tree).toMatchSnapshot()
// })

// Enzyme test
test('Search snapshot test', () => {
  const component = shallow(<Search />)
  const tree = shallowToJson(component)
  expect(tree).toMatchSnapshot()
})

test('Search should render a ShowCard for each show', () => {
  const component = shallow(<Search />)
  expect(preload.shows.length).toEqual(component.find(ShowCard).length)
})
<|endoftext|>


<commit_before>/* global define */
/* eslint-disable no-unused-vars, no-var */

define(['jquery', 'app', 'marionette', 'backbone', './electron.template.view', './electron.template.model'],
function($, app, Marionette, Backbone, TemplateView, Model) {
  app.on('template-extensions-render', function(contextObj) {
    var view;

    function renderRecipeMenu() {
      var model;

      if (contextObj.template.get('recipe') === 'electron-pdf') {
        model = new Model();
        model.setTemplate(contextObj.template);
        view = new TemplateView({ model: model });

        contextObj.extensionsRegion.show(view, 'electron');
      } else {
        if (view != null) {
          $(view.el).remove();
        }
      }
    }

    renderRecipeMenu();

    contextObj.template.on('change:recipe', function() {
      renderRecipeMenu();
    });
  });
});
<commit_msg>wait until other views unbind before rendering<commit_after>/* global define */
/* eslint-disable no-unused-vars, no-var */

define(['jquery', 'app', 'marionette', 'backbone', './electron.template.view', './electron.template.model'],
function($, app, Marionette, Backbone, TemplateView, Model) {
  app.on('template-extensions-render', function(contextObj) {
    var view;

    function renderRecipeMenu() {
      var model;

      if (contextObj.template.get('recipe') === 'electron-pdf') {
        model = new Model();
        model.setTemplate(contextObj.template);
        view = new TemplateView({ model: model });

        //wait until phantom-pdf or potentially other view unbinds from extensions menu
        //otherwise binding electron.width won't apply because phantom.width is still taking place
        setTimeout(function() {
          contextObj.extensionsRegion.show(view, 'electron');
        }, 0);
      } else {
        if (view != null) {
          $(view.el).remove();
        }
      }
    }

    renderRecipeMenu();

    contextObj.template.on('change:recipe', function() {
      renderRecipeMenu();
    });
  });
});
<|endoftext|>


<commit_before>
/* Swipe Functionality */
var myElement = document.getElementById('swipe');
var mc = new Hammer(myElement);

// listen to events...
mc.on("swipeleft swiperight swipeup swipedown", function(ev) {
    switch (ev.type) {
      case "swipeleft":
        window.location.href = "rightPage.html";
        break;
      case "swiperight":
        window.location.href = "leftPage.html";
        break;
      case "swipeup":
        window.location.href = "topPage.html";
        break;
      case "swipedown":
        window.location.href = "bottomPage.html";
      default:

    }
});
<commit_msg>Added vertical swipe<commit_after>
/* Swipe Functionality */
var myElement = document.getElementById('swipe');
var mc = new Hammer(myElement);
mc.get('swipe').set({ direction: Hammer.DIRECTION_ALL });
// listen to events...
mc.on("swipeleft swiperight swipeup swipedown", function(ev) {
    switch (ev.type) {
      case "swipeleft":
        window.location.href = "rightPage.html";
        break;
      case "swiperight":
        window.location.href = "leftPage.html";
        break;
      case "swipeup":
        window.location.href = "topPage.html";
        break;
      case "swipedown":
        window.location.href = "bottomPage.html";
      default:

    }
});
<|endoftext|>


<commit_before>/**
 * http://www.openjs.com/scripts/events/keyboard_shortcuts/
 * Version : 2.01.B
 * By Binny V A
 * License : BSD
 */
shortcut = {
    'all_shortcuts':{},//All the shortcuts are stored in this array
    'add': function(shortcut_combination,callback,opt) {
        //Provide a set of default options
        var default_options = {
            'type':'keydown',
            'propagate':false,
            'disable_in_input':false,
            'target':document,
            'keycode':false
        }
        if(!opt) opt = default_options;
        else {
            for(var dfo in default_options) {
                if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
            }
        }

        var ele = opt.target;
        if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
        var ths = this;
        shortcut_combination = shortcut_combination.toLowerCase();

        //The function to be called at keypress
        var func = function(e) {
            e = e || window.event;

            if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
                var element;
                if(e.target) element=e.target;
                else if(e.srcElement) element=e.srcElement;
                if(element.nodeType==3) element=element.parentNode;

                if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
            }

            //Find Which key is pressed
            if (e.keyCode) code = e.keyCode;
            else if (e.which) code = e.which;
            var character = String.fromCharCode(code).toLowerCase();

            if(code == 188) character=","; //If the user presses , when the type is onkeydown
            if(code == 190) character="."; //If the user presses , when the type is onkeydown

            var keys = shortcut_combination.split("+");
            //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
            var kp = 0;

            //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
            var shift_nums = {
                "`":"~",
                "1":"!",
                "2":"@",
                "3":"#",
                "4":"$",
                "5":"%",
                "6":"^",
                "7":"&",
                "8":"*",
                "9":"(",
                "0":")",
                "-":"_",
                "=":"+",
                ";":":",
                "'":"\"",
                ",":"<",
                ".":">",
                "/":"?",
                "\\":"|"
            }
            //Special Keys - and their codes
            var special_keys = {
                'esc':27,
                'escape':27,
                'tab':9,
                'space':32,
                'return':13,
                'enter':13,
                'backspace':8,

                'scrolllock':145,
                'scroll_lock':145,
                'scroll':145,
                'capslock':20,
                'caps_lock':20,
                'caps':20,
                'numlock':144,
                'num_lock':144,
                'num':144,

                'pause':19,
                'break':19,

                'insert':45,
                'home':36,
                'delete':46,
                'end':35,

                'pageup':33,
                'page_up':33,
                'pu':33,

                'pagedown':34,
                'page_down':34,
                'pd':34,

                'left':37,
                'up':38,
                'right':39,
                'down':40,

                'f1':112,
                'f2':113,
                'f3':114,
                'f4':115,
                'f5':116,
                'f6':117,
                'f7':118,
                'f8':119,
                'f9':120,
                'f10':121,
                'f11':122,
                'f12':123
            }

            var modifiers = {
                shift: { wanted:false, pressed:false},
                ctrl : { wanted:false, pressed:false},
                alt  : { wanted:false, pressed:false},
                meta : { wanted:false, pressed:false}    //Meta is Mac specific
            };

            if(e.ctrlKey)    modifiers.ctrl.pressed = true;
            if(e.shiftKey)    modifiers.shift.pressed = true;
            if(e.altKey)    modifiers.alt.pressed = true;
            if(e.metaKey)   modifiers.meta.pressed = true;

            for(var i=0; k=keys[i],i<keys.length; i++) {
                //Modifiers
                if(k == 'ctrl' || k == 'control') {
                    kp++;
                    modifiers.ctrl.wanted = true;

                } else if(k == 'shift') {
                    kp++;
                    modifiers.shift.wanted = true;

                } else if(k == 'alt') {
                    kp++;
                    modifiers.alt.wanted = true;
                } else if(k == 'meta') {
                    kp++;
                    modifiers.meta.wanted = true;
                } else if(k.length > 1) { //If it is a special key
                    if(special_keys[k] == code) kp++;

                } else if(opt['keycode']) {
                    if(opt['keycode'] == code) kp++;

                } else { //The special keys did not match
                    if(character == k) kp++;
                    else {
                        if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
                            character = shift_nums[character];
                            if(character == k) kp++;
                        }
                    }
                }
            }

            if(kp == keys.length &&
                        modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
                        modifiers.shift.pressed == modifiers.shift.wanted &&
                        modifiers.alt.pressed == modifiers.alt.wanted &&
                        modifiers.meta.pressed == modifiers.meta.wanted) {
                callback(e);

                if(!opt['propagate']) { //Stop the event
                    //e.cancelBubble is supported by IE - this will kill the bubbling process.
                    e.cancelBubble = true;
                    e.returnValue = false;

                    //e.stopPropagation works in Firefox.
                    if (e.stopPropagation) {
                        e.stopPropagation();
                        e.preventDefault();
                    }
                    return false;
                }
            }
        }
        this.all_shortcuts[shortcut_combination] = {
            'callback':func,
            'target':ele,
            'event': opt['type']
        };
        //Attach the function with the event
        if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
        else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
        else ele['on'+opt['type']] = func;
    },

    //Remove the shortcut - just specify the shortcut and I will remove the binding
    'remove':function(shortcut_combination) {
        shortcut_combination = shortcut_combination.toLowerCase();
        var binding = this.all_shortcuts[shortcut_combination];
        delete(this.all_shortcuts[shortcut_combination])
        if(!binding) return;
        var type = binding['event'];
        var ele = binding['target'];
        var callback = binding['callback'];

        if(ele.detachEvent) ele.detachEvent('on'+type, callback);
        else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
        else ele['on'+type] = false;
    }
}
<commit_msg>Fix JS error for undefined variable<commit_after>/**
 * http://www.openjs.com/scripts/events/keyboard_shortcuts/
 * Version : 2.01.B
 * By Binny V A
 * License : BSD
 */
shortcut = {
    'all_shortcuts':{},//All the shortcuts are stored in this array
    'add': function(shortcut_combination,callback,opt) {
        //Provide a set of default options
        var default_options = {
            'type':'keydown',
            'propagate':false,
            'disable_in_input':false,
            'target':document,
            'keycode':false
        }
        if(!opt) opt = default_options;
        else {
            for(var dfo in default_options) {
                if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
            }
        }

        var ele = opt.target;
        if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
        var ths = this;
        shortcut_combination = shortcut_combination.toLowerCase();

        //The function to be called at keypress
        var func = function(e) {
            e = e || window.event;

            if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
                var element;
                if(e.target) element=e.target;
                else if(e.srcElement) element=e.srcElement;
                if(element.nodeType==3) element=element.parentNode;

                if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
            }

            //Find Which key is pressed
            if (e.keyCode) code = e.keyCode;
            else if (e.which) code = e.which;
            else code = null;
            var character = String.fromCharCode(code).toLowerCase();

            if(code == 188) character=","; //If the user presses , when the type is onkeydown
            if(code == 190) character="."; //If the user presses , when the type is onkeydown

            var keys = shortcut_combination.split("+");
            //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
            var kp = 0;

            //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
            var shift_nums = {
                "`":"~",
                "1":"!",
                "2":"@",
                "3":"#",
                "4":"$",
                "5":"%",
                "6":"^",
                "7":"&",
                "8":"*",
                "9":"(",
                "0":")",
                "-":"_",
                "=":"+",
                ";":":",
                "'":"\"",
                ",":"<",
                ".":">",
                "/":"?",
                "\\":"|"
            }
            //Special Keys - and their codes
            var special_keys = {
                'esc':27,
                'escape':27,
                'tab':9,
                'space':32,
                'return':13,
                'enter':13,
                'backspace':8,

                'scrolllock':145,
                'scroll_lock':145,
                'scroll':145,
                'capslock':20,
                'caps_lock':20,
                'caps':20,
                'numlock':144,
                'num_lock':144,
                'num':144,

                'pause':19,
                'break':19,

                'insert':45,
                'home':36,
                'delete':46,
                'end':35,

                'pageup':33,
                'page_up':33,
                'pu':33,

                'pagedown':34,
                'page_down':34,
                'pd':34,

                'left':37,
                'up':38,
                'right':39,
                'down':40,

                'f1':112,
                'f2':113,
                'f3':114,
                'f4':115,
                'f5':116,
                'f6':117,
                'f7':118,
                'f8':119,
                'f9':120,
                'f10':121,
                'f11':122,
                'f12':123
            }

            var modifiers = {
                shift: { wanted:false, pressed:false},
                ctrl : { wanted:false, pressed:false},
                alt  : { wanted:false, pressed:false},
                meta : { wanted:false, pressed:false}    //Meta is Mac specific
            };

            if(e.ctrlKey)    modifiers.ctrl.pressed = true;
            if(e.shiftKey)    modifiers.shift.pressed = true;
            if(e.altKey)    modifiers.alt.pressed = true;
            if(e.metaKey)   modifiers.meta.pressed = true;

            for(var i=0; k=keys[i],i<keys.length; i++) {
                //Modifiers
                if(k == 'ctrl' || k == 'control') {
                    kp++;
                    modifiers.ctrl.wanted = true;

                } else if(k == 'shift') {
                    kp++;
                    modifiers.shift.wanted = true;

                } else if(k == 'alt') {
                    kp++;
                    modifiers.alt.wanted = true;
                } else if(k == 'meta') {
                    kp++;
                    modifiers.meta.wanted = true;
                } else if(k.length > 1) { //If it is a special key
                    if(special_keys[k] == code) kp++;

                } else if(opt['keycode']) {
                    if(opt['keycode'] == code) kp++;

                } else { //The special keys did not match
                    if(character == k) kp++;
                    else {
                        if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
                            character = shift_nums[character];
                            if(character == k) kp++;
                        }
                    }
                }
            }

            if(kp == keys.length &&
                        modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
                        modifiers.shift.pressed == modifiers.shift.wanted &&
                        modifiers.alt.pressed == modifiers.alt.wanted &&
                        modifiers.meta.pressed == modifiers.meta.wanted) {
                callback(e);

                if(!opt['propagate']) { //Stop the event
                    //e.cancelBubble is supported by IE - this will kill the bubbling process.
                    e.cancelBubble = true;
                    e.returnValue = false;

                    //e.stopPropagation works in Firefox.
                    if (e.stopPropagation) {
                        e.stopPropagation();
                        e.preventDefault();
                    }
                    return false;
                }
            }
        }
        this.all_shortcuts[shortcut_combination] = {
            'callback':func,
            'target':ele,
            'event': opt['type']
        };
        //Attach the function with the event
        if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
        else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
        else ele['on'+opt['type']] = func;
    },

    //Remove the shortcut - just specify the shortcut and I will remove the binding
    'remove':function(shortcut_combination) {
        shortcut_combination = shortcut_combination.toLowerCase();
        var binding = this.all_shortcuts[shortcut_combination];
        delete(this.all_shortcuts[shortcut_combination])
        if(!binding) return;
        var type = binding['event'];
        var ele = binding['target'];
        var callback = binding['callback'];

        if(ele.detachEvent) ele.detachEvent('on'+type, callback);
        else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
        else ele['on'+type] = false;
    }
}
<|endoftext|>