<commit_before>/* eslint-env node */

'use strict';

var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var StringReplace = require('string-replace-webpack-plugin');
var Merge = require('webpack-merge');

var files = require('./webpack-config/file-lists.js');
var xmoduleJS = require('./common/static/xmodule/webpack.xmodule.config.js');

var filesWithRequireJSBlocks = [
    path.resolve(__dirname, 'common/static/common/js/components/utils/view_utils.js'),
    /descriptors\/js/,
    /modules\/js/,
    /common\/lib\/xmodule\/xmodule\/js\/src\//
];

var defineHeader = /\(function ?\(((define|require|requirejs|\$)(, )?)+\) ?\{/;
var defineCallFooter = /\}\)\.call\(this, ((define|require)( \|\| RequireJS\.(define|require))?(, )?)+?\);/;
var defineDirectFooter = /\}\(((window\.)?(RequireJS\.)?(requirejs|define|require|jQuery)(, )?)+\)\);/;
var defineFancyFooter = /\}\).call\(\s*this(\s|.)*define(\s|.)*\);/;
var defineFooter = new RegExp('(' + defineCallFooter.source + ')|('
                             + defineDirectFooter.source + ')|('
                             + defineFancyFooter.source + ')', 'm');

module.exports = Merge.smart({
    context: __dirname,

    entry: {
        // Studio
        Import: './cms/static/js/features/import/factories/import.js',
        CourseOrLibraryListing: './cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx',
        'js/factories/login': './cms/static/js/factories/login.js',
        'js/factories/textbooks': './cms/static/js/factories/textbooks.js',
        'js/factories/container': './cms/static/js/factories/container.js',
        'js/factories/context_course': './cms/static/js/factories/context_course.js',
        'js/factories/library': './cms/static/js/factories/library.js',
        'js/factories/xblock_validation': './cms/static/js/factories/xblock_validation.js',
        'js/factories/edit_tabs': './cms/static/js/factories/edit_tabs.js',
        'js/sock': './cms/static/js/sock.js',

        // LMS
        SingleSupportForm: './lms/static/support/jsx/single_support_form.jsx',
        AlertStatusBar: './lms/static/js/accessible_components/StatusBarAlert.jsx',
        LearnerAnalyticsDashboard: './lms/static/js/learner_analytics_dashboard/LearnerAnalyticsDashboard.jsx',
        UpsellExperimentModal: './lms/static/common/js/components/UpsellExperimentModal.jsx',
        PortfolioExperimentUpsellModal: './lms/static/common/js/components/PortfolioExperimentUpsellModal.jsx',
        EntitlementSupportPage: './lms/djangoapps/support/static/support/jsx/entitlements/index.jsx',
        PasswordResetConfirmation: './lms/static/js/student_account/components/PasswordResetConfirmation.jsx',
        StudentAccountDeletion: './lms/static/js/student_account/components/StudentAccountDeletion.jsx',
        StudentAccountDeletionInitializer: './lms/static/js/student_account/StudentAccountDeletionInitializer.js',

        // Learner Dashboard
        EntitlementFactory: './lms/static/js/learner_dashboard/course_entitlement_factory.js',
        EntitlementUnenrollmentFactory: './lms/static/js/learner_dashboard/entitlement_unenrollment_factory.js',
        ProgramDetailsFactory: './lms/static/js/learner_dashboard/program_details_factory.js',
        ProgramListFactory: './lms/static/js/learner_dashboard/program_list_factory.js',
        UnenrollmentFactory: './lms/static/js/learner_dashboard/unenrollment_factory.js',
        ViewedEvent: './lms/static/completion/js/ViewedEvent.js',

        // Features
        CourseGoals: './openedx/features/course_experience/static/course_experience/js/CourseGoals.js',
        CourseHome: './openedx/features/course_experience/static/course_experience/js/CourseHome.js',
        CourseOutline: './openedx/features/course_experience/static/course_experience/js/CourseOutline.js',
        CourseSock: './openedx/features/course_experience/static/course_experience/js/CourseSock.js',
        CourseTalkReviews: './openedx/features/course_experience/static/course_experience/js/CourseTalkReviews.js',
        Currency: './openedx/features/course_experience/static/course_experience/js/currency.js',
        Enrollment: './openedx/features/course_experience/static/course_experience/js/Enrollment.js',
        LatestUpdate: './openedx/features/course_experience/static/course_experience/js/LatestUpdate.js',
        WelcomeMessage: './openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js',

        CookiePolicyBanner: './common/static/js/src/CookiePolicyBanner.jsx',

        // Common
        ReactRenderer: './common/static/js/src/ReactRenderer.jsx',
        XModuleShim: 'xmodule/js/src/xmodule.js',

        VerticalStudentView: './common/lib/xmodule/xmodule/assets/vertical/public/js/vertical_student_view.js'
    },

    output: {
        path: path.resolve(__dirname, 'common/static/bundles'),
        libraryTarget: 'window'
    },

    plugins: [
        new webpack.NoEmitOnErrorsPlugin(),
        new webpack.NamedModulesPlugin(),
        new BundleTracker({
            path: process.env.STATIC_ROOT_CMS,
            filename: 'webpack-stats.json'
        }),
        new BundleTracker({
            path: process.env.STATIC_ROOT_LMS,
            filename: 'webpack-stats.json'
        }),
        new webpack.ProvidePlugin({
            _: 'underscore',
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
            Popper: 'popper.js', // used by bootstrap
            CodeMirror: 'codemirror',
            'edx.HtmlUtils': 'edx-ui-toolkit/js/utils/html-utils',
            AjaxPrefix: 'ajax_prefix'
        }),

        // Note: Until karma-webpack releases v3, it doesn't play well with
        // the CommonsChunkPlugin. We have a kludge in karma.common.conf.js
        // that dynamically removes this plugin from webpack config when
        // running those tests (the details are in that file). This is a
        // recommended workaround, as this plugin is just an optimization. But
        // because of this, we really don't want to get too fancy with how we
        // invoke this plugin until we can upgrade karma-webpack.
        new webpack.optimize.CommonsChunkPlugin({
            // If the value below changes, update the render_bundle call in
            // common/djangoapps/pipeline_mako/templates/static_content.html
            name: 'commons',
            filename: 'commons.js',
            minChunks: 3
        })
    ],

    module: {
        noParse: [
            // See sinon/webpack interaction weirdness:
            // https://github.com/webpack/webpack/issues/304#issuecomment-272150177
            // (I've tried every other suggestion solution on that page, this
            // was the only one that worked.)
            /\/sinon\.js|codemirror-compressed\.js|hls\.js/
        ],
        rules: [
            {
                test: files.namespacedRequire.concat(files.textBangUnderscore, filesWithRequireJSBlocks),
                loader: StringReplace.replace(
                    ['babel-loader'],
                    {
                        replacements: [
                            {
                                pattern: defineHeader,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: defineFooter,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: /(\/\* RequireJS) \*\//g,
                                replacement: function(match, p1) { return p1; }
                            },
                            {
                                pattern: /\/\* Webpack/g,
                                replacement: function(match) { return match + ' */'; }
                            },
                            {
                                pattern: /text!(.*?\.underscore)/g,
                                replacement: function(match, p1) { return p1; }
                            },
                            {
                                pattern: /RequireJS.require/g,
                                replacement: function() {
                                    return 'require';
                                }
                            }
                        ]
                    }
                )
            },
            {
                test: /\.(js|jsx)$/,
                exclude: [
                    /node_modules/,
                    files.namespacedRequire,
                    files.textBangUnderscore,
                    filesWithRequireJSBlocks
                ],
                use: 'babel-loader'
            },
            {
                test: /\.(js|jsx)$/,
                include: [
                    /paragon/
                ],
                use: 'babel-loader'
            },
            {
                test: path.resolve(__dirname, 'common/static/js/src/ajax_prefix.js'),
                use: [
                    'babel-loader',
                    {
                        loader: 'exports-loader',
                        options: {
                            'this.AjaxPrefix': true
                        }
                    }
                ]
            },
            {
                test: /\.underscore$/,
                use: 'raw-loader'
            },
            {
                // This file is used by both RequireJS and Webpack and depends on window globals
                // This is a dirty hack and shouldn't be replicated for other files.
                test: path.resolve(__dirname, 'cms/static/cms/js/main.js'),
                loader: StringReplace.replace(
                    ['babel-loader'],
                    {
                        replacements: [
                            {
                                pattern: /\(function\(AjaxPrefix\) {/,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: /], function\(domReady, \$, str, Backbone, gettext, NotificationView\) {/,
                                replacement: function() {
                                    // eslint-disable-next-line
                                    return '], function(domReady, $, str, Backbone, gettext, NotificationView, AjaxPrefix) {';
                                }
                            },
                            {
                                pattern: /'..\/..\/common\/js\/components\/views\/feedback_notification',/,
                                replacement: function() {
                                    return "'../../common/js/components/views/feedback_notification', 'AjaxPrefix',";
                                }
                            },
                            {
                                pattern: /}\).call\(this, AjaxPrefix\);/,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: /'..\/..\/common\/js\/components\/views\/feedback_notification',/,
                                replacement: function() {
                                    return "'../../common/js/components/views/feedback_notification', 'AjaxPrefix',";
                                }
                            }
                        ]
                    }
                )
            },
            {
                test: /\.(woff2?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
                loader: 'file-loader'
            },
            {
                test: /\.svg$/,
                loader: 'svg-inline-loader'
            },
            {
                test: /xblock\/core/,
                loader: 'exports-loader?window.XBlock!imports-loader?jquery,jquery.immediateDescendents,this=>window'
            },
            {
                test: /xblock\/runtime.v1/,
                loader: 'exports-loader?window.XBlock!imports-loader?XBlock=xblock/core,this=>window'
            },
            {
                test: /descriptors\/js/,
                loader: 'imports-loader?this=>window'
            },
            {
                test: /modules\/js/,
                loader: 'imports-loader?this=>window'
            },
            {
                test: /codemirror/,
                loader: 'exports-loader?window.CodeMirror'
            },
            {
                test: /tinymce/,
                loader: 'imports-loader?this=>window'
            },
            {
                test: /xmodule\/js\/src\/xmodule/,
                loader: 'exports-loader?window.XModule!imports-loader?this=>window'
            },
            {
                test: /mock-ajax/,
                loader: 'imports-loader?exports=>false'
            },
            {
                test: /d3.min/,
                use: [
                    'babel-loader',
                    {
                        loader: 'exports-loader',
                        options: {
                            d3: true
                        }
                    }
                ]
            },
            {
                test: /logger/,
                loader: 'imports-loader?this=>window'
            }
        ]
    },

    resolve: {
        extensions: ['.js', '.jsx', '.json'],
        alias: {
            AjaxPrefix: 'ajax_prefix',
            accessibility: 'accessibility_tools',
            codemirror: 'codemirror-compressed',
            datepair: 'timepicker/datepair',
            'edx-ui-toolkit': 'edx-ui-toolkit/src/',  // @TODO: some paths in toolkit are not valid relative paths
            ieshim: 'ie_shim',
            jquery: 'jquery/src/jquery',  // Use the non-diqst form of jQuery for better debugging + optimization
            'jquery.flot': 'flot/jquery.flot.min',
            'jquery.ui': 'jquery-ui.min',
            'jquery.tinymce': 'tinymce/jquery.tinymce.min',
            'jquery.inputnumber': 'html5-input-polyfills/number-polyfill',
            'jquery.qtip': 'jquery.qtip.min',
            'jquery.smoothScroll': 'jquery.smooth-scroll.min',
            'jquery.timepicker': 'timepicker/jquery.timepicker',
            'backbone.associations': 'backbone-associations/backbone-associations-min',
            squire: 'Squire',

            // See sinon/webpack interaction weirdness:
            // https://github.com/webpack/webpack/issues/304#issuecomment-272150177
            // (I've tried every other suggestion solution on that page, this
            // was the only one that worked.)
            sinon: __dirname + '/node_modules/sinon/pkg/sinon.js',
            hls: 'hls.js/dist/hls.js'
        },
        modules: [
            'cms/djangoapps/pipeline_js/js',
            'cms/static',
            'cms/static/cms/js',
            'cms/templates/js',
            'lms/static',
            'common/lib/xmodule',
            'common/lib/xmodule/xmodule/js/src',
            'common/lib/xmodule/xmodule/assets/word_cloud/src/js',
            'common/static',
            'common/static/coffee/src',
            'common/static/common/js',
            'common/static/common/js/vendor/',
            'common/static/js/src',
            'common/static/js/vendor/',
            'common/static/js/vendor/jQuery-File-Upload/js/',
            'common/static/js/vendor/tinymce/js/tinymce',
            'node_modules',
            'common/static/xmodule'
        ]
    },

    resolveLoader: {
        alias: {
            text: 'raw-loader'  // Compatibility with RequireJSText's text! loader, uses raw-loader under the hood
        }
    },

    externals: {
        $: 'jQuery',
        backbone: 'Backbone',
        canvas: 'canvas',
        coursetalk: 'CourseTalk',
        gettext: 'gettext',
        jquery: 'jQuery',
        logger: 'Logger',
        underscore: '_',
        URI: 'URI',
        XBlockToXModuleShim: 'XBlockToXModuleShim',
        XModule: 'XModule'
    },

    watchOptions: {
        poll: true
    },

    node: {
        fs: 'empty'
    }

}, xmoduleJS);
<commit_msg>Load CodeMirror from an external<commit_after>/* eslint-env node */

'use strict';

var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var StringReplace = require('string-replace-webpack-plugin');
var Merge = require('webpack-merge');

var files = require('./webpack-config/file-lists.js');
var xmoduleJS = require('./common/static/xmodule/webpack.xmodule.config.js');

var filesWithRequireJSBlocks = [
    path.resolve(__dirname, 'common/static/common/js/components/utils/view_utils.js'),
    /descriptors\/js/,
    /modules\/js/,
    /common\/lib\/xmodule\/xmodule\/js\/src\//
];

var defineHeader = /\(function ?\(((define|require|requirejs|\$)(, )?)+\) ?\{/;
var defineCallFooter = /\}\)\.call\(this, ((define|require)( \|\| RequireJS\.(define|require))?(, )?)+?\);/;
var defineDirectFooter = /\}\(((window\.)?(RequireJS\.)?(requirejs|define|require|jQuery)(, )?)+\)\);/;
var defineFancyFooter = /\}\).call\(\s*this(\s|.)*define(\s|.)*\);/;
var defineFooter = new RegExp('(' + defineCallFooter.source + ')|('
                             + defineDirectFooter.source + ')|('
                             + defineFancyFooter.source + ')', 'm');

module.exports = Merge.smart({
    context: __dirname,

    entry: {
        // Studio
        Import: './cms/static/js/features/import/factories/import.js',
        CourseOrLibraryListing: './cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx',
        'js/factories/login': './cms/static/js/factories/login.js',
        'js/factories/textbooks': './cms/static/js/factories/textbooks.js',
        'js/factories/container': './cms/static/js/factories/container.js',
        'js/factories/context_course': './cms/static/js/factories/context_course.js',
        'js/factories/library': './cms/static/js/factories/library.js',
        'js/factories/xblock_validation': './cms/static/js/factories/xblock_validation.js',
        'js/factories/edit_tabs': './cms/static/js/factories/edit_tabs.js',
        'js/sock': './cms/static/js/sock.js',

        // LMS
        SingleSupportForm: './lms/static/support/jsx/single_support_form.jsx',
        AlertStatusBar: './lms/static/js/accessible_components/StatusBarAlert.jsx',
        LearnerAnalyticsDashboard: './lms/static/js/learner_analytics_dashboard/LearnerAnalyticsDashboard.jsx',
        UpsellExperimentModal: './lms/static/common/js/components/UpsellExperimentModal.jsx',
        PortfolioExperimentUpsellModal: './lms/static/common/js/components/PortfolioExperimentUpsellModal.jsx',
        EntitlementSupportPage: './lms/djangoapps/support/static/support/jsx/entitlements/index.jsx',
        PasswordResetConfirmation: './lms/static/js/student_account/components/PasswordResetConfirmation.jsx',
        StudentAccountDeletion: './lms/static/js/student_account/components/StudentAccountDeletion.jsx',
        StudentAccountDeletionInitializer: './lms/static/js/student_account/StudentAccountDeletionInitializer.js',

        // Learner Dashboard
        EntitlementFactory: './lms/static/js/learner_dashboard/course_entitlement_factory.js',
        EntitlementUnenrollmentFactory: './lms/static/js/learner_dashboard/entitlement_unenrollment_factory.js',
        ProgramDetailsFactory: './lms/static/js/learner_dashboard/program_details_factory.js',
        ProgramListFactory: './lms/static/js/learner_dashboard/program_list_factory.js',
        UnenrollmentFactory: './lms/static/js/learner_dashboard/unenrollment_factory.js',
        ViewedEvent: './lms/static/completion/js/ViewedEvent.js',

        // Features
        CourseGoals: './openedx/features/course_experience/static/course_experience/js/CourseGoals.js',
        CourseHome: './openedx/features/course_experience/static/course_experience/js/CourseHome.js',
        CourseOutline: './openedx/features/course_experience/static/course_experience/js/CourseOutline.js',
        CourseSock: './openedx/features/course_experience/static/course_experience/js/CourseSock.js',
        CourseTalkReviews: './openedx/features/course_experience/static/course_experience/js/CourseTalkReviews.js',
        Currency: './openedx/features/course_experience/static/course_experience/js/currency.js',
        Enrollment: './openedx/features/course_experience/static/course_experience/js/Enrollment.js',
        LatestUpdate: './openedx/features/course_experience/static/course_experience/js/LatestUpdate.js',
        WelcomeMessage: './openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js',

        CookiePolicyBanner: './common/static/js/src/CookiePolicyBanner.jsx',

        // Common
        ReactRenderer: './common/static/js/src/ReactRenderer.jsx',
        XModuleShim: 'xmodule/js/src/xmodule.js',

        VerticalStudentView: './common/lib/xmodule/xmodule/assets/vertical/public/js/vertical_student_view.js'
    },

    output: {
        path: path.resolve(__dirname, 'common/static/bundles'),
        libraryTarget: 'window'
    },

    plugins: [
        new webpack.NoEmitOnErrorsPlugin(),
        new webpack.NamedModulesPlugin(),
        new BundleTracker({
            path: process.env.STATIC_ROOT_CMS,
            filename: 'webpack-stats.json'
        }),
        new BundleTracker({
            path: process.env.STATIC_ROOT_LMS,
            filename: 'webpack-stats.json'
        }),
        new webpack.ProvidePlugin({
            _: 'underscore',
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
            Popper: 'popper.js', // used by bootstrap
            'edx.HtmlUtils': 'edx-ui-toolkit/js/utils/html-utils',
            AjaxPrefix: 'ajax_prefix'
        }),

        // Note: Until karma-webpack releases v3, it doesn't play well with
        // the CommonsChunkPlugin. We have a kludge in karma.common.conf.js
        // that dynamically removes this plugin from webpack config when
        // running those tests (the details are in that file). This is a
        // recommended workaround, as this plugin is just an optimization. But
        // because of this, we really don't want to get too fancy with how we
        // invoke this plugin until we can upgrade karma-webpack.
        new webpack.optimize.CommonsChunkPlugin({
            // If the value below changes, update the render_bundle call in
            // common/djangoapps/pipeline_mako/templates/static_content.html
            name: 'commons',
            filename: 'commons.js',
            minChunks: 3
        })
    ],

    module: {
        noParse: [
            // See sinon/webpack interaction weirdness:
            // https://github.com/webpack/webpack/issues/304#issuecomment-272150177
            // (I've tried every other suggestion solution on that page, this
            // was the only one that worked.)
            /\/sinon\.js|codemirror-compressed\.js|hls\.js/
        ],
        rules: [
            {
                test: files.namespacedRequire.concat(files.textBangUnderscore, filesWithRequireJSBlocks),
                loader: StringReplace.replace(
                    ['babel-loader'],
                    {
                        replacements: [
                            {
                                pattern: defineHeader,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: defineFooter,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: /(\/\* RequireJS) \*\//g,
                                replacement: function(match, p1) { return p1; }
                            },
                            {
                                pattern: /\/\* Webpack/g,
                                replacement: function(match) { return match + ' */'; }
                            },
                            {
                                pattern: /text!(.*?\.underscore)/g,
                                replacement: function(match, p1) { return p1; }
                            },
                            {
                                pattern: /RequireJS.require/g,
                                replacement: function() {
                                    return 'require';
                                }
                            }
                        ]
                    }
                )
            },
            {
                test: /\.(js|jsx)$/,
                exclude: [
                    /node_modules/,
                    files.namespacedRequire,
                    files.textBangUnderscore,
                    filesWithRequireJSBlocks
                ],
                use: 'babel-loader'
            },
            {
                test: /\.(js|jsx)$/,
                include: [
                    /paragon/
                ],
                use: 'babel-loader'
            },
            {
                test: path.resolve(__dirname, 'common/static/js/src/ajax_prefix.js'),
                use: [
                    'babel-loader',
                    {
                        loader: 'exports-loader',
                        options: {
                            'this.AjaxPrefix': true
                        }
                    }
                ]
            },
            {
                test: /\.underscore$/,
                use: 'raw-loader'
            },
            {
                // This file is used by both RequireJS and Webpack and depends on window globals
                // This is a dirty hack and shouldn't be replicated for other files.
                test: path.resolve(__dirname, 'cms/static/cms/js/main.js'),
                loader: StringReplace.replace(
                    ['babel-loader'],
                    {
                        replacements: [
                            {
                                pattern: /\(function\(AjaxPrefix\) {/,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: /], function\(domReady, \$, str, Backbone, gettext, NotificationView\) {/,
                                replacement: function() {
                                    // eslint-disable-next-line
                                    return '], function(domReady, $, str, Backbone, gettext, NotificationView, AjaxPrefix) {';
                                }
                            },
                            {
                                pattern: /'..\/..\/common\/js\/components\/views\/feedback_notification',/,
                                replacement: function() {
                                    return "'../../common/js/components/views/feedback_notification', 'AjaxPrefix',";
                                }
                            },
                            {
                                pattern: /}\).call\(this, AjaxPrefix\);/,
                                replacement: function() { return ''; }
                            },
                            {
                                pattern: /'..\/..\/common\/js\/components\/views\/feedback_notification',/,
                                replacement: function() {
                                    return "'../../common/js/components/views/feedback_notification', 'AjaxPrefix',";
                                }
                            }
                        ]
                    }
                )
            },
            {
                test: /\.(woff2?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
                loader: 'file-loader'
            },
            {
                test: /\.svg$/,
                loader: 'svg-inline-loader'
            },
            {
                test: /xblock\/core/,
                loader: 'exports-loader?window.XBlock!imports-loader?jquery,jquery.immediateDescendents,this=>window'
            },
            {
                test: /xblock\/runtime.v1/,
                loader: 'exports-loader?window.XBlock!imports-loader?XBlock=xblock/core,this=>window'
            },
            {
                test: /descriptors\/js/,
                loader: 'imports-loader?this=>window'
            },
            {
                test: /modules\/js/,
                loader: 'imports-loader?this=>window'
            },
            {
                test: /codemirror/,
                loader: 'exports-loader?window.CodeMirror'
            },
            {
                test: /tinymce/,
                loader: 'imports-loader?this=>window'
            },
            {
                test: /xmodule\/js\/src\/xmodule/,
                loader: 'exports-loader?window.XModule!imports-loader?this=>window'
            },
            {
                test: /mock-ajax/,
                loader: 'imports-loader?exports=>false'
            },
            {
                test: /d3.min/,
                use: [
                    'babel-loader',
                    {
                        loader: 'exports-loader',
                        options: {
                            d3: true
                        }
                    }
                ]
            },
            {
                test: /logger/,
                loader: 'imports-loader?this=>window'
            }
        ]
    },

    resolve: {
        extensions: ['.js', '.jsx', '.json'],
        alias: {
            AjaxPrefix: 'ajax_prefix',
            accessibility: 'accessibility_tools',
            datepair: 'timepicker/datepair',
            'edx-ui-toolkit': 'edx-ui-toolkit/src/',  // @TODO: some paths in toolkit are not valid relative paths
            ieshim: 'ie_shim',
            jquery: 'jquery/src/jquery',  // Use the non-diqst form of jQuery for better debugging + optimization
            'jquery.flot': 'flot/jquery.flot.min',
            'jquery.ui': 'jquery-ui.min',
            'jquery.tinymce': 'tinymce/jquery.tinymce.min',
            'jquery.inputnumber': 'html5-input-polyfills/number-polyfill',
            'jquery.qtip': 'jquery.qtip.min',
            'jquery.smoothScroll': 'jquery.smooth-scroll.min',
            'jquery.timepicker': 'timepicker/jquery.timepicker',
            'backbone.associations': 'backbone-associations/backbone-associations-min',
            squire: 'Squire',

            // See sinon/webpack interaction weirdness:
            // https://github.com/webpack/webpack/issues/304#issuecomment-272150177
            // (I've tried every other suggestion solution on that page, this
            // was the only one that worked.)
            sinon: __dirname + '/node_modules/sinon/pkg/sinon.js',
            hls: 'hls.js/dist/hls.js'
        },
        modules: [
            'cms/djangoapps/pipeline_js/js',
            'cms/static',
            'cms/static/cms/js',
            'cms/templates/js',
            'lms/static',
            'common/lib/xmodule',
            'common/lib/xmodule/xmodule/js/src',
            'common/lib/xmodule/xmodule/assets/word_cloud/src/js',
            'common/static',
            'common/static/coffee/src',
            'common/static/common/js',
            'common/static/common/js/vendor/',
            'common/static/js/src',
            'common/static/js/vendor/',
            'common/static/js/vendor/jQuery-File-Upload/js/',
            'common/static/js/vendor/tinymce/js/tinymce',
            'node_modules',
            'common/static/xmodule'
        ]
    },

    resolveLoader: {
        alias: {
            text: 'raw-loader'  // Compatibility with RequireJSText's text! loader, uses raw-loader under the hood
        }
    },

    externals: {
        $: 'jQuery',
        backbone: 'Backbone',
        canvas: 'canvas',
        coursetalk: 'CourseTalk',
        gettext: 'gettext',
        jquery: 'jQuery',
        logger: 'Logger',
        underscore: '_',
        URI: 'URI',
        XBlockToXModuleShim: 'XBlockToXModuleShim',
        XModule: 'XModule',
        CodeMirror: 'CodeMirror',
        codemirror: 'CodeMirror'
    },

    watchOptions: {
        poll: true
    },

    node: {
        fs: 'empty'
    }

}, xmoduleJS);
<|endoftext|>


<commit_before>var ENV     = process.env.NODE_ENV || 'development',
    path    = require('path'),
    webpack = require('webpack'),
    version = require('../package.json').version,
    envVars = null,
    plugin  = {ENV: JSON.stringify(ENV), VERSION: JSON.stringify(version)},
    package = require('../package.json');

envVars = [
  'FACEBOOK_ID',
  'GOOGLE_ID',
  'GITHUB_ID',
  'OAUTH_PROXY_URL',
  'SENTRY_DSN',
  'ANALYTICS_WRITE_KEY',
  'STRIPE_PUBLISHABLE_KEY',
  'CIRCLE_BRANCH',
  'CIRCLE_SHA1',
  'SYNCANO_API_KEY',
  'SYNCANO_INSTANCE_NAME'
];

// We want to check env variables like this: DEVELOPMENT_FACEBOOK_ID or FACEBOOK_ID or null
for (var i = 0; i < envVars.length; i++) {
    var name    = envVars[i],
        envName = ENV.toUpperCase() + '_' + name;
    plugin[name] = JSON.stringify(process.env[envName] || process.env[name] || '');
}

module.exports = {
  target: 'web',
  entry: {
      app: [path.resolve(__dirname, '../src/app.jsx')],
      vendor: Object.keys(package.dependencies)
  },
  output: {
    path: path.resolve(__dirname, '../dist/js'),
    filename: '[name].js',
    chunkFilename: '[name].[chunkhash].js',
    publicPath: 'js/',
  },
  plugins: [
    new webpack.DefinePlugin(plugin)
  ],
  module: {
    preLoaders: [],
    loaders: [
      {test: /\.(svg)$/, loader: 'raw-loader'},
      {test: /\.js(|x)$/, exclude: /node_modules/, loader: 'babel'},
      {test: /\.css$/, loader: 'style-loader!css-loader!autoprefixer-loader?browsers=last 2 version'},
      {test: /\.styl/, loader: 'style-loader!stylus-loader!autoprefixer-loader?browsers=last 2 version'},
      {
        test: /\.sass$/,
        loader: "style!css!sass?sourceMap&indentedSyntax&outputStyle=expanded&precision=8&" +
          "includePaths[]=" + (path.resolve(__dirname, "../node_modules/compass-mixins/lib")) + "&" +
          "includePaths[]=" + (path.resolve(__dirname, "../src/assets/sass")) + "&" +
          "includePaths[]=" + (path.resolve(__dirname, "../node_modules"))
      },
      {
        test: /\.scss$/,
        loader: 'style!css!sass?sourceMap&indentedSyntax&outputStyle=expanded&precision=8&' +
        'includePaths[]=' + (path.resolve(__dirname, '../node_modules/react-flexbox-grid'))
      }
    ]
  },
  resolve: {
    modulesDirectories: ['node_modules'],
    extensions: ['', '.js', '.json', '.jsx', '.css', '.scss', '.sass', '.svg', '.styl']
  },
  externals: {
    'analyticsjs': 'window.analytics',
    'hellojs': 'hello',
    'stripejs': 'Stripe'
  }
};
<commit_msg>[HAC-85] update scss loader, problem with classes names from scss file<commit_after>var ENV     = process.env.NODE_ENV || 'development',
    path    = require('path'),
    webpack = require('webpack'),
    version = require('../package.json').version,
    envVars = null,
    plugin  = {ENV: JSON.stringify(ENV), VERSION: JSON.stringify(version)},
    package = require('../package.json');

envVars = [
  'FACEBOOK_ID',
  'GOOGLE_ID',
  'GITHUB_ID',
  'OAUTH_PROXY_URL',
  'SENTRY_DSN',
  'ANALYTICS_WRITE_KEY',
  'STRIPE_PUBLISHABLE_KEY',
  'CIRCLE_BRANCH',
  'CIRCLE_SHA1',
  'SYNCANO_API_KEY',
  'SYNCANO_INSTANCE_NAME'
];

// We want to check env variables like this: DEVELOPMENT_FACEBOOK_ID or FACEBOOK_ID or null
for (var i = 0; i < envVars.length; i++) {
    var name    = envVars[i],
        envName = ENV.toUpperCase() + '_' + name;
    plugin[name] = JSON.stringify(process.env[envName] || process.env[name] || '');
}

module.exports = {
  target: 'web',
  entry: {
      app: [path.resolve(__dirname, '../src/app.jsx')],
      vendor: Object.keys(package.dependencies)
  },
  output: {
    path: path.resolve(__dirname, '../dist/js'),
    filename: '[name].js',
    chunkFilename: '[name].[chunkhash].js',
    publicPath: 'js/',
  },
  plugins: [
    new webpack.DefinePlugin(plugin)
  ],
  module: {
    preLoaders: [],
    loaders: [
      {test: /\.(svg)$/, loader: 'raw-loader'},
      {test: /\.js(|x)$/, exclude: /node_modules/, loader: 'babel'},
      {test: /\.css$/, loader: 'style-loader!css-loader!autoprefixer-loader?browsers=last 2 version'},
      {test: /\.styl/, loader: 'style-loader!stylus-loader!autoprefixer-loader?browsers=last 2 version'},
      {
        test: /\.scss$/,
        loaders: ['style', 'css?modules', 'sass'],
        include: path.resolve(__dirname, '../node_modules/react-flexbox-grid/lib')
      },
      {
        test: /\.sass$/,
        loader: "style!css!sass?sourceMap&indentedSyntax&outputStyle=expanded&precision=8&" +
          "includePaths[]=" + (path.resolve(__dirname, "../node_modules/compass-mixins/lib")) + "&" +
          "includePaths[]=" + (path.resolve(__dirname, "../src/assets/sass")) + "&" +
          "includePaths[]=" + (path.resolve(__dirname, "../node_modules"))
      }
    ]
  },
  resolve: {
    modulesDirectories: ['node_modules'],
    extensions: ['', '.js', '.json', '.jsx', '.css', '.scss', '.sass', '.svg', '.styl']
  },
  externals: {
    'analyticsjs': 'window.analytics',
    'hellojs': 'hello',
    'stripejs': 'Stripe'
  }
};
<|endoftext|>


<commit_before>//Searches for a song on youtube by its name and loads it into the MusicBot
registerPlugin({
	name: "Youtube Song Search",
	version: "1.0",
	description: "Searches for songs on youtube",
	author: "Rob Chiocchio",
	vars: [
		{
			name: "command_trigger",
			title: "Command",
			type: "string",
			placeholder: "play"
		}
	]
},

function(sinusbot, config) {

	var backend = require("backend");
	var engine = require("engine");
	var event = require("event");

	if
<commit_msg>Added code for yt-search.js v1.0<commit_after>//Searches for a song on youtube by its name and loads it into the MusicBot
registerPlugin({
	name: "Youtube Song Search",
	version: "1.0",
	description: "Searches for songs on youtube",
	author: "Rob Chiocchio",
	vars: [
		{
			name: "commandTrigger",
			title: "Command",
			type: "string",
			placeholder: "!song"
		},{
			name: "searchURL",
			title: "Search URL",
			type: "string",
			placeholder: "https://www.youtube.com/results?search_query="
		}
	]
}, function(sinusbot, config) {

	var backend = require("backend");
	var engine = require("engine");
	var event = require("event");
	var media = require("media");

	config.commandTrigger = config.commandTrigger || "!song";
	config.privateChatEnabled = config.privateChatEnabled || true;
	config.channelChatEnabled = config.channelChatEnabled || true;
	config.serverChatEnabled = config.serverChatEnabled || false;
	engine.saveConfig(config);

	event.on("chat", function (ev) {
		var client = ev.client;
		var channel = ev.channel;

		if (client.isSelf()) return;

		sinusbot.log("chat event: " + ev.text + ", " + ev.client.name() + ", " + ev.mode);

		if (ev.mode == 1 && config.privateChatEnabled ||
            ev.mode == 2 && config.channelChatEnabled ||
            ev.mode == 3 && config.serverChatEnabled) {

			var message = ev.msg;

			if (message.substr(0,4) == config.commandTrigger) {
				sinusbot.log("got command from " + ev.client.name());
				ev.client.chat("Attempting to queue requested song");
				var request = encodeURI(ev.text.substr(5));
				var url = config.searchURL + request;
				media.playURL(url);
				return;
			}
		}
	});
});<|endoftext|>


<commit_before>define([
  'angular',
  'jquery',
  'bootstrap-tagsinput'
],
function (angular, $) {
  'use strict';

  angular
    .module('kibana.directives')
    .directive('bootstrapTagsinput', function() {

      function getItemProperty(scope, property) {
        if (!property) {
          return undefined;
        }

        if (angular.isFunction(scope.$parent[property])) {
          return scope.$parent[property];
        }

        return function(item) {
          return item[property];
        };
      }

      return {
        restrict: 'EA',
        scope: {
          model: '=ngModel'
        },
        template: '<select multiple></select>',
        replace: false,
        link: function(scope, element, attrs) {

          if (!angular.isArray(scope.model)) {
            scope.model = [];
          }

          var select = $('select', element);

          if (attrs.placeholder) {
            select.attr('placeholder', attrs.placeholder);
          }

          select.tagsinput({
            typeahead : {
              source   : angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null
            },
            itemValue: getItemProperty(scope, attrs.itemvalue),
            itemText : getItemProperty(scope, attrs.itemtext),
            tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ?
              scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; }
          });

          select.on('itemAdded', function(event) {
            if (scope.model.indexOf(event.item) === -1) {
              scope.model.push(event.item);
            }
          });

          select.on('itemRemoved', function(event) {
            var idx = scope.model.indexOf(event.item);
            if (idx !== -1) {
              scope.model.splice(idx, 1);
            }
          });

          // create a shallow copy of model's current state, needed to determine
          // diff when model changes
          var prev = scope.model.slice();
          scope.$watch("model", function() {
            if (!angular.isArray(scope.model)) {
              scope.model = [];
            }

            select.tagsinput('removeAll');

            for (var i = 0; i < scope.model.length; i++) {
              select.tagsinput('add', scope.model[i]);
            }

          }, true);

        }
      };
    });
});<commit_msg>jshint fix<commit_after>define([
  'angular',
  'jquery',
  'bootstrap-tagsinput'
],
function (angular, $) {
  'use strict';

  angular
    .module('kibana.directives')
    .directive('bootstrapTagsinput', function() {

      function getItemProperty(scope, property) {
        if (!property) {
          return undefined;
        }

        if (angular.isFunction(scope.$parent[property])) {
          return scope.$parent[property];
        }

        return function(item) {
          return item[property];
        };
      }

      return {
        restrict: 'EA',
        scope: {
          model: '=ngModel'
        },
        template: '<select multiple></select>',
        replace: false,
        link: function(scope, element, attrs) {

          if (!angular.isArray(scope.model)) {
            scope.model = [];
          }

          var select = $('select', element);

          if (attrs.placeholder) {
            select.attr('placeholder', attrs.placeholder);
          }

          select.tagsinput({
            typeahead : {
              source   : angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null
            },
            itemValue: getItemProperty(scope, attrs.itemvalue),
            itemText : getItemProperty(scope, attrs.itemtext),
            tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ?
              scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; }
          });

          select.on('itemAdded', function(event) {
            if (scope.model.indexOf(event.item) === -1) {
              scope.model.push(event.item);
            }
          });

          select.on('itemRemoved', function(event) {
            var idx = scope.model.indexOf(event.item);
            if (idx !== -1) {
              scope.model.splice(idx, 1);
            }
          });

          scope.$watch("model", function() {
            if (!angular.isArray(scope.model)) {
              scope.model = [];
            }

            select.tagsinput('removeAll');

            for (var i = 0; i < scope.model.length; i++) {
              select.tagsinput('add', scope.model[i]);
            }

          }, true);

        }
      };
    });
});<|endoftext|>


<commit_before>var angular = require('angular');
var _ = require('lodash');
var config = require('../config.json');

/**
 *
 * Service to manage initialising and removing synchronisation processes for:
 *
 * - workorders
 * - workflows
 * - messages
 * - workflow results
 *
 * @param $q
 * @param mediator
 * @param workorderSync
 * @param workflowSync
 * @param resultSync
 * @param messageSync
 * @param syncService
 * @returns {{}}
 */
function SyncPoolService($q, mediator, workorderSync, workflowSync, resultSync, messageSync, syncService) {
  var syncPool = {};

  //Initialising the sync service - This is the global initialisation
  syncService.init(window.$fh, config.syncOptions);

  syncPool.removeManagers = function() {
    var promises = [];
    promises.push(workorderSync.removeManager());
    promises.push(messageSync.removeManager());
    promises.push(workflowSync.removeManager());
    promises.push(resultSync.removeManager());
    return $q.all(promises);
  };

  syncPool.syncManagerMap = function(profileData) {

    //If there is no user profile, don't initialise any of the sync managers.
    if (! profileData) {
      return $q.when({});
    }
    var promises = [];
    // add any additonal manager creates here
    promises.push(workorderSync.createManager());
    promises.push(workflowSync.createManager());
    promises.push(messageSync.createManager());
    promises.push(resultSync.createManager());

    //Initialising the sync managers for the required datasets.
    return syncService.manage(config.datasetIds.workorders, {}, {}, config.syncOptions)
      .then(syncService.manage(config.datasetIds.workflows, {}, {}, config.syncOptions))
      .then(syncService.manage(config.datasetIds.results, {}, {}, config.syncOptions))
      .then(syncService.manage(config.datasetIds.messages, {}, {}, config.syncOptions))
      .then(function() {
        return $q.all(promises).then(function(managers) {
          var map = {};
          managers.forEach(function(managerWrapper) {
            map[managerWrapper.manager.datasetId] = managerWrapper;
          });
          map.workorders.manager.publishRecordDeltaReceived(mediator);
          return map;
        });
      });
  };

  syncPool.forceSync = function(managers) {
    var promises = [];
    _.forOwn(managers, function(manager) {
      promises.push(
        manager.forceSync()
          .then(manager.waitForSync)
          .then(function() {
            return manager;
          })
      );
    });
    return $q.all(promises);
  };

  return syncPool;
}

angular.module('app').service('syncPool', ["$q", "mediator", "workorderSync", "workflowSync", "resultSync", "messageSync", "syncService", SyncPoolService]);<commit_msg>fix sync start issue<commit_after>var angular = require('angular');
var _ = require('lodash');
var config = require('../config.json');

/**
 *
 * Service to manage initialising and removing synchronisation processes for:
 *
 * - workorders
 * - workflows
 * - messages
 * - workflow results
 *
 * @param $q
 * @param mediator
 * @param workorderSync
 * @param workflowSync
 * @param resultSync
 * @param messageSync
 * @param syncService
 * @returns {{}}
 */
function SyncPoolService($q, mediator, workorderSync, workflowSync, resultSync, messageSync, syncService) {
  var syncPool = {};

  //Initialising the sync service - This is the global initialisation
  syncService.init(window.$fh, config.syncOptions);

  syncPool.removeManagers = function() {
    var promises = [];
    promises.push(workorderSync.removeManager());
    promises.push(messageSync.removeManager());
    promises.push(workflowSync.removeManager());
    promises.push(resultSync.removeManager());
    return $q.all(promises);
  };

  syncPool.syncManagerMap = function(profileData) {

    //If there is no user profile, don't initialise any of the sync managers.
    if (! profileData) {
      return $q.when({});
    }
    var promises = [];
    // add any additonal manager creates here
    promises.push(workorderSync.createManager());
    promises.push(workflowSync.createManager());
    promises.push(messageSync.createManager());
    promises.push(resultSync.createManager());

    //Initialising the sync managers for the required datasets.
    return syncService.manage(config.datasetIds.workorders, {}, {}, config.syncOptions)
      .then(syncService.manage(config.datasetIds.workflows, {}, {}, config.syncOptions))
      .then(syncService.manage(config.datasetIds.results, {}, {}, config.syncOptions))
      .then(syncService.manage(config.datasetIds.messages, {}, {}, config.syncOptions))
      .then(function() {
        return $q.all(promises).then(function(managers) {
          var map = {};
          managers.forEach(function(managerWrapper) {
            map[managerWrapper.manager.datasetId] = managerWrapper;
            managerWrapper.start();
          });
          map.workorders.manager.publishRecordDeltaReceived(mediator);
          return map;
        });
      });
  };

  syncPool.forceSync = function(managers) {
    var promises = [];
    _.forOwn(managers, function(manager) {
      promises.push(
        manager.forceSync()
          .then(manager.waitForSync)
          .then(function() {
            return manager;
          })
      );
    });
    return $q.all(promises);
  };

  return syncPool;
}

angular.module('app').service('syncPool', ["$q", "mediator", "workorderSync", "workflowSync", "resultSync", "messageSync", "syncService", SyncPoolService]);<|endoftext|>


<commit_before>/*! videojs-wavesurfer
 * Copyright (c) 2014 Collab
 * Licensed under the MIT license. */
(function(root, factory)
{
    if (typeof define === 'function' && define.amd)
    {
        define(['wavesurfer'], factory);
    }
    else
    {
        root.WaveSurfer.Videojs = factory(root.WaveSurfer);
    }
}(this, function(WaveSurfer)
{
    /**
     * Use waveform for audio files in video.js player.
     */
    videojs.Waveform = videojs.Component.extend({

        /**
         * The constructor function for the class.
         *
         * @param options: Player options.
         * @param ready: Ready callback function.
         */
        init: function(player, options, ready)
        {
            // run base component initializing with new options.
            videojs.Component.call(this, player, options, ready);

            this.waveReady = false;
            this.waveFinished = false;
            this.liveMode = false;

            if (this.options().options.src == 'live')
            {
                // check if the Microphone plugin can be enabled
                try
                {
                    this.microphone = Object.create(WaveSurfer.Microphone);

                    // enable audio input from a microphone
                    this.liveMode = true;
                    this.waveReady = true;
                }
                catch (TypeError)
                {
                    console.warn('Could not find Microphone plugin!');
                }
            }

            if (this.options().options.msDisplayMax !== undefined)
            {
            	// msDisplayMax indicates the number of seconds that is
                // considered the boundary value for displaying milliseconds
                // in the time controls. An audio clip with a total length of
                // 2 seconds and a msDisplayMax of 3 will use the format
                // M:SS:MMM. Clips longer than msDisplayMax will be displayed
            	// as M:SS or HH:MM:SS.
            	this.msDisplayMax = parseFloat(this.options().options.msDisplayMax);
            }
            else
            {
            	// default
            	this.msDisplayMax = 3;
            }

            // customize controls
            this.player().bigPlayButton.hide();
            if (this.player().options().controls)
            {
            	// progress control isn't used by this plugin
                this.player().controlBar.progressControl.hide();

                // prevent controlbar fadeout
                this.player().on('userinactive', function(event)
                {
                   this.player().userActive(true);
                });

                // videojs automatically hides the controls when no valid 'source'
                // element is included in the 'audio' tag. Don't.
                this.player().controlBar.show();

                // disable play button until waveform is ready
                // (except when in live mode)
                if (!this.liveMode)
                {
                    this.player().controlBar.playToggle.hide();
                }

                // disable currentTimeDisplay's 'timeupdate' event listener that
                // constantly tries to reset the current time value to 0
                this.player().off('timeupdate');
            }

            // waveform events
            this.surfer = Object.create(WaveSurfer);
            this.surfer.on('error', this.onWaveError.bind(this));
            this.surfer.on('finish', this.onWaveFinish.bind(this));

            // only listen to these events when we're not in live mode
            if (!this.liveMode)
            {
                this.surfer.on('ready', this.onWaveReady.bind(this));
                this.surfer.on('audioprocess', this.onWaveProgress.bind(this));
                this.surfer.on('seek', this.onWaveSeek.bind(this));
            }

            // player events
            this.player().on('play', this.onPlay.bind(this));
            this.player().on('pause', this.onPause.bind(this));
            this.player().on('volumechange', this.onVolumeChange.bind(this));
            this.player().on('fullscreenchange', this.onScreenChange.bind(this));

            // kick things off
            this.startPlayers();
        },

        /**
         * Start the players.
         */
        startPlayers: function()
        {
            var options = this.options().options;

            // init waveform
            this.initialize(options);

            if (options.src !== undefined)
            {
                if (this.microphone === undefined)
                {
                    // show loading spinner
                    this.player().loadingSpinner.show();

                    // start loading file
                    this.load(options.src);
                }
                else
                {
                    // hide loading spinner
                    this.player().loadingSpinner.hide();

                    // connect microphone input to our waveform
                    this.microphone.init({
                        wavesurfer: this.surfer
                    });
                }
            }
            else
            {
                // no valid src found, hide loading spinner
                this.player().loadingSpinner.hide();
            }
        },

        /**
         * Initializes the waveform.
         *
         * @param opts: Plugin options.
         */
        initialize: function(opts)
        {
            this.originalHeight = this.player().options().height;

            // set waveform element and dimensions
            opts.container = this.el();
            opts.height = this.player().height() - this.player().controlBar.height();

            // customize waveform appearance
            this.surfer.init(opts);
        },

        /**
         * Start loading waveform data.
         *
         * @param url: Either the URL of the audio file, or a Blob or File
         *             object.
         */
        load: function(url)
        {
            if (url instanceof Blob || url instanceof File)
            {
                this.surfer.loadArrayBuffer(url);
            }
            else
            {
                this.surfer.load(url);
            }
        },

        /**
         * Start/resume playback or microphone.
         */
        play: function()
        {
            if (this.liveMode)
            {
                // toggle microphone
                this.microphone.togglePlay();
            }
            else
            {
                // start playback
                this.surfer.play();
            }
        },

        /**
         * Pauses playback or microphone.
         */
        pause: function()
        {
            if (this.liveMode)
            {
                // toggle microphone
                this.microphone.togglePlay();
            }
            else
            {
                // pause playback
                if (!this.waveFinished)
                {
                    this.surfer.pause();
                }
                else
                {
                    this.waveFinished = false;
                }

                this.setCurrentTime();
            }
        },

        /**
         * Remove the player and waveform.
         */
        destroy: function()
        {
            this.surfer.destroy();
            this.player().dispose();
        },

        /**
         * Set the current volume of the media.
         *
         * @param volume: The new volume level.
         */
        setVolume: function(volume)
        {
            this.surfer.setVolume(volume);
        },

        /**
         * Updates the player's current time.
         */
        setCurrentTime: function()
        {
            var duration = this.surfer.getDuration();
            var currentTime = this.surfer.getCurrentTime();
            var time = Math.min(currentTime, duration);

            // update control
            this.player().controlBar.currentTimeDisplay.el(
                ).firstChild.innerHTML = this.formatTime(
                time, duration);
        },

        /**
         * Updates the duration time.
         */
        setDuration: function()
        {
            var duration = this.surfer.getDuration();

            // update control
            this.player().controlBar.durationDisplay.el(
                ).firstChild.innerHTML = this.formatTime(
                duration, duration);
        },

        /**
         * Audio is loaded, decoded and the waveform is drawn.
         */
        onWaveReady: function()
        {
            this.waveReady = true;
            this.waveFinished = false;

            // make sure the size of time controls is large enough to
            // display milliseconds
            if (this.surfer.getDuration() < this.msDisplayMax)
            {
                this.player().controlBar.durationDisplay.el().style.width =
                    this.player().controlBar.currentTimeDisplay.el().style.width = '6em';
            }

            // update time display
            this.setCurrentTime();
            this.setDuration();

            // enable and show play button
            this.player().controlBar.playToggle.show();

            // remove loading spinner
            this.player().removeChild(this.player().loadingSpinner);

            // auto-play when ready (if enabled)
            if (this.player().options().autoplay)
            {
                this.play();
            }
        },

        /**
         * Fires when audio playback completed.
         */
        onWaveFinish: function()
        {
            // check if player isn't paused already
            if (!this.player().paused())
            {
                // check if loop is enabled
                if (this.player().options().loop)
                {
                    // reset waveform
                    this.surfer.stop();
                    this.play();
                }
                else
                {
                	// finished
                	this.waveFinished = true;

                    // pause player
                    this.player().pause();
                }
            }
        },

        /**
         * Fires continuously during audio playback.
         *
         * @param percent: Percentage played so far.
         */
        onWaveProgress: function(percent)
        {
            this.setCurrentTime();
        },

        /**
         * Fires during seeking of the waveform.
         */
        onWaveSeek: function()
        {
            this.setCurrentTime();
        },

        /**
         * Fired whenever the media in the player begins or resumes playback.
         */
        onPlay: function()
        {
            // don't start playing until waveform's ready
            if (this.waveReady)
            {
                this.play();
            }
        },

        /**
         * Fired whenever the media in the player has been paused.
         */
        onPause: function()
        {
            this.pause();
        },

        /**
         * Fired when the volume in the player changes.
         */
        onVolumeChange: function()
        {
            var volume = this.player().volume();
            if (this.player().muted())
            {
                // muted volume
                volume = 0;
            }

            this.setVolume(volume);
        },

        /**
         * Fired when the player switches in or out of fullscreen mode.
         */
        onScreenChange: function()
        {
            var isFullscreen = this.player().isFullscreen();
            var newHeight;

            if (!isFullscreen)
            {
                // restore original height
                newHeight = this.originalHeight;
            }
            else
            {
                // fullscreen height
                newHeight = window.outerHeight;
            }

            if (this.waveReady)
            {
                if (this.liveMode && !this.microphone.active)
                {
                    // we're in live mode but the microphone hasn't been
                    // started yet
                    return;
                }

                // destroy old drawing
                this.surfer.drawer.destroy();

                // set new height
                this.surfer.params.height = newHeight - this.player().controlBar.height();
                this.surfer.createDrawer();

                // redraw
                this.surfer.drawBuffer();

                // make sure playhead is restored at right position
                this.surfer.drawer.progress(this.surfer.backend.getPlayedPercents());
            }
        },

        /**
         * Waveform error.
         */
        onWaveError: function(error)
        {
            console.warn(error);
        },

        /**
        * Format seconds as a time string, H:MM:SS, M:SS or M:SS:MMM.
        *
        * Supplying a guide (in seconds) will force a number of leading zeros
        * to cover the length of the guide.
        *
        * @param {Number} seconds Number of seconds to be turned into a string
        * @param {Number} guide Number (in seconds) to model the string after
        * @return {String} Time formatted as H:MM:SS, M:SS or M:SS:MMM.
        */
        formatTime: function(seconds, guide)
        {
            // Default to using seconds as guide
            guide = guide || seconds;
            var s = Math.floor(seconds % 60),
                m = Math.floor(seconds / 60 % 60),
                h = Math.floor(seconds / 3600),
                gm = Math.floor(guide / 60 % 60),
                gh = Math.floor(guide / 3600),
                ms = Math.floor((seconds - s) * 1000);

            // handle invalid times
            if (isNaN(seconds) || seconds === Infinity)
            {
                // '-' is false for all relational operators (e.g. <, >=) so this
                // setting will add the minimum number of fields specified by the
                // guide
                h = m = s = ms = '-';
            }

            // Check if we need to show milliseconds
            if (guide > 0 && guide < this.msDisplayMax)
            {
                if (ms < 100)
                {
                    if (ms < 10)
                    {
                        ms = '00' + ms;
                    }
                    else
                    {
                        ms = '0' + ms;
                    }
                }
                ms = ":" + ms;
            }
            else
            {
                ms = '';
            }

            // Check if we need to show hours
            h = (h > 0 || gh > 0) ? h + ':' : '';

            // If hours are showing, we may need to add a leading zero.
            // Always show at least one digit of minutes.
            m = (((h || gm >= 10) && m < 10) ? '0' + m : m) + ':';

            // Check if leading zero is need for seconds
            s = ((s < 10) ? '0' + s : s);

            return h + m + s + ms;
        }

    });

    var createWaveform = function()
    {
        var props = {
            className: 'vjs-waveform',
            tabIndex: 0
        };
        return videojs.Component.prototype.createEl(null, props);
    };

    var defaults = {};

    /**
     * Initialize the plugin.
     * @param options (optional) {object} configuration for the plugin
     */
    var wavesurferPlugin = function(options)
    {
        var settings = videojs.util.mergeOptions(defaults, options);
        var player = this;

        // create new waveform
        player.waveform = new videojs.Waveform(player,
        {
            'el': createWaveform(),
            'options': settings
        });

        // add waveform to dom
        player.el().appendChild(player.waveform.el());
    }

    // register the plugin
    videojs.plugin('wavesurfer', wavesurferPlugin);

    return wavesurferPlugin;

}));
<commit_msg>use  instead<commit_after>/*! videojs-wavesurfer
 * Copyright (c) 2014 Collab
 * Licensed under the MIT license. */
(function(root, factory)
{
    if (typeof define === 'function' && define.amd)
    {
        define(['wavesurfer'], factory);
    }
    else
    {
        root.WaveSurfer.Videojs = factory(root.WaveSurfer);
    }
}(this, function(WaveSurfer)
{
    /**
     * Use waveform for audio files in video.js player.
     */
    videojs.Waveform = videojs.Component.extend({

        /**
         * The constructor function for the class.
         *
         * @param options: Player options.
         * @param ready: Ready callback function.
         */
        init: function(player, options, ready)
        {
            // run base component initializing with new options.
            videojs.Component.call(this, player, options, ready);

            this.waveReady = false;
            this.waveFinished = false;
            this.liveMode = false;

            if (this.options().options.src == 'live')
            {
                // check if the Microphone plugin can be enabled
                try
                {
                    this.microphone = Object.create(WaveSurfer.Microphone);

                    // enable audio input from a microphone
                    this.liveMode = true;
                    this.waveReady = true;
                }
                catch (TypeError)
                {
                    console.warn('Could not find Microphone plugin!');
                }
            }

            if (this.options().options.msDisplayMax !== undefined)
            {
            	// msDisplayMax indicates the number of seconds that is
                // considered the boundary value for displaying milliseconds
                // in the time controls. An audio clip with a total length of
                // 2 seconds and a msDisplayMax of 3 will use the format
                // M:SS:MMM. Clips longer than msDisplayMax will be displayed
            	// as M:SS or HH:MM:SS.
            	this.msDisplayMax = parseFloat(this.options().options.msDisplayMax);
            }
            else
            {
            	// default
            	this.msDisplayMax = 3;
            }

            // customize controls
            this.player().bigPlayButton.hide();
            if (this.player().options().controls)
            {
            	// progress control isn't used by this plugin
                this.player().controlBar.progressControl.hide();

                // prevent controlbar fadeout
                this.player().on('userinactive', function(event)
                {
                   this.player().userActive(true);
                });

                // videojs automatically hides the controls when no valid 'source'
                // element is included in the 'audio' tag. Don't.
                this.player().controlBar.show();

                // disable play button until waveform is ready
                // (except when in live mode)
                if (!this.liveMode)
                {
                    this.player().controlBar.playToggle.hide();
                }

                // disable currentTimeDisplay's 'timeupdate' event listener that
                // constantly tries to reset the current time value to 0
                this.player().off('timeupdate');
            }

            // waveform events
            this.surfer = Object.create(WaveSurfer);
            this.surfer.on('error', this.onWaveError.bind(this));
            this.surfer.on('finish', this.onWaveFinish.bind(this));

            // only listen to these events when we're not in live mode
            if (!this.liveMode)
            {
                this.surfer.on('ready', this.onWaveReady.bind(this));
                this.surfer.on('audioprocess', this.onWaveProgress.bind(this));
                this.surfer.on('seek', this.onWaveSeek.bind(this));
            }

            // player events
            this.player().on('play', this.onPlay.bind(this));
            this.player().on('pause', this.onPause.bind(this));
            this.player().on('volumechange', this.onVolumeChange.bind(this));
            this.player().on('fullscreenchange', this.onScreenChange.bind(this));

            // kick things off
            this.startPlayers();
        },

        /**
         * Start the players.
         */
        startPlayers: function()
        {
            var options = this.options().options;

            // init waveform
            this.initialize(options);

            if (options.src !== undefined)
            {
                if (this.microphone === undefined)
                {
                    // show loading spinner
                    this.player().loadingSpinner.show();

                    // start loading file
                    this.load(options.src);
                }
                else
                {
                    // hide loading spinner
                    this.player().loadingSpinner.hide();

                    // connect microphone input to our waveform
                    this.microphone.init({
                        wavesurfer: this.surfer
                    });
                }
            }
            else
            {
                // no valid src found, hide loading spinner
                this.player().loadingSpinner.hide();
            }
        },

        /**
         * Initializes the waveform.
         *
         * @param opts: Plugin options.
         */
        initialize: function(opts)
        {
            this.originalHeight = this.player().options().height;

            // set waveform element and dimensions
            opts.container = this.el();
            opts.height = this.player().height() - this.player().controlBar.height();

            // customize waveform appearance
            this.surfer.init(opts);
        },

        /**
         * Start loading waveform data.
         *
         * @param url: Either the URL of the audio file, or a Blob or File
         *             object.
         */
        load: function(url)
        {
            if (url instanceof Blob || url instanceof File)
            {
                this.surfer.loadBlob(url);
            }
            else
            {
                this.surfer.load(url);
            }
        },

        /**
         * Start/resume playback or microphone.
         */
        play: function()
        {
            if (this.liveMode)
            {
                // toggle microphone
                this.microphone.togglePlay();
            }
            else
            {
                // start playback
                this.surfer.play();
            }
        },

        /**
         * Pauses playback or microphone.
         */
        pause: function()
        {
            if (this.liveMode)
            {
                // toggle microphone
                this.microphone.togglePlay();
            }
            else
            {
                // pause playback
                if (!this.waveFinished)
                {
                    this.surfer.pause();
                }
                else
                {
                    this.waveFinished = false;
                }

                this.setCurrentTime();
            }
        },

        /**
         * Remove the player and waveform.
         */
        destroy: function()
        {
            this.surfer.destroy();
            this.player().dispose();
        },

        /**
         * Set the current volume of the media.
         *
         * @param volume: The new volume level.
         */
        setVolume: function(volume)
        {
            this.surfer.setVolume(volume);
        },

        /**
         * Updates the player's current time.
         */
        setCurrentTime: function()
        {
            var duration = this.surfer.getDuration();
            var currentTime = this.surfer.getCurrentTime();
            var time = Math.min(currentTime, duration);

            // update control
            this.player().controlBar.currentTimeDisplay.el(
                ).firstChild.innerHTML = this.formatTime(
                time, duration);
        },

        /**
         * Updates the duration time.
         */
        setDuration: function()
        {
            var duration = this.surfer.getDuration();

            // update control
            this.player().controlBar.durationDisplay.el(
                ).firstChild.innerHTML = this.formatTime(
                duration, duration);
        },

        /**
         * Audio is loaded, decoded and the waveform is drawn.
         */
        onWaveReady: function()
        {
            this.waveReady = true;
            this.waveFinished = false;

            // make sure the size of time controls is large enough to
            // display milliseconds
            if (this.surfer.getDuration() < this.msDisplayMax)
            {
                this.player().controlBar.durationDisplay.el().style.width =
                    this.player().controlBar.currentTimeDisplay.el().style.width = '6em';
            }

            // update time display
            this.setCurrentTime();
            this.setDuration();

            // enable and show play button
            this.player().controlBar.playToggle.show();

            // remove loading spinner
            this.player().removeChild(this.player().loadingSpinner);

            // auto-play when ready (if enabled)
            if (this.player().options().autoplay)
            {
                this.play();
            }
        },

        /**
         * Fires when audio playback completed.
         */
        onWaveFinish: function()
        {
            // check if player isn't paused already
            if (!this.player().paused())
            {
                // check if loop is enabled
                if (this.player().options().loop)
                {
                    // reset waveform
                    this.surfer.stop();
                    this.play();
                }
                else
                {
                	// finished
                	this.waveFinished = true;

                    // pause player
                    this.player().pause();
                }
            }
        },

        /**
         * Fires continuously during audio playback.
         *
         * @param percent: Percentage played so far.
         */
        onWaveProgress: function(percent)
        {
            this.setCurrentTime();
        },

        /**
         * Fires during seeking of the waveform.
         */
        onWaveSeek: function()
        {
            this.setCurrentTime();
        },

        /**
         * Fired whenever the media in the player begins or resumes playback.
         */
        onPlay: function()
        {
            // don't start playing until waveform's ready
            if (this.waveReady)
            {
                this.play();
            }
        },

        /**
         * Fired whenever the media in the player has been paused.
         */
        onPause: function()
        {
            this.pause();
        },

        /**
         * Fired when the volume in the player changes.
         */
        onVolumeChange: function()
        {
            var volume = this.player().volume();
            if (this.player().muted())
            {
                // muted volume
                volume = 0;
            }

            this.setVolume(volume);
        },

        /**
         * Fired when the player switches in or out of fullscreen mode.
         */
        onScreenChange: function()
        {
            var isFullscreen = this.player().isFullscreen();
            var newHeight;

            if (!isFullscreen)
            {
                // restore original height
                newHeight = this.originalHeight;
            }
            else
            {
                // fullscreen height
                newHeight = window.outerHeight;
            }

            if (this.waveReady)
            {
                if (this.liveMode && !this.microphone.active)
                {
                    // we're in live mode but the microphone hasn't been
                    // started yet
                    return;
                }

                // destroy old drawing
                this.surfer.drawer.destroy();

                // set new height
                this.surfer.params.height = newHeight - this.player().controlBar.height();
                this.surfer.createDrawer();

                // redraw
                this.surfer.drawBuffer();

                // make sure playhead is restored at right position
                this.surfer.drawer.progress(this.surfer.backend.getPlayedPercents());
            }
        },

        /**
         * Waveform error.
         */
        onWaveError: function(error)
        {
            console.warn(error);
        },

        /**
        * Format seconds as a time string, H:MM:SS, M:SS or M:SS:MMM.
        *
        * Supplying a guide (in seconds) will force a number of leading zeros
        * to cover the length of the guide.
        *
        * @param {Number} seconds Number of seconds to be turned into a string
        * @param {Number} guide Number (in seconds) to model the string after
        * @return {String} Time formatted as H:MM:SS, M:SS or M:SS:MMM.
        */
        formatTime: function(seconds, guide)
        {
            // Default to using seconds as guide
            guide = guide || seconds;
            var s = Math.floor(seconds % 60),
                m = Math.floor(seconds / 60 % 60),
                h = Math.floor(seconds / 3600),
                gm = Math.floor(guide / 60 % 60),
                gh = Math.floor(guide / 3600),
                ms = Math.floor((seconds - s) * 1000);

            // handle invalid times
            if (isNaN(seconds) || seconds === Infinity)
            {
                // '-' is false for all relational operators (e.g. <, >=) so this
                // setting will add the minimum number of fields specified by the
                // guide
                h = m = s = ms = '-';
            }

            // Check if we need to show milliseconds
            if (guide > 0 && guide < this.msDisplayMax)
            {
                if (ms < 100)
                {
                    if (ms < 10)
                    {
                        ms = '00' + ms;
                    }
                    else
                    {
                        ms = '0' + ms;
                    }
                }
                ms = ":" + ms;
            }
            else
            {
                ms = '';
            }

            // Check if we need to show hours
            h = (h > 0 || gh > 0) ? h + ':' : '';

            // If hours are showing, we may need to add a leading zero.
            // Always show at least one digit of minutes.
            m = (((h || gm >= 10) && m < 10) ? '0' + m : m) + ':';

            // Check if leading zero is need for seconds
            s = ((s < 10) ? '0' + s : s);

            return h + m + s + ms;
        }

    });

    var createWaveform = function()
    {
        var props = {
            className: 'vjs-waveform',
            tabIndex: 0
        };
        return videojs.Component.prototype.createEl(null, props);
    };

    var defaults = {};

    /**
     * Initialize the plugin.
     * @param options (optional) {object} configuration for the plugin
     */
    var wavesurferPlugin = function(options)
    {
        var settings = videojs.util.mergeOptions(defaults, options);
        var player = this;

        // create new waveform
        player.waveform = new videojs.Waveform(player,
        {
            'el': createWaveform(),
            'options': settings
        });

        // add waveform to dom
        player.el().appendChild(player.waveform.el());
    }

    // register the plugin
    videojs.plugin('wavesurfer', wavesurferPlugin);

    return wavesurferPlugin;

}));
<|endoftext|>