<commit_before>module.exports = function(grunt) {
    'use strict';

    var jsdom = require('jsdom');
    var path = require('path');
    var fs = require('fs');
    var request = require('request');
    var async = require('async');

    var scripts = [
        '//ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js',
        '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.1/underscore-min.js'
    ];

    var documentToSource = function(document) {
        return document.doctype.toString() + document.innerHTML;
    };

    grunt.registerMultiTask('renderReferencePage', function() {
        var done = this.async();

        var filePath = '/mnt/Windows/nbsoftsolutions/_site/blog/reference-track-sheet.html';
        jsdom.env(filePath, scripts, function(errors, window) {

            var $ = window.$;
            var _ = window._;

            var contents = fs.readFileSync(path.resolve('./__citeBuffer.js'));
            contents = JSON.parse(contents);

            contents = _.chain(contents)
            .pluck('data')
            .flatten()
            .filter(function(val) { return !val.periodical && !val.website; })
            .groupBy(function(val) { return val.requestResult.id; })
            .map(function(val) {
                return {
                    count: val.length,
                    title: val[0].requestResult.volumeInfo.title,
                    authors: val[0].requestResult.volumeInfo.authors,
                    description: val[0].requestResult.volumeInfo.description,
                    publishedDate: val[0].requestResult.volumeInfo.publishedDate,
                    publisher: val[0].requestResult.volumeInfo.publisher,
                    image: val[0].requestResult.volumeInfo.imageLinks.thumbnail
                };
            })
            .sortBy(function(val) { return val.count; })
            .value()
            .reverse();

            var templ = _.template($('#referencePageTmpl').html());

            $('div.Product').append($('<div>').html(templ({ references: contents })));
            $('script.jsdom').remove();

            fs.writeFileSync(filePath, documentToSource(window.document));
            done();
        });
    });

    grunt.registerMultiTask('reference', function() {
        var task = this;
        var done = this.async();

        var files = this.filesSrc;

        var processDOM = function(window, options, callback) {
            var filePath = window.location.pathname;
            var $ = window.$;
            var _ = window._;

            var referenceElements = $('[cite], cite');

            var citationsCompleted = 0;
            var requests = _.map(referenceElements, function(val, ind, arr) {
                var citation = $.trim(val.getAttribute('cite') || $(val).text());

                var split = citation.split(' ');
                var lookup = split[0];
                var pageReference = split[1];

                return {
                    element: val,
                    elementIndex: ind,
                    page: parseInt(pageReference, 10) || 0,
                    periodical: lookup.indexOf('/') !== -1 && lookup.indexOf('http') === -1,
                    website: lookup.indexOf('http') !== -1,
                    lookup: lookup
                };
            });

            async.each(requests, function(newCitation, lookupComplete) {
                var lookup = newCitation.lookup;
                if (newCitation.website) {
                    newCitation.requestResult = { id: lookup };
                    lookupComplete();
                }
                else if (newCitation.periodical) {
                    var urlP = 'http://api.altmetric.com/v1/doi/' + lookup;
                    request.get(urlP, function(error, response, body) {
                        body = JSON.parse(body);
                        newCitation.requestResult = body;
                        newCitation.requestResult.publishedDate = new Date(body.published_on * 1000);
                        newCitation.requestResult.id = newCitation.requestResult.doi;
                        newCitation.requestResult.authors = [];
                        lookupComplete();
                    });
                }
                else {
                    var urlG = 'https://www.googleapis.com/books/v1/volumes?q=isbn:' + lookup;
                    request.get(urlG, function(error, response, body) {
                        body = JSON.parse(body);
                        newCitation.requestResult = body.items[0];
                        newCitation.requestResult.volumeInfo.publishedDate = new Date(Date.parse(newCitation.requestResult.volumeInfo.publishedDate));
                        lookupComplete();
                    });
                }
            }, function(err) {
                callback(window, requests, options);
            });

            if (referenceElements.length === 0) {
                callback(window, undefined);
            }
        };

        var mapIbids = function(arr) {
            var mapOnId = function(element) {
                return element.requestResult.id;
            };

            for (var i = arr.length - 1; i >= 0; i--) {
                var next = arr.map(mapOnId)
                    .lastIndexOf(arr[i].requestResult.id, i - 1);

                if (next <= 0 && arr[0].requestResult.id !== arr[i].requestResult.id) {
                    arr[i].ibidDifference = -1;
                }
                else {
                    arr[i].ibidDifference = i - next;
                }
            }
        };

        var domRequestsCompleted = function(window, data, options) {
            var $ = window.$;
            var _ = window._;

            mapIbids(data);

            var container = $('#' + options.referenceContainer);
            var elementTemplate = _.template($('#' + options.elementTemplateId).html());
            var containerTemplate = _.template($('#' + options.referenceTemplateId).html());

            data.forEach(function(val, ind) {
                $(val.element).after(elementTemplate({ i: ind }));
            });

            container.html(containerTemplate({ references: data }));

            $('script.jsdom').remove();

            fs.writeFileSync(window.location.pathname, documentToSource(window.document));
        };

        var fileJSON = [];
        async.each(files, function(f, callback) {
            jsdom.env(path.resolve(f), scripts, function(errors, window) {
                if (!errors){
                    processDOM(window, task.options(), function(window, data, options) {
                        if (data !== undefined) {
                            domRequestsCompleted(window, data, options);

                            data.forEach(function(val, ind) {
                                delete val.element;
                                delete val.elementIndex;
                            });

                            var newFile = {
                                title: window.document.title,
                                path: window.location.pathname,
                                data: data
                            };

                            fileJSON.push(newFile);
                        }
                        callback();
                    });
                }
                else {
                    grunt.log.writeln('error');
                    callback();
                }
            });
        }, function(error) {
            fs.writeFileSync('./__citeBuffer.js', JSON.stringify(fileJSON, null, '\t'));
            done();
        });
    });
};
<commit_msg>Fix async bug<commit_after>module.exports = function(grunt) {
    'use strict';

    var jsdom = require('jsdom');
    var path = require('path');
    var fs = require('fs');
    var request = require('request');
    var async = require('async');

    var scripts = [
        '//ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js',
        '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.1/underscore-min.js'
    ];

    var documentToSource = function(document) {
        return document.doctype.toString() + document.innerHTML;
    };

    grunt.registerMultiTask('renderReferencePage', function() {
        var done = this.async();

        var filePath = '/mnt/Windows/nbsoftsolutions/_site/blog/reference-track-sheet.html';
        jsdom.env(filePath, scripts, function(errors, window) {

            var $ = window.$;
            var _ = window._;

            var contents = fs.readFileSync(path.resolve('./__citeBuffer.js'));
            contents = JSON.parse(contents);

            contents = _.chain(contents)
            .pluck('data')
            .flatten()
            .filter(function(val) { return !val.periodical && !val.website; })
            .groupBy(function(val) { return val.requestResult.id; })
            .map(function(val) {
                return {
                    count: val.length,
                    title: val[0].requestResult.volumeInfo.title,
                    authors: val[0].requestResult.volumeInfo.authors,
                    description: val[0].requestResult.volumeInfo.description,
                    publishedDate: val[0].requestResult.volumeInfo.publishedDate,
                    publisher: val[0].requestResult.volumeInfo.publisher,
                    image: val[0].requestResult.volumeInfo.imageLinks.thumbnail
                };
            })
            .sortBy(function(val) { return val.count; })
            .value()
            .reverse();

            var templ = _.template($('#referencePageTmpl').html());

            $('div.Product').append($('<div>').html(templ({ references: contents })));
            $('script.jsdom').remove();

            fs.writeFileSync(filePath, documentToSource(window.document));
            done();
        });
    });

    grunt.registerMultiTask('reference', function() {
        var task = this;
        var done = this.async();

        var files = this.filesSrc;

        var processDOM = function(window, options, callback) {
            var filePath = window.location.pathname;
            var $ = window.$;
            var _ = window._;

            var referenceElements = $('[cite], cite');

            var requests = _.map(referenceElements, function(val, ind, arr) {
                var citation = $.trim(val.getAttribute('cite') || $(val).text());

                var split = citation.split(' ');
                var lookup = split[0];
                var pageReference = split[1];

                return {
                    element: val,
                    elementIndex: ind,
                    page: parseInt(pageReference, 10) || 0,
                    periodical: lookup.indexOf('/') !== -1 && lookup.indexOf('http') === -1,
                    website: lookup.indexOf('http') !== -1,
                    lookup: lookup
                };
            });

            async.each(requests, function(newCitation, lookupComplete) {
                var lookup = newCitation.lookup;
                if (newCitation.website) {
                    newCitation.requestResult = { id: lookup, authors: [] };
                    lookupComplete();
                }
                else if (newCitation.periodical) {
                    var urlP = 'http://api.altmetric.com/v1/doi/' + lookup;
                    request.get(urlP, function(error, response, body) {
                        body = JSON.parse(body);
                        newCitation.requestResult = body;
                        newCitation.requestResult.publishedDate = new Date(body.published_on * 1000);
                        newCitation.requestResult.id = newCitation.requestResult.doi;
                        newCitation.requestResult.authors = [];
                        lookupComplete();
                    });
                }
                else {
                    var urlG = 'https://www.googleapis.com/books/v1/volumes?q=isbn:' + lookup;
                    request.get(urlG, function(error, response, body) {
                        body = JSON.parse(body);
                        newCitation.requestResult = body.items[0];
                        newCitation.requestResult.volumeInfo.publishedDate = new Date(Date.parse(newCitation.requestResult.volumeInfo.publishedDate));
                        lookupComplete();
                    });
                }
            }, function(err) {
                callback(window, requests, options);
            });
        };

        var mapIbids = function(arr) {
            var mapOnId = function(element) {
                return element.requestResult.id;
            };

            for (var i = arr.length - 1; i >= 0; i--) {
                var next = arr.map(mapOnId)
                    .lastIndexOf(arr[i].requestResult.id, i - 1);

                if (next <= 0 && arr[0].requestResult.id !== arr[i].requestResult.id) {
                    arr[i].ibidDifference = -1;
                }
                else {
                    arr[i].ibidDifference = i - next;
                }
            }
        };

        var domRequestsCompleted = function(window, data, options) {
            var $ = window.$;
            var _ = window._;

            mapIbids(data);

            var container = $('#' + options.referenceContainer);
            var elementTemplate = _.template($('#' + options.elementTemplateId).html());
            var containerTemplate = _.template($('#' + options.referenceTemplateId).html());

            data.forEach(function(val, ind) {
                $(val.element).after(elementTemplate({ i: ind }));
            });

            container.html(containerTemplate({ references: data }));

            $('script.jsdom').remove();

            fs.writeFileSync(window.location.pathname, documentToSource(window.document));
        };

        var fileJSON = [];
        async.each(files, function(f, callback) {
            jsdom.env(path.resolve(f), scripts, function(errors, window) {
                if (!errors){
                    processDOM(window, task.options(), function(window, data, options) {
                        if (data.length !== 0) {
                            domRequestsCompleted(window, data, options);

                            data.forEach(function(val, ind) {
                                delete val.element;
                                delete val.elementIndex;
                            });

                            var newFile = {
                                title: window.document.title,
                                path: window.location.pathname,
                                data: data
                            };

                            fileJSON.push(newFile);
                        }
                        callback();
                    });
                }
                else {
                    grunt.log.writeln('error');
                    callback();
                }
            });
        }, function(error) {
            fs.writeFileSync('./__citeBuffer.js', JSON.stringify(fileJSON, null, '\t'));
            done();
        });
    });
};
<|endoftext|>


<commit_before>// These are tests to ensure we don't break 0.4 functionality
var grunt = require('grunt');

/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.deepEqual(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/

var outline = {
  'A grunt@0.4 plugin': {
    'using grunt-retro': {
      'can have templating on src': true,
      'can have templating on dest': true,
      'can register task without a description': true
    }
  }
};

// ANTI-PATTERN: Helper function for comparing tests
function compareFiles(filename) {
  return function fileComparison (test) {
    test.expect(1);

    // Load in the expected and actual content
    var expectedContent = grunt.file.read('expected/' + filename),
        actualContent = grunt.file.read('actual/' + filename);

    // Assert they are the same and return
    test.equal(actualContent, expectedContent, 'should return the correct value.');
    test.done();
  };
}

exports['0.4'] = {
  'src-template': compareFiles('src_template.txt'),
  'dest-template': compareFiles('dest_template.txt'),
  'register-description-less-task': function (test) {
    // Set up
    test.expect(1);

    // Assert we can register tasks sans description
    test.doesNotThrow(function () {
      grunt.registerTask('my-task', function () {
        return 'Stub content';
      });
    }, 'Grunt cannot register tasks without a description');

    // Callback
    test.done();
  }
};
<commit_msg>Adding regression test for description-less multitask in 0.4<commit_after>// These are tests to ensure we don't break 0.4 functionality
var grunt = require('grunt');

/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.deepEqual(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/

var outline = {
  'A grunt@0.4 plugin': {
    'using grunt-retro': {
      'can have templating on src': true,
      'can have templating on dest': true,
      'can register task without a description': true,
      'can run a multi task without a description': true
    }
  }
};

// ANTI-PATTERN: Helper function for comparing tests
function compareFiles(filename) {
  return function fileComparison (test) {
    test.expect(1);

    // Load in the expected and actual content
    var expectedContent = grunt.file.read('expected/' + filename),
        actualContent = grunt.file.read('actual/' + filename);

    // Assert they are the same and return
    test.equal(actualContent, expectedContent, 'should return the correct value.');
    test.done();
  };
}

exports['0.4'] = {
  'src-template': compareFiles('src_template.txt'),
  'dest-template': compareFiles('dest_template.txt'),
  'register-description-less-task': function (test) {
    // Set up
    test.expect(1);

    // Assert we can register tasks sans description
    test.doesNotThrow(function () {
      grunt.registerTask('my-task', function () {
        return 'Stub content';
      });
    }, 'Grunt cannot register tasks without a description');

    // Callback
    test.done();
  },
  'run-description-less-multitask': function (test) {
    // Set up
    test.expect(1);

    // Assert we can register tasks sans description
    test.doesNotThrow(function () {
      grunt.registerMultiTask('my-task', function () {
        return 'Stub content';
      });
    }, 'Grunt cannot register tasks without a description');

    // Callback
    test.done();
  }
};
<|endoftext|>


<commit_before>app.directive();
<commit_msg>Update appInfo.js<commit_after>app.directive('appInfo', function(){
  return {
    restrict: 'E',
    scope: {
      info: '='
    },
    templateUrl: 'js/directive/appInfo.html'
  };
});
<|endoftext|>


<commit_before>/*jslint esversion: 6, node: true, nomen: true, unparam: true */
'use strict';

var debug = require('debug')('myBus:rv2');
var express = require('express');
var router = express.Router();
var util = require('../module/util.js');

// initial DB object
var mysql = require('promise-mysql');
var sql_config = require('../sql_config');
var db = mysql.createPool(sql_config.db);

router.get('/route', function (req, res) {
    debug(JSON.stringify(req.query));
    if (req.query.route) {
        var query = `SELECT * FROM \`Bus_stop\` WHERE \`route\`=${Number(req.query.route)}`;
        db.query(query).then((rows, field)=>{
            res.send(JSON.stringify(rows));
        }, (err)=>{
            throw err;
        });
    } else {
        var err = new Error('Too few arguments');
        err.status = 400;
        throw err;
    }
});

router.get('/bus', function(req, res) {
    res.set("Connection", "close");
    res.send('this is bus');
});

router.post('/register', (req, res) => {
    res.set("Connection", "close");
    res.send('');
});

router.get('/lineStatus', (req, res) => {
    var query = '';

    if (req.query.verbose === undefined || util.escapeBoolean(req.query.verbose) === true) {
        query += 'SELECT * ';
    } else {
        query += 'SELECT `closestStop` ';
    }

    query += 'FROM `Bus_status` ';

    if (req.query.route && req.query.is_reverse) {
        query += `WHERE \`route\` = ${db.escape(req.query.route)} AND \`is_reverse\` = ${util.escapeBoolean(req.query.is_reverse)} `;
    } else {
        res.status(400);
        res.render('error', {
            message: 'Too few arguments',
            error: {}
        });
    }

    if (req.query.sn) {
        query += `ORDER BY ABS(closestStop-${req.query.sn})`;
    }

    debug(query);
    res.set("Connection", "close");
    db.query(query).then((rows) => {
        if (req.query.sn === undefined) {
            res.send(JSON.stringify(rows));
        } else {
            res.send(JSON.stringify(rows[0]));
        }
    });
});

router.post('/reservation', (req, res) => {
    // INSERT INTO `Reservation_List`(`UUID`, `route`, `is_reverse`, `from_sn`, `to_sn`) VALUES ('B397A7F7',160,false,1,3)
    var query = "INSERT INTO `Reservation_List`(`UID`, `route`, `is_reverse`, `from_sn`, `to_sn`) ";

    if (req.body.UID && req.body.route && req.body.from_sn && req.body.to_sn && !isNaN(req.body.from_sn) && !isNaN(req.body.to_sn)) {
        ['UID', 'route', 'from_sn', 'to_sn'].forEach((item, index) => {
            req.body[item] = mysql.escape(req.body[item]);
        });

        query += `VALUES (${req.body.UID},${req.body.route},${(req.body.from_sn<req.body.to_sn)},${req.body.from_sn},${req.body.to_sn})`;
        debug(query);
        db.query(query).then( (raws, field) => {
            res.send("Register OK");
        }, (err) => {
            if (err.code.includes('ER_DUP_ENTRY')) {
                //UPDATE `Reservation_List` SET `route`=160,`is_reverse`=true,`from_sn`=5,`to_sn`=3 WHERE `UID`='b397a7f7'
                debug(err.code);
                query = `UPDATE \`Reservation_List\` SET \`route\`=${req.body.route},\`is_reverse\`=${(req.body.from_sn<req.body.to_sn)},\`from_sn\`=${req.body.from_sn},\`to_sn\`=${req.body.to_sn} WHERE \`UID\`=${req.body.UID}`;
                debug(query);
                db.query(query).then(() => {
                    res.send("Register Update OK");
                });
            } else {
                throw err;
            }
        }).error((err) => {
            debug(err.code);
            if (err.code.includes('ER_NO_REFERENCED_ROW')) {
                res.status(400);
                res.render('error', {
                    message: 'Error you are not registered yet',
                    error: {}
                });
            } else {
                res.status(500);
                res.render('error', {
                    message: 'Unknown Error',
                    error: {}
                });
            }
        });
    } else {
        var err = new Error('Too few arguments');
        err.status = 400;
        throw err;
    }
});

module.exports = router;
<commit_msg>reply null when no bus<commit_after>/*jslint esversion: 6, node: true, nomen: true, unparam: true */
'use strict';

var debug = require('debug')('myBus:rv2');
var express = require('express');
var router = express.Router();
var util = require('../module/util.js');

// initial DB object
var mysql = require('promise-mysql');
var sql_config = require('../sql_config');
var db = mysql.createPool(sql_config.db);

router.get('/route', function (req, res) {
    debug(JSON.stringify(req.query));
    if (req.query.route) {
        var query = `SELECT * FROM \`Bus_stop\` WHERE \`route\`=${Number(req.query.route)}`;
        db.query(query).then((rows, field)=>{
            res.send(JSON.stringify(rows));
        }, (err)=>{
            throw err;
        });
    } else {
        var err = new Error('Too few arguments');
        err.status = 400;
        throw err;
    }
});

router.get('/bus', function(req, res) {
    res.set("Connection", "close");
    res.send('this is bus');
});

router.post('/register', (req, res) => {
    res.set("Connection", "close");
    res.send('');
});

router.get('/lineStatus', (req, res) => {
    var query = '';

    if (req.query.verbose === undefined || util.escapeBoolean(req.query.verbose) === true) {
        query += 'SELECT * ';
    } else {
        query += 'SELECT `closestStop` ';
    }

    query += 'FROM `Bus_status` ';

    if (req.query.route && req.query.is_reverse) {
        query += `WHERE \`route\` = ${db.escape(req.query.route)} AND \`is_reverse\` = ${util.escapeBoolean(req.query.is_reverse)} `;
    } else {
        res.status(400);
        res.render('error', {
            message: 'Too few arguments',
            error: {}
        });
    }

    if (req.query.sn) {
        query += `ORDER BY ABS(closestStop-${req.query.sn})`;
    }

    debug(query);
    res.set("Connection", "close");
    db.query(query).then((rows) => {
        if (rows.length === 0) {
            res.send(JSON.stringify(null));
        } else if (req.query.sn === undefined) {
            res.send(JSON.stringify(rows));
        } else {
            res.send(JSON.stringify(rows[0].closestStop));
        }
    });
});

router.post('/reservation', (req, res) => {
    // INSERT INTO `Reservation_List`(`UUID`, `route`, `is_reverse`, `from_sn`, `to_sn`) VALUES ('B397A7F7',160,false,1,3)
    var query = "INSERT INTO `Reservation_List`(`UID`, `route`, `is_reverse`, `from_sn`, `to_sn`) ";

    if (req.body.UID && req.body.route && req.body.from_sn && req.body.to_sn && !isNaN(req.body.from_sn) && !isNaN(req.body.to_sn)) {
        ['UID', 'route', 'from_sn', 'to_sn'].forEach((item, index) => {
            req.body[item] = mysql.escape(req.body[item]);
        });

        query += `VALUES (${req.body.UID},${req.body.route},${(req.body.from_sn<req.body.to_sn)},${req.body.from_sn},${req.body.to_sn})`;
        debug(query);
        db.query(query).then( (raws, field) => {
            res.send("Register OK");
        }, (err) => {
            if (err.code.includes('ER_DUP_ENTRY')) {
                //UPDATE `Reservation_List` SET `route`=160,`is_reverse`=true,`from_sn`=5,`to_sn`=3 WHERE `UID`='b397a7f7'
                debug(err.code);
                query = `UPDATE \`Reservation_List\` SET \`route\`=${req.body.route},\`is_reverse\`=${(req.body.from_sn<req.body.to_sn)},\`from_sn\`=${req.body.from_sn},\`to_sn\`=${req.body.to_sn} WHERE \`UID\`=${req.body.UID}`;
                debug(query);
                db.query(query).then(() => {
                    res.send("Register Update OK");
                });
            } else {
                throw err;
            }
        }).error((err) => {
            debug(err.code);
            if (err.code.includes('ER_NO_REFERENCED_ROW')) {
                res.status(400);
                res.render('error', {
                    message: 'Error you are not registered yet',
                    error: {}
                });
            } else {
                res.status(500);
                res.render('error', {
                    message: 'Unknown Error',
                    error: {}
                });
            }
        });
    } else {
        var err = new Error('Too few arguments');
        err.status = 400;
        throw err;
    }
});

module.exports = router;
<|endoftext|>


<commit_before>import "./passwordstrength";
import $ from "jquery";
import registry from "@patternslib/patternslib/src/core/registry";

/* ==========================
TEST: Password strength
========================== */

describe("Password strength", function () {

function fakeZxcvbn(input, strings) {
    window.providedStrings = strings;
    return {
	score: Math.min(input.length, 4),
    };
}

function getScripts() {
    return [].map
	.call(document.getElementsByTagName("script"), function (s) {
	    return s.src;
	})
	.filter(function (src) {
	    return src.indexOf("zxcvbn") !== -1;
	});
}

it("adds markup below input element", function () {
    var $el = $(
	'
<input type="password" class="pat-passwordstrength" />
'
    );
    window.zxcvbn = fakeZxcvbn;
    registry.scan($el);

    expect($el.find(".progress").length).toEqual(1);
    expect($el.find(".progress-bar").length).toEqual(1);
});

it("tries to load zxcvbn once if not available", function () {
    var $el2,
	$el = $(
	    '
<input type="password" class="pat-passwordstrength" data-pat-passwordstrength="zxcvbn: http://example.com/zxcvbn.js" />
'
	);
    window.zxcvbn = undefined;
    expect(getScripts().length).toEqual(0);
    registry.scan($el);
    expect(getScripts().length).toEqual(1);
    expect(getScripts()).toContain("http://example.com/zxcvbn.js");

    $el2 = $(
	'
<input type="password" class="pat-passwordstrength" data-pat-passwordstrength="zxcvbn: http://example.com/zxcvbn.js" />
'
    );
    registry.scan($el2);
    expect(getScripts().length).toEqual(1);
    expect(getScripts()).toContain("http://example.com/zxcvbn.js");
});

it("sets level based on the entered password", function () {
    var $el = $(
	'
<input type="password" class="pat-passwordstrength" />
'
    );
    window.zxcvbn = fakeZxcvbn;
    registry.scan($el);

    $el.find("input[type=password]").attr("value", "a").trigger("keyup");
    expect($el.find(".progress-bar").attr("class")).toEqual(
	"progress-bar w-25 bg-danger"
    );
    expect(window.providedStrings.length).toEqual(0);

    $el.find("input[type=password]").attr("value", "aa").trigger("keyup");
    expect($el.find(".progress-bar").attr("class")).toEqual(
	"progress-bar w-50 bg-warning"
    );
    expect(window.providedStrings.length).toEqual(0);

    $el.find("input[type=password]").attr("value", "aaa").trigger("keyup");
    expect($el.find(".progress-bar").attr("class")).toEqual(
	"progress-bar w-75 bg-warning"
    );
    expect(window.providedStrings.length).toEqual(0);

    $el.find("input[type=password]").attr("value", "aaaa").trigger("keyup");
    expect($el.find(".progress-bar").attr("class")).toEqual(
	"progress-bar w-100 bg-success"
    );
    expect(window.providedStrings.length).toEqual(0);
});

it("provides zxcvbn with other form field values", function () {
    var $el = $(
	"<form>" +
	    '<input type="input" name="username" value="bob_geldof" />' +
	    '<input type="password" class="pat-passwordstrength" />' +
	    '<input type="checkbox" name="spam_me" checked="yes">' +
	    "</form>"
    );
    window.zxcvbn = fakeZxcvbn;
    registry.scan($el);

    $el.find("input[type=password]").attr("value", "a").trigger("keyup");
    expect($el.find(".progress-bar").attr("class")).toEqual(
	"progress-bar w-25 bg-danger"
    );
    expect(window.providedStrings.length).toEqual(2);
    expect(window.providedStrings).toContain("bob_geldof");
    expect(window.providedStrings).toContain("on");
});
});
<commit_msg>Remove jquery dependency from tests, use es6 javascript<commit_after>import "./passwordstrength";
import registry from "@patternslib/patternslib/src/core/registry";

/* ==========================
TEST: Password strength
========================== */

describe("Password strength", function () {

function fakeZxcvbn(input, strings) {
    window.providedStrings = strings;
    return {
	score: Math.min(input.length, 4),
    };
}

function getScripts() {
    return [].map
	.call(document.getElementsByTagName("script"), function (s) {
	    return s.src;
	})
	.filter(function (src) {
	    return src.indexOf("zxcvbn") !== -1;
	});
}

it("adds markup below input element", function () {
    var $el = document.createElement('div');
    $el.innerHTML = '
<input type="password" class="pat-passwordstrength" />
';
    window.zxcvbn = fakeZxcvbn;
    registry.scan($el);
    expect($el.querySelectorAll(".progress").length).toEqual(1);
    expect($el.querySelectorAll(".progress-bar").length).toEqual(1);
});

it("tries to load zxcvbn once if not available", function () {
    var $el2 = document.createElement('div');
    var $el = document.createElement('div');
    $el.innerHTML = '
<input type="password" class="pat-passwordstrength" data-pat-passwordstrength="zxcvbn: http://example.com/zxcvbn.js" />
';

    window.zxcvbn = undefined;
    expect(getScripts().length).toEqual(0);
    registry.scan($el);
    expect(getScripts().length).toEqual(1);
    expect(getScripts()).toContain("http://example.com/zxcvbn.js");

    $el2.innerHTML = '
<input type="password" class="pat-passwordstrength" data-pat-passwordstrength="zxcvbn: http://example.com/zxcvbn.js" />
';
    registry.scan($el2);
    expect(getScripts().length).toEqual(1);
    expect(getScripts()).toContain("http://example.com/zxcvbn.js");
});

it("sets level based on the entered password", function () {
    var $el = document.createElement('div');
    $el.innerHTML = '
<input type="password" class="pat-passwordstrength" />
';
    window.zxcvbn = fakeZxcvbn;
    registry.scan($el);

    function returnKeyUp () {
    const event = new KeyboardEvent("keyup", {});
    return event;
    }

    $el.querySelectorAll("input[type=password]")[0].setAttribute("value", "a");
    $el.querySelectorAll("input[type=password]")[0].dispatchEvent(returnKeyUp());

    expect($el.querySelectorAll(".progress-bar")[0].getAttribute("class")).toEqual(
	"progress-bar w-25 bg-danger"
    );
    expect(window.providedStrings.length).toEqual(0);

    $el.querySelectorAll("input[type=password]")[0].setAttribute("value", "aa");
    $el.querySelectorAll("input[type=password]")[0].dispatchEvent(returnKeyUp());
    expect($el.querySelectorAll(".progress-bar")[0].getAttribute("class")).toEqual(
	"progress-bar w-50 bg-warning"
    );
    expect(window.providedStrings.length).toEqual(0);

    $el.querySelectorAll("input[type=password]")[0].setAttribute("value", "aaa");
    $el.querySelectorAll("input[type=password]")[0].dispatchEvent(returnKeyUp());
    expect($el.querySelectorAll(".progress-bar")[0].getAttribute("class")).toEqual(
	"progress-bar w-75 bg-warning"
    );
    expect(window.providedStrings.length).toEqual(0);

    $el.querySelectorAll("input[type=password]")[0].setAttribute("value", "aaaa");
    $el.querySelectorAll("input[type=password]")[0].dispatchEvent(returnKeyUp());

    expect($el.querySelectorAll(".progress-bar")[0].getAttribute("class")).toEqual(
	"progress-bar w-100 bg-success"
    );
    expect(window.providedStrings.length).toEqual(0);
});

it("provides zxcvbn with other form field values", function () {
    var $el = $(
	"<form>" +
	    '<input type="input" name="username" value="bob_geldof" />' +
	    '<input type="password" class="pat-passwordstrength" />' +
	    '<input type="checkbox" name="spam_me" checked="yes">' +
	    "</form>"
    );
    window.zxcvbn = fakeZxcvbn;
    registry.scan($el);

    $el.find("input[type=password]").attr("value", "a").trigger("keyup");
    expect($el.find(".progress-bar").attr("class")).toEqual(
	"progress-bar w-25 bg-danger"
    );
    expect(window.providedStrings.length).toEqual(2);
    expect(window.providedStrings).toContain("bob_geldof");
    expect(window.providedStrings).toContain("on");
});
});
<|endoftext|>


<commit_before>module.exports = {
  compile: {
    options: {
      baseUrl: "dist/",
      name: "../bower_components/almond/almond",
      paths: {
        "neue": "../js"
      },
      include: "neue/main",
      insertRequire: ["neue/main"],
      out: "dist/neue.js",
      wrap: true,
      preserveLicenseComments: false,
      generateSourceMaps: true,
      optimize: "uglify2",
      uglify2: {
        compress: {
          dead_code: true,
          drop_debugger: true,
          drop_console: true,
          global_defs: {
            DEBUG: false
          }
        }
      }
    }
  }
}
<commit_msg>Remove code optimization step.<commit_after>module.exports = {
  compile: {
    options: {
      baseUrl: "dist/",
      name: "../bower_components/almond/almond",
      paths: {
        "neue": "../js"
      },
      include: "neue/main",
      insertRequire: ["neue/main"],
      out: "dist/neue.js",
      wrap: true,
      preserveLicenseComments: false,
      generateSourceMaps: true,
      optimize: "uglify2"
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * This (asynchronous) grunt task builds and minifies an individual wrapper.
 * Note this file was created to support building the phet-io-wrapper-sonification repo, and should be worked on before
 * using on other wrappers.
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

// modules
var ChipperConstants = require( '../../../chipper/js/common/ChipperConstants' );
var copyDirectory = require( '../../../chipper/js/grunt/phet-io/copyDirectory' );
var createDependenciesJSON = require( '../../../chipper/js/grunt/createDependenciesJSON' );

// build in node apis
var fs = require( 'fs' );
var assert = require( 'assert' );

// Don't copy these files/folders into the built wrapper
var WRAPPER_BLACKLIST = [ '.git', 'README.md', '.gitignore', 'node_modules', 'build' ];

/**
 * @param grunt - the grunt instance
 * @param {Object} buildConfig - see getBuildConfig.js
 */
module.exports = function( grunt, buildConfig ) {
  'use strict';

  // Tell grunt to wait because this task is asynchronous.
  // Returns a handle to a function that must be called when the task has completed.
  var done = grunt.task.current.async();

  buildConfig.phetLibs.forEach( function( repo ) {

    //  We only need the common folder from this repo
    if ( repo === 'phet-io-wrappers' ) {
      repo = 'phet-io-wrappers/common';
    }

    // Special case for the sherpa repo. Look for packageJSON.wrapper.sherpaDependencies for individual files to copy on build.
    if ( repo === 'sherpa' ) {

      var pathToLib = '/sherpa/lib/';
      fs.mkdirSync( ChipperConstants.BUILD_DIR + '/' + repo );
      fs.mkdirSync( ChipperConstants.BUILD_DIR + pathToLib );
      grunt.log.debug( 'created sherpa lib file: ' + ChipperConstants.BUILD_DIR + pathToLib );

      assert( buildConfig.wrapperSherpaDependencies,
        'Must declare individual files of sherpaDependencies in wrapper\'s package.json to have "sherpa" repo as a dependency' );
      buildConfig.wrapperSherpaDependencies.forEach( function( file ) {
        grunt.file.copy( '..' + pathToLib + file, ChipperConstants.BUILD_DIR + pathToLib + file );
      } );
    }

    // otherwise copy the whole directory over, except the black list from above
    else {
      copyDirectory( grunt, '../' + repo, ChipperConstants.BUILD_DIR + '/' + repo + '/', null, {
        blacklist: WRAPPER_BLACKLIST, // List of files to not copy

        // TODO: We want to minify the built wrapper, but currently it is causing an error,
        // see https://github.com/phetsims/phet-io-wrapper-sonification/issues/19#event-1153696188
        minifyJS: true,
        licenseToPrepend: '// Copyright 2002-2017, University of Colorado Boulder\n' +
                          '// This PhET-iO file requires a license\n' +
                          '// USE WITHOUT A LICENSE AGREEMENT IS STRICTLY PROHIBITED.\n' +
                          '// For licensing, please contact phethelp@colorado.edu\n\n'
      } );
    }
  } );

  // Since this is an asynchronous task, each step in the task uses a callback to advance to the next step.
  // The final step in the task calls 'done', to tell grunt that the task has completed.
  createDependenciesJSON( grunt, buildConfig, function( dependenciesJSON ) {
    done();
  } );
};
<commit_msg>copy all of sherpa by default, https://github.com/phetsims/phet-io-wrapper-sonification/issues/26<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * This (asynchronous) grunt task builds and minifies an individual wrapper.
 * Note this file was created to support building the phet-io-wrapper-sonification repo, and should be worked on before
 * using on other wrappers.
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

// modules
var ChipperConstants = require( '../../../chipper/js/common/ChipperConstants' );
var copyDirectory = require( '../../../chipper/js/grunt/phet-io/copyDirectory' );
var createDependenciesJSON = require( '../../../chipper/js/grunt/createDependenciesJSON' );

// build in node apis
var fs = require( 'fs' );

// Don't copy these files/folders into the built wrapper
var WRAPPER_BLACKLIST = [ '.git', 'README.md', '.gitignore', 'node_modules', 'build' ];

/**
 * @param grunt - the grunt instance
 * @param {Object} buildConfig - see getBuildConfig.js
 */
module.exports = function( grunt, buildConfig ) {
  'use strict';

  // Tell grunt to wait because this task is asynchronous.
  // Returns a handle to a function that must be called when the task has completed.
  var done = grunt.task.current.async();

  buildConfig.phetLibs.forEach( function( repo ) {

    //  We only need the common folder from this repo
    if ( repo === 'phet-io-wrappers' ) {
      repo = 'phet-io-wrappers/common';
    }

    // Special case for the sherpa repo. Look for packageJSON.wrapper.sherpaDependencies for individual files to copy on build.
    if ( repo === 'sherpa' ) {

      // If there are no sherpaDependencies mentioned in the package.json, then still just copy the whole repo.
      if ( !buildConfig.wrapperSherpaDependencies ) {
        grunt.log.debug( 'To decrease the size of the sherpa dependency, use wrapper.sheraDependencies in package.json ' +
                         'to specify sherpa libraries from sherpa/lib.' );
      }

      else {
        var pathToLib = '/sherpa/lib/';
        fs.mkdirSync( ChipperConstants.BUILD_DIR + '/' + repo );
        fs.mkdirSync( ChipperConstants.BUILD_DIR + pathToLib );
        grunt.log.debug( 'created sherpa lib file: ' + ChipperConstants.BUILD_DIR + pathToLib );

        buildConfig.wrapperSherpaDependencies.forEach( function( file ) {
          grunt.file.copy( '..' + pathToLib + file, ChipperConstants.BUILD_DIR + pathToLib + file );
        } );

        return; // short circuit before the whole copy below.
      }
    }

    // otherwise copy the whole directory over, except the black list from above
    copyDirectory( grunt, '../' + repo, ChipperConstants.BUILD_DIR + '/' + repo + '/', null, {
      blacklist: WRAPPER_BLACKLIST, // List of files to not copy

      // TODO: We want to minify the built wrapper, but currently it is causing an error,
      // see https://github.com/phetsims/phet-io-wrapper-sonification/issues/19#event-1153696188
      minifyJS: true,
      licenseToPrepend: '// Copyright 2002-2017, University of Colorado Boulder\n' +
                        '// This PhET-iO file requires a license\n' +
                        '// USE WITHOUT A LICENSE AGREEMENT IS STRICTLY PROHIBITED.\n' +
                        '// For licensing, please contact phethelp@colorado.edu\n\n'
    } );
  } );

  // Since this is an asynchronous task, each step in the task uses a callback to advance to the next step.
  // The final step in the task calls 'done', to tell grunt that the task has completed.
  createDependenciesJSON( grunt, buildConfig, function() {
    done();
  } );
};
<|endoftext|>


<commit_before>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        /*
         * NAVIGATION
         */
        // jQuery to collapse the navbar on scroll
        $(window).scroll(function() {
          if ($('.navbar').offset().top > 70) {
            $('.navbar-fixed-top').addClass('top-nav-collapse');
          } else {
            $('.navbar-fixed-top').removeClass('top-nav-collapse');
          }
        });
        // jQuery for page scrolling feature - requires jQuery Easing plugin
        $(function() {
          $('a.page-scroll').bind('click', function(event) {
            var $anchor = $(this);
            $('html, body').stop().animate({
              scrollTop: $($anchor.attr('href')).offset().top
            }, 1500, 'easeInOutExpo');
            event.preventDefault();
          });
        });
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.
<commit_msg>Add owl carousel functionaility<commit_after>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        /*
         * NAVIGATION
         */
        // jQuery to collapse the navbar on scroll
        $(window).scroll(function() {
          if ($('.navbar').offset().top > 70) {
            $('.navbar-fixed-top').addClass('top-nav-collapse');
          } else {
            $('.navbar-fixed-top').removeClass('top-nav-collapse');
          }
        });
        // jQuery for page scrolling feature - requires jQuery Easing plugin
        $(function() {
          $('a.page-scroll').bind('click', function(event) {
            var $anchor = $(this);
            $('html, body').stop().animate({
              scrollTop: $($anchor.attr('href')).offset().top
            }, 1500, 'easeInOutExpo');
            event.preventDefault();
          });
        });
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
        $('.owl-carousel').each(function() {
          section_id = $(this).parents('section').attr('id');
          console.log(section_id);
          $('#' + section_id + ' .layout_gallery').owlCarousel({
            animateOut:   'fadeOut',
            animateIn:    'fadeIn',
            items:        1,
            loop:         false,
            margin:       0,
            nav:          false,
            dots:         true,
            autoplay:     true,
            autoHeight:   true
          });
        });
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.
<|endoftext|>


<commit_before>define(['./windowChannel', './runtime'], (WindowChannel, Runtime) => {
    'use strict';

    class Integration {
        constructor({ rootWindow }) {
            this.rootWindow = rootWindow;
            this.container = rootWindow.document.body;
            // channelId, frameId, hostId, parentHost
            this.hostParams = this.getParamsFromIFrame();
            this.hostChannelId = this.hostParams.channelId;

            // The original params from the plugin (taken from the url)
            this.pluginParams = this.hostParams.params;

            this.authorized = null;

            // this is the channel for this window.
            // this.channel = new WindowChannel.Channel({
            //     window: this.rootWindow,
            //     host: document.location.origin
            //     // recieveFor: [this.id],
            //     // clientId: this.iframe.id,
            //     // hostId: this.id
            // });

            // this.performanceMonitoringListener = null;

            // // This is the channel for the window containing this iframe.
            // this.hostChannel = new WindowChannel.Channel({
            //     window: this.rootWindow.parent,
            //     host: this.hostParams.parentHost,
            //     channelId: this.hostParams.channelId
            // });

            this.channel = new WindowChannel.BidirectionalWindowChannel({
                on: this.rootWindow,
                host: document.location.origin,
                to: this.hostChannelId
            });
        }

        getParamsFromIFrame() {
            if (!this.rootWindow.frameElement.hasAttribute('data-params')) {
                throw new Error('No params found in window!!');
            }
            return JSON.parse(decodeURIComponent(this.rootWindow.frameElement.getAttribute('data-params')));
        }

        start() {
            this.channel.start();

            this.channel.on('start', (payload) => {
                const { token, username, config, realname, email } = payload;
                if (token) {
                    this.authorization = { token, username, realname, email };
                } else {
                    this.authorization = null;
                }
                this.token = token;
                this.username = username;
                this.config = config;
                this.authorized = token ? true : false;

                this.runtime = new Runtime({ config, token, username, realname, email });
            });

            window.document.addEventListener('click', () => {
                this.channel.send('clicked', {});
            });

            // Sending 'ready' with our channel id and host name allows the
            // enclosing app (window) to send us messages on our very own channel.
            // We could just use the host's channel, have all sends and receives
            // on the same channel, with control via the channel id. However, there is a risk
            // the the channels will listen on for the same message ... unlikely though.
            // Still, it would be odd for one window to listen for messages on another...
            this.channel.send('ready', {
                channelId: this.channel.id,
                channelHost: this.channel.host
            });
        }

        stop() {}
    }

    return Integration;
});
<commit_msg>fix inegration; ensure started and start-error are sent after handling start.<commit_after>define(['./windowChannel', './runtime'], (WindowChannel, Runtime) => {
    'use strict';

    class Integration {
        constructor({ rootWindow }) {
            this.rootWindow = rootWindow;
            this.container = rootWindow.document.body;
            // channelId, frameId, hostId, parentHost
            this.hostParams = this.getParamsFromIFrame();
            this.hostChannelId = this.hostParams.channelId;

            // The original params from the plugin (taken from the url)
            this.pluginParams = this.hostParams.params;

            this.authorized = null;

            // this is the channel for this window.
            // this.channel = new WindowChannel.Channel({
            //     window: this.rootWindow,
            //     host: document.location.origin
            //     // recieveFor: [this.id],
            //     // clientId: this.iframe.id,
            //     // hostId: this.id
            // });

            // this.performanceMonitoringListener = null;

            // // This is the channel for the window containing this iframe.
            // this.hostChannel = new WindowChannel.Channel({
            //     window: this.rootWindow.parent,
            //     host: this.hostParams.parentHost,
            //     channelId: this.hostParams.channelId
            // });

            this.channel = new WindowChannel.BidirectionalWindowChannel({
                on: this.rootWindow,
                host: document.location.origin,
                to: this.hostChannelId
            });
        }

        getParamsFromIFrame() {
            if (!this.rootWindow.frameElement.hasAttribute('data-params')) {
                throw new Error('No params found in window!!');
            }
            return JSON.parse(decodeURIComponent(this.rootWindow.frameElement.getAttribute('data-params')));
        }

        start() {
            this.channel.start();

            this.channel.on('start', (payload) => {
                try {
                    const { token, username, config, realname, email } = payload;
                    if (token) {
                        this.authorization = { token, username, realname, email };
                    } else {
                        this.authorization = null;
                    }
                    this.token = token;
                    this.username = username;
                    this.config = config;
                    this.authorized = token ? true : false;

                    this.runtime = new Runtime({ config, token, username, realname, email });
                } catch (ex) {
                    this.channel.send('start-error', {
                        message: ex.message
                    });
                }

                this.channel.send('started');
            });

            window.document.addEventListener('click', () => {
                this.channel.send('clicked', {});
            });

            // Sending 'ready' with our channel id and host name allows the
            // enclosing app (window) to send us messages on our very own channel.
            // We could just use the host's channel, have all sends and receives
            // on the same channel, with control via the channel id. However, there is a risk
            // the the channels will listen on for the same message ... unlikely though.
            // Still, it would be odd for one window to listen for messages on another...
            this.channel.send('ready', {
                channelId: this.channel.id,
                channelHost: this.channel.host
            });
        }

        stop() {}
    }

    return Integration;
});
<|endoftext|>


<commit_before>'use strict';

di('log', function(injector) {
  var
    noop = function() {},
    log = {},
    logDebug = getConsoleWriteDelegate('debug');

  ['log', 'info', 'warn', 'error'].forEach(function(type) {
    log[type] = getConsoleWriteDelegate(type);
  });

  log.debug = function() {
    if (!log.debugEnabled) {
      return noop;
    }
    return logDebug.apply(null, Array.prototype.slice.call(arguments));
  };

  return log;

  function getConsoleWriteDelegate(type) {
    return function() {
      var
        console = window.console;

      if (console) {
        console[type].apply(console, Array.prototype.slice.call(arguments));
      }
    }
  }

});

<commit_msg>Fix logger in jquery version for IE9<commit_after>'use strict';

di('log', function(injector) {
  var
    log = {};

  ['log', 'info', 'warn', 'error'].forEach(function(type) {
    log[type] = getConsoleWriteDelegate(type);
  });

  return log;

  function getConsoleWriteDelegate(type) {
    return function() {
      var
        console = window.console,
        args = Array.prototype.slice.call(arguments);

      if (console[type].apply) {
        console[type].apply(console, args);
      }
      else {
        switch(args.length) {
          case 0: console[type](); break;
          default:
            args.forEach(function(arg) {
              console[type](arg);
            });
        }
      }
    }
  }

});

<|endoftext|>


<commit_before>/*
 * grunt-ristretto
 *
 * Copyright (c) 2013 Viliam Kopecky
 * Licensed under the MIT license.
 */

'use strict';

// show debug info on error
process.on('uncaughtException', function(err) {
    console.log(err.stack);
});

module.exports = function(grunt) {

  var fs = require('fs');
  var path = require('path');

  var metafilename = '.ristretto.json';

  var allow_publish = function(dir, meta) {
    var allow_write = false;

    if(grunt.file.exists(dir)) { // publish dir/file exists
      if(grunt.file.isDir(dir)) { // is directory
        if(grunt.file.exists(meta)) { // contains ristretto metadata
          allow_write = true;
        } else { // does not contain ristretto metadata
          if(grunt.file.expand([dir+'/**.*']).length === 0) { // directory is empty
            allow_write = true;
          } else { // directory is not empty, but doesn't contain ristretto metadata
            allow_write = true; //grunt.warn('Publish direrctory "'+dir+'" is not empty.');
          }
        }
      } else { // publish dir is not a directory
        grunt.warn('File '+dir+' already exists and is not a directory.');
      }
    } else { // publish dir doesn't exist
      allow_write = true;
    }
    return allow_write;
  };

  var build_and_copy = function(options, params, dest, meta, done) {

    var php_script = require('../libs/php_script');

    var latte2html = php_script.latte2html;
    var neon2json = php_script.neon2json;

    var copy_files = grunt.file.expand({ cwd: params.www_dir }, ['**/*.*', '**/.*', '!**/*.latte', '!**/*.neon']);
    var neon_files = grunt.file.expand({ cwd: params.model_dir }, ['**/*.neon']);
    var latte_files = grunt.file.expand({ cwd: params.latte_dir }, ['**/*.latte', '!**/@*.latte']);

    var next_total = 1;
    var next = function() {
      if(next_total === 3) {
          grunt.file.write(meta, JSON.stringify({ 'published_by': 'Ristretto', 'timestamp': (new Date()).getTime() }));
          grunt.log.writeln('');
          grunt.log.ok('Publish finished', meta);
          grunt.log.writeln('  ', dest);
          return done();
      }
      next_total++;
    };

    var published_copy = 0;
    var next_copy = function(){
      if(published_copy === copy_files.length) {
        grunt.log.ok('Finished: Copy static files');
        next();
        return;
      }
      var filepath = copy_files[published_copy];

      if(grunt.file.isFile(params.www_dir + '/' + filepath)) {
        grunt.log.writeln('   Copy file', filepath);

        grunt.file.copy(params.www_dir + '/' + filepath, dest + filepath);
      }
      published_copy++;
      next_copy();
    };
    next_copy();

    var published_latte = 0;
    var next_latte = function(){
      if(published_latte === latte_files.length) {
        grunt.log.ok('Finished: Compile Latte files');
        next();
        return;
      }
      var filepath = latte_files[published_latte];
      grunt.log.writeln('   Compiling Latte file', filepath);

      latte2html(options, filepath, function(body){
        var write = dest + filepath.substr(0, filepath.length - 'latte'.length) + 'html';
        grunt.log.writeln('   Writing Latte file', filepath);
        grunt.file.write(write, body);
        published_latte++;
        next_latte();
      });
    };
    next_latte();

    var published_neon = 0;
    var next_neon = function(){
      if(published_neon === neon_files.length) {
        grunt.log.ok('Finished: Compile NE-ON files');
        next();
        return;
      }
      var filepath = neon_files[published_neon];
      grunt.log.writeln('   Compiling NE-ON file', filepath);

      neon2json(options, filepath, function(body){
        var model_dest = dest;
        if(options.model_dir.indexOf(options.www_dir) === 0) {
          model_dest += options.model_dir.substr(options.www_dir.length+1);
        } else {
          model_dest += options.model_dir;
        }
        grunt.log.writeln('   Compiling NE-ON file', filepath);
        var write = model_dest + '/' +filepath;
        grunt.file.write(write, body);
        published_neon++;
        next_neon();
      });
    };
    next_neon();
  };

  var publish = function(options, done) {
    var dest = options.publish_dir + '/';
    dest = dest.replace('//', '/');

    var meta = dest + metafilename;

    var params = {
      www_dir: fs.realpathSync(options.www_dir),
      latte_dir: fs.realpathSync(options.latte_dir),
      temp_dir: fs.realpathSync(options.temp_dir)
    };

    if(options.model_dir && grunt.file.exists(options.model_dir)) {
      params.model_dir = fs.realpathSync(options.model_dir);
    }

    if(!allow_publish(dest, meta)) {
      done();
      return;
    }

    var created = false;
    if(!grunt.file.exists(dest)) {
      created = true;
      grunt.file.mkdir(dest);
    }

    if(grunt.file.isPathInCwd(dest)) {
      grunt.file.delete(dest);
      build_and_copy(options, params, dest, meta, done);
    } else {
      console.log('');
      grunt.log.warn('You are publishing into directory outside of CWD. This action will overwrite its contents.');
      grunt.log.warn(dest);
      require('co-prompt').confirm("\n   Are you sure? [ NO | yes ]: ")(function(wut, ok) {
        if(ok) {
          var time = (new Date).getTime();
          var temp_dest = dest.replace(/\/*$/, '') + '-ristretto-' + time;

          if(grunt.file.exists(dest)) {
            if(created) {
              grunt.file.delete(dest, { force: true });
            } else {
              require('fs').renameSync(dest, temp_dest);
            }
          }

          grunt.log.ok('Original contents moved to:');
          grunt.log.ok(temp_dest);

          build_and_copy(options, params, dest, meta, done);
        } else {
          console.log('');
          grunt.log.ok('Publish aborted');
          done();
        }
      });
    }

  };

  grunt.registerTask('ristretto', 'Ristretto frontend prototyping system', function() {
    var options = this.options();
    var config = options.config;

    var version = config.ristretto_version = grunt.file.readJSON(__dirname + '/../package.json').version;

    if(typeof config.port === 'undefined') {
      config.port = 8000;
    }

    if(typeof config.www_dir === 'undefined') {
      config.www_dir = '.';
    }

    if(typeof config.model_dir === 'undefined') {
      config.model_dir = config.www_dir + '/model';
    }

    if(typeof config.latte_dir === 'undefined') {
      config.latte_dir = config.www_dir;
    }

    if(typeof config.publish_dir === 'undefined') {
      config.publish_dir = 'publish';
    }

    if(typeof config.temp_dir === 'undefined') {
      config.temp_dir = require('os').tmpdir() + '/ristretto-'+version;
    }

    if(grunt.file.exists(config.temp_dir)) {
      if(!grunt.file.isDir(config.temp_dir)) {
        grunt.log.error('Temporary dir path is not a directory: `' + config.temp_dir + '`.');
      }
    } else {
      grunt.file.mkdir(config.temp_dir);
    }

    var flags = this.flags;
    var done = this.async();

    var request = require('request');

    if(flags['reload'] || flags['pages']) {
      request('http://127.0.0.1:'+config.port+'/reload', function(){
        done();
      });
    return;
    } else if(flags['reload-stylesheets'] || flags['styles'] || flags['stylesheets']) {
      request('http://127.0.0.1:'+config.port+'/reload-stylesheets', function(){
        done();
      });
      return;
    } else if(flags['publish']) {
      publish(config, function(){
        done();
      });
    return;
    } else if(flags['startup']) {
      require('../libs/server').startup(config, function() {
        console.log('Ristretto running on 127.0.0.1:'+config.port);
        done();
      });
    return;
    }

  });

};<commit_msg>Typo during publish<commit_after>/*
 * grunt-ristretto
 *
 * Copyright (c) 2013 Viliam Kopecky
 * Licensed under the MIT license.
 */

'use strict';

// show debug info on error
process.on('uncaughtException', function(err) {
    console.log(err.stack);
});

module.exports = function(grunt) {

  var fs = require('fs');
  var path = require('path');

  var metafilename = '.ristretto.json';

  var allow_publish = function(dir, meta) {
    var allow_write = false;

    if(grunt.file.exists(dir)) { // publish dir/file exists
      if(grunt.file.isDir(dir)) { // is directory
        if(grunt.file.exists(meta)) { // contains ristretto metadata
          allow_write = true;
        } else { // does not contain ristretto metadata
          if(grunt.file.expand([dir+'/**.*']).length === 0) { // directory is empty
            allow_write = true;
          } else { // directory is not empty, but doesn't contain ristretto metadata
            allow_write = true; //grunt.warn('Publish direrctory "'+dir+'" is not empty.');
          }
        }
      } else { // publish dir is not a directory
        grunt.warn('File '+dir+' already exists and is not a directory.');
      }
    } else { // publish dir doesn't exist
      allow_write = true;
    }
    return allow_write;
  };

  var build_and_copy = function(options, params, dest, meta, done) {

    var php_script = require('../libs/php_script');

    var latte2html = php_script.latte2html;
    var neon2json = php_script.neon2json;

    var copy_files = grunt.file.expand({ cwd: params.www_dir }, ['**/*.*', '**/.*', '!**/*.latte', '!**/*.neon']);
    var neon_files = grunt.file.expand({ cwd: params.model_dir }, ['**/*.neon']);
    var latte_files = grunt.file.expand({ cwd: params.latte_dir }, ['**/*.latte', '!**/@*.latte']);

    var next_total = 1;
    var next = function() {
      if(next_total === 3) {
          grunt.file.write(meta, JSON.stringify({ 'published_by': 'Ristretto', 'timestamp': (new Date()).getTime() }));
          grunt.log.writeln('');
          grunt.log.ok('Publish finished', meta);
          grunt.log.writeln('  ', dest);
          return done();
      }
      next_total++;
    };

    var published_copy = 0;
    var next_copy = function(){
      if(published_copy === copy_files.length) {
        grunt.log.ok('Finished: Copy static files');
        next();
        return;
      }
      var filepath = copy_files[published_copy];

      if(grunt.file.isFile(params.www_dir + '/' + filepath)) {
        grunt.log.writeln('   Copy file', filepath);

        grunt.file.copy(params.www_dir + '/' + filepath, dest + filepath);
      }
      published_copy++;
      next_copy();
    };
    next_copy();

    var published_latte = 0;
    var next_latte = function(){
      if(published_latte === latte_files.length) {
        grunt.log.ok('Finished: Compile Latte files');
        next();
        return;
      }
      var filepath = latte_files[published_latte];
      grunt.log.writeln('   Compiling Latte file', filepath);

      latte2html(options, filepath, function(body){
        var write = dest + filepath.substr(0, filepath.length - 'latte'.length) + 'html';
        grunt.log.writeln('   Writing Latte file', filepath);
        grunt.file.write(write, body);
        published_latte++;
        next_latte();
      });
    };
    next_latte();

    var published_neon = 0;
    var next_neon = function(){
      if(published_neon === neon_files.length) {
        grunt.log.ok('Finished: Compile NE-ON files');
        next();
        return;
      }
      var filepath = neon_files[published_neon];
      grunt.log.writeln('   Compiling NE-ON file', filepath);

      neon2json(options, filepath, function(body){
        var model_dest = dest;
        if(options.model_dir.indexOf(options.www_dir) === 0) {
          model_dest += options.model_dir.substr(options.www_dir.length+1);
        } else {
          model_dest += options.model_dir;
        }
        grunt.log.writeln('   Writing NE-ON file', filepath);
        var write = model_dest + '/' +filepath;
        grunt.file.write(write, body);
        published_neon++;
        next_neon();
      });
    };
    next_neon();
  };

  var publish = function(options, done) {
    var dest = options.publish_dir + '/';
    dest = dest.replace('//', '/');

    var meta = dest + metafilename;

    var params = {
      www_dir: fs.realpathSync(options.www_dir),
      latte_dir: fs.realpathSync(options.latte_dir),
      temp_dir: fs.realpathSync(options.temp_dir)
    };

    if(options.model_dir && grunt.file.exists(options.model_dir)) {
      params.model_dir = fs.realpathSync(options.model_dir);
    }

    if(!allow_publish(dest, meta)) {
      done();
      return;
    }

    var created = false;
    if(!grunt.file.exists(dest)) {
      created = true;
      grunt.file.mkdir(dest);
    }

    if(grunt.file.isPathInCwd(dest)) {
      grunt.file.delete(dest);
      build_and_copy(options, params, dest, meta, done);
    } else {
      console.log('');
      grunt.log.warn('You are publishing into directory outside of CWD. This action will overwrite its contents.');
      grunt.log.warn(dest);
      require('co-prompt').confirm("\n   Are you sure? [ NO | yes ]: ")(function(wut, ok) {
        if(ok) {
          var time = (new Date).getTime();
          var temp_dest = dest.replace(/\/*$/, '') + '-ristretto-' + time;

          if(grunt.file.exists(dest)) {
            if(created) {
              grunt.file.delete(dest, { force: true });
            } else {
              require('fs').renameSync(dest, temp_dest);
            }
          }

          grunt.log.ok('Original contents moved to:');
          grunt.log.ok(temp_dest);

          build_and_copy(options, params, dest, meta, done);
        } else {
          console.log('');
          grunt.log.ok('Publish aborted');
          done();
        }
      });
    }

  };

  grunt.registerTask('ristretto', 'Ristretto frontend prototyping system', function() {
    var options = this.options();
    var config = options.config;

    var version = config.ristretto_version = grunt.file.readJSON(__dirname + '/../package.json').version;

    if(typeof config.port === 'undefined') {
      config.port = 8000;
    }

    if(typeof config.www_dir === 'undefined') {
      config.www_dir = '.';
    }

    if(typeof config.model_dir === 'undefined') {
      config.model_dir = config.www_dir + '/model';
    }

    if(typeof config.latte_dir === 'undefined') {
      config.latte_dir = config.www_dir;
    }

    if(typeof config.publish_dir === 'undefined') {
      config.publish_dir = 'publish';
    }

    if(typeof config.temp_dir === 'undefined') {
      config.temp_dir = require('os').tmpdir() + '/ristretto-'+version;
    }

    if(grunt.file.exists(config.temp_dir)) {
      if(!grunt.file.isDir(config.temp_dir)) {
        grunt.log.error('Temporary dir path is not a directory: `' + config.temp_dir + '`.');
      }
    } else {
      grunt.file.mkdir(config.temp_dir);
    }

    var flags = this.flags;
    var done = this.async();

    var request = require('request');

    if(flags['reload'] || flags['pages']) {
      request('http://127.0.0.1:'+config.port+'/reload', function(){
        done();
      });
    return;
    } else if(flags['reload-stylesheets'] || flags['styles'] || flags['stylesheets']) {
      request('http://127.0.0.1:'+config.port+'/reload-stylesheets', function(){
        done();
      });
      return;
    } else if(flags['publish']) {
      publish(config, function(){
        done();
      });
    return;
    } else if(flags['startup']) {
      require('../libs/server').startup(config, function() {
        console.log('Ristretto running on 127.0.0.1:'+config.port);
        done();
      });
    return;
    }

  });

};<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var Promise     = require('bluebird');
var _           = require('lodash');
var path        = require('path');
var logger      = require('winston');

var mixin       = require('./entity');
var Variant     = require('./variant');
var utils       = require('../../utils');
var data        = require('../../data');
var md          = require('../../markdown');

/*
 * Export the component.
 */

module.exports = Component;

/*
 * Component constructor.
 *
 * - Extract config from config file, if present.
 * - Build component metadata .
 * - Instantiate and return new component.
 *
 * @api private
 */

function Component(entity, files, config, app){

    var self                = this;
    var engine              = app.getComponentViewEngine();

    this._app               = app;
    this._source            = entity;
    this._files             = files;
    this._config            = _.cloneDeep(config);

    this.readme             = null;
    this.default            = null;
    this.variants           = null;
    this.sourceType         = entity.type;
    this.type               = 'component';
    this.order              = entity.order;
    this.depth              = entity.depth;
    this.hidden             = !! (config.hidden || entity.hidden);
    this.path               = utils.fauxPath(this.sourceType == 'directory' ? entity.path : path.join(entity.relativeDir, entity.name));
    this.handlePath         = this.path;
    this.handle             = config.handle || utils.fauxPath(entity.name);
    this.fullHandle         = '@' + this.handle;
    this.label              = config.label || utils.titlize(entity.name);
    this.title              = config.title || this.label;
    this.defaultHandle      = config.default || 'default';
    this.viewExt            = engine.ext;
    this.engine             = engine.engine;

    this.variantDefaults = {
        status:     config.status || app.get('statuses:default'),
        context:    config.context || {},
        preview:    config.preview || app.get('components:preview:layout'),
        display:    config.display || {},
        view:       config.view || (entity.fsName + this.viewExt)
    };

    this._viewFiles = _.filter(files, function(file){
        return file.matches('^.*{{ext}}$', {
            ext: engine.ext
        });
    });

    this._configFiles = _.filter(files, function(file){
        return file.matches(app.get('components:config'), {
            name: '.*'
        }, null, true);
    });

    this._nonViewFiles = _.difference(files, this._viewFiles);

    this._nonCoreFiles = _.difference(files, this._viewFiles, this._configFiles);

};

mixin.call(Component.prototype);

/*
 * Initialise the component.
 * Returns a promise.
 *
 * @api private
 */

Component.prototype.init = function(){
    var self = this;
    var variants        = this.getVariants();
    this.readme         = this.getReadme();
    return Promise.join(variants, function(variants){
        self.variants = variants;
        self.default  = _.find(variants, 'handle', self.defaultHandle);
        self.status   = self.getStatuses();
        return self;
    });
};

/*
 * Get an array of all the available variants.
 * Includes the default variant, so this will always have a length > 0.
 *
 * @api private
 */

Component.prototype.getVariants = function(){
    if (this.variants) {
        return this.variants;
    }
    var self = this;
    var variants = [];
    var splitter = self._app.get('components:variantSplitter');
    var configs = _.map(this._config.variants || [], function(config){
        if (!_.isUndefined(config.handle)) {
            return makeVariantConfig(config.handle, config).then(function(conf){
                conf.files = _.clone(self._nonCoreFiles);
                // get the view file
                var file = _.find(self._viewFiles, 'fsBase', conf.view);
                if (!file) {
                    logger.error('Variant of ' + config.handle + ' could not be created - view file not found');
                    return null;
                }
                conf.files.unshift(file);
                return conf;
            });
        } else {
            logger.error('Variant of ' + config.handle + ' could not be created: ' + e.message );
        }
    });

    return Promise.all(configs).then(function(configs){

        // Generate configs for any files that look like a variant but don't have config specified.
        _.each(self._viewFiles, function(file){
            if (file.fsBase == self.variantDefaults.view) {
                // it's the default variant's view
                if (!_.find(configs, 'handle', self.defaultHandle)) {
                    var variantConf = makeVariantConfig(self.defaultHandle, {
                        handle: self.defaultHandle
                    }).then(function(conf){
                        conf.files = _.clone(self._nonCoreFiles);
                        conf.files.unshift(file);
                        return conf;
                    });
                    configs.push(variantConf);
                }
            } else {
                // Does the file match the expected variant view filename pattern?
                var matches = file.matches('^' + self.handle + '{{splitter}}.*{{ext}}$', {
                    splitter: splitter,
                    ext: self.viewExt
                });
                if (matches) {
                    var parts = file.match('^' + self.handle + '{{splitter}}(.*){{ext}}$', {
                        splitter: splitter,
                        ext: self.viewExt
                    });
                    if (parts && !_.find(configs, 'handle', parts[1])) {
                        // no configuration for this variant view yet so push it onto the stack
                        var variantConf = makeVariantConfig(parts[1], {
                            handle: parts[1],
                            view: file.base
                        }).then(function(conf){
                            conf.files = _.clone(self._nonCoreFiles);
                            conf.files.unshift(file);
                            return conf;
                        });
                        configs.push(variantConf);
                    }
                }
            }
        });

        // if (this.sourceType == 'directory') {
        //     // also check the subdirectories to see if any of those contain variants
        //     var subDirs = this._source.getDirectories();

        // }

        return Promise.all(configs).then(function(configs){
            // Now generate some variant objects from the configs
            return _.map(configs, function(config){
                return (new Variant(config.handle, config, self)).init();
            });
        });
    });

    function makeVariantConfig(handle, variantConf){
        // is there a variant-specific config file?
        var configFile = _.find(self._configFiles, function(entity){
            return entity.matches(self._app.get('components:config'), {
                name: self.handle + splitter + handle
            });
        });
        var specificConfig = configFile ? data.load(configFile.absolutePath) : Promise.resolve({});
        return specificConfig.then(function(spec){
            return _.defaultsDeep(spec, variantConf, self.variantDefaults);
        });
    }

};

/*
 * Get an object describing the specified variant.
 *
 * @api public
 */

Component.prototype.getVariant = function(handle){
    handle = handle || this.defaultHandle;
    var variant = _.find(this.variants, 'handle', handle);
    if (!variant) {
        throw new Error('The variant ' + handle + ' of component ' + this.handle + ' could not be found.');
    }
    return variant;
};

/*
 * Generate a rendered view of a variant.
 * Returns a Promise object.
 *
 * @api public
 */

Component.prototype.renderView = function(context, preview, handle){
    var variant = this.getVariant(handle);
    return variant.renderView(context, preview);
};

/*
 * Pre-render all variants.
 * Useful for running before .toJSON() to provide a one-hit promise-based rendering of variants.
 * Returns a promise of self.
 *
 * @api public
 */

Component.prototype.renderAll = function(){
    var self = this;
    var promises = _.map(this.variants, function(variant){
        return variant.preRender();
    });
    return Promise.all(promises).then(function(){
        return self;
    });
};

/*
 * Gets a de-duped array of the component variants statuses.
 *
 * @api public
 */

Component.prototype.getStatuses = function(){
    return _.compact(_.uniq(_.map(this.variants, function(variant){
        return variant.status;
    })));
};

/*
 * Get the readme contents.
 *
 * @api public
 */

Component.prototype.getReadme = function(){
    var str = null;
    var self = this;
    if (_.isUndefined(this._config.readme)) {
        var readMeFile = _.find(this._files, function(entity){
            return entity.matches(self._app.get('components:readme'));
        });
        str = readMeFile ? readMeFile.getContents() : null;
    } else {
        str = this._config.readme || null;
    }
    return str ? md(str) : null;
};

/*
 * Factory method to create a new component from a directory.
 *
 * @api public
 */

Component.fromDirectory = function(dir, config, app){
    return (new Component(dir, dir.getFiles(), config, app)).init();
};

/*
 * Factory method to create a new component from a file.
 *
 * @api public
 */

Component.fromFile = function(file, dir, config, app){
    var self = this;
    var files = _.filter(dir.getFiles(), function(file){
        return _.startsWith(file.name, file.name);
    });

    // check to see if there is some config associated with the file
    var configFile = _.find(files, function(entity){
        return entity.matches(app.get('components:config'), {
            name: file.name
        });
    });
    var componentConfig = configFile ? data.load(configFile.absolutePath) : Promise.resolve({});
    return componentConfig.then(function(componentConfig){
        return (new Component(file, files, _.defaultsDeep(componentConfig, config), app)).init();
    });
};<commit_msg>Fix variant ordering<commit_after>/**
 * Module dependencies.
 */

var Promise     = require('bluebird');
var _           = require('lodash');
var path        = require('path');
var logger      = require('winston');

var mixin       = require('./entity');
var Variant     = require('./variant');
var utils       = require('../../utils');
var data        = require('../../data');
var md          = require('../../markdown');

/*
 * Export the component.
 */

module.exports = Component;

/*
 * Component constructor.
 *
 * - Extract config from config file, if present.
 * - Build component metadata .
 * - Instantiate and return new component.
 *
 * @api private
 */

function Component(entity, files, config, app){

    var self                = this;
    var engine              = app.getComponentViewEngine();

    this._app               = app;
    this._source            = entity;
    this._files             = files;
    this._config            = _.cloneDeep(config);

    this.readme             = null;
    this.default            = null;
    this.variants           = null;
    this.sourceType         = entity.type;
    this.type               = 'component';
    this.order              = entity.order;
    this.depth              = entity.depth;
    this.hidden             = !! (config.hidden || entity.hidden);
    this.path               = utils.fauxPath(this.sourceType == 'directory' ? entity.path : path.join(entity.relativeDir, entity.name));
    this.handlePath         = this.path;
    this.handle             = config.handle || utils.fauxPath(entity.name);
    this.fullHandle         = '@' + this.handle;
    this.label              = config.label || utils.titlize(entity.name);
    this.title              = config.title || this.label;
    this.defaultHandle      = config.default || 'default';
    this.viewExt            = engine.ext;
    this.engine             = engine.engine;

    this.variantDefaults = {
        status:     config.status || app.get('statuses:default'),
        context:    config.context || {},
        preview:    config.preview || app.get('components:preview:layout'),
        display:    config.display || {},
        view:       config.view || (entity.fsName + this.viewExt)
    };

    this._viewFiles = _.filter(files, function(file){
        return file.matches('^.*{{ext}}$', {
            ext: engine.ext
        });
    });

    this._configFiles = _.filter(files, function(file){
        return file.matches(app.get('components:config'), {
            name: '.*'
        }, null, true);
    });

    this._nonViewFiles = _.difference(files, this._viewFiles);

    this._nonCoreFiles = _.difference(files, this._viewFiles, this._configFiles);

};

mixin.call(Component.prototype);

/*
 * Initialise the component.
 * Returns a promise.
 *
 * @api private
 */

Component.prototype.init = function(){
    var self = this;
    var variants        = this.getVariants();
    this.readme         = this.getReadme();
    return Promise.join(variants, function(variants){
        self.variants = variants;
        self.default  = _.find(variants, 'handle', self.defaultHandle);
        self.status   = self.getStatuses();
        return self;
    });
};

/*
 * Get an array of all the available variants.
 * Includes the default variant, so this will always have a length > 0.
 *
 * @api private
 */

Component.prototype.getVariants = function(){
    if (this.variants) {
        return this.variants;
    }
    var self = this;
    var variants = [];
    var splitter = self._app.get('components:variantSplitter');
    var configs = _.map(this._config.variants || [], function(config){
        if (!_.isUndefined(config.handle)) {
            return makeVariantConfig(config.handle, config).then(function(conf){
                conf.files = _.clone(self._nonCoreFiles);
                // get the view file
                var file = _.find(self._viewFiles, 'fsBase', conf.view);
                if (!file) {
                    logger.error('Variant of ' + config.handle + ' could not be created - view file not found');
                    return null;
                }
                conf.files.unshift(file);
                return conf;
            });
        } else {
            logger.error('Variant of ' + config.handle + ' could not be created: ' + e.message );
        }
    });

    return Promise.all(configs).then(function(configs){

        // Generate configs for any files that look like a variant but don't have config specified.
        _.each(self._viewFiles, function(file){
            if (file.fsBase == self.variantDefaults.view) {
                // it's the default variant's view
                if (!_.find(configs, 'handle', self.defaultHandle)) {
                    var variantConf = makeVariantConfig(self.defaultHandle, {
                        handle: self.defaultHandle
                    }).then(function(conf){
                        conf.files = _.clone(self._nonCoreFiles);
                        conf.files.unshift(file);
                        return conf;
                    });
                    configs.push(variantConf);
                }
            } else {
                // Does the file match the expected variant view filename pattern?
                var matches = file.matches('^' + self.handle + '{{splitter}}.*{{ext}}$', {
                    splitter: splitter,
                    ext: self.viewExt
                });
                if (matches) {
                    var parts = file.match('^' + self.handle + '{{splitter}}(.*){{ext}}$', {
                        splitter: splitter,
                        ext: self.viewExt
                    });
                    if (parts && !_.find(configs, 'handle', parts[1])) {
                        // no configuration for this variant view yet so push it onto the stack
                        var variantConf = makeVariantConfig(parts[1], {
                            handle: parts[1],
                            view: file.base
                        }).then(function(conf){
                            conf.files = _.clone(self._nonCoreFiles);
                            conf.files.unshift(file);
                            return conf;
                        });
                        configs.push(variantConf);
                    }
                }
            }
        });

        // if (this.sourceType == 'directory') {
        //     // also check the subdirectories to see if any of those contain variants
        //     var subDirs = this._source.getDirectories();

        // }

        return Promise.all(configs).then(function(configs){
            // Now generate some variant objects from the configs
            return _.map(configs, function(config){
                return (new Variant(config.handle, config, self)).init();
            }).sort(function(a, b){
                if (a.handle === self.defaultHandle) {
                    return -1;
                }
                if (b.handle === self.defaultHandle) {
                    return 1;
                }
                return 0;
            });
        });
    });

    function makeVariantConfig(handle, variantConf){
        // is there a variant-specific config file?
        var configFile = _.find(self._configFiles, function(entity){
            return entity.matches(self._app.get('components:config'), {
                name: self.handle + splitter + handle
            });
        });
        var specificConfig = configFile ? data.load(configFile.absolutePath) : Promise.resolve({});
        return specificConfig.then(function(spec){
            return _.defaultsDeep(spec, variantConf, self.variantDefaults);
        });
    }

};

/*
 * Get an object describing the specified variant.
 *
 * @api public
 */

Component.prototype.getVariant = function(handle){
    handle = handle || this.defaultHandle;
    var variant = _.find(this.variants, 'handle', handle);
    if (!variant) {
        throw new Error('The variant ' + handle + ' of component ' + this.handle + ' could not be found.');
    }
    return variant;
};

/*
 * Generate a rendered view of a variant.
 * Returns a Promise object.
 *
 * @api public
 */

Component.prototype.renderView = function(context, preview, handle){
    var variant = this.getVariant(handle);
    return variant.renderView(context, preview);
};

/*
 * Pre-render all variants.
 * Useful for running before .toJSON() to provide a one-hit promise-based rendering of variants.
 * Returns a promise of self.
 *
 * @api public
 */

Component.prototype.renderAll = function(){
    var self = this;
    var promises = _.map(this.variants, function(variant){
        return variant.preRender();
    });
    return Promise.all(promises).then(function(){
        return self;
    });
};

/*
 * Gets a de-duped array of the component variants statuses.
 *
 * @api public
 */

Component.prototype.getStatuses = function(){
    return _.compact(_.uniq(_.map(this.variants, function(variant){
        return variant.status;
    })));
};

/*
 * Get the readme contents.
 *
 * @api public
 */

Component.prototype.getReadme = function(){
    var str = null;
    var self = this;
    if (_.isUndefined(this._config.readme)) {
        var readMeFile = _.find(this._files, function(entity){
            return entity.matches(self._app.get('components:readme'));
        });
        str = readMeFile ? readMeFile.getContents() : null;
    } else {
        str = this._config.readme || null;
    }
    return str ? md(str) : null;
};

/*
 * Factory method to create a new component from a directory.
 *
 * @api public
 */

Component.fromDirectory = function(dir, config, app){
    return (new Component(dir, dir.getFiles(), config, app)).init();
};

/*
 * Factory method to create a new component from a file.
 *
 * @api public
 */

Component.fromFile = function(file, dir, config, app){
    var self = this;
    var files = _.filter(dir.getFiles(), function(file){
        return _.startsWith(file.name, file.name);
    });

    // check to see if there is some config associated with the file
    var configFile = _.find(files, function(entity){
        return entity.matches(app.get('components:config'), {
            name: file.name
        });
    });
    var componentConfig = configFile ? data.load(configFile.absolutePath) : Promise.resolve({});
    return componentConfig.then(function(componentConfig){
        return (new Component(file, files, _.defaultsDeep(componentConfig, config), app)).init();
    });
};<|endoftext|>