<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors' . \n");

	}
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
move = move || getinput();

   return move;

}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
move = move|| randomPlay();
   return move;
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
	if ((playerMove == "scissors")&& (computerMove == "rock")){
	return "computer";
} else if ((playerMove == "scissors")&& (computerMove == "paper")){
	return "player";
} else if ((playerMove == "rock")&& (computerMove == "scissors")){
	return "player";
} else if ((playerMove == "rock")&& (computerMove == "paper")){
	return "computer";
} else if ((playerMove == "paper")&& (computerMove == "scissors")){
	return "computer";
} else if ((playerMove == "paper")&& (computerMove == "rock")){
	return "player";
} else return "tie"

}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors" + '\n');

    var playerWins = 0;
    var computerWins = 0;
    var pMove;
    var cMove;

while ((playerWins < 5) || (computerWins <5))
   {
	 pMove = getPlayerMove();
	 cMove = getComputerMove();
	console.log('Player chose ' + pMove + ' while Computer chose ' +    cMove + '\n');
	var winner = getWinner(pMove,cMove);
	if (winner=="player")
	{
		playerWins=playerWins+1;
		console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');

        }else if (winner=="computer"){
	computerWins=computerWins+1;
		console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
	}else console.log('Tie, The score is currently ' + playerWins + ' to ' + computerWins + '\n');

    }
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
// This function should continue to play Rock Paper Scissors until either the
  // player or the computer has won five times.
  // After each 'round', display some text in the console indicating who played
  // what, who won, and what the current scoreboard looks like.
  // For example,
  //  console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
  //  console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
  /* YOUR CODE HERE */

    return [playerWins, computerWins];

}

<commit_msg>created a new game file without many comments<commit_after>
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors' . \n");

	}
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {

move = move || getinput();

   return move;

}

function getComputerMove(move) {

move = move|| randomPlay();
   return move;
}

function getWinner(playerMove,computerMove) {
    var winner;
    s 'rock'.

	if ((playerMove == "scissors")&& (computerMove == "rock")){
	return "computer";
} else if ((playerMove == "scissors")&& (computerMove == "paper")){
	return "player";
} else if ((playerMove == "rock")&& (computerMove == "scissors")){
	return "player";
} else if ((playerMove == "rock")&& (computerMove == "paper")){
	return "computer";
} else if ((playerMove == "paper")&& (computerMove == "scissors")){
	return "computer";
} else if ((playerMove == "paper")&& (computerMove == "rock")){
	return "player";
} else return "tie"

}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors" + '\n');

    var playerWins = 0;
    var computerWins = 0;
    var pMove;
    var cMove;

while ((playerWins < 5) || (computerWins <5))
   {
	 pMove = getPlayerMove();
	 cMove = getComputerMove();
	console.log('Player chose ' + pMove + ' while Computer chose ' +    cMove + '\n');
	var winner = getWinner(pMove,cMove);
	if (winner=="player")
	{
		playerWins=playerWins+1;
		console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');

        }else if (winner=="computer"){
	computerWins=computerWins+1;
		console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
	}else console.log('Tie, The score is currently ' + playerWins + ' to ' + computerWins + '\n');

    }

    return [playerWins, computerWins];

}

<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || getInput();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>Control Flow...<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || getInput();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === computerMove) {
        return 'tie';

    } else if (playerMove === "rock" && computerMove === "scissors") {
        winner = 'player';
        return playerWins;

    } else if (playerMove === 'scissors' && computerMove === 'paper') {
        winner = 'player';
        return playerWins;

    } else (playerMove === 'paper' && computerMove === 'rock') {
        winner = 'player';
        return playerWins;

    } else {
        winner = 'computer';
        return computerWins;
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<|endoftext|>


<commit_before>function var_export ( mixed_expression, bool_return ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // -    depends on: echo
    // *     example 1: var_export(new Array("hi", "there"))
    // *     returns 1: "array (
    //                     'hi',
    //                     'there',
    //                   )"

    var __pad_lines = function ( x ) {
        return x.split("\n").join("\n  ");
    }
    var retstr="";

    if(mixed_expression instanceof Array) {
        var iret="";
        for(i in mixed_expression) {
            iret=iret+"\n"+var_export(i,true)+" => "+var_export(mixed_expression[i], true)+",";
        }
    retstr = "array ("+__pad_lines(iret)+"\n)";
    }

    else if( mixed_expression === null) {
        retstr = "NULL";
    }
    else {
        retstr = (!isNaN( mixed_expression )) ? mixed_expression : "'"+mixed_expression.replace('/(["\'\])/g', "\\$1").replace('/\0/g', "\\0")+"'";
    }

    if(bool_return != true) {
        echo(retstr);
        return null;
    }
    else {
        return retstr;
    }
}

<commit_msg>current example breaks tester<commit_after>function var_export ( mixed_expression, bool_return ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // -    depends on: echo
    // *     example 1: var_export(null);
    // *     returns 1: 'NULL'

    var __pad_lines = function ( x ) {
        return x.split("\n").join("\n  ");
    }
    var retstr = "";

    if(mixed_expression instanceof Array) {
        var iret = "";
        for(i in mixed_expression) {
            iret=iret+"\n"+var_export(i,true)+" => "+var_export(mixed_expression[i], true)+",";
        }
        retstr = "array ("+__pad_lines(iret)+"\n)";
    } else if( mixed_expression === null) {
        retstr = "NULL";
    } else {
        retstr = (!isNaN( mixed_expression )) ? mixed_expression : "'" + mixed_expression.replace('/(["\'\])/g', "\\$1").replace('/\0/g', "\\0") + "'";
    }

    if(bool_return != true) {
        echo(retstr);
        return null;
    }
    else {
        return retstr;
    }
}

<|endoftext|>


<commit_before>'use strict';
import _ from 'lodash';
import Promise from 'native-promise-only';
import { checkCondition } from '../../../utils/utils';
import Component from '../component/Component';
import Components from '../../Components';

export default class NestedComponent extends Component {
  static schema(...extend) {
    return Component.schema({
      tree: true
    }, ...extend);
  }

  constructor(component, options, data) {
    super(component, options, data);
    this.type = 'components';
    this._collapsed = !!this.component.collapsed;
    this.components = [];
  }

  get defaultSchema() {
    return NestedComponent.schema();
  }

  get schema() {
    const schema = super.schema;
    schema.components = [];
    this.eachComponent((component) => schema.components.push(component.schema));
    return schema;
  }

  get collapsed() {
    return this._collapsed;
  }

  set collapsed(value) {
    this._collapsed = value;
    this.redraw();
  }

  set visible(value) {
    super.visible = value;
    const isVisible = this.visible;
    const forceShow = this.options.show && this.options.show[this.component.key];
    const forceHide = this.options.hide && this.options.hide[this.component.key];
    this.componentComponents.forEach(component => {
      const conditionallyVisible = component.conditionallyVisible();
      if (forceShow || (!isVisible && conditionallyVisible)) {
        component.visible = true;
      }
      else if (forceHide || (isVisible && !conditionallyVisible)) {
        component.visible = false;
      }
      // If hiding a nested component, clear all errors below.
      if (!component.visible) {
        component.error = '';
      }
      component.parentVisible = isVisible;
    });
  }

  get visible() {
    return super.visible;
  }

  set parentVisible(value) {
    super.parentVisible = value;
    this.components.forEach(component => {
      component.parentVisible = this.visible;
    });
  }

  get parentVisible() {
    return super.parentVisible;
  }

  getComponents() {
    return this.components || [];
  }

  getAllComponents() {
    return this.getComponents().reduce((components, component) => {
      let result = component;

      if (component && component.getAllComponents) {
        result = component.getAllComponents();
      }

      return components.concat(result);
    }, []);
  }

  /**
   * Perform a deep iteration over every component, including those
   * within other container based components.
   *
   * @param {function} fn - Called for every component.
   */
  everyComponent(fn) {
    const components = this.getComponents();
    _.each(components, (component, index) => {
      if (fn(component, components, index) === false) {
        return false;
      }

      if (typeof component.everyComponent === 'function') {
        if (component.everyComponent(fn) === false) {
          return false;
        }
      }
    });
  }

  /**
   * Perform an iteration over each component within this container component.
   *
   * @param {function} fn - Called for each component
   */
  eachComponent(fn) {
    _.each(this.getComponents(), (component, index) => {
      if (fn(component, index) === false) {
        return false;
      }
    });
  }

  /**
   * Returns a component provided a key. This performs a deep search within the
   * component tree.
   *
   * @param {string} key - The key of the component to retrieve.
   * @param {function} fn - Called with the component once found.
   * @return {Object} - The component that is located.
   */
  getComponent(key, fn) {
    let comp = null;
    this.everyComponent((component, components) => {
      if (component.component.key === key) {
        comp = component;
        if (fn) {
          fn(component, components);
        }
        return false;
      }
    });
    return comp;
  }

  /**
   * Return a component provided the Id of the component.
   *
   * @param {string} id - The Id of the component.
   * @param {function} fn - Called with the component once it is retrieved.
   * @return {Object} - The component retrieved.
   */
  getComponentById(id, fn) {
    let comp = null;
    this.everyComponent((component, components) => {
      if (component.id === id) {
        comp = component;
        if (fn) {
          fn(component, components);
        }
        return false;
      }
    });
    return comp;
  }

  /**
   * Create a new component and add it to the components array.
   *
   * @param component
   * @param data
   */
  createComponent(component, options, data, before) {
    options = options || this.options;
    data = data || this.data;
    const comp = Components.create(component, options, data, true);
    comp.parent = this;
    comp.root = this.root || this;
    comp.parentVisible = this.visible;
    comp.isBuilt = true;
    if (component.internal) {
      return comp;
    }

    if (before) {
      const index = _.findIndex(this.components, { id: before.id });
      if (index !== -1) {
        this.components.splice(index, 0, comp);
      }
      else {
        this.components.push(comp);
      }
    }
    else {
      this.components.push(comp);
    }
    return comp;
  }

  getContainer() {
    return this.element;
  }

  get componentComponents() {
    return this.component.components || [];
  }

  get nestedKey() {
    return `nested-${this.key}`;
  }

  get templateName() {
    return 'container';
  }

  init() {
    this.components = this.components || [];
    this.addComponents();
  }

  /**
   *
   * @param element
   * @param data
   */
  addComponents(data, options) {
    data = data || this.data;
    options = options || this.options;
    if (options.components) {
      this.components = options.components;
    }
    else {
      const components = this.hook('addComponents', this.componentComponents, this) || [];
      components.forEach((component) => this.addComponent(component, data));
    }
  }

  /**
   * Add a new component to the components array.
   *
   * @param {Object} component - The component JSON schema to add.
   * @param {Object} data - The submission data object to house the data for this component.
   * @param {HTMLElement} before - A DOM element to insert this element before.
   * @return {Component} - The created component instance.
   */
  addComponent(component, data, before, noAdd) {
    data = data || this.data;
    const comp = this.createComponent(component, this.options, data, before ? before.component : null);
    if (noAdd) {
      return comp;
    }
    return comp;
  }

  render(children) {
    // If already rendering, don't re-render.
    return super.render(children || this.renderTemplate(this.templateName, {
      children: this.renderComponents(),
      nestedKey: this.nestedKey,
      collapsed: this.collapsed,
    }));
  }

  renderComponents(components) {
    components = components || this.components;
    const children = components.map(component => component.render());
    return this.renderTemplate('components', {
      children,
      components,
    });
  }

  attach(element) {
    this.loadRefs(element, {
      header: 'single',
      collapsed: this.collapsed,
      [this.nestedKey]: 'single',
    });

    if (this.refs[this.nestedKey]) {
      this.attachComponents(this.refs[this.nestedKey]);
    }

    if (this.component.collapsible && this.refs.header) {
      this.addEventListener(this.refs.header, 'click', () => {
        this.collapsed = !this.collapsed;
      });
    }

    super.attach(element);
  }

  attachComponents(element, components, container) {
    components = components || this.components;
    container = container || this.component.components;

    element = this.hook('attachComponents', element, components, container, this);
    if (!element) {
      return;
    }

    let index = 0;
    Array.prototype.slice.call(element.children).forEach(child => {
      if (!child.getAttribute('data-noattach') && components[index]) {
        components[index].attach(child);
        index++;
      }
    });
  }

  /**
   * Remove a component from the components array.
   *
   * @param {Component} component - The component to remove from the components.
   * @param {Array<Component>} components - An array of components to remove this component from.
   */
  removeComponent(component, components) {
    component.destroy();
    _.remove(components, { id: component.id });
  }

  /**
   * Removes a component provided the API key of that component.
   *
   * @param {string} key - The API key of the component to remove.
   * @param {function} fn - Called once the component is removed.
   * @return {null}
   */
  removeComponentByKey(key, fn) {
    const comp = this.getComponent(key, (component, components) => {
      this.removeComponent(component, components);
      if (fn) {
        fn(component, components);
      }
    });
    if (!comp) {
      if (fn) {
        fn(null);
      }
      return null;
    }
  }

  /**
   * Removes a component provided the Id of the component.
   *
   * @param {string} id - The Id of the component to remove.
   * @param {function} fn - Called when the component is removed.
   * @return {null}
   */
  removeComponentById(id, fn) {
    const comp = this.getComponentById(id, (component, components) => {
      this.removeComponent(component, components);
      if (fn) {
        fn(component, components);
      }
    });
    if (!comp) {
      if (fn) {
        fn(null);
      }
      return null;
    }
  }

  updateValue(flags) {
    return this.componentComponents.reduce((changed, comp) => comp.updateValue(flags) || changed, false);
  }

  hasChanged() {
    return false;
  }

  /**
   * A more performant way to check the conditions, calculations, and validity of
   * a submission once it has been changed.
   *
   * @param data
   * @param flags
   */
  checkData(data, flags) {
    flags = flags || {};
    let valid = true;
    if (flags.noCheck) {
      return;
    }

    // Update the value.
    let changed = this.updateValue({
      noUpdateEvent: true
    });

    // Iterate through all components and check conditions, and calculate values.
    this.getComponents().forEach((comp) => {
      changed |= comp.calculateValue(data, {
        noUpdateEvent: true
      });
      comp.checkConditions(data);
      if (!flags.noValidate) {
        valid &= comp.checkValidity(data);
      }
    });

    // Trigger the change if the values changed.
    if (changed) {
      this.triggerChange(flags);
    }

    // Return if the value is valid.
    return valid;
  }

  checkConditions(data) {
    this.getComponents().forEach(comp => comp.checkConditions(data));
    return super.checkConditions(data);
  }

  clearOnHide(show) {
    super.clearOnHide(show);
    this.getComponents().forEach(component => component.clearOnHide(show));
  }

  /**
   * Allow components to hook into the next page trigger to perform their own logic.
   *
   * @return {*}
   */
  beforeNext() {
    return Promise.all(this.getComponents().map((comp) => comp.beforeNext()));
  }

  /**
   * Allow components to hook into the submission to provide their own async data.
   *
   * @return {*}
   */
  beforeSubmit() {
    return Promise.all(this.getComponents().map((comp) => comp.beforeSubmit()));
  }

  calculateValue(data, flags) {
    return this.getComponents().reduce(
      (changed, comp) => comp.calculateValue(data, flags) || changed,
      super.calculateValue(data, flags)
    );
  }

  isValid(data, dirty) {
    return this.getComponents().reduce(
      (valid, comp) => comp.isValid(data, dirty) && valid,
      super.isValid(data, dirty)
    );
  }

  checkValidity(data, dirty) {
    if (!checkCondition(this.component, data, this.data, this.root ? this.root._form : {}, this)) {
      this.setCustomValidity('');
      return true;
    }

    return this.getComponents().reduce(
      (check, comp) => comp.checkValidity(data, dirty) && check,
      super.checkValidity(data, dirty)
    );
  }

  setPristine(pristine) {
    super.setPristine(pristine);
    this.getComponents().forEach((comp) => comp.setPristine(pristine));
  }

  detach() {
    this.components.forEach(component => {
      component.detach();
    });
    super.detach();
  }

  destroy() {
    this.destroyComponents();
    super.destroy();
  }

  destroyComponents() {
    const components = this.componentComponents.slice();
    components.forEach((comp) => this.removeComponent(comp, this.components));
    this.components = [];
  }

  set disabled(disabled) {
    this.componentComponents.forEach((component) => component.disabled = disabled);
  }

  get errors() {
    return this.getAllComponents().reduce((errors, comp) => errors.concat(comp.errors || []), []);
  }

  getValue() {
    return this.data;
  }

  resetValue() {
    this.getComponents().forEach((comp) => comp.resetValue());
    _.unset(this.data, this.key);
    this.setPristine(true);
  }

  setNestedValue(component, value, flags, changed) {
    if (component.type === 'button') {
      return false;
    }
    if (component.type === 'components') {
      return component.setValue(value, flags) || changed;
    }
    else if (value && component.hasValue(value)) {
      return component.setValue(_.get(value, component.key), flags) || changed;
    }
    else {
      flags.noValidate = true;
      return component.setValue(component.defaultValue, flags) || changed;
    }
  }

  setValue(value, flags) {
    if (!value) {
      return false;
    }
    flags = this.getFlags.apply(this, arguments);
    return this.getComponents().reduce((changed, component) => {
      return this.setNestedValue(component, value, flags, changed);
    }, false);
  }
}
<commit_msg>Fixed problem where nested components would fire calculate value of children when it is conditionally hidden.<commit_after>'use strict';
import _ from 'lodash';
import Promise from 'native-promise-only';
import { checkCondition } from '../../../utils/utils';
import Component from '../component/Component';
import Components from '../../Components';

export default class NestedComponent extends Component {
  static schema(...extend) {
    return Component.schema({
      tree: true
    }, ...extend);
  }

  constructor(component, options, data) {
    super(component, options, data);
    this.type = 'components';
    this._collapsed = !!this.component.collapsed;
    this.components = [];
  }

  get defaultSchema() {
    return NestedComponent.schema();
  }

  get schema() {
    const schema = super.schema;
    schema.components = [];
    this.eachComponent((component) => schema.components.push(component.schema));
    return schema;
  }

  get collapsed() {
    return this._collapsed;
  }

  set collapsed(value) {
    this._collapsed = value;
    this.redraw();
  }

  set visible(value) {
    super.visible = value;
    const isVisible = this.visible;
    const forceShow = this.options.show && this.options.show[this.component.key];
    const forceHide = this.options.hide && this.options.hide[this.component.key];
    this.componentComponents.forEach(component => {
      const conditionallyVisible = component.conditionallyVisible();
      if (forceShow || (!isVisible && conditionallyVisible)) {
        component.visible = true;
      }
      else if (forceHide || (isVisible && !conditionallyVisible)) {
        component.visible = false;
      }
      // If hiding a nested component, clear all errors below.
      if (!component.visible) {
        component.error = '';
      }
      component.parentVisible = isVisible;
    });
  }

  get visible() {
    return super.visible;
  }

  set parentVisible(value) {
    super.parentVisible = value;
    this.components.forEach(component => {
      component.parentVisible = this.visible;
    });
  }

  get parentVisible() {
    return super.parentVisible;
  }

  getComponents() {
    return this.components || [];
  }

  getAllComponents() {
    return this.getComponents().reduce((components, component) => {
      let result = component;

      if (component && component.getAllComponents) {
        result = component.getAllComponents();
      }

      return components.concat(result);
    }, []);
  }

  /**
   * Perform a deep iteration over every component, including those
   * within other container based components.
   *
   * @param {function} fn - Called for every component.
   */
  everyComponent(fn) {
    const components = this.getComponents();
    _.each(components, (component, index) => {
      if (fn(component, components, index) === false) {
        return false;
      }

      if (typeof component.everyComponent === 'function') {
        if (component.everyComponent(fn) === false) {
          return false;
        }
      }
    });
  }

  /**
   * Perform an iteration over each component within this container component.
   *
   * @param {function} fn - Called for each component
   */
  eachComponent(fn) {
    _.each(this.getComponents(), (component, index) => {
      if (fn(component, index) === false) {
        return false;
      }
    });
  }

  /**
   * Returns a component provided a key. This performs a deep search within the
   * component tree.
   *
   * @param {string} key - The key of the component to retrieve.
   * @param {function} fn - Called with the component once found.
   * @return {Object} - The component that is located.
   */
  getComponent(key, fn) {
    let comp = null;
    this.everyComponent((component, components) => {
      if (component.component.key === key) {
        comp = component;
        if (fn) {
          fn(component, components);
        }
        return false;
      }
    });
    return comp;
  }

  /**
   * Return a component provided the Id of the component.
   *
   * @param {string} id - The Id of the component.
   * @param {function} fn - Called with the component once it is retrieved.
   * @return {Object} - The component retrieved.
   */
  getComponentById(id, fn) {
    let comp = null;
    this.everyComponent((component, components) => {
      if (component.id === id) {
        comp = component;
        if (fn) {
          fn(component, components);
        }
        return false;
      }
    });
    return comp;
  }

  /**
   * Create a new component and add it to the components array.
   *
   * @param component
   * @param data
   */
  createComponent(component, options, data, before) {
    options = options || this.options;
    data = data || this.data;
    const comp = Components.create(component, options, data, true);
    comp.parent = this;
    comp.root = this.root || this;
    comp.parentVisible = this.visible;
    comp.isBuilt = true;
    if (component.internal) {
      return comp;
    }

    if (before) {
      const index = _.findIndex(this.components, { id: before.id });
      if (index !== -1) {
        this.components.splice(index, 0, comp);
      }
      else {
        this.components.push(comp);
      }
    }
    else {
      this.components.push(comp);
    }
    return comp;
  }

  getContainer() {
    return this.element;
  }

  get componentComponents() {
    return this.component.components || [];
  }

  get nestedKey() {
    return `nested-${this.key}`;
  }

  get templateName() {
    return 'container';
  }

  init() {
    this.components = this.components || [];
    this.addComponents();
  }

  /**
   *
   * @param element
   * @param data
   */
  addComponents(data, options) {
    data = data || this.data;
    options = options || this.options;
    if (options.components) {
      this.components = options.components;
    }
    else {
      const components = this.hook('addComponents', this.componentComponents, this) || [];
      components.forEach((component) => this.addComponent(component, data));
    }
  }

  /**
   * Add a new component to the components array.
   *
   * @param {Object} component - The component JSON schema to add.
   * @param {Object} data - The submission data object to house the data for this component.
   * @param {HTMLElement} before - A DOM element to insert this element before.
   * @return {Component} - The created component instance.
   */
  addComponent(component, data, before, noAdd) {
    data = data || this.data;
    const comp = this.createComponent(component, this.options, data, before ? before.component : null);
    if (noAdd) {
      return comp;
    }
    return comp;
  }

  render(children) {
    // If already rendering, don't re-render.
    return super.render(children || this.renderTemplate(this.templateName, {
      children: this.renderComponents(),
      nestedKey: this.nestedKey,
      collapsed: this.collapsed,
    }));
  }

  renderComponents(components) {
    components = components || this.components;
    const children = components.map(component => component.render());
    return this.renderTemplate('components', {
      children,
      components,
    });
  }

  attach(element) {
    this.loadRefs(element, {
      header: 'single',
      collapsed: this.collapsed,
      [this.nestedKey]: 'single',
    });

    if (this.refs[this.nestedKey]) {
      this.attachComponents(this.refs[this.nestedKey]);
    }

    if (this.component.collapsible && this.refs.header) {
      this.addEventListener(this.refs.header, 'click', () => {
        this.collapsed = !this.collapsed;
      });
    }

    super.attach(element);
  }

  attachComponents(element, components, container) {
    components = components || this.components;
    container = container || this.component.components;

    element = this.hook('attachComponents', element, components, container, this);
    if (!element) {
      return;
    }

    let index = 0;
    Array.prototype.slice.call(element.children).forEach(child => {
      if (!child.getAttribute('data-noattach') && components[index]) {
        components[index].attach(child);
        index++;
      }
    });
  }

  /**
   * Remove a component from the components array.
   *
   * @param {Component} component - The component to remove from the components.
   * @param {Array<Component>} components - An array of components to remove this component from.
   */
  removeComponent(component, components) {
    component.destroy();
    _.remove(components, { id: component.id });
  }

  /**
   * Removes a component provided the API key of that component.
   *
   * @param {string} key - The API key of the component to remove.
   * @param {function} fn - Called once the component is removed.
   * @return {null}
   */
  removeComponentByKey(key, fn) {
    const comp = this.getComponent(key, (component, components) => {
      this.removeComponent(component, components);
      if (fn) {
        fn(component, components);
      }
    });
    if (!comp) {
      if (fn) {
        fn(null);
      }
      return null;
    }
  }

  /**
   * Removes a component provided the Id of the component.
   *
   * @param {string} id - The Id of the component to remove.
   * @param {function} fn - Called when the component is removed.
   * @return {null}
   */
  removeComponentById(id, fn) {
    const comp = this.getComponentById(id, (component, components) => {
      this.removeComponent(component, components);
      if (fn) {
        fn(component, components);
      }
    });
    if (!comp) {
      if (fn) {
        fn(null);
      }
      return null;
    }
  }

  updateValue(flags) {
    return this.componentComponents.reduce((changed, comp) => comp.updateValue(flags) || changed, false);
  }

  hasChanged() {
    return false;
  }

  /**
   * A more performant way to check the conditions, calculations, and validity of
   * a submission once it has been changed.
   *
   * @param data
   * @param flags
   */
  checkData(data, flags) {
    flags = flags || {};
    let valid = true;
    if (flags.noCheck) {
      return;
    }

    // Update the value.
    let changed = this.updateValue({
      noUpdateEvent: true
    });

    // Iterate through all components and check conditions, and calculate values.
    this.getComponents().forEach((comp) => {
      changed |= comp.calculateValue(data, {
        noUpdateEvent: true
      });
      comp.checkConditions(data);
      if (!flags.noValidate) {
        valid &= comp.checkValidity(data);
      }
    });

    // Trigger the change if the values changed.
    if (changed) {
      this.triggerChange(flags);
    }

    // Return if the value is valid.
    return valid;
  }

  checkConditions(data) {
    this.getComponents().forEach(comp => comp.checkConditions(data));
    return super.checkConditions(data);
  }

  clearOnHide(show) {
    super.clearOnHide(show);
    this.getComponents().forEach(component => component.clearOnHide(show));
  }

  /**
   * Allow components to hook into the next page trigger to perform their own logic.
   *
   * @return {*}
   */
  beforeNext() {
    return Promise.all(this.getComponents().map((comp) => comp.beforeNext()));
  }

  /**
   * Allow components to hook into the submission to provide their own async data.
   *
   * @return {*}
   */
  beforeSubmit() {
    return Promise.all(this.getComponents().map((comp) => comp.beforeSubmit()));
  }

  calculateValue(data, flags) {
    // Do not iterate into children and calculateValues if this nested component is conditionally hidden.
    if (!this.conditionallyVisible()) {
      return false;
    }
    return this.getComponents().reduce(
      (changed, comp) => comp.calculateValue(data, flags) || changed,
      super.calculateValue(data, flags)
    );
  }

  isValid(data, dirty) {
    return this.getComponents().reduce(
      (valid, comp) => comp.isValid(data, dirty) && valid,
      super.isValid(data, dirty)
    );
  }

  checkValidity(data, dirty) {
    if (!checkCondition(this.component, data, this.data, this.root ? this.root._form : {}, this)) {
      this.setCustomValidity('');
      return true;
    }

    return this.getComponents().reduce(
      (check, comp) => comp.checkValidity(data, dirty) && check,
      super.checkValidity(data, dirty)
    );
  }

  setPristine(pristine) {
    super.setPristine(pristine);
    this.getComponents().forEach((comp) => comp.setPristine(pristine));
  }

  detach() {
    this.components.forEach(component => {
      component.detach();
    });
    super.detach();
  }

  destroy() {
    this.destroyComponents();
    super.destroy();
  }

  destroyComponents() {
    const components = this.componentComponents.slice();
    components.forEach((comp) => this.removeComponent(comp, this.components));
    this.components = [];
  }

  set disabled(disabled) {
    this.componentComponents.forEach((component) => component.disabled = disabled);
  }

  get errors() {
    return this.getAllComponents().reduce((errors, comp) => errors.concat(comp.errors || []), []);
  }

  getValue() {
    return this.data;
  }

  resetValue() {
    this.getComponents().forEach((comp) => comp.resetValue());
    _.unset(this.data, this.key);
    this.setPristine(true);
  }

  setNestedValue(component, value, flags, changed) {
    if (component.type === 'button') {
      return false;
    }
    if (component.type === 'components') {
      return component.setValue(value, flags) || changed;
    }
    else if (value && component.hasValue(value)) {
      return component.setValue(_.get(value, component.key), flags) || changed;
    }
    else {
      flags.noValidate = true;
      return component.setValue(component.defaultValue, flags) || changed;
    }
  }

  setValue(value, flags) {
    if (!value) {
      return false;
    }
    flags = this.getFlags.apply(this, arguments);
    return this.getComponents().reduce((changed, component) => {
      return this.setNestedValue(component, value, flags, changed);
    }, false);
  }
}
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { injectIntl } from 'react-intl';
import { schemeCategory10 } from 'd3';
import { push } from 'react-router-redux';
import composeAsyncContainer from '../common/AsyncContainer';
import LoadingSpinner from '../common/LoadingSpinner';
import { LEVEL_ERROR } from '../common/Notice';
import { addNotice } from '../../actions/appActions';
import { selectBySearchParams, fetchSampleSearches, updateQuerySourceLookupInfo, updateQueryCollectionLookupInfo,
  fetchQuerySourcesByIds, fetchQueryCollectionsByIds, demoQuerySourcesByIds, demoQueryCollectionsByIds } from '../../actions/explorerActions';
// import { FETCH_INVALID, FETCH_SUCCEEDED } from '../../lib/fetchConstants';
import { DEFAULT_COLLECTION_OBJECT_ARRAY, autoMagicQueryLabel, generateQueryParamString, decodeQueryParamString } from '../../lib/explorerUtil';
import { getDateRange, solrFormat, PAST_MONTH } from '../../lib/dateUtil';
import { notEmptyString } from '../../lib/formValidators';

const localMessages = {
  errorInURLParams: { id: 'explorer.queryBuilder.urlParams',
    defaultMessage: 'Your URL query is incomplete. Check the URL and make sure the keyword(s), start and end dates, and collection(s) are properly specified.' },
};

/**
 * Only render the widget once we've pared the query from the URL - complicated because we do an async fetch
 * to get source and collection details from the server.
 */
function composeUrlBasedQueryContainer() {
  return (ChildComponent) => {
    class UrlBasedQueryContainer extends React.Component {
      state = {
        queryInStore: false,
      };
      componentWillMount() {
        const { location } = this.props;
        // if from homepage, allow automagic, if from URL, do not...
        const autoMagic = location.query.auto === 'true';
        this.setState({ queryInStore: false }); // if/def automagic here
        this.setQueryFromLocation(location, autoMagic);
      }
      componentWillReceiveProps(nextProps) {
        const { location, lastSearchTime, updateUrl, isLoggedIn } = this.props;
        // console.log('new props');
        // if URL has been updated by hand, reparse and store
        if ((nextProps.location.pathname !== location.pathname) && (lastSearchTime === nextProps.lastSearchTime)) {
          this.setState({ queryInStore: false }); // show spinner while parsing and loading query
          // console.log('  url change');
          this.setQueryFromLocation(location);
        // if we don't have all the data in the store yet
        } else if (this.state.queryInStore === false) {   // make sure to only do this once
          // console.log('  waiting for media info from server');
          // mark the whole thing as ready once any sources and collections have been set
          if (this.isAllMediaDetailsReady()) {
            // console.log('  got media info from server, ready!');
            this.setState({ queryInStore: true });  // mark that the parsing process has finished
          }
          if (nextProps.queries.filter(q => q.sources.length > 0).length === 0 && nextProps.queries.filter(q => q.collections.length > 0).length === 0) {
            this.setState({ queryInStore: true });
            updateUrl(nextProps.queries, isLoggedIn);
          }
        } else if (lastSearchTime !== nextProps.lastSearchTime) {
          updateUrl(nextProps.queries, isLoggedIn);
        } else {
          // console.log('  other change');
        }
      }
      setQueryFromLocation(location, autoName) {
        // regular searches are in a queryParam, but samples by id are part of the path
        const url = location.pathname;
        const lastPathPart = url.slice(url.lastIndexOf('/') + 1, url.length);
        const sampleNumber = parseInt(lastPathPart, 10);
        if (!isNaN(sampleNumber)) {
          this.setQueryFromSample(sampleNumber);
        } else {
          this.setQueryFromSearch(location.query.q.replace(/:""/g, ':"\\"').replace(/"",/g, '\\"",'), autoName);
        }
      }
      setQueryFromSearch(search, autoName) {
        // const queryAsJsonStr = search.slice(3, search.length);
        this.setQueryFromString(search, autoName);
      }
      setQueryFromSample(sampleNumber) {
        const { saveQueriesFromParsedUrl, samples, isLoggedIn } = this.props;
        const queriesFromUrl = samples[sampleNumber].queries;
        // push the queries in to the store
        saveQueriesFromParsedUrl(queriesFromUrl, isLoggedIn);
      }
      setQueryFromString(queryAsJsonStr, autoNaming) {
        const { addAppNotice, saveQueriesFromParsedUrl, isLoggedIn } = this.props;
        const { formatMessage } = this.props.intl;
        let queriesFromUrl;

        try {
          queriesFromUrl = decodeQueryParamString(decodeURIComponent(queryAsJsonStr));
        } catch (f) {
          addAppNotice({ level: LEVEL_ERROR, message: formatMessage(localMessages.errorInURLParams) });
          return;
        }

        let extraDefaults = {};
        // add in an index, label, and color if they are not there
        if (!isLoggedIn) {  // and demo mode needs some extra stuff too
          const dateObj = getDateRange(PAST_MONTH);
          extraDefaults = {
            sources: [],
            collections: DEFAULT_COLLECTION_OBJECT_ARRAY,
            startDate: solrFormat(dateObj.start),
            endDate: solrFormat(dateObj.end),
          };
        } else {
          extraDefaults = { autoNaming };
        }
        queriesFromUrl = queriesFromUrl.map((query, index) => ({
          ...query, // let anything on URL override label and color
          label: notEmptyString(query.label) ? query.label : autoMagicQueryLabel(query),
          // remember demo queries won't have sources or collections on the URL
          sources: query.sources ? query.sources.map(s => ({ id: s, media_id: s })) : undefined,
          collections: query.collections ? query.collections.map(s => ({ id: s, tags_id: s })) : undefined,
          q: query.q,
          color: query.color ? query.color : schemeCategory10[index % 10],
          index,  // redo index to be zero-based on reload of query
          ...extraDefaults, // for demo mode
        }));
        // push the queries in to the store
        saveQueriesFromParsedUrl(queriesFromUrl, isLoggedIn);
      }
      isAllMediaDetailsReady() {
        // we will only render the wrapped component once all the details of the sources and collections
        // have been fetched from the server and put in the right place on each query
        const { queries } = this.props;
        if (queries.length === 0) return false; // need to bail if no queries (ie. first page mount)
        const queryCollectionStatus = queries.map(q => q.collections.length === 0 ||
          q.collections.reduce((combined, c) => combined && c.tag_sets_id !== undefined, true));
        const collectionsAreReady = queryCollectionStatus.reduce((combined, q) => combined && q, true);
        const querySourceStatus = queries.map(q => q.sources.length === 0 ||
          q.sources.reduce((combined, s) => combined && s.name !== undefined, true));
        const sourcesAreReady = querySourceStatus.reduce((combined, q) => combined && q, true);
        return collectionsAreReady && sourcesAreReady;
      }
      render() {
        let content;
        if (this.state.queryInStore) {
          content = <ChildComponent {...this.props} />;
        } else {
          content = <LoadingSpinner />;
        }
        return (
          <div className="serializable-query">
            {content}
          </div>
        );
      }
    }

    UrlBasedQueryContainer.propTypes = {
      intl: PropTypes.object.isRequired,
      location: PropTypes.object,
      // from store
      isLoggedIn: PropTypes.bool.isRequired,
      fetchStatus: PropTypes.string.isRequired,
      samples: PropTypes.array,
      queries: PropTypes.array,
      lastSearchTime: PropTypes.number,
      // from dispatch
      saveQueriesFromParsedUrl: PropTypes.func.isRequired,
      addAppNotice: PropTypes.func.isRequired,
      updateUrl: PropTypes.func.isRequired,
    };

    const mapStateToProps = state => ({
      isLoggedIn: state.user.isLoggedIn,
      fetchStatus: state.explorer.samples.fetchStatus,
      samples: state.explorer.samples.list,
      queries: state.explorer.queries.queries,
      lastSearchTime: state.explorer.lastSearchTime.time,
    });

    // push any updates (including selected) into queries in state, will trigger async load in sub sections
    const mapDispatchToProps = dispatch => ({
      addAppNotice: (info) => {
        dispatch(addNotice(info));
      },
      // handles demo mode by allowing you to pass in extraDefaults
      saveQueriesFromParsedUrl: (queriesToUse, isLoggedIn) => {
        dispatch(selectBySearchParams(queriesToUse)); // load query data into the store
        // lookup ancillary data eg collection and source info for display purposes in QueryForm
        queriesToUse.forEach((q) => {
          const queryInfo = {
            ...q,
          };
          const sourceDetailsAction = isLoggedIn ? fetchQuerySourcesByIds : demoQuerySourcesByIds;
          if (q.sources && q.sources.length > 0) {
            queryInfo.sources = q.sources.map(src => src.media_id || src.id || src); // the latter in case of sample search
            dispatch(sourceDetailsAction(queryInfo))
            .then((results) => {
              queryInfo.sources = results;
              dispatch(updateQuerySourceLookupInfo(queryInfo)); // updates the query and the selected query
            });
          }
          const collectionDetailsAction = isLoggedIn ? fetchQueryCollectionsByIds : demoQueryCollectionsByIds;
          if (q.collections && q.collections.length > 0) {
            queryInfo.collections = q.collections.map(coll => coll.tags_id || coll.id || coll); // the latter in case of sample search
            dispatch(collectionDetailsAction(queryInfo))
            .then((results) => {
              queryInfo.collections = results;
              dispatch(updateQueryCollectionLookupInfo(queryInfo)); // updates the query and the selected query
            });
          }
        });
      },
      asyncFetch: () => {
        dispatch(fetchSampleSearches());   // inefficient: we need the sample searches loaded just in case
      },
      updateUrl: (queries, isLoggedIn) => {
        const unDeletedQueries = queries.filter(q => q.deleted !== true);
        const nonEmptyQueries = unDeletedQueries.filter(q => q.q !== undefined && q.q !== '');
        if (!isLoggedIn) {
          const urlParamString = nonEmptyQueries.map((q, idx) => `{"index":${idx},"q":"${encodeURIComponent(q.q)}","color":"${encodeURIComponent(q.color)}"}`);
          dispatch(push({ pathname: '/queries/demo/search', search: `?q=[${urlParamString}]` }));
        } else {
          const search = generateQueryParamString(queries.map(q => ({
            label: q.label,
            q: q.q,
            color: q.color,
            startDate: q.startDate,
            endDate: q.endDate,
            sources: q.sources, // de-aggregate media bucket into sources and collections
            collections: q.collections,
          })));
          dispatch(push({ pathname: '/queries/search', search: `?q=${search}` })); // query adds a '?query='
        }
      },
    });

    return injectIntl(
      connect(mapStateToProps, mapDispatchToProps)(
        composeAsyncContainer(
          UrlBasedQueryContainer
        )
      )
    );
  };
}

export default composeUrlBasedQueryContainer;
<commit_msg>crazy regex solution to readable, but also parse-able quoted queries (#990)<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { injectIntl } from 'react-intl';
import { schemeCategory10 } from 'd3';
import { push } from 'react-router-redux';
import composeAsyncContainer from '../common/AsyncContainer';
import LoadingSpinner from '../common/LoadingSpinner';
import { LEVEL_ERROR } from '../common/Notice';
import { addNotice } from '../../actions/appActions';
import { selectBySearchParams, fetchSampleSearches, updateQuerySourceLookupInfo, updateQueryCollectionLookupInfo,
  fetchQuerySourcesByIds, fetchQueryCollectionsByIds, demoQuerySourcesByIds, demoQueryCollectionsByIds } from '../../actions/explorerActions';
// import { FETCH_INVALID, FETCH_SUCCEEDED } from '../../lib/fetchConstants';
import { DEFAULT_COLLECTION_OBJECT_ARRAY, autoMagicQueryLabel, generateQueryParamString, decodeQueryParamString } from '../../lib/explorerUtil';
import { getDateRange, solrFormat, PAST_MONTH } from '../../lib/dateUtil';
import { notEmptyString } from '../../lib/formValidators';

const localMessages = {
  errorInURLParams: { id: 'explorer.queryBuilder.urlParams',
    defaultMessage: 'Your URL query is incomplete. Check the URL and make sure the keyword(s), start and end dates, and collection(s) are properly specified.' },
};

/**
 * Only render the widget once we've pared the query from the URL - complicated because we do an async fetch
 * to get source and collection details from the server.
 */
function composeUrlBasedQueryContainer() {
  return (ChildComponent) => {
    class UrlBasedQueryContainer extends React.Component {
      state = {
        queryInStore: false,
      };
      componentWillMount() {
        const { location } = this.props;
        // if from homepage, allow automagic, if from URL, do not...
        const autoMagic = location.query.auto === 'true';
        this.setState({ queryInStore: false }); // if/def automagic here
        this.updateQueriesFromLocation(location, autoMagic);
      }
      componentWillReceiveProps(nextProps) {
        const { location, lastSearchTime, updateUrl, isLoggedIn } = this.props;
        // console.log('new props');
        // if URL has been updated by hand, reparse and store
        if ((nextProps.location.pathname !== location.pathname) && (lastSearchTime === nextProps.lastSearchTime)) {
          this.setState({ queryInStore: false }); // show spinner while parsing and loading query
          // console.log('  url change');
          this.updateQueriesFromLocation(location);
        // if we don't have all the data in the store yet
        } else if (this.state.queryInStore === false) {   // make sure to only do this once
          // console.log('  waiting for media info from server');
          // mark the whole thing as ready once any sources and collections have been set
          if (this.isAllMediaDetailsReady()) {
            // console.log('  got media info from server, ready!');
            this.setState({ queryInStore: true });  // mark that the parsing process has finished
          }
          if (nextProps.queries.filter(q => q.sources.length > 0).length === 0 && nextProps.queries.filter(q => q.collections.length > 0).length === 0) {
            this.setState({ queryInStore: true });
            updateUrl(nextProps.queries, isLoggedIn);
          }
        } else if (lastSearchTime !== nextProps.lastSearchTime) {
          updateUrl(nextProps.queries, isLoggedIn);
        } else {
          // console.log('  other change');
        }
      }
      updateQueriesFromLocation(location, autoName) {
        // regular searches are in a queryParam, but samples by id are part of the path
        const url = location.pathname;
        const lastPathPart = url.slice(url.lastIndexOf('/') + 1, url.length);
        const sampleNumber = parseInt(lastPathPart, 10);
        if (!isNaN(sampleNumber)) {
          this.updateQueriesFromSampleId(sampleNumber);
        } else {
          // this is a crazy fix to make embedded quotes work by forcing us to escape them all... partially because
          // react-router decided to decode url components, partially because the JSON parser isn't that clever
          const text = location.query.q;
          const pattern = /:"([^,]*)"[,}]/g;  // gotta end with , or } here to support demo case (})
          let match = pattern.exec(text);
          let cleanedText = '';
          let lastSpot = 0;
          while (match != null) {
            const matchText = text.substring(match.index + 2, pattern.lastIndex - 2);
            const cleanedMatch = matchText.replace(/"/g, '\\"');
            cleanedText += `${text.substring(lastSpot, match.index)}:"${cleanedMatch}`;
            lastSpot = pattern.lastIndex - 2;
            match = pattern.exec(text);
          }
          cleanedText += text.substring(lastSpot, text.length);
          // now that we have a relatively clean url, lets use it!
          this.updateQueriesFromString(cleanedText, autoName);
        }
      }
      updateQueriesFromSampleId(sampleNumber) {
        const { saveQueriesFromParsedUrl, samples, isLoggedIn } = this.props;
        const queriesFromUrl = samples[sampleNumber].queries;
        // push the queries in to the store
        saveQueriesFromParsedUrl(queriesFromUrl, isLoggedIn);
      }
      updateQueriesFromString(queryAsJsonStr, autoNaming) {
        const { addAppNotice, saveQueriesFromParsedUrl, isLoggedIn } = this.props;
        const { formatMessage } = this.props.intl;
        let queriesFromUrl;

        try {
          queriesFromUrl = decodeQueryParamString(decodeURIComponent(queryAsJsonStr));
        } catch (f) {
          addAppNotice({ level: LEVEL_ERROR, message: formatMessage(localMessages.errorInURLParams) });
          return;
        }

        let extraDefaults = {};
        // add in an index, label, and color if they are not there
        if (!isLoggedIn) {  // and demo mode needs some extra stuff too
          const dateObj = getDateRange(PAST_MONTH);
          extraDefaults = {
            sources: [],
            collections: DEFAULT_COLLECTION_OBJECT_ARRAY,
            startDate: solrFormat(dateObj.start),
            endDate: solrFormat(dateObj.end),
          };
        } else {
          extraDefaults = { autoNaming };
        }
        queriesFromUrl = queriesFromUrl.map((query, index) => ({
          ...query, // let anything on URL override label and color
          label: notEmptyString(query.label) ? query.label : autoMagicQueryLabel(query),
          // remember demo queries won't have sources or collections on the URL
          sources: query.sources ? query.sources.map(s => ({ id: s, media_id: s })) : undefined,
          collections: query.collections ? query.collections.map(s => ({ id: s, tags_id: s })) : undefined,
          q: query.q,
          color: query.color ? query.color : schemeCategory10[index % 10],
          index,  // redo index to be zero-based on reload of query
          ...extraDefaults, // for demo mode
        }));
        // push the queries in to the store
        saveQueriesFromParsedUrl(queriesFromUrl, isLoggedIn);
      }
      isAllMediaDetailsReady() {
        // we will only render the wrapped component once all the details of the sources and collections
        // have been fetched from the server and put in the right place on each query
        const { queries } = this.props;
        if (queries.length === 0) return false; // need to bail if no queries (ie. first page mount)
        const queryCollectionStatus = queries.map(q => q.collections.length === 0 ||
          q.collections.reduce((combined, c) => combined && c.tag_sets_id !== undefined, true));
        const collectionsAreReady = queryCollectionStatus.reduce((combined, q) => combined && q, true);
        const querySourceStatus = queries.map(q => q.sources.length === 0 ||
          q.sources.reduce((combined, s) => combined && s.name !== undefined, true));
        const sourcesAreReady = querySourceStatus.reduce((combined, q) => combined && q, true);
        return collectionsAreReady && sourcesAreReady;
      }
      render() {
        let content;
        if (this.state.queryInStore) {
          content = <ChildComponent {...this.props} />;
        } else {
          content = <LoadingSpinner />;
        }
        return (
          <div className="serializable-query">
            {content}
          </div>
        );
      }
    }

    UrlBasedQueryContainer.propTypes = {
      intl: PropTypes.object.isRequired,
      location: PropTypes.object,
      // from store
      isLoggedIn: PropTypes.bool.isRequired,
      fetchStatus: PropTypes.string.isRequired,
      samples: PropTypes.array,
      queries: PropTypes.array,
      lastSearchTime: PropTypes.number,
      // from dispatch
      saveQueriesFromParsedUrl: PropTypes.func.isRequired,
      addAppNotice: PropTypes.func.isRequired,
      updateUrl: PropTypes.func.isRequired,
    };

    const mapStateToProps = state => ({
      isLoggedIn: state.user.isLoggedIn,
      fetchStatus: state.explorer.samples.fetchStatus,
      samples: state.explorer.samples.list,
      queries: state.explorer.queries.queries,
      lastSearchTime: state.explorer.lastSearchTime.time,
    });

    // push any updates (including selected) into queries in state, will trigger async load in sub sections
    const mapDispatchToProps = dispatch => ({
      addAppNotice: (info) => {
        dispatch(addNotice(info));
      },
      // handles demo mode by allowing you to pass in extraDefaults
      saveQueriesFromParsedUrl: (queriesToUse, isLoggedIn) => {
        dispatch(selectBySearchParams(queriesToUse)); // load query data into the store
        // lookup ancillary data eg collection and source info for display purposes in QueryForm
        queriesToUse.forEach((q) => {
          const queryInfo = {
            ...q,
          };
          const sourceDetailsAction = isLoggedIn ? fetchQuerySourcesByIds : demoQuerySourcesByIds;
          if (q.sources && q.sources.length > 0) {
            queryInfo.sources = q.sources.map(src => src.media_id || src.id || src); // the latter in case of sample search
            dispatch(sourceDetailsAction(queryInfo))
            .then((results) => {
              queryInfo.sources = results;
              dispatch(updateQuerySourceLookupInfo(queryInfo)); // updates the query and the selected query
            });
          }
          const collectionDetailsAction = isLoggedIn ? fetchQueryCollectionsByIds : demoQueryCollectionsByIds;
          if (q.collections && q.collections.length > 0) {
            queryInfo.collections = q.collections.map(coll => coll.tags_id || coll.id || coll); // the latter in case of sample search
            dispatch(collectionDetailsAction(queryInfo))
            .then((results) => {
              queryInfo.collections = results;
              dispatch(updateQueryCollectionLookupInfo(queryInfo)); // updates the query and the selected query
            });
          }
        });
      },
      asyncFetch: () => {
        dispatch(fetchSampleSearches());   // inefficient: we need the sample searches loaded just in case
      },
      updateUrl: (queries, isLoggedIn) => {
        const unDeletedQueries = queries.filter(q => q.deleted !== true);
        const nonEmptyQueries = unDeletedQueries.filter(q => q.q !== undefined && q.q !== '');
        if (!isLoggedIn) {
          const urlParamString = nonEmptyQueries.map((q, idx) => `{"index":${idx},"q":"${encodeURIComponent(q.q)}","color":"${encodeURIComponent(q.color)}"}`);
          dispatch(push({ pathname: '/queries/demo/search', search: `?q=[${urlParamString}]` }));
        } else {
          const search = generateQueryParamString(queries.map(q => ({
            label: q.label,
            q: q.q,
            color: q.color,
            startDate: q.startDate,
            endDate: q.endDate,
            sources: q.sources, // de-aggregate media bucket into sources and collections
            collections: q.collections,
          })));
          dispatch(push({ pathname: '/queries/search', search: `?q=${search}` })); // query adds a '?query='
        }
      },
    });

    return injectIntl(
      connect(mapStateToProps, mapDispatchToProps)(
        composeAsyncContainer(
          UrlBasedQueryContainer
        )
      )
    );
  };
}

export default composeUrlBasedQueryContainer;
<|endoftext|>


<commit_before>openerp.web_kanban_sparkline = function (instance) {

/**
 * Kanban widgets: Sparkline
 *
 */

instance.web_kanban.SparklineBarWidget = instance.web_kanban.AbstractField.extend({
    className: "oe_sparkline_bar",
    start: function() {
        var self = this;
        var title = this.$node.html() || this.field.string;
        setTimeout(function () {
            var value = _.pluck(self.field.value, 'value');
            var tooltips = _.pluck(self.field.value, 'tooltip');
            var suffix = self.options.tooltip_suffix || "";
            var sparkline_options = _.extend({
                    type: 'bar',
                    barWidth: 5,
                    height: '20px',
                    barWidth: 4,
                    barSpacing: 1,
                    barColor: '#96d854',
                    tooltipFormat: '{{offset:offset}} {{value}} ' + suffix,
                    chartRangeMin: 0,
                    tooltipValueLookups: {
                        'offset': tooltips
                    }
                }, self.options);
            self.$el.sparkline(value, sparkline_options);
            self.$el.tipsy({'delayIn': self.options.delayIn || 0, 'html': true, 'title': function(){return title}, 'gravity': 'n'});
        }, 0);
    },
});

instance.web_kanban.fields_registry.add("sparkline_bar", "instance.web_kanban.SparklineBarWidget");

}
<commit_msg>[MERGE] merge from trunk<commit_after>openerp.web_kanban_sparkline = function (instance) {

/**
 * Kanban widgets: Sparkline
 *
 */

instance.web_kanban.SparklineBarWidget = instance.web_kanban.AbstractField.extend({
    className: "oe_sparkline_bar",
    start: function() {
        var self = this;
        var title = this.$node.html() || this.field.string;
        setTimeout(function () {
            var value = _.pluck(self.field.value, 'value');
            var tooltips = _.pluck(self.field.value, 'tooltip');
            var suffix = self.options.tooltip_suffix || "";
            var tooltipFormat = self.options.type == 'tristate' && '{{offset:offset}}' + suffix || '{{offset:offset}} {{value:value}}' + suffix
            var sparkline_options = _.extend({
                    type: 'bar',
                    barWidth: 5,
                    height: '20px',
                    barWidth: 4,
                    barSpacing: 1,
                    barColor: '#96d854',
                    tooltipFormat: tooltipFormat,
                    chartRangeMin: 0,
                    tooltipValueLookups: {
                        'offset': tooltips
                    }
                }, self.options);
            self.$el.sparkline(value, sparkline_options);
            self.$el.tipsy({'delayIn': self.options.delayIn || 0, 'html': true, 'title': function(){return title}, 'gravity': 'n'});
        }, 0);
    },
});

instance.web_kanban.fields_registry.add("sparkline_bar", "instance.web_kanban.SparklineBarWidget");

}
<|endoftext|>


<commit_before>(function()
{
  /* extends window.templates interface */

  this.inspected_js_object = function(model, show_root, path){};
  this.inspected_js_prototype = function(model, path, index){};

  /* constants */

  const
  // sub message ObjectInfo
  VALUE = 0,
  PROPERTY_LIST = 1,
  // sub message ObjectValue
  OBJECT_ID = 0,
  CLASS_NAME = 4,
  // sub message Property
  NAME = 0,
  PROPERTY_TYPE = 1,
  PROPERTY_VALUE = 2,
  OBJECT_VALUE = 3,
  // added fields
  MAX_VALUE_LENGTH = 30,
  STYLE_EXPANDED = "style='background-position: 0px -11px' ",
  IS_EDITABLE = 5,
  UID = 6,
  TOOLTIP_NAME = cls.JSInspectionTooltip.tooltip_name;

  /* private */

  var _has_own_prop = Object.prototype.hasOwnProperty;

  var _is_unfolded = function(tree, index, name, collapsed_protos)
  {
    if (!index) // the properties of the object itself
      return true;

    if (!_has_own_prop.call(tree.protos, index.toString()))
      return collapsed_protos[0] == '*'
           ? false
           :  (collapsed_protos.indexOf(name) == -1);

    return Boolean(tree.protos[index]);
  }

  var _pretty_print_object = function(model,
                                      tree,
                                      obj_id,
                                      collapsed_protos,
                                      filter,
                                      searchterm)
  {
    var ret = [];
    var data = model.get_data(obj_id);
    if (data)
    {
      for (var proto = null, i = 0; proto = data[i]; i++)
      {
        ret.extend(_pretty_print_proto(model,
                                       tree,
                                       proto,
                                       i,
                                       collapsed_protos,
                                       filter,
                                       searchterm,
                                       obj_id));
      }
      if (ret.length)
      {
        ret.unshift("<examine-objects data-id='" + model.id + "' data-menu='object-inspection-key'>");
        ret.push("</examine-objects>");
      }
    };
    return ret;
  };

  var _pretty_print_proto = function(model,
                                     tree,
                                     proto,
                                     index,
                                     collapsed_protos,
                                     filter, //name, index
                                     searchterm,
                                     parent_obj_id)
  {
    var ret = [];
    var name = proto[VALUE][CLASS_NAME] || "";
    var is_unfolded = _is_unfolded(tree, index, name, collapsed_protos);
    var expanded_props = is_unfolded &&
                         _pretty_print_properties(model,
                                                  tree.protos && tree.protos[index] || {},
                                                  proto[PROPERTY_LIST] || [],
                                                  collapsed_protos,
                                                  filter,
                                                  name,
                                                  index,
                                                  searchterm,
                                                  parent_obj_id);
    var has_match = !searchterm || name.toLowerCase().contains(searchterm);
    if (has_match || expanded_props.length)
    {
      ret.push("
");
      // skip the first object description
      if (index)
      {
        ret.push(
          "
" +
            "<input type='button' " +
                   "class='folder-key'" +
                   "proto-index='" + index + "' " +
                   "/>",
            "<key>" + name + "</key>",
          "
");
      }
      if (is_unfolded)
      {
        ret.extend(expanded_props);
      }
      ret.push("
");
    }
    return ret;
  };

  var editable = function(prop)
  {
    if (prop[IS_EDITABLE])
    {
      return " data-prop-uid='" + prop[UID] + "' ";
    }
    return "";
  };

  var _pretty_print_properties = function(model,
                                          tree,
                                          property_list,
                                          collapsed_protos,
                                          filter,
                                          name,
                                          index,
                                          searchterm,
                                          parent_obj_id)
  {
    var
    ret = [],
    esc_name = '',
    value = '',
    type = '',
    short_val = '',
    obj_id = 0,
    filter_obj = !index && filter && filter[name],
    has_match = false,
    expanded_prop = null;

    for (var prop = null, i = 0; prop = property_list[i]; i++)
    {
      value = prop[PROPERTY_VALUE];
      esc_name = helpers.escapeAttributeHtml(prop[NAME]);
      switch (type = prop[PROPERTY_TYPE])
      {
        case "number":
        case "boolean":
        case "error":
        {
          if (!searchterm ||
              prop[NAME].toLowerCase().contains(searchterm) ||
              value.toLowerCase().contains(searchterm))
          {
            ret.push(
              "<item>" +
                "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                  editable(prop) + ">" +
                  esc_name +
                "</key>\u00A0" +
                "<value class='" + type + "'>" + value + "</value>" +
              "</item>"
            );
          }
          break;
        }
        case "script_getter":
        {
          if (!searchterm ||
              prop[NAME].toLowerCase().contains(searchterm) ||
              value.toLowerCase().contains(searchterm))
          {
            ret.push(
              "<item obj-id='" + parent_obj_id + "'>" +
                "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                  editable(prop) + ">" +
                  esc_name +
                "</key>\u00A0" +
                "<value class='" + type + "' handler='get-getter-value'>" +
                  "getter</value>" +
              "</item>"
            );
          }
          break;
        }
        case "string":
        {
          if (filter_obj &&
              (prop[NAME] in filter_obj) &&
              filter_obj[prop[NAME]].type == "string" &&
              filter_obj[prop[NAME]].value === value)
          {
            continue;
          }
          short_val = value.length > MAX_VALUE_LENGTH ?
                        value.slice(0, MAX_VALUE_LENGTH) + '…' : '';
          value = helpers.escapeAttributeHtml(value);
          if (short_val)
          {
            if (!searchterm ||
                prop[NAME].toLowerCase().contains(searchterm) ||
                short_val.toLowerCase().contains(searchterm))
            {
              ret.push(
                "<item>" +
                  "<input type='button' handler='expand-value' class='folder-key'/>" +
                  "<key data-spec='dom#" + esc_name + "'" +
                    editable(prop) + ">" + esc_name + "</key>\u00A0" +
                  "<value class='" + type + "' data-value='\"" + value + "\"'>" +
                    "\"" + helpers.escapeTextHtml(short_val) + "\"" +
                  "</value>" +
                "</item>"
              );
            }
          }
          else
          {
            if (!searchterm ||
                prop[NAME].toLowerCase().contains(searchterm) ||
                value.toLowerCase().contains(searchterm))
            {
              ret.push(
                "<item>" +
                  "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                    editable(prop) + ">" +
                    esc_name +
                  "</key>\u00A0" +
                  "<value class='" + type + "'>\"" + value + "\"</value>" +
                "</item>"
              );
            }
          }
          break;
        }
        case "null":
          if (filter_obj &&
              (prop[NAME] in filter_obj) &&
              filter_obj[prop[NAME]].type == "null")
            continue;
        case "undefined":
        {
          if (!searchterm ||
              prop[NAME].toLowerCase().contains(searchterm) ||
              type.toLowerCase().contains(searchterm))
          {
            ret.push(
              "<item>" +
                "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                  editable(prop) + ">" +
                  esc_name +
                "</key> " +
                "<value class='" + type + "'>" + type + "</value>" +
              "</item>"
            );
          }
          break;
        }
        case "object":
        {
          obj_id = prop[OBJECT_VALUE][OBJECT_ID];
          expanded_prop = _has_own_prop.call(tree, prop[NAME]) &&
                          _pretty_print_object(model,
                                               tree[prop[NAME]],
                                               obj_id,
                                               collapsed_protos,
                                               filter,
                                               searchterm);
          value = prop[OBJECT_VALUE][CLASS_NAME];
          has_match = !searchterm ||
                      prop[NAME].toLowerCase().contains(searchterm) ||
                      value.toLowerCase().contains(searchterm);
          if (has_match || expanded_prop.length)
          {
            ret.push(
              "<item obj-id='" + obj_id + "'>" +
              "<input " +
                "type='button' " +
                "handler='examine-object'  " +
                "class='folder-key" + (has_match ? "" : " no-match") + "' "
            );
            // 'in' is true for all non enumarables
            if (_has_own_prop.call(tree, prop[NAME]) && tree[prop[NAME]])
              ret.push(STYLE_EXPANDED);
            ret.push(
              "/>" +
              "<key " + (has_match ? "" : " class='no-match'") +
                        "data-spec='dom#" + esc_name + "'" + editable(prop) +
                        ">" + esc_name + "</key> " +
              "<value class='object" + (has_match ? "" : " no-match") + "' " +
                     "data-spec='dom#" + value + "' " +
                     "data-tooltip='" + TOOLTIP_NAME + "' >" + value + "</value>"
            );

            if (_has_own_prop.call(tree, prop[NAME]))
              ret.extend(expanded_prop);

            ret.push("</item>");
          }
          break;
        }
      }
    }
    return ret;
  };

  /* implementation */

  this.inspected_js_object = function(model, show_root, path, searchterm)
  {
    searchterm = searchterm && searchterm.toLowerCase();
    var tree = model.get_expanded_tree(show_root, path);
    var setting = window.settings.inspection;
    var collapsed_protos = setting.get('collapsed-prototypes');
    var filter = !setting.get('show-default-nulls-and-empty-strings') &&
                 window.inspectionfilters;
    var ret = _pretty_print_object(model,
                                   tree,
                                   tree.object_id,
                                   collapsed_protos,
                                   filter,
                                   searchterm).join('');
    if (model.scope_list && model.scope_list.length && !path)
      ret += this.inspected_js_scope_chain(model, searchterm);
    return ret;
  }

  this.inspected_js_prototype = function(model, path, index, name)
  {
    var OBJ_ID = 1;
    var tree = model.get_expanded_tree(null, path);
    var data = tree && model.get_data(tree.object_id);
    var setting = window.settings.inspection;
    var collapsed_protos = setting.get('collapsed-prototypes');
    var filter = !setting.get('show-default-nulls-and-empty-strings') &&
                 window.inspectionfilters;
    return data ? _pretty_print_proto(model,
                                      tree,
                                      data[index],
                                      index,
                                      collapsed_protos,
                                      filter,
                                      null,
                                      path.last[OBJ_ID]).join('') : '';
  }

  this.inspected_js_scope_chain = function(model, searchterm)
  {
    var ret = [];
    var name = ui_strings.S_LABEL_SCOPE_CHAIN;
    var has_match = !searchterm || name.toLowerCase().contains(searchterm);
    if (model.scope_list_models)
    {
      for (var i = 0, scope, scope_props; scope = model.scope_list_models[i]; i++)
      {
        if (scope_props = this.inspected_js_object(scope, true, null, searchterm))
        {
          ret.push(scope_props);
        }
      }
    }
    if (has_match || ret.length)
    {
      ret.unshift(
        "
" +
          "" +
            "<input type='button' " +
              "class='" + (model.scope_list_models ? "unfolded" : "") + "' >" +
            name +
          ""
      );
      ret.push("
");
    };
    return ret.join('');
  }

}).apply(window.templates || (window.templates = {}));
<commit_msg>Synced with mainline.<commit_after>(function()
{
  /* extends window.templates interface */

  this.inspected_js_object = function(model, show_root, path){};
  this.inspected_js_prototype = function(model, path, index){};

  /* constants */

  const
  // sub message ObjectInfo
  VALUE = 0,
  PROPERTY_LIST = 1,
  // sub message ObjectValue
  OBJECT_ID = 0,
  CLASS_NAME = 4,
  // sub message Property
  NAME = 0,
  PROPERTY_TYPE = 1,
  PROPERTY_VALUE = 2,
  OBJECT_VALUE = 3,
  // added fields
  MAX_VALUE_LENGTH = 30,
  STYLE_EXPANDED = "style='background-position: 0px -11px' ",
  IS_EDITABLE = 5,
  UID = 6,
  TOOLTIP_NAME = cls.JSInspectionTooltip.tooltip_name;

  /* private */

  var _has_own_prop = Object.prototype.hasOwnProperty;

  var _is_unfolded = function(tree, index, name, collapsed_protos)
  {
    if (!index) // the properties of the object itself
      return true;

    if (!_has_own_prop.call(tree.protos, index.toString()))
      return collapsed_protos[0] == '*'
           ? false
           :  (collapsed_protos.indexOf(name) == -1);

    return Boolean(tree.protos[index]);
  }

  var _pretty_print_object = function(model,
                                      tree,
                                      obj_id,
                                      collapsed_protos,
                                      filter,
                                      searchterm)
  {
    var ret = [];
    var data = model.get_data(obj_id);
    if (data)
    {
      for (var proto = null, i = 0; proto = data[i]; i++)
      {
        ret.extend(_pretty_print_proto(model,
                                       tree,
                                       proto,
                                       i,
                                       collapsed_protos,
                                       filter,
                                       searchterm,
                                       obj_id));
      }
      if (ret.length)
      {
        ret.unshift("<examine-objects data-id='" + model.id + "' data-menu='object-inspection-key'>");
        ret.push("</examine-objects>");
      }
    };
    return ret;
  };

  var _pretty_print_proto = function(model,
                                     tree,
                                     proto,
                                     index,
                                     collapsed_protos,
                                     filter, //name, index
                                     searchterm,
                                     parent_obj_id)
  {
    var ret = [];
    var name = proto[VALUE][CLASS_NAME] || "";
    var is_unfolded = _is_unfolded(tree, index, name, collapsed_protos);
    var expanded_props = is_unfolded &&
                         _pretty_print_properties(model,
                                                  tree.protos && tree.protos[index] || {},
                                                  proto[PROPERTY_LIST] || [],
                                                  collapsed_protos,
                                                  filter,
                                                  name,
                                                  index,
                                                  searchterm,
                                                  parent_obj_id);
    var has_match = !searchterm || name.toLowerCase().contains(searchterm);
    if (has_match || expanded_props.length)
    {
      ret.push("
");
      // skip the first object description
      if (index)
      {
        ret.push(
          "
" +
            "<input type='button' " +
                   "class='folder-key' " +
                   "proto-index='" + index + "' " +
                   "/>",
            "<key>" + name + "</key>",
          "
");
      }
      if (is_unfolded)
      {
        ret.extend(expanded_props);
      }
      ret.push("
");
    }
    return ret;
  };

  var editable = function(prop)
  {
    if (prop[IS_EDITABLE])
    {
      return " data-prop-uid='" + prop[UID] + "' ";
    }
    return "";
  };

  var _pretty_print_properties = function(model,
                                          tree,
                                          property_list,
                                          collapsed_protos,
                                          filter,
                                          name,
                                          index,
                                          searchterm,
                                          parent_obj_id)
  {
    var
    ret = [],
    esc_name = '',
    value = '',
    type = '',
    short_val = '',
    obj_id = 0,
    filter_obj = !index && filter && filter[name],
    has_match = false,
    expanded_prop = null;

    for (var prop = null, i = 0; prop = property_list[i]; i++)
    {
      value = prop[PROPERTY_VALUE];
      esc_name = helpers.escapeAttributeHtml(prop[NAME]);
      switch (type = prop[PROPERTY_TYPE])
      {
        case "number":
        case "boolean":
        case "error":
        {
          if (!searchterm ||
              prop[NAME].toLowerCase().contains(searchterm) ||
              value.toLowerCase().contains(searchterm))
          {
            ret.push(
              "<item>" +
                "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                  editable(prop) + ">" +
                  esc_name +
                "</key>\u00A0" +
                "<value class='" + type + "'>" + value + "</value>" +
              "</item>"
            );
          }
          break;
        }
        case "script_getter":
        {
          if (!searchterm ||
              prop[NAME].toLowerCase().contains(searchterm) ||
              value.toLowerCase().contains(searchterm))
          {
            ret.push(
              "<item obj-id='" + parent_obj_id + "'>" +
                "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                  editable(prop) + ">" +
                  esc_name +
                "</key>\u00A0" +
                "<value class='" + type + "' handler='get-getter-value'>" +
                  "getter</value>" +
              "</item>"
            );
          }
          break;
        }
        case "string":
        {
          if (filter_obj &&
              (prop[NAME] in filter_obj) &&
              filter_obj[prop[NAME]].type == "string" &&
              filter_obj[prop[NAME]].value === value)
          {
            continue;
          }
          short_val = value.length > MAX_VALUE_LENGTH ?
                        value.slice(0, MAX_VALUE_LENGTH) + '…' : '';
          value = helpers.escapeAttributeHtml(value);
          if (short_val)
          {
            if (!searchterm ||
                prop[NAME].toLowerCase().contains(searchterm) ||
                short_val.toLowerCase().contains(searchterm))
            {
              ret.push(
                "<item>" +
                  "<input type='button' handler='expand-value' class='folder-key'/>" +
                  "<key data-spec='dom#" + esc_name + "'" +
                    editable(prop) + ">" + esc_name + "</key>\u00A0" +
                  "<value class='" + type + "' data-value='\"" + value + "\"'>" +
                    "\"" + helpers.escapeTextHtml(short_val) + "\"" +
                  "</value>" +
                "</item>"
              );
            }
          }
          else
          {
            if (!searchterm ||
                prop[NAME].toLowerCase().contains(searchterm) ||
                value.toLowerCase().contains(searchterm))
            {
              ret.push(
                "<item>" +
                  "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                    editable(prop) + ">" +
                    esc_name +
                  "</key>\u00A0" +
                  "<value class='" + type + "'>\"" + value + "\"</value>" +
                "</item>"
              );
            }
          }
          break;
        }
        case "null":
          if (filter_obj &&
              (prop[NAME] in filter_obj) &&
              filter_obj[prop[NAME]].type == "null")
            continue;
        case "undefined":
        {
          if (!searchterm ||
              prop[NAME].toLowerCase().contains(searchterm) ||
              type.toLowerCase().contains(searchterm))
          {
            ret.push(
              "<item>" +
                "<key class='no-expander' data-spec='dom#" + esc_name + "'" +
                  editable(prop) + ">" +
                  esc_name +
                "</key> " +
                "<value class='" + type + "'>" + type + "</value>" +
              "</item>"
            );
          }
          break;
        }
        case "object":
        {
          obj_id = prop[OBJECT_VALUE][OBJECT_ID];
          expanded_prop = _has_own_prop.call(tree, prop[NAME]) &&
                          _pretty_print_object(model,
                                               tree[prop[NAME]],
                                               obj_id,
                                               collapsed_protos,
                                               filter,
                                               searchterm);
          value = prop[OBJECT_VALUE][CLASS_NAME];
          has_match = !searchterm ||
                      prop[NAME].toLowerCase().contains(searchterm) ||
                      value.toLowerCase().contains(searchterm);
          if (has_match || expanded_prop.length)
          {
            ret.push(
              "<item obj-id='" + obj_id + "'>" +
              "<input " +
                "type='button' " +
                "handler='examine-object'  " +
                "class='folder-key" + (has_match ? "" : " no-match") + "' "
            );
            // 'in' is true for all non enumarables
            if (_has_own_prop.call(tree, prop[NAME]) && tree[prop[NAME]])
              ret.push(STYLE_EXPANDED);
            ret.push(
              "/>" +
              "<key " + (has_match ? "" : " class='no-match'") +
                        "data-spec='dom#" + esc_name + "'" + editable(prop) +
                        ">" + esc_name + "</key> " +
              "<value class='object" + (has_match ? "" : " no-match") + "' " +
                     "data-spec='dom#" + value + "' " +
                     "data-tooltip='" + TOOLTIP_NAME + "' >" + value + "</value>"
            );

            if (_has_own_prop.call(tree, prop[NAME]))
              ret.extend(expanded_prop);

            ret.push("</item>");
          }
          break;
        }
      }
    }
    return ret;
  };

  /* implementation */

  this.inspected_js_object = function(model, show_root, path, searchterm)
  {
    searchterm = searchterm && searchterm.toLowerCase();
    var tree = model.get_expanded_tree(show_root, path);
    var setting = window.settings.inspection;
    var collapsed_protos = setting.get('collapsed-prototypes');
    var filter = !setting.get('show-default-nulls-and-empty-strings') &&
                 window.inspectionfilters;
    var ret = _pretty_print_object(model,
                                   tree,
                                   tree.object_id,
                                   collapsed_protos,
                                   filter,
                                   searchterm).join('');
    if (model.scope_list && model.scope_list.length && !path)
      ret += this.inspected_js_scope_chain(model, searchterm);
    return ret;
  }

  this.inspected_js_prototype = function(model, path, index, name)
  {
    var OBJ_ID = 1;
    var tree = model.get_expanded_tree(null, path);
    var data = tree && model.get_data(tree.object_id);
    var setting = window.settings.inspection;
    var collapsed_protos = setting.get('collapsed-prototypes');
    var filter = !setting.get('show-default-nulls-and-empty-strings') &&
                 window.inspectionfilters;
    return data ? _pretty_print_proto(model,
                                      tree,
                                      data[index],
                                      index,
                                      collapsed_protos,
                                      filter,
                                      null,
                                      path.last[OBJ_ID]).join('') : '';
  }

  this.inspected_js_scope_chain = function(model, searchterm)
  {
    var ret = [];
    var name = ui_strings.S_LABEL_SCOPE_CHAIN;
    var has_match = !searchterm || name.toLowerCase().contains(searchterm);
    if (model.scope_list_models)
    {
      for (var i = 0, scope, scope_props; scope = model.scope_list_models[i]; i++)
      {
        if (scope_props = this.inspected_js_object(scope, true, null, searchterm))
        {
          ret.push(scope_props);
        }
      }
    }
    if (has_match || ret.length)
    {
      ret.unshift(
        "
" +
          "" +
            "<input type='button' " +
              "class='" + (model.scope_list_models ? "unfolded" : "") + "' >" +
            name +
          ""
      );
      ret.push("
");
    };
    return ret.join('');
  }

}).apply(window.templates || (window.templates = {}));
<|endoftext|>


<commit_before>/*!
 * jQuery UI Effects Drop @VERSION
 * http://jqueryui.com
 *
 * Copyright 2012 jQuery Foundation and other contributors
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Drop
 *
 * Depends:
 *	jquery.ui.effect.js
 */
(function( $, undefined ) {

$.effects.effect.drop = function( o, done ) {

	var el = $( this ),
		props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
		mode = $.effects.setMode( el, o.mode || "hide" ),
		show = mode === "show",
		direction = o.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
		animation = {
			opacity: show ? 1 : 0
		},
		distance;

	// Adjust
	$.effects.save( el, props );
	el.show();
	$.effects.createWrapper( el );

	distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]({ margin: true }) / 2;

	if ( show ) {
		el
			.css( "opacity", 0 )
			.css( ref, motion === "pos" ? -distance : distance );
	}

	// Animation
	animation[ ref ] = ( show ?
		( motion === "pos" ? "+=" : "-=" ) :
		( motion === "pos" ? "-=" : "+=" ) ) +
		distance;

	// Animate
	el.animate( animation, {
		queue: false,
		duration: o.duration,
		easing: o.easing,
		complete: function() {
			if ( mode === "hide" ) {
				el.hide();
			}
			$.effects.restore( el, props );
			$.effects.removeWrapper( el );
			done();
		}
	});
};

})(jQuery);
<commit_msg>Effects: Fixing call to outerHeight/Width in drop effect for compat with 1.8 core<commit_after>/*!
 * jQuery UI Effects Drop @VERSION
 * http://jqueryui.com
 *
 * Copyright 2012 jQuery Foundation and other contributors
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Drop
 *
 * Depends:
 *	jquery.ui.effect.js
 */
(function( $, undefined ) {

$.effects.effect.drop = function( o, done ) {

	var el = $( this ),
		props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
		mode = $.effects.setMode( el, o.mode || "hide" ),
		show = mode === "show",
		direction = o.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
		animation = {
			opacity: show ? 1 : 0
		},
		distance;

	// Adjust
	$.effects.save( el, props );
	el.show();
	$.effects.createWrapper( el );

	distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;

	if ( show ) {
		el
			.css( "opacity", 0 )
			.css( ref, motion === "pos" ? -distance : distance );
	}

	// Animation
	animation[ ref ] = ( show ?
		( motion === "pos" ? "+=" : "-=" ) :
		( motion === "pos" ? "-=" : "+=" ) ) +
		distance;

	// Animate
	el.animate( animation, {
		queue: false,
		duration: o.duration,
		easing: o.easing,
		complete: function() {
			if ( mode === "hide" ) {
				el.hide();
			}
			$.effects.restore( el, props );
			$.effects.removeWrapper( el );
			done();
		}
	});
};

})(jQuery);
<|endoftext|>