<commit_before>var pathFn = require('path'),
  _ = require('lodash'),
  fs = require('fs'),
  imageSize = require('image-size'),
  glob = require('glob'),
  Canvas = require('canvas'),
  Image = Canvas.Image;

var uid = function(length){
  var src = 'abcdefghijklmnopqrstuvwxyz0123456789',
    srcLen = src.length,
    result = '';

  for (var i = 0; i < length; i++){
    result += src[parseInt(Math.random() * srcLen, 10)];
  }

  return result;
};

var Sprite = module.exports = function(options){
  var baseDir = options.base_dir,
    imageDir = pathFn.join(baseDir, options.image_dir),
    cachePath = pathFn.join(baseDir, options.cache_path),
    baseUrl = options.base_url,
    imageUrl = baseUrl + options.image_url,
    layout = options.layout,
    cache = {};

  var globOptions = {
    cwd: imageDir
  };

  var loadCache = function(){
    var exist = fs.existsSync(cachePath);

    if (exist){
      cache = require(cachePath);
    } else {
      cache = {
        files: {},
        lists: {},
        sprites: {}
      };
    }
  };

  var saveCache = function(){
    fs.writeFileSync(cachePath, JSON.stringify(cache));
  };

  var getFileCache = function(path){
    return cache.files[path];
  };

  var imageInfo = function(path){
    var data = getFileCache(path),
      src = pathFn.join(imageDir, path),
      exist = fs.existsSync(src);

    if (!exist){
      data = null;
      return {};
    }

    var stats = fs.statSync(src),
      mtime = stats.mtime.getTime();

    if (data && data.mtime === mtime){
      return data;
    }

    var size = imageSize(src);

    data = {
      mtime: mtime,
      width: size.width,
      height: size.height
    };

    return data;
  };

  var spriteFn = function(path){
    //
  };

  loadCache();

  return {
    spriteMap: function(data){
      var val = data.val,
        list = cache.lists[val],
        files = glob.sync(val, globOptions),
        changed = [],
        statObj = {},
        images = [];

      if (!files.length){
        return;
      }

      // Check whether files are modified or not
      files.forEach(function(file){
        var data = getFileCache(file),
          src = pathFn.join(imageDir, file),
          stats = statObj[file] = fs.statSync(src);

        if (!data || data.mtime !== stats.mtime.getTime()){
          changed.push(file);
        }
      });

      if (!changed.length && list && JSON.stringify(list.files) === JSON.stringify(files)){
        return spriteFn(val);
      }

      // Read files
      var maxWidth = 0,
        maxHeight = 0,
        totalWidth = 0,
        totalHeight = 0;

      files.forEach(function(file){
        var src = pathFn.join(imageDir, file),
          buf = fs.readFileSync(src),
          size = imageSize(buf),
          data = getFileCache(file),
          width = size.width,
          height = size.height;

        data = {
          mtime: statObj[file].mtime,
          width: width,
          height: height
        };

        if (width > maxWidth) maxWidth = width;
        if (height > maxHeight) maxHeight = height;

        totalWidth += width;
        totalHeight += height;

        images.push({
          file: file,
          buffer: buf,
          width: width,
          height: height
        });
      });

      var x = 0,
        y = 0,
        canvas,
        ctx;

      var sprite = cache.sprites[val] = {
        id: uid(12),
        map: {}
      };

      switch (layout){
        case 'horizontal':
          canvas = new Canvas(totalWidth, maxHeight);
          ctx = canvas.getContext('2d');

          images.forEach(function(data){
            var img = new Image();
            img.src = data.buffer;
            ctx.drawImage(img, x, y, data.width, data.height);

            sprite.map[data.file] = {
              x: x,
              y: y
            };

            x += data.width;
          });

          break;

        // TODO buggy
        case 'diagonal':
          canvas = new Canvas(totalWidth, totalHeight);
          ctx = canvas.getContext('2d');

          images.forEach(function(data){
            var img = new Image();
            img.src = data.buffer;
            ctx.drawImage(img, x, y, data.width, data.height);

            sprite.map[data.file] = {
              x: x,
              y: y
            };

            x += data.width;
            y += data.height;
          });

        default: // vertical
          canvas = new Canvas(maxWidth, totalHeight);
          ctx = canvas.getContext('2d');

          images.forEach(function(data){
            var img = new Image();
            img.src = data.buffer;
            ctx.drawImage(img, x, y, data.width, data.height);

            sprite.map[data.file] = {
              x: x,
              y: y
            };

            y += data.height;
          });
      }

      fs.writeFileSync(pathFn.join(imageDir, sprite.id + '.png'), canvas.toBuffer());
      images.length = 0;

      return spriteFn(val);
    },
    imageWidth: function(data){
      var info = imageInfo(data.val);

      return new this.renderer.nodes.Unit(info.width, 'px');
    },
    imageHeight : function(data){
      var info = imageInfo(data.val);

      return new this.renderer.nodes.Unit(info.height, 'px');
    }
  };
};<commit_msg>sprite-map: diagonal<commit_after>var pathFn = require('path'),
  _ = require('lodash'),
  fs = require('fs'),
  imageSize = require('image-size'),
  glob = require('glob'),
  Canvas = require('canvas'),
  Image = Canvas.Image;

var uid = function(length){
  var src = 'abcdefghijklmnopqrstuvwxyz0123456789',
    srcLen = src.length,
    result = '';

  for (var i = 0; i < length; i++){
    result += src[parseInt(Math.random() * srcLen, 10)];
  }

  return result;
};

var Sprite = module.exports = function(options){
  var baseDir = options.base_dir,
    imageDir = pathFn.join(baseDir, options.image_dir),
    cachePath = pathFn.join(baseDir, options.cache_path),
    baseUrl = options.base_url,
    imageUrl = baseUrl + options.image_url,
    layout = options.layout,
    cache = {};

  var globOptions = {
    cwd: imageDir
  };

  var loadCache = function(){
    var exist = fs.existsSync(cachePath);

    if (exist){
      cache = require(cachePath);
    } else {
      cache = {
        files: {},
        lists: {},
        sprites: {}
      };
    }
  };

  var saveCache = function(){
    fs.writeFileSync(cachePath, JSON.stringify(cache));
  };

  var getFileCache = function(path){
    return cache.files[path];
  };

  var imageInfo = function(path){
    var data = getFileCache(path),
      src = pathFn.join(imageDir, path),
      exist = fs.existsSync(src);

    if (!exist){
      data = null;
      return {};
    }

    var stats = fs.statSync(src),
      mtime = stats.mtime.getTime();

    if (data && data.mtime === mtime){
      return data;
    }

    var size = imageSize(src);

    data = {
      mtime: mtime,
      width: size.width,
      height: size.height
    };

    return data;
  };

  var spriteFn = function(path){
    //
  };

  loadCache();

  return {
    spriteMap: function(data){
      var val = data.val,
        list = cache.lists[val],
        files = glob.sync(val, globOptions),
        changed = [],
        statObj = {},
        images = [];

      if (!files.length){
        return;
      }

      // Check whether files are modified or not
      files.forEach(function(file){
        var data = getFileCache(file),
          src = pathFn.join(imageDir, file),
          stats = statObj[file] = fs.statSync(src);

        if (!data || data.mtime !== stats.mtime.getTime()){
          changed.push(file);
        }
      });

      if (!changed.length && list && JSON.stringify(list.files) === JSON.stringify(files)){
        return spriteFn(val);
      }

      // Read files
      var maxWidth = 0,
        maxHeight = 0,
        totalWidth = 0,
        totalHeight = 0;

      files.forEach(function(file){
        var src = pathFn.join(imageDir, file),
          buf = fs.readFileSync(src),
          size = imageSize(buf),
          data = getFileCache(file),
          width = size.width,
          height = size.height;

        data = {
          mtime: statObj[file].mtime,
          width: width,
          height: height
        };

        if (width > maxWidth) maxWidth = width;
        if (height > maxHeight) maxHeight = height;

        totalWidth += width;
        totalHeight += height;

        images.push({
          file: file,
          buffer: buf,
          width: width,
          height: height
        });
      });

      var x = 0,
        y = 0,
        canvas,
        ctx;

      var sprite = cache.sprites[val] = {
        id: uid(12),
        map: {}
      };

      switch (layout){
        case 'horizontal':
          canvas = new Canvas(totalWidth, maxHeight);
          ctx = canvas.getContext('2d');

          images.forEach(function(data){
            var img = new Image();
            img.src = data.buffer;
            ctx.drawImage(img, x, y, data.width, data.height);

            sprite.map[data.file] = {
              x: x,
              y: y
            };

            x += data.width;
          });

          break;

        case 'diagonal':
          canvas = new Canvas(totalWidth, totalHeight);
          ctx = canvas.getContext('2d');

          images.forEach(function(data){
            var img = new Image();
            img.src = data.buffer;
            ctx.drawImage(img, x, y, data.width, data.height);

            sprite.map[data.file] = {
              x: x,
              y: y
            };

            x += data.width;
            y += data.height;
          });

          break;

        default: // vertical
          canvas = new Canvas(maxWidth, totalHeight);
          ctx = canvas.getContext('2d');

          images.forEach(function(data){
            var img = new Image();
            img.src = data.buffer;
            ctx.drawImage(img, x, y, data.width, data.height);

            sprite.map[data.file] = {
              x: x,
              y: y
            };

            y += data.height;
          });
      }

      fs.writeFileSync(pathFn.join(imageDir, sprite.id + '.png'), canvas.toBuffer());
      images.length = 0;

      return spriteFn(val);
    },
    imageWidth: function(data){
      var info = imageInfo(data.val);

      return new this.renderer.nodes.Unit(info.width, 'px');
    },
    imageHeight : function(data){
      var info = imageInfo(data.val);

      return new this.renderer.nodes.Unit(info.height, 'px');
    }
  };
};<|endoftext|>


<commit_before>function expandSidebar(){
  var sidebar = $(".sidebar-container")[0];
  if(sidebar) {
    var page_content = $(".page-content-container")[0];
    if(page_content.offsetHeight > sidebar.offsetHeight) {
      sidebar.style.height = page_content.offsetHeight + 'px';
    }
  }
}

function adjustProgress(percent) {
  $('.ai-progressbar').width(percent + '%');
}

function adjustText(percent) {
  var ai_red    = '#FF4E48';           // source: _variables.scss
  var ai_white  = '#FFFFFF';
  var screen_width = $(window).width();
  if(screen_width < 690) {
    $('.ai-progress-text').css('visibility','hidden');
  } else {
    if(percent < 60) {
      $('.ai-progress-text').css({'color': ai_red, 'width': percent + '%', 'left': percent + 5 + '%'});
    }
    if(percent >= 60) {
      $('.ai-progress-text').css({'color': ai_white, 'width': percent + '%'});
    }
  }
}
<commit_msg>formatting issues on calendar<commit_after>function expandSidebar(){
  var sidebar = $(".sidebar-container")[0];
  if(sidebar) {
    var page_content = $(".page-content-container")[0];
    if(page_content.offsetHeight > sidebar.offsetHeight) {
      sidebar.style.height = page_content.offsetHeight + 'px';
    }
  }
}

function adjustProgress(percent) {
  $('.ai-progressbar').width(percent + '%');
}

function adjustText(percent) {
  var ai_red    = '#FF4E48';           // source: _variables.scss
  var ai_white  = '#FFFFFF';
  var screen_width = $(window).width();
  if(screen_width < 690) {
    $('.ai-progress-text').css('visibility','hidden');
  } else {
    if(percent < 30) {
      $('.ai-progress-text').css({'color': ai_red, 'width': '10%', 'left': '50%'});
    }
    if(percent >= 30 && percent < 65) {
      $('.ai-progress-text').css({'color': ai_red, 'width': '10%', 'left': percent + 5 + '%'});
    }
    if(percent >= 65) {
      $('.ai-progress-text').css({'color': ai_white, 'width': percent + '%'});
    }
  }
}
<|endoftext|>


<commit_before>"use strict";

/**
 * Native modules.
 */

var fs = require('fs')
  , os = require('os')
  , path = require('path')
  , createHash = require('crypto').createHash
  , EventEmitter = require('events').EventEmitter;

/**
 * Super charge the EventEmitters
 */

require('eventreactor');

/**
 * Third party modules.
 */

var Logger = require('devnull')
  , _ = require('underscore')._
  , exec = require('shelljs').exec;

/**
 * Cached variables.
 */

var slice = Array.prototype.slice;

/**
 * Require statement parser for inline includes.
 *
 * @type {RegExp}
 * @api private
 */

var reqparse = /(\/\*|\/\/)\s*\[square\]\s*\@(require|import|include)\s*\"([^"]+)?\"(.*)/i;

/**
 * Square
 *
 * @constructor
 * @param {Object} options
 * @api public
 */

var Square = module.exports = function Square (options) {
  this.env = process.env.NODE_ENV || 'development';
  this.logger = new Logger({ timestamp: false });
  this.reqparse = reqparse;

  _.extend(this, options || {});

  // should not be overridden
  this.config = require('../defaults');
  this.middleware = [];
  this.package = {};
};

Square.prototype.__proto__ = EventEmitter.prototype;

/**
 * Middleware layer. Use different middleware layers for compiling your bundles.
 * The order of definition is respected.
 *
 * @param {Function} layer
 * @api public
 */

Square.prototype.use = function use (layer) {
  if (typeof layer !== 'function') {
    this.logger.error('the supplied middleware isnt a valid function');
    return this;
  }

  // check if we this middleware is already configured
  if (!this.has(layer)) this.middleware.push(layer);
  return this;
};

/**
 * Checks if the middleware layer already exists based on the function name.
 *
 * @param {Function} layer
 * @return {Boolean}
 * @api private
 */

Square.prototype.has = function has (layer) {
  /**
   * Small some function that checks if the supplied middleware is the same as
   * the given middleware layer. This check is done on the contents of the
   * function body and the names of the function.
   *
   * @param {Function} middleware
   * @returns {Boolean}
   * @api private
   */

  function some (middleware) {
    return middleware.toString() === layer.toString()
      && middleware.name === layer.name;
  }

  return this.middleware.some(some);
};

/**
 * Load a file from our plugin directory in to our middleware.
 *
 * @param {Function} layer
 * @param {Object} options
 * @api public
 */

Square.prototype.plugin = function plugin (layer, options) {
  var middleware;

  options = options || !this.package.configuration
    ? options
    : this.package.configuration.plugin[layer];

  try { middleware = require('../plugins/' + layer); }
  catch (e) {
    this.logger.error('Failed to plugin', layer, e);
  }

  if (middleware) this.use(middleware(options));

  return this;
};

/**
 * Runs the supplied configuration function only for the set env. This allows
 * you to use different middleware stacks for development and production. You
 * can specify as many environments as you wish. It only requires a callback
 * function as last argument. All other arguments are seen as environment
 * variables where it should be toggled.
 *
 * @param {String} env environment
 * @param {Function} fn callback
 * @api public
 */

Square.prototype.configure = function configure (evn, fn) {
  var envs = 'all'
    , args = slice.call(arguments);

  // setup the correct argument structure
  fn = args.pop();

  if (args.length) envs = args;
  if (envs === 'all' || ~envs.indexOf(this.env)) fn.call(this);

  return this;
};

/**
 * Bundle all the things
 *
 * @api public
 */

Square.prototype.bundle = function bundle () {
  var args = slice.call(arguments).reduce(function (memory, arg) {
    memory[typeof arg] = arg;
    return memory;
  }, {});

  // when we receive an object in the arguments we assume it's the parse package
  // details
  this.package = args.object;

  // oh, we got a string, assume filename, fetch the file and parse it
  if (args.string) {
    args.package = fs.readFileSync(args.string, 'utf8');
    this.package = JSON.parse(args.package);        // the parsed file
    this.package.path = path.dirname(args.string);  // folder of the bundle
    this.package.source = args.package;             // stringified content
    this.package.location = args.string;            // location of the bundle
  }

  return this.parse();
};

/**
 * Parse the package.
 *
 * @param {Object} data
 * @api private
 */

Square.prototype.parse = function parse (data) {
  /**
   * Generate the weight of a single dependency.
   *
   * @param {Number} amount
   * @param {Number} padding
   * @return {Number}
   * @api private
   */

  function weight (amount, padding) {
    padding = padding < 10
      ? '0' + padding.toString(10)
      : padding.toString(10);

    return +(amount + '.' + padding);
  }

 /**
  * Does a deep merge on an object.
  *
  * @param {Object} target
  * @param {Object} additional
  * @api private
  */

  function merge (target, additional, deep, lastseen) {
    var seen = lastseen || []
      , depth = typeof deep === 'undefined' ? 2 : deep
      , prop;

    for (prop in additional) {
      if (additional.hasOwnProperty(prop) && seen.indexOf(prop) < 0) {
        if (typeof target[prop] !== 'object' || !depth) {
          target[prop] = additional[prop];
          seen.push(additional[prop]);
        } else {
          merge(target[prop], additional[prop], depth - 1, seen);
        }
      }
    }

    return target;
  }

  // default
  data = data || this.package;

  var dependencies = []
    , depended = {};

  Object.keys(data.bundle).forEach(function each (file, index, files) {
    var bundle = data.bundle[file]
      , base = data.path
      , location = path.join(base, file)
      , total;

    // add the current file to the dependency tree, as the last file so all
    // other dependencies are loaded before this file
    if (!Array.isArray(bundle.dependencies)) bundle.dependencies = [];
    if (!~bundle.dependencies.indexOf(file)) bundle.dependencies.push(file);

    // make sure it exists
    if (!path.existsSync(location)) {
      return this.logger.error(location + ' does not exist, cant read file');
    }

    // parse the data, and add some meta data
    bundle.content = fs.readFileSync(location, 'UTF8');
    bundle.meta = {
        location: location
      , path: base
      , extension: file.split('.').pop()
      , package: data
    };

    // find all the dependencies
    total = bundle.dependencies.length;
    bundle.dependencies.forEach(function each (file, index) {
      var amount = weight(bundle.weight || 1, total--);

      // the dependency always uses the highest weight it gets assigned
      if (!depended[file] || depended[file] < amount) depended[file] = amount;
      if (!~dependencies.indexOf(file)) dependencies.push(file);
    });
  }.bind(this));

  // sort the dependencies based on their assigned weight
  dependencies = dependencies.sort(function sort (a, b) {
    return depended[b] - depended[a];
  });

  // ensure that all dependencies are loaded correctly, so we don't generate any
  // files bundles with missing dependencies
  dependencies.some(function (file) {
    if (!data.bundle[file]) {
      this.logger.error('missing dependency: ' + file);
      return false;
    }

    return true;
  }.bind(this));

  // the package is now updated with the parsed data so we can use and abuse it
  this.package = data;

  // attach the dependencies for easy lookups
  this.package.dependencies = dependencies;

  // make sure there is a configuration, and if it's there merge it with our
  // default config so we are sure that every option is specified
  this.package.configuration = merge(this.config, this.package.configuration || {});

  // if there is a license file in the configuration we are going to parse it
  // out so we can use it
  var configuration = this.package.configuration
    , location;

  if (configuration.license) {
    location = path.join(this.package.path + configuration.license);

    if (!path.existsSync(location)) {
      this.logger.error(location + ' does not exit, cant read license file');
      delete this.package.configuration.license;
    } else {
      this.package.configuration.license = fs.readFileSync(location, 'UTF8');
    }
  }

  return this.emit('parse', this.package);
};

/**
 * Build the stuff.
 *
 * @api private
 */

Square.prototype.build = function build () {
  var layers = this.middleware.slice(0)
    , errors = []
    , self = this
    , backup;

  /**
   * Simple iteration helper function to process the middleware.
   *
   * @param {Mixed} err error or undef/null
   * @param {String} content
   * @api private
   */

  function iterate (err, content) {
    var layer = layers.shift();

    if (err) errors.push(err);
    if (content) backup = content;
    else content = backup;

    if (!layer) {
      if (errors.length) return self.logger.error('Failed to process content', errors);
      return self.write(content, 'min');
    }

    // capture errors that might be caused the middleware layers
    try { layer.call(self, content, iterate); }
    catch (e) { iterate.call(iterate, e, content); }
  }

  this.once('merge', function merged (content) {
    iterate(null, content);
    self.write(content, 'dev');
  });

  return this.merge();
};

/**
 * Process the template string.
 *
 * @param {String} str
 * @param {Object} data
 * @returns {String} result
 * @api private
 */

Square.prototype.template = function template (str, data) {
  data = data || this.package;

  for (var prop in data) {
    str = str.replace(new RegExp('{' + prop + '}', 'g'), data[prop]);
  }

  return str;
};

/**
 * Creates a tag / profile from the content so it can be used for processing.
 *
 * @param {String} content
 * @param {String} type
 * @param {String} extension
 * @returns {Object}
 * @api public
 */

Square.prototype.tag = function tag (content, type, extension) {
  var branch = exec('git branch', { silent:true }).output
    , sha = exec('git show -s', { silent:true }).output
    , date = new Date();

  if (branch) {
    branch = /\*\s([\w\.]+)/g.exec(branch) || '';
    branch = branch.length ? branch[1] : branch;
  }

  if (sha) {
    sha = /commit\s(\w+)/g.exec(sha) || '';
    sha = sha.length ? sha[1] : sha;
  }

  return _.extend({
      type: type || 'min'
    , md5: createHash('md5').update(content).digest('hex')
    , branch: branch
    , sha: sha
    , ext: extension || 'js'
    , date: date.toLocaleDateString()
    , year: date.getFullYear()
    , user: process.env.USER || 'anonymous'
    , host: os.hostname()
  }, this.package.configuration.vars || {});
};

/**
 * Write the output of the file to a directory.
 *
 * @param {String} content
 * @param {String} type
 * @param {String} extension
 * @api private
 */

Square.prototype.write = function write (content, type, extension) {
  var configuration = this.package.configuration
    , output = configuration.dist[type].replace(/^~/g, process.env.HOME)
    , file = this.template(output, this.tag.apply(this, arguments));

  file = path.resolve(file);
  content = this.license.apply(this, arguments);

  this.logger.info('writing', file);

  fs.writeFile(file, content, function written (err) {
    if (err) this.logger.error(err);
  }.bind(this));
};

/**
 * Merge all the dependencies in to one single file.
 *
 * @api private
 */

Square.prototype.merge = function merge () {
  var bundle = this.package.bundle
    , concat = []
    , self = this;

  if (!bundle || !this.package.dependencies) return this;

  /**
   * Search the code for require statements, parse it out and inline the
   * content's of the required file.
   *
   * @param {String} match complete matched result
   * @param {String} commenttype type of comment
   * @param {String} statement import statement name
   * @param {String} file the file that needs to be inlined
   * @returns {String}
   * @api private
   */

  function insert (match, commenttype, statement, file) {
    var location = path.join(self.package.base, file);

    return fs.readFileSync(location, 'UTF8');
  }

  this.package.dependencies.forEach(function each (file) {
    var content = bundle[file].content.toString('UTF8');

    content = content.split('\n')
      .map(function inspect (line) { return line.replace(self.reqparse, insert); })
      .join('\n');

    concat.push(content);
  });

  // emit a merge event
  this.emit('merge', concat.join('\n'));
  return this;
};

/**
 * Check if we need to prepend a license file.
 *
 * @param {String} content
 * @param {String} type
 * @param {String} extension
 * @returns {String}
 * @api private
 */

Square.prototype.license = function copyright (content, type, extenstion) {
  var configuration = this.package.configuration
    , license = configuration.license;

  if (!license) return content;

  // process the template with some variables
  license = this.template(license, this.tag.apply(this, arguments));
  return license + content;
};
<commit_msg>base path, check for absolute paths first instead of blindly joining them<commit_after>"use strict";

/**
 * Native modules.
 */

var fs = require('fs')
  , os = require('os')
  , path = require('path')
  , createHash = require('crypto').createHash
  , EventEmitter = require('events').EventEmitter;

/**
 * Super charge the EventEmitters
 */

require('eventreactor');

/**
 * Third party modules.
 */

var Logger = require('devnull')
  , _ = require('underscore')._
  , exec = require('shelljs').exec;

/**
 * Cached variables.
 */

var slice = Array.prototype.slice;

/**
 * Require statement parser for inline includes.
 *
 * @type {RegExp}
 * @api private
 */

var reqparse = /(\/\*|\/\/)\s*\[square\]\s*\@(require|import|include)\s*\"([^"]+)?\"(.*)/i;

/**
 * Simple helper function for working with absolute paths.
 *
 * @param {String} file
 * @param {String} root
 * @api private
 */

function basepath (file, root) {
  return file[0] === '/'
    ? file
    : path.join(root, file);
}

/**
 * Square
 *
 * @constructor
 * @param {Object} options
 * @api public
 */

var Square = module.exports = function Square (options) {
  this.env = process.env.NODE_ENV || 'development';
  this.logger = new Logger({ timestamp: false });
  this.reqparse = reqparse;

  _.extend(this, options || {});

  // should not be overridden
  this.config = require('../defaults');
  this.middleware = [];
  this.package = {};
};

Square.prototype.__proto__ = EventEmitter.prototype;

/**
 * Middleware layer. Use different middleware layers for compiling your bundles.
 * The order of definition is respected.
 *
 * @param {Function} layer
 * @api public
 */

Square.prototype.use = function use (layer) {
  if (typeof layer !== 'function') {
    this.logger.error('the supplied middleware isnt a valid function');
    return this;
  }

  // check if we this middleware is already configured
  if (!this.has(layer)) this.middleware.push(layer);
  return this;
};

/**
 * Checks if the middleware layer already exists based on the function name.
 *
 * @param {Function} layer
 * @return {Boolean}
 * @api private
 */

Square.prototype.has = function has (layer) {
  /**
   * Small some function that checks if the supplied middleware is the same as
   * the given middleware layer. This check is done on the contents of the
   * function body and the names of the function.
   *
   * @param {Function} middleware
   * @returns {Boolean}
   * @api private
   */

  function some (middleware) {
    return middleware.toString() === layer.toString()
      && middleware.name === layer.name;
  }

  return this.middleware.some(some);
};

/**
 * Load a file from our plugin directory in to our middleware.
 *
 * @param {Function} layer
 * @param {Object} options
 * @api public
 */

Square.prototype.plugin = function plugin (layer, options) {
  var middleware;

  options = options || !this.package.configuration
    ? options
    : this.package.configuration.plugin[layer];

  try { middleware = require('../plugins/' + layer); }
  catch (e) {
    this.logger.error('Failed to plugin', layer, e);
  }

  if (middleware) this.use(middleware(options));

  return this;
};

/**
 * Runs the supplied configuration function only for the set env. This allows
 * you to use different middleware stacks for development and production. You
 * can specify as many environments as you wish. It only requires a callback
 * function as last argument. All other arguments are seen as environment
 * variables where it should be toggled.
 *
 * @param {String} env environment
 * @param {Function} fn callback
 * @api public
 */

Square.prototype.configure = function configure (evn, fn) {
  var envs = 'all'
    , args = slice.call(arguments);

  // setup the correct argument structure
  fn = args.pop();

  if (args.length) envs = args;
  if (envs === 'all' || ~envs.indexOf(this.env)) fn.call(this);

  return this;
};

/**
 * Bundle all the things
 *
 * @api public
 */

Square.prototype.bundle = function bundle () {
  var args = slice.call(arguments).reduce(function (memory, arg) {
    memory[typeof arg] = arg;
    return memory;
  }, {});

  // when we receive an object in the arguments we assume it's the parse package
  // details
  this.package = args.object;

  // oh, we got a string, assume filename, fetch the file and parse it
  if (args.string) {
    args.package = fs.readFileSync(args.string, 'utf8');
    this.package = JSON.parse(args.package);        // the parsed file
    this.package.path = path.dirname(args.string);  // folder of the bundle
    this.package.source = args.package;             // stringified content
    this.package.location = args.string;            // location of the bundle
  }

  return this.parse();
};

/**
 * Parse the package.
 *
 * @param {Object} data
 * @api private
 */

Square.prototype.parse = function parse (data) {
  /**
   * Generate the weight of a single dependency.
   *
   * @param {Number} amount
   * @param {Number} padding
   * @return {Number}
   * @api private
   */

  function weight (amount, padding) {
    padding = padding < 10
      ? '0' + padding.toString(10)
      : padding.toString(10);

    return +(amount + '.' + padding);
  }

 /**
  * Does a deep merge on an object.
  *
  * @param {Object} target
  * @param {Object} additional
  * @api private
  */

  function merge (target, additional, deep, lastseen) {
    var seen = lastseen || []
      , depth = typeof deep === 'undefined' ? 2 : deep
      , prop;

    for (prop in additional) {
      if (additional.hasOwnProperty(prop) && seen.indexOf(prop) < 0) {
        if (typeof target[prop] !== 'object' || !depth) {
          target[prop] = additional[prop];
          seen.push(additional[prop]);
        } else {
          merge(target[prop], additional[prop], depth - 1, seen);
        }
      }
    }

    return target;
  }

  // default
  data = data || this.package;

  var dependencies = []
    , depended = {};

  Object.keys(data.bundle).forEach(function each (file, index, files) {
    var bundle = data.bundle[file]
      , base = data.path
      , location = basepath(file, base)
      , total;

    // add the current file to the dependency tree, as the last file so all
    // other dependencies are loaded before this file
    if (!Array.isArray(bundle.dependencies)) bundle.dependencies = [];
    if (!~bundle.dependencies.indexOf(file)) bundle.dependencies.push(file);

    // make sure it exists
    if (!path.existsSync(location)) {
      return this.logger.error(location + ' does not exist, cant read file');
    }

    // parse the data, and add some meta data
    bundle.content = fs.readFileSync(location, 'UTF8');
    bundle.meta = {
        location: location
      , path: base
      , extension: file.split('.').pop()
      , package: data
    };

    // find all the dependencies
    total = bundle.dependencies.length;
    bundle.dependencies.forEach(function each (file, index) {
      var amount = weight(bundle.weight || 1, total--);

      // the dependency always uses the highest weight it gets assigned
      if (!depended[file] || depended[file] < amount) depended[file] = amount;
      if (!~dependencies.indexOf(file)) dependencies.push(file);
    });
  }.bind(this));

  // sort the dependencies based on their assigned weight
  dependencies = dependencies.sort(function sort (a, b) {
    return depended[b] - depended[a];
  });

  // ensure that all dependencies are loaded correctly, so we don't generate any
  // files bundles with missing dependencies
  dependencies.some(function (file) {
    if (!data.bundle[file]) {
      this.logger.error('missing dependency: ' + file);
      return false;
    }

    return true;
  }.bind(this));

  // the package is now updated with the parsed data so we can use and abuse it
  this.package = data;

  // attach the dependencies for easy lookups
  this.package.dependencies = dependencies;

  // make sure there is a configuration, and if it's there merge it with our
  // default config so we are sure that every option is specified
  this.package.configuration = merge(this.config, this.package.configuration || {});

  // if there is a license file in the configuration we are going to parse it
  // out so we can use it
  var configuration = this.package.configuration
    , location;

  if (configuration.license) {
    location = basepath(configuration.license, this.package.path);

    if (!path.existsSync(location)) {
      this.logger.error(location + ' does not exit, cant read license file');
      delete this.package.configuration.license;
    } else {
      this.package.configuration.license = fs.readFileSync(location, 'UTF8');
    }
  }

  return this.emit('parse', this.package);
};

/**
 * Build the stuff.
 *
 * @api private
 */

Square.prototype.build = function build () {
  var layers = this.middleware.slice(0)
    , errors = []
    , self = this
    , backup;

  /**
   * Simple iteration helper function to process the middleware.
   *
   * @param {Mixed} err error or undef/null
   * @param {String} content
   * @api private
   */

  function iterate (err, content) {
    var layer = layers.shift();

    if (err) errors.push(err);
    if (content) backup = content;
    else content = backup;

    if (!layer) {
      if (errors.length) return self.logger.error('Failed to process content', errors);
      return self.write(content, 'min');
    }

    // capture errors that might be caused the middleware layers
    try { layer.call(self, content, iterate); }
    catch (e) { iterate.call(iterate, e, content); }
  }

  this.once('merge', function merged (content) {
    iterate(null, content);
    self.write(content, 'dev');
  });

  return this.merge();
};

/**
 * Process the template string.
 *
 * @param {String} str
 * @param {Object} data
 * @returns {String} result
 * @api private
 */

Square.prototype.template = function template (str, data) {
  data = data || this.package;

  for (var prop in data) {
    str = str.replace(new RegExp('{' + prop + '}', 'g'), data[prop]);
  }

  return str;
};

/**
 * Creates a tag / profile from the content so it can be used for processing.
 *
 * @param {String} content
 * @param {String} type
 * @param {String} extension
 * @returns {Object}
 * @api public
 */

Square.prototype.tag = function tag (content, type, extension) {
  var branch = exec('git branch', { silent:true }).output
    , sha = exec('git show -s', { silent:true }).output
    , date = new Date();

  if (branch) {
    branch = /\*\s([\w\.]+)/g.exec(branch) || '';
    branch = branch.length ? branch[1] : branch;
  }

  if (sha) {
    sha = /commit\s(\w+)/g.exec(sha) || '';
    sha = sha.length ? sha[1] : sha;
  }

  return _.extend({
      type: type || 'min'
    , md5: createHash('md5').update(content).digest('hex')
    , branch: branch
    , sha: sha
    , ext: extension || 'js'
    , date: date.toLocaleDateString()
    , year: date.getFullYear()
    , user: process.env.USER || 'anonymous'
    , host: os.hostname()
  }, this.package.configuration.vars || {});
};

/**
 * Write the output of the file to a directory.
 *
 * @param {String} content
 * @param {String} type
 * @param {String} extension
 * @api private
 */

Square.prototype.write = function write (content, type, extension) {
  var configuration = this.package.configuration
    , output = configuration.dist[type].replace(/^~/g, process.env.HOME)
    , file = this.template(output, this.tag.apply(this, arguments));

  file = path.resolve(file);
  content = this.license.apply(this, arguments);

  this.logger.info('writing', file);

  fs.writeFile(file, content, function written (err) {
    if (err) this.logger.error(err);
  }.bind(this));
};

/**
 * Merge all the dependencies in to one single file.
 *
 * @api private
 */

Square.prototype.merge = function merge () {
  var bundle = this.package.bundle
    , concat = []
    , self = this;

  if (!bundle || !this.package.dependencies) return this;

  /**
   * Search the code for require statements, parse it out and inline the
   * content's of the required file.
   *
   * @param {String} match complete matched result
   * @param {String} commenttype type of comment
   * @param {String} statement import statement name
   * @param {String} file the file that needs to be inlined
   * @returns {String}
   * @api private
   */

  function insert (match, commenttype, statement, file) {
    var location = basepath(file, self.package.path);

    return fs.readFileSync(location, 'UTF8');
  }

  this.package.dependencies.forEach(function each (file) {
    var content = bundle[file].content.toString('UTF8');

    content = content.split('\n')
      .map(function inspect (line) { return line.replace(self.reqparse, insert); })
      .join('\n');

    concat.push(content);
  });

  // emit a merge event
  this.emit('merge', concat.join('\n'));
  return this;
};

/**
 * Check if we need to prepend a license file.
 *
 * @param {String} content
 * @param {String} type
 * @param {String} extension
 * @returns {String}
 * @api private
 */

Square.prototype.license = function copyright (content, type, extenstion) {
  var configuration = this.package.configuration
    , license = configuration.license;

  if (!license) return content;

  // process the template with some variables
  license = this.template(license, this.tag.apply(this, arguments));
  return license + content;
};
<|endoftext|>


<commit_before>/**
  This is a jQuery plugin to support autocompleting values in our text fields.

  @module $.fn.autocomplete
**/
$.fn.autocomplete = function(options) {

  var autocompletePlugin = this;

  if (this.length === 0) return;

  if (options && options.cancel && this.data("closeAutocomplete")) {
    this.data("closeAutocomplete")();
    return this;
  }

  if (this.length !== 1) {
    alert("only supporting one matcher at the moment");
  }

  var disabled = options && options.disabled;
  var wrap = null;
  var autocompleteOptions = null;
  var selectedOption = null;
  var completeStart = null;
  var completeEnd = null;
  var me = this;
  var div = null;

  // input is handled differently
  var isInput = this[0].tagName === "INPUT";
  var inputSelectedItems = [];

  var closeAutocomplete = function() {
    if (div) {
      div.hide().remove();
    }
    div = null;
    completeStart = null;
    autocompleteOptions = null;
  };

  var addInputSelectedItem = function(item) {
    var transformed;
    if (options.transformComplete) {
      transformed = options.transformComplete(item);
    }
    var d = $("
" + (transformed || item) + "
");
    var prev = me.parent().find('.item:last');
    if (prev.length === 0) {
      me.parent().prepend(d);
    } else {
      prev.after(d);
    }
    inputSelectedItems.push(item);
    if (options.onChangeItems) {
      options.onChangeItems(inputSelectedItems);
    }
    return d.find('a').click(function() {
      closeAutocomplete();
      inputSelectedItems.splice($.inArray(item), 1);
      $(this).parent().parent().remove();
      if (options.onChangeItems) {
        return options.onChangeItems(inputSelectedItems);
      }
    });
  };

  var completeTerm = function(term) {
    if (term) {
      if (isInput) {
        me.val("");
        addInputSelectedItem(term);
      } else {
        if (options.transformComplete) {
          term = options.transformComplete(term);
        }
        var text = me.val();
        text = text.substring(0, completeStart) + (options.key || "") + term + ' ' + text.substring(completeEnd + 1, text.length);
        me.val(text);
        Discourse.Utilities.setCaretPosition(me[0], completeStart + 1 + term.length);
      }
    }
    closeAutocomplete();
  };

  if (isInput) {
    var width = this.width();
    var height = this.height();
    wrap = this.wrap("
").parent();
    wrap.width(width);
    this.width(150);
    this.attr('name', this.attr('name') + "-renamed");
    var vals = this.val().split(",");
    _.each(vals,function(x) {
      if (x !== "") {
        if (options.reverseTransform) {
          x = options.reverseTransform(x);
        }
        return addInputSelectedItem(x);
      }
    });
    this.val("");
    completeStart = 0;
    wrap.click(function() {
      autocompletePlugin.focus();
      return true;
    });
  }

  var markSelected = function() {
    var links = div.find('li a');
    links.removeClass('selected');
    return $(links[selectedOption]).addClass('selected');
  };

  var renderAutocomplete = function() {
    if (div) {
      div.hide().remove();
    }
    if (autocompleteOptions.length === 0) return;

    div = $(options.template({ options: autocompleteOptions }));

    var ul = div.find('ul');
    selectedOption = 0;
    markSelected();
    ul.find('li').click(function() {
      selectedOption = ul.find('li').index(this);
      completeTerm(autocompleteOptions[selectedOption]);
      return false;
    });
    var pos = null;
    var vOffset = 0;
    var hOffset = 0;
    if (isInput) {
      pos = {
        left: 0,
        top: 0
      };
      vOffset = -32;
      hOffset = 0;
    } else {
      pos = me.caretPosition({
        pos: completeStart,
        key: options.key
      });
      vOffset = div.height();
      hOffset = 27;
    }
    div.css({
      left: "-1000px"
    });
    me.parent().append(div);
    var mePos = me.position();
    var borderTop = parseInt(me.css('border-top-width'), 10) || 0;
    div.css({
      position: 'absolute',
      top: (mePos.top + pos.top - vOffset + borderTop) + 'px',
      left: (mePos.left + pos.left + hOffset) + 'px'
    });
  };

  var updateAutoComplete = function(r) {
    if (completeStart === null) return;

    autocompleteOptions = r;
    if (!r || r.length === 0) {
      closeAutocomplete();
    } else {
      renderAutocomplete();
    }
  };

  // chain to allow multiples
  var oldClose = me.data("closeAutocomplete");
  me.data("closeAutocomplete", function() {
    if (oldClose) {
      oldClose();
    }
    return closeAutocomplete();
  });

  $(this).keypress(function(e) {
    if (!options.key) return;

    // keep hunting backwards till you hit a
    if (e.which === options.key.charCodeAt(0)) {
      var caretPosition = Discourse.Utilities.caretPosition(me[0]);
      var prevChar = me.val().charAt(caretPosition - 1);
      if (!prevChar || /\s/.test(prevChar)) {
        completeStart = completeEnd = caretPosition;
        var term = "";
        options.dataSource(term).then(updateAutoComplete);
      }
    }
  });

  return $(this).keydown(function(e) {
    var c, caretPosition, i, initial, next, nextIsGood, prev, prevIsGood, stopFound, term, total, userToComplete;
    if (!options.key) {
      completeStart = 0;
    }
    if (e.which === 16) return;
    if ((completeStart === null) && e.which === 8 && options.key) {
      c = Discourse.Utilities.caretPosition(me[0]);
      next = me[0].value[c];
      nextIsGood = next === void 0 || /\s/.test(next);
      c -= 1;
      initial = c;
      prevIsGood = true;
      while (prevIsGood && c >= 0) {
        c -= 1;
        prev = me[0].value[c];
        stopFound = prev === options.key;
        if (stopFound) {
          prev = me[0].value[c - 1];
          if (!prev || /\s/.test(prev)) {
            completeStart = c;
            caretPosition = completeEnd = initial;
            term = me[0].value.substring(c + 1, initial);
            options.dataSource(term).then(updateAutoComplete);
            return true;
          }
        }
        prevIsGood = /[a-zA-Z\.]/.test(prev);
      }
    }

    // ESC
    if (e.which === 27) {
      if (completeStart !== null) {
        closeAutocomplete();
        return false;
      }
      return true;
    }

    if (completeStart !== null) {
      caretPosition = Discourse.Utilities.caretPosition(me[0]);

      // If we've backspaced past the beginning, cancel unless no key
      if (caretPosition <= completeStart && options.key) {
        closeAutocomplete();
        return false;
      }

      // Keyboard codes! So 80's.
      switch (e.which) {
        case 13:
        case 39:
        case 9:
          if (!autocompleteOptions) return true;
          if (selectedOption >= 0 && (userToComplete = autocompleteOptions[selectedOption])) {
            completeTerm(userToComplete);
          } else {
            // We're cancelling it, really.
            return true;
          }
          closeAutocomplete();
          return false;
        case 38:
          selectedOption = selectedOption - 1;
          if (selectedOption < 0) {
            selectedOption = 0;
          }
          markSelected();
          return false;
        case 40:
          total = autocompleteOptions.length;
          selectedOption = selectedOption + 1;
          if (selectedOption >= total) {
            selectedOption = total - 1;
          }
          if (selectedOption < 0) {
            selectedOption = 0;
          }
          markSelected();
          return false;
        default:
          // otherwise they're typing - let's search for it!
          completeEnd = caretPosition;
          if (e.which === 8) {
            caretPosition--;
          }
          if (caretPosition < 0) {
            closeAutocomplete();
            if (isInput) {
              i = wrap.find('a:last');
              if (i) {
                i.click();
              }
            }
            return false;
          }
          term = me.val().substring(completeStart + (options.key ? 1 : 0), caretPosition);
          if (e.which >= 48 && e.which <= 90) {
            term += String.fromCharCode(e.which);
          } else if (e.which === 187) {
            term += "+";
          } else if (e.which === 189) {
            term += "-";
          } else {
            if (e.which !== 8) {
              term += ",";
            }
          }
          options.dataSource(term).then(updateAutoComplete);
          return true;
      }
    }
  });
};
<commit_msg>fix positioning regression<commit_after>/**
  This is a jQuery plugin to support autocompleting values in our text fields.

  @module $.fn.autocomplete
**/
$.fn.autocomplete = function(options) {

  var autocompletePlugin = this;

  if (this.length === 0) return;

  if (options && options.cancel && this.data("closeAutocomplete")) {
    this.data("closeAutocomplete")();
    return this;
  }

  if (this.length !== 1) {
    alert("only supporting one matcher at the moment");
  }

  var disabled = options && options.disabled;
  var wrap = null;
  var autocompleteOptions = null;
  var selectedOption = null;
  var completeStart = null;
  var completeEnd = null;
  var me = this;
  var div = null;

  // input is handled differently
  var isInput = this[0].tagName === "INPUT";
  var inputSelectedItems = [];

  var closeAutocomplete = function() {
    if (div) {
      div.hide().remove();
    }
    div = null;
    completeStart = null;
    autocompleteOptions = null;
  };

  var addInputSelectedItem = function(item) {
    var transformed;
    if (options.transformComplete) {
      transformed = options.transformComplete(item);
    }
    var d = $("
" + (transformed || item) + "
");
    var prev = me.parent().find('.item:last');
    if (prev.length === 0) {
      me.parent().prepend(d);
    } else {
      prev.after(d);
    }
    inputSelectedItems.push(item);
    if (options.onChangeItems) {
      options.onChangeItems(inputSelectedItems);
    }
    return d.find('a').click(function() {
      closeAutocomplete();
      inputSelectedItems.splice($.inArray(item), 1);
      $(this).parent().parent().remove();
      if (options.onChangeItems) {
        return options.onChangeItems(inputSelectedItems);
      }
    });
  };

  var completeTerm = function(term) {
    if (term) {
      if (isInput) {
        me.val("");
        addInputSelectedItem(term);
      } else {
        if (options.transformComplete) {
          term = options.transformComplete(term);
        }
        var text = me.val();
        text = text.substring(0, completeStart) + (options.key || "") + term + ' ' + text.substring(completeEnd + 1, text.length);
        me.val(text);
        Discourse.Utilities.setCaretPosition(me[0], completeStart + 1 + term.length);
      }
    }
    closeAutocomplete();
  };

  if (isInput) {
    var width = this.width();
    var height = this.height();
    wrap = this.wrap("
").parent();
    wrap.width(width);
    this.width(150);
    this.attr('name', this.attr('name') + "-renamed");
    var vals = this.val().split(",");
    _.each(vals,function(x) {
      if (x !== "") {
        if (options.reverseTransform) {
          x = options.reverseTransform(x);
        }
        return addInputSelectedItem(x);
      }
    });
    this.val("");
    completeStart = 0;
    wrap.click(function() {
      autocompletePlugin.focus();
      return true;
    });
  }

  var markSelected = function() {
    var links = div.find('li a');
    links.removeClass('selected');
    return $(links[selectedOption]).addClass('selected');
  };

  var renderAutocomplete = function() {
    if (div) {
      div.hide().remove();
    }
    if (autocompleteOptions.length === 0) return;

    div = $(options.template({ options: autocompleteOptions }));

    var ul = div.find('ul');
    selectedOption = 0;
    markSelected();
    ul.find('li').click(function() {
      selectedOption = ul.find('li').index(this);
      completeTerm(autocompleteOptions[selectedOption]);
      return false;
    });
    var pos = null;
    var vOffset = 0;
    var hOffset = 0;
    if (isInput) {
      pos = {
        left: 0,
        top: 0
      };
      vOffset = -32;
      hOffset = 0;
    } else {
      pos = me.caretPosition({
        pos: completeStart,
        key: options.key
      });
      hOffset = 27;
    }
    div.css({
      left: "-1000px"
    });

    me.parent().append(div);

    if(!isInput){
      vOffset = div.height();
    }

    var mePos = me.position();
    var borderTop = parseInt(me.css('border-top-width'), 10) || 0;
    div.css({
      position: 'absolute',
      top: (mePos.top + pos.top - vOffset + borderTop) + 'px',
      left: (mePos.left + pos.left + hOffset) + 'px'
    });
  };

  var updateAutoComplete = function(r) {
    if (completeStart === null) return;

    autocompleteOptions = r;
    if (!r || r.length === 0) {
      closeAutocomplete();
    } else {
      renderAutocomplete();
    }
  };

  // chain to allow multiples
  var oldClose = me.data("closeAutocomplete");
  me.data("closeAutocomplete", function() {
    if (oldClose) {
      oldClose();
    }
    return closeAutocomplete();
  });

  $(this).keypress(function(e) {
    if (!options.key) return;

    // keep hunting backwards till you hit a
    if (e.which === options.key.charCodeAt(0)) {
      var caretPosition = Discourse.Utilities.caretPosition(me[0]);
      var prevChar = me.val().charAt(caretPosition - 1);
      if (!prevChar || /\s/.test(prevChar)) {
        completeStart = completeEnd = caretPosition;
        var term = "";
        options.dataSource(term).then(updateAutoComplete);
      }
    }
  });

  return $(this).keydown(function(e) {
    var c, caretPosition, i, initial, next, nextIsGood, prev, prevIsGood, stopFound, term, total, userToComplete;
    if (!options.key) {
      completeStart = 0;
    }
    if (e.which === 16) return;
    if ((completeStart === null) && e.which === 8 && options.key) {
      c = Discourse.Utilities.caretPosition(me[0]);
      next = me[0].value[c];
      nextIsGood = next === void 0 || /\s/.test(next);
      c -= 1;
      initial = c;
      prevIsGood = true;
      while (prevIsGood && c >= 0) {
        c -= 1;
        prev = me[0].value[c];
        stopFound = prev === options.key;
        if (stopFound) {
          prev = me[0].value[c - 1];
          if (!prev || /\s/.test(prev)) {
            completeStart = c;
            caretPosition = completeEnd = initial;
            term = me[0].value.substring(c + 1, initial);
            options.dataSource(term).then(updateAutoComplete);
            return true;
          }
        }
        prevIsGood = /[a-zA-Z\.]/.test(prev);
      }
    }

    // ESC
    if (e.which === 27) {
      if (completeStart !== null) {
        closeAutocomplete();
        return false;
      }
      return true;
    }

    if (completeStart !== null) {
      caretPosition = Discourse.Utilities.caretPosition(me[0]);

      // If we've backspaced past the beginning, cancel unless no key
      if (caretPosition <= completeStart && options.key) {
        closeAutocomplete();
        return false;
      }

      // Keyboard codes! So 80's.
      switch (e.which) {
        case 13:
        case 39:
        case 9:
          if (!autocompleteOptions) return true;
          if (selectedOption >= 0 && (userToComplete = autocompleteOptions[selectedOption])) {
            completeTerm(userToComplete);
          } else {
            // We're cancelling it, really.
            return true;
          }
          closeAutocomplete();
          return false;
        case 38:
          selectedOption = selectedOption - 1;
          if (selectedOption < 0) {
            selectedOption = 0;
          }
          markSelected();
          return false;
        case 40:
          total = autocompleteOptions.length;
          selectedOption = selectedOption + 1;
          if (selectedOption >= total) {
            selectedOption = total - 1;
          }
          if (selectedOption < 0) {
            selectedOption = 0;
          }
          markSelected();
          return false;
        default:
          // otherwise they're typing - let's search for it!
          completeEnd = caretPosition;
          if (e.which === 8) {
            caretPosition--;
          }
          if (caretPosition < 0) {
            closeAutocomplete();
            if (isInput) {
              i = wrap.find('a:last');
              if (i) {
                i.click();
              }
            }
            return false;
          }
          term = me.val().substring(completeStart + (options.key ? 1 : 0), caretPosition);
          if (e.which >= 48 && e.which <= 90) {
            term += String.fromCharCode(e.which);
          } else if (e.which === 187) {
            term += "+";
          } else if (e.which === 189) {
            term += "-";
          } else {
            if (e.which !== 8) {
              term += ",";
            }
          }
          options.dataSource(term).then(updateAutoComplete);
          return true;
      }
    }
  });
};
<|endoftext|>


<commit_before>function addSearch(id) {
    let searchbar = $('<input>').addClass("searchbar").attr('placeholder', "Search Table...");

    $(searchbar).on("keyup", function(){
        let value = $(this).val().toLowerCase();

        if(value === "") {
            removeSearch(id);
            return;
        }

        $('#'+id +" .table-row").filter(function(){
            $(this).removeClass("search-result");
            if($(this).text().toLowerCase().indexOf(value) > -1){
                $(this).addClass("search-result").show();
            }
        });
        updatePage_help(id, 0, $('#'+id).data('currentPageSize'), true);
    });
    $('#'+id).parent().prepend(searchbar);
}

function addSearchServer(id) {
    let searchbar = $('<input>').addClass("searchbar").attr('placeholder', "Search Table...");

    $(searchbar).on("keyup", function(){
        let value = $(this).val().toLowerCase();

        if(value === "") {
            removeSearch(id);
            return;
        }
        $('#' + id + " .table-row").remove();
        updatePage(id, 0, $('#'+id).data('currentPageSize'),-1, false, $('#'+id).data('params'), value);
    });
    $('#'+id).parent().prepend(searchbar);
}

function removeSearch(id) {
    $('#'+id +" .table-row").removeClass("search-result");
    updatePage_help(id, 0, $('#'+id).data('currentPageSize'));
}
<commit_msg>server side search clear search results when search box is empty<commit_after>function addSearch(id) {
    let searchbar = $('<input>').addClass("searchbar").attr('placeholder', "Search Table...");

    $(searchbar).on("keyup", function(){
        let value = $(this).val().toLowerCase();

        if(value === "") {
            removeSearch(id);
            return;
        }

        $('#'+id +" .table-row").filter(function(){
            $(this).removeClass("search-result");
            if($(this).text().toLowerCase().indexOf(value) > -1){
                $(this).addClass("search-result").show();
            }
        });
        updatePage_help(id, 0, $('#'+id).data('currentPageSize'), true);
    });
    $('#'+id).parent().prepend(searchbar);
}

function addSearchServer(id) {
    let searchbar = $('<input>').addClass("searchbar").attr('placeholder', "Search Table...");

    $(searchbar).on("keyup", function(){
        let value = $(this).val().toLowerCase();

        if(value === "") {
            $('#' + id + " .table-row").remove();
            removeSearch(id);
            return;
        }
        $('#' + id + " .table-row").remove();
        updatePage(id, 0, $('#'+id).data('currentPageSize'),-1, false, $('#'+id).data('params'), value);
    });
    $('#'+id).parent().prepend(searchbar);
}

function removeSearch(id) {
    $('#'+id +" .table-row").removeClass("search-result");
    updatePage_help(id, 0, $('#'+id).data('currentPageSize'));
}
<|endoftext|>


<commit_before>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';

import provide from 'react-redux-provide';

// Components
import AppBar from 'material-ui/lib/app-bar';

import TextField from 'material-ui/lib/text-field';

import IconMenu from 'material-ui/lib/menus/icon-menu';
import MenuItem from 'material-ui/lib/menus/menu-item';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';

import DropDownMenu from 'material-ui/lib/DropDownMenu';
import RaisedButton from 'material-ui/lib/raised-button';
import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import IconButton from 'material-ui/lib/icon-button';
import MoreVertIcon from 'material-ui/lib/svg-icons/navigation/more-vert';

import DialectDropDown from 'views/components/Navigation/DialectDropDown';
import Login from 'views/components/Navigation/Login';
import AppLeftNav from 'views/components/Navigation/AppLeftNav';

@provide
export default class Navigation extends Component {

  static propTypes = {
    pushWindowPath: PropTypes.func.isRequired,
    replaceWindowPath: PropTypes.func.isRequired,
    splitWindowPath: PropTypes.array.isRequired,
    toggleMenuAction: PropTypes.func.isRequired,
    properties: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    routeParams: PropTypes.object
  };

  /*static childContextTypes = {
    client: React.PropTypes.object,
    muiTheme: React.PropTypes.object,
    siteProps: React.PropTypes.object
  };

  static contextTypes = {
      muiTheme: React.PropTypes.object.isRequired,
      siteProps: React.PropTypes.object.isRequired
  };

  getChildContext() {
    return {
      //client: this.props.clientStore.client,
      muiTheme: this.context.muiTheme,
      siteProps: this.context.siteProps
    };
  }*/

  constructor(props, context){
    super(props, context);

    this.state = {
      hintTextSearch: "Search:"
    };

    this._handleMenuToggle = this._handleMenuToggle.bind(this);
    this.handleChangeRequestLeftNav = this.handleChangeRequestLeftNav.bind(this);
    this.handleRequestChangeList = this.handleRequestChangeList.bind(this);
    this._handleNavigationSearchSubmit = this._handleNavigationSearchSubmit.bind(this);
    //this._test = this._test.bind(this);
  }

  _handleMenuToggle (event) {
    //console.log(event);

    //const test = this.props.toggle("helloworld");
    //console.log(test);

    /*this.setState({
      leftNavOpen: !this.state.leftNavOpen,
    });*/
  }

  handleChangeRequestLeftNav(open) {
    console.log('ok2!');
    this.setState({
      leftNavOpen: open,
    });
  }

  handleRequestChangeList(event, value) {
    console.log('ok!');
    //this.context.router.push(value);
    this.setState({
      leftNavOpen: false,
    });
  }

  _handleNavigationSearchSubmit() {
	  let searchQueryParam = this.refs.navigationSearchField.getValue();
      let path = "/" + this.props.splitWindowPath.join("/");
      let queryPath = "";

      // Do a global search in either the workspace or section
      if(path.includes("/explore/FV/Workspaces/Data")) {
    	  queryPath = "/explore/FV/Workspaces/Data"
      }
      else if(path.includes("/explore/FV/sections/Data")) {
    	  queryPath = "/explore/FV/sections/Data"
      }
      else {
    	  queryPath = "/explore/FV/sections/Data"
      }

      // Clear out the input field
      this.refs.navigationSearchField.setValue("");
	  this.props.replaceWindowPath(queryPath + '/search/' + searchQueryParam);
  }

  render() {

    return

        <AppBar
          title={this.props.properties.title}
          onLeftIconButtonTouchTap={() => this.props.toggleMenuAction("AppLeftNav")}>

          <ToolbarGroup>
            <Login label="Sign in"/>

            <ToolbarSeparator style={{float: 'none', marginRight: '30px'}} />

            {/* KeymanWeb workaround for hinttext not disappearing */}
            <TextField ref="navigationSearchField" hintText={this.state.hintTextSearch} onBlur={() => this.setState({hintTextSearch: 'Search:'})} onFocus={() => this.setState({hintTextSearch: ''})} onEnterKeyDown={this._handleNavigationSearchSubmit} />

            <IconMenu
                iconButtonElement={
                  <IconButton><MoreVertIcon /></IconButton>
                }
                targetOrigin={{horizontal: 'right', vertical: 'top'}}
                anchorOrigin={{horizontal: 'right', vertical: 'top'}}
              >
                <MenuItem primaryText="Refresh" />
                <MenuItem primaryText="Help" />
                <MenuItem primaryText="Sign out" />
            </IconMenu>
          </ToolbarGroup>

        </AppBar>

        <Toolbar>

          <ToolbarGroup float="right">
            <DialectDropDown routeParams={this.props.routeParams} />
          </ToolbarGroup>

        </Toolbar>

        <AppLeftNav
          test="me1!"
          menu={{main: true}}
          open={false}
          //onRequestChangeLeftNav={this.handleChangeRequestLeftNav}
          //onRequestChangeList={this.handleRequestChangeList}
          docked={false} />

;
  }
}<commit_msg>More descriptive search hint text<commit_after>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';

import provide from 'react-redux-provide';

// Components
import AppBar from 'material-ui/lib/app-bar';

import TextField from 'material-ui/lib/text-field';

import IconMenu from 'material-ui/lib/menus/icon-menu';
import MenuItem from 'material-ui/lib/menus/menu-item';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';

import DropDownMenu from 'material-ui/lib/DropDownMenu';
import RaisedButton from 'material-ui/lib/raised-button';
import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import IconButton from 'material-ui/lib/icon-button';
import MoreVertIcon from 'material-ui/lib/svg-icons/navigation/more-vert';

import DialectDropDown from 'views/components/Navigation/DialectDropDown';
import Login from 'views/components/Navigation/Login';
import AppLeftNav from 'views/components/Navigation/AppLeftNav';

@provide
export default class Navigation extends Component {

  static propTypes = {
    pushWindowPath: PropTypes.func.isRequired,
    replaceWindowPath: PropTypes.func.isRequired,
    splitWindowPath: PropTypes.array.isRequired,
    toggleMenuAction: PropTypes.func.isRequired,
    properties: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    routeParams: PropTypes.object
  };

  /*static childContextTypes = {
    client: React.PropTypes.object,
    muiTheme: React.PropTypes.object,
    siteProps: React.PropTypes.object
  };

  static contextTypes = {
      muiTheme: React.PropTypes.object.isRequired,
      siteProps: React.PropTypes.object.isRequired
  };

  getChildContext() {
    return {
      //client: this.props.clientStore.client,
      muiTheme: this.context.muiTheme,
      siteProps: this.context.siteProps
    };
  }*/

  constructor(props, context){
    super(props, context);

    this.state = {
      hintTextSearch: "Search site:"
    };

    this._handleMenuToggle = this._handleMenuToggle.bind(this);
    this.handleChangeRequestLeftNav = this.handleChangeRequestLeftNav.bind(this);
    this.handleRequestChangeList = this.handleRequestChangeList.bind(this);
    this._handleNavigationSearchSubmit = this._handleNavigationSearchSubmit.bind(this);
    //this._test = this._test.bind(this);
  }

  _handleMenuToggle (event) {
    //console.log(event);

    //const test = this.props.toggle("helloworld");
    //console.log(test);

    /*this.setState({
      leftNavOpen: !this.state.leftNavOpen,
    });*/
  }

  handleChangeRequestLeftNav(open) {
    console.log('ok2!');
    this.setState({
      leftNavOpen: open,
    });
  }

  handleRequestChangeList(event, value) {
    console.log('ok!');
    //this.context.router.push(value);
    this.setState({
      leftNavOpen: false,
    });
  }

  _handleNavigationSearchSubmit() {
	  let searchQueryParam = this.refs.navigationSearchField.getValue();
      let path = "/" + this.props.splitWindowPath.join("/");
      let queryPath = "";

      // Do a global search in either the workspace or section
      if(path.includes("/explore/FV/Workspaces/Data")) {
    	  queryPath = "/explore/FV/Workspaces/Data"
      }
      else if(path.includes("/explore/FV/sections/Data")) {
    	  queryPath = "/explore/FV/sections/Data"
      }
      else {
    	  queryPath = "/explore/FV/sections/Data"
      }

      // Clear out the input field
      this.refs.navigationSearchField.setValue("");
	  this.props.replaceWindowPath(queryPath + '/search/' + searchQueryParam);
  }

  render() {

    return

        <AppBar
          title={this.props.properties.title}
          onLeftIconButtonTouchTap={() => this.props.toggleMenuAction("AppLeftNav")}>

          <ToolbarGroup>
            <Login label="Sign in"/>

            <ToolbarSeparator style={{float: 'none', marginRight: '30px'}} />

            {/* KeymanWeb workaround for hinttext not disappearing */}
            <TextField ref="navigationSearchField" hintText={this.state.hintTextSearch} onBlur={() => this.setState({hintTextSearch: 'Search:'})} onFocus={() => this.setState({hintTextSearch: ''})} onEnterKeyDown={this._handleNavigationSearchSubmit} />

            <IconMenu
                iconButtonElement={
                  <IconButton><MoreVertIcon /></IconButton>
                }
                targetOrigin={{horizontal: 'right', vertical: 'top'}}
                anchorOrigin={{horizontal: 'right', vertical: 'top'}}
              >
                <MenuItem primaryText="Refresh" />
                <MenuItem primaryText="Help" />
                <MenuItem primaryText="Sign out" />
            </IconMenu>
          </ToolbarGroup>

        </AppBar>

        <Toolbar>

          <ToolbarGroup float="right">
            <DialectDropDown routeParams={this.props.routeParams} />
          </ToolbarGroup>

        </Toolbar>

        <AppLeftNav
          test="me1!"
          menu={{main: true}}
          open={false}
          //onRequestChangeLeftNav={this.handleChangeRequestLeftNav}
          //onRequestChangeList={this.handleRequestChangeList}
          docked={false} />

;
  }
}<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require("path"),
    zlib = require('zlib'),
    util = require('util'),

    async = require('async'),
    mime = require('mime'),

    package_info = require('../package.json'),
    googleAnalytics = require('./googleanalyticsstream');

function setGa(ga) {
    googleAnalytics = ga;
}

// memoize = cache the results so that the file is only loaded from the hdd once
var getRawFile = async.memoize(function(name, cb) {
    fs.readFile(path.join(__dirname, '../public/', name), function(err, data) {
        if (err) {
            return cb(err);
        }
        var uncompressed = data.toString();
        uncompressed = uncompressed.replace('{version}', package_info.version);
        uncompressed = googleAnalytics.addGa(uncompressed);
        return cb(null, uncompressed);
    });
});

var DEFLATE = 'deflate',
    GZIP = 'gzip';
var getCompressedFile = async.memoize(function(file, compression, cb) {
    getRawFile(file, function(err, data) {
        if (err) {
            return cb(err);
        }
        if (compression == DEFLATE) zlib.deflate(data, cb);
        else if (compression == GZIP) zlib.gzip(data, cb);
        else process.nextTick(cb.bind(cb, null, data));
    });
});

function serveStatic(request, response) {

    var headers = {
        "content-type": mime.lookup(request.url)
    };

    if ((request.headers['accept-encoding'] || '')
        .match(/\bdeflate\b/)) {
        headers['content-encoding'] = DEFLATE;
    } else if ((request.headers['accept-encoding'] || '')
        .match(/\bgzip\b/)) {
        headers['content-encoding'] = GZIP;
    }

    getCompressedFile(request.url, headers['content-encoding'], function(err, data) {
        if (err) {
            response.writeHead(500, {
                "content-type": "text/plain"
            });
            return response.end(util.inspect(err));
        }
        response.writeHead(200, headers);
        response.end(data);
    });
}

module.exports = serveStatic;
module.exports.setGa = setGa;
<commit_msg>prefer gzip over deflate because of the checksum<commit_after>var fs = require('fs'),
    path = require("path"),
    zlib = require('zlib'),
    util = require('util'),

    async = require('async'),
    mime = require('mime'),

    package_info = require('../package.json'),
    googleAnalytics = require('./googleanalyticsstream');

function setGa(ga) {
    googleAnalytics = ga;
}

// memoize = cache the results so that the file is only loaded from the hdd once
var getRawFile = async.memoize(function(name, cb) {
    fs.readFile(path.join(__dirname, '../public/', name), function(err, data) {
        if (err) {
            return cb(err);
        }
        var uncompressed = data.toString();
        uncompressed = uncompressed.replace('{version}', package_info.version);
        uncompressed = googleAnalytics.addGa(uncompressed);
        return cb(null, uncompressed);
    });
});

var DEFLATE = 'deflate',
    GZIP = 'gzip';
var getCompressedFile = async.memoize(function(file, compression, cb) {
    getRawFile(file, function(err, data) {
        if (err) {
            return cb(err);
        }
        if (compression == DEFLATE) zlib.deflate(data, cb);
        else if (compression == GZIP) zlib.gzip(data, cb);
        else process.nextTick(cb.bind(cb, null, data));
    });
});

function serveStatic(request, response) {

    var headers = {
        "content-type": mime.lookup(request.url)
    };

    if ((request.headers['accept-encoding'] || '').match(/\bgzip\b/)) {
        headers['content-encoding'] = GZIP;
    } else if ((request.headers['accept-encoding'] || '').match(/\bdeflate\b/)) {
        headers['content-encoding'] = DEFLATE;
    }

    getCompressedFile(request.url, headers['content-encoding'], function(err, data) {
        if (err) {
            response.writeHead(500, {
                "content-type": "text/plain"
            });
            return response.end(util.inspect(err));
        }
        response.writeHead(200, headers);
        response.end(data);
    });
}

module.exports = serveStatic;
module.exports.setGa = setGa;
<|endoftext|>