<commit_before>import h from 'virtual-dom/h'
import diff from 'virtual-dom/diff'
import patch from 'virtual-dom/patch'
import createElement from 'virtual-dom/create-element'

let debug = false;

class Thunk {
  constructor(renderFn, state, shouldUpdate, name) {
    this.type = 'Thunk';
    this.renderFn = renderFn;
    this.state = state;
    this.shouldUpdate = shouldUpdate;
    this.name = name;
  }

  render(previous) {
    var previousState = previous ? previous.state : null;
    if (this.state === undefined && previousState === undefined && previous.vnode) {
      return previous.vnode;
    }
    if (this.shouldUpdate(this.state, previousState)) {
      if (debug) {
        console.log('call render of ', this.name);
      }
      return this.renderFn(this.state);
    }
    return previous.vnode;
  }
}

export class Component {
  constructor(state) {
    this.thunk = this.newThunk(state);
    this._skip_keys = {};
    let keys = this.skipKeys();
    for (let i = 0; i < keys.length; i++) {
      this._skip_keys[keys[i]] = true;
    }
  }

  skipKeys() {
    return [];
  }

  newThunk(state) {
    return new Thunk((state) => {
      let Hook = function(){}
      Hook.prototype.hook = (element) => {
        this.element = element;
        this.elementChanged(element);
      };
      let vnode = h('v3-' + this.constructor.name, {
        'element-changed': new Hook(),
      }, [this.render(state)]);
      return vnode;
    }, state, this.shouldUpdate.bind(this), this.constructor.name);
  }

  // abstract
  render(state) {
    return h();
  }

  bind(parent) {
    this.element = createElement(this.thunk);
    parent.appendChild(this.element);
  }

  setState(newState) {
    let newThunk = this.newThunk(newState);
    let patches = diff(this.thunk, newThunk);
    this.element = patch(this.element, patches);
    this.thunk = newThunk;
  }

  setStore(store) {
    store.setComponent(this);
  }

  // abstract
  elementChanged(element) {
    if (debug) {
      console.log('element changed', this.constructor.name);
    }
  }

  boundedEqual(a, b, n) {
    if (a === b) {
      return true;
    }
    if (n == 0) {
      return a === b;
    }
    let aType = typeof a;
    let bType = typeof b;
    if (aType != bType) {
      return false;
    }
    switch (aType) {
    case 'object':
      let aKeys = Object.keys(a);
      let bKeys = Object.keys(b);
      if (aKeys.length != bKeys.length) {
        return false;
      }
      let len = aKeys.length;
      for (let i = 0; i < len; i++) {
        let key = aKeys[i];
        if (!this.boundedEqual(a[key], b[key], n - 1)) {
          if (key.slice(0, 1) == 'on' && typeof a[key] == 'function' && typeof b[key] == 'function') {
            continue; // skip event handlers
          }
          return false;
        }
      }
      return true;
    default:
      return this.boundedEqual(a, b, n - 1);
    }
  }

  // abstract
  shouldUpdate(state, previousState) {
    if (previousState === undefined && state === undefined) {
      // no state
      return true;
    }
    if (!previousState || !state) {
      return true;
    }
    let keys = Object.keys(state);
    let prevKeys = Object.keys(previousState);
    if (keys.length != prevKeys.length) {
      return true;
    }
    if (state.style) {
      state.state = computed(state.style);
    }
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];
      if (this._skip_keys[key]) {
        continue;
      }
      let value = state[key];
      let prevValue = previousState[key];
      if (value !== prevValue) {
        // skip event handler
        if (key.slice(0, 1) == 'on' && typeof value == 'function' && typeof prevValue == 'function') {
          continue;
        }
        // skip explicitly specified
        if ((!is_none(value) && value._skip_in_should_update_check)
            || (!is_none(prevValue) && prevValue._skip_in_should_update_check)) {
          continue;
        }
        // do deep compare
        if ((!is_none(value) && value._do_deep_compare)
            || (!is_none(prevValue) && prevValue._do_deep_compare)) {
          if (this.boundedEqual(value, prevValue, -1)) {
            continue
          }
        }
        if (debug) {
          console.log('key changed:', key);
        }
        return true;
      }
    }
    return false;
  }
}

function is_none(o) {
  return o === undefined || o === null;
}

function has_key(o, key) {
  if (is_none(o)) {
    return false;
  }
  return key in o;
}

export function constant(obj) {
  return Object.defineProperty(obj, '_skip_in_should_update_check', {
    __proto__: null,
    value: true,
  });
}

export function computed(obj) {
  return Object.defineProperty(obj, '_do_deep_compare', {
    __proto__: null,
    value: true,
  });
}

export class Store {
  constructor(initState) {
    this.state = initState;
  }

  handle(state, event, data) {
    if (debug) {
      console.log('=state=>', state);
      console.log('=event=>', event, data);
    }
    let newState = state;
    if (typeof event == 'function') {
      let s = event(state, data);
      if (s) {
        newState = s;
      }
    } else if (event === undefined || event === null) {
      console.error('invalid event', data);
    }
    if (debug) {
      console.log('=state=>', newState);
    }
    return newState;
  }

  emit(event, data) {
    this.state = this.handle(this.state, event, data);
    if (this.component) {
      this.component.setState(this.state);
    }
  }

  setComponent(component) {
    this.component = component;
  }
}

export function e(selector, properties, children) {
  switch (typeof selector) {
  case 'string':
    return h(selector, properties, children);
  default:
    return new selector(properties).thunk;
  }
}

export var none = h('div', { style: { display: 'none' } });
export var clear = h('div', { style: { clear: 'both' } });

export let div = (args, subs) => h('div', args, subs);
export let p = (args, subs) => h('p', args, subs);
export let span = (args, subs) => h('span', args, subs);
export let ul = (args, subs) => h('ul', args, subs);
export let li = (args, subs) => h('li', args, subs);
export let form = (args, subs) => h('form', args, subs);
export let label = (args, subs) => h('label', args, subs);
export let input = (args, subs) => h('input', args, subs);
export let select = (args, subs) => h('select', args, subs);
export let option = (args, subs) => h('option', args, subs);
export let img = (args, subs) => h('img', args, subs);
export let button = (args, subs) => h('button', args, subs);

export function merge(a, b) {
  let aType = typeof a;
  let bType = typeof b;
  if (Array.isArray(a)) {
    aType = 'array';
  }
  if (Array.isArray(b)) {
    bType = 'array';
  }
  if (aType == 'object' && bType == 'object') {
    // the new object
    let obj = {};
    if (has_key(b, '>_<')) {
      // wildcard update
      for (let key in a) {
        obj[key] = merge_value(a[key], b['>_<']);
      }
    } else {
      // merge
      for (let key in b) {
        obj[key] = merge_value(a[key], b[key]);
      }
      // copy keys in a but not in b
      for (let key in a) {
        if (has_key(obj, key)) {
          continue
        }
        obj[key] = a[key];
      }
    }
    return obj;
  } else if (aType == 'array' && bType == 'object') {
    // the new object
    let obj = [];
    let wildcard = b['>_<'];
    for (let i = 0; i < a.length; i++) {
      if (has_key(b, i)) {
        obj.push(merge_value(a[i], b[i]));
      } else if (wildcard !== undefined && wildcard !== null) {
        obj.push(merge_value(a[i], wildcard));
      } else {
        obj.push(a[i]);
      }
    }
    return obj;
  } else {
    return b;
  }
}

export function op_insert(elem, index = 0) {
  return Object.defineProperty({
    elem: elem,
    index: index,
  }, '_op_insert', {
    __proto__: null,
    value: true,
  });
}

export function op_remove(index) {
  return Object.defineProperty({
    index: index,
  }, '_op_remove', {
    __proto__: null,
    value: true,
  });
}

export function op_call(cb) {
  return Object.defineProperty({
    cb: cb,
  }, '_op_call', {
    __proto__: null,
    value: true,
  });
}

function merge_value(left, right) {
  if (right._op_insert) {
    if (is_none(left)) {
      left = [];
    }
    return insert(left, right.elem, right.index);
  } else if (right._op_call) {
    return right.cb(left);
  } else if (right._op_remove) {
    return remove(left, right.index);
  }
  return merge(left, right);
}

export function insert(ary, elem, index = 0) {
  if (index < 0) {
    index = ary.length + index + 1;
  }
  return [
    ...ary.slice(0, index),
    elem,
    ...ary.slice(index),
  ];
}

export function remove(ary, index) {
  return [
    ...ary.slice(0, index),
    ...ary.slice(index + 1),
  ];
}
<commit_msg>bug fixes; simplified Store<commit_after>import h from 'virtual-dom/h'
import diff from 'virtual-dom/diff'
import patch from 'virtual-dom/patch'
import createElement from 'virtual-dom/create-element'

let debug = false;

class Thunk {
  constructor(renderFn, state, shouldUpdate, name) {
    this.type = 'Thunk';
    this.renderFn = renderFn;
    this.state = state;
    this.shouldUpdate = shouldUpdate;
    this.name = name;
  }

  render(previous) {
    var previousState = previous ? previous.state : null;
    if (this.state === undefined && previousState === undefined && previous.vnode) {
      return previous.vnode;
    }
    if (this.shouldUpdate(this.state, previousState)) {
      if (debug) {
        console.log('call render of ', this.name);
      }
      return this.renderFn(this.state);
    }
    return previous.vnode;
  }
}

export class Component {
  constructor(state) {
    this.thunk = this.newThunk(state);
    this._skip_keys = {};
    let keys = this.skipKeys();
    for (let i = 0; i < keys.length; i++) {
      this._skip_keys[keys[i]] = true;
    }
  }

  skipKeys() {
    return [];
  }

  newThunk(state) {
    return new Thunk((state) => {
      let Hook = function(){}
      Hook.prototype.hook = (element) => {
        this.element = element;
        this.elementChanged(element);
      };
      let vnode = h('v3-' + this.constructor.name, {
        'element-changed': new Hook(),
      }, [this.render(state)]);
      return vnode;
    }, state, this.shouldUpdate.bind(this), this.constructor.name);
  }

  // abstract
  render(state) {
    return h();
  }

  bind(parent) {
    this.element = createElement(this.thunk);
    parent.appendChild(this.element);
  }

  setState(newState) {
    let newThunk = this.newThunk(newState);
    let patches = diff(this.thunk, newThunk);
    this.element = patch(this.element, patches);
    this.thunk = newThunk;
  }

  setStore(store) {
    store.setComponent(this);
  }

  // abstract
  elementChanged(element) {
    if (debug) {
      console.log('element changed', this.constructor.name);
    }
  }

  boundedEqual(a, b, n) {
    if (a === b) {
      return true;
    }
    if (n <= 0) {
      return a === b;
    }
    let aType = typeof a;
    let bType = typeof b;
    if (aType != bType) {
      return false;
    }
    switch (aType) {
    case 'object':
      let aKeys = Object.keys(a);
      let bKeys = Object.keys(b);
      if (aKeys.length != bKeys.length) {
        return false;
      }
      let len = aKeys.length;
      for (let i = 0; i < len; i++) {
        let key = aKeys[i];
        if (!this.boundedEqual(a[key], b[key], n - 1)) {
          if (key.slice(0, 1) == 'on' && typeof a[key] == 'function' && typeof b[key] == 'function') {
            continue; // skip event handlers
          }
          return false;
        }
      }
      return true;
    default:
      return this.boundedEqual(a, b, n - 1);
    }
  }

  // abstract
  shouldUpdate(state, previousState) {
    if (previousState === undefined && state === undefined) {
      // no state
      return true;
    }
    if (!previousState || !state) {
      return true;
    }
    let keys = Object.keys(state);
    let prevKeys = Object.keys(previousState);
    if (keys.length != prevKeys.length) {
      return true;
    }
    if (state.style) {
      state.state = computed(state.style);
    }
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];
      if (this._skip_keys[key]) {
        continue;
      }
      let value = state[key];
      let prevValue = previousState[key];
      if (value !== prevValue) {
        // skip event handler
        if (key.slice(0, 1) == 'on' && typeof value == 'function' && typeof prevValue == 'function') {
          continue;
        }
        // skip explicitly specified
        if ((!is_none(value) && value._skip_in_should_update_check)
            || (!is_none(prevValue) && prevValue._skip_in_should_update_check)) {
          continue;
        }
        // do deep compare
        if ((!is_none(value) && value._do_deep_compare)
            || (!is_none(prevValue) && prevValue._do_deep_compare)) {
          if (this.boundedEqual(value, prevValue, -1)) {
            continue
          }
        }
        if (debug) {
          console.log('key changed:', key);
        }
        return true;
      }
    }
    return false;
  }
}

function is_none(o) {
  return o === undefined || o === null;
}

function has_key(o, key) {
  if (is_none(o)) {
    return false;
  }
  return key in o;
}

export function constant(obj) {
  return Object.defineProperty(obj, '_skip_in_should_update_check', {
    __proto__: null,
    value: true,
  });
}

export function computed(obj) {
  return Object.defineProperty(obj, '_do_deep_compare', {
    __proto__: null,
    value: true,
  });
}

export class Store {
  constructor(initState) {
    this.state = initState;
  }

  emit(event, ...args) {
    let newState = event(this.state, ...args);
    if (newState !== undefined && newState !== null) {
      this.state = newState;
      if (this.component) {
        this.component.setState(this.state);
      }
    }
  }

  setComponent(component) {
    this.component = component;
  }
}

export function e(selector, properties, children) {
  switch (typeof selector) {
  case 'string':
    return h(selector, properties, children);
  default:
    return new selector(properties).thunk;
  }
}

export var none = h('div', { style: { display: 'none' } });
export var clear = h('div', { style: { clear: 'both' } });

export let div = (args, subs) => h('div', args, subs);
export let p = (args, subs) => h('p', args, subs);
export let span = (args, subs) => h('span', args, subs);
export let ul = (args, subs) => h('ul', args, subs);
export let li = (args, subs) => h('li', args, subs);
export let form = (args, subs) => h('form', args, subs);
export let label = (args, subs) => h('label', args, subs);
export let input = (args, subs) => h('input', args, subs);
export let select = (args, subs) => h('select', args, subs);
export let option = (args, subs) => h('option', args, subs);
export let img = (args, subs) => h('img', args, subs);
export let button = (args, subs) => h('button', args, subs);

export function merge(a, b) {
  let aType = typeof a;
  let bType = typeof b;
  if (Array.isArray(a)) {
    aType = 'array';
  }
  if (Array.isArray(b)) {
    bType = 'array';
  }
  if (aType == 'object' && bType == 'object') {
    // the new object
    let obj = {};
    if (has_key(b, '>_<')) {
      // wildcard update
      for (let key in a) {
        obj[key] = merge_value(a[key], b['>_<']);
      }
    } else {
      // merge
      for (let key in b) {
        obj[key] = merge_value(a[key], b[key]);
      }
      // copy keys in a but not in b
      for (let key in a) {
        if (has_key(obj, key)) {
          continue
        }
        obj[key] = a[key];
      }
    }
    return obj;
  } else if (aType == 'array' && bType == 'object') {
    // the new object
    let obj = [];
    let wildcard = b['>_<'];
    for (let i = 0; i < a.length; i++) {
      if (has_key(b, i)) {
        obj.push(merge_value(a[i], b[i]));
      } else if (wildcard !== undefined && wildcard !== null) {
        obj.push(merge_value(a[i], wildcard));
      } else {
        obj.push(a[i]);
      }
    }
    return obj;
  } else {
    return b;
  }
}

export function op_insert(elem, index = 0) {
  return Object.defineProperty({
    elem: elem,
    index: index,
  }, '_op_insert', {
    __proto__: null,
    value: true,
  });
}

export function op_remove(index) {
  return Object.defineProperty({
    index: index,
  }, '_op_remove', {
    __proto__: null,
    value: true,
  });
}

export function op_call(cb) {
  return Object.defineProperty({
    cb: cb,
  }, '_op_call', {
    __proto__: null,
    value: true,
  });
}

function merge_value(left, right) {
  if (right === null) {
    return null;
  }
  if (right._op_insert) {
    if (is_none(left)) {
      left = [];
    }
    return insert(left, right.elem, right.index);
  } else if (right._op_call) {
    return right.cb(left);
  } else if (right._op_remove) {
    return remove(left, right.index);
  }
  return merge(left, right);
}

export function insert(ary, elem, index = 0) {
  if (index < 0) {
    index = ary.length + index + 1;
  }
  return [
    ...ary.slice(0, index),
    elem,
    ...ary.slice(index),
  ];
}

export function remove(ary, index) {
  return [
    ...ary.slice(0, index),
    ...ary.slice(index + 1),
  ];
}
<|endoftext|>


<commit_before>import baseTheme from "../baseTheme";
import basicsReadme from "../basics/README.md";
import densityReadme from "./DENSITY_README.md";
import colorSchemeReadme from "./COLOR_SCHEME_README.md";

function filterMatchByKey(o, keyFragment) {
  return Object.keys(o).reduce((acc, key) => {
    if (key.match(keyFragment)) {
      return { ...acc, [key]: o[key] };
    }
    return acc;
  }, {});
}

export default [
  {
    description: "Basics - Border radii",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.borderRadii"),
    readme: basicsReadme
  },
  {
    description: "Basics - Border widths",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.borderWidths"),
    readme: basicsReadme
  },
  {
    description: "Basics - Colors",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.colors"),
    readme: basicsReadme
  },
  {
    description: "Basics - Font families",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.fontFamilies"),
    readme: basicsReadme
  },
  {
    description: "Basics - Font sizes",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.fontSizes"),
    readme: basicsReadme
  },
  {
    description: "Basics - Font weights",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.fontWeights"),
    readme: basicsReadme
  },
  {
    description: "Basics - Line heights",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.lineHeights"),
    readme: basicsReadme
  },
  {
    description: "Basics - Shadows",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.shadows"),
    readme: basicsReadme
  },
  {
    description: "Basics - Spacings",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.spacings"),
    readme: basicsReadme
  },
  {
    description: "Color scheme",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "colorScheme"),
    readme: colorSchemeReadme
  },
  {
    description: "Density",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "density"),
    readme: densityReadme
  },
  {
    description: "Component",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^component./),
    readme: undefined
  },
  {
    description: "Component - Avatar",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^avatar./),
    readme: undefined
  },
  {
    description: "Component - Banner",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^banner./),
    readme: undefined
  },
  {
    description: "Component - Button",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^button./),
    readme: undefined
  },
  {
    description: "Component - Checkbox",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^checkbox./),
    readme: undefined
  },
  {
    description: "Component - Divider",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^divider./),
    readme: undefined
  },
  {
    description: "Component - Flyout",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^flyout./),
    readme: undefined
  },
  {
    description: "Component - Form field",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^formField./),
    readme: undefined
  },
  {
    description: "Component - Input",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^input./),
    readme: undefined
  },
  {
    description: "Component - Label",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^label./),
    readme: undefined
  },
  {
    description: "Component - Menu",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^menu./),
    readme: undefined
  },
  {
    description: "Component - Modal",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^modal./),
    readme: undefined
  },
  {
    description: "Component - Progress bar",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^progressBar./),
    readme: undefined
  },
  {
    description: "Component - Progress ring",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^progressRing./),
    readme: undefined
  },
  {
    description: "Component - Skeleton item",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^skeletonItem./),
    readme: undefined
  },
  {
    description: "Component - Slider",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^slider./),
    readme: undefined
  },
  {
    description: "Component - Tabs",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^tabs./),
    readme: undefined
  },
  {
    description: "Component - Text area",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^textArea./),
    readme: undefined
  },
  {
    description: "Component - Text link",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^textLink./),
    readme: undefined
  },
  {
    description: "Component - Tooltip",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^tooltip./),
    readme: undefined
  },
  {
    description: "Component - Typography",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^typography./),
    readme: undefined
  }
];
<commit_msg>docs: update theme-data stories for Accordion<commit_after>import baseTheme from "../baseTheme";
import basicsReadme from "../basics/README.md";
import densityReadme from "./DENSITY_README.md";
import colorSchemeReadme from "./COLOR_SCHEME_README.md";

function filterMatchByKey(o, keyFragment) {
  return Object.keys(o).reduce((acc, key) => {
    if (key.match(keyFragment)) {
      return { ...acc, [key]: o[key] };
    }
    return acc;
  }, {});
}

export default [
  {
    description: "Basics - Border radii",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.borderRadii"),
    readme: basicsReadme
  },
  {
    description: "Basics - Border widths",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.borderWidths"),
    readme: basicsReadme
  },
  {
    description: "Basics - Colors",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.colors"),
    readme: basicsReadme
  },
  {
    description: "Basics - Font families",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.fontFamilies"),
    readme: basicsReadme
  },
  {
    description: "Basics - Font sizes",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.fontSizes"),
    readme: basicsReadme
  },
  {
    description: "Basics - Font weights",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.fontWeights"),
    readme: basicsReadme
  },
  {
    description: "Basics - Line heights",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.lineHeights"),
    readme: basicsReadme
  },
  {
    description: "Basics - Shadows",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.shadows"),
    readme: basicsReadme
  },
  {
    description: "Basics - Spacings",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "basics.spacings"),
    readme: basicsReadme
  },
  {
    description: "Color scheme",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "colorScheme"),
    readme: colorSchemeReadme
  },
  {
    description: "Density",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, "density"),
    readme: densityReadme
  },
  {
    description: "Component",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^component./),
    readme: undefined
  },
  {
    description: "Component - Accordion",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^accordion./),
    readme: undefined
  },
  {
    description: "Component - Avatar",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^avatar./),
    readme: undefined
  },
  {
    description: "Component - Banner",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^banner./),
    readme: undefined
  },
  {
    description: "Component - Button",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^button./),
    readme: undefined
  },
  {
    description: "Component - Checkbox",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^checkbox./),
    readme: undefined
  },
  {
    description: "Component - Divider",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^divider./),
    readme: undefined
  },
  {
    description: "Component - Flyout",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^flyout./),
    readme: undefined
  },
  {
    description: "Component - Form field",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^formField./),
    readme: undefined
  },
  {
    description: "Component - Input",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^input./),
    readme: undefined
  },
  {
    description: "Component - Label",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^label./),
    readme: undefined
  },
  {
    description: "Component - Menu",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^menu./),
    readme: undefined
  },
  {
    description: "Component - Modal",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^modal./),
    readme: undefined
  },
  {
    description: "Component - Progress bar",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^progressBar./),
    readme: undefined
  },
  {
    description: "Component - Progress ring",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^progressRing./),
    readme: undefined
  },
  {
    description: "Component - Skeleton item",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^skeletonItem./),
    readme: undefined
  },
  {
    description: "Component - Slider",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^slider./),
    readme: undefined
  },
  {
    description: "Component - Tabs",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^tabs./),
    readme: undefined
  },
  {
    description: "Component - Text area",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^textArea./),
    readme: undefined
  },
  {
    description: "Component - Text link",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^textLink./),
    readme: undefined
  },
  {
    description: "Component - Tooltip",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^tooltip./),
    readme: undefined
  },
  {
    description: "Component - Typography",
    schema: filterMatchByKey(baseTheme.unresolvedRoles, /^typography./),
    readme: undefined
  }
];
<|endoftext|>


<commit_before>var tx = require('ethereumjs-tx');
var utils =  require('ethereumjs-util');
var BigNumber = require('bignumber.js');

var blockappsapi = function(host) {

    if(host == undefined)
        host = "http://stablenet.blockapps.net"

    this.host = host
    console.log(host)
}

blockappsapi.prototype.getBalance = function(address, callback) {

    // on node.js make sure we've imported
    // var XMLHttpRequest = require('xhr2').XMLHttpRequest;

    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.host + "/query/account?address=" + address, true)
    //xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8')

    xhr.onreadystatechange = function() {
         if (xhr.readyState == 4 && xhr.status == 200) {
               var bal = 0
               if(xhr.responseText != "[]"){
                  bal = JSON.parse(xhr.responseText)[0]["balance"]//*1000000000000000000
               }
               callback(undefined, bal)
            }
         }
         xhr.send('');
     }

blockappsapi.prototype.injectTransaction = function(signedTx, callback) {
     var js = _serialRawTxToJson(signedTx)
     var xhr = new XMLHttpRequest()
     xhr.open("POST", this.host+"/includetransaction", true)
     xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');

     xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var txHash = xhr.responseText.slice(xhr.responseText.lastIndexOf('='))
            callback(undefined, txHash)
        }
     }
     console.log(js)
     xhr.send(JSON.stringify(js));
}

blockappsapi.prototype.getNonce = function(address, callback) {
    // on node.js make sure we've imported
    // var XMLHttpRequest = require('xhr2').XMLHttpRequest;

    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.host + "/query/account?address=" + address, true)
    //xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8')

    xhr.onreadystatechange = function() {
         if (xhr.readyState == 4 && xhr.status == 200) {
               var bal = 0
               if(xhr.responseText != "[]"){
                  bal = JSON.parse(xhr.responseText)[0]["nonce"]
               }

               console.log("nonce is: " + bal)
               callback(undefined, bal)
            }
         }
         xhr.send('');
     }

blockappsapi.prototype.estimateGas = function(txObject, callback) {
    console.log("estimateGas() not yet implemented")
    return;
}

blockappsapi.prototype.getStorage = function(address, callback){

    console.log("address is : " + address)
    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.host + "/query/storage?address=" + address, true)

    xhr.onreadystatechange = function() {
         if (xhr.readyState == 4 && xhr.status == 200) {
               var bal = 0
               if(xhr.responseText != "[]"){
                  var res = JSON.parse(xhr.responseText)
                  bal = res[res.length-1]["value"]
               }

               //console.log("storage is: " + bal)
               callback(undefined, bal)
            }
         }
         xhr.send('');
     }

function _serialRawTxToJson(rawTx){

            var ttx = new tx(new Buffer(rawTx, 'hex'))
            BigNumber.config({ EXPONENTIAL_AT: 20000000 })
            var rawString = ttx.value.toString('hex')
            var bigValue = new BigNumber(0)
            if (rawString !== "") {
            bigValue = new BigNumber(rawString, 16)
	    }
             if (ttx.to.length  == 0){
              console.log("converting contract")
               js = {
                from : ttx.getSenderAddress().toString('hex'),
                        nonce : utils.bufferToInt(ttx.nonce),
                            gasPrice : utils.bufferToInt(ttx.gasPrice),
                          gasLimit : utils.bufferToInt(ttx.gasLimit),
                      //toAddress : ttx.to.toString('hex'),
                            value : bigValue.toString(),
                      codeOrData : (ttx.data).toString('hex'),
                        r : (ttx.r).toString('hex'),
                      s : (ttx.s).toString('hex'),
                      v : (ttx.v).toString('hex'),
                        hash : ttx.hash().toString('hex')
                     };
                }
            else {
              console.log("converting tx")
              js = {
                from : ttx.getSenderAddress().toString('hex'),
                        nonce : utils.bufferToInt(ttx.nonce),
                            gasPrice : utils.bufferToInt(ttx.gasPrice),
                          gasLimit : utils.bufferToInt(ttx.gasLimit),
                            value : bigValue.toString(),
                            to : (ttx.to).toString('hex'),
                      codeOrData : (ttx.data).toString('hex'),
                        r : (ttx.r).toString('hex'),
                      s : (ttx.s).toString('hex'),
                      v : (ttx.v).toString('hex'),
                        hash : ttx.hash().toString('hex')
                     };
                }

                return js;
         };

module.exports = blockappsapi;
<commit_msg>Blockappsapi cleanup.<commit_after>var tx = require('ethereumjs-tx');
var utils =  require('ethereumjs-util');
var BigNumber = require('bignumber.js');

var blockappsapi = function(host) {

    if(host == undefined)
        host = "http://stablenet.blockapps.net"

    this.host = host
    console.log(host)
}

blockappsapi.parseResponse = function(text, key) {
    var value = 0
    if(text != "[]"){
        value = JSON.parse(text)[0][key]
    }
    return value
}

blockappsapi.prototype.getBalance = function(address, callback) {

    // on node.js make sure we've imported
    // var XMLHttpRequest = require('xhr2').XMLHttpRequest;

    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.host + "/query/account?address=" + address, true)
    //xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8')

    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var balance = blockappsapi.parseResponse(xhr.responseText, "balance")//*1000000000000000000
            callback(undefined, balance)
        }
    }
    xhr.send('');
}

blockappsapi.prototype.injectTransaction = function(signedTx, callback) {
     var js = _serialRawTxToJson(signedTx)
     var xhr = new XMLHttpRequest()
     xhr.open("POST", this.host+"/includetransaction", true)
     xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');

     xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var txHash = xhr.responseText.slice(xhr.responseText.lastIndexOf('='))
            callback(undefined, txHash)
        }
     }
     console.log(js)
     xhr.send(JSON.stringify(js));
}

blockappsapi.prototype.getNonce = function(address, callback) {
    // on node.js make sure we've imported
    // var XMLHttpRequest = require('xhr2').XMLHttpRequest;

    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.host + "/query/account?address=" + address, true)
    //xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8')

    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var nonce = blockappsapi.parseResponse(xhr.responseText, "nonce")
            callback(undefined, nonce)
        }
    }
    xhr.send('');
}

blockappsapi.prototype.estimateGas = function(txObject, callback) {
    console.log("estimateGas() not yet implemented")
    return;
}

blockappsapi.prototype.getStorage = function(address, callback){

    console.log("address is : " + address)
    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.host + "/query/storage?address=" + address, true)

    xhr.onreadystatechange = function() {
         if (xhr.readyState == 4 && xhr.status == 200) {
               var bal = 0
               if(xhr.responseText != "[]"){
                  var res = JSON.parse(xhr.responseText)
                  bal = res[res.length-1]["value"]
               }

               //console.log("storage is: " + bal)
               callback(undefined, bal)
            }
         }
         xhr.send('');
     }

function _serialRawTxToJson(rawTx){

            var ttx = new tx(new Buffer(rawTx, 'hex'))
            BigNumber.config({ EXPONENTIAL_AT: 20000000 })
            var rawString = ttx.value.toString('hex')
            var bigValue = new BigNumber(0)
            if (rawString !== "") {
            bigValue = new BigNumber(rawString, 16)
	    }
             if (ttx.to.length  == 0){
              console.log("converting contract")
               js = {
                from : ttx.getSenderAddress().toString('hex'),
                        nonce : utils.bufferToInt(ttx.nonce),
                            gasPrice : utils.bufferToInt(ttx.gasPrice),
                          gasLimit : utils.bufferToInt(ttx.gasLimit),
                      //toAddress : ttx.to.toString('hex'),
                            value : bigValue.toString(),
                      codeOrData : (ttx.data).toString('hex'),
                        r : (ttx.r).toString('hex'),
                      s : (ttx.s).toString('hex'),
                      v : (ttx.v).toString('hex'),
                        hash : ttx.hash().toString('hex')
                     };
                }
            else {
              console.log("converting tx")
              js = {
                from : ttx.getSenderAddress().toString('hex'),
                        nonce : utils.bufferToInt(ttx.nonce),
                            gasPrice : utils.bufferToInt(ttx.gasPrice),
                          gasLimit : utils.bufferToInt(ttx.gasLimit),
                            value : bigValue.toString(),
                            to : (ttx.to).toString('hex'),
                      codeOrData : (ttx.data).toString('hex'),
                        r : (ttx.r).toString('hex'),
                      s : (ttx.s).toString('hex'),
                      v : (ttx.v).toString('hex'),
                        hash : ttx.hash().toString('hex')
                     };
                }

                return js;
         };

module.exports = blockappsapi;
<|endoftext|>


<commit_before>/**
 * @fileoverview Panel of the expression matrix component.
 */

'use strict';

/**
 * ExpressionPanel manages the UI control panel of the expression matrix.
 * @param {!Object} data Data object of the view.
 * @constructor
 */
genotet.ExpressionPanel = function(data) {
  this.base.constructor.call(this, data);
  _(this.data.options).extend({
    // TODO(bowen): Check how TFA data will be used.
    //showTFA: true,
    showProfiles: false,
    showGradient: false,
    autoScaleGradient: false,
    showGeneLabels: true,
    showConditionLabels: true
  });

  /**
   * Select2 for selecting genes to profile.
   * @private {select2}
   */
  this.selectProfiles_;
};

genotet.utils.inherit(genotet.ExpressionPanel, genotet.ViewPanel);

/** @inheritDoc */
genotet.ExpressionPanel.prototype.template =
    'components/expression/expression-panel.html';

/** @inheritDoc */
genotet.ExpressionPanel.prototype.panel = function(container) {
  this.base.panel.call(this, container);
};

/** @inheritDoc */
genotet.ExpressionPanel.prototype.dataLoaded = function() {
  this.updateGenes(this.data.matrix.geneNames);
};

/** @inheritDoc */
genotet.ExpressionPanel.prototype.initPanel = function() {
  // Data may have not been loaded. Use empty list.
  this.updateGenes([]);

 // Initialize switches.
  this.container_.find('.switches input').bootstrapSwitch({
    size: 'mini'
  });

  // Switch actions
  [
    {selector: '#overview', type: 'overview', attribute: 'showOverview'},
    {selector: '#bed', type: 'bed', attribute: 'showBed'},
    {selector: '#exons', type: 'exons', attribute: 'showExons'},
    {selector: '#auto-scale', type: 'auto-scale', attribute: 'autoScale'}
  ].forEach(function(bSwitch) {
    this.container_.find(bSwitch.selector).on('switchChange.bootstrapSwitch',
      function(event, state) {
        this.data.options[bSwitch.attribute] = state;
        this.signal('update', {
          type: bSwitch.type
        });
      }.bind(this));
   }, this);
};

/**
 * Updates the genes in the profile list.
 * Select2 will regenerate the selection list each time updated.
 * @param {!Array<string>} genes List of genes.
 */
genotet.ExpressionPanel.prototype.updateGenes = function(genes) {
  var genes = genes.map(function(gene, index) {
    return {
      id: gene,
      text: gene
    };
  });
  this.selectProfiles_ = this.container_.find('#profile select')
    .select2({
      data: genes,
      multiple: true
    });
  this.container_.find('#profile .select2-container').css({
    width: '100%'
  });
};

genotet.ExpressionPanel.prototype.setCellInfo_ = function(geneName, conditionName, container) {
  container.html(this.container_.find('#cell-info-template').html());
  container.children('#gene').children('span')
    .text(geneName);
  container.children('#condition').children('span')
    .text(conditionName);
};

genotet.ExpressionPanel.prototype.hideEdgeInfo_ = function() {
  this.container_.find('#cell-info').slideUp();
};

genotet.ExpressionPanel.prototype.tooltipHeatmap = function(geneName, conditionName) {
  var tooltip = genotet.tooltip.new();
  this.setCellInfo_(geneName, conditionName, tooltip)
  tooltip.find('.close').remove();
};

genotet.ExpressionPanel.prototype.displayCellInfo = function(cell, geneName, conditionName) {
  var info = this.container_.find('#cell-info').hide().slideDown();
  this.setCellInfo_(geneName, conditionName, info);
  info.find('.close').click(function() {
    this.hideEdgeInfo_();
  }.bind(this));
};

/*
$('#'+ this.htmlid + ' #labelrow').attr('checked', this.labelrows).change(function() { return layout.toggleLabelrows(); });
$('#'+ this.htmlid + ' #labelcol').attr('checked', this.labelcols).change(function() { return layout.toggleLablecols(); });
$('#'+ this.htmlid + ' #showplot').attr('checked', this.showPlot).change(function() { return layout.toggleShowPlot(); });
$('#'+ this.htmlid + ' #showtfa').attr('checked', this.showTFA).change(function() { return layout.toggleShowTFA(); });
$('#'+ this.htmlid + ' #showgrad').attr('checked', this.showGradient).change(function() { return layout.toggleShowGradient(); });
$('#'+ this.htmlid + ' #autoscale').attr('checked', this.autoScale).change(function() { return layout.toggleAutoScale(); });
$('#'+ this.htmlid + ' #addline').keydown(function(e) { if (e.which == 13) layout.uiUpdate('addline');});
$('#'+ this.htmlid + ' #exprow').keydown(function(e) { if (e.which == 13) layout.uiUpdate('exprow');});
$('#'+ this.htmlid + ' #expcol').keydown(function(e) { if (e.which == 13) layout.uiUpdate('expcol');});
$('#'+ this.htmlid + " #data option[value='" + this.parentView.loader.lastIdentifier.mat + "']").attr('selected', true);
$('#'+ this.htmlid + ' #data').change(function(e) { return layout.uiUpdate('data');});
*/

/*
 LayoutHeatmap.prototype.uiUpdate = function(type) {
 var data = this.parentView.viewdata.heatmapData;
 if (type == 'data') {
 var mat = $('#'+ this.htmlid + ' #data option:selected').val();
 if (mat != this.parentView.loader.lastIdentifier.mat) {
 this.parentView.viewdata.lineData = [];
 this.parentView.loader.loadHeatmap(mat);
 }
 }else if (type == 'addline') {
 //this.showPlot = true;
 var srch = $('#'+ this.htmlid + ' #addline').val();
 if (srch == '') return;
 this.parentView.loader.loadLine(null, srch);
 $('#'+ this.htmlid + ' #addline').val('');
 }else if (type == 'exprow' || type == 'expcol') {
 var exprows = 'a^', expcols = 'a^';  // a^ matches nothing
 var rmexprows = 'a^', rmexpcols = 'a^';
 var addrows = false, addcols = false, rmrows = false, rmcols = false;
 if (type == 'exprow') {
 var cmd = $('#'+ this.htmlid + ' #exprow').val().split(' ');
 if (cmd.length == 1) {  // sel
 exprows += '|' + cmd[0];
 }else if (cmd.length != 2) {
 options.alert('invalid syntax, usage: add/rm/sel regexp | regexp');
 return;
 }else {
 if (cmd[0].toLowerCase() == 'add') {
 addrows = true;
 exprows += '|' + cmd[1];
 }else if (cmd[0].toLowerCase() == 'rm') {
 rmexprows = cmd[1];
 rmrows = true;
 }else {
 exprows += '|' + cmd[1];
 }
 }
 addcols = true;
 }
 if (type == 'expcol') {
 var cmd = $('#'+ this.htmlid + ' #expcol').val().split(' ');
 if (cmd.length == 1) {  // sel
 expcols += '|' + cmd[0];
 }else if (cmd.length != 2) {
 options.alert('invalid syntax, usage: add/sel/rm regexp');
 return;
 }else {
 if (cmd[0].toLowerCase() == 'add') {
 addcols = true;
 expcols += '|' + cmd[1];
 }else if (cmd[0].toLowerCase() == 'rm') {
 rmexpcols = cmd[1];
 rmcols = true;
 }else {
 expcols += '|' + cmd[1];
 }
 }
 addrows = true;
 }
 for (var i = 0; i < data.rownames.length; i++) {
 if (rmrows && data.rownames[i].match(RegExp(rmexprows, 'i'))) continue;
 if (rmrows || addrows) exprows += '|^'+ this.filterRegexp(data.rownames[i]) + '$';
 }
 for (var i = 0; i < data.colnames.length; i++) {
 if (rmcols && data.colnames[i].match(RegExp(rmexpcols, 'i'))) continue;
 if (rmcols || addcols) expcols += '|^'+ this.filterRegexp(data.colnames[i]) + '$';
 }
 this.parentView.loader.loadHeatmap(null, exprows, expcols);
 }
 };

 LayoutHeatmap.prototype.filterRegexp = function(exp) {
 return exp
 .replace(/\+/g, '\\+')
 .replace(/\./g, '\\.')
 .replace(/\(/g, '\\(')
 .replace(/\)/g, '\\)');  // replace special chars
 };

 LayoutHeatmap.prototype.toggleAutoScale = function() {
 this.autoScale = !this.autoScale;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleLabelrows = function() {
 this.labelrows = !this.labelrows;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleLablecols = function() {
 this.labelcols = !this.labelcols;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleShowGradient = function() {
 this.showGradient = !this.showGradient;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleAutoScale = function() {
 this.autoScale = !this.autoScale;
 this.reloadData();
 };
 LayoutHeatmap.prototype.toggleShowTFA = function() {
 this.showTFA = !this.showTFA;
 this.updateLineSize();
 this.updateHeatmapSize();
 this.parentView.loader.loadHeatmap();
 };

 LayoutHeatmap.prototype.toggleShowPlot = function() {
 this.showPlot = !this.showPlot;
 this.updateLineSize();
 this.updateHeatmapSize();
 this.parentView.loader.loadHeatmap();
 };

 */<commit_msg>Fixed heatmap tooltip.<commit_after>/**
 * @fileoverview Panel of the expression matrix component.
 */

'use strict';

/**
 * ExpressionPanel manages the UI control panel of the expression matrix.
 * @param {!Object} data Data object of the view.
 * @constructor
 */
genotet.ExpressionPanel = function(data) {
  this.base.constructor.call(this, data);
  _(this.data.options).extend({
    // TODO(bowen): Check how TFA data will be used.
    //showTFA: true,
    showProfiles: false,
    showGradient: false,
    autoScaleGradient: false,
    showGeneLabels: true,
    showConditionLabels: true
  });

  /**
   * Select2 for selecting genes to profile.
   * @private {select2}
   */
  this.selectProfiles_;
};

genotet.utils.inherit(genotet.ExpressionPanel, genotet.ViewPanel);

/** @inheritDoc */
genotet.ExpressionPanel.prototype.template =
    'components/expression/expression-panel.html';

/** @inheritDoc */
genotet.ExpressionPanel.prototype.panel = function(container) {
  this.base.panel.call(this, container);
};

/** @inheritDoc */
genotet.ExpressionPanel.prototype.dataLoaded = function() {
  this.updateGenes(this.data.matrix.geneNames);
};

/** @inheritDoc */
genotet.ExpressionPanel.prototype.initPanel = function() {
  // Data may have not been loaded. Use empty list.
  this.updateGenes([]);

 // Initialize switches.
  this.container_.find('.switches input').bootstrapSwitch({
    size: 'mini'
  });

  // Switch actions
  [
    {selector: '#overview', type: 'overview', attribute: 'showOverview'},
    {selector: '#bed', type: 'bed', attribute: 'showBed'},
    {selector: '#exons', type: 'exons', attribute: 'showExons'},
    {selector: '#auto-scale', type: 'auto-scale', attribute: 'autoScale'}
  ].forEach(function(bSwitch) {
    this.container_.find(bSwitch.selector).on('switchChange.bootstrapSwitch',
      function(event, state) {
        this.data.options[bSwitch.attribute] = state;
        this.signal('update', {
          type: bSwitch.type
        });
      }.bind(this));
   }, this);
};

/**
 * Updates the genes in the profile list.
 * Select2 will regenerate the selection list each time updated.
 * @param {!Array<string>} genes List of genes.
 */
genotet.ExpressionPanel.prototype.updateGenes = function(genes) {
  var genes = genes.map(function(gene, index) {
    return {
      id: gene,
      text: gene
    };
  });
  this.selectProfiles_ = this.container_.find('#profile select')
    .select2({
      data: genes,
      multiple: true
    });
  this.container_.find('#profile .select2-container').css({
    width: '100%'
  });
};

genotet.ExpressionPanel.prototype.setCellInfo_ = function(geneName, conditionName, container) {
  container.html(this.container_.find('#cell-info-template').html());
  container.children('#gene').children('span')
    .text(geneName);
  container.children('#condition').children('span')
    .text(conditionName);
};

genotet.ExpressionPanel.prototype.hideCellInfo_ = function() {
  this.container_.find('#cell-info').slideUp();
};

genotet.ExpressionPanel.prototype.tooltipHeatmap = function(geneName, conditionName) {
  var tooltip = genotet.tooltip.new();
  this.setCellInfo_(geneName, conditionName, tooltip)
  tooltip.find('.close').remove();
};

genotet.ExpressionPanel.prototype.displayCellInfo = function(cell, geneName, conditionName) {
  var info = this.container_.find('#cell-info').hide().slideDown();
  this.setCellInfo_(geneName, conditionName, info);
  info.find('.close').click(function() {
    this.hideCellInfo_();
  }.bind(this));
};

/*
$('#'+ this.htmlid + ' #labelrow').attr('checked', this.labelrows).change(function() { return layout.toggleLabelrows(); });
$('#'+ this.htmlid + ' #labelcol').attr('checked', this.labelcols).change(function() { return layout.toggleLablecols(); });
$('#'+ this.htmlid + ' #showplot').attr('checked', this.showPlot).change(function() { return layout.toggleShowPlot(); });
$('#'+ this.htmlid + ' #showtfa').attr('checked', this.showTFA).change(function() { return layout.toggleShowTFA(); });
$('#'+ this.htmlid + ' #showgrad').attr('checked', this.showGradient).change(function() { return layout.toggleShowGradient(); });
$('#'+ this.htmlid + ' #autoscale').attr('checked', this.autoScale).change(function() { return layout.toggleAutoScale(); });
$('#'+ this.htmlid + ' #addline').keydown(function(e) { if (e.which == 13) layout.uiUpdate('addline');});
$('#'+ this.htmlid + ' #exprow').keydown(function(e) { if (e.which == 13) layout.uiUpdate('exprow');});
$('#'+ this.htmlid + ' #expcol').keydown(function(e) { if (e.which == 13) layout.uiUpdate('expcol');});
$('#'+ this.htmlid + " #data option[value='" + this.parentView.loader.lastIdentifier.mat + "']").attr('selected', true);
$('#'+ this.htmlid + ' #data').change(function(e) { return layout.uiUpdate('data');});
*/

/*
 LayoutHeatmap.prototype.uiUpdate = function(type) {
 var data = this.parentView.viewdata.heatmapData;
 if (type == 'data') {
 var mat = $('#'+ this.htmlid + ' #data option:selected').val();
 if (mat != this.parentView.loader.lastIdentifier.mat) {
 this.parentView.viewdata.lineData = [];
 this.parentView.loader.loadHeatmap(mat);
 }
 }else if (type == 'addline') {
 //this.showPlot = true;
 var srch = $('#'+ this.htmlid + ' #addline').val();
 if (srch == '') return;
 this.parentView.loader.loadLine(null, srch);
 $('#'+ this.htmlid + ' #addline').val('');
 }else if (type == 'exprow' || type == 'expcol') {
 var exprows = 'a^', expcols = 'a^';  // a^ matches nothing
 var rmexprows = 'a^', rmexpcols = 'a^';
 var addrows = false, addcols = false, rmrows = false, rmcols = false;
 if (type == 'exprow') {
 var cmd = $('#'+ this.htmlid + ' #exprow').val().split(' ');
 if (cmd.length == 1) {  // sel
 exprows += '|' + cmd[0];
 }else if (cmd.length != 2) {
 options.alert('invalid syntax, usage: add/rm/sel regexp | regexp');
 return;
 }else {
 if (cmd[0].toLowerCase() == 'add') {
 addrows = true;
 exprows += '|' + cmd[1];
 }else if (cmd[0].toLowerCase() == 'rm') {
 rmexprows = cmd[1];
 rmrows = true;
 }else {
 exprows += '|' + cmd[1];
 }
 }
 addcols = true;
 }
 if (type == 'expcol') {
 var cmd = $('#'+ this.htmlid + ' #expcol').val().split(' ');
 if (cmd.length == 1) {  // sel
 expcols += '|' + cmd[0];
 }else if (cmd.length != 2) {
 options.alert('invalid syntax, usage: add/sel/rm regexp');
 return;
 }else {
 if (cmd[0].toLowerCase() == 'add') {
 addcols = true;
 expcols += '|' + cmd[1];
 }else if (cmd[0].toLowerCase() == 'rm') {
 rmexpcols = cmd[1];
 rmcols = true;
 }else {
 expcols += '|' + cmd[1];
 }
 }
 addrows = true;
 }
 for (var i = 0; i < data.rownames.length; i++) {
 if (rmrows && data.rownames[i].match(RegExp(rmexprows, 'i'))) continue;
 if (rmrows || addrows) exprows += '|^'+ this.filterRegexp(data.rownames[i]) + '$';
 }
 for (var i = 0; i < data.colnames.length; i++) {
 if (rmcols && data.colnames[i].match(RegExp(rmexpcols, 'i'))) continue;
 if (rmcols || addcols) expcols += '|^'+ this.filterRegexp(data.colnames[i]) + '$';
 }
 this.parentView.loader.loadHeatmap(null, exprows, expcols);
 }
 };

 LayoutHeatmap.prototype.filterRegexp = function(exp) {
 return exp
 .replace(/\+/g, '\\+')
 .replace(/\./g, '\\.')
 .replace(/\(/g, '\\(')
 .replace(/\)/g, '\\)');  // replace special chars
 };

 LayoutHeatmap.prototype.toggleAutoScale = function() {
 this.autoScale = !this.autoScale;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleLabelrows = function() {
 this.labelrows = !this.labelrows;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleLablecols = function() {
 this.labelcols = !this.labelcols;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleShowGradient = function() {
 this.showGradient = !this.showGradient;
 this.reloadData();
 };

 LayoutHeatmap.prototype.toggleAutoScale = function() {
 this.autoScale = !this.autoScale;
 this.reloadData();
 };
 LayoutHeatmap.prototype.toggleShowTFA = function() {
 this.showTFA = !this.showTFA;
 this.updateLineSize();
 this.updateHeatmapSize();
 this.parentView.loader.loadHeatmap();
 };

 LayoutHeatmap.prototype.toggleShowPlot = function() {
 this.showPlot = !this.showPlot;
 this.updateLineSize();
 this.updateHeatmapSize();
 this.parentView.loader.loadHeatmap();
 };

 */<|endoftext|>


<commit_before>/**
 * Line highlighting
 */
$(function() {
    // Check if line hilighting is needed
    if(!$('.logs:not(.tailing)').length) {
        return;
    }

    var activeLines = [],
        /**
         * @param line
         */
        addLine = function(line) {
            // we don't want zero
            if (line === 0) {
                return;
            }

            // only add if not already in array
            if (activeLines.indexOf(line) == -1) {
                activeLines.push(line);
            }

            // add class
            $(".logs .line[data-line-num='" + line + "']").addClass('highlighted');
        },
        /**
         * @param line
         */
        removeLine = function(line) {
            // remove line from array
            var index;
            if ((index = activeLines.indexOf(line)) > -1) {
                activeLines.splice(index, 1);
            }

            // remove class
            $(".logs .line[data-line-num='" + line + "']").removeClass('highlighted');
        },
        /**
         * @returns {string}
         */
        createHash = function() {
            var result = 'L'; // hash (#) is automatically added
            var first = true;

            activeLines.forEach(function(entry) {
                if (!first) {
                    result += ',';
                }

                first = false;
                result += entry;
            });

            return result;
        },
        hashChange = function() {
            $('.logs .line').removeClass('highlighted');

            var hash = window.location.hash;

            var remainingPart = hash.substr(0, 2);
            if (remainingPart == "#L") {
                if ($('.logs').length !== 0) {
                    var remainingParts = hash.substr(2).split(',');
                    for (var i = 0; i < remainingParts.length; i++) {
                        var part = remainingParts[i];

                        if (part.indexOf('-') !== -1) {
                            var re = /([0-9]+)-([0-9]+)/;
                            var match = re.exec(part);
                            if (match.length === 3) {
                                var imin = Number(match[1]);
                                var imax = Number(match[2]);
                                if (imin > imax) {
                                    var tempMax = imax;
                                    imax = imin;
                                    imin = tempMax;
                                }
                                for (var j = imin; j <= imax; j++) {
                                    addLine(j);
                                }
                            }
                        } else {
                            var lineNum = Number(part);
                            if (!isNaN(lineNum)) {
                                addLine(lineNum);
                            }
                        }
                    }
                }
            }
        },
        jumpToFirstLine = function() {
            if (activeLines.length > 0) {
                var shift = Math.min.apply(Math, activeLines);
                var elem = $(".logs .line[data-line-num='" + shift + "']");
                $(window).scrollTop(elem.offset().top - 0.33 * $(window).height());
            }
        };

    // listen for hash changes
    $(window).on('hashchange', function() {
        hashChange();
    });

    // allow adding and removing lines using the icon beside the log line
    $(document).on('mousedown', '.logs .timestamp', function(event) {
        event.preventDefault();

        // climb the dom to .line
        var line = $(this).closest('.line').data('line-num');

        // if ctrl is being held, add another line
        if (event.ctrlKey || event.metaKey) {
            // if we're holding ctrl and the line exists, remove it
            if (activeLines.indexOf(line) != -1) {
                removeLine(line);
            } else {
                addLine(line);
            }
        } else if (event.shiftKey) {
            // We'll assume the user wants to select a range here

            // I'm arbitrarily deciding that a range will be made up of the last line they added to the list
            // and the line they're clicking now.

            var lastLine = activeLines[activeLines.length - 1];
            if (lastLine < line) {
                // The just-selected line is in front of the last selected line. Great, we'll
                // highlight all of the lines in between.

                window.location.hash = window.location.hash + "," + lastLine + "-" + line;
                hashChange();
                return;
            } else {
                // The last line is after the one the user just selected. We'll start at the selected line
                // and step to the next.

                window.location.hash = window.location.hash + "," + line + "-" + lastLine;
                hashChange();
                return;
            }

        } else {
            var alreadyExisted = (activeLines.indexOf(line) != -1 && activeLines.length === 1);
            // ctrl is not being held, remove all and add new
            activeLines.forEach(function(entry) {
                removeLine(entry);
            });
            activeLines = [];

            if (!alreadyExisted) {
                addLine(line);
            }
        }

        // set the new hash
        var hash = createHash();
        if (hash !== 'L') {
            window.location.hash = createHash();
        } else {
            window.location.hash = '';
        }
    });

    // delay load
    setTimeout(hashChange, 500);
    setTimeout(jumpToFirstLine, 600);
});

/**
 * Tooltips
 */
$(function() {
    var targets = $('[rel~=tooltip]'),
        target = false,
        tooltip = false,
        title = false;

    targets.bind('mouseenter', function() {
        target = $(this);
        tip = target.attr('title');
        tooltip = $('

');

        if (!tip || tip == '')
            return false;

        target.removeAttr('title');
        tooltip.css('opacity', 0)
            .html(tip)
            .appendTo('body');

        var init_tooltip = function() {
            if ($(window).width() < tooltip.outerWidth() * 1.5)
                tooltip.css('max-width', $(window).width() / 2);
            else
                tooltip.css('max-width', 340);

            var pos_left = target.offset().left + (target.outerWidth() / 2) - (tooltip.outerWidth() / 2),
                pos_top = target.offset().top - tooltip.outerHeight() - 20;

            if (pos_left < 0) {
                pos_left = target.offset().left + target.outerWidth() / 2 - 20;
                tooltip.addClass('left');
            } else
                tooltip.removeClass('left');

            if (pos_left + tooltip.outerWidth() > $(window).width()) {
                pos_left = target.offset().left - tooltip.outerWidth() + target.outerWidth() / 2 + 20;
                tooltip.addClass('right');
            } else
                tooltip.removeClass('right');

            if (pos_top < 0) {
                var pos_top = target.offset().top + target.outerHeight();
                tooltip.addClass('top');
            } else
                tooltip.removeClass('top');

            tooltip.css({
                left: pos_left,
                top: pos_top
            })
                .animate({
                    top: '+=10',
                    opacity: 1
                }, 50);
        };

        init_tooltip();
        $(window).resize(init_tooltip);

        var remove_tooltip = function() {
            tooltip.animate({
                top: '-=10',
                opacity: 0
            }, 50, function() {
                $(this).remove();
            });

            target.attr('title', tip);
        };

        target.bind('mouseleave', remove_tooltip);
        tooltip.bind('click', remove_tooltip);
    });
});

/**
 * Permissions
 */
$(function() {
    $('#permission-add').click(function(event) {
        event.preventDefault();

        var permissionList = $('#permissions');
        var permission = permissionList.attr('data-prototype');
        permission = permission.replace(/__name__/g, permissionCount);
        var permissionLi = $('

').html(
            '' + permission + '	Remove	'
        );
        permissionLi.appendTo(permissionList);

        permissionCount++;
    });

    $('body').on('click', 'a', function(event) {
        if (event.currentTarget.text == 'Remove') {
            console.log(event);
            event.preventDefault();
            var id = $(this).attr('data-related');
            $('*[data-content="' + id + '"]').remove();
            permissionCount--;
        }
    });
});

/**
 * Responsive nav
 */
$(function() {
    $(".navigation--menutoggle").click(function() {
        $("nav.navigation").toggleClass("on-mobile");
    });
});

<commit_msg>Don't scroll to top when unselecting lines<commit_after>/**
 * Line highlighting
 */
$(function() {
    // Check if line hilighting is needed
    if(!$('.logs:not(.tailing)').length) {
        return;
    }

    var activeLines = [],
        /**
         * @param line
         */
        addLine = function(line) {
            // we don't want zero
            if (line === 0) {
                return;
            }

            // only add if not already in array
            if (activeLines.indexOf(line) == -1) {
                activeLines.push(line);
            }

            // add class
            $(".logs .line[data-line-num='" + line + "']").addClass('highlighted');
        },
        /**
         * @param line
         */
        removeLine = function(line) {
            // remove line from array
            var index;
            if ((index = activeLines.indexOf(line)) > -1) {
                activeLines.splice(index, 1);
            }

            // remove class
            $(".logs .line[data-line-num='" + line + "']").removeClass('highlighted');
        },
        /**
         * @returns {string}
         */
        createHash = function() {
            var result = 'L'; // hash (#) is automatically added
            var first = true;

            activeLines.forEach(function(entry) {
                if (!first) {
                    result += ',';
                }

                first = false;
                result += entry;
            });

            return result;
        },
        hashChange = function() {
            $('.logs .line').removeClass('highlighted');

            var hash = window.location.hash;

            var remainingPart = hash.substr(0, 2);
            if (remainingPart == "#L") {
                if ($('.logs').length !== 0) {
                    var remainingParts = hash.substr(2).split(',');
                    for (var i = 0; i < remainingParts.length; i++) {
                        var part = remainingParts[i];

                        if (part.indexOf('-') !== -1) {
                            var re = /([0-9]+)-([0-9]+)/;
                            var match = re.exec(part);
                            if (match.length === 3) {
                                var imin = Number(match[1]);
                                var imax = Number(match[2]);
                                if (imin > imax) {
                                    var tempMax = imax;
                                    imax = imin;
                                    imin = tempMax;
                                }
                                for (var j = imin; j <= imax; j++) {
                                    addLine(j);
                                }
                            }
                        } else {
                            var lineNum = Number(part);
                            if (!isNaN(lineNum)) {
                                addLine(lineNum);
                            }
                        }
                    }
                }
            }
        },
        jumpToFirstLine = function() {
            if (activeLines.length > 0) {
                var shift = Math.min.apply(Math, activeLines);
                var elem = $(".logs .line[data-line-num='" + shift + "']");
                $(window).scrollTop(elem.offset().top - 0.33 * $(window).height());
            }
        };

    // listen for hash changes
    $(window).on('hashchange', function() {
        hashChange();
    });

    // allow adding and removing lines using the icon beside the log line
    $(document).on('mousedown', '.logs .timestamp', function(event) {
        event.preventDefault();

        // climb the dom to .line
        var line = $(this).closest('.line').data('line-num');

        // if ctrl is being held, add another line
        if (event.ctrlKey || event.metaKey) {
            // if we're holding ctrl and the line exists, remove it
            if (activeLines.indexOf(line) != -1) {
                removeLine(line);
            } else {
                addLine(line);
            }
        } else if (event.shiftKey) {
            // We'll assume the user wants to select a range here

            // I'm arbitrarily deciding that a range will be made up of the last line they added to the list
            // and the line they're clicking now.

            var lastLine = activeLines[activeLines.length - 1];
            if (lastLine < line) {
                // The just-selected line is in front of the last selected line. Great, we'll
                // highlight all of the lines in between.

                window.location.hash = window.location.hash + "," + lastLine + "-" + line;
                hashChange();
                return;
            } else {
                // The last line is after the one the user just selected. We'll start at the selected line
                // and step to the next.

                window.location.hash = window.location.hash + "," + line + "-" + lastLine;
                hashChange();
                return;
            }

        } else {
            var alreadyExisted = (activeLines.indexOf(line) != -1 && activeLines.length === 1);
            // ctrl is not being held, remove all and add new
            activeLines.forEach(function(entry) {
                removeLine(entry);
            });
            activeLines = [];

            if (!alreadyExisted) {
                addLine(line);
            }
        }

        // set the new hash
        var hash = createHash();
        if (hash !== 'L') {
            window.location.hash = createHash();
        } else {
            history.pushState('', document.title, window.location.pathname + window.location.search);
        }
    });

    // delay load
    setTimeout(hashChange, 500);
    setTimeout(jumpToFirstLine, 600);
});

/**
 * Tooltips
 */
$(function() {
    var targets = $('[rel~=tooltip]'),
        target = false,
        tooltip = false,
        title = false;

    targets.bind('mouseenter', function() {
        target = $(this);
        tip = target.attr('title');
        tooltip = $('

');

        if (!tip || tip == '')
            return false;

        target.removeAttr('title');
        tooltip.css('opacity', 0)
            .html(tip)
            .appendTo('body');

        var init_tooltip = function() {
            if ($(window).width() < tooltip.outerWidth() * 1.5)
                tooltip.css('max-width', $(window).width() / 2);
            else
                tooltip.css('max-width', 340);

            var pos_left = target.offset().left + (target.outerWidth() / 2) - (tooltip.outerWidth() / 2),
                pos_top = target.offset().top - tooltip.outerHeight() - 20;

            if (pos_left < 0) {
                pos_left = target.offset().left + target.outerWidth() / 2 - 20;
                tooltip.addClass('left');
            } else
                tooltip.removeClass('left');

            if (pos_left + tooltip.outerWidth() > $(window).width()) {
                pos_left = target.offset().left - tooltip.outerWidth() + target.outerWidth() / 2 + 20;
                tooltip.addClass('right');
            } else
                tooltip.removeClass('right');

            if (pos_top < 0) {
                var pos_top = target.offset().top + target.outerHeight();
                tooltip.addClass('top');
            } else
                tooltip.removeClass('top');

            tooltip.css({
                left: pos_left,
                top: pos_top
            })
                .animate({
                    top: '+=10',
                    opacity: 1
                }, 50);
        };

        init_tooltip();
        $(window).resize(init_tooltip);

        var remove_tooltip = function() {
            tooltip.animate({
                top: '-=10',
                opacity: 0
            }, 50, function() {
                $(this).remove();
            });

            target.attr('title', tip);
        };

        target.bind('mouseleave', remove_tooltip);
        tooltip.bind('click', remove_tooltip);
    });
});

/**
 * Permissions
 */
$(function() {
    $('#permission-add').click(function(event) {
        event.preventDefault();

        var permissionList = $('#permissions');
        var permission = permissionList.attr('data-prototype');
        permission = permission.replace(/__name__/g, permissionCount);
        var permissionLi = $('

').html(
            '' + permission + '	Remove	'
        );
        permissionLi.appendTo(permissionList);

        permissionCount++;
    });

    $('body').on('click', 'a', function(event) {
        if (event.currentTarget.text == 'Remove') {
            console.log(event);
            event.preventDefault();
            var id = $(this).attr('data-related');
            $('*[data-content="' + id + '"]').remove();
            permissionCount--;
        }
    });
});

/**
 * Responsive nav
 */
$(function() {
    $(".navigation--menutoggle").click(function() {
        $("nav.navigation").toggleClass("on-mobile");
    });
});

<|endoftext|>


<commit_before>// $Revision$
// Custom sorting functions for dataTable

$.extend($.fn.dataTableExt.oSort, {
  'numeric-asc': function (a, b) {
    var x = isNaN($.trim(a) || 'a') ? 1e100 : a;
    var y = isNaN($.trim(b) || 'a') ? 1e100 : b;
    return x - y;
  },
  'numeric-desc': function (a, b) {
    var x = isNaN($.trim(a) || 'a') ? -1e100 : a;
    var y = isNaN($.trim(b) || 'a') ? -1e100 : b;
    return y - x;
  },
  'position': function (dir, a, b) {
    var chr = !!(a.match(/:/) || b.match(/:/));

    a = a.split(/[:\-(]/).reverse();
    b = b.split(/[:\-(]/).reverse();

    if (a.length != b.length) {
      var t = a.length < b.length ? a : b;
      t.unshift(t[0]);
    }

    var rtn = 0;

    if (chr) {
      var chrA = a.pop();
      var chrB = b.pop();

      if (isNaN(chrA) && isNaN(chrB)) {
        rtn = this['string-' + dir](chrA, chrB);
      } else if (isNaN(chrA)) {
        rtn = dir == 'asc' ? 1 : -1;
      } else if (isNaN(chrB)) {
        rtn = dir == 'asc' ? -1 : 1;
      } else {
        rtn = this['numeric-' + dir](parseInt(chrA, 10), parseInt(chrB, 10));
      }

      if (rtn) {
        return rtn;
      }
    }

    var i = a.length;

    while (i--) {
      rtn = this['numeric-' + dir](parseInt(a[i], 10), parseInt(b[i], 10));

      if (rtn) {
        break;
      }
    }

    return rtn;
  },
  'position-asc': function (a, b) {
    return this.position('asc', a, b);
  },
  'position-desc': function (a, b) {
    return this.position('desc', a, b);
  },
  'position_html-asc': function (a, b) {
    return this.position('asc', a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  },
  'position_html-desc': function (a, b) {
    return this.position('desc', a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  },
  'string-asc': function (a, b) {
    var x = a === ' ' || a == '-' || a.toLowerCase() == 'n/a' ? 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' : a.toLowerCase();
    var y = b === ' ' || b == '-' || b.toLowerCase() == 'n/a' ? 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' : b.toLowerCase();
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  },
  'string-desc': function (a, b) {
    var x = a === ' ' || a == '-' || a.toLowerCase() == 'n/a' ? '' : a.toLowerCase();
    var y = b === ' ' || b == '-' || b.toLowerCase() == 'n/a' ? '' : b.toLowerCase();
    return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  },
  'html-asc': function (a, b) {
    return this['string-asc'](a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  },
  'html-desc': function (a, b) {
    return this['string-desc'](a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  }
});
<commit_msg>oh jQuery, why can't you treat numbers as strings for trimming?<commit_after>// $Revision$
// Custom sorting functions for dataTable

$.extend($.fn.dataTableExt.oSort, {
  'numeric-asc': function (a, b) {
    var x = isNaN(a) || a == ' ' || a == '' ? 1e100 : a;
    var y = isNaN(b) || b == ' ' || b == '' ? 1e100 : b;
    return x - y;
  },
  'numeric-desc': function (a, b) {
    var x = isNaN(a) || a == ' ' || a == '' ? -1e100 : a;
    var y = isNaN(b) || b == ' ' || b == '' ? -1e100 : b;
    return y - x;
  },
  'position': function (dir, a, b) {
    var chr = !!(a.match(/:/) || b.match(/:/));

    a = a.split(/[:\-(]/).reverse();
    b = b.split(/[:\-(]/).reverse();

    if (a.length != b.length) {
      var t = a.length < b.length ? a : b;
      t.unshift(t[0]);
    }

    var rtn = 0;

    if (chr) {
      var chrA = a.pop();
      var chrB = b.pop();

      if (isNaN(chrA) && isNaN(chrB)) {
        rtn = this['string-' + dir](chrA, chrB);
      } else if (isNaN(chrA)) {
        rtn = dir == 'asc' ? 1 : -1;
      } else if (isNaN(chrB)) {
        rtn = dir == 'asc' ? -1 : 1;
      } else {
        rtn = this['numeric-' + dir](parseInt(chrA, 10), parseInt(chrB, 10));
      }

      if (rtn) {
        return rtn;
      }
    }

    var i = a.length;

    while (i--) {
      rtn = this['numeric-' + dir](parseInt(a[i], 10), parseInt(b[i], 10));

      if (rtn) {
        break;
      }
    }

    return rtn;
  },
  'position-asc': function (a, b) {
    return this.position('asc', a, b);
  },
  'position-desc': function (a, b) {
    return this.position('desc', a, b);
  },
  'position_html-asc': function (a, b) {
    return this.position('asc', a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  },
  'position_html-desc': function (a, b) {
    return this.position('desc', a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  },
  'string-asc': function (a, b) {
    var x = a === ' ' || a == '-' || a.toLowerCase() == 'n/a' ? 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' : a.toLowerCase();
    var y = b === ' ' || b == '-' || b.toLowerCase() == 'n/a' ? 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' : b.toLowerCase();
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  },
  'string-desc': function (a, b) {
    var x = a === ' ' || a == '-' || a.toLowerCase() == 'n/a' ? '' : a.toLowerCase();
    var y = b === ' ' || b == '-' || b.toLowerCase() == 'n/a' ? '' : b.toLowerCase();
    return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  },
  'html-asc': function (a, b) {
    return this['string-asc'](a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  },
  'html-desc': function (a, b) {
    return this['string-desc'](a.replace(/<.*?>/g, ''), b.replace(/<.*?>/g, ''));
  }
});
<|endoftext|>


<commit_before>describe('Immutable manipulations for Arrays', () => {
  test('Array Shallow copy', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples'];
    /*
     * Use the spread operaror to make a shallow copy of the fruitBasket array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;
    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
  })

  test('Immutable Append', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples'];
    /*
     * Use the spread operaror to make a shallow copy of the fruitBasket array
     * while at the same time adding a new item "Melon" to the end of the array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;
    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Melon']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
  })

  test('Immutable Prepend', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples'];
    /*
     * Use the spread operaror to make a shallow copy of the fruitBasket array
     * while at the same time adding a new item "Pineapple" to the beginning of the array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;
    expect(updatedFruitBasket).toEqual(['Pineapple', 'Oranges', 'Bananas', 'Apples']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
  })

  test('Immutable Slice', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples', 'Strawberries'];
    /*
     * Use the slice method to make a copy of the fruitBasket array
     * containing only the FIRST three items of the array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Strawberries']);
  })

  test('Immutable Slice (until the end)', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples', 'Strawberries'];
    /*
     * Use the slice method to make a copy of the fruitBasket array
     * containing only the LAST two items ('Apples' and 'Strawberries').
     * Notice that when slicing up to the end of the array, you don't need
     * to provide the second parameter to the slice method.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const redFruits = fruitBasket;

    expect(redFruits).toEqual(['Apples', 'Strawberries']);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Strawberries']);
  })

  test('Remove at specific index', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries'];
    /*
     * Use a combination of the spread operator and the slice method to make
     * a copy of the fruitBasket array containing only the fruits
     * (In other words, remove the 'sausages' entry at index 2).
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Strawberries']);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries']);
  })

  test('Substitute at specific index', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries'];
    /*
     * Use a combination of the spread operator and the slice method to make
     * a copy of the fruitBasket array updating the
     * entry at index 2 (Sausages) for 'Blueberry'.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Blueberry', 'Apples', 'Strawberries']);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries']);
  })

  test('Conditional update', () => {
    const fruitBasket = [
      {name: 'Oranges', color: 'orange', tasty: false},
      {name: 'Bananas', color: 'yellow', tasty: false},
      {name: 'Apples', color: 'red', tasty: false},
      {name: 'Strawberries', color: 'red', tasty: false}
    ];
    /*
     * The map method is also a powerful array method that always return a new array.
     * It can be used for complex immutable manipulations.
     * Use map to change the 'tasty' value to 'true' for all red fruits
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual([
      {name: 'Oranges', color: 'orange', tasty: false},
      {name: 'Bananas', color: 'yellow', tasty: false},
      {name: 'Apples', color: 'red', tasty: true},
      {name: 'Strawberries', color: 'red', tasty: true}
    ]);
    expect(fruitBasket).toEqual([
      {name: 'Oranges', color: 'orange', tasty: false},
      {name: 'Bananas', color: 'yellow', tasty: false},
      {name: 'Apples', color: 'red', tasty: false},
      {name: 'Strawberries', color: 'red', tasty: false}
    ]);
  })
});

describe('Immutable manipulations for Objects', () => {
  test('Object Shallow copy', () => {
    const state = {
      name: 'Jon Snow',
      occupation: 'Lord Commander',
      skills: [] // knows nothing...
    }

    /*
     * Use the spread operaror to make a copy of the 'state' object.
     *
     * Assign the new object to the updatedState constant.
     */

    const updatedState = state;
    expect(updatedState).toEqual({name: 'Jon Snow', occupation: 'Lord Commander', skills: []});
    expect(updatedState).not.toBe(state);
  })

  test('Immutable update', () => {
    const state = {
      name: 'Jon Snow',
      occupation: 'Lord Commander',
      skills: [] // knows nothing...
    }

    /*
     * Use the spread operaror to make a copy of the 'state' object
     * while at the same updating the value of the 'occupation' key
     * to 'King in the North'.
     *
     * Assign the new object to the updatedState constant.
     */

    const updatedState = state;
    expect(updatedState).toEqual({name: 'Jon Snow', occupation: 'King in the North', skills: []});
    expect(updatedState).not.toBe(state);
  })

  test('Immutable deep update', () => {
    const state = {
      name: 'Jon Snow',
      occupation: 'Lord Commander',
      skills: [] // knows nothing...
    }

    /*
     * Use the spread operaror to make a copy of the 'state' object
     * while at the same updating the value of the 'occupation' key
     * to 'King in the North' and adding a new item "Fighting"
     * to the skills array.
     *
     * Be aware that the spread operator makes shallow copies,
     * so if you try to add an item to the `skills` array directly,
     * you'll end up changing the original one.
     *
     * Assign the new object to the updatedState constant.
     */

    const updatedState = state;

    expect(updatedState).toEqual({
      name: 'Jon Snow', occupation: 'King in the North', skills: ['Fighting']
    });
    expect(updatedState.skills).not.toBe(state.skills);
    expect(updatedState).not.toBe(state);
  })
});

describe('Bonus', () => {
  test('Immutable maniulation using dynamic keys', () => {
    const ownedCars = {
      ferrari: true,
      porsche: false,
      shelby: false,
    };

    const recentlyBoughtCar = 'porsche';

    /*
     * Use the spread operaror to make a copy of the 'ownedCars' object
     * while at the same updating to true the value whose key is stored
     * in the 'recentlyBoughtCar' variable.
     *
     * Assign the new object to the updatedOwnedCars constant.
     */

    const updatedOwnedCars = ownedCars;
    expect(updatedOwnedCars).toEqual({
      ferrari: true, porsche: true, shelby: false
    });
    expect(updatedOwnedCars).not.toBe(ownedCars);
  })
});
<commit_msg>Added filter test<commit_after>describe('Immutable manipulations for Arrays', () => {
  test('Array Shallow copy', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples'];
    /*
     * Use the spread operaror to make a shallow copy of the fruitBasket array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;
    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
  })

  test('Immutable Append', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples'];
    /*
     * Use the spread operaror to make a shallow copy of the fruitBasket array
     * while at the same time adding a new item "Melon" to the end of the array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;
    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Melon']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
  })

  test('Immutable Prepend', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples'];
    /*
     * Use the spread operaror to make a shallow copy of the fruitBasket array
     * while at the same time adding a new item "Pineapple" to the beginning of the array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;
    expect(updatedFruitBasket).toEqual(['Pineapple', 'Oranges', 'Bananas', 'Apples']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
  })

  test('Immutable Slice', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples', 'Strawberries'];
    /*
     * Use the slice method to make a copy of the fruitBasket array
     * containing only the FIRST three items of the array.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples']);
    expect(updatedFruitBasket).not.toBe(fruitBasket);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Strawberries']);
  })

  test('Immutable Slice (until the end)', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Apples', 'Strawberries'];
    /*
     * Use the slice method to make a copy of the fruitBasket array
     * containing only the LAST two items ('Apples' and 'Strawberries').
     * Notice that when slicing up to the end of the array, you don't need
     * to provide the second parameter to the slice method.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const redFruits = fruitBasket;

    expect(redFruits).toEqual(['Apples', 'Strawberries']);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Strawberries']);
  })

  test('Remove at specific index', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries'];
    /*
     * Use a combination of the spread operator and the slice method to make
     * a copy of the fruitBasket array containing only the fruits
     * (In other words, remove the 'sausages' entry at index 2).
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Apples', 'Strawberries']);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries']);
  })

  test('Substitute at specific index', () => {
    const fruitBasket = ['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries'];
    /*
     * Use a combination of the spread operator and the slice method to make
     * a copy of the fruitBasket array updating the
     * entry at index 2 (Sausages) for 'Blueberry'.
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual(['Oranges', 'Bananas', 'Blueberry', 'Apples', 'Strawberries']);
    expect(fruitBasket).toEqual(['Oranges', 'Bananas', 'Sausages', 'Apples', 'Strawberries']);
  })

  test('Filtering', () => {
    const fruitBasket = [
      {name: 'Oranges', tasty: true},
      {name: 'Bananas', tasty: true},
      {name: 'NastyBerry', tasty: false},
      {name: 'Strawberries', tasty: true}
    ];
    /*
     * Use the array's filter method to create a new array
     * containing only "tasty" fruits
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual([
      {name: 'Oranges', tasty: true},
      {name: 'Bananas', tasty: true},
      {name: 'Strawberries', tasty: true}
    ]);
    expect(fruitBasket).toEqual([
      {name: 'Oranges', tasty: true},
      {name: 'Bananas', tasty: true},
      {name: 'NastyBerry', tasty: false},
      {name: 'Strawberries', tasty: true}
    ]);
  })

  test('Conditional update', () => {
    const fruitBasket = [
      {name: 'Oranges', color: 'orange', tasty: false},
      {name: 'Bananas', color: 'yellow', tasty: false},
      {name: 'Apples', color: 'red', tasty: false},
      {name: 'Strawberries', color: 'red', tasty: false}
    ];
    /*
     * The map method is also a powerful array method that always return a new array.
     * It can be used for complex immutable manipulations.
     * Use map to change the 'tasty' value to 'true' for all red fruits
     *
     * Assign the new array to the updatedFruitBasket constant.
     */
    const updatedFruitBasket = fruitBasket;

    expect(updatedFruitBasket).toEqual([
      {name: 'Oranges', color: 'orange', tasty: false},
      {name: 'Bananas', color: 'yellow', tasty: false},
      {name: 'Apples', color: 'red', tasty: true},
      {name: 'Strawberries', color: 'red', tasty: true}
    ]);
    expect(fruitBasket).toEqual([
      {name: 'Oranges', color: 'orange', tasty: false},
      {name: 'Bananas', color: 'yellow', tasty: false},
      {name: 'Apples', color: 'red', tasty: false},
      {name: 'Strawberries', color: 'red', tasty: false}
    ]);
  })
});

describe('Immutable manipulations for Objects', () => {
  test('Object Shallow copy', () => {
    const state = {
      name: 'Jon Snow',
      occupation: 'Lord Commander',
      skills: [] // knows nothing...
    }

    /*
     * Use the spread operaror to make a copy of the 'state' object.
     *
     * Assign the new object to the updatedState constant.
     */

    const updatedState = state;
    expect(updatedState).toEqual({name: 'Jon Snow', occupation: 'Lord Commander', skills: []});
    expect(updatedState).not.toBe(state);
  })

  test('Immutable update', () => {
    const state = {
      name: 'Jon Snow',
      occupation: 'Lord Commander',
      skills: [] // knows nothing...
    }

    /*
     * Use the spread operaror to make a copy of the 'state' object
     * while at the same updating the value of the 'occupation' key
     * to 'King in the North'.
     *
     * Assign the new object to the updatedState constant.
     */

    const updatedState = state;
    expect(updatedState).toEqual({name: 'Jon Snow', occupation: 'King in the North', skills: []});
    expect(updatedState).not.toBe(state);
  })

  test('Immutable deep update', () => {
    const state = {
      name: 'Jon Snow',
      occupation: 'Lord Commander',
      skills: [] // knows nothing...
    }

    /*
     * Use the spread operaror to make a copy of the 'state' object
     * while at the same updating the value of the 'occupation' key
     * to 'King in the North' and adding a new item "Fighting"
     * to the skills array.
     *
     * Be aware that the spread operator makes shallow copies,
     * so if you try to add an item to the `skills` array directly,
     * you'll end up changing the original one.
     *
     * Assign the new object to the updatedState constant.
     */

    const updatedState = state;

    expect(updatedState).toEqual({
      name: 'Jon Snow', occupation: 'King in the North', skills: ['Fighting']
    });
    expect(updatedState.skills).not.toBe(state.skills);
    expect(updatedState).not.toBe(state);
  })
});

describe('Bonus', () => {
  test('Immutable maniulation using dynamic keys', () => {
    const ownedCars = {
      ferrari: true,
      porsche: false,
      shelby: false,
    };

    const recentlyBoughtCar = 'porsche';

    /*
     * Use the spread operaror to make a copy of the 'ownedCars' object
     * while at the same updating to true the value whose key is stored
     * in the 'recentlyBoughtCar' variable.
     *
     * Assign the new object to the updatedOwnedCars constant.
     */

    const updatedOwnedCars = ownedCars;
    expect(updatedOwnedCars).toEqual({
      ferrari: true, porsche: true, shelby: false
    });
    expect(updatedOwnedCars).not.toBe(ownedCars);
  })
});
<|endoftext|>