<commit_before>var fs = require('fs'),
    path = require('path'),
    chalk = require('chalk'),
    byline = require('byline'),
    Transform = require('stream').Transform,
    JSONStream = require('JSONStream'),
    output_file_temp = '_tmp/gitlogg.tmp',
    output_file = '_output/gitlogg.json';

console.log(chalk.yellow('\n Parsing JSON output...\n'));

// initialise timer
console.time(chalk.green(' JSON output parsed in'));

// create the streams
var stream = fs.createReadStream(output_file_temp, 'utf8');
var output = fs.createWriteStream(output_file, 'utf8');
// handle errors
stream.on('error', function() {
  console.log(chalk.red(' Could not read from ' + output_file_temp));
});
output.on('error', function() {
  console.log(chalk.red(' Something went wrong, ' + output_file + ' could not be written / saved'));
});
// handle completion callback
output.on('finish', function() {
  console.timeEnd(chalk.green(' JSON output parsed in'));
  console.log(chalk.green(' The file ' + chalk.blue(output_file) + ' was saved. ' + chalk.yellow('Done! ✨\n')));
});

// stream the stream line by line
stream = byline.createStream(stream);
// create a transform stream
var parser = new Transform({ objectMode: true });
// use a JSONStream: JSONStream.stringify(open, sep, close)
var jsonToStrings = JSONStream.stringify('{\n  "commits" : [\n    ', ',\n    ', '\n  ]\n}\n');

// massage the stats
var changes = function(data, index) {
  var v = data.split(',')[index] || 0;
  var w = 0;
  if (v !== 0) {
    var w = v.split(' ')[1]; // the number of changes is second on the array
  }
  return parseInt(w);
};

// decode UTF-8-ized Latin-1/ISO-8859-1 to UTF-8
var decode = function(str) {
  var s;
  try {
    // if the string is UTF-8, this will work and not throw an error.
    s = decodeURIComponent(escape(str));
  } catch(e) {
    // if it isn't, an error will be thrown, and we can asume that we have an ISO string.
    s = str;
  }
  return s;
};

// replace double quotes with single ones
var unquote = function(str) {
  if (str === undefined) {
    return '';
  } else if (str != '') {
    return str.replace(/"/g, "'");
  } else {
    return str;
  }
};

// slice the string as long as it's not empty
var sliceit = function(str) {
  if (str === undefined) {
    return '';
  } else if (str != '') {
    return str.slice(1);
  } else {
    return str;
  }
}

// do the transformations, through the transform stream
parser._transform = function(data, encoding, done) {
  var separator = /\\t/;
  var dataDecoded = decode(data);
  var c = dataDecoded.trim().split(separator);
  // console.log(c);
  // vars based on sequential values ( sanitise " to ' on fields that accept user input )
  var repository =                     c[3],                    // color-consolidator
      commit_nr =                      parseInt(c[0], 10),      // 3
      commit_hash =                    c[5],                    // 5109ad5a394a4873290ff7f7a38b7ca2e1b3b8e1
      commit_hash_abbreviated =        c[7],                    // 5109ad5
      tree_hash =                      c[9],                    // a1606ea8d6e24e1c832b52cb9c04ae1df2242ed4
      tree_hash_abbreviated =          c[11],                   // a1606ea
      parent_hashes =                  c[13],                   // 7082fa621bf93503fe173d06ada3c6111054a62b
      parent_hashes_abbreviated =      c[15],                   // 7082fa6
      author_name =                    unquote(c[17]),          // Wallace Sidhrée
      author_name_mailmap =            unquote(c[19]),          // Wallace Sidhrée
      author_email =                   c[21],                   // i@dreamyguy.com
      author_email_mailmap =           c[23],                   // i@dreamyguy.com
      author_date =                    c[25],                   // Fri Jan 3 14:16:56 2014 +0100
      author_date_RFC2822 =            c[27],                   // Fri, 3 Jan 2014 14:16:56 +0100
      author_date_relative =           c[29],                   // 2 years, 5 months ago
      author_date_unix_timestamp =     c[31],                   // 1388755016
      author_date_iso_8601 =           c[33],                   // 2014-01-03 14:16:56 +0100
      author_date_iso_8601_strict =    c[35],                   // 2014-01-03T14:16:56+01:00
      committer_name =                 unquote(c[37]),          // Wallace Sidhrée
      committer_name_mailmap =         unquote(c[39]),          // Wallace Sidhrée
      committer_email =                c[41],                   // i@dreamyguy.com
      committer_email_mailmap =        c[43],                   // i@dreamyguy.com
      committer_date =                 c[45],                   // Fri Jan 3 14:16:56 2014 +0100
      committer_date_RFC2822 =         c[47],                   // Fri, 3 Jan 2014 14:16:56 +0100
      committer_date_relative =        c[49],                   // 2 years, 5 months ago
      committer_date_unix_timestamp =  c[51],                   // 1388755016
      committer_date_iso_8601 =        c[53],                   // 2014-01-03 14:16:56 +0100
      committer_date_iso_8601_strict = c[55],                   // 2014-01-03T14:16:56+01:00
      ref_names =                      unquote(c[57]),          // ""
      ref_names_no_wrapping =          unquote(c[59]),          // ""
      encoding =                       c[61],                   // ""
      subject =                        unquote(c[63]),          // Upgrade FontAwesome from 3.2.1 to 4.0.3"
      subject_sanitized =              c[65],                   // Upgrade-FontAwesome-from-3.2.1-to-4.0.3"
      commit_notes =                   unquote(c[67]),          // ""
      stats =                          sliceit(c[69]);          // ` 9 files changed, 507 insertions(+), 2102 deletions(-)`
  // vars that require manipulation
  var time_array =                     author_date.split(' '),                  // Fri Jan 3 14:16:56 2014 +0100 => [Fri, Jan, 3, 14:16:56, 2014, +0100]
      time_array_clock =               time_array[3].split(':'),                // 14:16:56 => [14, 16, 56]
      time_hour =                      parseInt(time_array_clock[0], 10),       // [14, 16, 56] => 14
      time_minutes =                   parseInt(time_array_clock[1], 10),       // [14, 16, 56] => 16
      time_seconds =                   parseInt(time_array_clock[2], 10),       // [14, 16, 56] => 56
      time_gmt =                       time_array[5],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => +0100
      date_array =                     author_date_iso_8601.split(' ')[0],      // 2014-01-03 14:16:56 +0100 => 2014-01-03
      date_day_week =                  time_array[0],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => Fri
      date_iso_8601 =                  date_array,                              // 2014-01-03
      date_month_day =                 parseInt(date_array.split('-')[2], 10),  // 2014-01-03 => [2014, 01, 03] => 03
      date_month_name =                time_array[1],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => Jan
      date_month_number =              parseInt(date_array.split('-')[1], 10),  // 2014-01-03 => [2014, 01, 03] => 01
      date_year =                      time_array[4],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => 2014
      files_changed =                  changes(stats, 0),                       // ` 9 files changed, 507 insertions(+), 2102 deletions(-)` => 9
      insertions =                     changes(stats, 1),                       // ` 9 files changed, 507 insertions(+), 2102 deletions(-)` => 507
      deletions =                      changes(stats, 2),                       // ` 9 files changed, 507 insertions(+), 2102 deletions(-)` => 2102
      impact =                         (insertions - deletions);                // 507 - 2102 => -1595
  // create the object
  var obj = {
      repository: repository,
      commit_nr: commit_nr,
      commit_hash: commit_hash,
      // commit_hash_abbreviated: commit_hash_abbreviated,
      // tree_hash: tree_hash,
      // tree_hash_abbreviated: tree_hash_abbreviated,
      // parent_hashes: parent_hashes,
      // parent_hashes_abbreviated: parent_hashes_abbreviated,
      author_name: author_name,
      // author_name_mailmap: author_name_mailmap,
      author_email: author_email,
      // author_email_mailmap: author_email_mailmap,
      author_date: author_date,
      // author_date_RFC2822: author_date_RFC2822,
      author_date_relative: author_date_relative,
      author_date_unix_timestamp: author_date_unix_timestamp,
      author_date_iso_8601: author_date_iso_8601,
      // author_date_iso_8601_strict: author_date_iso_8601_strict,
      // committer_name: committer_name,
      // committer_name_mailmap: committer_name_mailmap,
      // committer_email: committer_email,
      // committer_email_mailmap: committer_email_mailmap,
      // committer_date: committer_date,
      // committer_date_RFC2822: committer_date_RFC2822,
      // committer_date_relative: committer_date_relative,
      // committer_date_unix_timestamp: committer_date_unix_timestamp,
      // committer_date_iso_8601: committer_date_iso_8601,
      // committer_date_iso_8601_strict: committer_date_iso_8601_strict,
      // ref_names: ref_names,
      // ref_names_no_wrapping: ref_names_no_wrapping,
      // encoding: encoding,
      subject: subject,
      subject_sanitized: subject_sanitized,
      // commit_notes: commit_notes,
      stats: stats,
      time_hour: time_hour,
      time_minutes: time_minutes,
      time_seconds: time_seconds,
      time_gmt: time_gmt,
      date_day_week: date_day_week,
      date_month_day: date_month_day,
      date_month_name: date_month_name,
      date_month_number: date_month_number,
      date_year: date_year,
      date_iso_8601: date_iso_8601,
      files_changed: files_changed,
      insertions: insertions,
      deletions: deletions,
      impact: impact
  };
  this.push(obj);
  done();
};

// initialise stream
stream
.pipe(parser)
.pipe(jsonToStrings)
.pipe(output);
<commit_msg>:shower: Simplify JSON format<commit_after>var fs = require('fs'),
    path = require('path'),
    chalk = require('chalk'),
    byline = require('byline'),
    Transform = require('stream').Transform,
    JSONStream = require('JSONStream'),
    output_file_temp = '_tmp/gitlogg.tmp',
    output_file = '_output/gitlogg.json';

console.log(chalk.yellow('\n Parsing JSON output...\n'));

// initialise timer
console.time(chalk.green(' JSON output parsed in'));

// create the streams
var stream = fs.createReadStream(output_file_temp, 'utf8');
var output = fs.createWriteStream(output_file, 'utf8');
// handle errors
stream.on('error', function() {
  console.log(chalk.red(' Could not read from ' + output_file_temp));
});
output.on('error', function() {
  console.log(chalk.red(' Something went wrong, ' + output_file + ' could not be written / saved'));
});
// handle completion callback
output.on('finish', function() {
  console.timeEnd(chalk.green(' JSON output parsed in'));
  console.log(chalk.green(' The file ' + chalk.blue(output_file) + ' was saved. ' + chalk.yellow('Done! ✨\n')));
});

// stream the stream line by line
stream = byline.createStream(stream);
// create a transform stream
var parser = new Transform({ objectMode: true });
// use a JSONStream: JSONStream.stringify(open, sep, close)
var jsonToStrings = JSONStream.stringify('[\n  ', ',\n  ','\n]\n');

// massage the stats
var changes = function(data, index) {
  var v = data.split(',')[index] || 0;
  var w = 0;
  if (v !== 0) {
    var w = v.split(' ')[1]; // the number of changes is second on the array
  }
  return parseInt(w);
};

// decode UTF-8-ized Latin-1/ISO-8859-1 to UTF-8
var decode = function(str) {
  var s;
  try {
    // if the string is UTF-8, this will work and not throw an error.
    s = decodeURIComponent(escape(str));
  } catch(e) {
    // if it isn't, an error will be thrown, and we can asume that we have an ISO string.
    s = str;
  }
  return s;
};

// replace double quotes with single ones
var unquote = function(str) {
  if (str === undefined) {
    return '';
  } else if (str != '') {
    return str.replace(/"/g, "'");
  } else {
    return str;
  }
};

// slice the string as long as it's not empty
var sliceit = function(str) {
  if (str === undefined) {
    return '';
  } else if (str != '') {
    return str.slice(1);
  } else {
    return str;
  }
}

// do the transformations, through the transform stream
parser._transform = function(data, encoding, done) {
  var separator = /\\t/;
  var dataDecoded = decode(data);
  var c = dataDecoded.trim().split(separator);
  // console.log(c);
  // vars based on sequential values ( sanitise " to ' on fields that accept user input )
  var repository =                     c[3],                    // color-consolidator
      commit_nr =                      parseInt(c[0], 10),      // 3
      commit_hash =                    c[5],                    // 5109ad5a394a4873290ff7f7a38b7ca2e1b3b8e1
      commit_hash_abbreviated =        c[7],                    // 5109ad5
      tree_hash =                      c[9],                    // a1606ea8d6e24e1c832b52cb9c04ae1df2242ed4
      tree_hash_abbreviated =          c[11],                   // a1606ea
      parent_hashes =                  c[13],                   // 7082fa621bf93503fe173d06ada3c6111054a62b
      parent_hashes_abbreviated =      c[15],                   // 7082fa6
      author_name =                    unquote(c[17]),          // Wallace Sidhrée
      author_name_mailmap =            unquote(c[19]),          // Wallace Sidhrée
      author_email =                   c[21],                   // i@dreamyguy.com
      author_email_mailmap =           c[23],                   // i@dreamyguy.com
      author_date =                    c[25],                   // Fri Jan 3 14:16:56 2014 +0100
      author_date_RFC2822 =            c[27],                   // Fri, 3 Jan 2014 14:16:56 +0100
      author_date_relative =           c[29],                   // 2 years, 5 months ago
      author_date_unix_timestamp =     c[31],                   // 1388755016
      author_date_iso_8601 =           c[33],                   // 2014-01-03 14:16:56 +0100
      author_date_iso_8601_strict =    c[35],                   // 2014-01-03T14:16:56+01:00
      committer_name =                 unquote(c[37]),          // Wallace Sidhrée
      committer_name_mailmap =         unquote(c[39]),          // Wallace Sidhrée
      committer_email =                c[41],                   // i@dreamyguy.com
      committer_email_mailmap =        c[43],                   // i@dreamyguy.com
      committer_date =                 c[45],                   // Fri Jan 3 14:16:56 2014 +0100
      committer_date_RFC2822 =         c[47],                   // Fri, 3 Jan 2014 14:16:56 +0100
      committer_date_relative =        c[49],                   // 2 years, 5 months ago
      committer_date_unix_timestamp =  c[51],                   // 1388755016
      committer_date_iso_8601 =        c[53],                   // 2014-01-03 14:16:56 +0100
      committer_date_iso_8601_strict = c[55],                   // 2014-01-03T14:16:56+01:00
      ref_names =                      unquote(c[57]),          // ""
      ref_names_no_wrapping =          unquote(c[59]),          // ""
      encoding =                       c[61],                   // ""
      subject =                        unquote(c[63]),          // Upgrade FontAwesome from 3.2.1 to 4.0.3"
      subject_sanitized =              c[65],                   // Upgrade-FontAwesome-from-3.2.1-to-4.0.3"
      commit_notes =                   unquote(c[67]),          // ""
      stats =                          sliceit(c[69]);          // ` 9 files changed, 507 insertions(+), 2102 deletions(-)`
  // vars that require manipulation
  var time_array =                     author_date.split(' '),                  // Fri Jan 3 14:16:56 2014 +0100 => [Fri, Jan, 3, 14:16:56, 2014, +0100]
      time_array_clock =               time_array[3].split(':'),                // 14:16:56 => [14, 16, 56]
      time_hour =                      parseInt(time_array_clock[0], 10),       // [14, 16, 56] => 14
      time_minutes =                   parseInt(time_array_clock[1], 10),       // [14, 16, 56] => 16
      time_seconds =                   parseInt(time_array_clock[2], 10),       // [14, 16, 56] => 56
      time_gmt =                       time_array[5],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => +0100
      date_array =                     author_date_iso_8601.split(' ')[0],      // 2014-01-03 14:16:56 +0100 => 2014-01-03
      date_day_week =                  time_array[0],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => Fri
      date_iso_8601 =                  date_array,                              // 2014-01-03
      date_month_day =                 parseInt(date_array.split('-')[2], 10),  // 2014-01-03 => [2014, 01, 03] => 03
      date_month_name =                time_array[1],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => Jan
      date_month_number =              parseInt(date_array.split('-')[1], 10),  // 2014-01-03 => [2014, 01, 03] => 01
      date_year =                      time_array[4],                           // [Fri, Jan, 3, 14:16:56, 2014, +0100] => 2014
      files_changed =                  changes(stats, 0),                       // ` 9 files changed, 507 insertions(+), 2102 deletions(-)` => 9
      insertions =                     changes(stats, 1),                       // ` 9 files changed, 507 insertions(+), 2102 deletions(-)` => 507
      deletions =                      changes(stats, 2),                       // ` 9 files changed, 507 insertions(+), 2102 deletions(-)` => 2102
      impact =                         (insertions - deletions);                // 507 - 2102 => -1595
  // create the object
  var obj = {
      repository: repository,
      commit_nr: commit_nr,
      commit_hash: commit_hash,
      // commit_hash_abbreviated: commit_hash_abbreviated,
      // tree_hash: tree_hash,
      // tree_hash_abbreviated: tree_hash_abbreviated,
      // parent_hashes: parent_hashes,
      // parent_hashes_abbreviated: parent_hashes_abbreviated,
      author_name: author_name,
      // author_name_mailmap: author_name_mailmap,
      author_email: author_email,
      // author_email_mailmap: author_email_mailmap,
      author_date: author_date,
      // author_date_RFC2822: author_date_RFC2822,
      author_date_relative: author_date_relative,
      author_date_unix_timestamp: author_date_unix_timestamp,
      author_date_iso_8601: author_date_iso_8601,
      // author_date_iso_8601_strict: author_date_iso_8601_strict,
      // committer_name: committer_name,
      // committer_name_mailmap: committer_name_mailmap,
      // committer_email: committer_email,
      // committer_email_mailmap: committer_email_mailmap,
      // committer_date: committer_date,
      // committer_date_RFC2822: committer_date_RFC2822,
      // committer_date_relative: committer_date_relative,
      // committer_date_unix_timestamp: committer_date_unix_timestamp,
      // committer_date_iso_8601: committer_date_iso_8601,
      // committer_date_iso_8601_strict: committer_date_iso_8601_strict,
      // ref_names: ref_names,
      // ref_names_no_wrapping: ref_names_no_wrapping,
      // encoding: encoding,
      subject: subject,
      subject_sanitized: subject_sanitized,
      // commit_notes: commit_notes,
      stats: stats,
      time_hour: time_hour,
      time_minutes: time_minutes,
      time_seconds: time_seconds,
      time_gmt: time_gmt,
      date_day_week: date_day_week,
      date_month_day: date_month_day,
      date_month_name: date_month_name,
      date_month_number: date_month_number,
      date_year: date_year,
      date_iso_8601: date_iso_8601,
      files_changed: files_changed,
      insertions: insertions,
      deletions: deletions,
      impact: impact
  };
  this.push(obj);
  done();
};

// initialise stream
stream
.pipe(parser)
.pipe(jsonToStrings)
.pipe(output);
<|endoftext|>


<commit_before>var frontend    = require('../controllers/frontend'),
    config      = require('../config'),
    express     = require('express'),
    utils       = require('../utils'),

    frontendRoutes;

frontendRoutes = function (middleware) {
    var router = express.Router(),
        subdir = config.paths.subdir,
        routeKeywords = config.routeKeywords;

    // ### Admin routes
    router.get(/^\/(logout|signout)\/$/, function redirect(req, res) {
        /*jslint unparam:true*/
        res.set({'Cache-Control': 'public, max-age=' + utils.ONE_YEAR_S});
        res.redirect(301, subdir + '/ghost/signout/');
    });
    router.get(/^\/signup\/$/, function redirect(req, res) {
        /*jslint unparam:true*/
        res.set({'Cache-Control': 'public, max-age=' + utils.ONE_YEAR_S});
        res.redirect(301, subdir + '/ghost/signup/');
    });

    // redirect to /ghost and let that do the authentication to prevent redirects to /ghost//admin etc.
    router.get(/^\/((ghost-admin|admin|wp-admin|dashboard|signin|login)\/?)$/, function (req, res) {
        /*jslint unparam:true*/
        res.redirect(subdir + '/ghost/');
    });

    // password-protected frontend route
    router.get('/' + routeKeywords.private + '/',
        middleware.isPrivateSessionAuth,
        frontend.private
    );
    router.post('/' + routeKeywords.private + '/',
        middleware.isPrivateSessionAuth,
        middleware.spamProtectedPrevention,
        middleware.authenticateProtection,
        frontend.private
    );

    // ### Frontend routes
    router.get('/rss/', frontend.rss);
    router.get('/rss/:page/', frontend.rss);
    router.get('/feed/', function redirect(req, res) {
        /*jshint unused:true*/
        res.set({'Cache-Control': 'public, max-age=' + utils.ONE_YEAR_S});
        res.redirect(301, subdir + '/rss/');
    });

    // Tags
    router.get('/' + routeKeywords.tag + '/:slug/rss/', frontend.rss);
    router.get('/' + routeKeywords.tag + '/:slug/rss/:page/', frontend.rss);
    router.get('/' + routeKeywords.tag + '/:slug/' + routeKeywords.page + '/:page/', frontend.tag);
    router.get('/' + routeKeywords.tag + '/:slug/', frontend.tag);

    // Authors
    router.get('/' + routeKeywords.author + '/:slug/rss/', frontend.rss);
    router.get('/' + routeKeywords.author + '/:slug/rss/:page/', frontend.rss);
    router.get('/' + routeKeywords.author + '/:slug/' + routeKeywords.page + '/:page/', frontend.author);
    router.get('/' + routeKeywords.author + '/:slug/', frontend.author);

    // Post Live Preview
    router.get('/' + routeKeywords.preview + '/:uuid', frontend.preview);

    // Default
    router.get('/' + routeKeywords.page + '/:page/', frontend.homepage);
    router.get('/', frontend.homepage);
    router.get('*', frontend.single);

    // custom code for adding a contact form with nodemailer
    // if you want to pass arguments to the function
    // it must be router.get instead of tarikk’s router.post

    // router.get('/mail/', middleware.authenticateClient, frontend.submitContactForm);
    // this is an experiment
    router.get('/mail/', function (req, res) {
        res.setHeader('Access-Control-Allow-Origin', 'http://petersekan.de');
        // res.setHeader('Access-Control-Allow-Methods', 'GET');
        frontend.submitContactForm

    });
    // end of custom code

    return router;
};

module.exports = frontendRoutes;
<commit_msg>edit form mailer<commit_after>var frontend    = require('../controllers/frontend'),
    config      = require('../config'),
    express     = require('express'),
    utils       = require('../utils'),

    frontendRoutes;

frontendRoutes = function (middleware) {
    var router = express.Router(),
        subdir = config.paths.subdir,
        routeKeywords = config.routeKeywords;

    // ### Admin routes
    router.get(/^\/(logout|signout)\/$/, function redirect(req, res) {
        /*jslint unparam:true*/
        res.set({'Cache-Control': 'public, max-age=' + utils.ONE_YEAR_S});
        res.redirect(301, subdir + '/ghost/signout/');
    });
    router.get(/^\/signup\/$/, function redirect(req, res) {
        /*jslint unparam:true*/
        res.set({'Cache-Control': 'public, max-age=' + utils.ONE_YEAR_S});
        res.redirect(301, subdir + '/ghost/signup/');
    });

    // redirect to /ghost and let that do the authentication to prevent redirects to /ghost//admin etc.
    router.get(/^\/((ghost-admin|admin|wp-admin|dashboard|signin|login)\/?)$/, function (req, res) {
        /*jslint unparam:true*/
        res.redirect(subdir + '/ghost/');
    });

    // password-protected frontend route
    router.get('/' + routeKeywords.private + '/',
        middleware.isPrivateSessionAuth,
        frontend.private
    );
    router.post('/' + routeKeywords.private + '/',
        middleware.isPrivateSessionAuth,
        middleware.spamProtectedPrevention,
        middleware.authenticateProtection,
        frontend.private
    );

    // ### Frontend routes
    router.get('/rss/', frontend.rss);
    router.get('/rss/:page/', frontend.rss);
    router.get('/feed/', function redirect(req, res) {
        /*jshint unused:true*/
        res.set({'Cache-Control': 'public, max-age=' + utils.ONE_YEAR_S});
        res.redirect(301, subdir + '/rss/');
    });

    // Tags
    router.get('/' + routeKeywords.tag + '/:slug/rss/', frontend.rss);
    router.get('/' + routeKeywords.tag + '/:slug/rss/:page/', frontend.rss);
    router.get('/' + routeKeywords.tag + '/:slug/' + routeKeywords.page + '/:page/', frontend.tag);
    router.get('/' + routeKeywords.tag + '/:slug/', frontend.tag);

    // Authors
    router.get('/' + routeKeywords.author + '/:slug/rss/', frontend.rss);
    router.get('/' + routeKeywords.author + '/:slug/rss/:page/', frontend.rss);
    router.get('/' + routeKeywords.author + '/:slug/' + routeKeywords.page + '/:page/', frontend.author);
    router.get('/' + routeKeywords.author + '/:slug/', frontend.author);

    // Post Live Preview
    router.get('/' + routeKeywords.preview + '/:uuid', frontend.preview);

    // Default
    router.get('/' + routeKeywords.page + '/:page/', frontend.homepage);
    router.get('/', frontend.homepage);
    router.get('*', frontend.single);

    // custom code for adding a contact form with nodemailer
    // if you want to pass arguments to the function
    // it must be router.get instead of tarikk’s router.post

    // router.get('/mail/', middleware.authenticateClient, frontend.submitContactForm);
    // this is an experiment
    router.get('/mail/', function (req, res) {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET');

        frontend.submitContactForm

    });
    // end of custom code

    return router;
};

module.exports = frontendRoutes;
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */
/*jshint esnext:true, es5:true, curly:false */
/*global FBTrace:true, Components:true, Proxy:true, define:true */

// A note on terminology: here a "closure"/"environment" is generally thought
// of as a container of "scopes".

define([
    "firebug/firebug",
    "firebug/lib/wrapper"
],
function(Firebug, Wrapper) {
"use strict";

// ********************************************************************************************* //
// Constants

const Cu = Components.utils;

const ScopeProxy = function() {};
const OptimizedAway = Object.create(null);
Object.freeze(OptimizedAway);

// ********************************************************************************************* //

var ClosureInspector =
{
    hasInit: false,
    Debugger: null,

    getInactiveDebuggerForContext: function(context)
    {
        if (context.inactiveDebugger)
            return context.inactiveDebugger;

        if (!this.hasInit)
        {
            this.hasInit = true;
            try
            {
                Cu.import("resource://gre/modules/jsdebugger.jsm");
                window.addDebuggerToGlobal(window);
                this.Debugger = window.Debugger;
            }
            catch (exc)
            {
                if (FBTrace.DBG_COMMANDLINE)
                    FBTrace.sysout("ClosureInspector; Debugger not found", exc);
            }
        }
        if (!this.Debugger)
            return;

        var dbg = new this.Debugger();
        dbg.enabled = false;
        context.inactiveDebugger = dbg;
        return dbg;
    },

    getVariableOrOptimizedAway: function(scope, name)
    {
        try
        {
            var ret = scope.getVariable(name);
            if (ret !== undefined)
                return ret;

            // With scopes are based on real objects - don't try anything fancy.
            // (Object properties probably don't get optimized away anyway, and
            // "with" tends to inhibit optimizations).
            if (scope.type === "with")
                return undefined;

            // The variable is either optimized away or actually set to undefined.
            // Optimized-away ones are apparantly not settable, so try to detect
            // them by that (it seems rather safe).
            scope.setVariable(name, 0);
            if (scope.getVariable(name) === undefined)
                return OptimizedAway;
            scope.setVariable(name, undefined);
            return undefined;
        }
        catch (exc)
        {
            // E.g. optimized-away "arguments" can throw "Debugger scope is not live".
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; getVariableOrOptimizedAway caught an exception", exc);
            return OptimizedAway;
        }
    },

    isOptimizedAway: function(obj)
    {
        return obj === OptimizedAway;
    },

    isSimple: function(dobj)
    {
        return (typeof dobj !== "object" || dobj === OptimizedAway);
    },

    unwrap: function(global, dglobal, obj)
    {
        dglobal.defineProperty("_firebugUnwrappedDebuggerObject", {
            value: obj,
            writable: true,
            configurable: true
        });
        return global._firebugUnwrappedDebuggerObject;
    },

    isScopeInteresting: function(scope)
    {
        return !!scope.parent;
    },

    getFunctionFromObject: function(obj)
    {
        var first = true;
        while (obj)
        {
            var names = obj.getOwnPropertyNames(), pd;

            // "constructor" is boring, use it last
            var ind = names.indexOf("constructor");
            if (ind !== -1)
            {
                names.splice(ind, 1);
                names.push("constructor");
            }

            // XXX keep a Map of scopes, and take the highest container of the first one or the (first) deepest one or something
            for (var i = 0; i < names.length; ++i)
            {
                // We assume that the first own property, or the first
                // enumerable property of the prototype (or "constructor"),
                // that is a function with some scope (i.e., it is interpreted,
                // JSScript-backed, and without optimized-away scope) shares
                // this scope with 'obj'.

                var name = names[i];
                try
                {
                    pd = obj.getOwnPropertyDescriptor(name);
                }
                catch (e)
                {
                    // getOwnPropertyDescriptor sometimes fails with
                    // "Illegal operation on WrappedNative prototype object",
                    // for instance on [window].proto.gopd("localStorage").
                    continue;
                }
                if (!pd || (!first && !pd.enumerable && name !== "constructor"))
                    continue;

                var toTest = [pd.get, pd.set, pd.value];
                for (var j = 0; j < toTest.length; ++j)
                {
                    var f = toTest[j];
                    if (f && f.environment && this.isScopeInteresting(f.environment))
                        return f;
                }
            }

            if (!first)
                break;
            first = false;
            obj = obj.proto;
        }

        // None found. :(
        return undefined;
    },

    // Within the security context of the (wrapped) window 'win', find a relevant
    // closure for the content object 'obj' (may be from another frame).
    // Throws exceptions on error.
    getEnvironmentForObject: function(win, obj, context)
    {
        var dbg = this.getInactiveDebuggerForContext(context);
        if (!dbg)
            throw new Error("debugger not available");

        if (!obj || !(typeof obj === "object" || typeof obj === "function"))
            throw new TypeError("can't get scope of non-object");

        var objGlobal = Cu.getGlobalForObject(obj);
        if (win !== objGlobal && !(win.document && objGlobal.document &&
            win.document.nodePrincipal.subsumes(objGlobal.document.nodePrincipal)))
        {
            throw new Error("permission denied to access cross origin scope");
        }

        var dglobal = dbg.addDebuggee(objGlobal);

        var dobj = dglobal.makeDebuggeeValue(obj);

        if (typeof obj === "object")
            dobj = this.getFunctionFromObject(dobj);

        if (!dobj || !dobj.environment || !this.isScopeInteresting(dobj.environment))
            throw new Error("missing closure");

        return dobj.environment;
    },

    getClosureVariablesList: function(obj, context)
    {
        var ret = [];

        // Avoid 'window' and 'document' getting associated with closures.
        var win = context.baseWindow || context.window;
        if (obj === win || obj === win.document)
            return ret;

        try
        {
            var env = this.getEnvironmentForObject(win, obj, context);
            for (var scope = env; scope; scope = scope.parent)
            {
                if (scope.type === "with" && scope.getVariable("profileEnd"))
                {
                    // Almost certainly the with(_FirebugCommandLine) block,
                    // which is at the top of the scope chain on objects
                    // defined through the console. Hide it for a nicer display.
                    break;
                }
                if (!this.isScopeInteresting(scope))
                    break;

                ret.push.apply(ret, scope.names());
            }
        }
        catch (exc)
        {
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; getClosureVariablesList failed", exc);
        }
        return ret;
    },

    getClosureWrapper: function(obj, win, context)
    {
        function throwUserError(exc)
        {
            // Throw an exception into user-land, where we hope it lands
            // safely in commandLineExposed.js for internals to be hidden.
            exc._dropFrames = true;
            throw exc;
        }

        var env, dbg, dglobal;
        try
        {
            env = this.getEnvironmentForObject(win, obj, context);

            dbg = this.getInactiveDebuggerForContext(context);
            dglobal = dbg.addDebuggee(win);
        }
        catch (exc)
        {
            throwUserError(exc);
        }

        // Return a wrapper for its scoped variables.
        var self = this;
        var handler = {};
        handler.getOwnPropertyDescriptor = function(name)
        {
            if (name === "__exposedProps__")
            {
                // Expose mostly everything, rw, through another proxy.
                return {
                    value: Proxy.create({
                        getPropertyDescriptor: function(name)
                        {
                            if (name === "__exposedProps__" || name === "__proto__")
                                return;
                            return {value: "rw", enumerable: true};
                        }
                    })
                };
            }

            return {
                get: function()
                {
                    try
                    {
                        var scope = env.find(name);
                        if (!scope)
                            return undefined;
                        var dval = self.getVariableOrOptimizedAway(scope, name);
                        if (self.isSimple(dval))
                            return dval;
                        var uwWin = Wrapper.getContentView(win);
                        return self.unwrap(uwWin, dglobal, dval);
                    }
                    catch (exc)
                    {
                        if (FBTrace.DBG_COMMANDLINE)
                            FBTrace.sysout("ClosureInspector; failed to return value from getter", exc);
                        return undefined;
                    }
                },

                set: function(value)
                {
                    var dvalue = dglobal.makeDebuggeeValue(value);
                    var scope = env.find(name);
                    if (!scope)
                        throwUserError(new Error("can't create new closure variable"));
                    if (self.getVariableOrOptimizedAway(scope, name) === OptimizedAway)
                        throwUserError(new Error("can't set optimized-away closure variable"));
                    scope.setVariable(name, dvalue);
                }
            };
        };
        handler.getPropertyDescriptor = handler.getOwnPropertyDescriptor;
        handler.delete = function(name)
        {
            throwUserError(new Error("can't delete closure variable"));
        };
        // Other traps are syntactically inaccessible, so we don't need to implement them.
        return Proxy.create(handler);
    },

    getScopeWrapper: function(obj, win, context, isScope)
    {
        var scope;
        try
        {
            if (isScope)
                scope = Object.getPrototypeOf(obj).scope.parent;
            else
                scope = this.getEnvironmentForObject(win, obj, context);
            if (!scope || !this.isScopeInteresting(scope))
                return;
        }
        catch (exc)
        {
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; getScopeWrapper failed", exc);
            return;
        }

        var dbg = this.getInactiveDebuggerForContext(context);
        var dwin = dbg.addDebuggee(win);

        var scopeDataHolder = Object.create(ScopeProxy.prototype);
        scopeDataHolder.scope = scope;

        var self = this;
        var names, namesSet;
        var lazyCreateNames = function()
        {
            lazyCreateNames = function() {};
            names = scope.names();

            // "arguments" is almost always present and optimized away, so hide it
            // for a nicer display.
            var ind = names.indexOf("arguments");
            if (ind !== -1 && self.getVariableOrOptimizedAway(scope, "arguments") === OptimizedAway)
                names.splice(ind, 1);

            namesSet = new Set();
            for (var i = 0; i < names.length; ++i)
                namesSet.add(names[i]);
        };

        return Proxy.create({
            desc: function(name)
            {
                if (!this.has(name))
                    return;
                var dval = self.getVariableOrOptimizedAway(scope, name);
                return {
                    get: function() {
                        if (self.isSimple(dval))
                            return dval;
                        var uwWin = Wrapper.getContentView(win);
                        return self.unwrap(uwWin, dwin, dval);
                    },
                    set: (dval === OptimizedAway ? undefined : function(value) {
                        dval = dwin.makeDebuggeeValue(value);
                        scope.setVariable(name, dval);
                    }),
                    enumerable: true,
                    configurable: false
                };
            },
            has: function(name)
            {
                lazyCreateNames();
                return namesSet.has(name);
            },
            hasOwn: function(name) { return this.has(name); },
            getOwnPropertyDescriptor: function(name) { return this.desc(name); },
            getPropertyDescriptor: function(name) { return this.desc(name); },
            keys: function()
            {
                lazyCreateNames();
                return names;
            },
            enumerate: function() { return this.keys(); },
            getOwnPropertyNames: function() { return this.keys(); },
            getPropertyNames: function() { return this.keys(); }
        }, scopeDataHolder);
    },

    isScopeWrapper: function(obj)
    {
        return obj instanceof ScopeProxy;
    },

    getScopeFromWrapper: function(obj)
    {
        return Object.getPrototypeOf(obj).scope;
    },

    extendLanguageSyntax: function(expr, win, context)
    {
        // Temporary FireClosure compatibility.
        if (Firebug.JSAutoCompleter.transformScopeExpr)
            return expr;

        // Note: this is also hard-coded elsewhere.
        var fname = "__fb_scopedVars";

        var newExpr = Firebug.JSAutoCompleter.transformScopeOperator(expr, fname);
        if (expr === newExpr)
            return expr;

        if (FBTrace.DBG_COMMANDLINE)
        {
            FBTrace.sysout("ClosureInspector; transforming expression: `" +
                    expr + "` -> `" + newExpr + "`");
        }

        // Stick the helper function for .%-expressions on the window object.
        // This really belongs on the command line object, but that doesn't
        // work when stopped in the debugger (issue 5321, which depends on
        // integrating JSD2) and we really need this to work there.
        // To avoid leaking capabilities into arbitrary web pages, this is
        // only injected when needed.
        try
        {
            var self = this;
            Object.defineProperty(Wrapper.getContentView(win), fname, {
                value: function(obj)
                {
                    return self.getClosureWrapper(obj, win, context);
                },
                writable: true,
                configurable: true
            });
        }
        catch (exc)
        {
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; failed to inject " + fname, exc);
        }

        return newExpr;
    }
};

Firebug.ClosureInspector = ClosureInspector;
return ClosureInspector;

// ********************************************************************************************* //
});
<commit_msg>Comment fixes<commit_after>/* See license.txt for terms of usage */
/*jshint esnext:true, es5:true, curly:false */
/*global FBTrace:true, Components:true, Proxy:true, define:true */

// A note on terminology: here a "closure"/"environment" is generally thought
// of as a container of "scopes".

define([
    "firebug/firebug",
    "firebug/lib/wrapper"
],
function(Firebug, Wrapper) {
"use strict";

// ********************************************************************************************* //
// Constants

const Cu = Components.utils;

const ScopeProxy = function() {};
const OptimizedAway = Object.create(null);
Object.freeze(OptimizedAway);

// ********************************************************************************************* //

var ClosureInspector =
{
    hasInit: false,
    Debugger: null,

    getInactiveDebuggerForContext: function(context)
    {
        if (context.inactiveDebugger)
            return context.inactiveDebugger;

        if (!this.hasInit)
        {
            this.hasInit = true;
            try
            {
                Cu.import("resource://gre/modules/jsdebugger.jsm");
                window.addDebuggerToGlobal(window);
                this.Debugger = window.Debugger;
            }
            catch (exc)
            {
                if (FBTrace.DBG_COMMANDLINE)
                    FBTrace.sysout("ClosureInspector; Debugger not found", exc);
            }
        }
        if (!this.Debugger)
            return;

        var dbg = new this.Debugger();
        dbg.enabled = false;
        context.inactiveDebugger = dbg;
        return dbg;
    },

    getVariableOrOptimizedAway: function(scope, name)
    {
        try
        {
            var ret = scope.getVariable(name);
            if (ret !== undefined)
                return ret;

            // With scopes are based on real objects - don't try anything fancy.
            // (Object properties probably don't get optimized away anyway, and
            // "with" tends to inhibit optimizations).
            if (scope.type === "with")
                return undefined;

            // The variable is either optimized away or actually set to undefined.
            // Optimized-away ones are apparently not settable, so try to detect
            // them by that (it seems rather safe).
            scope.setVariable(name, 0);
            if (scope.getVariable(name) === undefined)
                return OptimizedAway;
            scope.setVariable(name, undefined);
            return undefined;
        }
        catch (exc)
        {
            // E.g. optimized-away "arguments" can throw "Debugger scope is not live".
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; getVariableOrOptimizedAway caught an exception", exc);
            return OptimizedAway;
        }
    },

    isOptimizedAway: function(obj)
    {
        return obj === OptimizedAway;
    },

    isSimple: function(dobj)
    {
        return (typeof dobj !== "object" || dobj === OptimizedAway);
    },

    unwrap: function(global, dglobal, obj)
    {
        dglobal.defineProperty("_firebugUnwrappedDebuggerObject", {
            value: obj,
            writable: true,
            configurable: true
        });
        return global._firebugUnwrappedDebuggerObject;
    },

    isScopeInteresting: function(scope)
    {
        return !!scope.parent;
    },

    getFunctionFromObject: function(obj)
    {
        var first = true;
        while (obj)
        {
            var names = obj.getOwnPropertyNames(), pd;

            // "constructor" is boring, use it last
            var ind = names.indexOf("constructor");
            if (ind !== -1)
            {
                names.splice(ind, 1);
                names.push("constructor");
            }

            for (var i = 0; i < names.length; ++i)
            {
                // We assume that the first own property, or the first
                // enumerable property of the prototype (or "constructor"),
                // that is a function with some scope (i.e., it is interpreted,
                // JSScript-backed, and without optimized-away scope) shares
                // this scope with 'obj'.
                // (Since, in the current implementation, Firefox seems to give
                // all functions in a particular scope (except self-contained
                // ones) the same environment, the first is as good as any,
                // and it's probably near the definition of 'obj').

                var name = names[i];
                try
                {
                    pd = obj.getOwnPropertyDescriptor(name);
                }
                catch (e)
                {
                    // getOwnPropertyDescriptor sometimes fails with
                    // "Illegal operation on WrappedNative prototype object",
                    // for instance on [window].proto.gopd("localStorage").
                    continue;
                }
                if (!pd || (!first && !pd.enumerable && name !== "constructor"))
                    continue;

                var toTest = [pd.get, pd.set, pd.value];
                for (var j = 0; j < toTest.length; ++j)
                {
                    var f = toTest[j];
                    if (f && f.environment && this.isScopeInteresting(f.environment))
                        return f;
                }
            }

            if (!first)
                break;
            first = false;
            obj = obj.proto;
        }

        // None found. :(
        return undefined;
    },

    // Within the security context of the (wrapped) window 'win', find a relevant
    // closure for the content object 'obj' (may be from another frame).
    // Throws exceptions on error.
    getEnvironmentForObject: function(win, obj, context)
    {
        var dbg = this.getInactiveDebuggerForContext(context);
        if (!dbg)
            throw new Error("debugger not available");

        if (!obj || !(typeof obj === "object" || typeof obj === "function"))
            throw new TypeError("can't get scope of non-object");

        var objGlobal = Cu.getGlobalForObject(obj);
        if (win !== objGlobal && !(win.document && objGlobal.document &&
            win.document.nodePrincipal.subsumes(objGlobal.document.nodePrincipal)))
        {
            throw new Error("permission denied to access cross origin scope");
        }

        var dglobal = dbg.addDebuggee(objGlobal);

        var dobj = dglobal.makeDebuggeeValue(obj);

        if (typeof obj === "object")
            dobj = this.getFunctionFromObject(dobj);

        if (!dobj || !dobj.environment || !this.isScopeInteresting(dobj.environment))
            throw new Error("missing closure");

        return dobj.environment;
    },

    getClosureVariablesList: function(obj, context)
    {
        var ret = [];

        // Avoid 'window' and 'document' getting associated with closures.
        var win = context.baseWindow || context.window;
        if (obj === win || obj === win.document)
            return ret;

        try
        {
            var env = this.getEnvironmentForObject(win, obj, context);
            for (var scope = env; scope; scope = scope.parent)
            {
                if (scope.type === "with" && scope.getVariable("profileEnd"))
                {
                    // Almost certainly the with(_FirebugCommandLine) block,
                    // which is at the top of the scope chain on objects
                    // defined through the console. Hide it for a nicer display.
                    break;
                }
                if (!this.isScopeInteresting(scope))
                    break;

                ret.push.apply(ret, scope.names());
            }
        }
        catch (exc)
        {
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; getClosureVariablesList failed", exc);
        }
        return ret;
    },

    getClosureWrapper: function(obj, win, context)
    {
        function throwUserError(exc)
        {
            // Throw an exception into user-land, where we hope it lands
            // safely in commandLineExposed.js for internals to be hidden.
            exc._dropFrames = true;
            throw exc;
        }

        var env, dbg, dglobal;
        try
        {
            env = this.getEnvironmentForObject(win, obj, context);

            dbg = this.getInactiveDebuggerForContext(context);
            dglobal = dbg.addDebuggee(win);
        }
        catch (exc)
        {
            throwUserError(exc);
        }

        // Return a wrapper for its scoped variables.
        var self = this;
        var handler = {};
        handler.getOwnPropertyDescriptor = function(name)
        {
            if (name === "__exposedProps__")
            {
                // Expose mostly everything, rw, through another proxy.
                return {
                    value: Proxy.create({
                        getPropertyDescriptor: function(name)
                        {
                            if (name === "__exposedProps__" || name === "__proto__")
                                return;
                            return {value: "rw", enumerable: true};
                        }
                    })
                };
            }

            return {
                get: function()
                {
                    try
                    {
                        var scope = env.find(name);
                        if (!scope)
                            return undefined;
                        var dval = self.getVariableOrOptimizedAway(scope, name);
                        if (self.isSimple(dval))
                            return dval;
                        var uwWin = Wrapper.getContentView(win);
                        return self.unwrap(uwWin, dglobal, dval);
                    }
                    catch (exc)
                    {
                        if (FBTrace.DBG_COMMANDLINE)
                            FBTrace.sysout("ClosureInspector; failed to return value from getter", exc);
                        return undefined;
                    }
                },

                set: function(value)
                {
                    var dvalue = dglobal.makeDebuggeeValue(value);
                    var scope = env.find(name);
                    if (!scope)
                        throwUserError(new Error("can't create new closure variable"));
                    if (self.getVariableOrOptimizedAway(scope, name) === OptimizedAway)
                        throwUserError(new Error("can't set optimized-away closure variable"));
                    scope.setVariable(name, dvalue);
                }
            };
        };
        handler.getPropertyDescriptor = handler.getOwnPropertyDescriptor;
        handler.delete = function(name)
        {
            throwUserError(new Error("can't delete closure variable"));
        };
        // Other traps are syntactically inaccessible, so we don't need to implement them.
        return Proxy.create(handler);
    },

    getScopeWrapper: function(obj, win, context, isScope)
    {
        var scope;
        try
        {
            if (isScope)
                scope = Object.getPrototypeOf(obj).scope.parent;
            else
                scope = this.getEnvironmentForObject(win, obj, context);
            if (!scope || !this.isScopeInteresting(scope))
                return;
        }
        catch (exc)
        {
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; getScopeWrapper failed", exc);
            return;
        }

        var dbg = this.getInactiveDebuggerForContext(context);
        var dwin = dbg.addDebuggee(win);

        var scopeDataHolder = Object.create(ScopeProxy.prototype);
        scopeDataHolder.scope = scope;

        var self = this;
        var names, namesSet;
        var lazyCreateNames = function()
        {
            lazyCreateNames = function() {};
            names = scope.names();

            // "arguments" is almost always present and optimized away, so hide it
            // for a nicer display.
            var ind = names.indexOf("arguments");
            if (ind !== -1 && self.getVariableOrOptimizedAway(scope, "arguments") === OptimizedAway)
                names.splice(ind, 1);

            namesSet = new Set();
            for (var i = 0; i < names.length; ++i)
                namesSet.add(names[i]);
        };

        return Proxy.create({
            desc: function(name)
            {
                if (!this.has(name))
                    return;
                var dval = self.getVariableOrOptimizedAway(scope, name);
                return {
                    get: function() {
                        if (self.isSimple(dval))
                            return dval;
                        var uwWin = Wrapper.getContentView(win);
                        return self.unwrap(uwWin, dwin, dval);
                    },
                    set: (dval === OptimizedAway ? undefined : function(value) {
                        dval = dwin.makeDebuggeeValue(value);
                        scope.setVariable(name, dval);
                    }),
                    enumerable: true,
                    configurable: false
                };
            },
            has: function(name)
            {
                lazyCreateNames();
                return namesSet.has(name);
            },
            hasOwn: function(name) { return this.has(name); },
            getOwnPropertyDescriptor: function(name) { return this.desc(name); },
            getPropertyDescriptor: function(name) { return this.desc(name); },
            keys: function()
            {
                lazyCreateNames();
                return names;
            },
            enumerate: function() { return this.keys(); },
            getOwnPropertyNames: function() { return this.keys(); },
            getPropertyNames: function() { return this.keys(); }
        }, scopeDataHolder);
    },

    isScopeWrapper: function(obj)
    {
        return obj instanceof ScopeProxy;
    },

    getScopeFromWrapper: function(obj)
    {
        return Object.getPrototypeOf(obj).scope;
    },

    extendLanguageSyntax: function(expr, win, context)
    {
        // Temporary FireClosure compatibility.
        if (Firebug.JSAutoCompleter.transformScopeExpr)
            return expr;

        // Note: this is also hard-coded elsewhere.
        var fname = "__fb_scopedVars";

        var newExpr = Firebug.JSAutoCompleter.transformScopeOperator(expr, fname);
        if (expr === newExpr)
            return expr;

        if (FBTrace.DBG_COMMANDLINE)
        {
            FBTrace.sysout("ClosureInspector; transforming expression: `" +
                    expr + "` -> `" + newExpr + "`");
        }

        // Stick the helper function for .%-expressions on the window object.
        // This really belongs on the command line object, but that doesn't
        // work when stopped in the debugger (issue 5321, which depends on
        // integrating JSD2) and we really need this to work there.
        // To avoid leaking capabilities into arbitrary web pages, this is
        // only injected when needed.
        try
        {
            var self = this;
            Object.defineProperty(Wrapper.getContentView(win), fname, {
                value: function(obj)
                {
                    return self.getClosureWrapper(obj, win, context);
                },
                writable: true,
                configurable: true
            });
        }
        catch (exc)
        {
            if (FBTrace.DBG_COMMANDLINE)
                FBTrace.sysout("ClosureInspector; failed to inject " + fname, exc);
        }

        return newExpr;
    }
};

Firebug.ClosureInspector = ClosureInspector;
return ClosureInspector;

// ********************************************************************************************* //
});
<|endoftext|>


<commit_before>// TODO LIST:
// 1. Replace main js object from ES Class
// 2. Replace forms and arrays for ES Map

var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
// -----------------------
// BuilderProvider
// -----------------------

import { Utils }         from './builder.classes';
import { Component }     from './builder.classes';
import { FormObject }    from './builder.classes';
import { Page }          from './builder.classes';
import { Tag }           from './builder.classes';

export function BuilderProvider() {

  // Constants
  const displayTypes = Object.freeze({
    SINGLE: 'SINGLE',
    WIZARD: 'WIZARD'
  });

  var $injector = null, $http = null, $log = null, $templateCache = null;
  this.components = {};
  this.forms = { 'default': [] }; // replace for map
  this.pages = [];
  this.tags = [];
  this.groups = [];
  this.dependencies = [];
  this.broadcastChannel = {
    selectPage: '$selectPage',
    selectInput: '$selectInput',
    updateInput: '$updateInput',
    saveInput: '$saveInput',
    changeWizardStep: '$changeWizardStep',
    changeFormInputEvent: '$changeFormInputEvent'
  };

  let display = displayTypes.SINGLE;
  let current = {
    formObject: null,
    formObjectScope: null,
    formObjectElement: null,
    formName: null,
    page: null,
    form: this.forms['default']
  }

  this.convertComponent = (name, component) => {
    let result = new Component(name, component);

    if (!result.template && !result.templateUrl)
      $log.error("The template is empty.");

    if (!result.popoverTemplate && !result.popoverTemplateUrl)
      $log.error("The popoverTemplate is empty.");

    return result;
  };

  this.convertFormObject = (name, formObject) => {
    formObject = formObject || {};
    let component = this.components[formObject.component];
    if (component == null) {
      throw "The component " + formObject.component + " was not registered.";
    }

    let result = new FormObject(name, formObject, component)
    return result;
  };

  this.reindexFormObject = (name) => {
    var formObjects, i, index, ref;
    formObjects = this.forms[name];
    for (index = i = 0, ref = formObjects.length; i < ref; index = i += 1) {
      formObjects[index].index = index;
    }
  };

  this.setupProviders = (injector) => {
    $injector = injector;
    $http = $injector.get('$http');
    $templateCache = $injector.get('$templateCache');
    $log = $injector.get('$log');
  };

  this.loadTemplate = (component) => {
    if (component.template == null) {
      $http.get(component.templateUrl, {
        cache: $templateCache
      }).success((template) => {
        component.template = template;
      });
    }
    if (component.popoverTemplate == null) {
      $http.get(component.popoverTemplateUrl, {
        cache: $templateCache
      }).success((template) => {
        component.popoverTemplate = template;
      });
    }
  };

  this.copyObjectToScope = (object, scope) => {
    // Copy object (ng-repeat="object in objects") to scope without `hashKey`.
    var key, value;
    for (key in object) {
      value = object[key];
      if (key !== '$$hashKey') {
        scope[key] = value;
      }
    }
  }

  this.registerComponent = (name, component) => {
    if (component == null)
      component = {};

    /*
    Register the component for form-builder.
    @param name: The component name.
    @param component: The component object.
        group: {string} The component group.
        label: {string} The label of the input.
        description: {string} The description of the input.
        placeholder: {string} The placeholder of the input.
        editable: {bool} Is the form object editable?
        required: {bool} Is the form object required?
        validation: {string} angular-validator. "/regex/" or "[rule1, rule2]". (default is RegExp(.*))
        validationOptions: {array} [{rule: angular-validator, label: 'option label'}] the options for the validation. (default is [])
        options: {array} The input options.
        multipeChoice: {bool} checkbox could use this to convert input (default is no)
        template: {string} html template
        templateUrl: {string} The url of the template.
        popoverTemplate: {string} html template
        popoverTemplateUrl: {string} The url of the popover template.
     */
    if (this.components[name] == null) {
      let newComponent = this.convertComponent(name, component);
      this.components[name] = newComponent;

      if ($injector != null)
        this.loadTemplate(newComponent);
      if (newComponent.group, indexOf.call(this.groups, newComponent.group) < 0)
        this.groups.push(newComponent.group);

    } else {
      // $log.info("The component " + name + " was registered.");
    }
  };

  this.addFormObject = (name, formObject) => {
    if (formObject == null)
        formObject = {};
    // insert the form object into the form at last.
    let base;
    if ((base = this.forms)[name] == null)
      base[name] = [];

    return this.insertFormObject(name, this.forms[name].length, formObject);
  };

  this.getCurrentFormObject = () => {
    return current.formObject;
  }

  this.selectCurrentFormObject = (formName, formObject, element, objectScope) => {
    current.formName = formName;
    current.form = this.forms[formName];
    current.formObject = angular.copy(formObject);
    current.formObjectScope = objectScope;

    if(current.formObjectElement)
      current.formObjectElement.removeClass('active');

    current.formObjectElement = element
    current.formObjectElement.addClass('active');
  }

  this.updateFormObjectScope = (formObject, objectScope) => {
    objectScope = objectScope || current.formObjectScope;
    this.copyObjectToScope(formObject, objectScope);
  }

  this.addForm = (name) => {
    if(!this.forms[name])
      this.forms[name] = [];
    return this.forms[name];
  }

  this.getCurrentPage = () => {
    return current.page;
  }

  this.selectCurrentPage = (index) => {
    return current.page = this.pages[index];
  }

  this.addPage = (page) => {
    let pageNumber = this.pages.length;

    page = page || {};
    page.index = page.index || pageNumber;
    page.formReference = page.formReference || ('form' + pageNumber);
    page.components = this.addForm('form' + pageNumber);

    this.insertPage(page, pageNumber);
  }

  this.removePage = function(pageKey) {
    var index = this.pages.findIndex(function (page) {
      return page.key == pageKey;
    });
    if(this.pages.length > 1) {
      this.pages.splice(index, 1);
      if(index > this.getCurrentPage().index)
        this.selectCurrentPage(index-1);
      else
        this.selectCurrentPage(index+1);
    } else {
      $log.error("Cant delete the first page.");
    }
  };

  this.insertPage = (page, pageNumber) => {
    page = new Page(page);
    this.pages.push(page);
    this.selectCurrentPage(pageNumber);
    return page;
  }

  this.insertFormObject = (name, index, formObject) => {

    if (formObject == null)
      formObject = {};

    /*
    Insert the form object into the form at {index}.
    @param name: The form name.
    @param index: The form object index.
    @param form: The form object.
        id: The form object id.
        component: {string} The component name
        editable: {bool} Is the form object editable? (default is yes)
        label: {string} The form object label.
        description: {string} The form object description.
        placeholder: {string} The form object placeholder.
        options: {array} The form object options.
        required: {bool} Is the form object required? (default is no)
        validation: {string} angular-validator. "/regex/" or "[rule1, rule2]".
        [index]: {int} The form object index. It will be updated by $builder.
    @return: The form object.
     */
    let base;
    if ((base = this.forms)[name] == null)
      base[name] = [];

    if (index > this.forms[name].length) {
      index = this.forms[name].length;
    } else if (index < 0) {
      index = 0;
    }

    this.forms[name].splice(index, 0, this.convertFormObject(name, formObject));
    this.reindexFormObject(name);
    // this.addAnswerDependency(formObject, answer);
    return this.forms[name][index];
  };

  this.removeFormObject = (name, index) => {
    /*
    Remove the form object by the index.
    @param name: The form name.
    @param index: The form object index.
     */
    name = name || current.formName
    index = index || current.formObject.index;
    let formObjects = this.forms[name];
    formObjects.splice(index, 1);

    if(!formObjects.length)
      if(current.page)
        if(current.page.form.name == current.formName)
          current.formObject = undefined;

    return this.reindexFormObject(name);
  };

  this.duplicateFormObject = (name, formObject) => {
    name = name || current.formName
    formObject = formObject || current.formObject

    let index = formObject.index
    let formObjects = this.forms[name];
    formObjects.splice(index, 0, angular.copy(formObject));

    return this.reindexFormObject(name);
  }

  this.updateFormObjectIndex = (name, oldIndex, newIndex) => {
    /*
    Update the index of the form object.
    @param name: The form name.
    @param oldIndex: The old index.
    @param newIndex: The new index.
     */
    if (oldIndex == newIndex)
      return;

    let formObjects = this.forms[name];
    let formObject = formObjects.splice(oldIndex, 1)[0];
    formObjects.splice(newIndex, 0, formObject);
    return this.reindexFormObject(name);
  };

  this.addTag = (tag) => {
    tag = new Tag(tag);
    this.tags.push(new Tag(tag));
    return tag;
  }

  this.removeTag = (tagKey) => {
    let index = this.tags.findIndex(tag => tag.key == tagKey)
    this.tags.splice(index, 1);
  }

  this.addAnswerDependency = (formObject, formObjectHandler, formAnswer) => {
    this.removeAnswerDependency(formObject);
    formObject.display = false;
    this.dependencies.push({
      formObjectTargetKey: formObject.key,
      formObjectKey: formObjectHandler,
      formAnswerKey: formAnswer
    });
  };

  this.removeAnswerDependency = (formObject, deepDestroy = false) => {
    formObject.display = true;
    this.dependencies.forEach((d, index) => {
      if(d.formObjectTargetKey == formObject.key) {
        this.dependencies.splice(index, 1);
        if(deepDestroy) formObject.dependentFrom = {};
      }
    });
  }

  this.removeAnswerDependencybyTarget = (formObject) => {
    let dependentTargets = this.findDependencyTargets(formObject.key)
    if(!dependentTargets.length) return false;

    dependentTargets.forEach( dependentFormObject => {
      this.removeAnswerDependency(dependentFormObject, true);
    });
  }

  this.findDependencyTargets = (formObjectKey) => {
    return this.dependencies.filter( d => {
      return d.formObjectKey == formObjectKey;
    }).map( d => {
      return this.findFormObjectByKey(d.formObjectTargetKey)
    });
  }

  this.findFormObjectByKey = (key) => {
    let selectedFormObject = Object.keys(this.forms).reduce((sum, key) => {
      sum = sum.concat(this.forms[key]);
      return sum;
    }, []).filter(fo => { return fo.key == key; })[0];
    return selectedFormObject || false
  }

  this.findPageByFormObjectKey = (key) => {
    let selectedPage = this.pages.find((page) => {
      let selectedComponent = page.components.find((component) => {
        return component.key == key;
      });
      return selectedComponent;
    });
    return selectedPage || false;
  }

  this.setDisplay = (displayType) => {
    if(displayType == displayTypes.SINGLE || displayType == displayTypes.WIZARD) {
      display = displayType
      if(display == displayTypes.SINGLE)
        this.selectCurrentPage(0);
    }
    else
      $log.error("The display type is not permited");
  }

  this.getDisplay = () => {
    return display;
  }

  this.setupDefaults = (defaultValues) => {
    this.pages.length = 0;
    this.dependencies.length = 0;
    this.forms = {};

    display = defaultValues.display || display;
    this.tags = defaultValues.tags || this.tags;

    if(defaultValues.components) {
      if(display == displayTypes.WIZARD) {
        defaultValues.components.forEach((page) => {
          let formObjects = angular.copy(page.components);
          this.addPage(page);
          formObjects.forEach((formObject) => {
            this.addFormObject(page.formReference, formObject);
          });
        });
      }
      if(display == displayTypes.SINGLE) {
        this.addPage();
        defaultValues.components.forEach((formObject) => {
          this.addFormObject(this.pages[0].formReference, formObject);
        });
      }
    }

    if (defaultValues.dependencies.length)
      defaultValues.dependencies.forEach(function (d) {
        let formObject = _this.findFormObjectByKey(d.formObjectTargetKey);
        _this.addAnswerDependency(formObject, d.formObjectKey, d.formAnswerKey);
      });
  }

  this.$get = [
    '$injector', function($injector) {
      this.setupProviders($injector);
      let components = this.components;
      for (let name in components) {
        let component = components[name];
        this.loadTemplate(component);
      }
      return {
        // Objects & Arrays
        forms: this.forms,
        pages: this.pages,
        groups: this.groups,
        tags: this.tags,
        dependencies: this.dependencies,
        components: this.components,
        // Pages handlers
        addPage: this.addPage,
        removePage: this.removePage,
        getCurrentPage: this.getCurrentPage,
        selectCurrentPage: this.selectCurrentPage,
        findPageByFormObjectKey: this.findPageByFormObjectKey,
        // Form Objects handlers
        addForm: this.addForm,
        getCurrentFormObject: this.getCurrentFormObject,
        selectCurrentFormObject: this.selectCurrentFormObject,
        updateFormObjectScope: this.updateFormObjectScope,
        addFormObject: this.addFormObject,
        insertFormObject: this.insertFormObject,
        removeFormObject: this.removeFormObject,
        duplicateFormObject: this.duplicateFormObject,
        updateFormObjectIndex: this.updateFormObjectIndex,
        findFormObjectByKey: this.findFormObjectByKey,
        // Tags handlers
        addTag: this.addTag,
        removeTag: this.removeTag,
        // Dependencies hadlers
        addAnswerDependency: this.addAnswerDependency,
        removeAnswerDependency: this.removeAnswerDependency,
        removeAnswerDependencybyTarget: this.removeAnswerDependencybyTarget,
        findDependencyTargets: this.findDependencyTargets,
        // Display handlers
        setDisplay: this.setDisplay,
        getDisplay: this.getDisplay,
        displayTypes: displayTypes,
        // Components HANDLERS
        registerComponent: this.registerComponent,
        // Other utils functions
        broadcastChannel: this.broadcastChannel,
        copyObjectToScope: this.copyObjectToScope,
        generateKey: new Utils().generateKey(),
        setupDefaults: this.setupDefaults
      };
    }
  ];
}
<commit_msg>fix(builder.provider): fix context in dependencies<commit_after>// TODO LIST:
// 1. Replace main js object from ES Class
// 2. Replace forms and arrays for ES Map

var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
// -----------------------
// BuilderProvider
// -----------------------

import { Utils }         from './builder.classes';
import { Component }     from './builder.classes';
import { FormObject }    from './builder.classes';
import { Page }          from './builder.classes';
import { Tag }           from './builder.classes';

export function BuilderProvider() {

  // Constants
  const displayTypes = Object.freeze({
    SINGLE: 'SINGLE',
    WIZARD: 'WIZARD'
  });

  var $injector = null, $http = null, $log = null, $templateCache = null;
  this.components = {};
  this.forms = { 'default': [] }; // replace for map
  this.pages = [];
  this.tags = [];
  this.groups = [];
  this.dependencies = [];
  this.broadcastChannel = {
    selectPage: '$selectPage',
    selectInput: '$selectInput',
    updateInput: '$updateInput',
    saveInput: '$saveInput',
    changeWizardStep: '$changeWizardStep',
    changeFormInputEvent: '$changeFormInputEvent'
  };

  let display = displayTypes.SINGLE;
  let current = {
    formObject: null,
    formObjectScope: null,
    formObjectElement: null,
    formName: null,
    page: null,
    form: this.forms['default']
  }

  this.convertComponent = (name, component) => {
    let result = new Component(name, component);

    if (!result.template && !result.templateUrl)
      $log.error("The template is empty.");

    if (!result.popoverTemplate && !result.popoverTemplateUrl)
      $log.error("The popoverTemplate is empty.");

    return result;
  };

  this.convertFormObject = (name, formObject) => {
    formObject = formObject || {};
    let component = this.components[formObject.component];
    if (component == null) {
      throw "The component " + formObject.component + " was not registered.";
    }

    let result = new FormObject(name, formObject, component)
    return result;
  };

  this.reindexFormObject = (name) => {
    var formObjects, i, index, ref;
    formObjects = this.forms[name];
    for (index = i = 0, ref = formObjects.length; i < ref; index = i += 1) {
      formObjects[index].index = index;
    }
  };

  this.setupProviders = (injector) => {
    $injector = injector;
    $http = $injector.get('$http');
    $templateCache = $injector.get('$templateCache');
    $log = $injector.get('$log');
  };

  this.loadTemplate = (component) => {
    if (component.template == null) {
      $http.get(component.templateUrl, {
        cache: $templateCache
      }).success((template) => {
        component.template = template;
      });
    }
    if (component.popoverTemplate == null) {
      $http.get(component.popoverTemplateUrl, {
        cache: $templateCache
      }).success((template) => {
        component.popoverTemplate = template;
      });
    }
  };

  this.copyObjectToScope = (object, scope) => {
    // Copy object (ng-repeat="object in objects") to scope without `hashKey`.
    var key, value;
    for (key in object) {
      value = object[key];
      if (key !== '$$hashKey') {
        scope[key] = value;
      }
    }
  }

  this.registerComponent = (name, component) => {
    if (component == null)
      component = {};

    /*
    Register the component for form-builder.
    @param name: The component name.
    @param component: The component object.
        group: {string} The component group.
        label: {string} The label of the input.
        description: {string} The description of the input.
        placeholder: {string} The placeholder of the input.
        editable: {bool} Is the form object editable?
        required: {bool} Is the form object required?
        validation: {string} angular-validator. "/regex/" or "[rule1, rule2]". (default is RegExp(.*))
        validationOptions: {array} [{rule: angular-validator, label: 'option label'}] the options for the validation. (default is [])
        options: {array} The input options.
        multipeChoice: {bool} checkbox could use this to convert input (default is no)
        template: {string} html template
        templateUrl: {string} The url of the template.
        popoverTemplate: {string} html template
        popoverTemplateUrl: {string} The url of the popover template.
     */
    if (this.components[name] == null) {
      let newComponent = this.convertComponent(name, component);
      this.components[name] = newComponent;

      if ($injector != null)
        this.loadTemplate(newComponent);
      if (newComponent.group, indexOf.call(this.groups, newComponent.group) < 0)
        this.groups.push(newComponent.group);

    } else {
      // $log.info("The component " + name + " was registered.");
    }
  };

  this.addFormObject = (name, formObject) => {
    if (formObject == null)
        formObject = {};
    // insert the form object into the form at last.
    let base;
    if ((base = this.forms)[name] == null)
      base[name] = [];

    return this.insertFormObject(name, this.forms[name].length, formObject);
  };

  this.getCurrentFormObject = () => {
    return current.formObject;
  }

  this.selectCurrentFormObject = (formName, formObject, element, objectScope) => {
    current.formName = formName;
    current.form = this.forms[formName];
    current.formObject = angular.copy(formObject);
    current.formObjectScope = objectScope;

    if(current.formObjectElement)
      current.formObjectElement.removeClass('active');

    current.formObjectElement = element
    current.formObjectElement.addClass('active');
  }

  this.updateFormObjectScope = (formObject, objectScope) => {
    objectScope = objectScope || current.formObjectScope;
    this.copyObjectToScope(formObject, objectScope);
  }

  this.addForm = (name) => {
    if(!this.forms[name])
      this.forms[name] = [];
    return this.forms[name];
  }

  this.getCurrentPage = () => {
    return current.page;
  }

  this.selectCurrentPage = (index) => {
    return current.page = this.pages[index];
  }

  this.addPage = (page) => {
    let pageNumber = this.pages.length;

    page = page || {};
    page.index = page.index || pageNumber;
    page.formReference = page.formReference || ('form' + pageNumber);
    page.components = this.addForm('form' + pageNumber);

    this.insertPage(page, pageNumber);
  }

  this.removePage = function(pageKey) {
    var index = this.pages.findIndex(function (page) {
      return page.key == pageKey;
    });
    if(this.pages.length > 1) {
      this.pages.splice(index, 1);
      if(index > this.getCurrentPage().index)
        this.selectCurrentPage(index-1);
      else
        this.selectCurrentPage(index+1);
    } else {
      $log.error("Cant delete the first page.");
    }
  };

  this.insertPage = (page, pageNumber) => {
    page = new Page(page);
    this.pages.push(page);
    this.selectCurrentPage(pageNumber);
    return page;
  }

  this.insertFormObject = (name, index, formObject) => {

    if (formObject == null)
      formObject = {};

    /*
    Insert the form object into the form at {index}.
    @param name: The form name.
    @param index: The form object index.
    @param form: The form object.
        id: The form object id.
        component: {string} The component name
        editable: {bool} Is the form object editable? (default is yes)
        label: {string} The form object label.
        description: {string} The form object description.
        placeholder: {string} The form object placeholder.
        options: {array} The form object options.
        required: {bool} Is the form object required? (default is no)
        validation: {string} angular-validator. "/regex/" or "[rule1, rule2]".
        [index]: {int} The form object index. It will be updated by $builder.
    @return: The form object.
     */
    let base;
    if ((base = this.forms)[name] == null)
      base[name] = [];

    if (index > this.forms[name].length) {
      index = this.forms[name].length;
    } else if (index < 0) {
      index = 0;
    }

    this.forms[name].splice(index, 0, this.convertFormObject(name, formObject));
    this.reindexFormObject(name);
    // this.addAnswerDependency(formObject, answer);
    return this.forms[name][index];
  };

  this.removeFormObject = (name, index) => {
    /*
    Remove the form object by the index.
    @param name: The form name.
    @param index: The form object index.
     */
    name = name || current.formName
    index = index || current.formObject.index;
    let formObjects = this.forms[name];
    formObjects.splice(index, 1);

    if(!formObjects.length)
      if(current.page)
        if(current.page.form.name == current.formName)
          current.formObject = undefined;

    return this.reindexFormObject(name);
  };

  this.duplicateFormObject = (name, formObject) => {
    name = name || current.formName
    formObject = formObject || current.formObject

    let index = formObject.index
    let formObjects = this.forms[name];
    formObjects.splice(index, 0, angular.copy(formObject));

    return this.reindexFormObject(name);
  }

  this.updateFormObjectIndex = (name, oldIndex, newIndex) => {
    /*
    Update the index of the form object.
    @param name: The form name.
    @param oldIndex: The old index.
    @param newIndex: The new index.
     */
    if (oldIndex == newIndex)
      return;

    let formObjects = this.forms[name];
    let formObject = formObjects.splice(oldIndex, 1)[0];
    formObjects.splice(newIndex, 0, formObject);
    return this.reindexFormObject(name);
  };

  this.addTag = (tag) => {
    tag = new Tag(tag);
    this.tags.push(new Tag(tag));
    return tag;
  }

  this.removeTag = (tagKey) => {
    let index = this.tags.findIndex(tag => tag.key == tagKey)
    this.tags.splice(index, 1);
  }

  this.addAnswerDependency = (formObject, formObjectHandler, formAnswer) => {
    this.removeAnswerDependency(formObject);
    formObject.display = false;
    this.dependencies.push({
      formObjectTargetKey: formObject.key,
      formObjectKey: formObjectHandler,
      formAnswerKey: formAnswer
    });
  };

  this.removeAnswerDependency = (formObject, deepDestroy = false) => {
    formObject.display = true;
    this.dependencies.forEach((d, index) => {
      if(d.formObjectTargetKey == formObject.key) {
        this.dependencies.splice(index, 1);
        if(deepDestroy) formObject.dependentFrom = {};
      }
    });
  }

  this.removeAnswerDependencybyTarget = (formObject) => {
    let dependentTargets = this.findDependencyTargets(formObject.key)
    if(!dependentTargets.length) return false;

    dependentTargets.forEach( dependentFormObject => {
      this.removeAnswerDependency(dependentFormObject, true);
    });
  }

  this.findDependencyTargets = (formObjectKey) => {
    return this.dependencies.filter( d => {
      return d.formObjectKey == formObjectKey;
    }).map( d => {
      return this.findFormObjectByKey(d.formObjectTargetKey)
    });
  }

  this.findFormObjectByKey = (key) => {
    let selectedFormObject = Object.keys(this.forms).reduce((sum, key) => {
      sum = sum.concat(this.forms[key]);
      return sum;
    }, []).filter(fo => { return fo.key == key; })[0];
    return selectedFormObject || false
  }

  this.findPageByFormObjectKey = (key) => {
    let selectedPage = this.pages.find((page) => {
      let selectedComponent = page.components.find((component) => {
        return component.key == key;
      });
      return selectedComponent;
    });
    return selectedPage || false;
  }

  this.setDisplay = (displayType) => {
    if(displayType == displayTypes.SINGLE || displayType == displayTypes.WIZARD) {
      display = displayType
      if(display == displayTypes.SINGLE)
        this.selectCurrentPage(0);
    }
    else
      $log.error("The display type is not permited");
  }

  this.getDisplay = () => {
    return display;
  }

  this.setupDefaults = (defaultValues) => {
    this.pages.length = 0;
    this.dependencies.length = 0;
    this.forms = {};

    display = defaultValues.display || display;
    this.tags = defaultValues.tags || this.tags;

    if(defaultValues.components) {
      if(display == displayTypes.WIZARD) {
        defaultValues.components.forEach((page) => {
          let formObjects = angular.copy(page.components);
          this.addPage(page);
          formObjects.forEach((formObject) => {
            this.addFormObject(page.formReference, formObject);
          });
        });
      }
      if(display == displayTypes.SINGLE) {
        this.addPage();
        defaultValues.components.forEach((formObject) => {
          this.addFormObject(this.pages[0].formReference, formObject);
        });
      }
    }

    if (defaultValues.dependencies.length)
      defaultValues.dependencies.forEach(function (d) {
        let formObject = this.findFormObjectByKey(d.formObjectTargetKey);
        this.addAnswerDependency(formObject, d.formObjectKey, d.formAnswerKey);
      });
  }

  this.$get = [
    '$injector', function($injector) {
      this.setupProviders($injector);
      let components = this.components;
      for (let name in components) {
        let component = components[name];
        this.loadTemplate(component);
      }
      return {
        // Objects & Arrays
        forms: this.forms,
        pages: this.pages,
        groups: this.groups,
        tags: this.tags,
        dependencies: this.dependencies,
        components: this.components,
        // Pages handlers
        addPage: this.addPage,
        removePage: this.removePage,
        getCurrentPage: this.getCurrentPage,
        selectCurrentPage: this.selectCurrentPage,
        findPageByFormObjectKey: this.findPageByFormObjectKey,
        // Form Objects handlers
        addForm: this.addForm,
        getCurrentFormObject: this.getCurrentFormObject,
        selectCurrentFormObject: this.selectCurrentFormObject,
        updateFormObjectScope: this.updateFormObjectScope,
        addFormObject: this.addFormObject,
        insertFormObject: this.insertFormObject,
        removeFormObject: this.removeFormObject,
        duplicateFormObject: this.duplicateFormObject,
        updateFormObjectIndex: this.updateFormObjectIndex,
        findFormObjectByKey: this.findFormObjectByKey,
        // Tags handlers
        addTag: this.addTag,
        removeTag: this.removeTag,
        // Dependencies hadlers
        addAnswerDependency: this.addAnswerDependency,
        removeAnswerDependency: this.removeAnswerDependency,
        removeAnswerDependencybyTarget: this.removeAnswerDependencybyTarget,
        findDependencyTargets: this.findDependencyTargets,
        // Display handlers
        setDisplay: this.setDisplay,
        getDisplay: this.getDisplay,
        displayTypes: displayTypes,
        // Components HANDLERS
        registerComponent: this.registerComponent,
        // Other utils functions
        broadcastChannel: this.broadcastChannel,
        copyObjectToScope: this.copyObjectToScope,
        generateKey: new Utils().generateKey(),
        setupDefaults: this.setupDefaults
      };
    }
  ];
}
<|endoftext|>