<commit_before>// # Eval plugin (eval)

/*
The eval plugin will evaluate a field's `eval` property and exchange those
properties for whatever the expression returns. Expressions are just JSON
except if the first element of an array is a string that starts with '@'. In
that case, the array is treated as a Lisp expression where the first element
refers to a function that is called with the rest of the elements as the
arguments. For example:

```js
['@sum', 1, 2]
```

will return the value 3.
*/

'use strict';

var _ = require('underscore');

module.exports = function (plugin) {

  var evalFunctionPlugins = plugin.requireAllOf('eval-function');
  var functions = {};
  _.each(evalFunctionPlugins, function (fn, name) {
    var fnName = name.substring(name.indexOf('.') + 1);
    functions[fnName] = fn;
  });

  var isFunctionArray = function (array) {
    return array.length > 0 && array[0][0] === '@';
  };

  var evalFunction = function (fnArray, field) {
    var fnName = fnArray[0].substring(1);
    try {
      return functions[fnName](fnArray.slice(1), field);
    } catch (e) {
      if (!(fnName in functions)) {
        throw new Error('Eval function ' + fnName + ' not defined.');
      }
      throw e;
    }
  };

  var evaluate = function (expression, field) {
    if (_.isArray(expression)) {
      if (isFunctionArray(expression)) {
        return evalFunction(expression, field);
      } else {
        return expression.map(function (item) {
          return evaluate(item, field);
        });
      }
    } else if (_.isObject(expression)) {
      var obj = {};
      Object.keys(expression).forEach(function (key) {
        var result = evaluate(expression[key], field);
        if (typeof result !== 'undefined') {
          obj[key] = result;
        }
      });
      return obj;
    } else {
      return expression;
    }
  };

  plugin.exports.evaluate = evaluate;
};
<commit_msg>Finish comments for eval.<commit_after>// # Eval plugin (eval)

/*
The eval plugin will evaluate a field's `eval` property (which must be an
object) and exchange the properties of that object for whatever the
expression returns. Expressions are just JSON except if the first element of
an array is a string that starts with '@'. In that case, the array is
treated as a Lisp expression where the first element refers to a function
that is called with the rest of the elements as the arguments. For example:

```js
['@sum', 1, 2]
```

will return the value 3. The expression could be used in an `eval` property of
a field like:

```js
{
  type: 'string',
  key: 'name',
  eval: {
    rows: ['@sum', 1, 2]
  }
}
```

The `rows` property of the field would be set to 3 in this case.

Any plugin registered with the prefix `eval-function.` will be available as a
function in these expressions.
*/

'use strict';

var _ = require('underscore');

module.exports = function (plugin) {

  // Grab all the function plugins.
  var evalFunctionPlugins = plugin.requireAllOf('eval-function');

  // Just strip off the 'eval-functions.' prefix and put in a different object.
  var functions = {};
  _.each(evalFunctionPlugins, function (fn, name) {
    var fnName = name.substring(name.indexOf('.') + 1);
    functions[fnName] = fn;
  });

  // Check an array to see if it's a function expression.
  var isFunctionArray = function (array) {
    return array.length > 0 && array[0][0] === '@';
  };

  // Evaluate a function expression and return the result.
  var evalFunction = function (fnArray, field) {
    var fnName = fnArray[0].substring(1);
    try {
      return functions[fnName](fnArray.slice(1), field);
    } catch (e) {
      if (!(fnName in functions)) {
        throw new Error('Eval function ' + fnName + ' not defined.');
      }
      throw e;
    }
  };

  // Evaluate an expression in the context of a field.
  var evaluate = function (expression, field) {
    if (_.isArray(expression)) {
      if (isFunctionArray(expression)) {
        return evalFunction(expression, field);
      } else {
        return expression.map(function (item) {
          return evaluate(item, field);
        });
      }
    } else if (_.isObject(expression)) {
      var obj = {};
      Object.keys(expression).forEach(function (key) {
        var result = evaluate(expression[key], field);
        if (typeof result !== 'undefined') {
          obj[key] = result;
        }
      });
      return obj;
    } else {
      return expression;
    }
  };

  plugin.exports.evaluate = evaluate;
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('underscore');

module.exports = function (plugin) {

  var util = plugin.exports;

  util.isBlank = function (value) {
    return value === undefined || value === null || value === '';
  };

  // Set value at some path in object.
  util.setIn = function (obj, path, value) {
    if (_.isString(path)) {
      path = [path];
    }
    if (path.length === 0) {
      return value;
    }
    if (path.length === 1) {
      obj[path[0]] = value;
      return obj;
    }
    if (!obj[path[0]]) {
      obj[path[0]] = {};
    }
    util.setIn(obj[path[0]], path.slice(1), value);
    return obj;
  };

  // Remove value at path in some object.
  util.removeIn = function (obj, path) {
    if (_.isString(path)) {
      path = [path];
    }
    if (path.length === 0) {
      return null;
    }
    if (path.length === 1) {
      if (_.isArray(obj)) {
        if (_.isNumber(path[0])) {
          obj.splice(path[0], 1);
        }
      } else if (_.isObject(obj)) {
        delete obj[path[0]];
      }
      return obj;
    }
    if (obj[path[0]]) {
      util.removeIn(obj[path[0]], path.slice(1));
    }
    return obj;
  };

  // Get value at path in some object.
  util.getIn = function (obj, path) {
    if (_.isString(path)) {
      path = [path];
    }
    if (path.length === 0) {
      return obj;
    }
    if (obj[path[0]]) {
      return util.getIn(obj[path[0]], path.slice(1));
    }
    return null;
  };

  // Append to array at path in some object.
  util.appendIn = function (obj, path, value) {
    var subObj = util.getIn(obj, path);
    if (_.isArray(subObj)) {
      subObj.push(value);
    }
    return obj;
  };

  // Swap two keys at path in some object.
  util.moveIn = function (obj, path, fromKey, toKey) {
    var subObj = util.getIn(obj, path);
    if (_.isArray(subObj)) {
      if (_.isNumber(fromKey) && _.isNumber(toKey)) {
        var fromIndex = fromKey;
        var toIndex = toKey;
        if (fromIndex !== toIndex &&
          fromIndex >= 0 && fromIndex < subObj.length &&
          toIndex >= 0 && toIndex < subObj.length
        ) {
          subObj.splice(toIndex, 0, subObj.splice(fromIndex, 1)[0]);
        }
      }
    } else {
      var fromValue = subObj[fromKey];
      subObj[fromKey] = subObj[toKey];
      subObj[toKey] = fromValue;
    }
    return obj;
  };

  // Copy obj, leaving non-JSON behind.
  util.copyValue = function (value) {
    return JSON.parse(JSON.stringify(value));
  };

  // Copy obj recursing deeply.
  util.deepCopy = function (obj) {
    if (_.isArray(obj)) {
      return obj.map(function (item) {
        return util.deepCopy(item);
      });
    } else if (_.isObject(obj)) {
      var copy = {};
      _.each(obj, function (value, key) {
        copy[key] = util.deepCopy(value);
      });
      return copy;
    } else {
      return obj;
    }
  };

  // Check if item matches some value, based on the item's `match` property.
  util.itemMatchesValue = function (item, value) {
    var match = item.match;
    if (!match) {
      return true;
    }
    return _.every(_.keys(match), function (key) {
      return _.isEqual(match[key], value[key]);
    });
  };

  // Create a field definition from a value.
  util.fieldDefFromValue = function (value) {
    var def = {
      type: 'json'
    };
    if (_.isString(value)) {
      def = {
        type: 'string'
      };
    } else if (_.isArray(value)) {
      var arrayItemFields = value.map(function (value, i) {
        var childDef = util.fieldDefFromValue(value);
        childDef.key = i;
        return childDef;
      });
      def = {
        type: 'array',
        fields: arrayItemFields
      };
    } else if (_.isObject(value)) {
      var objectItemFields = Object.keys(value).map(function (key) {
        var childDef = util.fieldDefFromValue(value[key]);
        childDef.key = key;
        childDef.label = util.humanize(key);
        return childDef;
      });
      def = {
        type: 'object',
        fields: objectItemFields
      };
    } else if (_.isNull(value)) {
      def = {
        type: 'null'
      };
    }
    return def;
  };

  util.humanize = function(property) {
    property = property.replace(/\{\{/g, '');
    property = property.replace(/\}\}/g, '');
    return property.replace(/_/g, ' ')
      .replace(/(\w+)/g, function(match) {
        return match.charAt(0).toUpperCase() + match.slice(1);
      });
  };

  util.className = function () {

    var classNames = Array.prototype.slice.call(arguments, 0);

    classNames = classNames.filter(function (name) {
      return name;
    });

    return classNames.join(' ');
  };

  util.joinMetaKeys = function (keys) {
    return keys.join('::');
  };

  util.splitMetaKey = function (key) {
    return key.split('::');
  };

  var textPart = function (value, type) {
    type = type || 'text';
    return {
      type: type,
      value: value
    };
  };

  util.parseTextWithTags = function (value) {
    value = value || '';
    var parts = value.split(/{{(?!{)/);
    var frontPart = [];
    if (parts[0] !== '') {
      frontPart = [
        textPart(parts[0])
      ];
    }
    parts = frontPart.concat(
      parts.slice(1).map(function (part) {
        if (part.indexOf('}}') >= 0) {
          return [
            textPart(part.substring(0, part.indexOf('}}')), 'tag'),
            textPart(part.substring(part.indexOf('}}') + 2))
          ];
        } else {
          return textPart('{{' + part, 'text');
        }
      })
    );
    return [].concat.apply([], parts);
  };

  util.copyElementStyle = function (fromElement, toElement) {
    var fromStyle = window.getComputedStyle(fromElement, '');

    if (fromStyle.cssText !== '') {
      toElement.style.cssText = fromStyle.cssText;
      return;
    }

    var cssRules = [];
    for (var i = 0; i < fromStyle.length; i++) {
      //console.log(i, fromStyle[i], fromStyle.getPropertyValue(fromStyle[i]))
      //toElement.style[fromStyle[i]] = fromStyle.getPropertyValue(fromStyle[i]);
      cssRules.push(fromStyle[i] + ':' + fromStyle.getPropertyValue(fromStyle[i]) + ';');
    }
    var cssText = cssRules.join('');

    toElement.style.cssText = cssText;
  };

  var browser = {
    isChrome: false,
    isMozilla: false,
    isOpera: false,
    isIe: false,
    isSafari: false
  };

  var ua = navigator.userAgent;
  if(ua.indexOf('Chrome') > -1) {
    browser.isChrome = true;
  } else if (ua.indexOf('Safari') > -1) {
    browser.isSafari = true;
  } else if (ua.indexOf('Opera') > -1) {
    browser.isOpera = true;
  } else if (ua.indexOf('Firefox') > -1) {
    browser.isMozilla = true;
  } else if (ua.indexOf('MSIE') > -1) {
    browser.isIe = true;
  }

  util.browser = browser;

};
<commit_msg>Humanize fn should be pluggable.<commit_after>'use strict';

var _ = require('underscore');

module.exports = function (plugin) {

  var util = plugin.exports;

  util.isBlank = function (value) {
    return value === undefined || value === null || value === '';
  };

  // Set value at some path in object.
  util.setIn = function (obj, path, value) {
    if (_.isString(path)) {
      path = [path];
    }
    if (path.length === 0) {
      return value;
    }
    if (path.length === 1) {
      obj[path[0]] = value;
      return obj;
    }
    if (!obj[path[0]]) {
      obj[path[0]] = {};
    }
    util.setIn(obj[path[0]], path.slice(1), value);
    return obj;
  };

  // Remove value at path in some object.
  util.removeIn = function (obj, path) {
    if (_.isString(path)) {
      path = [path];
    }
    if (path.length === 0) {
      return null;
    }
    if (path.length === 1) {
      if (_.isArray(obj)) {
        if (_.isNumber(path[0])) {
          obj.splice(path[0], 1);
        }
      } else if (_.isObject(obj)) {
        delete obj[path[0]];
      }
      return obj;
    }
    if (obj[path[0]]) {
      util.removeIn(obj[path[0]], path.slice(1));
    }
    return obj;
  };

  // Get value at path in some object.
  util.getIn = function (obj, path) {
    if (_.isString(path)) {
      path = [path];
    }
    if (path.length === 0) {
      return obj;
    }
    if (obj[path[0]]) {
      return util.getIn(obj[path[0]], path.slice(1));
    }
    return null;
  };

  // Append to array at path in some object.
  util.appendIn = function (obj, path, value) {
    var subObj = util.getIn(obj, path);
    if (_.isArray(subObj)) {
      subObj.push(value);
    }
    return obj;
  };

  // Swap two keys at path in some object.
  util.moveIn = function (obj, path, fromKey, toKey) {
    var subObj = util.getIn(obj, path);
    if (_.isArray(subObj)) {
      if (_.isNumber(fromKey) && _.isNumber(toKey)) {
        var fromIndex = fromKey;
        var toIndex = toKey;
        if (fromIndex !== toIndex &&
          fromIndex >= 0 && fromIndex < subObj.length &&
          toIndex >= 0 && toIndex < subObj.length
        ) {
          subObj.splice(toIndex, 0, subObj.splice(fromIndex, 1)[0]);
        }
      }
    } else {
      var fromValue = subObj[fromKey];
      subObj[fromKey] = subObj[toKey];
      subObj[toKey] = fromValue;
    }
    return obj;
  };

  // Copy obj, leaving non-JSON behind.
  util.copyValue = function (value) {
    return JSON.parse(JSON.stringify(value));
  };

  // Copy obj recursing deeply.
  util.deepCopy = function (obj) {
    if (_.isArray(obj)) {
      return obj.map(function (item) {
        return util.deepCopy(item);
      });
    } else if (_.isObject(obj)) {
      var copy = {};
      _.each(obj, function (value, key) {
        copy[key] = util.deepCopy(value);
      });
      return copy;
    } else {
      return obj;
    }
  };

  // Check if item matches some value, based on the item's `match` property.
  util.itemMatchesValue = function (item, value) {
    var match = item.match;
    if (!match) {
      return true;
    }
    return _.every(_.keys(match), function (key) {
      return _.isEqual(match[key], value[key]);
    });
  };

  // Create a field definition from a value.
  util.fieldDefFromValue = function (value) {
    var def = {
      type: 'json'
    };
    if (_.isString(value)) {
      def = {
        type: 'string'
      };
    } else if (_.isArray(value)) {
      var arrayItemFields = value.map(function (value, i) {
        var childDef = util.fieldDefFromValue(value);
        childDef.key = i;
        return childDef;
      });
      def = {
        type: 'array',
        fields: arrayItemFields
      };
    } else if (_.isObject(value)) {
      var objectItemFields = Object.keys(value).map(function (key) {
        var childDef = util.fieldDefFromValue(value[key]);
        childDef.key = key;
        childDef.label = util.humanize(key);
        return childDef;
      });
      def = {
        type: 'object',
        fields: objectItemFields
      };
    } else if (_.isNull(value)) {
      def = {
        type: 'null'
      };
    }
    return def;
  };

  if (plugin.config.humanize) {
    util.humanize = plugin.require(plugin.config.humanize);
  } else {
    util.humanize = function(property) {
      property = property.replace(/\{\{/g, '');
      property = property.replace(/\}\}/g, '');
      return property.replace(/_/g, ' ')
        .replace(/(\w+)/g, function(match) {
          return match.charAt(0).toUpperCase() + match.slice(1);
        });
    };
  }

  util.className = function () {

    var classNames = Array.prototype.slice.call(arguments, 0);

    classNames = classNames.filter(function (name) {
      return name;
    });

    return classNames.join(' ');
  };

  util.joinMetaKeys = function (keys) {
    return keys.join('::');
  };

  util.splitMetaKey = function (key) {
    return key.split('::');
  };

  var textPart = function (value, type) {
    type = type || 'text';
    return {
      type: type,
      value: value
    };
  };

  util.parseTextWithTags = function (value) {
    value = value || '';
    var parts = value.split(/{{(?!{)/);
    var frontPart = [];
    if (parts[0] !== '') {
      frontPart = [
        textPart(parts[0])
      ];
    }
    parts = frontPart.concat(
      parts.slice(1).map(function (part) {
        if (part.indexOf('}}') >= 0) {
          return [
            textPart(part.substring(0, part.indexOf('}}')), 'tag'),
            textPart(part.substring(part.indexOf('}}') + 2))
          ];
        } else {
          return textPart('{{' + part, 'text');
        }
      })
    );
    return [].concat.apply([], parts);
  };

  util.copyElementStyle = function (fromElement, toElement) {
    var fromStyle = window.getComputedStyle(fromElement, '');

    if (fromStyle.cssText !== '') {
      toElement.style.cssText = fromStyle.cssText;
      return;
    }

    var cssRules = [];
    for (var i = 0; i < fromStyle.length; i++) {
      //console.log(i, fromStyle[i], fromStyle.getPropertyValue(fromStyle[i]))
      //toElement.style[fromStyle[i]] = fromStyle.getPropertyValue(fromStyle[i]);
      cssRules.push(fromStyle[i] + ':' + fromStyle.getPropertyValue(fromStyle[i]) + ';');
    }
    var cssText = cssRules.join('');

    toElement.style.cssText = cssText;
  };

  var browser = {
    isChrome: false,
    isMozilla: false,
    isOpera: false,
    isIe: false,
    isSafari: false
  };

  var ua = navigator.userAgent;
  if(ua.indexOf('Chrome') > -1) {
    browser.isChrome = true;
  } else if (ua.indexOf('Safari') > -1) {
    browser.isSafari = true;
  } else if (ua.indexOf('Opera') > -1) {
    browser.isOpera = true;
  } else if (ua.indexOf('Firefox') > -1) {
    browser.isMozilla = true;
  } else if (ua.indexOf('MSIE') > -1) {
    browser.isIe = true;
  }

  util.browser = browser;

};
<|endoftext|>


<commit_before>'use strict';

var CachingWriter = require('broccoli-caching-writer');
var path = require('path');
var fs = require('fs');
var uniq = require('lodash.uniq');
var mkdirp = require('mkdirp');
var cheerio = require('cheerio');

function ensurePosix(filePath) {
  if (path.sep !== '/') {
    return filePath.split(path.sep).join('/');
  }
  return filePath;
}

function getHelperKey(filePath) {
  return path.basename(filePath)
    .replace(/\.[^/.]+$/, '')
    .replace(/[\s]/g, '-');
}

function getSVGData(svgContent) {
  var $svg = cheerio.load(svgContent, { xmlMode: true })('svg');
  var viewBox = $svg.attr('viewBox');
  var viewBoxValues = viewBox.split(/\s+/);

  return {
    content: $svg.html(),
    viewBox: viewBox,
    width: $svg.attr('width') || viewBoxValues[2],
    height: $svg.attr('height') || viewBoxValues[3]
  };
}

function DemoBuilder(inputNode, options) {
  if (!options || !options.outputFile) {
    throw new Error('the outputFile option is required');
  }

  CachingWriter.call(this, [inputNode], {
    name: 'DemoBuilder',
    annotation: options.annotation,
  });

  /**
    All options:
    - outputFile,
    - strategy,
    - symbolsPrefix
  */
  this.options = options;
}

DemoBuilder.prototype = Object.create(CachingWriter.prototype);
DemoBuilder.prototype.constructor = DemoBuilder;

DemoBuilder.prototype.build = function() {
  var demoContent = JSON.stringify(this.getDemoModel());
  var outputFilePath = path.join(this.outputPath, this.options.outputFile);
  mkdirp.sync(path.dirname(outputFilePath));
  fs.writeFileSync(outputFilePath, demoContent);
};

DemoBuilder.prototype.getFilePaths = function() {
  var posixFilePaths = this.listFiles().map(ensurePosix);

  return uniq(posixFilePaths).filter(function(filePath) {
    // files returned from this.listFiles are directories if they end in /
    var isDirectory = filePath.charAt(filePath.length - 1) === '/';
    return !isDirectory;
  });
};

DemoBuilder.prototype.getDemoAssetUsage = function(relativePath) {
  var helperKey = getHelperKey(relativePath);

  if (this.options.strategy === 'symbol') {
    helperKey = '#' + this.options.symbolsPrefix + helperKey;
  }

  return '{{svg-jar "' + helperKey + '"}}';
};

DemoBuilder.prototype.getDemoModel = function() {
  var inputPath = this.inputPaths[0];
  var posixInputPath = ensurePosix(inputPath);
  var demoAssets = [];
  var _this = this;

  this.getFilePaths().forEach(function(posixFilePath) {
    var relativePath = posixFilePath.replace(posixInputPath + '/', '');
    var filePath = path.join(inputPath, relativePath);
    var svgConent = fs.readFileSync(filePath, 'UTF-8');
    var fileName = path.basename(relativePath);
    var fileDir = relativePath.replace(fileName, '');

    demoAssets.push({
      svg: getSVGData(svgConent),
      copypasta: _this.getDemoAssetUsage(relativePath),
      name: fileName,
      fileDir: fileDir
    });
  });

  return {
    arrangeBy: [
      { name: 'File dir', value: 'fileDir' }
    ],

    assets: demoAssets
  };
};

module.exports = DemoBuilder;
<commit_msg>Add support for arranging by base size - #2<commit_after>'use strict';

var CachingWriter = require('broccoli-caching-writer');
var path = require('path');
var fs = require('fs');
var uniq = require('lodash.uniq');
var mkdirp = require('mkdirp');
var cheerio = require('cheerio');

function ensurePosix(filePath) {
  if (path.sep !== '/') {
    return filePath.split(path.sep).join('/');
  }
  return filePath;
}

function getHelperKey(filePath) {
  return path.basename(filePath)
    .replace(/\.[^/.]+$/, '')
    .replace(/[\s]/g, '-');
}

function getSVGData(svgContent) {
  var $svg = cheerio.load(svgContent, { xmlMode: true })('svg');
  var viewBox = $svg.attr('viewBox');
  var viewBoxValues = viewBox.split(/\s+/);

  return {
    content: $svg.html(),
    viewBox: viewBox,
    width: $svg.attr('width') || viewBoxValues[2],
    height: $svg.attr('height') || viewBoxValues[3]
  };
}

function DemoBuilder(inputNode, options) {
  if (!options || !options.outputFile) {
    throw new Error('the outputFile option is required');
  }

  CachingWriter.call(this, [inputNode], {
    name: 'DemoBuilder',
    annotation: options.annotation,
  });

  /**
    All options:
    - outputFile,
    - strategy,
    - symbolsPrefix
  */
  this.options = options;
}

DemoBuilder.prototype = Object.create(CachingWriter.prototype);
DemoBuilder.prototype.constructor = DemoBuilder;

DemoBuilder.prototype.build = function() {
  var demoContent = JSON.stringify(this.getDemoModel());
  var outputFilePath = path.join(this.outputPath, this.options.outputFile);
  mkdirp.sync(path.dirname(outputFilePath));
  fs.writeFileSync(outputFilePath, demoContent);
};

DemoBuilder.prototype.getFilePaths = function() {
  var posixFilePaths = this.listFiles().map(ensurePosix);

  return uniq(posixFilePaths).filter(function(filePath) {
    // files returned from this.listFiles are directories if they end in /
    var isDirectory = filePath.charAt(filePath.length - 1) === '/';
    return !isDirectory;
  });
};

DemoBuilder.prototype.getDemoAssetUsage = function(relativePath) {
  var helperKey = getHelperKey(relativePath);

  if (this.options.strategy === 'symbol') {
    helperKey = '#' + this.options.symbolsPrefix + helperKey;
  }

  return '{{svg-jar "' + helperKey + '"}}';
};

DemoBuilder.prototype.getDemoModel = function() {
  var inputPath = this.inputPaths[0];
  var posixInputPath = ensurePosix(inputPath);
  var demoAssets = [];
  var _this = this;

  this.getFilePaths().forEach(function(posixFilePath) {
    var relativePath = posixFilePath.replace(posixInputPath + '/', '');
    var filePath = path.join(inputPath, relativePath);
    var svgConent = fs.readFileSync(filePath, 'UTF-8');
    var fileName = path.basename(relativePath);
    var fileDir = relativePath.replace(fileName, '');
    var svgData = getSVGData(svgConent);

    demoAssets.push({
      svg: svgData,
      copypasta: _this.getDemoAssetUsage(relativePath),
      name: fileName,
      fileDir: fileDir,
      baseSize: svgData.height + 'px'
    });
  });

  return {
    arrangeBy: [
      { name: 'File dir', value: 'fileDir' },
      { name: 'Base size', value: 'baseSize' }
    ],

    assets: demoAssets
  };
};

module.exports = DemoBuilder;
<|endoftext|>


<commit_before>var Lail; if(!Lail) Lail={};
Lail.PaginatedList = function(list, options) {
  // todo: paste John Resig's code

  options = options || {};
  var self = this;

  this.set = [];
  this.set_length = 0;
  this.current_page = 1;
  this.page_size = options.page_size || 20;
  this.page_count = 1;
  this.observer = new Observer();
  this.pagination_container = null;

  this.count = function() {
    return self.set_length;
  }

  this.init = function(list, initialPage) {
    self.set = list;
    self.set_length = self.set.length;
    self.page_count = parseInt(Math.ceil(self.set_length / self.page_size));
    if(self.page_count < 1) {
      self.page_count = 1;
    }
    self.current_page = 0;
    self.gotoPage(initialPage || 1);
  }

  this.gotoPage = function(page_number) {
    page_number = +page_number; // needs to be an integer
    if(page_number < 1) page_number = 1;
    if(page_number > self.total_pages) page_number = self.total_pages;
    if(page_number != self.current_page) __setCurrentPage(page_number);
  }

  function __setCurrentPage(page_number) {
    self.current_page = page_number;
    self.current_set = self.set.slice(self.firstItemIndex(), self.lastItemIndex());
    renderPagination();
    notifyOfPageChange();
  }

  this.firstItemIndex = function() {
    return (self.current_page - 1) * self.page_size;
  }

  this.lastItemIndex = function() {
    var end = self.current_page * self.page_size;
    return (end > self.set_length) ? self.set_length : end;
  }

  this.getCurrentPage = function() {
    return self.current_page;
  }

  this.getCurrentSet = function() {
    return self.current_set;
  }

  this.getEntireSet = function() {
    return self.set;
  }

  function renderPagination() {
    if(self.pagination_container) {
      self.pagination_container.html(self.renderPagination());
    }
  }

  function notifyOfPageChange() {
    self.observer.fire('changed');
  }

  this.onPageChange = function(callback) {
    self.observer.observe('changed', callback);
  }

  this.gotoNextPage = function() {
    if(self.isLastPage()) {
      return false;
    } else {
      self.gotoPage(self.current_page + 1);
      return true;
    }
  }

  this.getNextPageNumber = function() {
    return self.isLastPage() ? self.current_page : (self.current_page + 1);
  }

  this.isLastPage = function() {
    return (self.current_page == self.page_count);
  }

  this.gotoPreviousPage = function() {
    if(self.isFirstPage()) {
      return false;
    } else {
      self.gotoPage(self.current_page - 1);
      return true;
    }
  }

  this.getPreviousPageNumber = function() {
    return self.isFirstPage() ? self.current_page : (self.current_page - 1);
  }

  this.isFirstPage = function() {
    return (self.current_page == 1);
  }

  // !nb: uses jQuery!!!
  this.renderPaginationIn = function(selector) {
    self.pagination_container = jQuery(selector);
    self.pagination_container.delegate('a', 'click', function(e) {
      e.preventDefault();
      e.stopImmediatePropagation();
      var a = jQuery(this);
      if(a.hasClass('prev_page')) {
        self.gotoPreviousPage();
      } else if(a.hasClass('next_page')) {
        self.gotoNextPage();
      } else if(a.hasClass('goto_page')) {
        self.gotoPage(parseInt(a.attr('id').substring(5)));
      }
      return false;
    });
  }

  // !todo: use Handlebars
  this.renderPagination = function() {
    var html = '';

    if(self.isFirstPage()) {
      html += '« Previous ';
    } else {
      html += '« Previous ';
    }

    // list no more than 7 page numbers
    var current = self.current_page,
        count = self.page_count,
        min = 1,
        max = count;
    if(self.page_count > 7) {
      min = current - 3;
      max = current + 3;
      var shift = (min < 1) ? (1 - min) : ((max > count) ? (count - max) : 0);
      min += shift;
      max += shift;
    }
    for(var i=min; i<=max; i++) {
      if(i == self.current_page) {
        html += ' ' + i + ' ';
      } else {
        html += ' ' + i + ' ';
      }
    }

    if(self.isLastPage()) {
      html += ' Next »';
    } else {
      html += ' Next »';
    }

    return html;
  }

  // !todo: use handlebars
  this.renderExtendedPagination = function() {
    var html = 'Listing ';
    if(self.count() > 0) {
      html += (self.firstItemIndex()+1) + '–' + self.lastItemIndex() + ' of ';
    }
    return html + self.count() + '';
  }

  this.init(list || []);
}<commit_msg>add option to paginated_list to omit pagination when it isn't needed<commit_after>var Lail; if(!Lail) Lail={};
Lail.PaginatedList = function(list, options) {
  // todo: paste John Resig's code

  options = options || {};
  var self = this;

  this.set = [];
  this.set_length = 0;
  this.current_page = 1;
  this.page_size = options.page_size || 20;
  this.always_show = (typeof options.always_show == 'undefined') ? true : options.always_show;
  this.page_count = 1;
  this.observer = new Observer();
  this.pagination_container = null;

  this.count = function() {
    return self.set_length;
  }

  this.init = function(list, initialPage) {
    self.set = list;
    self.set_length = self.set.length;
    self.page_count = parseInt(Math.ceil(self.set_length / self.page_size));
    if(self.page_count < 1) {
      self.page_count = 1;
    }
    self.current_page = 0;
    self.gotoPage(initialPage || 1);
  }

  this.gotoPage = function(page_number) {
    page_number = +page_number; // needs to be an integer
    if(page_number < 1) page_number = 1;
    if(page_number > self.total_pages) page_number = self.total_pages;
    if(page_number != self.current_page) __setCurrentPage(page_number);
  }

  function __setCurrentPage(page_number) {
    self.current_page = page_number;
    self.current_set = self.set.slice(self.firstItemIndex(), self.lastItemIndex());
    renderPagination();
    notifyOfPageChange();
  }

  this.firstItemIndex = function() {
    return (self.current_page - 1) * self.page_size;
  }

  this.lastItemIndex = function() {
    var end = self.current_page * self.page_size;
    return (end > self.set_length) ? self.set_length : end;
  }

  this.getCurrentPage = function() {
    return self.current_page;
  }

  this.getCurrentSet = function() {
    return self.current_set;
  }

  this.getEntireSet = function() {
    return self.set;
  }

  function renderPagination() {
    if(self.pagination_container) {
      self.pagination_container.html(self.renderPagination());
    }
  }

  function notifyOfPageChange() {
    self.observer.fire('changed');
  }

  this.onPageChange = function(callback) {
    self.observer.observe('changed', callback);
  }

  this.gotoNextPage = function() {
    if(self.isLastPage()) {
      return false;
    } else {
      self.gotoPage(self.current_page + 1);
      return true;
    }
  }

  this.getNextPageNumber = function() {
    return self.isLastPage() ? self.current_page : (self.current_page + 1);
  }

  this.isLastPage = function() {
    return (self.current_page == self.page_count);
  }

  this.gotoPreviousPage = function() {
    if(self.isFirstPage()) {
      return false;
    } else {
      self.gotoPage(self.current_page - 1);
      return true;
    }
  }

  this.getPreviousPageNumber = function() {
    return self.isFirstPage() ? self.current_page : (self.current_page - 1);
  }

  this.isFirstPage = function() {
    return (self.current_page == 1);
  }

  // !nb: uses jQuery!!!
  this.renderPaginationIn = function(selector) {
    self.pagination_container = jQuery(selector);
    self.pagination_container.delegate('a', 'click', function(e) {
      e.preventDefault();
      e.stopImmediatePropagation();
      var a = jQuery(this);
      if(a.hasClass('prev_page')) {
        self.gotoPreviousPage();
      } else if(a.hasClass('next_page')) {
        self.gotoNextPage();
      } else if(a.hasClass('goto_page')) {
        self.gotoPage(parseInt(a.attr('id').substring(5)));
      }
      return false;
    });
  }

  // !todo: use Handlebars
  this.renderPagination = function() {
    var html = '',
        current = self.current_page,
        count = self.page_count,
        min = 1,
        max = count;

    if(this.always_show || count > 1) {
      if(self.isFirstPage()) {
        html += '« Previous ';
      } else {
        html += '« Previous ';
      }

      // list no more than 7 page numbers
      if(self.page_count > 7) {
        min = current - 3;
        max = current + 3;
        var shift = (min < 1) ? (1 - min) : ((max > count) ? (count - max) : 0);
        min += shift;
        max += shift;
      }
      for(var i=min; i<=max; i++) {
        if(i == self.current_page) {
          html += ' ' + i + ' ';
        } else {
          html += ' ' + i + ' ';
        }
      }

      if(self.isLastPage()) {
        html += ' Next »';
      } else {
        html += ' Next »';
      }
    }

    return html;
  }

  // !todo: use handlebars
  this.renderExtendedPagination = function() {
    var html = 'Listing ';
    if(self.count() > 0) {
      html += (self.firstItemIndex()+1) + '–' + self.lastItemIndex() + ' of ';
    }
    return html + self.count() + '';
  }

  this.init(list || []);
}<|endoftext|>


<commit_before>(function(){

  angular
  .module('linguine.analysis')
  .controller('AnalysisNewController', AnalysisNewController);

  function AnalysisNewController($http, $scope, $state, $rootScope, flash, usSpinnerService) {
    $scope.analysisNotSelected = true;
    $scope.needTokenizer = true;
    $scope.analysis = {analysisName: ""};
    $scope.preprocAvailable = true;
    $scope.tabs = [{active: true}, {active: false}, {active: false}];

    /*
     * Analyses are the crux of the NLP workflow, so they should be
     * chosen before anything else. Analysis can be run on either
     * a single corpus or an entire corpora. Rach analysis can also have
     * tokenization tasks and specific cleanup tasks bound to them, represented
     * by the tokenizerTypes and cleanupTypes objects.
     */
    $scope.analysisTypes = [
      {
        name: "Term Frequency Analysis",
        unfriendly_name: "wordcloudop",
        description: "This operation uses the NLTK Punkt tokenizer to separate terms. Used for finding the most frequent words a single corpus.",
        multipleCorporaAllowed: false,
        tokenAllowed: true,
        tokenizerRequired: true
      },
      {
        name: "Disfluency Analysis (SPLAT)",
        unfriendly_name: "splat-disfluency",
        description: "This operation parses the text of the corpus and gathers some metrics for disfluencies, such as 'UH' and 'UM'.",
        multipleCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "N-gram Frequency Analysis (SPLAT)",
        unfriendly_name: "splat-ngrams",
        description: "This operation extracts the unigrams, bigrams, and trigrams from the corpus using the Natural Language ToolKit (NLTK).",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenierRequired: false
      },
      {
        name: "Complexity Analysis (SPLAT)",
        unfriendly_name: "splat-complexity",
        description: "This operation calculates four different types of complexity: content density, idea density, Flesch readability, and Flesch-Kincaid grade level.",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenierRequired: false
      },
      {
        name: "Part of Speech Frequencies (SPLAT)",
        unfriendly_name: "splat-pos",
        description: "This operation performs a part of speech analysis on each word provided in the corpus. Each word will receive an identifier which represents the appropriate part of speech for the given word. It then displays a table of the frequencies of each (Penn Treebank) POS tag.",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Syllable Frequencies (SPLAT)",
        unfriendly_name: "splat-syllables",
        description: "This operation uses the cmudict to lookup syllable counts for each word in the corpus. For each unique syllable count found, words with that many syllables will be grouped together and displayed in a table. If a word is not found in the cmudict, the python library difflib is used to find the closest matching word in the cmudict, and the syllable count for that closest match is used.",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Syntactic Parse Trees w/ Part of Speech Tags (Stanford CoreNLP)",
        unfriendly_name: "nlp-pos",
        description: "This operation performs a part of speech analysis on each word provided in the corpus. Each word will receive an identifier which represents the appropriate part of speech for the given word. ",
        multipleCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Coreference Resolution (Stanford CoreNLP)",
        unfriendly_name: "nlp-coref",
        description: "Determine entities in the given corpus and show where each entity is mentioned",
        multipleCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Named Entity Recognition (Stanford CoreNLP)",
        unfriendly_name: "nlp-ner",
        description: "This operation will classify each word in the corpus based on its status as a place, organization, location, or expression of time. If a term does not match as a named entity, it will recieve a status of '0' ",
        tokenAllowed: false,
        multipleCorporaAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Sentiment (Stanford CoreNLP)",
        unfriendly_name: "nlp-sentiment",
        description: "This operation will measure the sentiment of the corpus, sentences, and tokens using models provided by Stanford Core NLP.",
        tokenAllowed: false,
        multipleCorporaAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Relation Extraction (Stanford CoreNLP)",
        unfriendly_name: "nlp-relation",
        description: "This operation will attempt to find relationship triples between words based on Stanford Core NLP models in the OpenIE libraries.",
        tokenAllowed: false,
        multipleCorporaAllowed: false,
        tokenizerRequired: false
      }
    ];

    /*
     * Object to keep track of all cleanup tasks that
     * are available to pass back to the Python server. The keys
     * are the unfriendly names of each cleanup task so that they
     * can be bound to each analysis in the cleanupTypes object
     */
    var cleanups = {
      "stem_porter": {
        name: "Stem (Porter)",
        unfriendly_name: "stem_porter",
        description: "Stem words using the NLTK Porter Stemmer. Converts inflected words in the corpus to their base form. This is a good general purpose stemmer to use."
      },
      "removecapsnnp": {
        name: "Remove Capitalization (NNP)",
        unfriendly_name: "removecapsnnp",
        description: "Convert uppercase letters to lowercase letters while leaving proper nouns capitalized, using TextBlob's Part-of-Speech tagger to identify proper nouns."
      },
      "removepunct": {
        name: "Remove Punctuation",
        unfriendly_name: "removepunct",
        description: "Remove all punctuation, using NLTK's Regexp tokenizer to scan the text for patterns of punctuation marks."
      },
      "stop_words": {
        name: "Remove Stop Words",
        unfriendly_name: "stop_words",
        description: "Removes NLTK's compiled list of stop words like 'and', 'or', 'but', etc."
      },
      "removesilence": {
        name: "Remove Silent Pauses",
        unfriendly_name: "removesilence",
        description: "Removes the tokens that represent silent pauses in speech: {SL} and {sl}."
      }
    };

    /*
     * for each unfriendly_name of an analysis, there is a set of cleanup tasks
     * that are deemed applicable.
     * This object is used to list all cleanup tasks relevant to each analysis on the view.
     *
     * Key[analysisUnfriendlyName] => value [cleanupUnfriendlyName1, unfriendlyName2, ... n]
     */
    $scope.cleanupTypes = {
      "pos_tag": [cleanups.stem_porter, cleanups.removecapsnnp, cleanups.removepunct, cleanups.stop_words, cleanups.removesilence],
      "wordcloudop": [cleanups.stem_porter, cleanups.removecapsnnp, cleanups.removepunct, cleanups.stop_words, cleanups.removesilence],
      "nlp-pos": [cleanups.removesilence],
      "splat-disfluency": [cleanups.removesilence],
      "splat-ngrams": [cleanups.removesilence],
      "splat-complexity": [cleanups.removesilence],
      "splat-pos": [cleanups.removesilence],
      "splat-syllables": [cleanups.removesilence],
      "nlp-ner": [cleanups.removesilence],
      "nlp-coref": [cleanups.removesilence],
      "nlp-sentiment": [cleanups.removesilence],
      "nlp-relation": [cleanups.removesilence]
    };

    $scope.tokenizerTypes = [
      {
        name: "Word Tokenize (Penn Treebank)",
        unfriendly_name: "word_tokenize_treebank",
        description: "Separates the text in each corpus into individual word tokens, using NLTK's Penn Treebank tokenizer. This is a good general purpose tokenizer to use."
      },
    ];

    $http.get('api/corpora')
    .success(function (data) {
      $scope.corpora = data;
    });

    /*
     * Determine if the selected analysis can either accept
     * a single corpora or multiple, and handle
     * the selection appropriately.
     */
    $scope.onCorpusClick = function (e) {
      var activeCount = 0;
      var activeCorpora = [];

      //Keep track of the corpora that are currently active
      $scope.corpora.forEach(function(corpora) {
        if(corpora.active){
          activeCount++;
          activeCorpora.push(corpora);
        }
      });

      //User selects a corpora when one is already selected
      //and analysis can only accept 1 corpora
      if(!e.corpus.active && activeCount == 1  && !$scope.selectedAnalysis.multipleCorporaAllowed) {
        e.corpus.active = true;
        //Disable previous corpora
        activeCorpora[0].active = false;
      }
      //Any other case, user can de-select or select multiple
      else {
        e.corpus.active = !e.corpus.active;
      }
    };

    $scope.onAnalysisClick = function (e) {
      $scope.selectedAnalysis = e.analysis;
      $scope.analysis.analysisName = e.analysis.name;

      //re-enable the preprocessing tab once an analysis is clicked
      $scope.analysisNotSelected = false;
    };

    $scope.onCleanupClick = function(e) {
      e.cleanup.active = !e.cleanup.active;
    };

    $scope.onTokenizerClick = function(e) {
      $scope.selectedTokenizer = e.tokenizer;
      $scope.needTokenizer = false;
    };

    $scope.checkIfNoPreprocessingAvailable = function() {
      var analysisName = $scope.selectedAnalysis.unfriendly_name;
      var noCleanupTypes = $scope.cleanupTypes[analysisName].length == 0;

      if(noCleanupTypes && !$scope.selectedAnalysis.tokenAllowed) {
          flash.info.setMessage("No preprocessing options are available for " +            $scope.selectedAnalysis.name);
          $rootScope.$emit("event:angularFlash");
      }
    }

    $scope.onPreprocessingTabClick = function(e) {
      if(!$scope.selectedAnalysis) {
        flash.danger.setMessage('Please select an analysis before selecting preprocessing options.');
        $rootScope.$emit("event:angularFlash");
      }
      $scope.checkIfNoPreprocessingAvailable();
      $scope.tabs[0].active = false;$scope.tabs[1].active = false;$scope.tabs[2].active = true;
    };

    $scope.onCorporaTabClick = function(e) {
      //Reset the corpora selected if we've chosen an analysis
      //that can only accept one corpora
      var activeCount = 0;
      $scope.corpora.forEach(function(corpus) {
        if(corpus.active === true) {
          activeCount++;
        }
      });

      if(activeCount > 1) {
        //flush the list of selected corpora
        $scope.corpora.forEach(function(corpus) {
          if(corpus.active) {
            corpus.active = false;
          }
        });
        //Display a message to the user that corpora has been cleared
        flash.info.setMessage($scope.selectedAnalysis.name + "Cannot be used with multiple" +
        " corpora. Please choose a new corpora.");

        $rootScope.$emit("event:angularFlash");

      }

      if(!$scope.selectedAnalysis) {
        flash.danger.setMessage('Please select an analysis before selecting corpora.');
        $rootScope.$emit("event:angularFlash");
      }
      $scope.tabs[0].active = false;$scope.tabs[1].active = true;$scope.tabs[2].active = false;
    };

    $scope.onAnalysisTabClick = function(e) {
      $scope.tabs[0].active = true;$scope.tabs[1].active = false;$scope.tabs[2].active = false;
    };

    $scope.onPreviousButtonClick = function(e) {
      if ($scope.tabs[1].active) {
        $scope.onAnalysisTabClick(e);
      } else if ($scope.tabs[2].active) {
        $scope.onCorporaTabClick(e);
      }
    };

    $scope.onNextButtonClick = function(e) {
      if (!(($scope.tabs[0].active && $scope.analysisNotSelected) || $scope.tabs[2].active)) {
        if ($scope.tabs[0].active) {
          $scope.onCorporaTabClick(e);
        } else {
          $scope.onPreprocessingTabClick(e);
        }
      }
    };

    $scope.onCreateAnalysis = function () {

      if($scope.needTokenizer && $scope.selectedAnalysis.tokenizerRequired) {
        flash.info.setMessage('The selected analysis requires a tokenizer to complete.');
        $rootScope.$emit("event:angularFlash");
        return;
      }

      var numActive = 0;
      $scope.corpora.forEach(function(corpora) {
        if(corpora.active){numActive++;}
      });

      if(numActive == 0) {
        flash.info.setMessage('Please select a corpora before continuing.');
        $rootScope.$emit("event:angularFlash");
        return;
      }

      try {
        usSpinnerService.spin('analysisProcSpinner');
        theDate = new Date();
        var payload = {
          corpora_ids: _.pluck(_.where($scope.corpora, 'active'), '_id'),
          cleanup: _.map(_.where($scope.cleanupTypes[$scope.selectedAnalysis.unfriendly_name], 'active'), function (cleanupType) {
            return cleanupType.unfriendly_name;
          }),
          operation: $scope.selectedAnalysis.unfriendly_name,
          tokenizer: $scope.selectedTokenizer? $scope.selectedTokenizer.unfriendly_name: "",
          library: "",
          transaction_id: "",
          analysis_name: $scope.analysis.analysisName,
          time_created: new Date().getTime(),
          user_id: ""
        };

        $http.post('api/analysis', payload)
        .success(function (data) {
          console.log(data);
          usSpinnerService.stop('analysisProcSpinner');
          $state.go('linguine.analysis.index');
        })
        .error(function (data) {
          usSpinnerService.stop('analysisProcSpinner');
          flash.danger.setMessage('An error occurred while trying to create your analysis.');
          $rootScope.$emit("event:angularFlash");
        });
      } catch (error) {
        usSpinnerService.stop('analysisProcSpinner');
        flash.danger.setMessage('There was a problem with your request.  Please review the options you have selected and try again.');
        $rootScope.$emit("event:angularFlash");
      }
    };
  }
})();
<commit_msg>Updated preprocessing steps.<commit_after>(function(){

  angular
  .module('linguine.analysis')
  .controller('AnalysisNewController', AnalysisNewController);

  function AnalysisNewController($http, $scope, $state, $rootScope, flash, usSpinnerService) {
    $scope.analysisNotSelected = true;
    $scope.needTokenizer = true;
    $scope.analysis = {analysisName: ""};
    $scope.preprocAvailable = true;
    $scope.tabs = [{active: true}, {active: false}, {active: false}];

    /*
     * Analyses are the crux of the NLP workflow, so they should be
     * chosen before anything else. Analysis can be run on either
     * a single corpus or an entire corpora. Rach analysis can also have
     * tokenization tasks and specific cleanup tasks bound to them, represented
     * by the tokenizerTypes and cleanupTypes objects.
     */
    $scope.analysisTypes = [
      {
        name: "Term Frequency Analysis",
        unfriendly_name: "wordcloudop",
        description: "This operation uses the NLTK Punkt tokenizer to separate terms. Used for finding the most frequent words a single corpus.",
        multipleCorporaAllowed: false,
        tokenAllowed: true,
        tokenizerRequired: true
      },
      {
        name: "Disfluency Analysis (SPLAT)",
        unfriendly_name: "splat-disfluency",
        description: "This operation parses the text of the corpus and gathers some metrics for disfluencies, such as 'UH' and 'UM'.",
        multipleCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "N-gram Frequency Analysis (SPLAT)",
        unfriendly_name: "splat-ngrams",
        description: "This operation extracts the unigrams, bigrams, and trigrams from the corpus using the Natural Language ToolKit (NLTK).",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenierRequired: false
      },
      {
        name: "Complexity Analysis (SPLAT)",
        unfriendly_name: "splat-complexity",
        description: "This operation calculates four different types of complexity: content density, idea density, Flesch readability, and Flesch-Kincaid grade level.",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenierRequired: false
      },
      {
        name: "Part of Speech Frequencies (SPLAT)",
        unfriendly_name: "splat-pos",
        description: "This operation performs a part of speech analysis on each word provided in the corpus. Each word will receive an identifier which represents the appropriate part of speech for the given word. It then displays a table of the frequencies of each (Penn Treebank) POS tag.",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Syllable Frequencies (SPLAT)",
        unfriendly_name: "splat-syllables",
        description: "This operation uses the cmudict to lookup syllable counts for each word in the corpus. For each unique syllable count found, words with that many syllables will be grouped together and displayed in a table. If a word is not found in the cmudict, the python library difflib is used to find the closest matching word in the cmudict, and the syllable count for that closest match is used.",
        multiCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Syntactic Parse Trees w/ Part of Speech Tags (Stanford CoreNLP)",
        unfriendly_name: "nlp-pos",
        description: "This operation performs a part of speech analysis on each word provided in the corpus. Each word will receive an identifier which represents the appropriate part of speech for the given word. ",
        multipleCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Coreference Resolution (Stanford CoreNLP)",
        unfriendly_name: "nlp-coref",
        description: "Determine entities in the given corpus and show where each entity is mentioned",
        multipleCorporaAllowed: false,
        tokenAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Named Entity Recognition (Stanford CoreNLP)",
        unfriendly_name: "nlp-ner",
        description: "This operation will classify each word in the corpus based on its status as a place, organization, location, or expression of time. If a term does not match as a named entity, it will recieve a status of '0' ",
        tokenAllowed: false,
        multipleCorporaAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Sentiment (Stanford CoreNLP)",
        unfriendly_name: "nlp-sentiment",
        description: "This operation will measure the sentiment of the corpus, sentences, and tokens using models provided by Stanford Core NLP.",
        tokenAllowed: false,
        multipleCorporaAllowed: false,
        tokenizerRequired: false
      },
      {
        name: "Relation Extraction (Stanford CoreNLP)",
        unfriendly_name: "nlp-relation",
        description: "This operation will attempt to find relationship triples between words based on Stanford Core NLP models in the OpenIE libraries.",
        tokenAllowed: false,
        multipleCorporaAllowed: false,
        tokenizerRequired: false
      }
    ];

    /*
     * Object to keep track of all cleanup tasks that
     * are available to pass back to the Python server. The keys
     * are the unfriendly names of each cleanup task so that they
     * can be bound to each analysis in the cleanupTypes object
     */
    var cleanups = {
      "stem_porter": {
        name: "Stem (Porter)",
        unfriendly_name: "stem_porter",
        description: "Stem words using the NLTK Porter Stemmer. Converts inflected words in the corpus to their base form. This is a good general purpose stemmer to use."
      },
      "removecapsnnp": {
        name: "Remove Capitalization (NNP)",
        unfriendly_name: "removecapsnnp",
        description: "Convert uppercase letters to lowercase letters while leaving proper nouns capitalized, using TextBlob's Part-of-Speech tagger to identify proper nouns."
      },
      "removepunct": {
        name: "Remove Punctuation",
        unfriendly_name: "removepunct",
        description: "Remove all punctuation, using NLTK's Regexp tokenizer to scan the text for patterns of punctuation marks."
      },
      "stop_words": {
        name: "Remove Stop Words",
        unfriendly_name: "stop_words",
        description: "Removes NLTK's compiled list of stop words like 'and', 'or', 'but', etc."
      },
      "removesilence": {
        name: "Remove Silent Pauses",
        unfriendly_name: "removesilence",
        description: "Removes the tokens that represent silent pauses in speech: {SL} and {sl}."
      }
    };

    /*
     * for each unfriendly_name of an analysis, there is a set of cleanup tasks
     * that are deemed applicable.
     * This object is used to list all cleanup tasks relevant to each analysis on the view.
     *
     * Key[analysisUnfriendlyName] => value [cleanupUnfriendlyName1, unfriendlyName2, ... n]
     */
    $scope.cleanupTypes = {
      "pos_tag": [cleanups.stem_porter, cleanups.removecapsnnp, cleanups.removepunct, cleanups.stop_words, cleanups.removesilence],
      "wordcloudop": [cleanups.stem_porter, cleanups.removecapsnnp, cleanups.removepunct, cleanups.stop_words, cleanups.removesilence],
      "nlp-pos": [cleanups.removesilence],
      "splat-disfluency": [cleanups.removesilence],
      "splat-ngrams": [cleanups.removesilence],
      "splat-complexity": [],
      "splat-pos": [cleanups.removesilence],
      "splat-syllables": [cleanups.removesilence],
      "nlp-ner": [cleanups.removesilence],
      "nlp-coref": [cleanups.removesilence],
      "nlp-sentiment": [cleanups.removesilence],
      "nlp-relation": [cleanups.removesilence]
    };

    $scope.tokenizerTypes = [
      {
        name: "Word Tokenize (Penn Treebank)",
        unfriendly_name: "word_tokenize_treebank",
        description: "Separates the text in each corpus into individual word tokens, using NLTK's Penn Treebank tokenizer. This is a good general purpose tokenizer to use."
      },
    ];

    $http.get('api/corpora')
    .success(function (data) {
      $scope.corpora = data;
    });

    /*
     * Determine if the selected analysis can either accept
     * a single corpora or multiple, and handle
     * the selection appropriately.
     */
    $scope.onCorpusClick = function (e) {
      var activeCount = 0;
      var activeCorpora = [];

      //Keep track of the corpora that are currently active
      $scope.corpora.forEach(function(corpora) {
        if(corpora.active){
          activeCount++;
          activeCorpora.push(corpora);
        }
      });

      //User selects a corpora when one is already selected
      //and analysis can only accept 1 corpora
      if(!e.corpus.active && activeCount == 1  && !$scope.selectedAnalysis.multipleCorporaAllowed) {
        e.corpus.active = true;
        //Disable previous corpora
        activeCorpora[0].active = false;
      }
      //Any other case, user can de-select or select multiple
      else {
        e.corpus.active = !e.corpus.active;
      }
    };

    $scope.onAnalysisClick = function (e) {
      $scope.selectedAnalysis = e.analysis;
      $scope.analysis.analysisName = e.analysis.name;

      //re-enable the preprocessing tab once an analysis is clicked
      $scope.analysisNotSelected = false;
    };

    $scope.onCleanupClick = function(e) {
      e.cleanup.active = !e.cleanup.active;
    };

    $scope.onTokenizerClick = function(e) {
      $scope.selectedTokenizer = e.tokenizer;
      $scope.needTokenizer = false;
    };

    $scope.checkIfNoPreprocessingAvailable = function() {
      var analysisName = $scope.selectedAnalysis.unfriendly_name;
      var noCleanupTypes = $scope.cleanupTypes[analysisName].length == 0;

      if(noCleanupTypes && !$scope.selectedAnalysis.tokenAllowed) {
          flash.info.setMessage("No preprocessing options are available for " +            $scope.selectedAnalysis.name);
          $rootScope.$emit("event:angularFlash");
      }
    }

    $scope.onPreprocessingTabClick = function(e) {
      if(!$scope.selectedAnalysis) {
        flash.danger.setMessage('Please select an analysis before selecting preprocessing options.');
        $rootScope.$emit("event:angularFlash");
      }
      $scope.checkIfNoPreprocessingAvailable();
      $scope.tabs[0].active = false;$scope.tabs[1].active = false;$scope.tabs[2].active = true;
    };

    $scope.onCorporaTabClick = function(e) {
      //Reset the corpora selected if we've chosen an analysis
      //that can only accept one corpora
      var activeCount = 0;
      $scope.corpora.forEach(function(corpus) {
        if(corpus.active === true) {
          activeCount++;
        }
      });

      if(activeCount > 1) {
        //flush the list of selected corpora
        $scope.corpora.forEach(function(corpus) {
          if(corpus.active) {
            corpus.active = false;
          }
        });
        //Display a message to the user that corpora has been cleared
        flash.info.setMessage($scope.selectedAnalysis.name + "Cannot be used with multiple" +
        " corpora. Please choose a new corpora.");

        $rootScope.$emit("event:angularFlash");

      }

      if(!$scope.selectedAnalysis) {
        flash.danger.setMessage('Please select an analysis before selecting corpora.');
        $rootScope.$emit("event:angularFlash");
      }
      $scope.tabs[0].active = false;$scope.tabs[1].active = true;$scope.tabs[2].active = false;
    };

    $scope.onAnalysisTabClick = function(e) {
      $scope.tabs[0].active = true;$scope.tabs[1].active = false;$scope.tabs[2].active = false;
    };

    $scope.onPreviousButtonClick = function(e) {
      if ($scope.tabs[1].active) {
        $scope.onAnalysisTabClick(e);
      } else if ($scope.tabs[2].active) {
        $scope.onCorporaTabClick(e);
      }
    };

    $scope.onNextButtonClick = function(e) {
      if (!(($scope.tabs[0].active && $scope.analysisNotSelected) || $scope.tabs[2].active)) {
        if ($scope.tabs[0].active) {
          $scope.onCorporaTabClick(e);
        } else {
          $scope.onPreprocessingTabClick(e);
        }
      }
    };

    $scope.onCreateAnalysis = function () {

      if($scope.needTokenizer && $scope.selectedAnalysis.tokenizerRequired) {
        flash.info.setMessage('The selected analysis requires a tokenizer to complete.');
        $rootScope.$emit("event:angularFlash");
        return;
      }

      var numActive = 0;
      $scope.corpora.forEach(function(corpora) {
        if(corpora.active){numActive++;}
      });

      if(numActive == 0) {
        flash.info.setMessage('Please select a corpora before continuing.');
        $rootScope.$emit("event:angularFlash");
        return;
      }

      try {
        usSpinnerService.spin('analysisProcSpinner');
        theDate = new Date();
        var payload = {
          corpora_ids: _.pluck(_.where($scope.corpora, 'active'), '_id'),
          cleanup: _.map(_.where($scope.cleanupTypes[$scope.selectedAnalysis.unfriendly_name], 'active'), function (cleanupType) {
            return cleanupType.unfriendly_name;
          }),
          operation: $scope.selectedAnalysis.unfriendly_name,
          tokenizer: $scope.selectedTokenizer? $scope.selectedTokenizer.unfriendly_name: "",
          library: "",
          transaction_id: "",
          analysis_name: $scope.analysis.analysisName,
          time_created: new Date().getTime(),
          user_id: ""
        };

        $http.post('api/analysis', payload)
        .success(function (data) {
          console.log(data);
          usSpinnerService.stop('analysisProcSpinner');
          $state.go('linguine.analysis.index');
        })
        .error(function (data) {
          usSpinnerService.stop('analysisProcSpinner');
          flash.danger.setMessage('An error occurred while trying to create your analysis.');
          $rootScope.$emit("event:angularFlash");
        });
      } catch (error) {
        usSpinnerService.stop('analysisProcSpinner');
        flash.danger.setMessage('There was a problem with your request.  Please review the options you have selected and try again.');
        $rootScope.$emit("event:angularFlash");
      }
    };
  }
})();
<|endoftext|>


<commit_before><commit_msg>support binding and config<commit_after><|endoftext|>


<commit_before>    var customIcons = {
        building: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/building_icon.png'
        },
        student_centre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/student_centre_icon.png'
        },
        lecture_theatre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/lecture_theatre_icon.png'
        },
        computer_lab: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/computer_lab_icon.png'
        },
        library: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/library_icon.png'
        },
        cycle_hire: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_hire_icon.png'
        },
        cycle_parking: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_parking_icon.png'
        },
        atm: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/atm_icon.png'
        }
    };

    var markerGroups = {
        "building": [],
        "student_centre": [],
        "lecture_theatre": [],
        "computer_lab": [],
        "library": [],
        "cycle_hire": [],
        "cycle_parking": [],
        "atm": []
    };

    function loadMap() {
    var map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(51.527287, -0.103842),
        zoom: 15,
        mapTypeId: 'roadmap'
    });

    downloadUrl("../../includes/university-map/source/overview_source.php", function(data) {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
        var name = markers[i].getAttribute("name");
        var notes = markers[i].getAttribute("notes");
        var category = markers[i].getAttribute("category");
        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var marker = createMarker(point, name, notes, category, map);
    }
    });
    }

    var infoWindow = new google.maps.InfoWindow({
        maxWidth: 400
    });

    function createMarker(point, name, notes, category, map) {
        var icon = customIcons[category] || {};
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,
            type: category
        });
        if (!markerGroups[category]) markerGroups[category] = [];
        markerGroups[category].push(marker);
        var html = "" + name + "
" + notes;
        bindInfoWindow(marker, map, infoWindow, html);
        return marker;
    }

    function toggleGroup(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            if (!marker.getVisible()) {
                marker.setVisible(true);
            } else {
                marker.setVisible(false);
            }
        }
    }

    function clearMarkers(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            marker[i].setMap(null);
            markerGroups = [];
        }
    }

    function bindInfoWindow(marker, map, infoWindow, html) {
        google.maps.event.addListener(marker, 'click', function() {
            infoWindow.setContent(html);
            infoWindow.open(map, marker);

        });
    }

    function downloadUrl(url, callback) {
        var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();

        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                request.onreadystatechange = doNothing;
                callback(request, request.status);
            }
        };

        request.open('GET', url, true);
        request.send(null);
    }

    function doNothing() {}
<commit_msg>Changed structure<commit_after>    var customIcons = {
        building: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/building_icon.png'
        },
        student_centre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/student_centre_icon.png'
        },
        lecture_theatre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/lecture_theatre_icon.png'
        },
        computer_lab: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/computer_lab_icon.png'
        },
        library: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/library_icon.png'
        },
        cycle_hire: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_hire_icon.png'
        },
        cycle_parking: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_parking_icon.png'
        },
        atm: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/atm_icon.png'
        }
    };

    var markerGroups = {
        "building": [],
        "student_centre": [],
        "lecture_theatre": [],
        "computer_lab": [],
        "library": [],
        "cycle_hire": [],
        "cycle_parking": [],
        "atm": []
    };

    function loadMap() {
    var map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(51.527287, -0.103842),
        zoom: 15,
        mapTypeId: 'roadmap'
    });

    downloadUrl("../../includes/university-map/source/overview_source.php", function(data) {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
        var name = markers[i].getAttribute("name");
        var notes = markers[i].getAttribute("notes");
        var category = markers[i].getAttribute("category");
        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var marker = createMarker(point, name, notes, category, map);
    }
    });
    }

    var infoWindow = new google.maps.InfoWindow({
        maxWidth: 400
    });

    function createMarker(point, name, notes, category, map) {
        var icon = customIcons[category] || {};
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,
            type: category
        });
        if (!markerGroups[category]) markerGroups[category] = [];
        markerGroups[category].push(marker);
        var html = "" + name + "
" + notes;
        bindInfoWindow(marker, map, infoWindow, html);
        return marker;
    }

    function toggleGroup(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            if (!marker.getVisible()) {
                marker.setVisible(true);
            } else {
                marker.setVisible(false);
            }
        }
    }

    function bindInfoWindow(marker, map, infoWindow, html) {
        google.maps.event.addListener(marker, 'click', function() {
            infoWindow.setContent(html);
            infoWindow.open(map, marker);

        });
    }

    function downloadUrl(url, callback) {
        var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();

        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                request.onreadystatechange = doNothing;
                callback(request, request.status);
            }
        };

        request.open('GET', url, true);
        request.send(null);
    }

    function doNothing() {}
<|endoftext|>


<commit_before>/**
  @module ember-flexberry
*/

import Ember from 'ember';
import FlexberryBaseComponent from './flexberry-base-component';

/**
  Menu component for Semantic UI.

  Questions:
  - Need {{yield}} in flexberry-menu.hbs?

  Sample usage:
  ```javascript
  // app/controllers/menu.js
  ...
  items: [{
    icon: 'search icon',
    title: 'Search',
  },{
    icon: 'settings icon',
    iconAlignment: 'right',
    title: 'Settings',
  },{
    icon: 'list icon',
    title: 'Submenu',
    items: [{
      icon: 'trash icon',
      title: 'Delete',
    }],
  }],
  ...
  actions: {
    ...
    onItemClick(e) {
      let clickedMenuItem = Ember.$(e.currentTarget);
      ...
    },
    ...
  },
  ...
  ```

  ```handlebars
  <!-- app/templates/menu.hbs -->
  ...
  {{flexberry-menu
    items=items
    onItemClick=(action 'onItemClick')
  }}
  ...
  ```

  @class FlexberryMenu
  @extends FlexberryBaseComponent
*/
export default FlexberryBaseComponent.extend({
  /**
    Flag: indicates whether to call 'items.[].onClick' callbacks or not.

    @property callItemsOnClickCallbacks
    @type Boolean
    @default true
  */
  callItemsOnClickCallbacks: true,

  /**
    Menu items.

    @property items
    @type Array
    @default null
  */
  items: null,

  /**
    Array CSS class names.
    [More info](http://emberjs.com/api/classes/Ember.Component.html#property_classNames).

    @property classNames
    @type Array
    @readOnly
  */
  classNames: ['flexberry-menu', 'ui', 'floating', 'icon', 'dropdown', 'button'],

  /**
    Path to component's settings in application configuration (JSON from ./config/environment.js).

    @property appConfigSettingsPath
    @type String
    @default 'APP.components.flexberryMenu'
  */
  appConfigSettingsPath: 'APP.components.flexberryMenu',

  /**
    Initializes component.
  */
  init() {
    this._super(...arguments);

    // Component properties will be defined in class prototype,
    // so complex properties like object or arrays, will be shared between all class instances,
    // that's why such properties should be initialized manually in 'init' method.
    let items = this.get('items');
    if (Ember.isNone(items)) {
      items = [];
    }

    // Call to 'configurateItems' hook.
    let configurateItems = this.get('configurateItems');

    if (configurateItems) {
      let configurateItemsType = Ember.typeOf(configurateItems);

      if (configurateItemsType === 'function') {
        configurateItems(items);
      } else {
        Ember.Logger.error(
          'Wrong type of flexberry-menu \'configurateItems\' propery: ' +
          'actual type is \'' +
          configurateItemsType +
          '\', but \'function\' is expected.');
      }
    }

    this.set('items', items);
  },

  /**
    Initializes DOM-related component's logic.
  */
  didInsertElement() {
    this._super(...arguments);

    // Bind right context to menu click event handler.
    let onClickHandler = this.get('_onClickHandler').bind(this);
    this.set('_onClickHandler', onClickHandler);

    // Attach menu click event handler.
    this.$().on('click', onClickHandler);

    this.$().dropdown();
  },

  /**
    Cleans up DOM-related component's logic.
  */
  willDestroyElement() {
    this._super(...arguments);

    // Remove menu item click event handler.
    let onClickHandler = this.get('_onClickHandler');
    this.$().off('click', onClickHandler);
  },

  /**
    Hook which will be called to configure menu items.

    Example:
    ```handlebars
    <!-- app/templates/menu.hbs -->
    {{flexberry-menu
      ...
      configurateItems=(action 'configurateItems')
      ...
    }}
    ```

    ```javascript
    // app/controllers/menu.js
    export default Ember.Controller.extend({
    ...
      actions: {
        ...
        configurateItems(items) {
          items.push({
            icon: 'edit icon',
            title: 'Edit',
          });
        },
        ...
      }
    ...
    });
    ```

    @method configurateItems
    @param {Array} items Menu items array.
  */
  configurateItems: undefined,

  /**
    Menu click handler.
    Used to delegate menu items clicks handling.

    @method _onClickHandler
    @param {JQuery.Event} e Click event object.
    @private
  */
  _onClickHandler(e) {
    // Find clicked menu item element.
    let itemElement = Ember.$(e.target);
    if (!itemElement.hasClass('flexberry-menuitem')) {
      itemElement = itemElement.parents('.flexberry-menuitem');
    }

    // Replace currentTarget with clicked menu item element.
    e.currentTarget = itemElement[0];

    // Add clicked item's content to click event object.
    let item = itemElement.data('flexberry-menuitem.item');
    e.item = item;

    // Call onClick handler if it is specified in the given menu item.
    if (item && Ember.typeOf(item.onClick) === 'function' && this.get('callItemsOnClickCallbacks')) {
      item.onClick.call(e.currentTarget, e);
    }

    // Send 'onClick' action on clicked 'flexberry-menuitem' component.
    this.sendAction('onItemClick', e);
  },
});
<commit_msg>Remove loating class from flexberry-menu component<commit_after>/**
  @module ember-flexberry
*/

import Ember from 'ember';
import FlexberryBaseComponent from './flexberry-base-component';

/**
  Menu component for Semantic UI.

  Questions:
  - Need {{yield}} in flexberry-menu.hbs?

  Sample usage:
  ```javascript
  // app/controllers/menu.js
  ...
  items: [{
    icon: 'search icon',
    title: 'Search',
  },{
    icon: 'settings icon',
    iconAlignment: 'right',
    title: 'Settings',
  },{
    icon: 'list icon',
    title: 'Submenu',
    items: [{
      icon: 'trash icon',
      title: 'Delete',
    }],
  }],
  ...
  actions: {
    ...
    onItemClick(e) {
      let clickedMenuItem = Ember.$(e.currentTarget);
      ...
    },
    ...
  },
  ...
  ```

  ```handlebars
  <!-- app/templates/menu.hbs -->
  ...
  {{flexberry-menu
    items=items
    onItemClick=(action 'onItemClick')
  }}
  ...
  ```

  @class FlexberryMenu
  @extends FlexberryBaseComponent
*/
export default FlexberryBaseComponent.extend({
  /**
    Flag: indicates whether to call 'items.[].onClick' callbacks or not.

    @property callItemsOnClickCallbacks
    @type Boolean
    @default true
  */
  callItemsOnClickCallbacks: true,

  /**
    Menu items.

    @property items
    @type Array
    @default null
  */
  items: null,

  /**
    Array CSS class names.
    [More info](http://emberjs.com/api/classes/Ember.Component.html#property_classNames).

    @property classNames
    @type Array
    @readOnly
  */
  classNames: ['flexberry-menu', 'ui', 'icon', 'dropdown', 'button'],

  /**
    Path to component's settings in application configuration (JSON from ./config/environment.js).

    @property appConfigSettingsPath
    @type String
    @default 'APP.components.flexberryMenu'
  */
  appConfigSettingsPath: 'APP.components.flexberryMenu',

  /**
    Initializes component.
  */
  init() {
    this._super(...arguments);

    // Component properties will be defined in class prototype,
    // so complex properties like object or arrays, will be shared between all class instances,
    // that's why such properties should be initialized manually in 'init' method.
    let items = this.get('items');
    if (Ember.isNone(items)) {
      items = [];
    }

    // Call to 'configurateItems' hook.
    let configurateItems = this.get('configurateItems');

    if (configurateItems) {
      let configurateItemsType = Ember.typeOf(configurateItems);

      if (configurateItemsType === 'function') {
        configurateItems(items);
      } else {
        Ember.Logger.error(
          'Wrong type of flexberry-menu \'configurateItems\' propery: ' +
          'actual type is \'' +
          configurateItemsType +
          '\', but \'function\' is expected.');
      }
    }

    this.set('items', items);
  },

  /**
    Initializes DOM-related component's logic.
  */
  didInsertElement() {
    this._super(...arguments);

    // Bind right context to menu click event handler.
    let onClickHandler = this.get('_onClickHandler').bind(this);
    this.set('_onClickHandler', onClickHandler);

    // Attach menu click event handler.
    this.$().on('click', onClickHandler);

    this.$().dropdown();
  },

  /**
    Cleans up DOM-related component's logic.
  */
  willDestroyElement() {
    this._super(...arguments);

    // Remove menu item click event handler.
    let onClickHandler = this.get('_onClickHandler');
    this.$().off('click', onClickHandler);
  },

  /**
    Hook which will be called to configure menu items.

    Example:
    ```handlebars
    <!-- app/templates/menu.hbs -->
    {{flexberry-menu
      ...
      configurateItems=(action 'configurateItems')
      ...
    }}
    ```

    ```javascript
    // app/controllers/menu.js
    export default Ember.Controller.extend({
    ...
      actions: {
        ...
        configurateItems(items) {
          items.push({
            icon: 'edit icon',
            title: 'Edit',
          });
        },
        ...
      }
    ...
    });
    ```

    @method configurateItems
    @param {Array} items Menu items array.
  */
  configurateItems: undefined,

  /**
    Menu click handler.
    Used to delegate menu items clicks handling.

    @method _onClickHandler
    @param {JQuery.Event} e Click event object.
    @private
  */
  _onClickHandler(e) {
    // Find clicked menu item element.
    let itemElement = Ember.$(e.target);
    if (!itemElement.hasClass('flexberry-menuitem')) {
      itemElement = itemElement.parents('.flexberry-menuitem');
    }

    // Replace currentTarget with clicked menu item element.
    e.currentTarget = itemElement[0];

    // Add clicked item's content to click event object.
    let item = itemElement.data('flexberry-menuitem.item');
    e.item = item;

    // Call onClick handler if it is specified in the given menu item.
    if (item && Ember.typeOf(item.onClick) === 'function' && this.get('callItemsOnClickCallbacks')) {
      item.onClick.call(e.currentTarget, e);
    }

    // Send 'onClick' action on clicked 'flexberry-menuitem' component.
    this.sendAction('onItemClick', e);
  },
});
<|endoftext|>


<commit_before>    var customIcons = {
    building: {
        icon: 'http://labs.google.com/ridefinder/images/mm_20_blue.png'
    },
    student_centre: {
        icon: 'http://labs.google.com/ridefinder/images/mm_20_red.png'
    },
    lecture_theatre: {
        icon: 'http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_green.png'
    },
    computer_lab: {
        icon: 'http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_yellow.png'
    },
    library: {
        icon: 'http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_black.png'
    }
    };

    var markerGroups = {
        "building": [],
        "student_centre": [],
        "lecture_theatre": [],
        "computer_lab": [],
        "library": [],
        "cycle_hire": [],
        "cycle_parking": [],
        "ATM": []
    };

    function loadMap() {
        var map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(51.527287, -0.103842),
        zoom: 15,
        mapTypeId: 'roadmap'
        });
        var infoWindow = new google.maps.InfoWindow({
            maxWidth: 400
        });

    // Change this depending on the name of your PHP file
    downloadUrl("../../includes/university-map/source/overview_source.php", function(data) {
        var xml = data.responseXML;
        var markers = xml.documentElement.getElementsByTagName("marker");
        for (var i = 0; i < markers.length; i++) {
        var name = markers[i].getAttribute("name");
        var notes = markers[i].getAttribute("notes");
        var category = markers[i].getAttribute("category");
        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var html = "" + name + "
" + notes;
        var marker = createMarker(point, name, notes, category, map);
        bindInfoWindow(marker, map, infoWindow, html);
        }
    });
    }

    function createMarker(point, name, notes, category, map) {
        var icon = customIcons[category] || {};
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,
            type: category
        });
        if (!markerGroups[category]) markerGroups[category] = [];
        markerGroups[type].push(marker);
        var html = "" + name + "
" + notes;
        bindInfoWindow(marker, map, infoWindow, html);
        return marker;
    }

    function toggleGroup(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            if (!marker.getVisible()) {
                marker.setVisible(true);
            } else {
                marker.setVisible(false);
            }
        }
    }

    function bindInfoWindow(marker, map, infoWindow, html) {
        google.maps.event.addListener(marker, 'click', function() {
        infoWindow.setContent(html);
        infoWindow.open(map, marker);
        });
    }

    function downloadUrl(url, callback) {
        var request = window.ActiveXObject ?
        new ActiveXObject('Microsoft.XMLHTTP') :
        new XMLHttpRequest;

    request.onreadystatechange = function() {
        if (request.readyState == 4) {
        request.onreadystatechange = doNothing;
        callback(request, request.status);
        }
    };

    request.open('GET', url, true);
    request.send(null);
    }

    function doNothing() {}<commit_msg>Changed structure<commit_after>    var customIcons = {
    building: {
        icon: 'http://labs.google.com/ridefinder/images/mm_20_blue.png'
    },
    student_centre: {
        icon: 'http://labs.google.com/ridefinder/images/mm_20_red.png'
    },
    lecture_theatre: {
        icon: 'http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_green.png'
    },
    computer_lab: {
        icon: 'http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_yellow.png'
    },
    library: {
        icon: 'http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_black.png'
    }
    };

    var markerGroups = {
        "building": [],
        "student_centre": [],
        "lecture_theatre": [],
        "computer_lab": [],
        "library": [],
        "cycle_hire": [],
        "cycle_parking": [],
        "ATM": []
    };

    function loadMap() {
        var map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(51.527287, -0.103842),
        zoom: 15,
        mapTypeId: 'roadmap'
        });
        var infoWindow = new google.maps.InfoWindow({
            maxWidth: 400
        });

    // Change this depending on the name of your PHP file
    downloadUrl("../../includes/university-map/source/overview_source.php", function(data) {
        var xml = data.responseXML;
        var markers = xml.documentElement.getElementsByTagName("marker");
        for (var i = 0; i < markers.length; i++) {
        var name = markers[i].getAttribute("name");
        var notes = markers[i].getAttribute("notes");
        var category = markers[i].getAttribute("category");
        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var html = "" + name + "
" + notes;
        var marker = createMarker(point, name, notes, category, map);
        bindInfoWindow(marker, map, infoWindow, html);
        }
    });
    }

    function createMarker(point, name, notes, category, map) {
        var icon = customIcons[category] || {};
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,
            type: category
        });
        if (!markerGroups[category]) markerGroups[category] = [];
        markerGroups[category].push(marker);
        var html = "" + name + "
" + notes;
        bindInfoWindow(marker, map, infoWindow, html);
        return marker;
    }

    function toggleGroup(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            if (!marker.getVisible()) {
                marker.setVisible(true);
            } else {
                marker.setVisible(false);
            }
        }
    }

    function bindInfoWindow(marker, map, infoWindow, html) {
        google.maps.event.addListener(marker, 'click', function() {
        infoWindow.setContent(html);
        infoWindow.open(map, marker);
        });
    }

    function downloadUrl(url, callback) {
        var request = window.ActiveXObject ?
        new ActiveXObject('Microsoft.XMLHTTP') :
        new XMLHttpRequest;

    request.onreadystatechange = function() {
        if (request.readyState == 4) {
        request.onreadystatechange = doNothing;
        callback(request, request.status);
        }
    };

    request.open('GET', url, true);
    request.send(null);
    }

    function doNothing() {}<|endoftext|>


<commit_before>import addons from '@storybook/addons';
import uuid from 'uuid/v1';
import { action } from './preview';

jest.mock('uuid/v1');
jest.mock('@storybook/addons');

describe('preview', () => {
  describe('action()', () => {
    it('should use a uuid for action ids', () => {
      const channel = { emit: jest.fn() };
      const uuidGenerator = (function*() {
        yield '42';
        yield '24';
      })();
      uuid.mockImplementation(() => uuidGenerator.next().value);
      addons.getChannel.mockReturnValue(channel);
      const fn = action('foo');

      fn();
      fn();
      expect(channel.emit).toHaveBeenCalledTimes(2);
      expect(channel.emit.mock.calls[0][1].id).toBe('42');
      expect(channel.emit.mock.calls[1][1].id).toBe('24');
    });
  });
});
<commit_msg>add test<commit_after>import addons from '@storybook/addons';
import uuid from 'uuid/v1';
import { action } from './preview';

jest.mock('uuid/v1');
jest.mock('@storybook/addons');

describe('preview', () => {
  describe('action()', () => {
    it('should use a uuid for action ids', () => {
      const channel = { emit: jest.fn() };
      const uuidGenerator = (function*() {
        yield '42';
        yield '24';
      })();
      uuid.mockImplementation(() => uuidGenerator.next().value);
      addons.getChannel.mockReturnValue(channel);
      const fn = action('foo');

      fn();
      fn();
      expect(channel.emit).toHaveBeenCalledTimes(2);
      expect(channel.emit.mock.calls[0][1].id).toBe('42');
      expect(channel.emit.mock.calls[1][1].id).toBe('24');
    });
    it('should be able to handle cyclic object without hanging', () => {
      action('foo')(process);
    });
  });
});
<|endoftext|>


<commit_before>L.Control.ZoomMin = L.Control.Zoom.extend({
  options: {
    position: "topleft",
    zoomInText: "+",
    zoomInTitle: "Zoom in",
    zoomOutText: "-",
    zoomOutTitle: "Zoom out",
    zoomMinText: "Zoom min",
    zoomMinTitle: "Zoom min"
  },

  onAdd: function (map) {
    var zoomName = "leaflet-control-zoom"
      , container = L.DomUtil.create("div", zoomName + " leaflet-bar")
      , options = this.options

    this._map = map

    this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,
     zoomName + '-in', container, this._zoomIn, this)

    this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
     zoomName + '-out', container, this._zoomOut, this)

    this._zoomMinButton = this._createButton(options.zoomMinText, options.zoomMinTitle,
     zoomName + '-min', container, this._zoomMin, this)

    this._updateDisabled()
    map.on('zoomend zoomlevelschange', this._updateDisabled, this)

    return container
  },

  _zoomMin: function () {
    this._map.setZoom(this._map.getMinZoom())
  },

  _updateDisabled: function () {
    var map = this._map
      , className = "leaflet-disabled"

    L.DomUtil.removeClass(this._zoomInButton, className)
    L.DomUtil.removeClass(this._zoomOutButton, className)
    L.DomUtil.removeClass(this._zoomMinButton, className)

    if (map._zoom === map.getMinZoom()) {
      L.DomUtil.addClass(this._zoomOutButton, className)
    }

    if (map._zoom === map.getMaxZoom()) {
      L.DomUtil.addClass(this._zoomInButton, className)
    }

    if (map._zoom === map.getMinZoom()) {
      L.DomUtil.addClass(this._zoomMinButton, className)
    }
  }
})<commit_msg>option for minBounds rather that just min zoom<commit_after>L.Control.ZoomMin = L.Control.Zoom.extend({
  options: {
    position: "topleft",
    zoomInText: "+",
    zoomInTitle: "Zoom in",
    zoomOutText: "-",
    zoomOutTitle: "Zoom out",
    zoomMinText: "Zoom min",
    zoomMinTitle: "Zoom min"
  },

  onAdd: function (map) {
    var zoomName = "leaflet-control-zoom"
      , container = L.DomUtil.create("div", zoomName + " leaflet-bar")
      , options = this.options

    this._map = map

    this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,
     zoomName + '-in', container, this._zoomIn, this)

    this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
     zoomName + '-out', container, this._zoomOut, this)

    this._zoomMinButton = this._createButton(options.zoomMinText, options.zoomMinTitle,
     zoomName + '-min', container, this._zoomMin, this)

    this._updateDisabled()
    map.on('zoomend zoomlevelschange', this._updateDisabled, this)

    return container
  },

  _zoomMin: function () {
    if (this.options.minBounds) {
      return this._map.fitBounds(this.options.minBounds);
    }

    this._map.setZoom(this._map.getMinZoom())
  },

  _updateDisabled: function () {
    var map = this._map
      , className = "leaflet-disabled"

    L.DomUtil.removeClass(this._zoomInButton, className)
    L.DomUtil.removeClass(this._zoomOutButton, className)
    L.DomUtil.removeClass(this._zoomMinButton, className)

    if (map._zoom === map.getMinZoom()) {
      L.DomUtil.addClass(this._zoomOutButton, className)
    }

    if (map._zoom === map.getMaxZoom()) {
      L.DomUtil.addClass(this._zoomInButton, className)
    }

    if (map._zoom === map.getMinZoom()) {
      L.DomUtil.addClass(this._zoomMinButton, className)
    }
  }
})
<|endoftext|>