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

/**
 * Renderer for standard form equation with integer coefficients that can be changed.
 * Form is y = ax^2 + bx + c, where a, b, and c can be changed with number pickers
 *
 * @author Andrea Lin
 */
define( require => {
  'use strict';

  // modules
  const CoefficientSlider = require( 'GRAPHING_QUADRATICS/common/view/CoefficientSlider' );
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const GQSymbols = require( 'GRAPHING_QUADRATICS/common/GQSymbols' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const MathSymbols = require( 'SCENERY_PHET/MathSymbols' );
  const Node = require( 'SCENERY/nodes/Node' );
  const NumberDisplay = require( 'SCENERY_PHET/NumberDisplay' );
  const NumberProperty = require( 'AXON/NumberProperty' );
  const PhetFont = require( 'SCENERY_PHET/PhetFont' );
  const Property = require( 'AXON/Property' );
  const Quadratic = require( 'GRAPHING_QUADRATICS/common/model/Quadratic' );
  const QuadraticCoefficientSlider = require( 'GRAPHING_QUADRATICS/common/view/QuadraticCoefficientSlider' );
  const RichText = require( 'SCENERY/nodes/RichText' );

  class ExploreInteractiveEquationNode extends Node {

    /**
     * @param {Property.<Quadratic|undefined>} quadraticProperty
     * @param {RangeWithValue} aRange
     * @param {RangeWithValue} bRange
     * @param {RangeWithValue} cRange
     * @param {Object} [options]
     */
    constructor( quadraticProperty, aRange, bRange, cRange, options ) {

      options = options || {};

      // coefficient Properties
      const aProperty = new NumberProperty( aRange.defaultValue, { range: aRange, reentrant: true } );
      const bProperty = new NumberProperty( bRange.defaultValue, { range: bRange } );
      const cProperty = new NumberProperty( cRange.defaultValue, { range: cRange } );

      // dynamic parts of the equation (coefficients)
      const numberDisplayOptions = {
        font: new PhetFont( { size: GQConstants.INTERACTIVE_EQUATION_FONT_SIZE, weight: 'bold' } ),
        backgroundFill: null,
        backgroundStroke: null,
        xMargin: 0,
        yMargin: 0
      };
      const aDisplay = new NumberDisplay( aProperty, aProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.EXPLORE_A,
        decimalPlaces: 2
      } ) );
      const bDisplay = new NumberDisplay( bProperty, bProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.EXPLORE_B,
        decimalPlaces: 1
      } ) );
      const cDisplay = new NumberDisplay( cProperty, bProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.EXPLORE_C,
        decimalPlaces: 1
      } ) );

      // static parts of the equation
      const richTextOptions = { font: new PhetFont( GQConstants.INTERACTIVE_EQUATION_FONT_SIZE ) };
      const yText = new RichText( GQSymbols.y, richTextOptions );
      const equalToText = new RichText( MathSymbols.EQUAL_TO, richTextOptions );
      const xSquaredText = new RichText( GQSymbols.xSquared, richTextOptions );
      const plusText = new RichText( MathSymbols.PLUS, richTextOptions );
      const xText = new RichText( GQSymbols.x, richTextOptions );
      const secondPlusText = new RichText( MathSymbols.PLUS, richTextOptions );

      // coefficient sliders
      const aSlider = new QuadraticCoefficientSlider( GQSymbols.a, aProperty, {
        interval: GQConstants.EXPLORE_SLIDER_INTERVAL_A,
        labelColor: GQColors.EXPLORE_A
      } );
      const bSlider = new CoefficientSlider( GQSymbols.b, bProperty, {
        interval: GQConstants.EXPLORE_SLIDER_INTERVAL_B,
        labelColor: GQColors.EXPLORE_B
      } );
      const cSlider = new CoefficientSlider( GQSymbols.c, cProperty, {
        interval: GQConstants.EXPLORE_SLIDER_INTERVAL_C,
        labelColor: GQColors.EXPLORE_C
      } );

      assert && assert( !options.children, 'ExploreInteractiveEquationNode sets children' );
      options.children = [
        yText, equalToText, aDisplay, xSquaredText, plusText, bDisplay, xText, secondPlusText, cDisplay,
        aSlider, bSlider, cSlider
      ];

      super( options );

      //TODO empirically isn't going to cut it because of variation in font size across platforms
      // equation layout, spacing determined empirically
      equalToText.left = yText.right + 10;
      aDisplay.left = equalToText.right + 10;
      xSquaredText.left = aDisplay.right + 5;
      plusText.left = xSquaredText.right + 10;
      bDisplay.left = plusText.right + 10;
      xText.left = bDisplay.right + 5;
      secondPlusText.left = xText.right + 10;
      cDisplay.left = secondPlusText.right + 10;
      aDisplay.bottom = yText.bottom;
      bDisplay.bottom = yText.bottom;
      cDisplay.bottom = yText.bottom;

      // sliders below equation
      const ySpacing = 5;
      aSlider.centerX = aDisplay.centerX;
      bSlider.centerX = bDisplay.centerX;
      cSlider.centerX = cDisplay.centerX;
      aSlider.top = aDisplay.bottom + ySpacing;
      bSlider.top = bDisplay.bottom + ySpacing;
      cSlider.top = cDisplay.bottom + ySpacing;

      // When the quadratic changes, update the coefficients.
      quadraticProperty.link( quadratic => {
        if ( quadratic.a !== aProperty.value ) {
          aProperty.value = quadratic.a;
        }
        if ( quadratic.b !== bProperty.value ) {
          bProperty.value = quadratic.b;
        }
        if ( quadratic.c !== cProperty.value ) {
          cProperty.value = quadratic.c;
        }
      } );

      // When the coefficients change, update the quadratic.
      Property.multilink( [ aProperty, bProperty, cProperty ], ( a, b, c ) => {
        quadraticProperty.value = new Quadratic( a, b, c, { color: quadraticProperty.value.color } );
      } );
    }
  }

  return graphingQuadratics.register( 'ExploreInteractiveEquationNode', ExploreInteractiveEquationNode );
} );
<commit_msg>TODO<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Renderer for standard form equation with integer coefficients that can be changed.
 * Form is y = ax^2 + bx + c, where a, b, and c can be changed with number pickers
 *
 * @author Andrea Lin
 */
define( require => {
  'use strict';

  // modules
  const CoefficientSlider = require( 'GRAPHING_QUADRATICS/common/view/CoefficientSlider' );
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const GQSymbols = require( 'GRAPHING_QUADRATICS/common/GQSymbols' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const MathSymbols = require( 'SCENERY_PHET/MathSymbols' );
  const Node = require( 'SCENERY/nodes/Node' );
  const NumberDisplay = require( 'SCENERY_PHET/NumberDisplay' );
  const NumberProperty = require( 'AXON/NumberProperty' );
  const PhetFont = require( 'SCENERY_PHET/PhetFont' );
  const Property = require( 'AXON/Property' );
  const Quadratic = require( 'GRAPHING_QUADRATICS/common/model/Quadratic' );
  const QuadraticCoefficientSlider = require( 'GRAPHING_QUADRATICS/common/view/QuadraticCoefficientSlider' );
  const RichText = require( 'SCENERY/nodes/RichText' );

  class ExploreInteractiveEquationNode extends Node {

    /**
     * @param {Property.<Quadratic|undefined>} quadraticProperty
     * @param {RangeWithValue} aRange
     * @param {RangeWithValue} bRange
     * @param {RangeWithValue} cRange
     * @param {Object} [options]
     */
    constructor( quadraticProperty, aRange, bRange, cRange, options ) {

      options = options || {};

      // coefficient Properties
      const aProperty = new NumberProperty( aRange.defaultValue, { range: aRange, reentrant: true } );
      const bProperty = new NumberProperty( bRange.defaultValue, { range: bRange } );
      const cProperty = new NumberProperty( cRange.defaultValue, { range: cRange } );

      // dynamic parts of the equation (coefficients)
      const numberDisplayOptions = {
        font: new PhetFont( { size: GQConstants.INTERACTIVE_EQUATION_FONT_SIZE, weight: 'bold' } ),
        backgroundFill: null,
        backgroundStroke: null,
        xMargin: 0,
        yMargin: 0
      };
      const aDisplay = new NumberDisplay( aProperty, aProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.EXPLORE_A,
        decimalPlaces: 2
      } ) );
      const bDisplay = new NumberDisplay( bProperty, bProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.EXPLORE_B,
        decimalPlaces: 1
      } ) );
      const cDisplay = new NumberDisplay( cProperty, bProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.EXPLORE_C,
        decimalPlaces: 1
      } ) );

      // static parts of the equation
      const richTextOptions = { font: new PhetFont( GQConstants.INTERACTIVE_EQUATION_FONT_SIZE ) };
      const yText = new RichText( GQSymbols.y, richTextOptions );
      const equalToText = new RichText( MathSymbols.EQUAL_TO, richTextOptions );
      const xSquaredText = new RichText( GQSymbols.xSquared, richTextOptions );
      const plusText = new RichText( MathSymbols.PLUS, richTextOptions );
      const xText = new RichText( GQSymbols.x, richTextOptions );
      const secondPlusText = new RichText( MathSymbols.PLUS, richTextOptions );

      // coefficient sliders
      const aSlider = new QuadraticCoefficientSlider( GQSymbols.a, aProperty, {
        interval: GQConstants.EXPLORE_SLIDER_INTERVAL_A,
        labelColor: GQColors.EXPLORE_A
      } );
      const bSlider = new CoefficientSlider( GQSymbols.b, bProperty, {
        interval: GQConstants.EXPLORE_SLIDER_INTERVAL_B,
        labelColor: GQColors.EXPLORE_B
      } );
      const cSlider = new CoefficientSlider( GQSymbols.c, cProperty, {
        interval: GQConstants.EXPLORE_SLIDER_INTERVAL_C,
        labelColor: GQColors.EXPLORE_C
      } );

      assert && assert( !options.children, 'ExploreInteractiveEquationNode sets children' );
      options.children = [
        yText, equalToText, aDisplay, xSquaredText, plusText, bDisplay, xText, secondPlusText, cDisplay,
        aSlider, bSlider, cSlider
      ];

      super( options );

      // equation layout, spacing determined empirically
      equalToText.left = yText.right + 10;
      aDisplay.left = equalToText.right + 10;
      xSquaredText.left = aDisplay.right + 5;
      plusText.left = xSquaredText.right + 10;
      bDisplay.left = plusText.right + 10;
      xText.left = bDisplay.right + 5;
      secondPlusText.left = xText.right + 10;
      cDisplay.left = secondPlusText.right + 10;
      aDisplay.bottom = yText.bottom;
      bDisplay.bottom = yText.bottom;
      cDisplay.bottom = yText.bottom;

      //TODO sliders are not quite centered under values
      // sliders below equation
      const ySpacing = 5;
      aSlider.centerX = aDisplay.centerX;
      bSlider.centerX = bDisplay.centerX;
      cSlider.centerX = cDisplay.centerX;
      aSlider.top = aDisplay.bottom + ySpacing;
      bSlider.top = bDisplay.bottom + ySpacing;
      cSlider.top = cDisplay.bottom + ySpacing;

      // When the quadratic changes, update the coefficients.
      quadraticProperty.link( quadratic => {
        if ( quadratic.a !== aProperty.value ) {
          aProperty.value = quadratic.a;
        }
        if ( quadratic.b !== bProperty.value ) {
          bProperty.value = quadratic.b;
        }
        if ( quadratic.c !== cProperty.value ) {
          cProperty.value = quadratic.c;
        }
      } );

      // When the coefficients change, update the quadratic.
      Property.multilink( [ aProperty, bProperty, cProperty ], ( a, b, c ) => {
        quadraticProperty.value = new Quadratic( a, b, c, { color: quadraticProperty.value.color } );
      } );
    }
  }

  return graphingQuadratics.register( 'ExploreInteractiveEquationNode', ExploreInteractiveEquationNode );
} );
<|endoftext|>


<commit_before>import {Container} from 'aurelia-dependency-injection';
import {View} from './view';
import {ViewSlot} from './view-slot';
import {ContentSelector} from './content-selector';
import {ViewResources} from './resource-registry';

class BehaviorContainer extends Container {
  get(key){
    if(key === Element){
      return this.element;
    }

    if(key === BoundViewFactory){
      return this.boundViewFactory || (this.boundViewFactory = new BoundViewFactory(this, this.instruction.viewFactory, this.executionContext));
    }

    if(key === ViewSlot){
      if(this.viewSlot === undefined){
        this.viewSlot = new ViewSlot(this.element, this.instruction.anchorIsContainer, this.executionContext);
        this.children.push(this.viewSlot);
      }

      return this.viewSlot;
    }

    if(key === ViewResources){
      return this.viewResources;
    }

    return super.get(key);
  }
}

function applyInstructions(containers, executionContext, element, instruction,
  behaviors, bindings, children, contentSelectors, resources){
  var behaviorInstructions = instruction.behaviorInstructions,
      expressions = instruction.expressions,
      elementContainer, i, ii, providers, current, instance;

  if(instruction.contentExpression){
    bindings.push(instruction.contentExpression.createBinding(element.nextSibling));
    element.parentNode.removeChild(element);
    return;
  }

  if(instruction.contentSelector){
    contentSelectors.push(new ContentSelector(element, instruction.selector));
    return;
  }

  if(behaviorInstructions.length){
    containers[instruction.injectorId] = elementContainer = containers[instruction.parentInjectorId].createTypedChild(BehaviorContainer);

    elementContainer.element = element;
    elementContainer.instruction = instruction;
    elementContainer.executionContext = executionContext;
    elementContainer.children = children;
    elementContainer.viewResources = resources;

    providers = instruction.providers;
    i = providers.length;

    while(i--) {
      elementContainer.registerSingleton(providers[i]);
    }

    for(i = 0, ii = behaviorInstructions.length; i < ii; ++i){
      current = behaviorInstructions[i];
      instance = current.type.create(elementContainer, current, element, bindings);

      if(instance.contentView){
        children.push(instance.contentView);
      }

      behaviors.push(instance);
    }
  }

  for(i = 0, i = expressions.length; i < ii; ++i){
    bindings.push(expressions[i].createBinding(element));
  }
}

export class BoundViewFactory {
  constructor(parentContainer, viewFactory, executionContext){
    this.parentContainer = parentContainer;
    this.viewFactory = viewFactory;
    this.executionContext = executionContext;
    this.factoryOptions = { behaviorInstance:false };
  }

  create(executionContext){
    var childContainer = this.parentContainer.createChild(),
        context = executionContext || this.executionContext;

    this.factoryOptions.systemControlled = !executionContext;

    return this.viewFactory.create(childContainer, context, this.factoryOptions);
  }
}

var defaultFactoryOptions = {
  systemControlled:false,
  suppressBind:false
};

export class ViewFactory{
  constructor(template, instructions, resources){
    this.template = template;
    this.instructions = instructions;
    this.resources = resources;
  }

  create(container, executionContext, options=defaultFactoryOptions){
    var fragment = this.template.cloneNode(true),
        instructables = fragment.querySelectorAll('.au-target'),
        instructions = this.instructions,
        resources = this.resources,
        behaviors = [],
        bindings = [],
        children = [],
        contentSelectors = [],
        containers = { root:container },
        i, ii, view;

    for(i = 0, ii = instructables.length; i < ii; ++i){
      applyInstructions(containers, executionContext, instructables[i],
        instructions[i], behaviors, bindings, children, contentSelectors, resources);
    }

    view = new View(fragment, behaviors, bindings, children, options.systemControlled, contentSelectors);
    view.created(executionContext);

    if(!options.suppressBind){
      view.bind(executionContext);
    }

    return view;
  }
}<commit_msg>fix(view-factory): incorrect loop variable name<commit_after>import {Container} from 'aurelia-dependency-injection';
import {View} from './view';
import {ViewSlot} from './view-slot';
import {ContentSelector} from './content-selector';
import {ViewResources} from './resource-registry';

class BehaviorContainer extends Container {
  get(key){
    if(key === Element){
      return this.element;
    }

    if(key === BoundViewFactory){
      return this.boundViewFactory || (this.boundViewFactory = new BoundViewFactory(this, this.instruction.viewFactory, this.executionContext));
    }

    if(key === ViewSlot){
      if(this.viewSlot === undefined){
        this.viewSlot = new ViewSlot(this.element, this.instruction.anchorIsContainer, this.executionContext);
        this.children.push(this.viewSlot);
      }

      return this.viewSlot;
    }

    if(key === ViewResources){
      return this.viewResources;
    }

    return super.get(key);
  }
}

function applyInstructions(containers, executionContext, element, instruction,
  behaviors, bindings, children, contentSelectors, resources){
  var behaviorInstructions = instruction.behaviorInstructions,
      expressions = instruction.expressions,
      elementContainer, i, ii, providers, current, instance;

  if(instruction.contentExpression){
    bindings.push(instruction.contentExpression.createBinding(element.nextSibling));
    element.parentNode.removeChild(element);
    return;
  }

  if(instruction.contentSelector){
    contentSelectors.push(new ContentSelector(element, instruction.selector));
    return;
  }

  if(behaviorInstructions.length){
    containers[instruction.injectorId] = elementContainer = containers[instruction.parentInjectorId].createTypedChild(BehaviorContainer);

    elementContainer.element = element;
    elementContainer.instruction = instruction;
    elementContainer.executionContext = executionContext;
    elementContainer.children = children;
    elementContainer.viewResources = resources;

    providers = instruction.providers;
    i = providers.length;

    while(i--) {
      elementContainer.registerSingleton(providers[i]);
    }

    for(i = 0, ii = behaviorInstructions.length; i < ii; ++i){
      current = behaviorInstructions[i];
      instance = current.type.create(elementContainer, current, element, bindings);

      if(instance.contentView){
        children.push(instance.contentView);
      }

      behaviors.push(instance);
    }
  }

  for(i = 0, ii = expressions.length; i < ii; ++i){
    bindings.push(expressions[i].createBinding(element));
  }
}

export class BoundViewFactory {
  constructor(parentContainer, viewFactory, executionContext){
    this.parentContainer = parentContainer;
    this.viewFactory = viewFactory;
    this.executionContext = executionContext;
    this.factoryOptions = { behaviorInstance:false };
  }

  create(executionContext){
    var childContainer = this.parentContainer.createChild(),
        context = executionContext || this.executionContext;

    this.factoryOptions.systemControlled = !executionContext;

    return this.viewFactory.create(childContainer, context, this.factoryOptions);
  }
}

var defaultFactoryOptions = {
  systemControlled:false,
  suppressBind:false
};

export class ViewFactory{
  constructor(template, instructions, resources){
    this.template = template;
    this.instructions = instructions;
    this.resources = resources;
  }

  create(container, executionContext, options=defaultFactoryOptions){
    var fragment = this.template.cloneNode(true),
        instructables = fragment.querySelectorAll('.au-target'),
        instructions = this.instructions,
        resources = this.resources,
        behaviors = [],
        bindings = [],
        children = [],
        contentSelectors = [],
        containers = { root:container },
        i, ii, view;

    for(i = 0, ii = instructables.length; i < ii; ++i){
      applyInstructions(containers, executionContext, instructables[i],
        instructions[i], behaviors, bindings, children, contentSelectors, resources);
    }

    view = new View(fragment, behaviors, bindings, children, options.systemControlled, contentSelectors);
    view.created(executionContext);

    if(!options.suppressBind){
      view.bind(executionContext);
    }

    return view;
  }
}<|endoftext|>


<commit_before>import { h } from './vdom';

export const bold = {
  name: 'bold',
  selector: 'strong, b',
  vdom: children => {children},
};

export const italics = {
  name: 'italic',
  selector: 'em, i',
  vdom: children => {children},
};

export const link = {
  name: 'link',
  selector: 'a[href]',
  attr: node => node.href,
  vdom: (children, attr) => {children},
};
<commit_msg>Fix bug reading out links<commit_after>import { h } from './vdom';

export const bold = {
  name: 'bold',
  selector: 'strong, b',
  vdom: children => {children},
};

export const italics = {
  name: 'italic',
  selector: 'em, i',
  vdom: children => {children},
};

export const link = {
  name: 'link',
  selector: 'a[href]',
  dom: node => node.href,
  vdom: (children, attr) => {children},
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';
const program = require('commander');
const fs = require('fs');
const cheerio = require('cheerio');

require('babel-register')({
  presets: ['es2015']
});
const AST = require('../src/lib/format/ftl/ast/ast').default;
const Serializer = require('../src/lib/format/ftl/ast/serializer').default;

function trimString(str) {
  return str.split('\n').map(line => {
    return line.trim();
  }).join('\n');
}

function extractFromHTML(err, data) {
  const res = new AST.Resource();

  const $ = cheerio.load(data.toString());
  const elements = $('*[data-l10n-id]');
  elements.each(function(index, element) {

    const id = new AST.Identifier($(this).attr('data-l10n-id'));
    const value = new AST.Pattern(trimString($(this).text().trim()));

    const traits = [];

    for (let i in element.attribs) {
      if (i === 'title') {
        const id = new AST.Identifier(i, 'html');
        const value = new AST.Pattern($(this).attr(i));
        const trait = new AST.Member(id, value);
        traits.push(trait);
      }
    }
    res.body.push(new AST.Entity(id, value, traits));
  });

  console.log(Serializer.serialize(res));
}

function extractFromJS(err, data) {
}

program
  .version('0.0.1')
  .usage('[options] [file]')
  .parse(process.argv);

if (program.args[0].endsWith('.html')) {
  fs.readFile(program.args[0], extractFromHTML);
}
if (program.args[0].endsWith('.js')) {
  fs.readFile(program.args[0], extractFromJS);
}
<commit_msg>Support some variant of JS<commit_after>#!/usr/bin/env node

'use strict';
const program = require('commander');
const fs = require('fs');
const cheerio = require('cheerio');
const esprima = require('esprima');
const esprimaWalk = require('esprima-walk');

require('babel-register')({
  presets: ['es2015']
});
const AST = require('../src/lib/format/ftl/ast/ast').default;
const Serializer = require('../src/lib/format/ftl/ast/serializer').default;

function trimString(str) {
  return str.split('\n').map(line => {
    return line.trim();
  }).join('\n');
}

function extractFromHTML(err, data) {
  const res = new AST.Resource();

  const $ = cheerio.load(data.toString());
  const elements = $('*[data-l10n-id]');
  elements.each(function(index, element) {

    const id = new AST.Identifier($(this).attr('data-l10n-id'));
    const value = new AST.Pattern(trimString($(this).text().trim()));

    const traits = [];

    for (let i in element.attribs) {
      if (i === 'title') {
        const id = new AST.Identifier(i, 'html');
        const value = new AST.Pattern($(this).attr(i));
        const trait = new AST.Member(id, value);
        traits.push(trait);
      }
    }
    res.body.push(new AST.Entity(id, value, traits));
  });

  console.log(Serializer.serialize(res));
}

function extractFromJS(err, data) {
  const res = new AST.Resource();

  const ast = esprima.parse(data.toString());

  esprimaWalk(ast, node => {
    if (node.type === 'CallExpression') {
      if (node.callee.object.type === 'MemberExpression' &&
          node.callee.object.object.type === 'Identifier' &&
          node.callee.object.object.name === 'document' &&
          node.callee.object.property.type === 'Identifier' &&
          node.callee.object.property.name === 'l10n' &&
          node.callee.property.type === 'Identifier' &&
          node.callee.property.name === 'formatValue') {
        const id = node.arguments[0].value;
        const source = node.arguments[1].value;

        res.body.push(new AST.Entity(
          new AST.Identifier(id),
          new AST.Pattern(source)
        ));
      };
    }
  });

  console.log(Serializer.serialize(res));
}

program
  .version('0.0.1')
  .usage('[options] [file]')
  .parse(process.argv);

if (program.args[0].endsWith('.html')) {
  fs.readFile(program.args[0], extractFromHTML);
}
if (program.args[0].endsWith('.js')) {
  fs.readFile(program.args[0], extractFromJS);
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';
const program = require('commander');
const fs = require('fs');
const cheerio = require('cheerio');
const esprima = require('esprima');
const esprimaWalk = require('esprima-walk');

require('babel-register')({
  presets: ['es2015']
});
const AST = require('../src/lib/format/ftl/ast/ast').default;
const Serializer = require('../src/lib/format/ftl/ast/serializer').default;

function trimString(str) {
  return str.split('\n').map(line => {
    return line.trim();
  }).join('\n');
}

function extractFromHTML(err, data) {
  const res = new AST.Resource();

  const $ = cheerio.load(data.toString());
  const elements = $('*[data-l10n-id]');
  elements.each(function(index, element) {

    const id = new AST.Identifier($(this).attr('data-l10n-id'));
    const value = new AST.Pattern(trimString($(this).text().trim()));

    const traits = [];

    for (let i in element.attribs) {
      if (i === 'title') {
        const id = new AST.Identifier(i, 'html');
        const value = new AST.Pattern($(this).attr(i));
        const trait = new AST.Member(id, value);
        traits.push(trait);
      }
    }
    res.body.push(new AST.Entity(id, value, traits));
  });

  console.log(Serializer.serialize(res));
}

function extractFromJS(err, data) {
  const res = new AST.Resource();

  const ast = esprima.parse(data.toString());

  esprimaWalk(ast, node => {
    if (node.type === 'CallExpression') {
      if (node.callee.object.type === 'MemberExpression' &&
          node.callee.object.object.type === 'Identifier' &&
          node.callee.object.object.name === 'document' &&
          node.callee.object.property.type === 'Identifier' &&
          node.callee.object.property.name === 'l10n' &&
          node.callee.property.type === 'Identifier' &&
          node.callee.property.name === 'formatValue') {
        const id = node.arguments[0].value;
        const source = node.arguments[1].value;

        res.body.push(new AST.Entity(
          new AST.Identifier(id),
          new AST.Pattern(source)
        ));
      };
    }
  });

  console.log(Serializer.serialize(res));
}

program
  .version('0.0.1')
  .usage('[options] [file]')
  .parse(process.argv);

if (program.args[0].endsWith('.html')) {
  fs.readFile(program.args[0], extractFromHTML);
}
if (program.args[0].endsWith('.js')) {
  fs.readFile(program.args[0], extractFromJS);
}
<commit_msg>And support setAttributes in extract-strings<commit_after>#!/usr/bin/env node

'use strict';
const program = require('commander');
const fs = require('fs');
const cheerio = require('cheerio');
const esprima = require('esprima');
const esprimaWalk = require('esprima-walk');

require('babel-register')({
  presets: ['es2015']
});
const AST = require('../src/lib/format/ftl/ast/ast').default;
const Serializer = require('../src/lib/format/ftl/ast/serializer').default;

function trimString(str) {
  return str.split('\n').map(line => {
    return line.trim();
  }).join('\n');
}

function extractFromHTML(err, data) {
  const res = new AST.Resource();

  const $ = cheerio.load(data.toString());
  const elements = $('*[data-l10n-id]');
  elements.each(function(index, element) {

    const id = new AST.Identifier($(this).attr('data-l10n-id'));
    const value = new AST.Pattern(trimString($(this).text().trim()));

    const traits = [];

    for (let i in element.attribs) {
      if (i === 'title') {
        const id = new AST.Identifier(i, 'html');
        const value = new AST.Pattern($(this).attr(i));
        const trait = new AST.Member(id, value);
        traits.push(trait);
      }
    }
    res.body.push(new AST.Entity(id, value, traits));
  });

  console.log(Serializer.serialize(res));
}

function extractFromJS(err, data) {
  const res = new AST.Resource();

  const ast = esprima.parse(data.toString());

  esprimaWalk(ast, node => {
    if (node.type === 'CallExpression') {
      if (node.callee.object.type === 'MemberExpression' &&
          node.callee.object.object.type === 'Identifier' &&
          node.callee.object.object.name === 'document' &&
          node.callee.object.property.type === 'Identifier' &&
          node.callee.object.property.name === 'l10n') {

        if(node.callee.property.type === 'Identifier' &&
            node.callee.property.name === 'formatValue') {
          const id = node.arguments[0].value;
          const source = node.arguments[1].value;

          res.body.push(new AST.Entity(
            new AST.Identifier(id),
            new AST.Pattern(source)
          ));
        }
        if(node.callee.property.type === 'Identifier' &&
            node.callee.property.name === 'setAttributes') {
          const id = node.arguments[1].value;
          const source = node.arguments[2].value;

          res.body.push(new AST.Entity(
            new AST.Identifier(id),
            new AST.Pattern(source)
          ));
        }
      }
    }
  });

  console.log(Serializer.serialize(res));
}

program
  .version('0.0.1')
  .usage('[options] [file]')
  .parse(process.argv);

if (program.args[0].endsWith('.html')) {
  fs.readFile(program.args[0], extractFromHTML);
}
if (program.args[0].endsWith('.js')) {
  fs.readFile(program.args[0], extractFromJS);
}
<|endoftext|>


<commit_before>;(function($){

	var defaults = {
		handleSize: 10,
		handleColor: "red",
		handleLineWidth: 1,
		lineType: "draw", // can be "straight" or "draw"
		edgeType: function( sourceNode, targetNode ){
			return "node"; // can return "flat" for flat edges between nodes or "node" for intermediate node between them
			// returning null/undefined means an edge can't be added between the two nodes
		},
		loopAllowed: function( node ){
			return false;
		},
		nodeParams: function( sourceNode, targetNode ){
			return {};
		},
		edgeParams: function( sourceNode, targetNode ){
			return {};
		},
		start: function( sourceNode ){
			// fired when edgehandles interaction starts (drag on handle)
		},
		complete: function( sourceNode, targetNodes, addedEntities ){
			// fired when edgehandles is done and entities are added
		},
		stop: function( sourceNode ){
			// fired when edgehandles interaction is stopped (either complete with added edges or incomplete)
		}
	};

	$.fn.cytoscapewebEdgehandles = function( params ){
		var fn = params;

		var functions = {
			destroy: function(){
				var $container = $(this);
				var data = $container.data("cyedgehandles");

				if( data == null ){
					return;
				}

				data.unbind();
				$container.data("cyedgehandles", {});

				return $container;
			},

			option: function(name, value){
				var $container = $(this);
				var data = $container.data("cyedgehandles");

				if( data == null ){
					return;
				}

				var options = data.options;

				if( value === undefined ){
					if( typeof name == typeof {} ){
						var newOpts = name;
						options = $.extend(true, {}, defaults, newOpts);
						data.options = options;
					} else {
						return options[ name ];
					}
				} else {
					options[ name ] = value;
				}

				return $container;
			},

			init: function(){
				var options = $.extend(true, {}, defaults, params);
				var $container = $(this);
				var svg, cy;
				var handle;
				var line, linePoints;
				var mdownOnHandle = false;
				var grabbingNode = false;
				var hx, hy, hr;

				// write options to data
				var data = $container.data("cyedgehandles");
				if( data == null ){
					data = {};
				}
				data.options = options;

				function svgIsInCy( svgDomElement ){
					var $ele = $(svgDomElement);
					var inside = false;

					$ele.parents().each(function(){
						if( this == $container[0] ){
							inside = true;
						}
					});

					return inside;
				}

				function safelyRemoveCySvgChild( svgDomElement ){
					if( svgDomElement != null && svgIsInCy( svgDomElement ) ){
						svg.remove( svgDomElement );
					}
				}

				function resetToDefaultState(){
//					console.log("resetToDefaultState");

					safelyRemoveCySvgChild( handle );
					safelyRemoveCySvgChild( line );

					cy.nodes()
						.removeClass("ui-cytoscapeweb-edgehandles-hover")
						.removeClass("ui-cytoscapeweb-edgehandles-source")
						.removeClass("ui-cytoscapeweb-edgehandles-target")
					;

					linePoints = null;

					cy.zooming(true).panning(true);
				}

				function makePreview( source, target ){
					makeEdges( true );
				}

				function removePreview( source, target ){
					source.edgesWith(target).filter(".ui-cytoscapeweb-edgehandles-preview").remove();

					target
						.neighborhood("node.ui-cytoscapeweb-edgehandles-preview")
						.closedNeighborhood(".ui-cytoscapeweb-edgehandles-preview")
						.remove();

				}

				function makeEdges( preview ){

					// console.log("make edges");

					var source = cy.nodes(".ui-cytoscapeweb-edgehandles-source");
					var targets = cy.nodes(".ui-cytoscapeweb-edgehandles-target");
					var classes = preview ? "ui-cytoscapeweb-edgehandles-preview" : "";
					var added = cy.collection();

					if( source.size() == 0 || targets.size() == 0 ){
						return; // nothing to do :(
					}

					// just remove preview class if we already have the edges
					if( !preview && options.preview ){
						added = cy.elements(".ui-cytoscapeweb-edgehandles-preview").removeClass("ui-cytoscapeweb-edgehandles-preview");

						options.complete( source, targets, added );
						return;
					} else {
						// remove old previews
						cy.elements(".ui-cytoscapeweb-edgehandles-preview").remove();
					}

					targets.each(function(i, target){
						switch( options.edgeType( source, target ) ){
						case "node":

							var p1 = source.position(false);
							var p2 = target.position(false);
							var p = {
								x: (p1.x + p2.x)/2,
								y: (p1.y + p2.y)/2
							};

							var interNode = cy.add($.extend( true, {
								group: "nodes",
								position: p
							}, options.nodeParams(source, target) )).addClass(classes);

							var source2inter = cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: interNode.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);

							var inter2target = cy.add($.extend( true, {
								group: "edges",
								data: {
									source: interNode.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);

							added = added.add( interNode ).add( source2inter ).add( inter2target );

							break;

						case "flat":
							var edge = cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);

							added = added.add( edge );

							break;

						default:
							target.removeClass("ui-cytoscapeweb-edgehandles-target");
							break; // don't add anything
						}
					});

					if( !preview ){
						options.complete( source, targets, added );
					}
				}

				$container.cytoscapeweb(function(e){
					cy = this;
					svg = $container.svg("get");

					var transformHandler;
					cy.bind("zoom pan", transformHandler = function(){
						safelyRemoveCySvgChild( handle );
					});

					var startHandler, hoverHandler, leaveHandler, grabNodeHandler, freeNodeHandler;
					cy.nodes().live("mouseover", startHandler = function(e){
						if( mdownOnHandle || grabbingNode || this.hasClass("ui-cytoscapeweb-edgehandles-preview") ){
							return; // don't override existing handle that's being dragged
							// also don't trigger when grabbing a node
						}

						// console.log("node mover");

						var node = this;
						var source = this;
						var p = node.renderedPosition();
						var d = node.renderedDimensions();

						// remove old handle
						safelyRemoveCySvgChild( handle );

						hx = p.x;
						hy = p.y - d.height/2;
						hr = options.handleSize/2;

						// add new handle
						handle = svg.circle(hx, hy, hr, {
							fill: options.handleColor
						});
						var $handle = $(handle);

						function mdownHandler(e){
							if( e.button != 0 ){
								return; // sorry, no right clicks allowed
							}

//							console.log("-- mdownHandler %o --", e);

							mdownOnHandle = true;

							e.preventDefault();
							node.unbind("mouseout", removeHandler);
							$handle.unbind("mouseout", removeHandler);

							node.addClass("ui-cytoscapeweb-edgehandles-source");

							function doneMoving(dmEvent){
//								console.log("doneMoving %o", dmEvent);

								if( !mdownOnHandle ){
									return;
								}

								var $this = $(this);
								mdownOnHandle = false;
								$(window).unbind("mousemove", moveHandler);

								makeEdges();
								resetToDefaultState();

								options.stop( node );
							}

							$(window).one("mouseup blur", doneMoving).bind("mousemove", moveHandler);
							cy.zooming(false).panning(false);

							options.start( node );
						}

						function moveHandler(e){
							// console.log("move");

							var x = e.pageX - $container.offset().left;
							var y = e.pageY - $container.offset().top;

							safelyRemoveCySvgChild( line );

							var style = {
								stroke: options.handleColor,
								strokeWidth: options.handleLineWidth,
								fill: "none",
								"pointer-events": "none"
							};

							// draw line based on type
							switch( options.lineType ){
							case "straight":

								line = svg.line(hx, hy, x, y, style);

								break;
							case "draw":
							default:

								if( linePoints == null ){
									linePoints = [ [hx, hy], [x, y] ];
								} else {
									linePoints.push([ x, y ]);
								}

								line = svg.polyline(linePoints, style);

								break;
							}

						}

						function removeHandler(e){
							var newTargetIsHandle = e.toElement == handle;
							var newTargetIsNode = e.toElement == node._private.renderer.svg;

							if( newTargetIsHandle || newTargetIsNode || mdownOnHandle ){
								return; // don't consider mouseout
							}

//							console.log("removeHandler %o", e);

							node.unbind("mouseout", removeHandler);
							resetToDefaultState();
						}

						node.bind("mouseout", removeHandler);
						$handle.bind("mouseout", removeHandler);
						$handle.bind("mousedown", mdownHandler);

					}).live("mouseover", hoverHandler = function(){
						if( this.hasClass("ui-cytoscapeweb-edgehandles-preview") ){
							return; // ignore preview nodes
						}

						if( mdownOnHandle ){ // only handle mdown case
							var node = this;
							var target = this;
							var source = cy.nodes(".ui-cytoscapeweb-edgehandles-source");

							var isLoop = node.hasClass("ui-cytoscapeweb-edgehandles-source");
							var loopAllowed = options.loopAllowed( node );

							if( !isLoop || (isLoop && loopAllowed) ){
								this.addClass("ui-cytoscapeweb-edgehandles-hover");
								this.toggleClass("ui-cytoscapeweb-edgehandles-target");

								if( options.preview ){
									if( this.hasClass("ui-cytoscapeweb-edgehandles-target") ){
										makePreview( source, target );
									} else {
										removePreview( source, target );
									}
								}
							}
						}
					}).live("mouseout", leaveHandler = function(){
						this.removeClass("ui-cytoscapeweb-edgehandles-hover");
					}).live("grab", grabNodeHandler = function(){
						grabbingNode = true;
						resetToDefaultState();
					}).live("free", freeNodeHandler = function(){
						grabbingNode = false;
					});

					data.unbind = function(){
						cy.nodes()
							.die("mouseover", startHandler)
							.die("mouseover", hoverHandler)
							.die("mouseout", leaveHandler)
							.die("grab", grabNodeHandler)
							.die("free", freeNodeHandler)
						;

						cy.unbind("zoom pan", transformHandler);
					};
				});

				$container.data("cyedgehandles", data);
			}
		};

		if( functions[fn] ){
			return functions[fn].apply(this, Array.prototype.slice.call( arguments, 1 ));
		} else if( typeof fn == 'object' || !fn ) {
			return functions.init.apply( this, arguments );
		} else {
			$.error("No such function `"+ fn +"` for jquery.cytoscapewebEdgeHandles");
		}

		return $(this);
	};

})( jQuery );<commit_msg>add hoverDelay to edgehandles<commit_after>;(function($){

	var defaults = {
		handleSize: 10,
		handleColor: "red",
		handleLineWidth: 1,
		hoverDelay: 100,
		lineType: "draw", // can be "straight" or "draw"
		edgeType: function( sourceNode, targetNode ){
			return "node"; // can return "flat" for flat edges between nodes or "node" for intermediate node between them
			// returning null/undefined means an edge can't be added between the two nodes
		},
		loopAllowed: function( node ){
			return false;
		},
		nodeParams: function( sourceNode, targetNode ){
			return {};
		},
		edgeParams: function( sourceNode, targetNode ){
			return {};
		},
		start: function( sourceNode ){
			// fired when edgehandles interaction starts (drag on handle)
		},
		complete: function( sourceNode, targetNodes, addedEntities ){
			// fired when edgehandles is done and entities are added
		},
		stop: function( sourceNode ){
			// fired when edgehandles interaction is stopped (either complete with added edges or incomplete)
		}
	};

	$.fn.cytoscapewebEdgehandles = function( params ){
		var fn = params;

		var functions = {
			destroy: function(){
				var $container = $(this);
				var data = $container.data("cyedgehandles");

				if( data == null ){
					return;
				}

				data.unbind();
				$container.data("cyedgehandles", {});

				return $container;
			},

			option: function(name, value){
				var $container = $(this);
				var data = $container.data("cyedgehandles");

				if( data == null ){
					return;
				}

				var options = data.options;

				if( value === undefined ){
					if( typeof name == typeof {} ){
						var newOpts = name;
						options = $.extend(true, {}, defaults, newOpts);
						data.options = options;
					} else {
						return options[ name ];
					}
				} else {
					options[ name ] = value;
				}

				return $container;
			},

			init: function(){
				var options = $.extend(true, {}, defaults, params);
				var $container = $(this);
				var svg, cy;
				var handle;
				var line, linePoints;
				var mdownOnHandle = false;
				var grabbingNode = false;
				var hx, hy, hr;
				var hoverTimeout;

				// write options to data
				var data = $container.data("cyedgehandles");
				if( data == null ){
					data = {};
				}
				data.options = options;

				function svgIsInCy( svgDomElement ){
					var $ele = $(svgDomElement);
					var inside = false;

					$ele.parents().each(function(){
						if( this == $container[0] ){
							inside = true;
						}
					});

					return inside;
				}

				function safelyRemoveCySvgChild( svgDomElement ){
					if( svgDomElement != null && svgIsInCy( svgDomElement ) ){
						svg.remove( svgDomElement );
					}
				}

				function resetToDefaultState(){
//					console.log("resetToDefaultState");

					safelyRemoveCySvgChild( handle );
					safelyRemoveCySvgChild( line );

					cy.nodes()
						.removeClass("ui-cytoscapeweb-edgehandles-hover")
						.removeClass("ui-cytoscapeweb-edgehandles-source")
						.removeClass("ui-cytoscapeweb-edgehandles-target")
					;

					linePoints = null;

					cy.zooming(true).panning(true);
				}

				function makePreview( source, target ){
					makeEdges( true );
				}

				function removePreview( source, target ){
					source.edgesWith(target).filter(".ui-cytoscapeweb-edgehandles-preview").remove();

					target
						.neighborhood("node.ui-cytoscapeweb-edgehandles-preview")
						.closedNeighborhood(".ui-cytoscapeweb-edgehandles-preview")
						.remove();

				}

				function makeEdges( preview ){

					// console.log("make edges");

					var source = cy.nodes(".ui-cytoscapeweb-edgehandles-source");
					var targets = cy.nodes(".ui-cytoscapeweb-edgehandles-target");
					var classes = preview ? "ui-cytoscapeweb-edgehandles-preview" : "";
					var added = cy.collection();

					if( source.size() == 0 || targets.size() == 0 ){
						return; // nothing to do :(
					}

					// just remove preview class if we already have the edges
					if( !preview && options.preview ){
						added = cy.elements(".ui-cytoscapeweb-edgehandles-preview").removeClass("ui-cytoscapeweb-edgehandles-preview");

						options.complete( source, targets, added );
						return;
					} else {
						// remove old previews
						cy.elements(".ui-cytoscapeweb-edgehandles-preview").remove();
					}

					targets.each(function(i, target){
						switch( options.edgeType( source, target ) ){
						case "node":

							var p1 = source.position(false);
							var p2 = target.position(false);
							var p = {
								x: (p1.x + p2.x)/2,
								y: (p1.y + p2.y)/2
							};

							var interNode = cy.add($.extend( true, {
								group: "nodes",
								position: p
							}, options.nodeParams(source, target) )).addClass(classes);

							var source2inter = cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: interNode.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);

							var inter2target = cy.add($.extend( true, {
								group: "edges",
								data: {
									source: interNode.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);

							added = added.add( interNode ).add( source2inter ).add( inter2target );

							break;

						case "flat":
							var edge = cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);

							added = added.add( edge );

							break;

						default:
							target.removeClass("ui-cytoscapeweb-edgehandles-target");
							break; // don't add anything
						}
					});

					if( !preview ){
						options.complete( source, targets, added );
					}
				}

				$container.cytoscapeweb(function(e){
					cy = this;
					svg = $container.svg("get");

					var transformHandler;
					cy.bind("zoom pan", transformHandler = function(){
						safelyRemoveCySvgChild( handle );
					});

					var startHandler, hoverHandler, leaveHandler, grabNodeHandler, freeNodeHandler;
					cy.nodes().live("mouseover", startHandler = function(e){
						if( mdownOnHandle || grabbingNode || this.hasClass("ui-cytoscapeweb-edgehandles-preview") ){
							return; // don't override existing handle that's being dragged
							// also don't trigger when grabbing a node
						}

						// console.log("node mover");

						var node = this;
						var source = this;
						var p = node.renderedPosition();
						var d = node.renderedDimensions();

						// remove old handle
						safelyRemoveCySvgChild( handle );

						hx = p.x;
						hy = p.y - d.height/2;
						hr = options.handleSize/2;

						// add new handle
						handle = svg.circle(hx, hy, hr, {
							fill: options.handleColor
						});
						var $handle = $(handle);

						function mdownHandler(e){
							if( e.button != 0 ){
								return; // sorry, no right clicks allowed
							}

//							console.log("-- mdownHandler %o --", e);

							mdownOnHandle = true;

							e.preventDefault();
							node.unbind("mouseout", removeHandler);
							$handle.unbind("mouseout", removeHandler);

							node.addClass("ui-cytoscapeweb-edgehandles-source");

							function doneMoving(dmEvent){
//								console.log("doneMoving %o", dmEvent);

								if( !mdownOnHandle ){
									return;
								}

								var $this = $(this);
								mdownOnHandle = false;
								$(window).unbind("mousemove", moveHandler);

								makeEdges();
								resetToDefaultState();

								options.stop( node );
							}

							$(window).one("mouseup blur", doneMoving).bind("mousemove", moveHandler);
							cy.zooming(false).panning(false);

							options.start( node );
						}

						function moveHandler(e){
							// console.log("move");

							var x = e.pageX - $container.offset().left;
							var y = e.pageY - $container.offset().top;

							safelyRemoveCySvgChild( line );

							var style = {
								stroke: options.handleColor,
								strokeWidth: options.handleLineWidth,
								fill: "none",
								"pointer-events": "none"
							};

							// draw line based on type
							switch( options.lineType ){
							case "straight":

								line = svg.line(hx, hy, x, y, style);

								break;
							case "draw":
							default:

								if( linePoints == null ){
									linePoints = [ [hx, hy], [x, y] ];
								} else {
									linePoints.push([ x, y ]);
								}

								line = svg.polyline(linePoints, style);

								break;
							}

						}

						function removeHandler(e){
							var newTargetIsHandle = e.toElement == handle;
							var newTargetIsNode = e.toElement == node._private.renderer.svg;

							if( newTargetIsHandle || newTargetIsNode || mdownOnHandle ){
								return; // don't consider mouseout
							}

//							console.log("removeHandler %o", e);

							node.unbind("mouseout", removeHandler);
							resetToDefaultState();
						}

						node.bind("mouseout", removeHandler);
						$handle.bind("mouseout", removeHandler);
						$handle.bind("mousedown", mdownHandler);

					}).live("mouseover", hoverHandler = function(){
						var node = this;
						var target = this;

						if( this.hasClass("ui-cytoscapeweb-edgehandles-preview") ){
							return; // ignore preview nodes
						}

						if( mdownOnHandle ){ // only handle mdown case

							clearTimeout( hoverTimeout );
							hoverTimeout = setTimeout(function(){
								var source = cy.nodes(".ui-cytoscapeweb-edgehandles-source");

								var isLoop = node.hasClass("ui-cytoscapeweb-edgehandles-source");
								var loopAllowed = options.loopAllowed( node );

								if( !isLoop || (isLoop && loopAllowed) ){
									node.addClass("ui-cytoscapeweb-edgehandles-hover");
									node.toggleClass("ui-cytoscapeweb-edgehandles-target");

									if( options.preview ){
										if( node.hasClass("ui-cytoscapeweb-edgehandles-target") ){
											makePreview( source, target );
										} else {
											removePreview( source, target );
										}
									}
								}
							}, options.hoverDelay);
						}
					}).live("mouseout", leaveHandler = function(){
						this.removeClass("ui-cytoscapeweb-edgehandles-hover");

						if( mdownOnHandle ){
							clearTimeout(hoverTimeout);
						}
					}).live("grab", grabNodeHandler = function(){
						grabbingNode = true;
						resetToDefaultState();
					}).live("free", freeNodeHandler = function(){
						grabbingNode = false;
					});

					data.unbind = function(){
						cy.nodes()
							.die("mouseover", startHandler)
							.die("mouseover", hoverHandler)
							.die("mouseout", leaveHandler)
							.die("grab", grabNodeHandler)
							.die("free", freeNodeHandler)
						;

						cy.unbind("zoom pan", transformHandler);
					};
				});

				$container.data("cyedgehandles", data);
			}
		};

		if( functions[fn] ){
			return functions[fn].apply(this, Array.prototype.slice.call( arguments, 1 ));
		} else if( typeof fn == 'object' || !fn ) {
			return functions.init.apply( this, arguments );
		} else {
			$.error("No such function `"+ fn +"` for jquery.cytoscapewebEdgeHandles");
		}

		return $(this);
	};

})( jQuery );<|endoftext|>


<commit_before>'use strict';

require('./vpoll-player.less');
require('./chart-component');
require('./poll-form-component');

import vjs from 'video.js';
import hls from 'videojs-contrib-hls';
import io from 'socket.io-client';
import chart from 'chart.js';

window.chart = window.chart || chart;
window.vjs = window.vjs || vjs;
window.videojs = window.videojs || vjs;
window.vPollPlayer = vPollPlayer;

export default function vPollPlayer(elementId, options) {
  if (!options.socketUrl) throw new Error('options.socketUrl needs to be specified');

  let socket = window.socket = io(options.socketUrl);

  socket.on('message', (msg) => console.log(msg));

  let player = vjs(elementId, options);

  let chartComponent = new vjs.Chart( player, options );
  let chartEl = player.addChild(chartComponent);

  let pollComponent = new vjs.formPoll( player, options );
  let pollEl = player.addChild(pollComponent);

  return player;
};

window.sendPoll = function() {
	console.log("No logic for sending implemented .... hiding poll");
	document.getElementById("vjs-form-overlay").className = "hide-el";

}

window.askPoll = function() {
	console.log("Showing poll form");
	document.getElementById("vjs-form-overlay").className = "show-el";
}<commit_msg>issue 8 closes #8<commit_after>'use strict';

require('./vpoll-player.less');
require('./chart-component');
require('./poll-form-component');

import vjs from 'video.js';
import hls from 'videojs-contrib-hls';
import io from 'socket.io-client';
import chart from 'chart.js';

window.chart = window.chart || chart;
window.vjs = window.vjs || vjs;
window.videojs = window.videojs || vjs;
window.vPollPlayer = vPollPlayer;

export default function vPollPlayer(elementId, options) {
  if (!options.socketUrl) throw new Error('options.socketUrl needs to be specified');

  let socket = window.socket = io(options.socketUrl);

  socket.on('message', (msg) => console.log(msg));

  let player = vjs(elementId, options);

  let chartComponent = new vjs.Chart( player, options );
  let chartEl = player.addChild(chartComponent);

  let pollComponent = new vjs.formPoll( player, options );
  let pollEl = player.addChild(pollComponent);

  return player;
};

// Poll form calls on this function onSubmit
window.sendPoll = function() {
	console.log("No logic for sending implemented .... hiding poll");
	document.getElementById("vjs-form-overlay").className = "hide-el";

}

// Called in order to display the poll form
window.askPoll = function() {
	console.log("Showing poll form");
	document.getElementById("vjs-form-overlay").className = "show-el";
}<|endoftext|>


<commit_before>import {Math} from 'gamebox';
import colorConstants from 'flockn/constants/color';

const {clamp} = Math;

class Color {
  constructor(r = 0, g = 0, b = 0, a = 1) {
    this.set(r, g, b, a);
  }

  set(r = 0, g = 0, b = 0, a = 1) {
    this.r = r;
    this.g = g;
    this.b = b;
    this.a = a;
  }

  lighten(factor) {
    factor = clamp(factor, 0, 1);

    this.r = clamp(this.r + (factor * 255) | 0, 0, 255);
    this.g = clamp(this.g + (factor * 255) | 0, 0, 255);
    this.b = clamp(this.b + (factor * 255) | 0, 0, 255);
  }

  darken(factor) {
    factor = clamp(factor, 0, 1);

    this.r = clamp(this.r - (factor * 255) | 0, 0, 255);
    this.g = clamp(this.g - (factor * 255) | 0, 0, 255);
    this.b = clamp(this.b - (factor * 255) | 0, 0, 255);
  }

  fadeIn(factor) {
    factor = clamp(factor, 0, 1);

    this.a = this.a + this.a * factor;
    if (this.a > 1) {
      this.a = 1;
    }
  }

  fadeOut(factor) {
    factor = clamp(factor, 0, 1);

    this.a = this.a - this.a * factor;
    if (this.a < 0) {
      this.a = 0;
    }
  }

  toJSON() {
    if (this.a < 1) {
      if (this.a === 0) {
        return 'transparent';
      } else {
        return `rgba(${this.r},${this.g},${this.b},${this.a})`;
      }
    } else {
      return `rgb(${this.r},${this.g},${this.b})`;
    }
  }

  toString() {
    return this.toJSON();
  }

  toHex() {
    return `#${this.r.toString(16)}${this.g.toString(16)}${this.b.toString(16)}`;
  }

  // Getting a random color for debugging is quite useful sometimes
  static random() {
    var col = [0, 0, 0];

    col = col.map(function() {
      return ~~(Math.random() * 255);
    });

    return new Color(col[0], col[1], col[2]);
  }
}

for (var colorName in colorConstants) {
  var colorValue = colorConstants[colorName];

  (function(colorName, colorValue) {
    Color[colorName] = function() {
      var col = new Color(colorValue.r, colorValue.g, colorValue.b, colorValue.a);
      col.name = colorName;
      return col;
    };
  })(colorName, colorValue);
}

export default Color;
<commit_msg>:fire: Use gamebox color and add color constants<commit_after>import {Math, Types} from 'gamebox';
import colorConstants from '../constants/color';

let {Color} = Types;

const {clamp} = Math;

for (var colorName in colorConstants) {
  var colorValue = colorConstants[colorName];

  (function(colorName, colorValue) {
    Color[colorName] = function() {
      var col = new Color(colorValue.r, colorValue.g, colorValue.b, colorValue.a);
      col.name = colorName;
      return col;
    };
  })(colorName, colorValue);
}

export default Color;
<|endoftext|>


<commit_before>import { controllerLookup } from 'toolkit/extension/utils/ember';
import { withToolkitError } from 'toolkit/core/common/errors/with-toolkit-error';
import { getEntityManager } from 'toolkit/extension/utils/ynab';

let instance = null;

export class RouteChangeListener {
  constructor() {
    if (instance) {
      return instance;
    }

    let routeChangeListener = this;
    routeChangeListener.features = [];

    let applicationController = controllerLookup('application');
    applicationController.reopen({
      onRouteChanged: Ember.observer(
        'currentRouteName', // this will handle accounts -> budget and vise versa
        'budgetVersionId', // this will handle changing budgets
        'selectedAccountId', // this will handle switching around accounts
        'monthString', // this will handle changing which month of a budget you're looking at
        (controller, changedProperty) => {
          if (changedProperty === 'budgetVersionId') {
            (function poll() {
              const applicationBudgetVersion = controllerLookup('application').get(
                'budgetVersionId'
              );
              const { activeBudgetVersion } = getEntityManager().getSharedLibInstance();
              if (
                activeBudgetVersion &&
                activeBudgetVersion.entityId &&
                activeBudgetVersion.entityId === applicationBudgetVersion
              ) {
                Ember.run.scheduleOnce('afterRender', controller, 'emitBudgetRouteChange');
              } else {
                Ember.run.next(poll, 250);
              }
            })();
          } else {
            Ember.run.scheduleOnce('afterRender', controller, 'emitSameBudgetRouteChange');
          }
        }
      ),

      emitSameBudgetRouteChange: function() {
        let currentRoute = applicationController.get('currentRouteName');
        routeChangeListener.features.forEach(feature => {
          const observe = feature.onRouteChanged.bind(feature, currentRoute);
          const wrapped = withToolkitError(observe, feature);
          Ember.run.later(wrapped, 0);
        });
      },

      emitBudgetRouteChange: function() {
        let currentRoute = applicationController.get('currentRouteName');
        routeChangeListener.features.forEach(feature => {
          const observe = feature.onBudgetChanged.bind(feature, currentRoute);
          const wrapped = withToolkitError(observe, feature);
          Ember.run.later(wrapped, 0);
        });
      },
    });

    instance = this;
  }

  addFeature(feature) {
    if (this.features.indexOf(feature) === -1) {
      this.features.push(feature);
    }
  }
}
<commit_msg>Use `currentState` observer on router for routeChangeListener (#1717)<commit_after>import { controllerLookup } from 'toolkit/extension/utils/ember';
import { withToolkitError } from 'toolkit/core/common/errors/with-toolkit-error';
import { getRouter } from 'toolkit/extension/utils/ember';

let instance = null;

export class RouteChangeListener {
  constructor() {
    if (instance) {
      return instance;
    }

    const routeChangeListener = this;
    routeChangeListener.features = [];

    function emitSameBudgetRouteChange() {
      const applicationController = controllerLookup('application');
      const currentRoute = applicationController.get('currentRouteName');
      routeChangeListener.features.forEach(feature => {
        const observe = feature.onRouteChanged.bind(feature, currentRoute);
        const wrapped = withToolkitError(observe, feature);
        Ember.run.later(wrapped, 0);
      });
    }

    function emitBudgetRouteChange() {
      const applicationController = controllerLookup('application');
      const currentRoute = applicationController.get('currentRouteName');
      routeChangeListener.features.forEach(feature => {
        const observe = feature.onBudgetChanged.bind(feature, currentRoute);
        const wrapped = withToolkitError(observe, feature);
        Ember.run.later(wrapped, 0);
      });
    }

    getRouter().addObserver('currentState', ({ location, router }) => {
      if (router && router.state && router.state.params && router.state.params.index) {
        if (location.location.href.includes(router.state.params.index.budgetVersionId)) {
          Ember.run.scheduleOnce('afterRender', null, emitSameBudgetRouteChange);
        } else {
          Ember.run.scheduleOnce('afterRender', null, emitBudgetRouteChange);
        }
      }
    });

    instance = this;
  }

  addFeature(feature) {
    if (this.features.indexOf(feature) === -1) {
      this.features.push(feature);
    }
  }
}
<|endoftext|>


<commit_before>// TODO
//    - Don't show ZCI if results == 0.
//    - Use canonical header style: "query (PLOS)".
//    - Change list style, use ordered list.
//    - Remove bolding titles, use another thing to make it stand out.
//    - Make citation look clickable.
//    - Check if data is available before showing "undefined".

function ddg_spice_plos(request) {

  // Get query and exclude the trigger.
  var query = DDG.get_query().replace(/plos/i, "");

  // Check if response is OK and results > 0.
  var status = request['responseHeader']['status'];
  var numFound = request['response']['numFound'];

  if (status === 0) {
    // Get docs and define loop limit.
    var docs = request['response']['docs'];
    if (docs.length < 5) {
      var limit = docs.length;
    } else {
      var limit = 5;
    };

    // Create object for results.
    var results = '
'
                + 'Data Provided by PLOS'
                + '
';

    // Loop over documents.
    for (var i = 0; i < limit; i++) {
      // Define article and its variables.
      var doc = docs[i];
      var title = doc['title_display'];
      var author_list = doc['author_display'];
      if (author_list.length > 3) {
        var authors = author_list.splice(0, 3).join(', ') + ', et al';
      } else {
        var authors = author_list.join(', ');
      }
      var journal = doc['journal'];
      var pubdate = doc['publication_date'];
      var year = pubdate.substr(0, 4);
      var id = doc['id'];
      results += '
'
              + ''
              + '' + title + ''
              + '' + authors + '. '
              + '' + journal + ' '
              + '(' + year + ')'
              + ''
              + '
';
    };

    // Finish results.
    results += '
'
            + '
';

    // Define callback items.
    var items = [[]];
    items[0] = {
      a: results,
      h: query + ' (PLOS)',
      s: 'PLOS',
      u: 'http://www.plosone.org/search/advancedSearch.action?pageSize=50&unformattedQuery=' + query,
      force_big_header: true,
    }
    nra(items);
  }
}
<commit_msg>Updates citation styles and switch to ordered list<commit_after>// TODO
//    - Don't show ZCI if results == 0.
//    - Check if data is available before showing "undefined".

function ddg_spice_plos(request) {

  // Get query and exclude the trigger.
  var query = DDG.get_query().replace(/plos/i, "");

  // Check if response is OK and results > 0.
  var status = request['responseHeader']['status'];
  var numFound = request['response']['numFound'];

  if (status === 0) {
    // Get docs and define loop limit.
    var docs = request['response']['docs'];
    if (docs.length < 5) {
      var limit = docs.length;
    } else {
      var limit = 5;
    };

    // Create object for results.
    var results = '
'
                + 'Data Provided by PLOS'
                + '
';

    // Loop over documents.
    for (var i = 0; i < limit; i++) {
      // Define article and its variables.
      var doc = docs[i];
      var title = doc['title_display'];
      var author_list = doc['author_display'];
      if (author_list.length > 3) {
        var authors = author_list.splice(0, 3).join(', ') + ', et al';
      } else {
        var authors = author_list.join(', ');
      }
      var journal = doc['journal'];
      var pubdate = doc['publication_date'];
      var year = pubdate.substr(0, 4);
      var id = doc['id'];
      results += '
'
              + ''
              + '' + title + '
'
              + '' + authors + '. '
              + '' + journal + ' '
              + '(' + year + ')'
              + ''
              + '
';
    };

    // Finish results.
    results += '
'
            + '
';

    // Define callback items.
    var items = [[]];
    items[0] = {
      a: results,
      h: query + ' (PLOS)',
      s: 'PLOS',
      u: 'http://www.plosone.org/search/advancedSearch.action?pageSize=50&unformattedQuery=' + query,
      force_big_header: true,
    }
    nra(items);
  }
}
<|endoftext|>


<commit_before>/*
  backgrid-paginator
  http://github.com/wyuenho/backgrid

  Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
  Licensed under the MIT @license.
*/

(function ($, _, Backbone, Backgrid) {

  "use strict";

  /**
     Paginator is a Backgrid extension that renders a series of configurable
     pagination handles. This extension is best used for splitting a large data
     set across multiple pages. If the number of pages is larger then a
     threshold, which is set to 10 by default, the page handles are rendered
     within a sliding window, plus the fast forward, fast backward, previous and
     next page handles. The fast forward, fast backward, previous and next page
     handles can be turned off.

     @class Backgrid.Extension.Paginator
  */
  Backgrid.Extension.Paginator = Backbone.View.extend({

    /** @property */
    className: "backgrid-paginator",

    /** @property */
    windowSize: 10,

    /**
       @property {Object} fastForwardHandleLabels You can disable specific
       handles by setting its value to `null`.
    */
    fastForwardHandleLabels: {
      first: "《",
      prev: "〈",
      next: "〉",
      last: "》"
    },

    /** @property */
    template: _.template('
<% _.each(handles, function (handle) { %><li <% if (handle.className) { %>class="<%= handle.className %>"<% } %>><a href="#" <% if (handle.title) {%> title="<%= handle.title %>"<% } %>><%= handle.label %>
<% }); %>
'),

    /** @property */
    events: {
      "click a": "changePage"
    },

    /**
       Initializer.

       @param {Object} options
       @param {Backbone.Collection.<Backgrid.Column>|Array.<Backgrid.Column>|Array.<Object>} options.columns
       Column metadata.
       @param {Backbone.Collection} options.collection
       @param {boolean} [options.fastForwardHandleLabels] Whether to render fast forward buttons.
    */
    initialize: function (options) {
      Backgrid.requireOptions(options, ["columns", "collection"]);

      this.columns = options.columns;
      if (!(this.columns instanceof Backbone.Collection)) {
        this.columns = new Backgrid.Columns(this.columns);
      }

      var columns = this.columns;
      this.listenTo(columns, "add", this.render);
      this.listenTo(columns, "remove", this.render);
      this.listenTo(columns, "change:renderable", this.render);
      var collection = this.collection;
      var fullCollection = collection.fullCollection;
      if (fullCollection) {
        this.listenTo(fullCollection, "add", this.render);
        this.listenTo(fullCollection, "remove", this.render);
        this.listenTo(fullCollection, "reset", this.render);
      }
      else {
        this.listenTo(collection, "add", this.render);
        this.listenTo(collection, "remove", this.render);
        this.listenTo(collection, "reset", this.render);
      }
    },

    /**
       jQuery event handler for the page handlers. Goes to the right page upon
       clicking.

       @param {Event} e
     */
    changePage: function (e) {
      e.preventDefault();

      var $li = $(e.target).parent();
      if (!$li.hasClass("active") && !$li.hasClass("disabled")) {

        var label = $(e.target).text();
        var ffLabels = this.fastForwardHandleLabels;

        var collection = this.collection;

        if (ffLabels) {
          switch (label) {
          case ffLabels.first:
            collection.getFirstPage();
            return;
          case ffLabels.prev:
            collection.getPreviousPage();
            return;
          case ffLabels.next:
            collection.getNextPage();
            return;
          case ffLabels.last:
            collection.getLastPage();
            return;
          }
        }

        var state = collection.state;
        var pageIndex = +label;
        collection.getPage(state.firstPage === 0 ? pageIndex - 1 : pageIndex);
      }
    },

    /**
       Internal method to create a list of page handle objects for the template
       to render them.

       @return {Array.<Object>} an array of page handle objects hashes
     */
    makeHandles: function () {

      var handles = [];
      var collection = this.collection;
      var state = collection.state;

      // convert all indices to 0-based here
      var firstPage = state.firstPage;
      var lastPage = +state.lastPage;
      lastPage = Math.max(0, firstPage ? lastPage - 1 : lastPage);
      var currentPage = Math.max(state.currentPage, state.firstPage);
      currentPage = firstPage ? currentPage - 1 : currentPage;
      var windowStart = Math.floor(currentPage / this.windowSize) * this.windowSize;
      var windowEnd = Math.min(lastPage + 1, windowStart + this.windowSize);

      if (collection.mode !== "infinite") {
        for (var i = windowStart; i < windowEnd; i++) {
          handles.push({
            label: i + 1,
            title: "No. " + (i + 1),
            className: currentPage === i ? "active" : undefined
          });
        }
      }

      var ffLabels = this.fastForwardHandleLabels;
      if (ffLabels) {

        if (ffLabels.prev) {
          handles.unshift({
            label: ffLabels.prev,
            className: collection.hasPrevious() ? void 0 : "disabled"
          });
        }

        if (ffLabels.first) {
          handles.unshift({
            label: ffLabels.first,
            className: collection.hasPrevious() ? void 0 : "disabled"
          });
        }

        if (ffLabels.next) {
          handles.push({
            label: ffLabels.next,
            className: collection.hasNext() ? void 0 : "disabled"
          });
        }

        if (ffLabels.last) {
          handles.push({
            label: ffLabels.last,
            className: collection.hasNext() ? void 0 : "disabled"
          });
        }
      }

      return handles;
    },

    /**
       Render the paginator handles inside an unordered list placed inside a
       cell that spans all the columns.
    */
    render: function () {
      this.$el.empty();

      this.$el.append(this.template({
        handles: this.makeHandles()
      }));

      this.delegateEvents();

      return this;
    }

  });

}(jQuery, _, Backbone, Backgrid));
<commit_msg>Remove leftover columns-related code in the paginator<commit_after>/*
  backgrid-paginator
  http://github.com/wyuenho/backgrid

  Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
  Licensed under the MIT @license.
*/

(function ($, _, Backbone, Backgrid) {

  "use strict";

  /**
     Paginator is a Backgrid extension that renders a series of configurable
     pagination handles. This extension is best used for splitting a large data
     set across multiple pages. If the number of pages is larger then a
     threshold, which is set to 10 by default, the page handles are rendered
     within a sliding window, plus the fast forward, fast backward, previous and
     next page handles. The fast forward, fast backward, previous and next page
     handles can be turned off.

     @class Backgrid.Extension.Paginator
  */
  Backgrid.Extension.Paginator = Backbone.View.extend({

    /** @property */
    className: "backgrid-paginator",

    /** @property */
    windowSize: 10,

    /**
       @property {Object} fastForwardHandleLabels You can disable specific
       handles by setting its value to `null`.
    */
    fastForwardHandleLabels: {
      first: "《",
      prev: "〈",
      next: "〉",
      last: "》"
    },

    /** @property */
    template: _.template('
<% _.each(handles, function (handle) { %><li <% if (handle.className) { %>class="<%= handle.className %>"<% } %>><a href="#" <% if (handle.title) {%> title="<%= handle.title %>"<% } %>><%= handle.label %>
<% }); %>
'),

    /** @property */
    events: {
      "click a": "changePage"
    },

    /**
       Initializer.

       @param {Object} options
       @param {Backbone.Collection} options.collection
       @param {boolean} [options.fastForwardHandleLabels] Whether to render fast forward buttons.
    */
    initialize: function (options) {
      Backgrid.requireOptions(options, ["collection"]);

      var collection = this.collection;
      var fullCollection = collection.fullCollection;
      if (fullCollection) {
        this.listenTo(fullCollection, "add", this.render);
        this.listenTo(fullCollection, "remove", this.render);
        this.listenTo(fullCollection, "reset", this.render);
      }
      else {
        this.listenTo(collection, "add", this.render);
        this.listenTo(collection, "remove", this.render);
        this.listenTo(collection, "reset", this.render);
      }
    },

    /**
       jQuery event handler for the page handlers. Goes to the right page upon
       clicking.

       @param {Event} e
     */
    changePage: function (e) {
      e.preventDefault();

      var $li = $(e.target).parent();
      if (!$li.hasClass("active") && !$li.hasClass("disabled")) {

        var label = $(e.target).text();
        var ffLabels = this.fastForwardHandleLabels;

        var collection = this.collection;

        if (ffLabels) {
          switch (label) {
          case ffLabels.first:
            collection.getFirstPage();
            return;
          case ffLabels.prev:
            collection.getPreviousPage();
            return;
          case ffLabels.next:
            collection.getNextPage();
            return;
          case ffLabels.last:
            collection.getLastPage();
            return;
          }
        }

        var state = collection.state;
        var pageIndex = +label;
        collection.getPage(state.firstPage === 0 ? pageIndex - 1 : pageIndex);
      }
    },

    /**
       Internal method to create a list of page handle objects for the template
       to render them.

       @return {Array.<Object>} an array of page handle objects hashes
     */
    makeHandles: function () {

      var handles = [];
      var collection = this.collection;
      var state = collection.state;

      // convert all indices to 0-based here
      var firstPage = state.firstPage;
      var lastPage = +state.lastPage;
      lastPage = Math.max(0, firstPage ? lastPage - 1 : lastPage);
      var currentPage = Math.max(state.currentPage, state.firstPage);
      currentPage = firstPage ? currentPage - 1 : currentPage;
      var windowStart = Math.floor(currentPage / this.windowSize) * this.windowSize;
      var windowEnd = Math.min(lastPage + 1, windowStart + this.windowSize);

      if (collection.mode !== "infinite") {
        for (var i = windowStart; i < windowEnd; i++) {
          handles.push({
            label: i + 1,
            title: "No. " + (i + 1),
            className: currentPage === i ? "active" : undefined
          });
        }
      }

      var ffLabels = this.fastForwardHandleLabels;
      if (ffLabels) {

        if (ffLabels.prev) {
          handles.unshift({
            label: ffLabels.prev,
            className: collection.hasPrevious() ? void 0 : "disabled"
          });
        }

        if (ffLabels.first) {
          handles.unshift({
            label: ffLabels.first,
            className: collection.hasPrevious() ? void 0 : "disabled"
          });
        }

        if (ffLabels.next) {
          handles.push({
            label: ffLabels.next,
            className: collection.hasNext() ? void 0 : "disabled"
          });
        }

        if (ffLabels.last) {
          handles.push({
            label: ffLabels.last,
            className: collection.hasNext() ? void 0 : "disabled"
          });
        }
      }

      return handles;
    },

    /**
       Render the paginator handles inside an unordered list.
    */
    render: function () {
      this.$el.empty();

      this.$el.append(this.template({
        handles: this.makeHandles()
      }));

      this.delegateEvents();

      return this;
    }

  });

}(jQuery, _, Backbone, Backgrid));
<|endoftext|>


<commit_before>import emoticons from "../../constants/emoticons";

const handlers = {
	"emoticonPicker/show": (state, action) => ({
		...state,
		visible: true,
		x: action.x,
		y: action.y,
		direction: action.direction,
		onPick: action.onPick,
		search: "",
		filteredEmoticons: state.allEmoticons,
		selected: _.first(state.allEmoticons).name,
		searchInputVisible: action.searchInputVisible
	}),
	"emoticonPicker/hide": state => ({
		...state,
		visible: false
	}),
	"emoticonPicker/search": (state, action) => {
		const filteredEmoticons = _.filter(state.allEmoticons, emoticon =>
			new RegExp(action.text, "i").test(emoticon.name)
		);

		if (filteredEmoticons.length > 0) {
			return {
				...state,
				search: action.text,
				filteredEmoticons,
				selected: _.first(filteredEmoticons).name
			};
		} else {
			// Nothing found, close picker
			return {
				...state,
				visible: false
			};
		}
	},
	"emoticonPicker/selectLeft": state => {
		let previousIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) - 1;
		if (previousIndex < 0) {
			previousIndex = state.filteredEmoticons.length -1;
		}
		return {
			...state,
			selected: state.filteredEmoticons[previousIndex].name
		};
	},
	"emoticonPicker/selectRight": state => {
		let nextIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) + 1;
		if (nextIndex === state.filteredEmoticons.length) {
			nextIndex = 0;
		}

		console.log("nextIndex", nextIndex);
		return {
			...state,
			selected: state.filteredEmoticons[nextIndex].name
		};
	},
	"emoticonPicker/selectUp": state => {
		let previousIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) - 5;
		if (previousIndex < 0) {
			previousIndex = 0;
		}
		return {
			...state,
			selected: state.filteredEmoticons[previousIndex].name
		};
	},
	"emoticonPicker/selectDown": state => {
		let nextIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) + 5;
		if (nextIndex > state.filteredEmoticons.length) {
			nextIndex = state.filteredEmoticons.length;
		}
		return {
			...state,
			selected: state.filteredEmoticons[nextIndex].name
		};
	}
};

const initialState = {
	allEmoticons: emoticons.imageEmoticons,
	filteredEmoticons: [], // make picker load with no gifs rendered on load to reduce lag
	search: ""
};

export default function(state = initialState, action) {
	return handlers[action.type] ? handlers[action.type](state, action) : state;
}
<commit_msg>remove console log<commit_after>import emoticons from "../../constants/emoticons";

const handlers = {
	"emoticonPicker/show": (state, action) => ({
		...state,
		visible: true,
		x: action.x,
		y: action.y,
		direction: action.direction,
		onPick: action.onPick,
		search: "",
		filteredEmoticons: state.allEmoticons,
		selected: _.first(state.allEmoticons).name,
		searchInputVisible: action.searchInputVisible
	}),
	"emoticonPicker/hide": state => ({
		...state,
		visible: false
	}),
	"emoticonPicker/search": (state, action) => {
		const filteredEmoticons = _.filter(state.allEmoticons, emoticon =>
			new RegExp(action.text, "i").test(emoticon.name)
		);

		if (filteredEmoticons.length > 0) {
			return {
				...state,
				search: action.text,
				filteredEmoticons,
				selected: _.first(filteredEmoticons).name
			};
		} else {
			// Nothing found, close picker
			return {
				...state,
				visible: false
			};
		}
	},
	"emoticonPicker/selectLeft": state => {
		let previousIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) - 1;
		if (previousIndex < 0) {
			previousIndex = state.filteredEmoticons.length -1;
		}
		return {
			...state,
			selected: state.filteredEmoticons[previousIndex].name
		};
	},
	"emoticonPicker/selectRight": state => {
		let nextIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) + 1;
		if (nextIndex === state.filteredEmoticons.length) {
			nextIndex = 0;
		}

		return {
			...state,
			selected: state.filteredEmoticons[nextIndex].name
		};
	},
	"emoticonPicker/selectUp": state => {
		let previousIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) - 5;
		if (previousIndex < 0) {
			previousIndex = 0;
		}
		return {
			...state,
			selected: state.filteredEmoticons[previousIndex].name
		};
	},
	"emoticonPicker/selectDown": state => {
		let nextIndex = _.findIndex(state.filteredEmoticons, { name: state.selected }) + 5;
		if (nextIndex > state.filteredEmoticons.length) {
			nextIndex = state.filteredEmoticons.length;
		}
		return {
			...state,
			selected: state.filteredEmoticons[nextIndex].name
		};
	}
};

const initialState = {
	allEmoticons: emoticons.imageEmoticons,
	filteredEmoticons: [], // make picker load with no gifs rendered on load to reduce lag
	search: ""
};

export default function(state = initialState, action) {
	return handlers[action.type] ? handlers[action.type](state, action) : state;
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'ServiceProviderAwareDAO',
  extends: 'foam.dao.ProxyDAO',

  documentation: `A DAO decorator which:
- filters find and select by the 'owning' ServiceProvider ID (spid),
- enforces spid permissions on update and create,
- restricts or filters by spid on remove.
The DAO can act on models which explicitly implement ServiceProviderAware,
or where a Reference/Relationship model implements ServiceProviderAware.
Where the ServiceProviderAware is found through a Reference or Relationship,
the DAO uses a Map of class and PropertyInfos to traverse the Reference,
Relationship hierarchy.`,

  javaImports: [
    'foam.core.FObject',
    'foam.core.PropertyInfo',
    'foam.core.X',
    'foam.dao.DAO',
    'foam.dao.ProxyDAO',
    'foam.dao.ProxySink',
    'foam.dao.Sink',
    'foam.mlang.MLang',
    'foam.mlang.predicate.Predicate',
    'foam.nanos.app.AppConfig',
    'foam.nanos.auth.AuthService',
    'foam.nanos.auth.User',
    'foam.nanos.logger.Logger',
    'foam.util.SafetyUtil',
    'java.util.Map',
    'java.util.Map.Entry',
    'java.util.HashMap',
    'java.util.stream.Collectors'
  ],

  properties: [
    {
      documentation: `A Map propertyInfo[] key on class name.  For some class,
the propertyInfos are the Reference or Relationship property from which to find
the next step in the hierachy on route the instance which implements
ServiceProviderAware`,
      name: 'propertyInfos',
      class: 'Map'
    }
  ],

  methods: [
    {
      name: 'put_',
      javaThrows: ['AuthorizationException'],
      javaCode: `
    if ( ! ( obj instanceof ServiceProviderAware ) ) {
      return super.put_(x, obj);
    }

    Object id = obj.getProperty("id");
    FObject oldObj = getDelegate().inX(x).find(id);
    boolean isCreate = id == null || oldObj == null;

    ServiceProviderAware sp = (ServiceProviderAware) obj;
    ServiceProviderAware oldSp = (ServiceProviderAware) oldObj;
    AuthService auth = (AuthService) x.get("auth");

    if ( isCreate ) {
      if ( SafetyUtil.isEmpty(sp.getSpid()) ||
           ( ! SafetyUtil.isEmpty(sp.getSpid()) &&
             ! auth.check(x, "spid.create." + sp.getSpid()) ) ) {
        User user = (User) x.get("user");
        if ( user != null &&
             ! SafetyUtil.isEmpty(user.getSpid()) ) {
          sp.setSpid(user.getSpid());
        } else {
          sp.setSpid(((AppConfig) x.get("appConfig")).getDefaultSpid());
        }
      }
    } else if ( ! sp.getSpid().equals(oldSp.getSpid()) &&
                ! (auth.check(x, "spid.update." + oldSp.getSpid()) &&
                   auth.check(x, "spid.update." + sp.getSpid())) ) {
      throw new AuthorizationException("You do not have permission to update ServiceProvider (spid) property.");
    }

    return super.put_(x, obj);
      `
    },
    {
      name: 'find_',
      javaCode: `
    FObject result = getDelegate().find_(x, id);
    if ( result == null ||
         ((AuthService) x.get("auth")).check(x, "*") ) {
      return result;
    }

    if ( new ServiceProviderAwareSupport().match(x, getPropertyInfos(), result) ) {
      return result;
    }

    return null;
      `
    },
    {
      name: 'select_',
      javaCode: `
    if ( ((AuthService) x.get("auth")).check(x, "*") ) {
      return super.select_(x, sink, skip, limit, order, predicate);
    }

    Predicate spidPredicate = predicate;

    if ( ServiceProviderAware.class.isAssignableFrom(getOf().getObjClass()) ) {
      User user = (User) x.get("user");
      PropertyInfo spidProperty = ((PropertyInfo) getOf().getAxiomByName("spid"));
      spidPredicate = MLang.EQ(spidProperty, user.getSpid());

      if ( predicate != null ) {
        spidPredicate = MLang.AND(
          spidPredicate,
          predicate
        );
      }
    } else if ( getPropertyInfos() != null &&
                getPropertyInfos().size() > 0 ) {
      spidPredicate = new ServiceProviderAwarePredicate(x, predicate, getPropertyInfos());
    }

    return getDelegate().select_(
      x,
      sink,
      skip,
      limit,
      order,
      spidPredicate
    );
     `
    }
  ]
});
<commit_msg>Skip spid filtering when no spid in context.<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'ServiceProviderAwareDAO',
  extends: 'foam.dao.ProxyDAO',

  documentation: `A DAO decorator which:
- filters find and select by the 'owning' ServiceProvider ID (spid),
- enforces spid permissions on update and create,
- restricts or filters by spid on remove.
The DAO can act on models which explicitly implement ServiceProviderAware,
or where a Reference/Relationship model implements ServiceProviderAware.
Where the ServiceProviderAware is found through a Reference or Relationship,
the DAO uses a Map of class and PropertyInfos to traverse the Reference,
Relationship hierarchy.`,

  javaImports: [
    'foam.core.FObject',
    'foam.core.PropertyInfo',
    'foam.core.X',
    'foam.dao.DAO',
    'foam.dao.ProxyDAO',
    'foam.dao.ProxySink',
    'foam.dao.Sink',
    'foam.mlang.MLang',
    'foam.mlang.predicate.Predicate',
    'foam.nanos.app.AppConfig',
    'foam.nanos.auth.AuthService',
    'foam.nanos.auth.User',
    'foam.nanos.logger.Logger',
    'foam.util.SafetyUtil',
    'java.util.Map',
    'java.util.Map.Entry',
    'java.util.HashMap',
    'java.util.stream.Collectors'
  ],

  properties: [
    {
      documentation: `A Map propertyInfo[] key on class name.  For some class,
the propertyInfos are the Reference or Relationship property from which to find
the next step in the hierachy on route the instance which implements
ServiceProviderAware`,
      name: 'propertyInfos',
      class: 'Map'
    }
  ],

  methods: [
    {
      name: 'put_',
      javaThrows: ['AuthorizationException'],
      javaCode: `
    if ( ! ( obj instanceof ServiceProviderAware ) ) {
      return super.put_(x, obj);
    }

    Object id = obj.getProperty("id");
    FObject oldObj = getDelegate().inX(x).find(id);
    boolean isCreate = id == null || oldObj == null;

    ServiceProviderAware sp = (ServiceProviderAware) obj;
    ServiceProviderAware oldSp = (ServiceProviderAware) oldObj;
    AuthService auth = (AuthService) x.get("auth");

    if ( isCreate ) {
      if ( SafetyUtil.isEmpty(sp.getSpid()) ||
           ( ! SafetyUtil.isEmpty(sp.getSpid()) &&
             ! auth.check(x, "spid.create." + sp.getSpid()) ) ) {
        User user = (User) x.get("user");
        if ( user != null &&
             ! SafetyUtil.isEmpty(user.getSpid()) ) {
          sp.setSpid(user.getSpid());
        } else {
          sp.setSpid(((AppConfig) x.get("appConfig")).getDefaultSpid());
        }
      }
    } else if ( ! sp.getSpid().equals(oldSp.getSpid()) &&
                ! (auth.check(x, "spid.update." + oldSp.getSpid()) &&
                   auth.check(x, "spid.update." + sp.getSpid())) ) {
      throw new AuthorizationException("You do not have permission to update ServiceProvider (spid) property.");
    }

    return super.put_(x, obj);
      `
    },
    {
      name: 'find_',
      javaCode: `
    FObject result = getDelegate().find_(x, id);
    if ( result == null ||
         ((AuthService) x.get("auth")).check(x, "*") ) {
      return result;
    }

    if ( new ServiceProviderAwareSupport().match(x, getPropertyInfos(), result) ) {
      return result;
    }

    return null;
      `
    },
    {
      name: 'select_',
      javaCode: `
    if ( ((AuthService) x.get("auth")).check(x, "*") ) {
      return super.select_(x, sink, skip, limit, order, predicate);
    }

    Predicate spidPredicate = predicate;

    String spid = (String) x.get("spid");
    if ( spid != null ) { // spid may be null during account creation.
      if ( ServiceProviderAware.class.isAssignableFrom(getOf().getObjClass()) ) {

        PropertyInfo spidProperty = ((PropertyInfo) getOf().getAxiomByName("spid"));
        spidPredicate = MLang.EQ(spidProperty, spid);

        if ( predicate != null ) {
          spidPredicate = MLang.AND(
            spidPredicate,
            predicate
          );
        }
      } else if ( getPropertyInfos() != null &&
                  getPropertyInfos().size() > 0 ) {
        spidPredicate = new ServiceProviderAwarePredicate(x, predicate, getPropertyInfos());
      }
    }

    return getDelegate().select_(
      x,
      sink,
      skip,
      limit,
      order,
      spidPredicate
    );
     `
    }
  ]
});
<|endoftext|>


<commit_before>module.exports.pre = function(version, packagePath) {
	return Promise.resolve(true);
};

module.exports.post = function(version, packagePath) {
	return Promise.resolve();
};
<commit_msg>Update hook to try getting around the update issues on renaming files in use for windows<commit_after>var fs = require('fs');
var path = require('path');

function rename(from, to) {
	return new Promise(function(resolve, reject) {
		fs.rename(from, to, function(err) {
			if (err) {
				reject(err);
			} else {
				resolve();
			}
		});
	});
}

module.exports.pre = function(version, packagePath) {
	if (process.platform !== 'win32') {
		return Promise.resolve(true);
	}

	return rename(packagePath, path.join(packagePath, '..', 'package-old2'))
		.then(function() {
			return new Promise(function(resolve) {
				setTimeout(resolve, 3000);
			});
		})
		.then(function() {
			fs.writeFileSync(packagePath, 'test');
			return new Promise(function(resolve) {
				setTimeout(resolve, 3000);
			});
		})
		.then(function() {
			return true;
		});
};

module.exports.post = function(version, packagePath) {
	return Promise.resolve();
};
<|endoftext|>