<commit_before>'use strict';

/* eslint-disable prefer-arrow-callback */
/* TODO: Use arrow-functions for tasks once gulp-param fixes bug that causes them not to work */

const gulp = require('gulp-help')(require('gulp-param')(require('gulp'), process.argv));
const async = require('async');
const del = require('del');
const merge = require('merge2');
const path = require('path');

// load gulp plugins
const jeditor = require('gulp-json-editor');
const G$ = require('gulp-load-plugins')({ lazy: true });
const chalk = G$.util.colors;

// constants
const PROJECT_VAR = '{project}';

// load settings
const settings = require('./gulp.json');
const tsconfig = require('./tsconfig.master.json');
const projects = require('./projects.json');
const projectNames = Object.keys(projects);

function expandPaths(globArray) {
    const expandedGlob = [];
    globArray.forEach(item => {
        if (item.indexOf(PROJECT_VAR) > 0) {
            projectNames.forEach(project => {
                expandedGlob.push(item.replace(PROJECT_VAR, project));
            });
        } else {
            expandedGlob.push(item);
        }
    });
    return expandedGlob;
}

function wildcharPaths(globArray) {
    const expandedGlob = [];
    globArray.forEach(item => {
        if (item.indexOf(PROJECT_VAR) > 0) {
            expandedGlob.push(item.replace(PROJECT_VAR, '*'));
        } else {
            expandedGlob.push(item);
        }
    });
    return expandedGlob;
}

function mapPaths(globArray, project) {
    return globArray.map(path =>
        mapPath(path, project));
}

function mapPath(path, project) {
    return path.replace(PROJECT_VAR, project);
}

function plumberErrorHandler(err) {
    console.log(err.stack);
    this.emit('end'); // For gulp watch
}

const exec = require('child_process').exec;

function runCommand(command, options, callback) {
    try {
        exec(command, options, function (error, stdout, stderr) {
            console.log(`${path.resolve(options.cwd || '.')} ${command}`);
            console.log(stdout);
            console.log(stderr);
            if (error !== null) {
                console.log('exec error: ', error);
            }
            callback();
        });
    } catch (ex) {
        console.log('rc ex', ex);
    }
}

/*
 * {cmd: "", cwd: ""}
 */
function runCommands(commands, callback) {
    async.eachSeries(commands, function (command, done) {
        runCommand(command.cmd, { cwd: command.cwd }, done);
    }, function () {
        callback();
    });
}

// Setup

gulp.task('setup', 'Install all modules and link projects', function (callback) {
    G$.sequence('install', 'link', callback);
});

gulp.task('teardown', 'Clean all and unlink projects', function (callback) {
    G$.sequence('unlink', 'deepclean', callback);
});

// npm install

gulp.task('install', 'Install all npm modules', function (callback) {
    const commands = [];
    commands.push({ cmd: 'npm install', cwd: undefined });
    projectNames.forEach(name => {
        commands.push({ cmd: 'npm install', cwd: `projects/${name}` });
    });
    runCommands(commands, callback);
});

// npm link

gulp.task('link', 'Link dependencies on local disk', function (callback) {
    linker(true, callback);
});

gulp.task('unlink', 'Unlink dependencies on local disk', function (callback) {
    linker(false, callback);
});

function linker(mode, callback) {
    const linkedDeps = {};
    const commands = [];
    projectNames.forEach(proj => {
        if (projects[proj].dependencies) {
            projects[proj].dependencies.forEach(dep => {
                if (!linkedDeps[dep]) {
                    commands.push({ cmd: `npm ${mode ? 'link' : 'unlink'} --no-bin-links`, cwd: `projects/${dep}` });
                    linkedDeps[dep] = true;
                }
                if (mode) {
                    const packageName = require(`./projects/${dep}/package.json`).name;
                    commands.push({ cmd: `npm ${mode ? 'link' : 'unlink'} ${packageName} --no-bin-links`, cwd: `projects/${proj}` });
                }
            });
        }
    });
    runCommands(commands, callback);
    // info about "--no-bin-links" : see http://stackoverflow.com/questions/17990647/npm-install-errors-with-error-enoent-chmod
}

// Building

gulp.task('build', 'Compiles all TypeScript source files and updates module references', function (callback) {
    G$.sequence(['tslint', 'clean'], 'ts-all', callback);
});

gulp.task('watch', 'Contiuous build', ['build'], function () {
    projectNames.forEach(project => {
        gulp.watch(mapPaths(Array.prototype.concat(settings.tsfiles, settings.jsFiles), project), [`ts-${project}`]);
    });
});

// see https://www.npmjs.com/package/tslint
gulp.task('tslint', 'Lints all TypeScript source files', function () {
    return gulp.src(wildcharPaths(settings.tsfiles))
        .pipe(G$.tslint({ formatter: 'verbose' }))
        .pipe(G$.tslint.report({ emitError: false }));
});

// Cleaning

gulp.task('clean', 'Cleans the generated files from lib directory', function () {
    return del(expandPaths(settings.clean));
});

gulp.task('deepclean', 'Cleans the generated files from lib directory and all node_modules', function () {
    return del(expandPaths(settings.deepClean));
});

// Transpiling
projectNames.forEach(project => {
    gulp.task(`ts-${project}`, `Transpile ${chalk.green(project)}`, function () {
        const tsResult = gulp.src(mapPaths(settings.tsfiles, project))
            .pipe(G$.sourcemaps.init())
            .pipe(G$.typescript.createProject(tsconfig.compilerOptions)());
        const dest = mapPath(settings.dest, project);
        return merge([
            tsResult.dts.pipe(gulp.dest(dest)),
            tsResult.js
                .pipe(G$.sourcemaps.write('.')) // separate .js.map files
                .pipe(gulp.dest(dest)),
            // JS files
            gulp.src(mapPaths(settings.jsFiles, project)).pipe(G$.babel({
                presets: ['es2015']
            })).pipe(gulp.dest(dest)),
            // all other files
            gulp.src(mapPaths(settings.resources, project)).pipe(gulp.dest(dest))
        ]);
    });
});

gulp.task('ts-all', 'Transpile all projects', function (callback) {
    G$.sequence(projectNames.map(name => `ts-${name}`), callback);
});

// Extras

gulp.task('npm-i', `Install and save a ${chalk.cyan('pack')}age to a ${chalk.cyan('project')}`, function (project, pack, callback) {
    runCommand(`npm install --save ${pack}`, { cwd: mapPath(settings.projectPath, project) }, function () {
        callback();
    });
}, {
    options: {
        pack: 'Package name',
        project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
    }
});

gulp.task('npm-u', `Uninstall and save a ${chalk.cyan('pack')}age to a ${chalk.cyan('project')}`, function (project, pack, callback) {
    runCommand(`npm uninstall --save ${pack}`, { cwd: mapPath(settings.projectPath, project) }, function () {
        callback();
    });
}, {
    options: {
        pack: 'Package name',
        project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
    }
});

gulp.task('stats', 'Get lines of code', function (project) {
    console.log(project);
    if (project) {
        console.log(`Source Lines of Code: ${chalk.green(project)}`);
        gulp.src(mapPaths(settings.sloc_project, project)).pipe(G$.sloc({ tolerant: true }));
    } else {
        console.log(`Source Lines of Code: ${chalk.white('ALL')}`);
        gulp.src(settings.sloc_all).pipe(G$.sloc({ tolerant: true }));
    }
}, {
    options: {
        project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
    }
});

gulp.task('size', 'Get size of code', function (project) {
    console.log(project);
    if (project) {
        console.log(`Source Lines of Code: ${chalk.green(project)}`);
        gulp.src(mapPaths(settings.runtimeFiles, project)).pipe(G$.size({ showFiles: true }));
    } else {
        console.log(`Source Lines of Code: ${chalk.white('ALL')}`);
        gulp.src(expandPaths(settings.runtimeFiles)).pipe(G$.size({ showFiles: true }));
    }
}, {
    options: {
        project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
    }
});

// Deploying

function getPackageName(packagePath) {
    const packageFile = require(path.join(path.resolve(packagePath), 'package.json'));
    return `${packageFile.name}_${packageFile.version}`;
}

gulp.task('package', false, function () {
    const packageFileName = `${getPackageName(settings.edgeDir)}.tar`;
    return gulp.src(settings.packageFiles, { follow: true })
        .pipe(gulp.dest('dist/droplit-edge'))
        .pipe(G$.debug({ title: 'package:' }))
        .pipe(G$.tar(packageFileName))
        .pipe(G$.gzip())
        .pipe(gulp.dest('dist'));
});

gulp.task('clean-dist', false, function () {
    return del('dist');
});

gulp.task('move-temp', false, function () {
    return gulp.src(settings.edgeFiles, { follow: true })
        .pipe(gulp.dest('temp/droplit-edge'));
});

gulp.task('clean-temp', false, function () {
    return del('temp');
});

gulp.task('setup-package', false, function () {
    return gulp.src('./temp/droplit-edge/package.json')
        .pipe(jeditor(function (json) {
            const localConfig = require('./temp/droplit-edge/localsettings.json');
            if (Array.isArray(localConfig.plugins))
                localConfig.plugins.forEach(plugin => {
                    if (typeof plugin === 'string') {
                        json.dependencies[plugin] = `../../projects/${plugin}`;
                        return;
                    }

                    if (typeof plugin === 'object' && plugin.hasOwnProperty('name') && plugin.enabled !== false)
                        json.dependencies[plugin.name] = `../../projects/${plugin.name}`;
                });
            else
                Object.keys(localConfig.plugins).forEach(plugin => {
                    if (localConfig.plugins[plugin] && localConfig.plugins[plugin].enabled !== false) {
                        json.dependencies[plugin] = `../../projects/${plugin}`;
                    }
                });
            return json;
        }))
        .pipe(gulp.dest('temp/droplit-edge/'));
});

gulp.task('pre-install-dist', false, function () {
    return del('temp/droplit-edge/node_modules');
});

gulp.task('install-dist', false, function (callback) {
    runCommand('npm install', { cwd: 'temp/droplit-edge' }, () => {
        console.log('done');
        callback();
    });
});

gulp.task('build-dist', false, function (callback) {
    G$.sequence('clean-dist', 'build', 'unlink', 'move-temp', 'setup-package', 'pre-install-dist', 'install-dist', 'package', 'clean-temp', callback);
});

gulp.task('deploy', 'Glob the Droplit Edge for embedding', function (callback) {
    G$.sequence('setup', 'build-dist', callback);
});

// Testing for improving package
gulp.task('prep', false, function () {
    return del(expandPaths(settings.prep));
});

// Version bump

const bumpOpts = {
    options: {
        major: 'when you make incompatible API changes',
        minor: 'when you add functionality in a backwards-compatible manner',
        patch: 'when you make backwards-compatible bug fixes',
        project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
    }
};

gulp.task('bump', 'Version bump a project.', function (major, minor, patch, project) {
    if (!project) return console.log(`${chalk.red('No project specified!')}`);
    let type = '';
    if (major && !minor && !patch) type = 'major';
    if (!major && minor && !patch) type = 'minor';
    if (!major && !minor && patch) type = 'patch';
    if (!type) return console.log(`${chalk.red('Specify one version type to bump!')}`);
    const cwd = 'projects/project/';
    return gulp.src('./package.json', { cwd })
        .pipe(G$.bump({ type }))
        .pipe(gulp.dest('./', { cwd }));
}, bumpOpts);

gulp.task('debug', 'Debug droplit-edge', function () {
    const project = 'droplit-edge';
    G$.nodemon({
        script: `${project}.js`,
        ext: 'js',
        env: {
            DEBUG: 'droplit:*'
        },
        delay: 1, // Sec
        watch: `projects/${project}`,
        ignore: `projects/${project}/src`
    });
});

// .pipe(G$.plumber()) // exit gracefully if something fails after this

// gulp.task('test', 'Runs all tests', [], function () {
//     $.util.log(colors.cyan(`Testing ${settings.testGlob}`));

//     return gulp
//         .src(settings.testGlob, { read: true })
//         .pipe($.plumber()) // exit gracefully if something fails after this
//         .pipe($.mocha({ reporter: 'spec' }));
// });

// Attitional reference: https://github.com/johnpapa/gulp-patterns
// http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm<commit_msg>Npm 5 Support and speedy setup time<commit_after>'use strict';

/* eslint-disable prefer-arrow-callback */
/* TODO: Use arrow-functions for tasks once gulp-param fixes bug that causes them not to work */

const gulp = require('gulp-help')(require('gulp-param')(require('gulp'), process.argv));
const async = require('async');
const del = require('del');
const merge = require('merge2');
const path = require('path');

// load gulp plugins
const jeditor = require('gulp-json-editor');
const G$ = require('gulp-load-plugins')({ lazy: true });
const chalk = G$.util.colors;

// constants
const PROJECT_VAR = '{project}';

// load settings
const settings = require('./gulp.json');
const tsconfig = require('./tsconfig.master.json');
const projects = require('./projects.json');
const projectNames = Object.keys(projects);

function expandPaths(globArray) {
    const expandedGlob = [];
    globArray.forEach(item => {
        if (item.indexOf(PROJECT_VAR) > 0) {
            projectNames.forEach(project => {
                expandedGlob.push(item.replace(PROJECT_VAR, project));
            });
        } else {
            expandedGlob.push(item);
        }
    });
    return expandedGlob;
}

function wildcharPaths(globArray) {
    const expandedGlob = [];
    globArray.forEach(item => {
        if (item.indexOf(PROJECT_VAR) > 0) {
            expandedGlob.push(item.replace(PROJECT_VAR, '*'));
        } else {
            expandedGlob.push(item);
        }
    });
    return expandedGlob;
}

function mapPaths(globArray, project) {
    return globArray.map(path =>
        mapPath(path, project));
}

function mapPath(path, project) {
    return path.replace(PROJECT_VAR, project);
}

function plumberErrorHandler(err) {
    console.log(err.stack);
    this.emit('end'); // For gulp watch
}

const exec = require('child_process').exec;

function runCommand(command, options, callback) {
    try {
        exec(command, options, function (error, stdout, stderr) {
            console.log(`${path.resolve(options.cwd || '.')} ${chalk.cyan(command)}`);
            console.log(stdout);
            console.log(stderr);
            if (error !== null) {
                console.log('exec error: ', error);
            }
            callback();
        });
    } catch (ex) {
        console.log('rc ex', ex);
    }
}

/*
 * {cmd: "", cwd: ""}
 */
function runCommands(commands, parallel, callback) {
    if (parallel === true) {
        async.each(commands, function (command, done) {
            runCommand(command.cmd, { cwd: command.cwd }, done);
        }, function () {
            callback();
        });
    } else {
        async.eachSeries(commands, function (command, done) {
            runCommand(command.cmd, { cwd: command.cwd }, done);
        }, function () {
            callback();
        });
    }
}

// Setup

gulp.task('setup', 'Install all modules and link projects', function (callback) {
    G$.sequence('install', 'link', callback);
});

gulp.task('teardown', 'Clean all and unlink projects', function (callback) {
    G$.sequence('unlink', 'deepclean', callback);
});

// npm install

gulp.task('install', 'Install all npm modules', function (callback) {
    const commands = [];
    commands.push({ cmd: 'npm install', cwd: undefined });
    projectNames.forEach(name => {
        commands.push({ cmd: 'npm install', cwd: `projects/${name}` });
    });
    runCommands(commands, truncate, callback);
});

// npm link

gulp.task('link', 'Link dependencies on local disk', function (callback) {
    linker(true, callback);
});

gulp.task('unlink', 'Unlink dependencies on local disk', function (callback) {
    linker(false, callback);
});

function linker(mode, callback) {
    const linkCommands = [];
    const packageLinkCommands = [];
    projectNames.forEach(project => {
        linkCommands.push({ cmd: `npm ${mode ? 'link' : 'unlink'} --no-bin-links`, cwd: `projects/${project}` });
    });
    if (mode) {
        projectNames.forEach(project => {
            if (projects[project].dependencies) {
                projects[project].dependencies.forEach(dep => {
                    const packageName = require(`./projects/${dep}/package.json`).name;
                    packageLinkCommands.push({ cmd: `npm ${mode ? 'link' : 'unlink'} ${packageName} --no-bin-links`, cwd: `projects/${project}` });
                });
            }
        });
    }
    runCommands(linkCommands, true, () => {
        runCommands(packageLinkCommands, true, callback)
    });
    // info about "--no-bin-links" : see http://stackoverflow.com/questions/17990647/npm-install-errors-with-error-enoent-chmod
}

// Building

gulp.task('build', 'Compiles all TypeScript source files and updates module references', function (callback) {
    G$.sequence(['tslint', 'clean'], 'ts-all', callback);
});

gulp.task('watch', 'Contiuous build', ['build'], function () {
    projectNames.forEach(project => {
        gulp.watch(mapPaths(Array.prototype.concat(settings.tsfiles, settings.jsFiles), project), [`ts-${project}`]);
    });
});

// see https://www.npmjs.com/package/tslint
gulp.task('tslint', 'Lints all TypeScript source files', function () {
    return gulp.src(wildcharPaths(settings.tsfiles))
        .pipe(G$.tslint({ formatter: 'verbose' }))
        .pipe(G$.tslint.report({ emitError: false }));
});

// Cleaning

gulp.task('clean', 'Cleans the generated files from lib directory', function () {
    return del(expandPaths(settings.clean));
});

gulp.task('deepclean', 'Cleans the generated files from lib directory and all node_modules', function () {
    return del(expandPaths(settings.deepClean));
});

// Transpiling
projectNames.forEach(project => {
    gulp.task(`ts-${project}`, `Transpile ${chalk.green(project)}`, function () {
        const tsResult = gulp.src(mapPaths(settings.tsfiles, project))
            .pipe(G$.sourcemaps.init())
            .pipe(G$.typescript.createProject(tsconfig.compilerOptions)());
        const dest = mapPath(settings.dest, project);
        return merge([
            tsResult.dts.pipe(gulp.dest(dest)),
            tsResult.js
                .pipe(G$.sourcemaps.write('.')) // separate .js.map files
                .pipe(gulp.dest(dest)),
            // JS files
            gulp.src(mapPaths(settings.jsFiles, project)).pipe(G$.babel({
                presets: ['es2015']
            })).pipe(gulp.dest(dest)),
            // all other files
            gulp.src(mapPaths(settings.resources, project)).pipe(gulp.dest(dest))
        ]);
    });
});

gulp.task('ts-all', 'Transpile all projects', function (callback) {
    G$.sequence(projectNames.map(name => `ts-${name}`), callback);
});

// Extras

gulp.task('npm-i', `Install and save a ${chalk.cyan('pack')}age to a ${chalk.cyan('project')}`, function (project, pack, callback) {
    runCommand(`npm install --save ${pack}`, { cwd: mapPath(settings.projectPath, project) }, function () {
        callback();
    });
}, {
        options: {
            pack: 'Package name',
            project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
        }
    });

gulp.task('npm-u', `Uninstall and save a ${chalk.cyan('pack')}age to a ${chalk.cyan('project')}`, function (project, pack, callback) {
    runCommand(`npm uninstall --save ${pack}`, { cwd: mapPath(settings.projectPath, project) }, function () {
        callback();
    });
}, {
        options: {
            pack: 'Package name',
            project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
        }
    });

gulp.task('stats', 'Get lines of code', function (project) {
    console.log(project);
    if (project) {
        console.log(`Source Lines of Code: ${chalk.green(project)}`);
        gulp.src(mapPaths(settings.sloc_project, project)).pipe(G$.sloc({ tolerant: true }));
    } else {
        console.log(`Source Lines of Code: ${chalk.white('ALL')}`);
        gulp.src(settings.sloc_all).pipe(G$.sloc({ tolerant: true }));
    }
}, {
        options: {
            project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
        }
    });

gulp.task('size', 'Get size of code', function (project) {
    console.log(project);
    if (project) {
        console.log(`Source Lines of Code: ${chalk.green(project)}`);
        gulp.src(mapPaths(settings.runtimeFiles, project)).pipe(G$.size({ showFiles: true }));
    } else {
        console.log(`Source Lines of Code: ${chalk.white('ALL')}`);
        gulp.src(expandPaths(settings.runtimeFiles)).pipe(G$.size({ showFiles: true }));
    }
}, {
        options: {
            project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
        }
    });

// Deploying

function getPackageName(packagePath) {
    const packageFile = require(path.join(path.resolve(packagePath), 'package.json'));
    return `${packageFile.name}_${packageFile.version}`;
}

gulp.task('package', false, function () {
    const packageFileName = `${getPackageName(settings.edgeDir)}.tar`;
    return gulp.src(settings.packageFiles, { follow: true })
        .pipe(gulp.dest('dist/droplit-edge'))
        .pipe(G$.debug({ title: 'package:' }))
        .pipe(G$.tar(packageFileName))
        .pipe(G$.gzip())
        .pipe(gulp.dest('dist'));
});

gulp.task('clean-dist', false, function () {
    return del('dist');
});

gulp.task('move-temp', false, function () {
    return gulp.src(settings.edgeFiles, { follow: true })
        .pipe(gulp.dest('temp/droplit-edge'));
});

gulp.task('clean-temp', false, function () {
    return del('temp');
});

gulp.task('setup-package', false, function () {
    return gulp.src('./temp/droplit-edge/package.json')
        .pipe(jeditor(function (json) {
            const localConfig = require('./temp/droplit-edge/localsettings.json');
            if (Array.isArray(localConfig.plugins))
                localConfig.plugins.forEach(plugin => {
                    if (typeof plugin === 'string') {
                        json.dependencies[plugin] = `../../projects/${plugin}`;
                        return;
                    }

                    if (typeof plugin === 'object' && plugin.hasOwnProperty('name') && plugin.enabled !== false)
                        json.dependencies[plugin.name] = `../../projects/${plugin.name}`;
                });
            else
                Object.keys(localConfig.plugins).forEach(plugin => {
                    if (localConfig.plugins[plugin] && localConfig.plugins[plugin].enabled !== false) {
                        json.dependencies[plugin] = `../../projects/${plugin}`;
                    }
                });
            return json;
        }))
        .pipe(gulp.dest('temp/droplit-edge/'));
});

gulp.task('pre-install-dist', false, function () {
    return del('temp/droplit-edge/node_modules');
});

gulp.task('install-dist', false, function (callback) {
    runCommand('npm install', { cwd: 'temp/droplit-edge' }, () => {
        console.log('done');
        callback();
    });
});

gulp.task('build-dist', false, function (callback) {
    G$.sequence('clean-dist', 'build', 'unlink', 'move-temp', 'setup-package', 'pre-install-dist', 'install-dist', 'package', 'clean-temp', callback);
});

gulp.task('deploy', 'Glob the Droplit Edge for embedding', function (callback) {
    G$.sequence('setup', 'build-dist', callback);
});

// Testing for improving package
gulp.task('prep', false, function () {
    return del(expandPaths(settings.prep));
});

// Version bump

const bumpOpts = {
    options: {
        major: 'when you make incompatible API changes',
        minor: 'when you add functionality in a backwards-compatible manner',
        patch: 'when you make backwards-compatible bug fixes',
        project: `Project name: ${chalk.green(projectNames.join(chalk.white(', ')))}`
    }
};

gulp.task('bump', 'Version bump a project.', function (major, minor, patch, project) {
    if (!project) return console.log(`${chalk.red('No project specified!')}`);
    let type = '';
    if (major && !minor && !patch) type = 'major';
    if (!major && minor && !patch) type = 'minor';
    if (!major && !minor && patch) type = 'patch';
    if (!type) return console.log(`${chalk.red('Specify one version type to bump!')}`);
    const cwd = 'projects/project/';
    return gulp.src('./package.json', { cwd })
        .pipe(G$.bump({ type }))
        .pipe(gulp.dest('./', { cwd }));
}, bumpOpts);

gulp.task('debug', 'Debug droplit-edge', function () {
    const project = 'droplit-edge';
    G$.nodemon({
        script: `${project}.js`,
        ext: 'js',
        env: {
            DEBUG: 'droplit:*'
        },
        delay: 1, // Sec
        watch: `projects/${project}`,
        ignore: `projects/${project}/src`
    });
});

// .pipe(G$.plumber()) // exit gracefully if something fails after this

// gulp.task('test', 'Runs all tests', [], function () {
//     $.util.log(colors.cyan(`Testing ${settings.testGlob}`));

//     return gulp
//         .src(settings.testGlob, { read: true })
//         .pipe($.plumber()) // exit gracefully if something fails after this
//         .pipe($.mocha({ reporter: 'spec' }));
// });

// Attitional reference: https://github.com/johnpapa/gulp-patterns
// http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm<|endoftext|>


<commit_before>define([ "WebmakerUI", "localized", "dialog/dialog", "util/lang", "l10n!/layouts/header.html", "ui/widget/textbox", "ui/widget/tooltip", "ui/widget/ProjectDetails" ],
  function( WebmakerUI, Localized, Dialog, Lang, HEADER_TEMPLATE, TextBoxWrapper, ToolTip, ProjectDetails ) {

  return function( butter, options ){

    options = options || {};

    var TOOLTIP_NAME = "name-error-header-tooltip";

    var _this = this,
        _rootElement = Lang.domFragment( HEADER_TEMPLATE, ".butter-header" ),
        _bodyWrapper = document.querySelector( ".body-wrapper" ),
        _saveButton = _rootElement.querySelector( ".butter-save-btn" ),
        _projectTitle = _rootElement.querySelector( ".butter-project-title" ),
        _projectName = _projectTitle.querySelector( ".butter-project-name" ),
        _clearEvents = _rootElement.querySelector( ".butter-clear-events-btn" ),
        _removeProject = _rootElement.querySelector( ".butter-remove-project-btn" ),
        _previewBtn = _rootElement.querySelector( ".butter-preview-btn" ),
        _projectMenu = _rootElement.querySelector( ".butter-project-menu" ),
        _projectMenuControl = _rootElement.querySelector( ".butter-project-menu-control" ),
        _projectMenuList = _projectMenu.querySelector( ".butter-btn-menu" ),
        _noProjectNameToolTip,
        _makeDetails = _rootElement.querySelector( "#make-details" ),
        _projectTitlePlaceHolderText = _projectName.innerHTML,
        _toolTip, _loginTooltip,
        _projectDetails = new ProjectDetails( butter ),
        _langSelector = _rootElement.querySelector( "#lang-picker" );

    // URL redirector for language picker
    WebmakerUI.langPicker( _langSelector );

    // create a tooltip for the plrojectName element
    _toolTip = ToolTip.create({
      title: "header-title-tooltip",
      message: Localized.get( "Change the name of your project" ),
      element: _projectTitle,
      top: "60px"
    });

    // Default state
    _toolTip.hidden = true;

    _loginTooltip = ToolTip.create({
      title: "header-title-tooltip",
      message: Localized.get( "Login to save your project!" ),
      element: _projectTitle,
      top: "60px"
    });

    _this.element = _rootElement;

    ToolTip.apply( _projectTitle );

    function showErrorDialog( message ) {
      var dialog = Dialog.spawn( "error-message", {
        data: message,
        events: {
          cancel: function() {
            dialog.close();
          }
        }
      });
      dialog.open();
    }

    function afterSave() {
      openProjectEditor();
      togglePreviewButton( true );
      toggleProjectNameListeners( true );
      toggleDeleteProject( true );
    }

    function submitSave() {
      toggleSaveButton( false );

      butter.project.save(function( e ) {
        if ( e.error === "okay" ) {
          afterSave();
          return;
        } else {
          toggleSaveButton( true );
          togglePreviewButton( false );
          toggleProjectNameListeners( true );
          showErrorDialog( Localized.get( "There was a problem saving your project" ) );
        }
      });
    }

    function saveProject() {
      if ( butter.project.isSaved ) {
        return;
      } else if ( !checkProjectName( butter.project.name ) ) {
        nameError();
      } else if ( !butter.project.id ) {
        toggleSaveButton( false );
        _makeDetails.classList.remove( "butter-hidden" );
      } else {
        submitSave();
      }
    }

    function openProjectEditor() {
      butter.editor.openEditor( "project-editor" );
    }

    function toggleSaveButton( on ) {
      if ( on ) {
        _saveButton.classList.remove( "butter-disabled" );
        _saveButton.addEventListener( "click", saveProject, false );
      } else {
        _saveButton.classList.add( "butter-disabled" );
        _saveButton.removeEventListener( "click", saveProject, false );
      }
    }

    function togglePreviewButton( on ) {
      if ( on ) {
        _previewBtn.classList.remove( "butter-disabled" );
        _previewBtn.href = butter.project.publishUrl;
        _previewBtn.onclick = function() {
          return true;
        };
      } else {
        _previewBtn.classList.add( "butter-disabled" );
        _previewBtn.href = "";
        _previewBtn.onclick = function() {
          return false;
        };
      }
    }

    function toggleProjectNameListeners( state, tooltipIgnore ) {
      if ( state ) {
        _projectTitle.addEventListener( "click", projectNameClick, false );
        _projectName.classList.remove( "butter-disabled" );
        _projectName.addEventListener( "click", projectNameClick, false );
      } else {
        _projectTitle.removeEventListener( "click", projectNameClick, false );
        _projectName.removeEventListener( "click", projectNameClick, false );
        _projectName.classList.add( "butter-disabled" );
      }

      if ( !tooltipIgnore ) {
        _loginTooltip.hidden = state;
        _toolTip.hidden = !state;
      }
    }

    function removeProject() {
      var dialog;
      if ( butter.project.id && butter.project.isSaved ) {
        dialog = Dialog.spawn( "remove-project", {
          data: {
            callback: function() {
              butter.project.remove(function( e ) {

                if ( e.error === "okay" ) {
                  window.onbeforeunload = null;
                  window.history.replaceState( {}, "", "/" + Localized.getCurrentLang() + "/editor/" );
                  window.location.reload();
                } else {
                  showErrorDialog( Localized.get( "There was a problem saving your project" ) );
                }
              });
            }
          }
        });
        dialog.open();
      }
    }

    function toggleDeleteProject( state ) {
      if ( state ) {
        _removeProject.addEventListener( "click", removeProject, false );
        _removeProject.classList.remove( "butter-disabled" );
      } else {
        _removeProject.removeEventListener( "click", removeProject, false );
        _removeProject.classList.add( "butter-disabled" );
      }
    }

    function projectNameClick() {
      var input = document.createElement( "input" );

      input.type = "text";

      input.placeholder = _projectTitlePlaceHolderText;
      input.classList.add( "butter-project-name" );
      input.value = _projectName.textContent !== _projectTitlePlaceHolderText ? _projectName.textContent : "";
      TextBoxWrapper.applyTo( input );
      _projectTitle.replaceChild( input, _projectName );
      toggleProjectNameListeners( false, true );
      input.focus();
      input.addEventListener( "blur", onBlur, false );
      input.addEventListener( "keypress", onKeyPress, false );
    }

    function clearEventsClick() {
      var dialog;
      if ( butter.currentMedia && butter.currentMedia.hasTrackEvents() ) {
        dialog = Dialog.spawn( "delete-track-events", {
          data: butter
        });
        dialog.open();
      }
    }

    this.views = {
      dirty: function() {
        togglePreviewButton( false );
        toggleSaveButton( butter.cornfield.authenticated() );
      },
      clean: function() {
        togglePreviewButton( true );
        toggleSaveButton( false );
      },
      login: function() {
        var isSaved = butter.project.isSaved;

        toggleProjectNameListeners( butter.cornfield.authenticated() );
        togglePreviewButton( isSaved );
        toggleSaveButton( !isSaved && butter.cornfield.authenticated() );
        toggleDeleteProject( isSaved && butter.cornfield.authenticated() );
      },
      logout: function() {
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleProjectNameListeners( false );
      }
    };

    function destroyToolTip() {
      if ( _noProjectNameToolTip && !_noProjectNameToolTip.destroyed ) {
        _projectTitle.removeEventListener( "mouseover", destroyToolTip, false );
        _noProjectNameToolTip.destroy();
      }
    }

    function onKeyPress( e ) {
      var node = _projectTitle.querySelector( ".butter-project-name" );

      // if this wasn't the 'enter' key, return early
      if ( e.keyCode !== 13 ) {
        return;
      }

      node.blur();
      node.removeEventListener( "keypress", onKeyPress, false );
    }

    /*
     * Function: checkProjectName
     *
     * Checks whether the current projects name is a valid one or not.
     * @returns boolean value representing whether or not the current project name is valid
     */
    function checkProjectName( name ) {
      return !!name && name !== _projectTitlePlaceHolderText;
    }

    function nameError() {
      destroyToolTip();

      _projectTitle.addEventListener( "mouseover", destroyToolTip, false );

      _noProjectNameToolTip = ToolTip.create({
        name: TOOLTIP_NAME,
        message: Localized.get( "Please give your project a name before saving" ),
        hidden: false,
        hover: false,
        element: _projectTitle,
        top: "60px",
        error: true
      });
    }

    function onBlur() {
      var node = _projectTitle.querySelector( ".butter-project-name" );
      node.removeEventListener( "blur", onBlur, false );

      _projectName.textContent = node.value || _projectTitlePlaceHolderText;
      if( checkProjectName( _projectName.textContent ) ) {
        butter.project.name = _projectName.textContent;
        saveProject();
      } else {
        nameError();
        toggleProjectNameListeners( true );
      }

      _projectTitle.replaceChild( _projectName, node );
    }

    this.attachToDOM = function() {
      document.body.classList.add( "butter-header-spacing" );
      document.body.insertBefore( _rootElement, document.body.firstChild );

      loadDashboard();
    };

    butter.listen( "authenticated", _this.views.login, false );
    butter.listen( "logout", _this.views.logout, false );

    butter.listen( "projectsaved", function() {
      // Disable "Save" button
      _this.views.clean();
      toggleDeleteProject( true );
      _projectName.textContent = butter.project.name;
    });

    butter.listen( "projectchanged", function() {
      // Re-enable "Save" button to indicate things are not saved
      _this.views.dirty();
    });

    function loadDashboard() {
      var myProjectsButton = document.querySelector( ".my-makes" ),
          container = document.querySelector( ".my-projects-container" ),
          iframe = document.querySelector( ".my-projects-iframe" );

     function close() {
        myProjectsButton.addEventListener( "click", open, false );
        myProjectsButton.removeEventListener( "click", close, false );

        container.classList.remove( "open" );
        iframe.style.height = "";
      }

      function open() {
        myProjectsButton.addEventListener( "click", close, false );
        myProjectsButton.removeEventListener( "click", open, false );

        container.classList.add( "open" );
        iframe.style.height = "300px";
        iframe.src = "/dashboard/" + Localized.getCurrentLang();
      }

      myProjectsButton.addEventListener( "click", open, false );
    }

    butter.listen( "ready", function() {
      if ( butter.project.name && ( butter.project.id || butter.project.isRemix ) ) {
        _projectName.textContent = butter.project.name;
      }

      if ( !butter.cornfield.authenticated() ) {
        toggleProjectNameListeners( false );
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleDeleteProject( false );
      }

      _projectDetails.thumbnail( _makeDetails.querySelector( "[name='thumbnail']" ) );
      _projectDetails.tags( _makeDetails.querySelector( "[name='tags']" ) );
      _projectDetails.description( _makeDetails.querySelector( "[name='description']" ) );
      _projectDetails.buttons( _makeDetails.querySelector( "[name='buttons']" ), function( save ) {
        if ( save ) {
          submitSave();
        }

        _makeDetails.classList.add( "butter-hidden" );
        toggleSaveButton( true );
        togglePreviewButton( false );
        toggleProjectNameListeners( true );
      });

      _clearEvents.addEventListener( "click", clearEventsClick, false );
    });
  };
});
<commit_msg>added code to hide the makes panel if clicked outside of it<commit_after>define([ "WebmakerUI", "localized", "dialog/dialog", "util/lang", "l10n!/layouts/header.html", "ui/widget/textbox", "ui/widget/tooltip", "ui/widget/ProjectDetails" ],
  function( WebmakerUI, Localized, Dialog, Lang, HEADER_TEMPLATE, TextBoxWrapper, ToolTip, ProjectDetails ) {

  return function( butter, options ){

    options = options || {};

    var TOOLTIP_NAME = "name-error-header-tooltip";

    var _this = this,
        _rootElement = Lang.domFragment( HEADER_TEMPLATE, ".butter-header" ),
        _bodyWrapper = document.querySelector( ".body-wrapper" ),
        _saveButton = _rootElement.querySelector( ".butter-save-btn" ),
        _projectTitle = _rootElement.querySelector( ".butter-project-title" ),
        _projectName = _projectTitle.querySelector( ".butter-project-name" ),
        _clearEvents = _rootElement.querySelector( ".butter-clear-events-btn" ),
        _removeProject = _rootElement.querySelector( ".butter-remove-project-btn" ),
        _previewBtn = _rootElement.querySelector( ".butter-preview-btn" ),
        _projectMenu = _rootElement.querySelector( ".butter-project-menu" ),
        _projectMenuControl = _rootElement.querySelector( ".butter-project-menu-control" ),
        _projectMenuList = _projectMenu.querySelector( ".butter-btn-menu" ),
        _noProjectNameToolTip,
        _makeDetails = _rootElement.querySelector( "#make-details" ),
        _projectTitlePlaceHolderText = _projectName.innerHTML,
        _toolTip, _loginTooltip,
        _projectDetails = new ProjectDetails( butter ),
        _langSelector = _rootElement.querySelector( "#lang-picker" );

    // URL redirector for language picker
    WebmakerUI.langPicker( _langSelector );

    // create a tooltip for the plrojectName element
    _toolTip = ToolTip.create({
      title: "header-title-tooltip",
      message: Localized.get( "Change the name of your project" ),
      element: _projectTitle,
      top: "60px"
    });

    // Default state
    _toolTip.hidden = true;

    _loginTooltip = ToolTip.create({
      title: "header-title-tooltip",
      message: Localized.get( "Login to save your project!" ),
      element: _projectTitle,
      top: "60px"
    });

    _this.element = _rootElement;

    ToolTip.apply( _projectTitle );

    function showErrorDialog( message ) {
      var dialog = Dialog.spawn( "error-message", {
        data: message,
        events: {
          cancel: function() {
            dialog.close();
          }
        }
      });
      dialog.open();
    }

    function afterSave() {
      openProjectEditor();
      togglePreviewButton( true );
      toggleProjectNameListeners( true );
      toggleDeleteProject( true );
    }

    function submitSave() {
      toggleSaveButton( false );

      butter.project.save(function( e ) {
        if ( e.error === "okay" ) {
          afterSave();
          return;
        } else {
          toggleSaveButton( true );
          togglePreviewButton( false );
          toggleProjectNameListeners( true );
          showErrorDialog( Localized.get( "There was a problem saving your project" ) );
        }
      });
    }

    function saveProject() {
      if ( butter.project.isSaved ) {
        return;
      } else if ( !checkProjectName( butter.project.name ) ) {
        nameError();
      } else if ( !butter.project.id ) {
        toggleSaveButton( false );
        _makeDetails.classList.remove( "butter-hidden" );
      } else {
        submitSave();
      }
    }

    function openProjectEditor() {
      butter.editor.openEditor( "project-editor" );
    }

    function toggleSaveButton( on ) {
      if ( on ) {
        _saveButton.classList.remove( "butter-disabled" );
        _saveButton.addEventListener( "click", saveProject, false );
      } else {
        _saveButton.classList.add( "butter-disabled" );
        _saveButton.removeEventListener( "click", saveProject, false );
      }
    }

    function togglePreviewButton( on ) {
      if ( on ) {
        _previewBtn.classList.remove( "butter-disabled" );
        _previewBtn.href = butter.project.publishUrl;
        _previewBtn.onclick = function() {
          return true;
        };
      } else {
        _previewBtn.classList.add( "butter-disabled" );
        _previewBtn.href = "";
        _previewBtn.onclick = function() {
          return false;
        };
      }
    }

    function toggleProjectNameListeners( state, tooltipIgnore ) {
      if ( state ) {
        _projectTitle.addEventListener( "click", projectNameClick, false );
        _projectName.classList.remove( "butter-disabled" );
        _projectName.addEventListener( "click", projectNameClick, false );
      } else {
        _projectTitle.removeEventListener( "click", projectNameClick, false );
        _projectName.removeEventListener( "click", projectNameClick, false );
        _projectName.classList.add( "butter-disabled" );
      }

      if ( !tooltipIgnore ) {
        _loginTooltip.hidden = state;
        _toolTip.hidden = !state;
      }
    }

    function removeProject() {
      var dialog;
      if ( butter.project.id && butter.project.isSaved ) {
        dialog = Dialog.spawn( "remove-project", {
          data: {
            callback: function() {
              butter.project.remove(function( e ) {

                if ( e.error === "okay" ) {
                  window.onbeforeunload = null;
                  window.history.replaceState( {}, "", "/" + Localized.getCurrentLang() + "/editor/" );
                  window.location.reload();
                } else {
                  showErrorDialog( Localized.get( "There was a problem saving your project" ) );
                }
              });
            }
          }
        });
        dialog.open();
      }
    }

    function toggleDeleteProject( state ) {
      if ( state ) {
        _removeProject.addEventListener( "click", removeProject, false );
        _removeProject.classList.remove( "butter-disabled" );
      } else {
        _removeProject.removeEventListener( "click", removeProject, false );
        _removeProject.classList.add( "butter-disabled" );
      }
    }

    function projectNameClick() {
      var input = document.createElement( "input" );

      input.type = "text";

      input.placeholder = _projectTitlePlaceHolderText;
      input.classList.add( "butter-project-name" );
      input.value = _projectName.textContent !== _projectTitlePlaceHolderText ? _projectName.textContent : "";
      TextBoxWrapper.applyTo( input );
      _projectTitle.replaceChild( input, _projectName );
      toggleProjectNameListeners( false, true );
      input.focus();
      input.addEventListener( "blur", onBlur, false );
      input.addEventListener( "keypress", onKeyPress, false );
    }

    function clearEventsClick() {
      var dialog;
      if ( butter.currentMedia && butter.currentMedia.hasTrackEvents() ) {
        dialog = Dialog.spawn( "delete-track-events", {
          data: butter
        });
        dialog.open();
      }
    }

    this.views = {
      dirty: function() {
        togglePreviewButton( false );
        toggleSaveButton( butter.cornfield.authenticated() );
      },
      clean: function() {
        togglePreviewButton( true );
        toggleSaveButton( false );
      },
      login: function() {
        var isSaved = butter.project.isSaved;

        toggleProjectNameListeners( butter.cornfield.authenticated() );
        togglePreviewButton( isSaved );
        toggleSaveButton( !isSaved && butter.cornfield.authenticated() );
        toggleDeleteProject( isSaved && butter.cornfield.authenticated() );
      },
      logout: function() {
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleProjectNameListeners( false );
      }
    };

    function destroyToolTip() {
      if ( _noProjectNameToolTip && !_noProjectNameToolTip.destroyed ) {
        _projectTitle.removeEventListener( "mouseover", destroyToolTip, false );
        _noProjectNameToolTip.destroy();
      }
    }

    function onKeyPress( e ) {
      var node = _projectTitle.querySelector( ".butter-project-name" );

      // if this wasn't the 'enter' key, return early
      if ( e.keyCode !== 13 ) {
        return;
      }

      node.blur();
      node.removeEventListener( "keypress", onKeyPress, false );
    }

    /*
     * Function: checkProjectName
     *
     * Checks whether the current projects name is a valid one or not.
     * @returns boolean value representing whether or not the current project name is valid
     */
    function checkProjectName( name ) {
      return !!name && name !== _projectTitlePlaceHolderText;
    }

    function nameError() {
      destroyToolTip();

      _projectTitle.addEventListener( "mouseover", destroyToolTip, false );

      _noProjectNameToolTip = ToolTip.create({
        name: TOOLTIP_NAME,
        message: Localized.get( "Please give your project a name before saving" ),
        hidden: false,
        hover: false,
        element: _projectTitle,
        top: "60px",
        error: true
      });
    }

    function onBlur() {
      var node = _projectTitle.querySelector( ".butter-project-name" );
      node.removeEventListener( "blur", onBlur, false );

      _projectName.textContent = node.value || _projectTitlePlaceHolderText;
      if( checkProjectName( _projectName.textContent ) ) {
        butter.project.name = _projectName.textContent;
        saveProject();
      } else {
        nameError();
        toggleProjectNameListeners( true );
      }

      _projectTitle.replaceChild( _projectName, node );
    }

    this.attachToDOM = function() {
      document.body.classList.add( "butter-header-spacing" );
      document.body.insertBefore( _rootElement, document.body.firstChild );

      loadDashboard();
    };

    butter.listen( "authenticated", _this.views.login, false );
    butter.listen( "logout", _this.views.logout, false );

    butter.listen( "projectsaved", function() {
      // Disable "Save" button
      _this.views.clean();
      toggleDeleteProject( true );
      _projectName.textContent = butter.project.name;
    });

    butter.listen( "projectchanged", function() {
      // Re-enable "Save" button to indicate things are not saved
      _this.views.dirty();
    });

    function loadDashboard() {
      var myProjectsButton = document.querySelector( ".my-makes" ),
          container = document.querySelector( ".my-projects-container" ),
          iframe = document.querySelector( ".my-projects-iframe" );

     function close() {
        document.removeEventListener( "mousedown", close, false );
        myProjectsButton.addEventListener( "click", open, false );
        myProjectsButton.removeEventListener( "click", close, false );

        container.classList.remove( "open" );
        iframe.style.height = "";
      }

      function open() {
        myProjectsButton.addEventListener( "click", close, false );
        myProjectsButton.removeEventListener( "click", open, false );

        container.classList.add( "open" );
        iframe.style.height = "300px";
        iframe.src = "/dashboard/" + Localized.getCurrentLang();
        // WARNING: this works because we don't use mousedown in other events,
        //          but only click events, which trigger after mousedown. If we
        //          do add more mousedown events, this may introduce timing issues.
        document.addEventListener( "mousedown", close, false );
      }

      myProjectsButton.addEventListener( "click", open, false );
    }

    butter.listen( "ready", function() {
      if ( butter.project.name && ( butter.project.id || butter.project.isRemix ) ) {
        _projectName.textContent = butter.project.name;
      }

      if ( !butter.cornfield.authenticated() ) {
        toggleProjectNameListeners( false );
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleDeleteProject( false );
      }

      _projectDetails.thumbnail( _makeDetails.querySelector( "[name='thumbnail']" ) );
      _projectDetails.tags( _makeDetails.querySelector( "[name='tags']" ) );
      _projectDetails.description( _makeDetails.querySelector( "[name='description']" ) );
      _projectDetails.buttons( _makeDetails.querySelector( "[name='buttons']" ), function( save ) {
        if ( save ) {
          submitSave();
        }

        _makeDetails.classList.add( "butter-hidden" );
        toggleSaveButton( true );
        togglePreviewButton( false );
        toggleProjectNameListeners( true );
      });

      _clearEvents.addEventListener( "click", clearEventsClick, false );
    });
  };
});
<|endoftext|>


<commit_before>$(function() {

	CMS.init({

		// Name of your site or location of logo file ,relative to root directory (img/logo.png)
		siteName: 'CXP | Blog',

		// Tagline for your site
		siteTagline: '',

		// Email address
		siteEmail: 'info@commerce-experts.com',

		// Name
		siteAuthor: 'CXP - Commerce Experts',

		// Navigation items
		siteNavItems: [
			{ name: 'Home'},
			{ name: 'Main Site', href: 'http://www.commerce-experts.com', newWindow: false}
		],

		// Posts folder name
		postsFolder: 'posts',

		// Homepage posts snippet length
		postSnippetLength: 120,

		// Pages folder name
		pagesFolder: 'pages',

		// Site fade speed
		fadeSpeed: 50,

		// Site footer text
		footerText: '© ' + new Date().getFullYear() + ' CXP Commerce Experts UG (haftungsbeschränkt)',

		// Mode 'Github' for Github Pages, 'Apache' for Apache server. Defaults
		// to Github
		mode: 'Github',

		// If Github mode is set, your Github username and repo name. Defaults
		// to Github pages branch (gh-pages)
		githubUserSettings: {
			username: 'commerce-experts',
			repo: 'blog'
		}

	});

	// Markdown settings
	marked.setOptions({
		renderer: new marked.Renderer(),
		gfm: true,
		tables: true,
		breaks: false,
		pedantic: false,
		sanitize: true,
		smartLists: true,
		smartypants: false
	});

});
<commit_msg>added link<commit_after>$(function() {

	CMS.init({

		// Name of your site or location of logo file ,relative to root directory (img/logo.png)
		siteName: 'CXP | Blog',

		// Tagline for your site
		siteTagline: '',

		// Email address
		siteEmail: 'info@commerce-experts.com',

		// Name
		siteAuthor: 'CXP - Commerce Experts',

		// Navigation items
		siteNavItems: [
			{ name: 'Home', href: 'http://blog.commerce-experts.com', newWindow: false},
			{ name: 'Main Site', href: 'http://www.commerce-experts.com', newWindow: false}
		],

		// Posts folder name
		postsFolder: 'posts',

		// Homepage posts snippet length
		postSnippetLength: 120,

		// Pages folder name
		pagesFolder: 'pages',

		// Site fade speed
		fadeSpeed: 50,

		// Site footer text
		footerText: '© ' + new Date().getFullYear() + ' CXP Commerce Experts UG (haftungsbeschränkt)',

		// Mode 'Github' for Github Pages, 'Apache' for Apache server. Defaults
		// to Github
		mode: 'Github',

		// If Github mode is set, your Github username and repo name. Defaults
		// to Github pages branch (gh-pages)
		githubUserSettings: {
			username: 'commerce-experts',
			repo: 'blog'
		}

	});

	// Markdown settings
	marked.setOptions({
		renderer: new marked.Renderer(),
		gfm: true,
		tables: true,
		breaks: false,
		pedantic: false,
		sanitize: true,
		smartLists: true,
		smartypants: false
	});

});
<|endoftext|>


<commit_before>var browsersync = require('browser-sync');
var reload      = browsersync.reload;
var gulp        = require('gulp');
var runSequence = require('run-sequence');
var pngquant    = require('imagemin-pngquant');
var pkg         = require( process.cwd() + '/package.json');

var autoprefixerBrowsers = ['> 1%', 'last 2 versions'];

var headerBanner = [
'/*!',
' * <%= pkg.name %> - <%= pkg.description %>',
' * @version v<%= pkg.version %>',
' * @link    <%= pkg.homepage %>',
' * @author  <%= pkg.author %>',
' * @license <%= pkg.license %>',
' */',
''].join('\n');

gulp.task('browserify', function(){
  return require(process.cwd() + '/lib/browserify')({
    bundleName:  "bundle.js",
    src:  './sandbox/src/browserify/main.js',
    dest: './sandbox/build/browserify',
  });
});

gulp.task('rubysass', function(){
  return require(process.cwd() + '/lib/rubysass')({
    src: './sandbox/src/scss/sass.scss',
    dest: './sandbox/build/rubysass/',
    rubySassOptions: {
      sourcemap: true,
      noCache: true,
    },
    autoprefixer: autoprefixerBrowsers,
    fallback:{
      use:true,
      colorHexOptions:{rgba: true}
    },
    filter:'**/*.css',
    headerBanner : true,
    banner:headerBanner,
    pkg: pkg,
    notify :"Compiled RubySass"
  });
});

gulp.task('cssmin', function(){
  return require(process.cwd() + '/lib/cssmin')({
    src:  './sandbox/build/**/*.css',
    dest: './sandbox/build/cssmin/'
  });
});

gulp.task('csslint', function(){
  return require(process.cwd() + '/lib/csslint')({
    // csslint: './.csslintrc',
    src:  './sandbox/build/**/*.css',
  });
});

gulp.task('concat', function(){
  return require(process.cwd() + '/lib/concat')({
    src:  './sandbox/src/js/*.js',
    dest: './sandbox/build/js',
    name: 'concat.js'
  });
});

gulp.task('jsmin', function(){
  return require(process.cwd() + '/lib/jsmin')({
    src:  './sandbox/src/js/concat.js',
    dest: './sandbox/build/js/'
  });
});

gulp.task('jshint', function(){
  return require(process.cwd() + '/lib/jshint')({
    // jshintPath: './.jshintrc',
    src:  './sandbox/build/js/concat.js'
  });
});

gulp.task('image', function(){
  return require(process.cwd() + '/lib/image')({
    src:  './sandbox/src/images/**/*',
    dest: './sandbox/build/images',
    options:{
      progressive: true,
      svgoPlugins: [{removeViewBox: false}],
      use: [pngquant()]
    }
  });
});

gulp.task('svg2png', function(){
  return require(process.cwd() + '/lib/svg2png')({
    src:  './sandbox/src/images/**/*.svg',
    dest: './sandbox/src/images'
  });
});

gulp.task('iconfont', function(){
  return require(process.cwd() + '/lib/iconfont')({
    name:     'icon',
    svgSrc:   './sandbox/src/icon/svg/*.svg',
    cssSrc:   './sandbox/src/icon/css/template.css',
    cssDest:  './sandbox/build/icon/css',
    fontPath: '../font/',
    dest:     './sandbox/build/icon/font'
  });
});

gulp.task('sftp', function(){
  return require(process.cwd() + '/lib/sftp')({
    src:'production',
    options: {
      host: 'example.com',
      port: '22',
      user: 'user_name',
      pass: '1234',
      remotePath: ''
    }
  });
});

gulp.task('banner', function(){
  return require(process.cwd() + '/lib/banner')({
    src:  './sandbox/build/js/concat.js',
    dest:  './sandbox/build/js/banner',
    pkg: pkg,
    banner:headerBanner
  });
});

gulp.task('bump', function(){
  return require(process.cwd() + '/lib/bump')({
    version: pkg.version,
    src:  './bower.json',
    dest: '.'
  });
});

gulp.task('uninstall', function(){
  return require(process.cwd() + '/lib/uninstall')({
    files:[
      "./sandbox/build"
    ]
  });
});

gulp.task('browsersync', function(){
  browsersync({
    server: "./sandbox",
  });
});

gulp.task('default',['browsersync'], function(){
  gulp.watch(['./sandbox/src/scss/*.scss'], ['rubysass']);
  gulp.watch(['./sandbox/src/browserify/*.js'], ['browserify']);
  gulp.watch("./sandbox/build/*/*.{css,js}").on('change', reload);
});

gulp.task('build', function(){
  runSequence(
    'uninstall',
    'browserify',
    'rubysass',
    'concat',
    ['cssmin','jsmin','svg2png'],
    'image',
    'banner',
    'jshint',
    // 'csslint',
    'iconfont'
  );
});
<commit_msg>Update sass task options<commit_after>var browsersync = require('browser-sync');
var reload      = browsersync.reload;
var gulp        = require('gulp');
var runSequence = require('run-sequence');
var pngquant    = require('imagemin-pngquant');
var pkg         = require( process.cwd() + '/package.json');

var autoprefixerBrowsers = ['> 1%', 'last 2 versions'];

var headerBanner = [
'/*!',
' * <%= pkg.name %> - <%= pkg.description %>',
' * @version v<%= pkg.version %>',
' * @link    <%= pkg.homepage %>',
' * @author  <%= pkg.author %>',
' * @license <%= pkg.license %>',
' */',
''].join('\n');

gulp.task('browserify', function(){
  return require(process.cwd() + '/lib/browserify')({
    bundleName:  "bundle.js",
    src:  './sandbox/src/browserify/main.js',
    dest: './sandbox/build/browserify',
  });
});

gulp.task('sass', function(){
  return require(process.cwd() + '/lib/sass')({
    src: './sandbox/src/scss/sass.scss',
    dest: './sandbox/build/sass/',
    rubySass: {
      sourcemap: true,
      noCache: true,
    },
    fallback:{
      autoprefixer: ['> 1%', 'last 2 versions'],
      opacity:true,
      rgba:true,
      pixrem:true
    },
    banner: {
      content: headerBanner,
      pkg: pkg
    }
  });
});

gulp.task('cssmin', function(){
  return require(process.cwd() + '/lib/cssmin')({
    src:  './sandbox/build/**/*.css',
    dest: './sandbox/build/cssmin/'
  });
});

gulp.task('csslint', function(){
  return require(process.cwd() + '/lib/csslint')({
    // csslint: './.csslintrc',
    src:  './sandbox/build/**/*.css',
  });
});

gulp.task('concat', function(){
  return require(process.cwd() + '/lib/concat')({
    src:  './sandbox/src/js/*.js',
    dest: './sandbox/build/js',
    name: 'concat.js'
  });
});

gulp.task('jsmin', function(){
  return require(process.cwd() + '/lib/jsmin')({
    src:  './sandbox/src/js/concat.js',
    dest: './sandbox/build/js/'
  });
});

gulp.task('jshint', function(){
  return require(process.cwd() + '/lib/jshint')({
    // jshintPath: './.jshintrc',
    src:  './sandbox/build/js/concat.js'
  });
});

gulp.task('image', function(){
  return require(process.cwd() + '/lib/image')({
    src:  './sandbox/src/images/**/*',
    dest: './sandbox/build/images',
    options:{
      progressive: true,
      svgoPlugins: [{removeViewBox: false}],
      use: [pngquant()]
    }
  });
});

gulp.task('svg2png', function(){
  return require(process.cwd() + '/lib/svg2png')({
    src:  './sandbox/src/images/**/*.svg',
    dest: './sandbox/src/images'
  });
});

gulp.task('iconfont', function(){
  return require(process.cwd() + '/lib/iconfont')({
    name:     'icon',
    svgSrc:   './sandbox/src/icon/svg/*.svg',
    cssSrc:   './sandbox/src/icon/css/template.css',
    cssDest:  './sandbox/build/icon/css',
    fontPath: '../font/',
    dest:     './sandbox/build/icon/font'
  });
});

gulp.task('sftp', function(){
  return require(process.cwd() + '/lib/sftp')({
    src:'production',
    options: {
      host: 'example.com',
      port: '22',
      user: 'user_name',
      pass: '1234',
      remotePath: ''
    }
  });
});

gulp.task('banner', function(){
  return require(process.cwd() + '/lib/banner')({
    src:  './sandbox/build/js/concat.js',
    dest:  './sandbox/build/js/banner',
    pkg: pkg,
    banner:headerBanner
  });
});

gulp.task('uninstall', function(){
  return require(process.cwd() + '/lib/uninstall')({
    files:[
      "./sandbox/build"
    ]
  });
});

gulp.task('browsersync', function(){
  browsersync({
    server: "./sandbox",
  });
});

gulp.task('default',['browsersync'], function(){
  gulp.watch(['./sandbox/src/scss/*.scss'], ['rubysass']);
  gulp.watch(['./sandbox/src/browserify/*.js'], ['browserify']);
  gulp.watch("./sandbox/build/*/*.{css,js}").on('change', reload);
});

gulp.task('build', function(){
  runSequence(
    'uninstall',
    'browserify',
    'rubysass',
    'concat',
    ['cssmin','jsmin','svg2png'],
    'image',
    'banner',
    'jshint',
    // 'csslint',
    'iconfont'
  );
});
<|endoftext|>


<commit_before>var consts = {};

consts.isBeta = false;<commit_msg>Update beta flag<commit_after>var consts = {};

consts.isBeta = true;<|endoftext|>


<commit_before>import React from 'react';
import cx from 'classnames';
import omit from 'lodash.omit';
import { t, props } from 'tcomb-react';
import { cookie as cookieLite } from 'browser-cookie-lite';
import styleUtils from './styleUtils';
t.interface.strict = true;

const Props = {
  children: t.maybe(t.ReactChildren),
  message: t.maybe(t.String),
  onAccept: t.maybe(t.Function),
  link: t.maybe(t.interface({
    msg: t.maybe(t.String),
    url: t.String,
    target: t.maybe(t.enums.of(['_blank', '_self', '_parent', '_top', 'framename']))
  })),
  buttonMessage: t.maybe(t.String),
  cookie: t.maybe(t.String),
  cookieExpiration: t.maybe(t.union([
    t.Integer,
    t.interface({
      years: t.maybe(t.Number),
      days: t.maybe(t.Number),
      hours: t.maybe(t.Number)
    })
  ])),
  dismissOnScroll: t.maybe(t.Boolean),
  dismissOnScrollThreshold: t.maybe(t.Number),
  closeIcon: t.maybe(t.String),
  disableStyle: t.maybe(t.Boolean),
  styles: t.maybe(t.Object),
  className: t.maybe(t.String)
};

/** React Cookie banner dismissable with just a scroll!
 * @param children - custom component rendered if user has not accepted cookies
 * @param message - message written inside default cookie banner
 * @param onAccept - called when user accepts cookies
 * @param link - object with infos used to render a link to your cookie-policy page
 * @param buttonMessage - message written inside the button of the default cookie banner
 * @param cookie - cookie-key used to save user's decision about you cookie-policy
 * @param dismissOnScroll - wheter the cookie banner should be dismissed on scroll or not
 * @param dismissOnScrollThreshold - amount of pixel the user need to scroll to dismiss the cookie banner
 * @param closeIcon - className passed to close-icon
 * @param disableStyle - pass `true` if you want to disable default style
 * @param styles - object with custom styles used to overwrite default ones
 */
@props(Props, { strict: false })
export default class CookieBanner extends React.Component {

  static defaultProps = {
    onAccept: () => {},
    dismissOnScroll: true,
    cookie: 'accepts-cookies',
    cookieExpiration: { years: 1 },
    buttonMessage: 'Got it',
    dismissOnScrollThreshold: 0,
    styles: {}
  };

  state = { listeningScroll: false }

  componentDidMount() {
    this.addOnScrollListener();
  }

  addOnScrollListener = (props) => {
    props = props || this.props;
    if (!this.state.listeningScroll && !this.hasAcceptedCookies() && props.dismissOnScroll) {
      if (window.attachEvent) {
        //Internet Explorer
        window.attachEvent('onscroll', this.onScroll);
      } else if(window.addEventListener) {
        window.addEventListener('scroll', this.onScroll, false);
      }
      this.setState({ listeningScroll: true });
    }
  }

  removeOnScrollListener = () => {
    if (this.state.listeningScroll) {
      if (window.detachEvent) {
        //Internet Explorer
        window.detachEvent('onscroll', this.onScroll);
      } else if(window.removeEventListener) {
        window.removeEventListener('scroll', this.onScroll, false);
      }
      this.setState({ listeningScroll: false });
    }
  }

  onScroll = () => {
    // tacit agreement buahaha! (evil laugh)
    if (window.pageYOffset > this.props.dismissOnScrollThreshold) {
      this.onAccept();
    }
  }

  getSecondsSinceExpiration = cookieExpiration => {
    if (t.Integer.is(cookieExpiration)) {
      return cookieExpiration;
    }

    const SECONDS_IN_YEAR = 31536000;
    const SECONDS_IN_DAY = 86400;
    const SECONDS_IN_HOUR = 3600;

    const _cookieExpiration = {
      years: 0, days: 0, hours: 0,
      ...cookieExpiration
    };

    const { years, days, hours } = _cookieExpiration;

    return (years * SECONDS_IN_YEAR) + (days * SECONDS_IN_DAY) + (hours * SECONDS_IN_HOUR);
  }

  onAccept = () => {
    const { cookie, cookieExpiration, onAccept } = this.props;

    cookieLite(cookie, true, this.getSecondsSinceExpiration(cookieExpiration));
    onAccept({ cookie });

    if (this.state.listeningScroll) {
      this.removeOnScrollListener();
    } else {
      this.forceUpdate();
    }
  }

  getStyle = (style) => {
    const { disableStyle, styles } = this.props;
    if (!disableStyle) {
      // apply custom styles if available
      return { ...styleUtils.getStyle(style), ...styles[style] };
    }
  }

  getCloseButton = () => {
    const { closeIcon, buttonMessage } = this.props;
    if (closeIcon) {
      return ;
    }
    return (

        {buttonMessage}

    );
  }

  getLink = () => {
    const { link } = this.props;
    if (link) {
      return (

            {link.msg || 'Learn more'}

      );
    }
  }

  getBanner = () => {
    const { children, className, message } = this.props;
    if (children) {
      return children;
    }

    const props = omit(this.props, Object.keys(Props));
    return (

          {message}
          {this.getLink()}

        {this.getCloseButton()}

    );
  }

  hasAcceptedCookies = () => {
    return (typeof window !== 'undefined') && cookieLite(this.props.cookie);
  }

  render() {
    return this.hasAcceptedCookies() ? null : this.getBanner();
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.dismissOnScroll) {
      this.addOnScrollListener(nextProps);
    } else {
      this.removeOnScrollListener();
    }
  }

  componentWillUnmount() {
    this.removeOnScrollListener();
  }

}
<commit_msg>add missing prop doc for "cookieExpiration"<commit_after>import React from 'react';
import cx from 'classnames';
import omit from 'lodash.omit';
import { t, props } from 'tcomb-react';
import { cookie as cookieLite } from 'browser-cookie-lite';
import styleUtils from './styleUtils';
t.interface.strict = true;

const Props = {
  children: t.maybe(t.ReactChildren),
  message: t.maybe(t.String),
  onAccept: t.maybe(t.Function),
  link: t.maybe(t.interface({
    msg: t.maybe(t.String),
    url: t.String,
    target: t.maybe(t.enums.of(['_blank', '_self', '_parent', '_top', 'framename']))
  })),
  buttonMessage: t.maybe(t.String),
  cookie: t.maybe(t.String),
  cookieExpiration: t.maybe(t.union([
    t.Integer,
    t.interface({
      years: t.maybe(t.Number),
      days: t.maybe(t.Number),
      hours: t.maybe(t.Number)
    })
  ])),
  dismissOnScroll: t.maybe(t.Boolean),
  dismissOnScrollThreshold: t.maybe(t.Number),
  closeIcon: t.maybe(t.String),
  disableStyle: t.maybe(t.Boolean),
  styles: t.maybe(t.Object),
  className: t.maybe(t.String)
};

/** React Cookie banner dismissable with just a scroll!
 * @param children - custom component rendered if user has not accepted cookies
 * @param message - message written inside default cookie banner
 * @param onAccept - called when user accepts cookies
 * @param link - object with infos used to render a link to your cookie-policy page
 * @param buttonMessage - message written inside the button of the default cookie banner
 * @param cookie - cookie-key used to save user's decision about you cookie-policy
 * @param cookieExpiration - used to set the cookie expiration
 * @param dismissOnScroll - whether the cookie banner should be dismissed on scroll or not
 * @param dismissOnScrollThreshold - amount of pixel the user need to scroll to dismiss the cookie banner
 * @param closeIcon - className passed to close-icon
 * @param disableStyle - pass `true` if you want to disable default style
 * @param styles - object with custom styles used to overwrite default ones
 */
@props(Props, { strict: false })
export default class CookieBanner extends React.Component {

  static defaultProps = {
    onAccept: () => {},
    dismissOnScroll: true,
    cookie: 'accepts-cookies',
    cookieExpiration: { years: 1 },
    buttonMessage: 'Got it',
    dismissOnScrollThreshold: 0,
    styles: {}
  };

  state = { listeningScroll: false }

  componentDidMount() {
    this.addOnScrollListener();
  }

  addOnScrollListener = (props) => {
    props = props || this.props;
    if (!this.state.listeningScroll && !this.hasAcceptedCookies() && props.dismissOnScroll) {
      if (window.attachEvent) {
        //Internet Explorer
        window.attachEvent('onscroll', this.onScroll);
      } else if(window.addEventListener) {
        window.addEventListener('scroll', this.onScroll, false);
      }
      this.setState({ listeningScroll: true });
    }
  }

  removeOnScrollListener = () => {
    if (this.state.listeningScroll) {
      if (window.detachEvent) {
        //Internet Explorer
        window.detachEvent('onscroll', this.onScroll);
      } else if(window.removeEventListener) {
        window.removeEventListener('scroll', this.onScroll, false);
      }
      this.setState({ listeningScroll: false });
    }
  }

  onScroll = () => {
    // tacit agreement buahaha! (evil laugh)
    if (window.pageYOffset > this.props.dismissOnScrollThreshold) {
      this.onAccept();
    }
  }

  getSecondsSinceExpiration = cookieExpiration => {
    if (t.Integer.is(cookieExpiration)) {
      return cookieExpiration;
    }

    const SECONDS_IN_YEAR = 31536000;
    const SECONDS_IN_DAY = 86400;
    const SECONDS_IN_HOUR = 3600;

    const _cookieExpiration = {
      years: 0, days: 0, hours: 0,
      ...cookieExpiration
    };

    const { years, days, hours } = _cookieExpiration;

    return (years * SECONDS_IN_YEAR) + (days * SECONDS_IN_DAY) + (hours * SECONDS_IN_HOUR);
  }

  onAccept = () => {
    const { cookie, cookieExpiration, onAccept } = this.props;

    cookieLite(cookie, true, this.getSecondsSinceExpiration(cookieExpiration));
    onAccept({ cookie });

    if (this.state.listeningScroll) {
      this.removeOnScrollListener();
    } else {
      this.forceUpdate();
    }
  }

  getStyle = (style) => {
    const { disableStyle, styles } = this.props;
    if (!disableStyle) {
      // apply custom styles if available
      return { ...styleUtils.getStyle(style), ...styles[style] };
    }
  }

  getCloseButton = () => {
    const { closeIcon, buttonMessage } = this.props;
    if (closeIcon) {
      return ;
    }
    return (

        {buttonMessage}

    );
  }

  getLink = () => {
    const { link } = this.props;
    if (link) {
      return (

            {link.msg || 'Learn more'}

      );
    }
  }

  getBanner = () => {
    const { children, className, message } = this.props;
    if (children) {
      return children;
    }

    const props = omit(this.props, Object.keys(Props));
    return (

          {message}
          {this.getLink()}

        {this.getCloseButton()}

    );
  }

  hasAcceptedCookies = () => {
    return (typeof window !== 'undefined') && cookieLite(this.props.cookie);
  }

  render() {
    return this.hasAcceptedCookies() ? null : this.getBanner();
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.dismissOnScroll) {
      this.addOnScrollListener(nextProps);
    } else {
      this.removeOnScrollListener();
    }
  }

  componentWillUnmount() {
    this.removeOnScrollListener();
  }

}
<|endoftext|>


<commit_before>/**
	Linkify basic global tests
*/
QUnit.assert.oneOf = function (value, possibleExpected, message) {
	message = message || 'Expected ' + value + ' to be contained in ' + possibleExpected + '.';
	this.push(possibleExpected.indexOf(value) >= 0, value, possibleExpected, message);
};

QUnit.module('linkify');

QUnit.test('exists in window', function (assert) {
	assert.ok('linkify' in w);
});

QUnit.test('contains find function', function (assert) {
	assert.ok('find' in w.linkify);
	assert.equal(typeof w.linkify.find, 'function');
});

QUnit.test('contains test function', function (assert) {
	assert.ok('test' in w.linkify);
	assert.equal(typeof w.linkify.test, 'function');
});

QUnit.test('contains tokenize function', function (assert) {
	assert.ok('tokenize' in w.linkify);
	assert.equal(typeof w.linkify.tokenize, 'function');
});

QUnit.test('contains an options object', function (assert) {
	assert.ok('options' in w.linkify);
	assert.equal(typeof w.linkify.options, 'object');
});

QUnit.test('contains a parser object', function (assert) {
	assert.ok('parser' in w.linkify);
	assert.equal(typeof w.linkify.parser, 'object');
});

QUnit.test('contains a scanner object', function (assert) {
	assert.ok('scanner' in w.linkify);
	assert.equal(typeof w.linkify.scanner, 'object');
});

QUnit.module('linkify.find');

QUnit.test('linkify.find correctly finds a URL', function (assert) {
	var result = w.linkify.find('The url is github.com');
	assert.equal(result.length, 1);
	assert.equal(result[0].type, 'url');
	assert.equal(result[0].value, 'github.com');
	assert.equal(result[0].href, 'http://github.com');
});

QUnit.test('linkify.find correctly finds an email address', function (assert) {
	var result = w.linkify.find('The url is github.com and the email is test@example.com', 'email');
	assert.equal(result.length, 1);
	assert.equal(result[0].type, 'email');
	assert.equal(result[0].value, 'test@example.com');
	assert.equal(result[0].href, 'mailto:test@example.com');
});

QUnit.module('linkify.test');

QUnit.test('correctly identifies a URL as a link', function (assert) {
	assert.ok(w.linkify.test('github.com'));
});

QUnit.test('correctly identifies a URL as NOT an email', function (assert) {
	assert.notOk(w.linkify.test('github.com', 'email'));
});

QUnit.test('correctly identifies text as not an email', function (assert) {
	assert.notOk(w.linkify.test('gobbledegook'));
});

QUnit.module('linkify.options');

QUnit.test('contains normalize function', function (assert) {
	assert.ok('normalize' in w.linkify.options);
	assert.equal(typeof w.linkify.options.normalize, 'function');
});

QUnit.test('contains resolve function', function (assert) {
	assert.ok('resolve' in w.linkify.options);
	assert.equal(typeof w.linkify.options.resolve, 'function');
});

QUnit.module('linkify.options.normalize');

QUnit.test('returns in the hash of default options when given an empty object', function (assert) {
	var result = w.linkify.options.normalize({});
	assert.propEqual(result, {
		attributes: null,
		defaultProtocol: 'http',
		events: null,
		format: function () {},
		validate: function () {},
		formatHref: function () {},
		newLine: false, // deprecated
		nl2br: false,
		tagName: 'a',
		target: function () {},
		linkClass: 'linkified'
	});
	assert.equal(typeof result.format, 'function');
	assert.equal(typeof result.validate, 'function');
	assert.equal(result.format('test'), 'test');
	assert.equal(typeof result.formatHref, 'function');
	assert.equal(result.formatHref('test'), 'test');
	assert.equal(typeof result.target, 'function');
	assert.equal(result.target('test', 'url'), '_blank');
	assert.equal(result.target('email'), null);
});

QUnit.module('linkify.options.resolve');

QUnit.test('results in the value given when called with a non-function', function (assert) {
	var result0 = 0;
	var result1 = 1;
	var result2 = 'test';
	var result3 = {test: 'test'};

	assert.equal(w.linkify.options.resolve(result0), result0);
	assert.equal(w.linkify.options.resolve(result1), result1);
	assert.equal(w.linkify.options.resolve(result2), result2);
	assert.equal(w.linkify.options.resolve(result3), result3);
});

QUnit.test('Results the results of the function when called with a function and arguments', function (assert) {
	function concat(str1, str2) {
		return str1 + str2;
	}

	assert.equal(
		w.linkify.options.resolve(concat, 'testone', 'testtwo'), 'testonetesttwo'
	);
});

QUnit.module('linkify-plugin-hashtag');

QUnit.test('finds valid hashtags', function (assert) {
	var result = w.linkify.find('#urls are #awesome2015');
	assert.deepEqual(result, [{
		type: 'hashtag',
		value: '#urls',
		href: '#urls',
	}, {
		type: 'hashtag',
		value: '#awesome2015',
		href: '#awesome2015'
	}]);
});

// HTML rendered in body
var originalHtml = 'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
';

// Possible results with regular settings (will vary by browser)
var linkifiedHtml = [
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
'
];

// Possible results with overriden settings
var linkifiedHtmlAlt = [
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
'
];

QUnit.module('linkify-jquery', {
	beforeEach: function () {
		var $elem = jQuery('
');
		$elem.html(originalHtml);
		jQuery('body').append($elem);
	},
	afterEach: function () {
		jQuery('#linkify-test-elem').remove();
	}
});

QUnit.test('jQuery plugin exists', function (assert) {
	assert.ok('linkify' in jQuery.fn);
	assert.equal(typeof jQuery.fn.linkify, 'function');
});

QUnit.test('works with default options', function (assert) {
	var $elem = jQuery('#linkify-test-elem').linkify();
	assert.oneOf($elem.html(), linkifiedHtml);
});

QUnit.test('works with overriden options', function (assert) {
	var $elem = jQuery('#linkify-test-elem').linkify({
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.oneOf($elem.html(), linkifiedHtmlAlt);
});

QUnit.module('linkify-element', {
	beforeEach: function () {
		var $elem = jQuery('
');
		$elem.html(originalHtml);
		jQuery('body').append($elem);
	},
	afterEach: function () {
		jQuery('#linkify-test-elem').remove();
	}
});

QUnit.test('linkifyElement exists', function (assert) {
	assert.ok('linkifyElement' in w);
	assert.equal(typeof w.linkifyElement, 'function');
});

QUnit.test('works with default options', function (assert) {
	var elem = document.getElementById('linkify-test-elem');
	w.linkifyElement(elem);
	assert.oneOf(jQuery(elem).html(), linkifiedHtml);
});

QUnit.test('works with overriden options', function (assert) {
	var elem = document.getElementById('linkify-test-elem');
	w.linkifyElement(elem, {
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.oneOf(jQuery(elem).html(), linkifiedHtmlAlt);
});

QUnit.module('linkify-html');

QUnit.test('linkifyHtml exists', function (assert) {
	assert.ok('linkifyHtml' in w);
	assert.equal(typeof w.linkifyHtml, 'function');
});

QUnit.test('works with default options', function (assert) {
	var result = w.linkifyHtml(originalHtml);
	assert.equal(result, linkifiedHtml[0]);
});

QUnit.test('works with overriden options', function (assert) {
	var result = w.linkifyHtml(originalHtml, {
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.equal(result, linkifiedHtmlAlt[0]);
});

QUnit.module('linkify-string');

QUnit.test('linkifyStr exists', function (assert) {
	assert.ok('linkifyStr' in w);
	assert.equal(typeof w.linkifyStr, 'function');
});

QUnit.test('works with default options', function (assert) {
	var result = w.linkifyStr('google.ca and me@gmail.com');
	assert.equal(result, 'google.ca and me@gmail.com');
});

QUnit.test('works with overriden options', function (assert) {
	var result = w.linkifyStr('google.ca and me@gmail.com', {
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.equal(result, 'google.ca and me@gmail.com');
});
<commit_msg>Fixing qunit tests for ignoreTags option<commit_after>/**
	Linkify basic global tests
*/
QUnit.assert.oneOf = function (value, possibleExpected, message) {
	message = message || 'Expected ' + value + ' to be contained in ' + possibleExpected + '.';
	this.push(possibleExpected.indexOf(value) >= 0, value, possibleExpected, message);
};

QUnit.module('linkify');

QUnit.test('exists in window', function (assert) {
	assert.ok('linkify' in w);
});

QUnit.test('contains find function', function (assert) {
	assert.ok('find' in w.linkify);
	assert.equal(typeof w.linkify.find, 'function');
});

QUnit.test('contains test function', function (assert) {
	assert.ok('test' in w.linkify);
	assert.equal(typeof w.linkify.test, 'function');
});

QUnit.test('contains tokenize function', function (assert) {
	assert.ok('tokenize' in w.linkify);
	assert.equal(typeof w.linkify.tokenize, 'function');
});

QUnit.test('contains an options object', function (assert) {
	assert.ok('options' in w.linkify);
	assert.equal(typeof w.linkify.options, 'object');
});

QUnit.test('contains a parser object', function (assert) {
	assert.ok('parser' in w.linkify);
	assert.equal(typeof w.linkify.parser, 'object');
});

QUnit.test('contains a scanner object', function (assert) {
	assert.ok('scanner' in w.linkify);
	assert.equal(typeof w.linkify.scanner, 'object');
});

QUnit.module('linkify.find');

QUnit.test('linkify.find correctly finds a URL', function (assert) {
	var result = w.linkify.find('The url is github.com');
	assert.equal(result.length, 1);
	assert.equal(result[0].type, 'url');
	assert.equal(result[0].value, 'github.com');
	assert.equal(result[0].href, 'http://github.com');
});

QUnit.test('linkify.find correctly finds an email address', function (assert) {
	var result = w.linkify.find('The url is github.com and the email is test@example.com', 'email');
	assert.equal(result.length, 1);
	assert.equal(result[0].type, 'email');
	assert.equal(result[0].value, 'test@example.com');
	assert.equal(result[0].href, 'mailto:test@example.com');
});

QUnit.module('linkify.test');

QUnit.test('correctly identifies a URL as a link', function (assert) {
	assert.ok(w.linkify.test('github.com'));
});

QUnit.test('correctly identifies a URL as NOT an email', function (assert) {
	assert.notOk(w.linkify.test('github.com', 'email'));
});

QUnit.test('correctly identifies text as not an email', function (assert) {
	assert.notOk(w.linkify.test('gobbledegook'));
});

QUnit.module('linkify.options');

QUnit.test('contains normalize function', function (assert) {
	assert.ok('normalize' in w.linkify.options);
	assert.equal(typeof w.linkify.options.normalize, 'function');
});

QUnit.test('contains resolve function', function (assert) {
	assert.ok('resolve' in w.linkify.options);
	assert.equal(typeof w.linkify.options.resolve, 'function');
});

QUnit.module('linkify.options.normalize');

QUnit.test('returns in the hash of default options when given an empty object', function (assert) {
	var result = w.linkify.options.normalize({});
	assert.propEqual(result, {
		attributes: null,
		defaultProtocol: 'http',
		events: null,
		format: function () {},
		validate: function () {},
		formatHref: function () {},
		newLine: false, // deprecated
		nl2br: false,
		tagName: 'a',
		target: function () {},
		linkClass: 'linkified',
		ignoreTags: []
	});
	assert.equal(typeof result.format, 'function');
	assert.equal(typeof result.validate, 'function');
	assert.equal(result.format('test'), 'test');
	assert.equal(typeof result.formatHref, 'function');
	assert.equal(result.formatHref('test'), 'test');
	assert.equal(typeof result.target, 'function');
	assert.equal(result.target('test', 'url'), '_blank');
	assert.equal(result.target('email'), null);
});

QUnit.module('linkify.options.resolve');

QUnit.test('results in the value given when called with a non-function', function (assert) {
	var result0 = 0;
	var result1 = 1;
	var result2 = 'test';
	var result3 = {test: 'test'};

	assert.equal(w.linkify.options.resolve(result0), result0);
	assert.equal(w.linkify.options.resolve(result1), result1);
	assert.equal(w.linkify.options.resolve(result2), result2);
	assert.equal(w.linkify.options.resolve(result3), result3);
});

QUnit.test('Results the results of the function when called with a function and arguments', function (assert) {
	function concat(str1, str2) {
		return str1 + str2;
	}

	assert.equal(
		w.linkify.options.resolve(concat, 'testone', 'testtwo'), 'testonetesttwo'
	);
});

QUnit.module('linkify-plugin-hashtag');

QUnit.test('finds valid hashtags', function (assert) {
	var result = w.linkify.find('#urls are #awesome2015');
	assert.deepEqual(result, [{
		type: 'hashtag',
		value: '#urls',
		href: '#urls',
	}, {
		type: 'hashtag',
		value: '#awesome2015',
		href: '#awesome2015'
	}]);
});

// HTML rendered in body
var originalHtml = 'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
';

// Possible results with regular settings (will vary by browser)
var linkifiedHtml = [
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
'
];

// Possible results with overriden settings
var linkifiedHtmlAlt = [
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
',
	'Hello here are some links to ftp://awesome.com/?where=this and localhost:8080, pretty neat right?
Here\'s a nested github.com/SoapBox/linkifyjs paragraph
'
];

QUnit.module('linkify-jquery', {
	beforeEach: function () {
		var $elem = jQuery('
');
		$elem.html(originalHtml);
		jQuery('body').append($elem);
	},
	afterEach: function () {
		jQuery('#linkify-test-elem').remove();
	}
});

QUnit.test('jQuery plugin exists', function (assert) {
	assert.ok('linkify' in jQuery.fn);
	assert.equal(typeof jQuery.fn.linkify, 'function');
});

QUnit.test('works with default options', function (assert) {
	var $elem = jQuery('#linkify-test-elem').linkify();
	assert.oneOf($elem.html(), linkifiedHtml);
});

QUnit.test('works with overriden options', function (assert) {
	var $elem = jQuery('#linkify-test-elem').linkify({
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.oneOf($elem.html(), linkifiedHtmlAlt);
});

QUnit.module('linkify-element', {
	beforeEach: function () {
		var $elem = jQuery('
');
		$elem.html(originalHtml);
		jQuery('body').append($elem);
	},
	afterEach: function () {
		jQuery('#linkify-test-elem').remove();
	}
});

QUnit.test('linkifyElement exists', function (assert) {
	assert.ok('linkifyElement' in w);
	assert.equal(typeof w.linkifyElement, 'function');
});

QUnit.test('works with default options', function (assert) {
	var elem = document.getElementById('linkify-test-elem');
	w.linkifyElement(elem);
	assert.oneOf(jQuery(elem).html(), linkifiedHtml);
});

QUnit.test('works with overriden options', function (assert) {
	var elem = document.getElementById('linkify-test-elem');
	w.linkifyElement(elem, {
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.oneOf(jQuery(elem).html(), linkifiedHtmlAlt);
});

QUnit.module('linkify-html');

QUnit.test('linkifyHtml exists', function (assert) {
	assert.ok('linkifyHtml' in w);
	assert.equal(typeof w.linkifyHtml, 'function');
});

QUnit.test('works with default options', function (assert) {
	var result = w.linkifyHtml(originalHtml);
	assert.equal(result, linkifiedHtml[0]);
});

QUnit.test('works with overriden options', function (assert) {
	var result = w.linkifyHtml(originalHtml, {
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.equal(result, linkifiedHtmlAlt[0]);
});

QUnit.module('linkify-string');

QUnit.test('linkifyStr exists', function (assert) {
	assert.ok('linkifyStr' in w);
	assert.equal(typeof w.linkifyStr, 'function');
});

QUnit.test('works with default options', function (assert) {
	var result = w.linkifyStr('google.ca and me@gmail.com');
	assert.equal(result, 'google.ca and me@gmail.com');
});

QUnit.test('works with overriden options', function (assert) {
	var result = w.linkifyStr('google.ca and me@gmail.com', {
		linkAttributes: {
			rel: 'nofollow'
		}
	});
	assert.equal(result, 'google.ca and me@gmail.com');
});
<|endoftext|>