<commit_before>import React from "react";

function randomFromList(list) {
  if (!list) return;
  const length = list.length;
  const index = Math.floor(Math.random() * length);
  return list[index];
}

const ScanPresets = ({ onChange, domain, ...props }) => {
  const handleChange = evt => {
    let dataField = evt.target.value;
    if (dataField === "omnicourse") {
      dataField = `Course Calculated:
      X: ${Math.round(Math.random() * 100000) / 100}
      Y: ${Math.round(Math.random() * 100000) / 100}
      Z: ${Math.round(Math.random() * 100000) / 100}`;
    }
    if (dataField === "weakness") {
      dataField = `Fault in ${randomFromList([
        "engines",
        "shields",
        "weapons",
        "hull",
        "sensors",
        "communications",
        "tractor beam"
      ])} detected.`;
    }
    if (dataField === "thrusterdodge") {
      dataField = `Incoming weapons detected. Recommend firing ${randomFromList(
        ["port", "starboard", "forward", "reverse", "up", "down"]
      )} thrusters to dodge.`;
    }
    onChange(dataField);
  };
  React.useEffect(() => {
    const keypress = evt => {
      if (evt.altKey) {
        evt.preventDefault();
        const index = parseInt(evt.code.substr(-1, 1), 10);
        if (!isNaN(index)) {
          const data =
            index === 0 ? ScanPresets()[10] : ScanPresets()[index - 1];
          this.scanPreset({ target: { value: data.value } });
        }
      }
    };
    document.addEventListener("keydown", keypress);
    return () => document.removeEventListener("keydown", keypress);
  }, []);

  return (
    <select value={"answers"} onChange={handleChange} {...props}>
      <option value={"answers"} disabled>
        Answers
      </option>
      {getPresetOptions(domain).map(p => (
        <option key={p.label} value={p.value}>
          {p.label}
        </option>
      ))}
    </select>
  );
};
export default ScanPresets;

const getPresetOptions = which =>
  [
    { label: "None detected.", value: "None detected." },
    {
      label: "Specify",
      value: "Please specify what you wish to scan for."
    },
    {
      label: "Does not compute",
      value: "The scan does not compute - Please restate or rephrase."
    },
    {
      label: "Unknown",
      value: "Request is unknown or ambiguous. Please restate or clarify."
    },
    {
      label: "Omni course",
      value: "omnicourse"
    },

    {
      label: "Eta",
      value:
        "At current speed this vessel will reach its destination in **minutes, **seconds."
    },
    {
      label: "Destination",
      value: "Now approaching destination. Recommend slowing to Full Stop."
    },
    { label: "Detected.", value: "Detected." },
    {
      label: "None in range",
      value: "None detected within sensor range."
    },
    {
      label: "External sensors offline",
      value: "Unable to complete scan. External sensors are offline."
    },
    { label: "Invalid", value: "Invalid search query." },
    {
      label: "No probe",
      value: "Unable to complete scan.  No probe has been launched."
    },
    {
      label: "Ship not in range",
      value: "Unable to complete scan. Ship is not within range."
    },
    {
      label: "Radiation interference",
      value: "Radiation is interfering with sensors.  Unable to complete scan."
    },
    {
      label: "Scanning...",
      value: "Scanning... Results will be displayed on the main view screen."
    },
    {
      label: "Sensors damaged",
      value: "Sensor systems have been damaged.  Unable to complete scan."
    },
    {
      label: "Which contact.",
      value: "Please specify which contact you wish to scan."
    },
    {
      label: "Thruster Dodge",
      value: "thrusterdodge"
    },
    {
      label: "Undocking Instructions",
      value:
        "This vessel is currently docked. The Boarding Ramps and the Docking Clamps must be retracted before the Thrusters can be used to undock."
    },
    {
      label: "Undocking Completed",
      value:
        "This vessel has successfully undocked. It is recommended to calculate a course to our destination."
    },
    {
      label: "Asteroids",
      value:
        "Asteroids detected in the area. It is recommended that Thrusters be used to dodge asteroids. The weapon systems can be used to destroy incoming projectiles before impact."
    },
    {
      label: "On Course",
      value: "Now on course "
    },
    {
      label: "Weakness",
      value: "weakness"
    },
    which && {
      label: `Use ${which === "internal" ? "External" : "Internal"}`,
      value: `Unable to complete scan. Recommend using ${
        which === "internal" ? "External" : "Internal"
      } Sensors.`
    }
  ].filter(Boolean);
<commit_msg>fix(Sensor Scans): Fixes the alt-key scan preset hotkey. Closes #2426<commit_after>import React from "react";

function randomFromList(list) {
  if (!list) return;
  const length = list.length;
  const index = Math.floor(Math.random() * length);
  return list[index];
}

const ScanPresets = ({ onChange = () => {}, domain, ...props }) => {
  const handleChange = React.useCallback(
    evt => {
      let dataField = evt.target.value;
      if (dataField === "omnicourse") {
        dataField = `Course Calculated:
      X: ${Math.round(Math.random() * 100000) / 100}
      Y: ${Math.round(Math.random() * 100000) / 100}
      Z: ${Math.round(Math.random() * 100000) / 100}`;
      }
      if (dataField === "weakness") {
        dataField = `Fault in ${randomFromList([
          "engines",
          "shields",
          "weapons",
          "hull",
          "sensors",
          "communications",
          "tractor beam"
        ])} detected.`;
      }
      if (dataField === "thrusterdodge") {
        dataField = `Incoming weapons detected. Recommend firing ${randomFromList(
          ["port", "starboard", "forward", "reverse", "up", "down"]
        )} thrusters to dodge.`;
      }
      onChange(dataField);
    },
    [onChange]
  );
  React.useEffect(() => {
    const keypress = evt => {
      if (evt.altKey) {
        evt.preventDefault();
        const index = parseInt(evt.code.substr(-1, 1), 10);
        if (!isNaN(index)) {
          const data =
            index === 0
              ? getPresetOptions(domain)[10]
              : getPresetOptions(domain)[index - 1];
          handleChange({ target: { value: data.value } });
        }
      }
    };
    document.addEventListener("keydown", keypress);
    return () => document.removeEventListener("keydown", keypress);
  }, [domain, handleChange]);

  return (
    <select value={"answers"} onChange={handleChange} {...props}>
      <option value={"answers"} disabled>
        Answers
      </option>
      {getPresetOptions(domain).map(p => (
        <option key={p.label} value={p.value}>
          {p.label}
        </option>
      ))}
    </select>
  );
};
export default ScanPresets;

const getPresetOptions = which =>
  [
    { label: "None detected.", value: "None detected." },
    {
      label: "Specify",
      value: "Please specify what you wish to scan for."
    },
    {
      label: "Does not compute",
      value: "The scan does not compute - Please restate or rephrase."
    },
    {
      label: "Unknown",
      value: "Request is unknown or ambiguous. Please restate or clarify."
    },
    {
      label: "Omni course",
      value: "omnicourse"
    },

    {
      label: "Eta",
      value:
        "At current speed this vessel will reach its destination in **minutes, **seconds."
    },
    {
      label: "Destination",
      value: "Now approaching destination. Recommend slowing to Full Stop."
    },
    { label: "Detected.", value: "Detected." },
    {
      label: "None in range",
      value: "None detected within sensor range."
    },
    {
      label: "External sensors offline",
      value: "Unable to complete scan. External sensors are offline."
    },
    { label: "Invalid", value: "Invalid search query." },
    {
      label: "No probe",
      value: "Unable to complete scan.  No probe has been launched."
    },
    {
      label: "Ship not in range",
      value: "Unable to complete scan. Ship is not within range."
    },
    {
      label: "Radiation interference",
      value: "Radiation is interfering with sensors.  Unable to complete scan."
    },
    {
      label: "Scanning...",
      value: "Scanning... Results will be displayed on the main view screen."
    },
    {
      label: "Sensors damaged",
      value: "Sensor systems have been damaged.  Unable to complete scan."
    },
    {
      label: "Which contact.",
      value: "Please specify which contact you wish to scan."
    },
    {
      label: "Thruster Dodge",
      value: "thrusterdodge"
    },
    {
      label: "Undocking Instructions",
      value:
        "This vessel is currently docked. The Boarding Ramps and the Docking Clamps must be retracted before the Thrusters can be used to undock."
    },
    {
      label: "Undocking Completed",
      value:
        "This vessel has successfully undocked. It is recommended to calculate a course to our destination."
    },
    {
      label: "Asteroids",
      value:
        "Asteroids detected in the area. It is recommended that Thrusters be used to dodge asteroids. The weapon systems can be used to destroy incoming projectiles before impact."
    },
    {
      label: "On Course",
      value: "Now on course "
    },
    {
      label: "Weakness",
      value: "weakness"
    },
    which && {
      label: `Use ${which === "internal" ? "External" : "Internal"}`,
      value: `Unable to complete scan. Recommend using ${
        which === "internal" ? "External" : "Internal"
      } Sensors.`
    }
  ].filter(Boolean);
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Concept
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*****************************************************************************/
/* DownloadListTable: Helpers */
/*****************************************************************************/

Template.DownloadList.helpers({
  getData: function(id, options) {
    var report = Router._currentController && Router._currentController.data && Router._currentController.data();
    if(options.hash && options.hash.parent && options.hash.parent.type) {
      if (options.hash.parent.type === 'images') {
        if(report && report.images){
            var img_data = _.find(report.images, function(img){ return img.fileId == id; });

            return _.extend(this, img_data);
        }
        return this;
      } else if (options.hash.parent.type === 'files') {
        if(report && report.references){
            var ref_data = _.find(report.references, function(ref){ return ref.fileId == id; });

            return _.extend(this, ref_data);
        }
        return this;
      }
    }
    return null;
  },

  // TODO: fix bad code
  // Runs for every image file in list, each time uploadObject changes
  getUrl: function(img, store) {
    uploadObject.dep.depend();

    if (img) {
      if (store) {
        return img.url(store);
      }
      else
        return img.url();
    }
    return null;
  },

  fileName: function() {
    var len = 20;
    var file = this;

    if(file) {
      var oldName = file.name();

      var ext = oldName.substring(oldName.lastIndexOf(".") + 1, oldName.length).toLowerCase();
      var filename = oldName.replace('.' + ext, '');

      // If the cut-length specified do not affect the filename, return the old filename
      if(filename.length <= len) {
          return oldName;
      }

      // Cut the string and append [...] if the name actually got sliced.
      filename = filename.substr(0, len) + (oldName.length > len ? '[...]' : '');

      // Return the filename with the correct extension
      return filename + '.' + ext;
    }

    return "";
  },

  isChoosenasMainResource: function(resource) {
    return uploadObject.getImages().indexOf(resource) === 0;
  }
});

Template.DownloadList.events({
  'click .set-main-img': function (evt, tmpl) {
    uploadObject.setAsMainImg(this.fileId);
  }
});
<commit_msg>Fixes choose main image bug. fixes #106<commit_after>/*
 * Copyright 2015 Concept
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*****************************************************************************/
/* DownloadListTable: Helpers */
/*****************************************************************************/

Template.DownloadList.helpers({
  getData: function(id, options) {
    var report = Router._currentController && Router._currentController.data && Router._currentController.data();
    if(options.hash && options.hash.parent && options.hash.parent.type) {
      if (options.hash.parent.type === 'images') {
        if(report && report.images){
            var img_data = _.find(report.images, function(img){ return img.fileId == id; });

            return _.extend(this, img_data);
        }
        return this;
      } else if (options.hash.parent.type === 'files') {
        if(report && report.references){
            var ref_data = _.find(report.references, function(ref){ return ref.fileId == id; });

            return _.extend(this, ref_data);
        }
        return this;
      }
    }
    return null;
  },

  // TODO: fix bad code
  // Runs for every image file in list, each time uploadObject changes
  getUrl: function(img, store) {
    uploadObject.dep.depend();

    if (img) {
      if (store) {
        return img.url(store);
      }
      else
        return img.url();
    }
    return null;
  },

  fileName: function() {
    var len = 20;
    var file = this;

    if(file) {
      var oldName = file.name();

      var ext = oldName.substring(oldName.lastIndexOf(".") + 1, oldName.length).toLowerCase();
      var filename = oldName.replace('.' + ext, '');

      // If the cut-length specified do not affect the filename, return the old filename
      if(filename.length <= len) {
          return oldName;
      }

      // Cut the string and append [...] if the name actually got sliced.
      filename = filename.substr(0, len) + (oldName.length > len ? '[...]' : '');

      // Return the filename with the correct extension
      return filename + '.' + ext;
    }

    return "";
  },

  isChoosenasMainResource: function(resource) {
    return uploadObject.getImages().indexOf(resource) === 0;
  }
});

Template.DownloadList.events({
  'click .set-main-img': function (evt, tmpl) {
    uploadObject.setAsMainImg(this.fileId || this._id);
  }
});
<|endoftext|>


<commit_before>'use strict';

import React from 'react/addons';

import classNames from 'classnames';

import Icon from './Icon.js';
import TimeFormatter from './TimeFormatter.js';
import GroupAttributes from './GroupAttributes.js';
import ArtworkImage from './ArtworkImage.js';

import CollectionStore from '../stores/CollectionStore.js';
import CollectionActions from '../actions/CollectionActions.js';

import PlaylistStore from '../stores/PlaylistStore.js';
import PlaylistActions from '../actions/PlaylistActions.js';

import NowPlayingStore from '../stores/NowPlayingStore.js';

export default class Playlist extends React.Component {
  constructor(props) {
    super(props);

    this.state = {list: PlaylistStore.getPlaylist()};
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    PlaylistStore.addChangeListener(this._onChange);
  }

  componentWillUnmount() {
    PlaylistStore.removeChangeListener(this._onChange);
  }

  render() {
    var rootCount = {};
    var items = this.state.list.map(function(item, i) {
      if (!rootCount[item.root]) {
        rootCount[item.root] = 0;
      }
      rootCount[item.root]++;
      return <RootGroup path={item.root} key={item.root+rootCount[item.root]} itemIndex={i} />;
    });

    return (

        {items}

    );
  }

  _onChange() {
    this.setState({list: PlaylistStore.getPlaylist()});
  }
}

function getItem(path) {
  var c = CollectionStore.getCollection(path);
  if (c === undefined) {
    return null;
  }
  return c;
}

function getRootGroupState(props) {
  return {item: getItem(props.path)};
}

class RootGroup extends React.Component {
  constructor(props) {
    super(props);

    this.state = getRootGroupState(this.props);
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    CollectionStore.addChangeListener(this._onChange);
    CollectionActions.fetch(this.props.path);
  }

  componentWillUnmount() {
    CollectionStore.removeChangeListener(this._onChange);
  }

  render() {
    if (this.state.item === null) {
      return null;
    }

    return (
      <Group item={this.state.item} path={this.props.path} itemIndex={this.props.itemIndex} />
    );
  }

  _onChange(keyPath) {
    if (CollectionStore.pathToKey(this.props.path) === keyPath) {
       this.setState(getRootGroupState(this.props));
    }
  }
}

RootGroup.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired
};

class Group extends React.Component {
  constructor(props) {
    super(props);

    this.state = {expanded: true, common: {}};
    this.setCommon = this.setCommon.bind(this);
    this._onClick = this._onClick.bind(this);
    this._onClickRemove = this._onClickRemove.bind(this);
  }

  setCommon(c) {
    this.setState({common: c});
  }

  render() {
    var groupClasses = {
      'group': true,
      'expanded': this.state.expanded
    };

    var image = null;
    if (this.state.common.TrackID) {
      image = <ArtworkImage path={"/artwork/" + this.state.common.TrackID} />;
    }

    var duration = null;
    if (this.state.common.TotalTime) {
      duration = <TimeFormatter className="duration" time={parseInt(this.state.common.TotalTime/1000)} />;
    }

    var common = this.state.common;
    var fields = ['Artist', 'Composer', 'Year'];
    var attributeArr = [];
    fields.forEach(function(f) {
      if (common[f]) {
        attributeArr.push(common[f]);
      }
    });

    var attributes = null;
    if (attributeArr.length > 0) {
      attributes = <GroupAttributes list={attributeArr} />;
    }

    var content = null;
    if (this.state.expanded) {
      content = <GroupContent path={this.props.path} setCommon={this.setCommon} itemIndex={this.props.itemIndex} />;
    }

    return (

        {image}

{this.props.item.Name}

              {attributes}

{duration}

              <Icon icon="remove" onClick={this._onClickRemove} />

        {content}

    );
  }

  _onClickRemove(e) {
    e.stopPropagation();
    PlaylistActions.remove(this.props.itemIndex, this.props.path);
  }

  _onClick() {
    this.setState({expanded: !this.state.expanded});
  }
}

Group.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired,
  item: React.PropTypes.object.isRequired
};

class GroupContent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {item: null};
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    CollectionStore.addChangeListener(this._onChange);
    CollectionActions.fetch(this.props.path);
  }

  componentWillUnmount() {
    CollectionStore.removeChangeListener(this._onChange);
  }

  render() {
    var item = this.state.item;
    if (item === null) {
      return null;
    }

    var pathKeys = PlaylistStore.getItemKeys(this.props.itemIndex, this.props.path);
    if (item.Groups) {
      return <GroupList path={this.props.path} list={item.Groups} itemIndex={this.props.itemIndex} keys={pathKeys.keys} />;
    }
    return <TrackList path={this.props.path} list={item.Tracks} listStyle={item.ListStyle} itemIndex={this.props.itemIndex} keys={pathKeys.keys} />;
  }

  _onChange(keyPath) {
    if (CollectionStore.pathToKey(this.props.path) === keyPath) {
      var item = CollectionStore.getCollection(this.props.path);

      var common = {};
      var fields = ['TotalTime', 'Artist', 'Composer', 'TrackID', 'Year'];
      fields.forEach(function(f) {
        if (item[f]) {
          common[f] = item[f];
        }
      });

      if (Object.keys(common).length > 0) {
        this.props.setCommon(common);
      }
      this.setState({item: item});
    }
  }
}

GroupContent.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired,
};

class GroupList extends React.Component {
  render() {
    var keys = this.props.keys;
    var list = this.props.list;

    var itemByKey = {};
    list.forEach(function(item) {
      itemByKey[item.Key] = item;
    });

    var groups = keys.map(function(key) {
      return <Group path={this.props.path.concat([key])} key={key} item={itemByKey[key]} itemIndex={this.props.itemIndex} />;
    }.bind(this));

    return (

        {groups}

    );
  }
}

GroupList.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired,
  keys: React.PropTypes.array.isRequired
};

class TrackList extends React.Component {
  render() {
    var list = this.props.list;
    var keys = this.props.keys;
    var tracks = keys.map(function(i) {
      return <Track key={list[i].TrackID} data={list[i]} path={this.props.path.concat([i])} itemIndex={this.props.itemIndex} index={i} />;
    }.bind(this));

    return (

          {tracks}

    );
  }
}

TrackList.propTypes = {
  itemIndex: React.PropTypes.number.isRequired,
  path: React.PropTypes.array.isRequired,
  list: React.PropTypes.array.isRequired,
  keys: React.PropTypes.array.isRequired,
  listStyle: React.PropTypes.string.isRequired,
};

function pathsEqual(p1, p2) {
  return CollectionStore.pathToKey(p1) === CollectionStore.pathToKey(p2);
}

function isCurrent(i, p) {
  var c = PlaylistStore.getCurrent();
  if (c === null) {
    return false;
  }
  return pathsEqual(c.path, p) && (i === c.item);
}

function isPlaying(trackId) {
  var playing = NowPlayingStore.getPlaying();
  if (!playing) {
    return false;
  }

  var t = NowPlayingStore.getTrack();
  if (t) {
    return t.TrackID === trackId;
  }
  return false;
}

function getTrackState(props) {
  return {
    isCurrent: isCurrent(props.itemIndex, props.path),
    isPlaying: isPlaying(props.data.TrackID)
  };
}

class Track extends React.Component {
  constructor(props) {
    super(props);

    this.state = getTrackState(this.props);
    this._onClick = this._onClick.bind(this);
    this._onClickRemove = this._onClickRemove.bind(this);
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    PlaylistStore.addChangeListener(this._onChange);
    NowPlayingStore.addChangeListener(this._onChange);
  }

  componentWillUnmount() {
    PlaylistStore.removeChangeListener(this._onChange);
    NowPlayingStore.removeChangeListener(this._onChange);
  }

  render() {
    var durationSecs = parseInt(this.props.data.TotalTime/1000);
    var style = {
      current: this.state.isCurrent,
      'is-playing': this.state.isPlaying,
    };

    return (

        {this.props.data.Name}

          <Icon icon="remove" onClick={this._onClickRemove} />
          <TimeFormatter className="duration" time={durationSecs} />

    );
  }

  _onClick() {
    PlaylistActions.play(this.props.itemIndex, this.props.path, this.props.data);
  }

  _onClickRemove(e) {
    e.stopPropagation();
    PlaylistActions.remove(this.props.itemIndex, this.props.path);
  }

  _onChange() {
    this.setState(getTrackState(this.props));
  }
}

Track.propTypes = {
  itemIndex: React.PropTypes.number.isRequired,
  index: React.PropTypes.number.isRequired,
  path: React.PropTypes.array.isRequired
};
<commit_msg>Don't use the class collection on a playlist group<commit_after>'use strict';

import React from 'react/addons';

import classNames from 'classnames';

import Icon from './Icon.js';
import TimeFormatter from './TimeFormatter.js';
import GroupAttributes from './GroupAttributes.js';
import ArtworkImage from './ArtworkImage.js';

import CollectionStore from '../stores/CollectionStore.js';
import CollectionActions from '../actions/CollectionActions.js';

import PlaylistStore from '../stores/PlaylistStore.js';
import PlaylistActions from '../actions/PlaylistActions.js';

import NowPlayingStore from '../stores/NowPlayingStore.js';

export default class Playlist extends React.Component {
  constructor(props) {
    super(props);

    this.state = {list: PlaylistStore.getPlaylist()};
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    PlaylistStore.addChangeListener(this._onChange);
  }

  componentWillUnmount() {
    PlaylistStore.removeChangeListener(this._onChange);
  }

  render() {
    var rootCount = {};
    var items = this.state.list.map(function(item, i) {
      if (!rootCount[item.root]) {
        rootCount[item.root] = 0;
      }
      rootCount[item.root]++;
      return <RootGroup path={item.root} key={item.root+rootCount[item.root]} itemIndex={i} />;
    });

    return (

        {items}

    );
  }

  _onChange() {
    this.setState({list: PlaylistStore.getPlaylist()});
  }
}

function getItem(path) {
  var c = CollectionStore.getCollection(path);
  if (c === undefined) {
    return null;
  }
  return c;
}

function getRootGroupState(props) {
  return {item: getItem(props.path)};
}

class RootGroup extends React.Component {
  constructor(props) {
    super(props);

    this.state = getRootGroupState(this.props);
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    CollectionStore.addChangeListener(this._onChange);
    CollectionActions.fetch(this.props.path);
  }

  componentWillUnmount() {
    CollectionStore.removeChangeListener(this._onChange);
  }

  render() {
    if (this.state.item === null) {
      return null;
    }

    return (
      <Group item={this.state.item} path={this.props.path} itemIndex={this.props.itemIndex} />
    );
  }

  _onChange(keyPath) {
    if (CollectionStore.pathToKey(this.props.path) === keyPath) {
       this.setState(getRootGroupState(this.props));
    }
  }
}

RootGroup.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired
};

class Group extends React.Component {
  constructor(props) {
    super(props);

    this.state = {expanded: true, common: {}};
    this.setCommon = this.setCommon.bind(this);
    this._onClick = this._onClick.bind(this);
    this._onClickRemove = this._onClickRemove.bind(this);
  }

  setCommon(c) {
    this.setState({common: c});
  }

  render() {
    var groupClasses = {
      'group': true,
      'expanded': this.state.expanded
    };

    var image = null;
    if (this.state.common.TrackID) {
      image = <ArtworkImage path={"/artwork/" + this.state.common.TrackID} />;
    }

    var duration = null;
    if (this.state.common.TotalTime) {
      duration = <TimeFormatter className="duration" time={parseInt(this.state.common.TotalTime/1000)} />;
    }

    var common = this.state.common;
    var fields = ['Artist', 'Composer', 'Year'];
    var attributeArr = [];
    fields.forEach(function(f) {
      if (common[f]) {
        attributeArr.push(common[f]);
      }
    });

    var attributes = null;
    if (attributeArr.length > 0) {
      attributes = <GroupAttributes list={attributeArr} />;
    }

    var content = null;
    if (this.state.expanded) {
      content = <GroupContent path={this.props.path} setCommon={this.setCommon} itemIndex={this.props.itemIndex} />;
    }

    return (

        {image}

{this.props.item.Name}

              {attributes}

{duration}

              <Icon icon="remove" onClick={this._onClickRemove} />

        {content}

    );
  }

  _onClickRemove(e) {
    e.stopPropagation();
    PlaylistActions.remove(this.props.itemIndex, this.props.path);
  }

  _onClick() {
    this.setState({expanded: !this.state.expanded});
  }
}

Group.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired,
  item: React.PropTypes.object.isRequired
};

class GroupContent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {item: null};
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    CollectionStore.addChangeListener(this._onChange);
    CollectionActions.fetch(this.props.path);
  }

  componentWillUnmount() {
    CollectionStore.removeChangeListener(this._onChange);
  }

  render() {
    var item = this.state.item;
    if (item === null) {
      return null;
    }

    var pathKeys = PlaylistStore.getItemKeys(this.props.itemIndex, this.props.path);
    if (item.Groups) {
      return <GroupList path={this.props.path} list={item.Groups} itemIndex={this.props.itemIndex} keys={pathKeys.keys} />;
    }
    return <TrackList path={this.props.path} list={item.Tracks} listStyle={item.ListStyle} itemIndex={this.props.itemIndex} keys={pathKeys.keys} />;
  }

  _onChange(keyPath) {
    if (CollectionStore.pathToKey(this.props.path) === keyPath) {
      var item = CollectionStore.getCollection(this.props.path);

      var common = {};
      var fields = ['TotalTime', 'Artist', 'Composer', 'TrackID', 'Year'];
      fields.forEach(function(f) {
        if (item[f]) {
          common[f] = item[f];
        }
      });

      if (Object.keys(common).length > 0) {
        this.props.setCommon(common);
      }
      this.setState({item: item});
    }
  }
}

GroupContent.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired,
};

class GroupList extends React.Component {
  render() {
    var keys = this.props.keys;
    var list = this.props.list;

    var itemByKey = {};
    list.forEach(function(item) {
      itemByKey[item.Key] = item;
    });

    var groups = keys.map(function(key) {
      return <Group path={this.props.path.concat([key])} key={key} item={itemByKey[key]} itemIndex={this.props.itemIndex} />;
    }.bind(this));

    return (

        {groups}

    );
  }
}

GroupList.propTypes = {
  path: React.PropTypes.array.isRequired,
  itemIndex: React.PropTypes.number.isRequired,
  keys: React.PropTypes.array.isRequired
};

class TrackList extends React.Component {
  render() {
    var list = this.props.list;
    var keys = this.props.keys;
    var tracks = keys.map(function(i) {
      return <Track key={list[i].TrackID} data={list[i]} path={this.props.path.concat([i])} itemIndex={this.props.itemIndex} index={i} />;
    }.bind(this));

    return (

          {tracks}

    );
  }
}

TrackList.propTypes = {
  itemIndex: React.PropTypes.number.isRequired,
  path: React.PropTypes.array.isRequired,
  list: React.PropTypes.array.isRequired,
  keys: React.PropTypes.array.isRequired,
  listStyle: React.PropTypes.string.isRequired,
};

function pathsEqual(p1, p2) {
  return CollectionStore.pathToKey(p1) === CollectionStore.pathToKey(p2);
}

function isCurrent(i, p) {
  var c = PlaylistStore.getCurrent();
  if (c === null) {
    return false;
  }
  return pathsEqual(c.path, p) && (i === c.item);
}

function isPlaying(trackId) {
  var playing = NowPlayingStore.getPlaying();
  if (!playing) {
    return false;
  }

  var t = NowPlayingStore.getTrack();
  if (t) {
    return t.TrackID === trackId;
  }
  return false;
}

function getTrackState(props) {
  return {
    isCurrent: isCurrent(props.itemIndex, props.path),
    isPlaying: isPlaying(props.data.TrackID)
  };
}

class Track extends React.Component {
  constructor(props) {
    super(props);

    this.state = getTrackState(this.props);
    this._onClick = this._onClick.bind(this);
    this._onClickRemove = this._onClickRemove.bind(this);
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    PlaylistStore.addChangeListener(this._onChange);
    NowPlayingStore.addChangeListener(this._onChange);
  }

  componentWillUnmount() {
    PlaylistStore.removeChangeListener(this._onChange);
    NowPlayingStore.removeChangeListener(this._onChange);
  }

  render() {
    var durationSecs = parseInt(this.props.data.TotalTime/1000);
    var style = {
      current: this.state.isCurrent,
      'is-playing': this.state.isPlaying,
    };

    return (

        {this.props.data.Name}

          <Icon icon="remove" onClick={this._onClickRemove} />
          <TimeFormatter className="duration" time={durationSecs} />

    );
  }

  _onClick() {
    PlaylistActions.play(this.props.itemIndex, this.props.path, this.props.data);
  }

  _onClickRemove(e) {
    e.stopPropagation();
    PlaylistActions.remove(this.props.itemIndex, this.props.path);
  }

  _onChange() {
    this.setState(getTrackState(this.props));
  }
}

Track.propTypes = {
  itemIndex: React.PropTypes.number.isRequired,
  index: React.PropTypes.number.isRequired,
  path: React.PropTypes.array.isRequired
};
<|endoftext|>


<commit_before>module.exports = {
  purge: {
    mode: 'all',
    content: ['./src/**/*.html', './src/**/*.svelte', './src/**/*.vue', './src/**/*.jsx'],
    options: {
      whitelistPatterns: [/mapboxgl/, /svelte-/, /.sparkline--/]
    }
  },
  theme: {
    extend: {
      screens: {
        'print': { 'raw': 'print' }
      }
    }
  },
  variants: {},
  plugins: []
}
<commit_msg>ignore sparkline style<commit_after>module.exports = {
  purge: {
    mode: 'all',
    content: ['./src/**/*.html', './src/**/*.svelte', './src/**/*.vue', './src/**/*.jsx'],
    options: {
      whitelistPatterns: [/mapboxgl/, /svelte-/, /sparkline--/]
    }
  },
  theme: {
    extend: {
      screens: {
        'print': { 'raw': 'print' }
      }
    }
  },
  variants: {},
  plugins: []
}
<|endoftext|>


<commit_before>define(["cilantro/define/viewelement"],
    function(ViewElement) {

    // browser refers to the div on screen where the concept will be displayed
    var VocabBrowser = ViewElement.extend({

        constructor: function(viewset, concept_pk) {
            this.base(viewset, concept_pk);
            this.ds =  [];
        },

        render: function(){
            var objRef = this;

            var pk = this.pk = this.concept_pk + '_' + this.viewset.pk;
            var dom = this.dom = $($.jqote(VocabBrowser.vocabBrowserTemplate, this.viewset));
            var tabs = $('.tabs', dom);
            var choices = this.choices = $('.choices', dom);
            var selected = this.selected = $('.selected', dom);
            var search = this.search = $('.search', dom);
            var results = this.results = $('.results', dom);
            var breadcrumbs = this.breadcrumbs = $('.breadcrumbs', dom);

            // enable tabs, we use a very barebones tabs implementation
            // the core code only adds the appropriate classes to selected
            // and non-selected tabs, represented by  elements.
            tabs.tabs(false, function (evt, tab) {
                var siblings = tabs.find('.tab')
                // hide everything
                siblings.each(function(i, o) {
                    $(o.hash, objRef.dom).hide();
                });

                // get the current on and show it
                $(tab.attr('hash'), objRef.dom).show();
            });

            // breadcrumb navigation
            breadcrumbs.delegate('a', 'click', function(){
                objRef.reloadBrowser($(this).attr('href'));
                return false;
            });

            function addItem(evt) {
                var target = $(this).parent();
                objRef.addNode(target.data());
                return false;
            }

            // add item from available choices
            choices.delegate('button', 'click', addItem);
            results.delegate('button', 'click', addItem);

            function linkItem(evt) {
                var item = $(this);
                var li = item.parents('li');

                // switch to the browse tab
                tabs.tabs('toggle', 0);

                // reload the browser with the item's url
                objRef.reloadBrowser(item.attr('href'), function() {

                    // get the corresponding list item in the browser
                    var target = $('[data-id='+li.data('id')+']', objRef.choices);

                    // scroll down to the referenced item since this page
                    // represents this item's parent.
                    objRef.choices.scrollTo(target, 500, {
                        offset: -150,
                        onAfter: function() {
                            // add highlight effect to ensure the user sees the
                            // location of the item
                            target.effect('highlight', null, 2000);
                        }
                    });

                });
                return false;
            };

            // handler for clicking on search results, they take the user
            // to the location of the item in the browser since to provide
            // more context
            results.delegate('a', 'click', linkItem);
            selected.delegate('a', 'click', linkItem);

            // descend in hierarchy
            choices.delegate('.folder', 'click', function() {
                objRef.reloadBrowser($(this).data('uri'));
                return false;
            });

            // remove item from selected items
            selected.delegate('button', 'click', function() {
                var target = $(this);
                var li = target.parent();
                objRef.removeNode(li.data());
                li.remove();
                return false;
            });

            this.execute();
        },

        execute: function(){
            var objRef = this;
            var results = this.results;

            // Setup the browser
            this.reloadBrowser();

            // Setup the search
            this.search.autocomplete2({
                start: function() {
                    results.block();
                },
                success: function(query, resp) {
                    results.empty();

                    // no results
                    if (!resp.length) {
                        results.html('
No results found.
');
                        return;
                    }

                    // show results
                    $.each(resp, function(i, o){
                        var li = objRef.renderListElement(o, VocabBrowser.searchResultsTemplate);
                        results.append(li);
                    });

                    objRef.refreshBrowser();
                    results.unblock();
                }
            });
        },

        updateDS: function(evt, new_ds) {
            var objRef = this;
            var operator = /operator$/;
            this.refreshBrowser();

            if (!$.isEmptyObject(new_ds)){
                // Add items
                for (key in new_ds){

                    // ignore the operator
                    if (operator.test(key)) continue;

                    $.each(new_ds[key], function(index, instance_id){
                        $.ajax({
                            url: objRef.viewset.directory + instance_id + '/',
                            success: function(node) {
                                objRef.addNode(node);
                            },
                        });
                    });
                }
            }
        },

        updateElement: function(evt, element) {},

        elementChanged: function(evt, element) {},

        reloadBrowser: function(url, callback) {
            url = url || this.viewset.directory;
            callback = callback || function() {};

            var objRef = this;
            var breadcrumbs = [{name: 'All', uri: this.viewset.directory}];

            this.choices.block();
            $.getJSON(url, function(data){
                objRef.choices.empty();
                objRef.breadcrumbs.empty()

                if (!$.isArray(data)) {
                    nodes = data.children
                    breadcrumbs = breadcrumbs.concat(data.ancestors.length ? data.ancestors : []);
                    breadcrumbs.push({name: data.name});
                } else {
                    nodes = data;
                }

                for (var li, n, i = 0; i < nodes.length; i++) {
                    n = nodes[i];
                    li = objRef.renderListElement(n, VocabBrowser.browseTemplate);
                    objRef.choices.append(li);
                }

                // update breadcrumbs
                var tmpl = $.jqote(VocabBrowser.breadcrumbsTemplate, {breadcrumbs: breadcrumbs});
                objRef.breadcrumbs.html(tmpl);

                // ensure the new list of items reflect the current state
                objRef.refreshBrowser();

                // execute caller-defined callback
                callback();

                objRef.choices.unblock();

            });
        },

        renderListElement: function(node, template) {
            // always ensure there is a reference to the parent node
            if (!node.parent) {
                if (!node.ancestors || node.ancestors.length == 0)
                    node.parent = {uri: this.viewset.directory}
                else
                    node.parent = {uri: node.ancestors[0].uri}
            }

            var li = $($.jqote(template, node));
            // bind data locally to element since this may be used to render
            // another template
            li.data(node);

            return li;

        },

        addNode : function(node) {
            // ensure this is not redundant
            if (this.ds.indexOf(node.id) < 0) {
                this.ds.push(node.id);
                var li = this.renderListElement(node, VocabBrowser.selectedTemplate);
                this.selected.append(li);
            }

            // ensure everything is synced up
            this.dom.trigger("ElementChangedEvent", [{name: this.pk, value: this.ds}]);
            this.refreshBrowser();
        },

        // Remove a previously selected node..
        removeNode : function(node) {
            // remove this ID from the list
            var i;
            if ((i = this.ds.indexOf(node.id)) > -1)
                this.ds.splice(i, 1);

            this.dom.trigger("ElementChangedEvent", [{name: this.pk,
                value: this.ds.length > 0 ? this.ds : undefined}]);
            this.refreshBrowser();
        },

        // Make sure the currently displayed nodes are correctly colored
        // as to whether they are selected for the query.
        refreshBrowser : function() {
            $('li', this.choices).removeClass("added");
            $('button', this.choices).attr("disabled", false);

            $('li', this.results).removeClass("added");
            $('button', this.results).attr("disabled", false);

            for (var id, li, i = this.ds.length; i--; ) {
                id = this.ds[i];

                $('li[data-id='+id+']', this.choices)
                    .addClass('added')
                    .find('button').attr('disabled', true);

                $('li[data-id='+id+']', this.results)
                    .addClass('added')
                    .find('button').attr('disabled', true);
            }

        }
    },

    {
        breadcrumbsTemplate : $.jqotec([
            '<% for (var b, i = 0; i < this.breadcrumbs.length; i++) {%>',
                '<% b = this.breadcrumbs[i]; %>',
                '<% if (i === (this.breadcrumbs.length-1)) {%>',
                    '<h3 title="<%= b.name %>"><%= b.name %>
',
                '<% } else { %>',
                    '» <a href="<%= b.uri %>" title="<%= b.name %>"><%= b.name %>',
                '<% } %>',
            '<% } %>'].join('')),

        browseTemplate : $.jqotec([
            '<li data-id="<%= this.id %>" data-uri="<%= this.uri %>" <% if (!this.terminal) { %>class="folder"<% } %>>',
                '<button class="button-add">+</button>',
                '<%= this.name %>',
                    '<% if (this.attrs) { %>',
                        '
',
                            '<% for (var k in this.attrs) { %>',
                                '<%= k %>: <%= this.attrs[k] %>',
                            '<% } %>',
                        '',
                    '<% } %>',
                '',
            '
'].join('')),

        searchResultsTemplate : $.jqotec([
            '<li data-id="<%= this.id %>" <% if (!this.terminal) { %>class="folder"<% } %>>',
                '<button class="button-add">+</button>',
                '<a href="<%= this.parent.uri %>"><%= this.name %>',
                    '<% if (this.attrs) { %>',
                        '
',
                            '<% for (var k in this.attrs) { %>',
                                '<%= k %>: <%= this.attrs[k] %>',
                            '<% } %>',
                        '',
                    '<% } %>',
                '',
            '
'].join('')),

        selectedTemplate : $.jqotec([
            '<li data-id="<%= this.id %>" <% if (!this.terminal) { %>class="folder"<% } %>>',
                '<button class="button-remove">-</button>',
                '<a href="<%= this.parent.uri %>"><%= this.name %>',
            '
'].join('')),

        vocabBrowserTemplate : $.jqotec([
            '
',

                '
',
                    '<a class="tab" href="#browse-tab-<%= this.pk %>">Browse <%= this.title %>',
                    '<a class="tab" href="#search-tab-<%= this.pk %>">Search <%= this.title %>',
                '
',

                '
',

                    '<div id="browse-tab-<%= this.pk %>">',
                        '

',
                        '

',
                    '
',

                    '<div id="search-tab-<%= this.pk %>">',
                        '<form method="get" action="<%= this.directory %>">',
                            '<input type="text" class="search" name="q" placeholder="Search...">',
                            ' Note: only the first 100 results are displayed',
                        '</form>',
                        '
',
                            '

Enter search terms above.',
                                ' Results can be clicked to go to their location in the Browse tab.

',
                        '
',
                    '
',

                    '
Selected <%= this.title %>
',
                    'Note: this query is currently limited to getting results having ',
                    'at least ONE of these <%= this.title.toLowerCase() %>.',
                    '

',

                '
',
            '
'
        ].join(''))
    });

    return VocabBrowser;
});

<commit_msg>Bug as a result of jQuery 1.6+ upgrade, `hash' is a property<commit_after>define(["cilantro/define/viewelement"],
    function(ViewElement) {

    // browser refers to the div on screen where the concept will be displayed
    var VocabBrowser = ViewElement.extend({

        constructor: function(viewset, concept_pk) {
            this.base(viewset, concept_pk);
            this.ds =  [];
        },

        render: function(){
            var objRef = this;

            var pk = this.pk = this.concept_pk + '_' + this.viewset.pk;
            var dom = this.dom = $($.jqote(VocabBrowser.vocabBrowserTemplate, this.viewset));
            var tabs = $('.tabs', dom);
            var choices = this.choices = $('.choices', dom);
            var selected = this.selected = $('.selected', dom);
            var search = this.search = $('.search', dom);
            var results = this.results = $('.results', dom);
            var breadcrumbs = this.breadcrumbs = $('.breadcrumbs', dom);

            // enable tabs, we use a very barebones tabs implementation
            // the core code only adds the appropriate classes to selected
            // and non-selected tabs, represented by  elements.
            tabs.tabs(false, function (evt, tab) {
                var siblings = tabs.find('.tab')
                // hide everything
                siblings.each(function(i, o) {
                    $(o.hash, objRef.dom).hide();
                });

                // get the current on and show it
                $(tab.prop('hash'), objRef.dom).show();
            });

            // breadcrumb navigation
            breadcrumbs.delegate('a', 'click', function(){
                objRef.reloadBrowser($(this).attr('href'));
                return false;
            });

            function addItem(evt) {
                var target = $(this).parent();
                objRef.addNode(target.data());
                return false;
            }

            // add item from available choices
            choices.delegate('button', 'click', addItem);
            results.delegate('button', 'click', addItem);

            function linkItem(evt) {
                var item = $(this);
                var li = item.parents('li');

                // switch to the browse tab
                tabs.tabs('toggle', 0);

                // reload the browser with the item's url
                objRef.reloadBrowser(item.attr('href'), function() {

                    // get the corresponding list item in the browser
                    var target = $('[data-id='+li.data('id')+']', objRef.choices);

                    // scroll down to the referenced item since this page
                    // represents this item's parent.
                    objRef.choices.scrollTo(target, 500, {
                        offset: -150,
                        onAfter: function() {
                            // add highlight effect to ensure the user sees the
                            // location of the item
                            target.effect('highlight', null, 2000);
                        }
                    });

                });
                return false;
            };

            // handler for clicking on search results, they take the user
            // to the location of the item in the browser since to provide
            // more context
            results.delegate('a', 'click', linkItem);
            selected.delegate('a', 'click', linkItem);

            // descend in hierarchy
            choices.delegate('.folder', 'click', function() {
                objRef.reloadBrowser($(this).data('uri'));
                return false;
            });

            // remove item from selected items
            selected.delegate('button', 'click', function() {
                var target = $(this);
                var li = target.parent();
                objRef.removeNode(li.data());
                li.remove();
                return false;
            });

            this.execute();
        },

        execute: function(){
            var objRef = this;
            var results = this.results;

            // Setup the browser
            this.reloadBrowser();

            // Setup the search
            this.search.autocomplete2({
                start: function() {
                    results.block();
                },
                success: function(query, resp) {
                    results.empty();

                    // no results
                    if (!resp.length) {
                        results.html('
No results found.
');
                        return;
                    }

                    // show results
                    $.each(resp, function(i, o){
                        var li = objRef.renderListElement(o, VocabBrowser.searchResultsTemplate);
                        results.append(li);
                    });

                    objRef.refreshBrowser();
                    results.unblock();
                }
            });
        },

        updateDS: function(evt, new_ds) {
            var objRef = this;
            var operator = /operator$/;
            this.refreshBrowser();

            if (!$.isEmptyObject(new_ds)){
                // Add items
                for (key in new_ds){

                    // ignore the operator
                    if (operator.test(key)) continue;

                    $.each(new_ds[key], function(index, instance_id){
                        $.ajax({
                            url: objRef.viewset.directory + instance_id + '/',
                            success: function(node) {
                                objRef.addNode(node);
                            },
                        });
                    });
                }
            }
        },

        updateElement: function(evt, element) {},

        elementChanged: function(evt, element) {},

        reloadBrowser: function(url, callback) {
            url = url || this.viewset.directory;
            callback = callback || function() {};

            var objRef = this;
            var breadcrumbs = [{name: 'All', uri: this.viewset.directory}];

            this.choices.block();
            $.getJSON(url, function(data){
                objRef.choices.empty();
                objRef.breadcrumbs.empty()

                if (!$.isArray(data)) {
                    nodes = data.children
                    breadcrumbs = breadcrumbs.concat(data.ancestors.length ? data.ancestors : []);
                    breadcrumbs.push({name: data.name});
                } else {
                    nodes = data;
                }

                for (var li, n, i = 0; i < nodes.length; i++) {
                    n = nodes[i];
                    li = objRef.renderListElement(n, VocabBrowser.browseTemplate);
                    objRef.choices.append(li);
                }

                // update breadcrumbs
                var tmpl = $.jqote(VocabBrowser.breadcrumbsTemplate, {breadcrumbs: breadcrumbs});
                objRef.breadcrumbs.html(tmpl);

                // ensure the new list of items reflect the current state
                objRef.refreshBrowser();

                // execute caller-defined callback
                callback();

                objRef.choices.unblock();

            });
        },

        renderListElement: function(node, template) {
            // always ensure there is a reference to the parent node
            if (!node.parent) {
                if (!node.ancestors || node.ancestors.length == 0)
                    node.parent = {uri: this.viewset.directory}
                else
                    node.parent = {uri: node.ancestors[0].uri}
            }

            var li = $($.jqote(template, node));
            // bind data locally to element since this may be used to render
            // another template
            li.data(node);

            return li;

        },

        addNode : function(node) {
            // ensure this is not redundant
            if (this.ds.indexOf(node.id) < 0) {
                this.ds.push(node.id);
                var li = this.renderListElement(node, VocabBrowser.selectedTemplate);
                this.selected.append(li);
            }

            // ensure everything is synced up
            this.dom.trigger("ElementChangedEvent", [{name: this.pk, value: this.ds}]);
            this.refreshBrowser();
        },

        // Remove a previously selected node..
        removeNode : function(node) {
            // remove this ID from the list
            var i;
            if ((i = this.ds.indexOf(node.id)) > -1)
                this.ds.splice(i, 1);

            this.dom.trigger("ElementChangedEvent", [{name: this.pk,
                value: this.ds.length > 0 ? this.ds : undefined}]);
            this.refreshBrowser();
        },

        // Make sure the currently displayed nodes are correctly colored
        // as to whether they are selected for the query.
        refreshBrowser : function() {
            $('li', this.choices).removeClass("added");
            $('button', this.choices).attr("disabled", false);

            $('li', this.results).removeClass("added");
            $('button', this.results).attr("disabled", false);

            for (var id, li, i = this.ds.length; i--; ) {
                id = this.ds[i];

                $('li[data-id='+id+']', this.choices)
                    .addClass('added')
                    .find('button').attr('disabled', true);

                $('li[data-id='+id+']', this.results)
                    .addClass('added')
                    .find('button').attr('disabled', true);
            }

        }
    },

    {
        breadcrumbsTemplate : $.jqotec([
            '<% for (var b, i = 0; i < this.breadcrumbs.length; i++) {%>',
                '<% b = this.breadcrumbs[i]; %>',
                '<% if (i === (this.breadcrumbs.length-1)) {%>',
                    '<h3 title="<%= b.name %>"><%= b.name %>
',
                '<% } else { %>',
                    '» <a href="<%= b.uri %>" title="<%= b.name %>"><%= b.name %>',
                '<% } %>',
            '<% } %>'].join('')),

        browseTemplate : $.jqotec([
            '<li data-id="<%= this.id %>" data-uri="<%= this.uri %>" <% if (!this.terminal) { %>class="folder"<% } %>>',
                '<button class="button-add">+</button>',
                '<%= this.name %>',
                    '<% if (this.attrs) { %>',
                        '
',
                            '<% for (var k in this.attrs) { %>',
                                '<%= k %>: <%= this.attrs[k] %>',
                            '<% } %>',
                        '',
                    '<% } %>',
                '',
            '
'].join('')),

        searchResultsTemplate : $.jqotec([
            '<li data-id="<%= this.id %>" <% if (!this.terminal) { %>class="folder"<% } %>>',
                '<button class="button-add">+</button>',
                '<a href="<%= this.parent.uri %>"><%= this.name %>',
                    '<% if (this.attrs) { %>',
                        '
',
                            '<% for (var k in this.attrs) { %>',
                                '<%= k %>: <%= this.attrs[k] %>',
                            '<% } %>',
                        '',
                    '<% } %>',
                '',
            '
'].join('')),

        selectedTemplate : $.jqotec([
            '<li data-id="<%= this.id %>" <% if (!this.terminal) { %>class="folder"<% } %>>',
                '<button class="button-remove">-</button>',
                '<a href="<%= this.parent.uri %>"><%= this.name %>',
            '
'].join('')),

        vocabBrowserTemplate : $.jqotec([
            '
',

                '
',
                    '<a class="tab" href="#browse-tab-<%= this.pk %>">Browse <%= this.title %>',
                    '<a class="tab" href="#search-tab-<%= this.pk %>">Search <%= this.title %>',
                '
',

                '
',

                    '<div id="browse-tab-<%= this.pk %>">',
                        '

',
                        '

',
                    '
',

                    '<div id="search-tab-<%= this.pk %>">',
                        '<form method="get" action="<%= this.directory %>">',
                            '<input type="text" class="search" name="q" placeholder="Search...">',
                            ' Note: only the first 100 results are displayed',
                        '</form>',
                        '
',
                            '

Enter search terms above.',
                                ' Results can be clicked to go to their location in the Browse tab.

',
                        '
',
                    '
',

                    '
Selected <%= this.title %>
',
                    'Note: this query is currently limited to getting results having ',
                    'at least ONE of these <%= this.title.toLowerCase() %>.',
                    '

',

                '
',
            '
'
        ].join(''))
    });

    return VocabBrowser;
});

<|endoftext|>


<commit_before>let socket;
let lastFire;
$(document).ready(() => {
    if(!socket) {
        socket = io();
        initSocket();
    }
    $('#tablePlayer1').html(makeTable(1));
    $('#tablePlayer2').html(makeTable(2));
    sizeContent();

    open_player_name_modal();
});

$(window).resize(sizeContent);

function initSocket() {
    socket.on('fireResult', isHit => {
        if (isHit) {
            markMyHit(lastFire[0] , lastFire[1]);
        } else {
            markMyNoHit(lastFire[0] , lastFire[1]);
        }
    });
    socket.on('fireResultEnemy', (x, y, isHit) =>{
        if (isHit) {
            markOpponentHit(x,y);
        } else {
            markOpponentNoHit(x,y)
        }
    });
    socket.on('myShips', playerField => {
        for (let y = 0; y < 10; y++) {
            for (let x = 0; x < 10; x++) {
                if (playerField[y][x]) {
                    markMyShips(x,y);
                }
            }
        }
    });
    socket.on('playerTurn', isYourTurn => {
        if (isYourTurn) {
            $('#myLabel').css('color', 'red');
            $('#opponentLabel').css('color', 'black');
        }
        else {
            $('#myLabel').css('color', 'black');
            $('#opponentLabel').css('color', 'red');
        }
    });
    socket.on('won',highscore => {
        document.getElementById('myBody').style.backgroundColor = 'green';
        $('#highscore').html('DEIN HIGHSCORE: ' + highscore);
        $('#resetGame').css('visibility', 'visible');
    });
    socket.on('lost',highscore => {
        document.getElementById('myBody').style.backgroundColor = 'red';
        $('#highscore').html('GEGNER SEIN HIGHSCORE: '+ highscore);
        $('#resetGame').css('visibility', 'visible');
    });
    socket.on('myDestroyedShips', (x,y) => {
        markOpponentDestroy(x,y);
    });
    socket.on('opponentDestroyedShips', (x,y) => {
        markMyDestroy(x,y);
    });
    socket.on('refreshName', name => {
        $("#opponentLabel").html(name);
    });

    socket.on('resetField', () => {
        $('#tablePlayer1').html(makeTable(1));
        $('#tablePlayer2').html(makeTable(2));
        document.getElementById('myBody').style.backgroundColor = 'white';
        $('#highscore').html('');
        $('#resetGame').css('visibility', 'hidden');
    });

    socket.on('rejoinGame', (myShots, opponentShots) => {
        myShots.forEach(shot => {
            if(shot["typeOfHit"] === "noHit") {
                markMyNoHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "hit") {
                markMyHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "destroyed"){
                markMyDestroy(shot["xCoordinate"], shot["yCoordinate"]);
            }
        });
        opponentShots.forEach(shot => {
            if(shot["typeOfHit"] === "noHit") {
                markOpponentNoHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "hit") {
                markOpponentHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "destroyed"){
                markOpponentDestroy(shot["xCoordinate"], shot["yCoordinate"]);
            }
        });
    });
    socket.on('onLobbyFull', () => {
        window.location.href = "http://" + window.location.host + "/full-lobby.html";
    });
}

function markMyHit(x,y) {
    document.getElementById('enemField' + x + y).style.backgroundColor = '#FF5341';
}

function markMyNoHit(x,y) {
    document.getElementById('enemField' + x + y).style.backgroundColor = '#0ab2bd';
}

function markMyDestroy(x,y) {
    document.getElementById('enemField' + x + y).style.backgroundColor = '#008eb7';
}

function markOpponentHit(x,y) {
    document.getElementById('myField' + x + y).style.backgroundColor = '#034044';
}

function markOpponentNoHit(x,y) {
    document.getElementById('myField' + x + y).style.backgroundColor = '#0ab2bd';
}

function markOpponentDestroy(x,y) {
    document.getElementById('myField' + x + y).style.backgroundColor = '#008eb7';
}

function markMyShips(x,y){
    document.getElementById('myField' + x + y).style.backgroundColor = '#000000';
}

function fire(x, y) {
    lastFire = [x, y];
    socket.emit('fire', x, y);
}

function makeTable(playerNumber) {
    let str = '';
    str += '
';
    for (let y = 0; y < 10; y++) {
        str += '
';
        for (let x = 0; x < 10; x++) {
            if (playerNumber == 1) {
                str += '	';
            } else {
                str += '	';
            }
        }
        str += '
';
    }
    str += '
';
    return str;
}

$('#playerName').modal({
    show: true,
    keyboard: false,
    backdrop: 'static'
});

function open_player_name_modal() {
    $('#playerName').modal({
        show: true,
        keyboard: false,
        backdrop: 'static'
    });
}

function reset_the_game(){
    socket.emit('restart');
}

function set_player_name() {
    let myLabel = document.getElementById('myLabelInput');
    // We have to reset the form errors with custom validity
    myLabel.setCustomValidity('');

    if (myLabel.checkValidity()) {
        let myLabelName = myLabel.value.trim();
        if (myLabelName.length == 0) {
            myLabel.setCustomValidity('Du brauchst einen Namen');
        } else {
            document.getElementById('myLabel').innerHTML = myLabelName;
            $('#playerName').modal('hide');
            socket.emit('setPlayerName', myLabelName);
        }
    }
}

function sizeContent() {
    let newHeight = $("html").height()*0.4 + "px";

    document.getElementById("tablePlayer1").setAttribute("style","width: " + newHeight + "!important");
    document.getElementById("tablePlayer2").setAttribute("style","width: " + newHeight + "!important");

    let tableWidth = $(".table-bordered").width();
    let marginLeft = ($("html").width()*0.5 - tableWidth*0.5) + "px";
    $("#changePlayername").css("margin-left", marginLeft);
    $(".namesOfPlayer").css("margin-left", marginLeft);
}
<commit_msg>jiiooo wahrscheinlich oder<commit_after>let socket;
let lastFire;
$(document).ready(() => {
    if(!socket) {
        socket = io();
        initSocket();
    }
    $('#tablePlayer1').html(makeTable(1));
    $('#tablePlayer2').html(makeTable(2));
    sizeContent();

    open_player_name_modal();
});

$(window).resize(sizeContent);

function initSocket() {
    socket.on('fireResult', isHit => {
        if (isHit) {
            markMyHit(lastFire[0] , lastFire[1]);
        } else {
            markMyNoHit(lastFire[0] , lastFire[1]);
        }
    });
    socket.on('fireResultEnemy', (x, y, isHit) =>{
        if (isHit) {
            markOpponentHit(x,y);
        } else {
            markOpponentNoHit(x,y)
        }
    });
    socket.on('myShips', playerField => {
        for (let y = 0; y < 10; y++) {
            for (let x = 0; x < 10; x++) {
                if (playerField[y][x]) {
                    markMyShips(x,y);
                }
            }
        }
    });
    socket.on('playerTurn', isYourTurn => {
        if (isYourTurn) {
            $('#myLabel').css('color', 'red');
            $('#opponentLabel').css('color', 'black');
        }
        else {
            $('#myLabel').css('color', 'black');
            $('#opponentLabel').css('color', 'red');
        }
    });
    socket.on('won',highscore => {
        document.getElementById('myBody').style.backgroundColor = 'green';
        $('#highscore').html('DEIN HIGHSCORE: ' + highscore);
        $('#resetGame').css('visibility', 'visible');
    });
    socket.on('lost',highscore => {
        document.getElementById('myBody').style.backgroundColor = 'red';
        $('#highscore').html('GEGNER SEIN HIGHSCORE: '+ highscore);
        $('#resetGame').css('visibility', 'visible');
    });
    socket.on('myDestroyedShips', (x,y) => {
        markOpponentDestroy(x,y);
    });
    socket.on('opponentDestroyedShips', (x,y) => {
        markMyDestroy(x,y);
    });
    socket.on('refreshName', name => {
        $("#opponentLabel").html(name);
    });

    socket.on('resetField', () => {
        $('#tablePlayer1').html(makeTable(1));
        $('#tablePlayer2').html(makeTable(2));
        document.getElementById('myBody').style.backgroundColor = 'white';
        $('#highscore').html('');
        $('#resetGame').css('visibility', 'hidden');
    });

    socket.on('rejoinGame', (myShots, opponentShots) => {
        myShots.forEach(shot => {
            if(shot["typeOfHit"] === "noHit") {
                markMyNoHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "hit") {
                markMyHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "destroyed"){
                markMyDestroy(shot["xCoordinate"], shot["yCoordinate"]);
            }
        });
        opponentShots.forEach(shot => {
            if(shot["typeOfHit"] === "noHit") {
                markOpponentNoHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "hit") {
                markOpponentHit(shot["xCoordinate"], shot["yCoordinate"]);
            } else if(shot["typeOfHit"] === "destroyed"){
                markOpponentDestroy(shot["xCoordinate"], shot["yCoordinate"]);
            }
        });
    });
    socket.on('onLobbyFull', () => {
        window.location.href = "http://" + window.location.host + "/full-lobby.html";
    });
}

function markMyHit(x,y) {
    document.getElementById('enemField' + x + y).style.backgroundColor = '#FF5341';
}

function markMyNoHit(x,y) {
    document.getElementById('enemField' + x + y).style.backgroundColor = '#0ab2bd';
}

function markMyDestroy(x,y) {
    document.getElementById('enemField' + x + y).style.backgroundColor = '#008eb7';
}

function markOpponentHit(x,y) {
    document.getElementById('myField' + x + y).style.backgroundColor = '#034044';
}

function markOpponentNoHit(x,y) {
    document.getElementById('myField' + x + y).style.backgroundColor = '#0ab2bd';
}

function markOpponentDestroy(x,y) {
    document.getElementById('myField' + x + y).style.backgroundColor = '#008eb7';
}

function markMyShips(x,y){
    document.getElementById('myField' + x + y).style.backgroundColor = '#000000';
}

function fire(x, y) {
    lastFire = [x, y];
    socket.emit('fire', x, y);
}

function makeTable(playerNumber) {
    let str = '';
    str += '
';
    for (let y = 0; y < 10; y++) {
        str += '
';
        for (let x = 0; x < 10; x++) {
            if (playerNumber == 1) {
                str += '	';
            } else {
                str += '	';
            }
        }
        str += '
';
    }
    str += '
';
    return str;
}

$('#playerName').modal({
    show: true,
    keyboard: false,
    backdrop: 'static'
});

function open_player_name_modal() {
    $('#playerName').modal({
        show: true,
        keyboard: false,
        backdrop: 'static'
    });
}

function reset_the_game(){
    socket.emit('restart');
}

function set_player_name() {
    let myLabel = document.getElementById('myLabelInput');
    // We have to reset the form errors with custom validity
    myLabel.setCustomValidity('');

    if (myLabel.checkValidity()) {
        let myLabelName = myLabel.value.trim();
        if (myLabelName.length == 0) {
            myLabel.setCustomValidity('Du brauchst einen Namen');
        } else {
            document.getElementById('myLabel').innerHTML = myLabelName;
            $('#playerName').modal('hide');
            socket.emit('setPlayerName', myLabelName);
        }
    }
}

function sizeContent() {
    let newHeight = $("html").height()*0.35 + "px";

    document.getElementById("tablePlayer1").setAttribute("style","width: " + newHeight + "!important");
    document.getElementById("tablePlayer2").setAttribute("style","width: " + newHeight + "!important");

    let tableWidth = $(".table-bordered").width();
    let marginLeft = ($("html").width()*0.5 - tableWidth*0.5) + "px";
    $("#changePlayername").css("margin-left", marginLeft);
    $(".namesOfPlayer").css("margin-left", marginLeft);
}
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2011 Strobe Inc. and contributors.
//            Portions ©2008-2010 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

/** Detects the current browser type. Borrowed from jQuery + prototype */
SC.mixin(SC.browser, (function() {
  var viewport  = window.innerWidth,
      browser = SC.browser,
      standalone = navigator.standalone;

  // Add more SC-like descriptions...
  SC.extend(browser, /** @scope SC.browser */ {

    isOpera: !!browser.opera,
    isIe: !!browser.msie,
    isIE: !!browser.msie,
    isSafari: !!browser.safari,
    isChrome: !!browser.chrome && !!!browser.safari,
    isMobileSafari: (!!browser.mobileSafari || !!browser.standalone),
    isMozilla: !!browser.mozilla,
    isWindows: !!browser.windows,
    isMac: !!browser.mac,
    isiPhone: ((!!browser.mobileSafari || !!browser.standalone) && (viewport == 320 || viewport == 480)),

    /**
      The current browser name.  This is useful for switch statements. */
    current: browser.msie ? 'msie' : browser.mozilla ? 'mozilla' : browser.chrome ? 'chrome' : browser.safari ? 'safari' : browser.opera ? 'opera' : 'unknown',

    /**
      Pass any number of arguments, and this will check them against the browser
      version split on ".".  If any of them are not equal, return the inequality.
      If as many arguments as were passed in are equal, return 0.  If something
      is NaN, return 0. */
    compareVersion: function () {
      if (this._versionSplit === undefined) {
        var coerce = function (part) {
          return Number(part.match(/^[0-9]+/));
        };
        this._versionSplit = SC.A(this.version.split('.')).map(coerce);
      }

      var tests = SC.A(arguments).map(Number);
      for (var i = 0; i < tests.length; i++) {
        var check = this._versionSplit[i] - tests[i];
        if (isNaN(check)) return 0;
        if (check !== 0) return check;
      }

      return 0;
    }

  }) ;

  return browser ;

})() );

<commit_msg>Correct browser detection for safari and chrome<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2011 Strobe Inc. and contributors.
//            Portions ©2008-2010 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

/** Detects the current browser type. Borrowed from jQuery + prototype */
SC.mixin(SC.browser, (function() {
  var viewport  = window.innerWidth,
      browser = SC.browser,
      standalone = navigator.standalone;

  // Add more SC-like descriptions...
  SC.extend(browser, /** @scope SC.browser */ {

    isOpera: !!browser.opera,
    isIe: !!browser.msie,
    isIE: !!browser.msie,
    isSafari: !!browser.safari && !browser.chrome,
    isChrome: !!browser.chrome && !browser.isSafari,
    isMobileSafari: (!!browser.mobileSafari || !!browser.standalone),
    isMozilla: !!browser.mozilla,
    isWindows: !!browser.windows,
    isMac: !!browser.mac,
    isiPhone: ((!!browser.mobileSafari || !!browser.standalone) && (viewport == 320 || viewport == 480)),

    /**
      The current browser name.  This is useful for switch statements. */
    current: browser.msie ? 'msie' : browser.mozilla ? 'mozilla' : browser.chrome ? 'chrome' : browser.safari ? 'safari' : browser.opera ? 'opera' : 'unknown',

    /**
      Pass any number of arguments, and this will check them against the browser
      version split on ".".  If any of them are not equal, return the inequality.
      If as many arguments as were passed in are equal, return 0.  If something
      is NaN, return 0. */
    compareVersion: function () {
      if (this._versionSplit === undefined) {
        var coerce = function (part) {
          return Number(part.match(/^[0-9]+/));
        };
        this._versionSplit = SC.A(this.version.split('.')).map(coerce);
      }

      var tests = SC.A(arguments).map(Number);
      for (var i = 0; i < tests.length; i++) {
        var check = this._versionSplit[i] - tests[i];
        if (isNaN(check)) return 0;
        if (check !== 0) return check;
      }

      return 0;
    }

  }) ;

  return browser ;

})() );

<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================
/*global ActiveXObject */

SC.Request = SC.Object.extend({

  isAsynchronous: true,
  rawResponse: null,
  error: null,
  transportClass: null,
  isJSON: false,

  init: function(){
    sc_super() ;

    this._headers = {};
  },

  header: function(key, value) {
    if (typeof key == 'object' && !value) {
      for (var headerKey in key) {
        this.header(headerKey,key[headerKey]) ;
      }
      return this;
    }

    if (typeof key == 'string' && !value) {
      return this._headers[key] ;
    }

    this.propertyWillChange('headers') ;

    //set value for key
    this._headers[key] = value ;

    this.propertyDidChange('headers') ;
    return this ;
  },

  send: function(body) {
    var request = this ;
    if(body) {
      if(this.get('isJSON')) {
        body=SC.json.encode(body);
        if(body===undefined) console.error('There was an error encoding to JSON');
      }
      request.set('body', body) ;
    }
    SC.Request.manager.sendRequest(request) ;
    return request ;
  },

  notify: function(target, action, params) {
    if (SC.typeOf(action) === SC.T_STRING) action = target[action];
    this.set('notifyTarget', target)
    .set('notifyAction', action)
    .set('notifyParams', params);
    return this;
  },

  response: function() {
    var response = this.get("rawResponse") ;
    if (!response || !SC.$ok(response)) {
        return response ;
    }

    if (this.get("isJSON")) {
      var source = response.responseText ;
      var json = SC.json.decode(source) ;
      //TODO cache this value?
      return json ;
    }

    if(response.responseXML) return response.responseXML ;
    return response.responseText ;
  }.property('rawResponse').cacheable()

});

SC.Request.getUrl = function(address) {
  var req = SC.Request.create() ;
  req.set('address', address) ;
  req.set('type', 'GET') ;

  return req ;
};

SC.Request.postUrl = function(address, body) {
  var req = SC.Request.create() ;
  req.set('address',address) ;
  if(body) req.set('body', body) ;
  req.set('type', 'POST') ;

  return req ;
};

SC.Request.deleteUrl = function(address) {
  var req = SC.Request.create() ;
  req.set('address',address) ;
  req.set('type', 'DELETE') ;

  return req ;
};

SC.Request.putUrl = function(address, body) {
  var req = SC.Request.create() ;
  req.set('address',address) ;
  if(body) req.set('body', body) ;
  req.set('type', 'PUT') ;

  return req ;
};

SC.Request.manager = SC.Object.create( SC.DelegateSupport, {
  maxRequests: 2,

  currentRequests: [],
  queue: [],

  canLoadAnotherRequest: function() {
    return (this.get('numberOfCurrentRequests') < this.get('maxRequests')) ;
  }.property('numberOfCurrentRequests'),

  numberOfCurrentRequests: function() {
    return this.get('currentRequests').length ;
  }.property('currentRequests'),

  numberOfRequests: function() {
    return this.get('queue').length ;
  }.property('queue'),

  sendRequest: function(request) {
    if(!request) return;

    request = {
      request: request,
      action:  request.get('notifyAction'),
      target:  request.get('notifyTarget'),
      params:  request.get('notifyParams') };

    this.propertyWillChange("queue");
    this.get('queue').pushObject(request);
    this.propertyDidChange("queue");

    this.fireRequestIfNeeded();
  },

  removeRequest: function(request) {
    this.get('queue').removeObject(request);
    return YES;
  },

  cancelAllRequests: function() {
    var r, xhrRequest;
    this.set('queue', []);
    var activeRequests=this.get('currentRequests');
    while(r=activeRequests.popObject()){
      xhrRequest = r.get('request');
      xhrRequest.abort();
    }
    return YES;
  },

  fireRequestIfNeeded: function() {
    if (this.canLoadAnotherRequest()) {
      this.propertyWillChange('queue') ;
      var item = this.get('queue').popObject() ;
      this.propertyDidChange('queue') ;

      if (item) {
        var transportClass = item.request.get('transportClass') ;
        if (!transportClass) transportClass = this.get('transportClass') ;

        if (transportClass) {
          var transport = this.transportClass.create(item) ;
          if (transport) {
            item.request.set('transport', transport) ;
            this._transportDidOpen(transport) ;
          }
        }
      }
    }
  },

  _transportDidOpen: function(transport) {
    this.propertyWillChange('currentRequests') ;
    this.get('currentRequests').pushObject(transport) ;
    this.propertyDidChange('currentRequests') ;

    transport.fire() ;
  },

  transportDidClose: function(request) {
    this.propertyWillChange('currentRequests') ;
    this.get('currentRequests').removeObject(request) ;
    this.propertyDidChange('currentRequests') ;
  }

});

// abstract superclass, creates no-op objects
SC.RequestTransport = SC.Object.extend({

  fire: function() {
    SC.Request.manager.transportDidClose(this) ;
  }

});

SC.XHRRequestTransport = SC.RequestTransport.extend({

  fire: function() {

    var tryThese = function() {
      for (var i=0; i < arguments.length; i++) {
        try {
          var item = arguments[i]() ;
          return item ;
        } catch (e) {}
      }
      return NO;
    };

    var rawRequest = tryThese(
      function() { return new XMLHttpRequest(); },
      function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
      function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
    );

    var request = this.get('request') ;

    rawRequest.source = request;

    var async = (request.get('isAsynchronous') ? YES : NO) ;
    if (async) SC.Event.add(rawRequest, 'readystatechange', this, this.handleReadyStateChange, rawRequest) ;

    rawRequest.open( request.get('type'), request.get('address'), async ) ;

    // headers need to be set *After* the open call.
    var headers = request._headers ;
    for (var headerKey in headers) {
      rawRequest.setRequestHeader(headerKey, headers[headerKey]) ;
    }

    rawRequest.send(request.get('body')) ;

    if (!async) this.finishRequest(rawRequest) ;

    return rawRequest ;
  },

  didSucceed: function(request) {
    var status = null ;
    try {
        status = request.status || 0;
    } catch (e) {}
    return !status || (status >= 200 && status < 300) ;
  },

  finishRequest: function(request) {
    var readyState = request.readyState ;
    var didSucceed = !request ? NO : this.didSucceed(request) ;

    if (readyState == 4) {
      request._complete = YES ;

      if (didSucceed) {
        var response = request ;
        request.source.set('rawResponse', response) ;
      } else {
        var error = SC.$error("HTTP Request failed", "Fail", -1) ;
        error.set("request",request) ;
        request.source.set('rawResponse', error) ;
      }
      if (this.target && this.action) {
        SC.RunLoop.begin();
        this.action.call(this.target, request.source, this.params);
        SC.RunLoop.end();
      }

      SC.Request.manager.transportDidClose(this) ;
     }

     if (readyState == 4) {
       // avoid memory leak in MSIE: clean up
       request.onreadystatechange = function() {} ;
     }
  },

  handleReadyStateChange: function(readyStateEvent) {
    return this.finishRequest(readyStateEvent.context) ;
  }

});

SC.Request.manager.set('transportClass', SC.XHRRequestTransport) ;
<commit_msg>Fix for not decoding JSON response if responseText is empty and initial SC.Request documentation<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================
/*global ActiveXObject */

/**
  Description to come.

  @since SproutCore 1.0
*/

SC.Request = SC.Object.extend({

  isAsynchronous: true,
  rawResponse: null,
  error: null,
  transportClass: null,
  isJSON: false,

  /**
    Sets up the request object
  */
  init: function(){
    sc_super() ;
    this._headers = {};
  },

  /**
    To set headers on the request object

    @param {String} key
    @param {String} value
    @returns {SC.Request} receiver
  */
  header: function(key, value) {
    if (typeof key == 'object' && !value) {
      for (var headerKey in key) {
        this.header(headerKey,key[headerKey]) ;
      }
      return this;
    }

    if (typeof key == 'string' && !value) {
      return this._headers[key] ;
    }

    this.propertyWillChange('headers') ;

    //set value for key
    this._headers[key] = value ;

    this.propertyDidChange('headers') ;
    return this ;
  },

  /**
    Will fire the actual request.

    @param {String} body (optional)
    @returns {SC.Request} receiver
  */
  send: function(body) {
    var request = this ;
    if(body) {
      if(this.get('isJSON')) {
        body=SC.json.encode(body);
        if(body===undefined) console.error('There was an error encoding to JSON');
      }
      request.set('body', body) ;
    }
    SC.Request.manager.sendRequest(request) ;
    return request ;
  },

  /**
    Set up notifications.

    @param {Object} target
    @param {String|function} action
    @param {Hash} params
    @returns {SC.Request} receiver
  */
  notify: function(target, action, params) {
    if (SC.typeOf(action) === SC.T_STRING) action = target[action];
    this.set('notifyTarget', target)
    .set('notifyAction', action)
    .set('notifyParams', params);
    return this;
  },

  /**
    Response method

    @returns {Object} response
  */
  response: function() {
    var response = this.get("rawResponse") ;
    if (!response || !SC.$ok(response) || response.responseText.trim()==='') {
        return response ;
    }

    if (this.get("isJSON")) {
      var source = response.responseText ;
      var json = SC.json.decode(source) ;
      //TODO cache this value?
      return json ;
    }

    if(response.responseXML) return response.responseXML ;
    return response.responseText ;
  }.property('rawResponse').cacheable()

});

/**
  Helper method for quickly setting up a GET request.

  @param {String} address url of request
  @returns {SC.Request} receiver
*/
SC.Request.getUrl = function(address) {
  var req = SC.Request.create() ;
  req.set('address', address) ;
  req.set('type', 'GET') ;

  return req ;
};

/**
  Helper method for quickly setting up a POST request.

  @param {String} address url of request
  @param {String} body
  @returns {SC.Request} receiver
*/
SC.Request.postUrl = function(address, body) {
  var req = SC.Request.create() ;
  req.set('address',address) ;
  if(body) req.set('body', body) ;
  req.set('type', 'POST') ;

  return req ;
};

/**
  Helper method for quickly setting up a DELETE request.

  @param {String} address url of request
  @returns {SC.Request} receiver
*/
SC.Request.deleteUrl = function(address) {
  var req = SC.Request.create() ;
  req.set('address',address) ;
  req.set('type', 'DELETE') ;

  return req ;
};

/**
  Helper method for quickly setting up a PUT request.

  @param {String} address url of request
  @param {String} body
  @returns {SC.Request} receiver
*/
SC.Request.putUrl = function(address, body) {
  var req = SC.Request.create() ;
  req.set('address',address) ;
  if(body) req.set('body', body) ;
  req.set('type', 'PUT') ;

  return req ;
};

/**
  The request manager.
  More description to come.
*/
SC.Request.manager = SC.Object.create( SC.DelegateSupport, {
  maxRequests: 2,

  currentRequests: [],
  queue: [],

  canLoadAnotherRequest: function() {
    return (this.get('numberOfCurrentRequests') < this.get('maxRequests')) ;
  }.property('numberOfCurrentRequests'),

  numberOfCurrentRequests: function() {
    return this.get('currentRequests').length ;
  }.property('currentRequests'),

  numberOfRequests: function() {
    return this.get('queue').length ;
  }.property('queue'),

  sendRequest: function(request) {
    if(!request) return;

    request = {
      request: request,
      action:  request.get('notifyAction'),
      target:  request.get('notifyTarget'),
      params:  request.get('notifyParams') };

    this.propertyWillChange("queue");
    this.get('queue').pushObject(request);
    this.propertyDidChange("queue");

    this.fireRequestIfNeeded();
  },

  removeRequest: function(request) {
    this.get('queue').removeObject(request);
    return YES;
  },

  cancelAllRequests: function() {
    var r, xhrRequest;
    this.set('queue', []);
    var activeRequests=this.get('currentRequests');
    while(r=activeRequests.popObject()){
      xhrRequest = r.get('request');
      xhrRequest.abort();
    }
    return YES;
  },

  fireRequestIfNeeded: function() {
    if (this.canLoadAnotherRequest()) {
      this.propertyWillChange('queue') ;
      var item = this.get('queue').popObject() ;
      this.propertyDidChange('queue') ;

      if (item) {
        var transportClass = item.request.get('transportClass') ;
        if (!transportClass) transportClass = this.get('transportClass') ;

        if (transportClass) {
          var transport = this.transportClass.create(item) ;
          if (transport) {
            item.request.set('transport', transport) ;
            this._transportDidOpen(transport) ;
          }
        }
      }
    }
  },

  _transportDidOpen: function(transport) {
    this.propertyWillChange('currentRequests') ;
    this.get('currentRequests').pushObject(transport) ;
    this.propertyDidChange('currentRequests') ;

    transport.fire() ;
  },

  transportDidClose: function(request) {
    this.propertyWillChange('currentRequests') ;
    this.get('currentRequests').removeObject(request) ;
    this.propertyDidChange('currentRequests') ;
  }

});

// abstract superclass, creates no-op objects
SC.RequestTransport = SC.Object.extend({

  fire: function() {
    SC.Request.manager.transportDidClose(this) ;
  }

});

SC.XHRRequestTransport = SC.RequestTransport.extend({

  fire: function() {

    var tryThese = function() {
      for (var i=0; i < arguments.length; i++) {
        try {
          var item = arguments[i]() ;
          return item ;
        } catch (e) {}
      }
      return NO;
    };

    var rawRequest = tryThese(
      function() { return new XMLHttpRequest(); },
      function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
      function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
    );

    var request = this.get('request') ;

    rawRequest.source = request;

    var async = (request.get('isAsynchronous') ? YES : NO) ;
    if (async) SC.Event.add(rawRequest, 'readystatechange', this, this.handleReadyStateChange, rawRequest) ;

    rawRequest.open( request.get('type'), request.get('address'), async ) ;

    // headers need to be set *After* the open call.
    var headers = request._headers ;
    for (var headerKey in headers) {
      rawRequest.setRequestHeader(headerKey, headers[headerKey]) ;
    }

    rawRequest.send(request.get('body')) ;

    if (!async) this.finishRequest(rawRequest) ;

    return rawRequest ;
  },

  didSucceed: function(request) {
    var status = null ;
    try {
        status = request.status || 0;
    } catch (e) {}
    return !status || (status >= 200 && status < 300) ;
  },

  finishRequest: function(request) {
    var readyState = request.readyState ;
    var didSucceed = !request ? NO : this.didSucceed(request) ;

    if (readyState == 4) {
      request._complete = YES ;

      if (didSucceed) {
        var response = request ;
        request.source.set('rawResponse', response) ;
      } else {
        var error = SC.$error("HTTP Request failed", "Fail", -1) ;
        error.set("request",request) ;
        request.source.set('rawResponse', error) ;
      }
      if (this.target && this.action) {
        SC.RunLoop.begin();
        this.action.call(this.target, request.source, this.params);
        SC.RunLoop.end();
      }

      SC.Request.manager.transportDidClose(this) ;
     }

     if (readyState == 4) {
       // avoid memory leak in MSIE: clean up
       request.onreadystatechange = function() {} ;
     }
  },

  handleReadyStateChange: function(readyStateEvent) {
    return this.finishRequest(readyStateEvent.context) ;
  }

});

SC.Request.manager.set('transportClass', SC.XHRRequestTransport) ;
<|endoftext|>


<commit_before>var temp = require('temp').track();
var fs = require('fs');
var execSync = require('child_process').execSync;
var path = require('path')
var webpack_json = path.resolve(path.dirname(__filename), '../../build_tools/webpack_json.py')

module.exports = function() {
  // the temporary path where the webpack_json json is stored
  var webpack_json_tempfile = temp.openSync({ suffix: '.json' }).path;

  // Run the script below to extract the relevant information about the plugin configuration from the Python code.
  execSync(`python ${webpack_json} --output_file  ${webpack_json_tempfile}`);

  var result = fs.readFileSync(webpack_json_tempfile);

  temp.cleanupSync(); // cleanup the tempfile immediately!

  if (result.length > 0) {
    // The above script prints JSON to stdout, here we parse that JSON and use it as input to our webpack
    // configuration builder module, parseBundlePlugin.
    return JSON.parse(result);
  }

  return [];
};
<commit_msg>read webpackjson<commit_after>var temp = require('temp').track();
var fs = require('fs');
var execSync = require('child_process').execSync;
var path = require('path');
var webpack_json = path.resolve(path.dirname(__filename), '../../build_tools/webpack_json.py');

module.exports = function() {
  // the temporary path where the webpack_json json is stored
  var webpack_json_tempfile = temp.openSync({ suffix: '.json' }).path;

  // Run the script below to extract the relevant information about the plugin configuration from the Python code.
  execSync(`python ${webpack_json} --output_file  ${webpack_json_tempfile}`);

  var result = fs.readFileSync(webpack_json_tempfile);

  temp.cleanupSync(); // cleanup the tempfile immediately!

  if (result.length > 0) {
    // The above script prints JSON to stdout, here we parse that JSON and use it as input to our webpack
    // configuration builder module, parseBundlePlugin.
    return JSON.parse(result);
  }

  return [];
};
<|endoftext|>