<commit_before>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/orelBelohlavy/01.jpg'),
  require('../../images/animals/orelBelohlavy/02.jpg'),
  require('../../images/animals/orelBelohlavy/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/orelBelohlavy/01-thumb.jpg'),
  require('../../images/animals/orelBelohlavy/02-thumb.jpg'),
  require('../../images/animals/orelBelohlavy/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
       Orel bělohlavý (lat. <Text style={styles.italic}>Haliaeetus leucocephalus</Text>) patří v Zoo Brno k největším chloubám naší ptačí kolekce. Tento nádherný dravec pochází ze Severní Ameriky, kde byl v 18. století prohlášen za národního ptáka a státní symbol Spojených států amerických. Stal se ikonou svobody, krásy i síly a v tradičních indiánských kulturách je ctěn jako posel mezi bohy a lidmi.
        </AnimalText>
        <AnimalText>
        I přes jeho veškerou majestátnost a vznešenost se orel bělohlavý ocitl v polovině 20. století na pokraji vyhynutí. Otrava pesticidy a nelegální lov patřily mezi hlavní příčiny zápisu tohoto zvířete na seznam ohrožených druhů. Po mnohých ochranářských opatřeních se však početní stavy orlů bělohlavých podařilo opět zvýšit. V divočině se průměrně dožívají 28 let, v zajetí až 36 let.
        </AnimalText>
        <AnimalText>
        Jak už druhové jméno napovídá, hlava tohoto dravce je pokryta bílým peřím, což výrazně kontrastuje s tmavě hnědým tělem a křídly. Ocas má taktéž bílý a jeho pařáty, zobák a duhovky jsou naopak zářivě žluté. Celková délka těla orla bělohlavého dosahuje v průměru 70–102 cm a rozpětí křídel 168–244 cm. Zajímavé je, že samice přerůstají samce, a to až o 25 %.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Orel bělohlavý si vyhledává místa především u velkých vodních ploch. Je možné ho zahlédnout na břehu moře, oceánu, u velkých jezer či řek. Není tedy žádným překvapením, že jeho hlavní potravou jsou ryby. Živí se také savci, ptáky a obojživelníky. Je to od přírody výborný letec, což mu lov potravy výrazně usnadňuje. Při vodorovném letu dosahuje maximální rychlosti 70 km/h, při chytání ryb a střemhlavém ponoření až 160 km/h.
        </AnimalText>
        <AnimalText>
        Většina orlů bělohlavých si vytváří partnerství na celý život. V případě zmizení nebo úmrtí jednoho z páru si však opuštěný jedinec hledá partnera nového. Orlí námluvy často připomínají pozoruhodnou vzdušnou akrobacii, při níž pár létá střemhlav k zemi, nahání se a předvádí nejrůznější přemety.
        </AnimalText>
        <InPageImage indexes={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Během doby páření si staví orli hnízda, která patří k vůbec největším ptačím hnízdům na světě (hloubka 4 m a průměr až 2,5 m). Bývají umístěna vysoko na stromech nebo na skalních římsách a orlům mohou sloužit až pět let. Samička ročně snáší jedno až tři vejce, jejichž inkubační doba je kolem 35 dnů. Na vejcích střídavě sedí samice i samec. Jen málokdy se ovšem podaří přivést na svět všechna mláďata.
        </AnimalText>
        <AnimalText>
        V Zoo Brno se můžete s těmito dravci seznámit doslova tváří v tvář v unikátní volně průchozí voliéře, která byla slavnostně otevřena v roce 2014. Momentálně jsou zde dva jedinci – matka s dcerou. Orlí matka, která do Brna dorazila z liberecké zoo, se narodila ve Frankfurtu nad Mohanem v roce 1988 (je to tedy již opravdová dáma v orlích letech). Její dcera se vylíhla v roce 2015 v brněnské zoo, což považujeme za velký úspěch, neboť odchov těchto dravců v zajetí je všeobecně velmi složitý.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<commit_msg>Update orelBelohlavy.adult.js<commit_after>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/orelBelohlavy/01.jpg'),
  require('../../images/animals/orelBelohlavy/02.jpg'),
  require('../../images/animals/orelBelohlavy/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/orelBelohlavy/01-thumb.jpg'),
  require('../../images/animals/orelBelohlavy/02-thumb.jpg'),
  require('../../images/animals/orelBelohlavy/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
       Orel bělohlavý (lat. <Text style={styles.italic}>Haliaeetus leucocephalus</Text>) patří v Zoo Brno k největším chloubám naší ptačí kolekce. Tento nádherný dravec pochází ze Severní Ameriky, kde byl v 18. století prohlášen za národního ptáka a státní symbol Spojených států amerických. Stal se ikonou svobody, krásy i síly a v tradičních indiánských kulturách je ctěn jako posel mezi bohy a lidmi.
        </AnimalText>
        <AnimalText>
        I přes jeho veškerou majestátnost a vznešenost se orel bělohlavý ocitl v polovině 20. století na pokraji vyhynutí. Otrava pesticidy a nelegální lov patřily mezi hlavní příčiny zápisu tohoto zvířete na seznam ohrožených druhů. Po mnohých ochranářských opatřeních se však početní stavy orlů bělohlavých podařilo opět zvýšit. V divočině se průměrně dožívají 28 let, v zajetí až 36 let.
        </AnimalText>
        <AnimalText>
        Jak už druhové jméno napovídá, hlava tohoto dravce je pokryta bílým peřím, což výrazně kontrastuje s tmavě hnědým tělem a křídly. Ocas má taktéž bílý a jeho pařáty, zobák a duhovky jsou naopak zářivě žluté. Celková délka těla orla bělohlavého dosahuje v průměru 70–102 cm a rozpětí křídel 168–244 cm. Zajímavé je, že samice přerůstají samce, a to až o 25 %. U dravců je to ovšem pravidlem.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Orel bělohlavý si vyhledává místa především u velkých vodních ploch. Je možné ho zahlédnout na břehu moře, oceánu, u velkých jezer či řek. Není tedy žádným překvapením, že jeho hlavní potravou jsou ryby. Živí se také savci, ptáky a obojživelníky. Je to od přírody výborný letec, což mu lov potravy výrazně usnadňuje. Při vodorovném letu dosahuje maximální rychlosti 70 km/h, při chytání ryb a střemhlavém ponoření až 160 km/h.
        </AnimalText>
        <AnimalText>
        Většina orlů bělohlavých si vytváří partnerství na celý život. V případě zmizení nebo úmrtí jednoho z páru si však opuštěný jedinec hledá partnera nového. Orlí námluvy často připomínají pozoruhodnou vzdušnou akrobacii, při níž pár létá střemhlav k zemi, nahání se a předvádí nejrůznější přemety.
        </AnimalText>
        <InPageImage indexes={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Během doby páření si staví orli hnízda, která patří k vůbec největším ptačím hnízdům na světě (hloubka 4 m a průměr až 2,5 m). Bývají umístěna vysoko na stromech nebo na skalních římsách a orlům mohou sloužit až pět let. Samička ročně snáší jedno až tři vejce, jejichž inkubační doba je kolem 35 dnů. Na vejcích střídavě sedí samice i samec. Jen málokdy se ovšem podaří přivést na svět všechna mláďata.
        </AnimalText>
        <AnimalText>
        V Zoo Brno se můžete s těmito dravci seznámit doslova tváří v tvář v unikátní volně průchozí voliéře, která byla slavnostně otevřena v roce 2014. Momentálně jsou zde dva jedinci – matka s dcerou. Orlí matka, která do Brna dorazila z liberecké zoo, se narodila ve Frankfurtu nad Mohanem v roce 1988 (je to tedy již opravdová dáma v orlích letech). Její dcera se vylíhla v roce 2015 v brněnské zoo, což považujeme za velký úspěch, neboť odchov těchto dravců v zajetí je všeobecně velmi složitý.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<|endoftext|>


<commit_before>'use strict';

const CommunicationError = require('../../lib/error/CommunicationError');
const WebSocket = require('./websocket').WebSocket;
const lib = require('../../lib/baqend');

/**
 * @alias connector.WebSocketConnector
 */
class WebSocketConnector {
  /**
   * @param {connector.Connector} connector a connector
   * @param {String=} url The websocket connect script url
   * @return {connector.WebSocketConnector} a websocket connection
   */
  static create(url) {
    let websocket = this.websockets[url];
    if (!websocket) {
      websocket = new WebSocketConnector(url);
      this.websockets[url] = websocket;
    }
    return websocket;
  }

  /**
   * @param {String} url
   */
  constructor(url) {
    this.observers = {};
    this.socket = null;
    this.url = url;
  }

  open() {
    if (!this.socket) {
      const socket = new WebSocket(this.url);
      let socketPromise;

      const handleSocketCompletion = (error) => {
        // observable error calls can throw an exception therefore cleanup beforehand
        let isError = false;
        if (this.socket === socketPromise) {
          isError = socket.readyState !== 3;
          this.socket = null;
        }

        let firstErr;
        Object.keys(this.observers).forEach((id) => {
          const observer = this.observers[id];
          delete this.observers[id]; // unsubscribe to allow resubscriptions
          try {
            if (isError) {
              observer.error(new CommunicationError(null, error));
            } else {
              observer.complete();
            }
          } catch (e) {
            if (!firstErr) { firstErr = e; }
          }
        });

        if (firstErr) { throw firstErr; }
      };

      socket.onerror = handleSocketCompletion;
      socket.onclose = handleSocketCompletion;
      socket.onmessage = (event) => {
        const message = JSON.parse(event.data);
        message.date = new Date(message.date);

        const id = message.id;
        if (!id) {
          if (message.type === 'error') { handleSocketCompletion(message); }
          return;
        }

        const observer = this.observers[id];
        if (observer) {
          if (message.type === 'error') {
            observer.error(new CommunicationError(null, message));
          } else {
            observer.next(message);
          }
        }
      };

      socketPromise = new Promise((resolve) => {
        socket.onopen = resolve;
      }).then(() => socket);

      this.socket = socketPromise;
    }

    return this.socket;
  }

  close() {
    if (this.socket) {
      this.socket.then((socket) => {
        socket.close();
      });
      this.socket = null;
    }
  }

  /**
   * @param {util.TokenStorage} tokenStorage
   * @param {string} id subscription ID
   * @return {connector.ObservableStream} The channel for sending and receiving messages
   */
  openStream(tokenStorage, id) {
    const stream = new lib.Observable((observer) => {
      if (this.observers[id]) { throw new Error('Only one subscription per stream is allowed.'); }

      this.observers[id] = observer;
      return () => {
        // cleanup only our subscription and handle resubscription on the same stream id correctly
        if (this.observers[id] === observer) { delete this.observers[id]; }
      };
    });

    stream.send = (message) => {
      this.open().then((socket) => {
        message.id = id;
        if (tokenStorage.token) { message.token = tokenStorage.token; }
        const jsonMessage = JSON.stringify(message);
        socket.send(jsonMessage);
      });
    };

    return stream;
  }
}

Object.assign(WebSocketConnector, /** @lends connector.WebSocketConnector */ {
  /**
   * Map of all available connectors to their respective websocket connections
   * @type connector.Connector[]
   */
  websockets: {},
});

module.exports = WebSocketConnector;
<commit_msg>Added null check for observers on socket completion; should fix a strange bug…<commit_after>'use strict';

const CommunicationError = require('../../lib/error/CommunicationError');
const WebSocket = require('./websocket').WebSocket;
const lib = require('../../lib/baqend');

/**
 * @alias connector.WebSocketConnector
 */
class WebSocketConnector {
  /**
   * @param {connector.Connector} connector a connector
   * @param {String=} url The websocket connect script url
   * @return {connector.WebSocketConnector} a websocket connection
   */
  static create(url) {
    let websocket = this.websockets[url];
    if (!websocket) {
      websocket = new WebSocketConnector(url);
      this.websockets[url] = websocket;
    }
    return websocket;
  }

  /**
   * @param {String} url
   */
  constructor(url) {
    this.observers = {};
    this.socket = null;
    this.url = url;
  }

  open() {
    if (!this.socket) {
      const socket = new WebSocket(this.url);
      let socketPromise;

      const handleSocketCompletion = (error) => {
        // observable error calls can throw an exception therefore cleanup beforehand
        let isError = false;
        if (this.socket === socketPromise) {
          isError = socket.readyState !== 3;
          this.socket = null;
        }

        let firstErr;
        Object.keys(this.observers).forEach((id) => {
          const observer = this.observers[id];
          delete this.observers[id]; // unsubscribe to allow resubscriptions
          if (!observer) {
            return;
          }
          try {
            if (isError) {
              observer.error(new CommunicationError(null, error));
            } else {
              observer.complete();
            }
          } catch (e) {
            if (!firstErr) {
              firstErr = e;
            }
          }
        });

        if (firstErr) { throw firstErr; }
      };

      socket.onerror = handleSocketCompletion;
      socket.onclose = handleSocketCompletion;
      socket.onmessage = (event) => {
        const message = JSON.parse(event.data);
        message.date = new Date(message.date);

        const id = message.id;
        if (!id) {
          if (message.type === 'error') { handleSocketCompletion(message); }
          return;
        }

        const observer = this.observers[id];
        if (observer) {
          if (message.type === 'error') {
            observer.error(new CommunicationError(null, message));
          } else {
            observer.next(message);
          }
        }
      };

      socketPromise = new Promise((resolve) => {
        socket.onopen = resolve;
      }).then(() => socket);

      this.socket = socketPromise;
    }

    return this.socket;
  }

  close() {
    if (this.socket) {
      this.socket.then((socket) => {
        socket.close();
      });
      this.socket = null;
    }
  }

  /**
   * @param {util.TokenStorage} tokenStorage
   * @param {string} id subscription ID
   * @return {connector.ObservableStream} The channel for sending and receiving messages
   */
  openStream(tokenStorage, id) {
    const stream = new lib.Observable((observer) => {
      if (this.observers[id]) { throw new Error('Only one subscription per stream is allowed.'); }

      this.observers[id] = observer;
      return () => {
        // cleanup only our subscription and handle resubscription on the same stream id correctly
        if (this.observers[id] === observer) { delete this.observers[id]; }
      };
    });

    stream.send = (message) => {
      this.open().then((socket) => {
        message.id = id;
        if (tokenStorage.token) { message.token = tokenStorage.token; }
        const jsonMessage = JSON.stringify(message);
        socket.send(jsonMessage);
      });
    };

    return stream;
  }
}

Object.assign(WebSocketConnector, /** @lends connector.WebSocketConnector */ {
  /**
   * Map of all available connectors to their respective websocket connections
   * @type connector.Connector[]
   */
  websockets: {},
});

module.exports = WebSocketConnector;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

// Constants
import { FORM_ELEMENTS } from 'components/dashboards/form/constants';

// Components
import Field from 'components/form/Field';
import Input from 'components/form/Input';
import TextArea from 'components/form/TextArea';
import FileImage from 'components/form/FileImage';
import Checkbox from 'components/form/Checkbox';

// Wysiwyg
import Wysiwyg from 'components/form/Wysiwyg';
import DashboardWidget from 'components/dashboards/wysiwyg/DashboardWidget';
import WidgetBlockEdition from 'components/dashboards/wysiwyg/widget-block-edition/widget-block-edition';

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

    this.state = {
      id: props.id,
      form: props.form
    };
  }

  componentWillReceiveProps(nextProps) {
    this.setState({ form: nextProps.form });
  }

  render() {
    // Reset FORM_ELEMENTS
    FORM_ELEMENTS.elements = {};

    return (

        <fieldset className="c-field-container">
          {/* NAME */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.name = c; }}
            onChange={value => this.props.onChange({ name: value })}
            validations={['required']}
            className="-fluid"
            properties={{
              name: 'name',
              label: 'Name',
              type: 'text',
              required: true,
              default: this.state.form.name
            }}
          >
            {Input}
          </Field>

          {/* SUMMARY */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.summary = c; }}
            onChange={value => this.props.onChange({ summary: value })}
            className="-fluid"
            properties={{
              name: 'summary',
              label: 'Summary',
              rows: '6',
              default: this.state.form.summary
            }}
          >
            {TextArea}
          </Field>

          {/* DESCRIPTION */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.description = c; }}
            onChange={value => this.props.onChange({ description: value })}
            className="-fluid"
            properties={{
              name: 'description',
              label: 'Description',
              rows: '6',
              default: this.state.form.description
            }}
          >
            {TextArea}
          </Field>

          {/* THUMBNAIL */}

                <Field
                  ref={(c) => { if (c) FORM_ELEMENTS.elements.photo = c; }}
                  onChange={(value) => {
                    this.props.onChange({ photo: value });
                  }}
                  validations={['required']}
                  className="-fluid"
                  properties={{
                    name: 'photo',
                    label: 'Photo',
                    placeholder: 'Browse file',
                    default: this.state.form.photo,
                    required: true
                  }}
                >
                  {FileImage}
                </Field>

          {/* PUBLISHED */}
          {!this.props.basic &&
            <Field
              ref={(c) => { if (c) FORM_ELEMENTS.elements.published = c; }}
              onChange={value => this.props.onChange({
                published: value.checked,
                private: !value.checked
              })}
              properties={{
                name: 'published',
                label: 'Do you want to set this dasboard as published?',
                value: 'published',
                title: 'Published',
                defaultChecked: this.props.form.published,
                checked: this.props.form.published
              }}
            >
              {Checkbox}
            </Field>
          }
        </fieldset>

        <fieldset className="c-field-container">
          {/* CONTENT */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.content = c; }}
            onChange={value => this.props.onChange({ content: value })}
            validations={['required']}
            className="-fluid"
            properties={{
              name: 'content',
              label: 'Content',
              required: true,
              default: this.state.form.content,
              blocks: {
                widget: {
                  Component: DashboardWidget,
                  EditionComponent: WidgetBlockEdition,
                  renderer: 'modal'
                }
              },
              onUploadImage: (files) => {
                return new Promise((resolve, reject) => {
                  const file = files[0];
                  console.log(file);
                  resolve(file.name);

                  // reject(file.name);
                });
              }
            }}
          >
            {Wysiwyg}
          </Field>
        </fieldset>

    );
  }
}

Step1.propTypes = {
  id: PropTypes.string,
  form: PropTypes.object,
  basic: PropTypes.bool,
  onChange: PropTypes.func
};

export default Step1;
<commit_msg>WIP: image uploads<commit_after>import React from 'react';
import PropTypes from 'prop-types';

// Constants
import { FORM_ELEMENTS } from 'components/dashboards/form/constants';

// Components
import Field from 'components/form/Field';
import Input from 'components/form/Input';
import TextArea from 'components/form/TextArea';
import FileImage from 'components/form/FileImage';
import Checkbox from 'components/form/Checkbox';

// Wysiwyg
import Wysiwyg from 'components/form/Wysiwyg';
import DashboardWidget from 'components/dashboards/wysiwyg/DashboardWidget';
import WidgetBlockEdition from 'components/dashboards/wysiwyg/widget-block-edition/widget-block-edition';

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

    this.state = {
      id: props.id,
      form: props.form
    };
  }

  componentWillReceiveProps(nextProps) {
    this.setState({ form: nextProps.form });
  }

  render() {
    // Reset FORM_ELEMENTS
    FORM_ELEMENTS.elements = {};

    return (

        <fieldset className="c-field-container">
          {/* NAME */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.name = c; }}
            onChange={value => this.props.onChange({ name: value })}
            validations={['required']}
            className="-fluid"
            properties={{
              name: 'name',
              label: 'Name',
              type: 'text',
              required: true,
              default: this.state.form.name
            }}
          >
            {Input}
          </Field>

          {/* SUMMARY */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.summary = c; }}
            onChange={value => this.props.onChange({ summary: value })}
            className="-fluid"
            properties={{
              name: 'summary',
              label: 'Summary',
              rows: '6',
              default: this.state.form.summary
            }}
          >
            {TextArea}
          </Field>

          {/* DESCRIPTION */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.description = c; }}
            onChange={value => this.props.onChange({ description: value })}
            className="-fluid"
            properties={{
              name: 'description',
              label: 'Description',
              rows: '6',
              default: this.state.form.description
            }}
          >
            {TextArea}
          </Field>

          {/* THUMBNAIL */}

                <Field
                  ref={(c) => { if (c) FORM_ELEMENTS.elements.photo = c; }}
                  onChange={(value) => {
                    this.props.onChange({ photo: value });
                  }}
                  validations={['required']}
                  className="-fluid"
                  properties={{
                    name: 'photo',
                    label: 'Photo',
                    placeholder: 'Browse file',
                    default: this.state.form.photo,
                    required: true
                  }}
                >
                  {FileImage}
                </Field>

          {/* PUBLISHED */}
          {!this.props.basic &&
            <Field
              ref={(c) => { if (c) FORM_ELEMENTS.elements.published = c; }}
              onChange={value => this.props.onChange({
                published: value.checked,
                private: !value.checked
              })}
              properties={{
                name: 'published',
                label: 'Do you want to set this dasboard as published?',
                value: 'published',
                title: 'Published',
                defaultChecked: this.props.form.published,
                checked: this.props.form.published
              }}
            >
              {Checkbox}
            </Field>
          }
        </fieldset>

        <fieldset className="c-field-container">
          {/* CONTENT */}
          <Field
            ref={(c) => { if (c) FORM_ELEMENTS.elements.content = c; }}
            onChange={value => this.props.onChange({ content: value })}
            validations={['required']}
            className="-fluid"
            properties={{
              name: 'content',
              label: 'Content',
              required: true,
              default: this.state.form.content,
              blocks: {
                widget: {
                  Component: DashboardWidget,
                  EditionComponent: WidgetBlockEdition,
                  renderer: 'modal'
                }
              },
              onUploadImage: (files) => {
                return new Promise((resolve, reject) => {
                  const file = files[0];

                  setTimeout(() => {
                    console.log(file);
                    resolve(file.name);
                  }, 2000)

                  // reject(file.name);
                });
              }
            }}
          >
            {Wysiwyg}
          </Field>
        </fieldset>

    );
  }
}

Step1.propTypes = {
  id: PropTypes.string,
  form: PropTypes.object,
  basic: PropTypes.bool,
  onChange: PropTypes.func
};

export default Step1;
<|endoftext|>


<commit_before>$(function(){
    // re-create the bootstrap collapse... but slide from left
    $(document).on('click', '[data-toggle="slide-collapse"]', function(event) {
        event.preventDefault(event);
        var collapsed = this.classList.contains('collapsed');
        $btn = $(this);
        target = $btn.data('target');
        $('[data-toggle="slide-collapse"][data-target="' + target + '"]').toggleClass('collapsed', collapsed);
        if (!collapsed) {
            hide_sidebar();
        } else {
            show_sidebar();
        }
    });

    highlightBookmarkButton();

    // open sidebar if active page link clicked
    $('#left-nav li a').on('click', function(event) {
        // if the link has a [data-is-link] attribute navigate to the link
        if(!event.currentTarget.dataset.isLink) {
            event.preventDefault();
        } else {
            var href = event.currentTarget.href;
            window.location.href = href;
            return false;
        }

        const $link = $(this);
        const $sidebar_inner = $($link.data('sidebar')); // (.sidebar_inner)

        // show 2nd level - if on 3rd level
        let secondlevel_menuitems = $('.sidebar-menu > li.collapse').length;
        let open_secondlevel_menuitems = $('.sidebar-menu > li.collapse.in').length
        let thirdLevelOpen = secondlevel_menuitems !== open_secondlevel_menuitems;

        // alter tab states
        $link.parent().addClass(activeClass).siblings().removeClass(activeClass);

        // hide if not sidebar found
        if ($sidebar_inner.length == 0) {
            hide_sidebar();
        } else {
            if ($('body').hasClass('collapsed')) {
                // closed sidebar
                show_sidebar();
                $sidebar_inner.addClass(activeClass).siblings().removeClass(activeClass)
                if ($('body').hasClass('auto')) $('body').toggleClass('auto manual')

            } else {
                // already open sidebar
                if ($sidebar_inner.hasClass(activeClass)) {
                    // hide sidebar if clicked item already active and on 2nd level
                    if(!thirdLevelOpen) {
                        hide_sidebar();
                    } else {
                        hideMenuItems(event);
                        // @todo: make the sidebar show 2nd level and not hide_sidebar()
                        hide_sidebar();
                    }
                    if ($('body').hasClass('auto')) $('body').toggleClass('auto manual')
                } else {
                    // enable correct sidebar inner based on clicked tab
                    $sidebar_inner.addClass(activeClass).find('li a').each(function(){
                        $(this)[0].tabIndex = "0";
                    })
                    $sidebar_inner.siblings('.sidebar-inner').each(function(i,n) {
                        $(this).removeClass(activeClass);
                        $(this).find('li a').each(function(j,m){
                            $(this)[0].tabIndex = "-1";
                        })
                    })
                }
            }
        }
    });

    // on trigger sidebar hide/show
    $('#sidebar').on('hide.sidebar.collapse show.sidebar.collapse', function(event){
        // resize after slight delay
        var timeout = false
        timeout = setTimeout(function(){
            if(timeout) clearTimeout(timeout)
            // if (typeof graph_resize === 'function'){
            //     graph_resize();
            // }
            // if (typeof graph_draw === 'function'){
            //     graph_draw();
            // }
            // @note: assumes the css animation takes 200ms
            if(event.type === 'hide') {
                $('#sidebar').trigger('hidden.sidebar.collapse')
            }else{
                $('#sidebar').trigger('shown.sidebar.collapse')
            }
        }, 200);
    });

    $(document).on('window.resized', function(){
        if ($('body').hasClass('auto')) {
            if ($(window).width() < 870) {
                hide_sidebar();
                document.body.classList.add('narrow');
            }
            if ($(window).width() >= 870 && $(document.body).hasClass('collapsed')) {
                show_sidebar();
                document.body.classList.remove('narrow');
            }
        } else {
            if (!$(document.body).hasClass('collapsed')) {
                if ($(window).width() < 870) {
                    $(".content-container").css("margin","2.7rem 0 0 0");
                } else {
                    $('body').toggleClass('manual auto')
                    $(".content-container").css("margin","2.7rem 0 0 15rem");
                }
            }
        }
    })

    // hide sidebar on load on narrow devices
    if ($(window).width() < 870) {
        document.body.classList.add('narrow','collapsed');
        hide_sidebar();
        // allow narrow screens to expand sidebar after delay to avoid animation of hiding sidebar
        setTimeout(function(){
            document.body.classList.add('has-animation');
        }, 500);
    }
    /**
     * If menu 3rd level menu shown shrink 2nd level entries
     *
     * @param {object} [event] mouse event if triggered by click
     */
    function hideMenuItems(event) {
        if (!event) return;

        var $menu = $(event.target).parents('ul').first();
        var clicked = false;
        if (typeof event !== 'undefined') {
            event.preventDefault();
            event.stopPropagation();
            clicked = true;
        }
        let link = $menu.find('li.active a');
        if (clicked) {
            // hide the back arrow from active third level links - on click
            $(event.target).parents('.nav').first().find('.active .third-level-indicator').toggleClass('hidden');
        }
        let active_menu = link.parents('.sidebar-menu').first();
        if(active_menu.length !== 1) return; // no menu found

        let active_menu_name = active_menu.attr('id').split('-');
        active_menu_name.shift();

        let relative_path = window.location.href.replace(path,''); // eg subtracts http://localhost/emoncms from http://localhost/emoncms/feed/list
        let controller = relative_path.split('/')[0].replace(/(.*)#.*/,'$1'); // eg. feed
        let include_id = [active_menu_name,controller,'sidebar','include'].join('-'); // eg. setup-feed-sidebar-include
        let include = $('#' + include_id);

        if (include.length == 1 && clicked) {
            // show 3rd level menu
            include.toggleClass('in');
            // hide 2nd level menu items
            $menu.find('li').not('.active').toggleClass('in');
        }
    }
    function getQueryStringValue (key) {
        return decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURIComponent(key).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
    }
    // add current page to user's bookmark list
    $('#set-bookmark, #remove-bookmark').click(function(event) {
        event.preventDefault();
        var bookmarks = [];
        var $nav = $('#footer_nav');
        var currentPage = window.location.href.replace(path,'');
        var key = 'bookmarks';
        var $button = $(this);
        var $icon = $button.find('.icon');
        var remove = $icon.is('.star');
        var currentTitle = $('#sidebar .sidebar-menu li.active a').first().text();
        if(currentTitle.length==0) currentTitle = $('h1').first().text();
        if(currentTitle.length==0) currentTitle = $('h2').first().text();
        if(currentTitle.length==0) currentTitle = $('h3').first().text();
        if(currentTitle.length==0) currentTitle = document.title;
        if(currentTitle.toLowerCase().trim() === 'graphs') {
            let graphName = $('#graphName').val()
            if(graphName.length > 0) currentTitle = graphName
        }
        if(getQueryStringValue("name")) {
            currentTitle = decodeURI(getQueryStringValue("name").replace('+',' '));
        }
        // get current bookmarks
        $.get(path+'user/preferences.json',{preferences:key})
        .done(function(data){
            // catch json parsing errors
            bookmarks = data || [];
            if(!remove) {
            // remove current page to bookmarks
                var unique = false;
                for(b in bookmarks) {
                    if (bookmarks[b]['path'] && bookmarks[b]['path'] !== currentPage){
                        unique = true;
                    }
                }
                if(unique || bookmarks.length === 0){
                    bookmarks.push({
                        'path': currentPage,
                        'text': currentTitle
                    })
                }
            } else {
            // remove current page from bookmarks
                var newBookmarks = [];
                for(b in bookmarks) {
                    if (bookmarks[b]['path'] && bookmarks[b]['path'] !== currentPage){
                        newBookmarks.push(bookmarks[b]);
                    }
                }
                bookmarks = newBookmarks;
            }
            // save new user preferences
            $.post(path+'user/preferences.json', {
                preferences: {
                    bookmarks: JSON.stringify(bookmarks)
                }
            }, function(data) {
                var $menu = $('#sidebar_bookmarks');
                var $template = $('#bookmark_link');
                if(data.success) {
                    // saved successfully change icon
                    $('#set-bookmark, #remove-bookmark').parent().toggleClass('d-none');
                    if(!remove) {
                        // add new item to menu
                        $($template.html()).appendTo($menu)
                        .find('a').attr({
                            href: path+currentPage,
                            title: currentTitle
                        })
                        .text(currentTitle).hide().fadeIn();
                        $menu.trigger('bookmarks:updated');
                        $nav.fadeIn();

                    } else {
                        // remove entry from menu
                        $.each($menu.find('li'), function(n, elem){
                            $li = $(elem);
                            var relative = $li.find('a').attr('href').replace(path,'');
                            if(relative === currentPage) {
                                $li.animate({height:0},function(){
                                    $(this).remove();
                                    $menu.trigger('bookmarks:updated');
                                    setTimeout(function(){
                                        if($menu.find('li').length == 0) {
                                            $nav.fadeOut();
                                        }
                                        // $nav.toggleClass('d-none', $menu.find('li').length == 0);
                                    },400)
                                });
                            }
                        });
                    }
                }
            });
        });
    });

    // show/hide sidebar includes
    $(document).on('click', '#menu-emoncms li.active a', hideMenuItems);
    // show hide 2nd / 3rd menu items
    // setTimeout(hideMenuItems, 100);

    // save a cookie to remember user's choice to hide or show the bookmarks
    $('#sidebar_bookmarks').on('show hide', function(event) {
        var bookmarks_collapsed = event.type !== 'show';
        docCookies.setItem('bookmarks_collapsed', bookmarks_collapsed)
    })

    $(document).keyup(function(e) {
        if (e.keyCode == 27) { // escape key maps to keycode `27`
            $('.navbar .dropdown').removeClass('open')
        }
    });

}); // end of jquery ready()

// trigger the events to allow module js scripts to attach actions to the events
function show_sidebar(options) {
    $('#sidebar').trigger('show.sidebar.collapse');
    $('body').removeClass('collapsed').addClass('expanded');

    if ($(window).width() < 870) {
        $(".content-container").css("margin","2.7rem 0 0 0");
    } else {
        $(".content-container").css("margin","2.7rem 0 0 15rem");
    }
}
function hide_sidebar(options) {
    $('#sidebar').trigger('hide.sidebar.collapse');
    $('body').addClass('collapsed').removeClass('expanded');
    $(".content-container").css("margin","2.7rem auto 0 auto");
}

// backward compatible empty function
if(typeof init_sidebar !== 'function') var init_sidebar = function(){}

// get/set document cookies
var docCookies = {
    getItem: function (sKey) {
      if (!sKey) { return null; }
      return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
    },
    setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
      if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
      var sExpires = "";
      if (vEnd) {
        switch (vEnd.constructor) {
          case Number:
          //   sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
            sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; expires=" + (new Date(vEnd * 1e3 + Date.now())).toUTCString();
            break;
          case String:
            sExpires = "; expires=" + vEnd;
            break;
          case Date:
            sExpires = "; expires=" + vEnd.toUTCString();
            break;
        }
      }
      document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
      return true;
    },
    removeItem: function (sKey, sPath, sDomain) {
      if (!this.hasItem(sKey)) { return false; }
      document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
      return true;
    },
    hasItem: function (sKey) {
      if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
      return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
    },
    keys: function () {
      var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
      for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
      return aKeys;
    }
  };

// if bookmarks has url hash fragment (eg. controller/view/#fragment) - js must be used to show
// @todo : this might not be needed to be done in php now?
// @see : https://github.com/emoncms/emoncms/blob/master/Theme/basic/menu_view.php#L66
function highlightBookmarkButton() {
    if (typeof user_bookmarks !== 'undefined') {
        var currentPageIsBookmarked = false
        for (n in user_bookmarks) {
            let bookmark = user_bookmarks[n]
            if (path + bookmark.path === window.location.href) {
                currentPageIsBookmarked = true
            }
        }
        if (currentPageIsBookmarked) {
            $('#remove-bookmark').parent().removeClass('d-none')
            $('#set-bookmark').parent().addClass('d-none')
        } else {
            $('#remove-bookmark').parent().addClass('d-none')
            $('#set-bookmark').parent().removeClass('d-none')
        }
    }
}

window.addEventListener('hashchange', function(event) {
    highlightBookmarkButton()
});<commit_msg>corrected issue with activeClass being undefined<commit_after>$(function(){
    // re-create the bootstrap collapse... but slide from left
    $(document).on('click', '[data-toggle="slide-collapse"]', function(event) {
        event.preventDefault(event);
        var collapsed = this.classList.contains('collapsed');
        $btn = $(this);
        target = $btn.data('target');
        $('[data-toggle="slide-collapse"][data-target="' + target + '"]').toggleClass('collapsed', collapsed);
        if (!collapsed) {
            hide_sidebar();
        } else {
            show_sidebar();
        }
    });

    highlightBookmarkButton();

    // open sidebar if active page link clicked
    $('#left-nav li a').on('click', function(event) {
        // if the link has a [data-is-link] attribute navigate to the link
        if(!event.currentTarget.dataset.isLink) {
            event.preventDefault();
        } else {
            var href = event.currentTarget.href;
            window.location.href = href;
            return false;
        }

        const $link = $(this);
        const $sidebar_inner = $($link.data('sidebar')); // (.sidebar_inner)
        const activeClass = 'active';

        // show 2nd level - if on 3rd level
        let secondlevel_menuitems = $('.sidebar-menu > li.collapse').length;
        let open_secondlevel_menuitems = $('.sidebar-menu > li.collapse.in').length
        let thirdLevelOpen = secondlevel_menuitems !== open_secondlevel_menuitems;

        // alter tab states
        $link.parent().addClass(activeClass).siblings().removeClass(activeClass);

        // hide if not sidebar found
        if ($sidebar_inner.length == 0) {
            hide_sidebar();
        } else {
            if ($('body').hasClass('collapsed')) {
                // closed sidebar
                show_sidebar();
                $sidebar_inner.addClass(activeClass).siblings().removeClass(activeClass)
                if ($('body').hasClass('auto')) $('body').toggleClass('auto manual')

            } else {
                // already open sidebar
                if ($sidebar_inner.hasClass(activeClass)) {
                    // hide sidebar if clicked item already active and on 2nd level
                    if(!thirdLevelOpen) {
                        hide_sidebar();
                    } else {
                        hideMenuItems(event);
                        // @todo: make the sidebar show 2nd level and not hide_sidebar()
                        hide_sidebar();
                    }
                    if ($('body').hasClass('auto')) $('body').toggleClass('auto manual')
                } else {
                    // enable correct sidebar inner based on clicked tab
                    $sidebar_inner.addClass(activeClass).find('li a').each(function(){
                        $(this)[0].tabIndex = "0";
                    })
                    $sidebar_inner.siblings('.sidebar-inner').each(function(i,n) {
                        $(this).removeClass(activeClass);
                        $(this).find('li a').each(function(j,m){
                            $(this)[0].tabIndex = "-1";
                        })
                    })
                }
            }
        }
    });

    // on trigger sidebar hide/show
    $('#sidebar').on('hide.sidebar.collapse show.sidebar.collapse', function(event){
        // resize after slight delay
        var timeout = false
        timeout = setTimeout(function(){
            if(timeout) clearTimeout(timeout)
            // if (typeof graph_resize === 'function'){
            //     graph_resize();
            // }
            // if (typeof graph_draw === 'function'){
            //     graph_draw();
            // }
            // @note: assumes the css animation takes 200ms
            if(event.type === 'hide') {
                $('#sidebar').trigger('hidden.sidebar.collapse')
            }else{
                $('#sidebar').trigger('shown.sidebar.collapse')
            }
        }, 200);
    });

    $(document).on('window.resized', function(){
        if ($('body').hasClass('auto')) {
            if ($(window).width() < 870) {
                hide_sidebar();
                document.body.classList.add('narrow');
            }
            if ($(window).width() >= 870 && $(document.body).hasClass('collapsed')) {
                show_sidebar();
                document.body.classList.remove('narrow');
            }
        } else {
            if (!$(document.body).hasClass('collapsed')) {
                if ($(window).width() < 870) {
                    $(".content-container").css("margin","2.7rem 0 0 0");
                } else {
                    $('body').toggleClass('manual auto')
                    $(".content-container").css("margin","2.7rem 0 0 15rem");
                }
            }
        }
    })

    // hide sidebar on load on narrow devices
    if ($(window).width() < 870) {
        document.body.classList.add('narrow','collapsed');
        hide_sidebar();
        // allow narrow screens to expand sidebar after delay to avoid animation of hiding sidebar
        setTimeout(function(){
            document.body.classList.add('has-animation');
        }, 500);
    }
    /**
     * If menu 3rd level menu shown shrink 2nd level entries
     *
     * @param {object} [event] mouse event if triggered by click
     */
    function hideMenuItems(event) {
        if (!event) return;

        var $menu = $(event.target).parents('ul').first();
        var clicked = false;
        if (typeof event !== 'undefined') {
            event.preventDefault();
            event.stopPropagation();
            clicked = true;
        }
        let link = $menu.find('li.active a');
        if (clicked) {
            // hide the back arrow from active third level links - on click
            $(event.target).parents('.nav').first().find('.active .third-level-indicator').toggleClass('hidden');
        }
        let active_menu = link.parents('.sidebar-menu').first();
        if(active_menu.length !== 1) return; // no menu found

        let active_menu_name = active_menu.attr('id').split('-');
        active_menu_name.shift();

        let relative_path = window.location.href.replace(path,''); // eg subtracts http://localhost/emoncms from http://localhost/emoncms/feed/list
        let controller = relative_path.split('/')[0].replace(/(.*)#.*/,'$1'); // eg. feed
        let include_id = [active_menu_name,controller,'sidebar','include'].join('-'); // eg. setup-feed-sidebar-include
        let include = $('#' + include_id);

        if (include.length == 1 && clicked) {
            // show 3rd level menu
            include.toggleClass('in');
            // hide 2nd level menu items
            $menu.find('li').not('.active').toggleClass('in');
        }
    }
    function getQueryStringValue (key) {
        return decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURIComponent(key).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
    }
    // add current page to user's bookmark list
    $('#set-bookmark, #remove-bookmark').click(function(event) {
        event.preventDefault();
        var bookmarks = [];
        var $nav = $('#footer_nav');
        var currentPage = window.location.href.replace(path,'');
        var key = 'bookmarks';
        var $button = $(this);
        var $icon = $button.find('.icon');
        var remove = $icon.is('.star');
        var currentTitle = $('#sidebar .sidebar-menu li.active a').first().text();
        if(currentTitle.length==0) currentTitle = $('h1').first().text();
        if(currentTitle.length==0) currentTitle = $('h2').first().text();
        if(currentTitle.length==0) currentTitle = $('h3').first().text();
        if(currentTitle.length==0) currentTitle = document.title;
        if(currentTitle.toLowerCase().trim() === 'graphs') {
            let graphName = $('#graphName').val()
            if(graphName.length > 0) currentTitle = graphName
        }
        if(getQueryStringValue("name")) {
            currentTitle = decodeURI(getQueryStringValue("name").replace('+',' '));
        }
        // get current bookmarks
        $.get(path+'user/preferences.json',{preferences:key})
        .done(function(data){
            // catch json parsing errors
            bookmarks = data || [];
            if(!remove) {
            // remove current page to bookmarks
                var unique = false;
                for(b in bookmarks) {
                    if (bookmarks[b]['path'] && bookmarks[b]['path'] !== currentPage){
                        unique = true;
                    }
                }
                if(unique || bookmarks.length === 0){
                    bookmarks.push({
                        'path': currentPage,
                        'text': currentTitle
                    })
                }
            } else {
            // remove current page from bookmarks
                var newBookmarks = [];
                for(b in bookmarks) {
                    if (bookmarks[b]['path'] && bookmarks[b]['path'] !== currentPage){
                        newBookmarks.push(bookmarks[b]);
                    }
                }
                bookmarks = newBookmarks;
            }
            // save new user preferences
            $.post(path+'user/preferences.json', {
                preferences: {
                    bookmarks: JSON.stringify(bookmarks)
                }
            }, function(data) {
                var $menu = $('#sidebar_bookmarks');
                var $template = $('#bookmark_link');
                if(data.success) {
                    // saved successfully change icon
                    $('#set-bookmark, #remove-bookmark').parent().toggleClass('d-none');
                    if(!remove) {
                        // add new item to menu
                        $($template.html()).appendTo($menu)
                        .find('a').attr({
                            href: path+currentPage,
                            title: currentTitle
                        })
                        .text(currentTitle).hide().fadeIn();
                        $menu.trigger('bookmarks:updated');
                        $nav.fadeIn();

                    } else {
                        // remove entry from menu
                        $.each($menu.find('li'), function(n, elem){
                            $li = $(elem);
                            var relative = $li.find('a').attr('href').replace(path,'');
                            if(relative === currentPage) {
                                $li.animate({height:0},function(){
                                    $(this).remove();
                                    $menu.trigger('bookmarks:updated');
                                    setTimeout(function(){
                                        if($menu.find('li').length == 0) {
                                            $nav.fadeOut();
                                        }
                                        // $nav.toggleClass('d-none', $menu.find('li').length == 0);
                                    },400)
                                });
                            }
                        });
                    }
                }
            });
        });
    });

    // show/hide sidebar includes
    $(document).on('click', '#menu-emoncms li.active a', hideMenuItems);
    // show hide 2nd / 3rd menu items
    // setTimeout(hideMenuItems, 100);

    // save a cookie to remember user's choice to hide or show the bookmarks
    $('#sidebar_bookmarks').on('show hide', function(event) {
        var bookmarks_collapsed = event.type !== 'show';
        docCookies.setItem('bookmarks_collapsed', bookmarks_collapsed)
    })

    $(document).keyup(function(e) {
        if (e.keyCode == 27) { // escape key maps to keycode `27`
            $('.navbar .dropdown').removeClass('open')
        }
    });

}); // end of jquery ready()

// trigger the events to allow module js scripts to attach actions to the events
function show_sidebar(options) {
    $('#sidebar').trigger('show.sidebar.collapse');
    $('body').removeClass('collapsed').addClass('expanded');

    if ($(window).width() < 870) {
        $(".content-container").css("margin","2.7rem 0 0 0");
    } else {
        $(".content-container").css("margin","2.7rem 0 0 15rem");
    }
}
function hide_sidebar(options) {
    $('#sidebar').trigger('hide.sidebar.collapse');
    $('body').addClass('collapsed').removeClass('expanded');
    $(".content-container").css("margin","2.7rem auto 0 auto");
}

// backward compatible empty function
if(typeof init_sidebar !== 'function') var init_sidebar = function(){}

// get/set document cookies
var docCookies = {
    getItem: function (sKey) {
      if (!sKey) { return null; }
      return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
    },
    setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
      if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
      var sExpires = "";
      if (vEnd) {
        switch (vEnd.constructor) {
          case Number:
          //   sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
            sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; expires=" + (new Date(vEnd * 1e3 + Date.now())).toUTCString();
            break;
          case String:
            sExpires = "; expires=" + vEnd;
            break;
          case Date:
            sExpires = "; expires=" + vEnd.toUTCString();
            break;
        }
      }
      document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
      return true;
    },
    removeItem: function (sKey, sPath, sDomain) {
      if (!this.hasItem(sKey)) { return false; }
      document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
      return true;
    },
    hasItem: function (sKey) {
      if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
      return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
    },
    keys: function () {
      var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
      for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
      return aKeys;
    }
  };

// if bookmarks has url hash fragment (eg. controller/view/#fragment) - js must be used to show
// @todo : this might not be needed to be done in php now?
// @see : https://github.com/emoncms/emoncms/blob/master/Theme/basic/menu_view.php#L66
function highlightBookmarkButton() {
    if (typeof user_bookmarks !== 'undefined') {
        var currentPageIsBookmarked = false
        for (n in user_bookmarks) {
            let bookmark = user_bookmarks[n]
            if (path + bookmark.path === window.location.href) {
                currentPageIsBookmarked = true
            }
        }
        if (currentPageIsBookmarked) {
            $('#remove-bookmark').parent().removeClass('d-none')
            $('#set-bookmark').parent().addClass('d-none')
        } else {
            $('#remove-bookmark').parent().addClass('d-none')
            $('#set-bookmark').parent().removeClass('d-none')
        }
    }
}

window.addEventListener('hashchange', function(event) {
    highlightBookmarkButton()
});<|endoftext|>


<commit_before>/**
 * Checks if a given DOM property of an element has the expected value. For all the available DOM element properties, consult the [Element doc at MDN](https://developer.mozilla.org/en-US/docs/Web/API/element).
 *
 * @example
 * this.demoTest = function (browser) {
 *   browser.expect.element('body').to.have.propery('className').equals('test-class');
 *   browser.expect.element('body').to.have.propery('className').matches(/^something\ else/);
 *   browser.expect.element('body').to.not.have.propery('classList').equals('test-class');
 *   browser.expect.element('body').to.have.propery('classList').deep.equal(['class-one', 'class-two']);
 *   browser.expect.element('body').to.have.propery('classList').contain('class-two');
 * };
 *
 * @method property
 * @param {string} property The property name
 * @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
 * @display .property(name)
 * @api expect.element
 */
const BaseAssertion = require('./_element-assertion.js');

class PropertyAssertion extends BaseAssertion {
  static get assertionType() {
    return BaseAssertion.AssertionType.METHOD;
  }

  init(property, msg) {
    super.init();

    this.flag('attributeFlag', true);
    this.property = property;
    this.hasCustomMessage = typeof msg != 'undefined';
    this.message = msg || 'Expected element <%s> to ' + (this.negate ? 'not have' : 'have') + ' dom property "' + property + '"';

    this.start();
  }

  executeCommand() {
    return this.executeProtocolAction('getElementProperty', [this.property]).then(result => {
      if (!this.transport.isResultSuccess(result) || result.value === null) {
        throw result;
      }

      return result;
    }).catch(result => {
      this.propertyNotFound();

      return false;
    });
  }

  onResultSuccess() {
    if (this.retries > 0 && this.negate) {
      return;
    }

    if (!this.hasCondition()) {
      this.passed = !this.negate;
      this.expected = this.negate ? 'not found' : 'found';
      this.actual = 'found';
    }

    this.addExpectedInMessagePart();
  }

  propertyNotFound() {
    this.processFlags();
    this.passed = this.hasCondition() ? false : this.negate;

    if (!this.passed && this.shouldRetry()) {
      this.scheduleRetry();
    } else {
      this.addExpectedInMessagePart();
      if (!this.hasCondition()) {
        console.log('EXPECTED', this.expected)
        //this.expected = this.negate ? 'not found' : 'found';
        this.actual = 'not found';
      }

      if (!this.negate) {
        this.messageParts.push(' - property was not found');
      }
      this.done();
    }
  }

  onResultFailed() {
    this.passed = false;
  }
}

module.exports = PropertyAssertion;
<commit_msg>Update property.js (#2332)<commit_after>/**
 * Checks if a given DOM property of an element has the expected value. For all the available DOM element properties, consult the [Element doc at MDN](https://developer.mozilla.org/en-US/docs/Web/API/element).
 *
 * @example
 * this.demoTest = function (browser) {
 *   browser.expect.element('body').to.have.property('className').equals('test-class');
 *   browser.expect.element('body').to.have.property('className').matches(/^something\ else/);
 *   browser.expect.element('body').to.not.have.property('classList').equals('test-class');
 *   browser.expect.element('body').to.have.property('classList').deep.equal(['class-one', 'class-two']);
 *   browser.expect.element('body').to.have.property('classList').contain('class-two');
 * };
 *
 * @method property
 * @param {string} property The property name
 * @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
 * @display .property(name)
 * @api expect.element
 */
const BaseAssertion = require('./_element-assertion.js');

class PropertyAssertion extends BaseAssertion {
  static get assertionType() {
    return BaseAssertion.AssertionType.METHOD;
  }

  init(property, msg) {
    super.init();

    this.flag('attributeFlag', true);
    this.property = property;
    this.hasCustomMessage = typeof msg != 'undefined';
    this.message = msg || 'Expected element <%s> to ' + (this.negate ? 'not have' : 'have') + ' dom property "' + property + '"';

    this.start();
  }

  executeCommand() {
    return this.executeProtocolAction('getElementProperty', [this.property]).then(result => {
      if (!this.transport.isResultSuccess(result) || result.value === null) {
        throw result;
      }

      return result;
    }).catch(result => {
      this.propertyNotFound();

      return false;
    });
  }

  onResultSuccess() {
    if (this.retries > 0 && this.negate) {
      return;
    }

    if (!this.hasCondition()) {
      this.passed = !this.negate;
      this.expected = this.negate ? 'not found' : 'found';
      this.actual = 'found';
    }

    this.addExpectedInMessagePart();
  }

  propertyNotFound() {
    this.processFlags();
    this.passed = this.hasCondition() ? false : this.negate;

    if (!this.passed && this.shouldRetry()) {
      this.scheduleRetry();
    } else {
      this.addExpectedInMessagePart();
      if (!this.hasCondition()) {
        console.log('EXPECTED', this.expected)
        //this.expected = this.negate ? 'not found' : 'found';
        this.actual = 'not found';
      }

      if (!this.negate) {
        this.messageParts.push(' - property was not found');
      }
      this.done();
    }
  }

  onResultFailed() {
    this.passed = false;
  }
}

module.exports = PropertyAssertion;
<|endoftext|>


<commit_before>// a JSON-to-JSON translater used by a migration

function originalToJSLibFigure(figures) {
  return figures.map(originalToJSLibFigure1);
}

function originalToJSLibFigure1(figure) {
  var move = translateMoveName(figure.move);
  var params = parameters(move);
  var get_parameter_values = function (param) {
    if (param.name === 'who') {
      return translateWho(figure.who);
    } else if (param.name === 'beats') {
      return figure.beats;
    } else if (param.name === 'bal') {
      return figure.balance || false;
    } else if (param.name === 'hand') {
      return oldMoveIsClockwise(figure.move);
    } else if (param.name === 'circling' ||
               param.name === 'places' ||
               param.name === 'turn' ||
               param.name === 'shoulder') {
      return figure.degrees;
    } else if (param.name === 'custom') {
      return '';
    } else {
      throw_up("param name '"+param.name+"' missing from originalToJSLibFigure xxx");
    }
  };
  var h = {parameter_values: params.map(get_parameter_values), move: move};
  if (figure.notes) { h.note = figure.notes; }
  if (figure.formation && (figure.formation !== 'square')) {
    h.note = (h.note || '') + ' from ' + figure.formation.replace(/_/g, ' ');
  }
  return h;
}

var _translate_move_name = {
  allemande_left: 'allemande',
  allemande_right: 'allemande',
  circle_left: 'circle',
  circle_right: 'circle',
  gyre_left: 'gyre',
  gyre_right: 'gyre',
  star_left: 'star',
  star_right: 'star',
  pull_by_left: 'pull by',
  pull_by_right: 'pull by'
}
function translateMoveName(oldMove) {
  return _translate_move_name[oldMove] || oldMove.replace(/_/g, ' ');
}

var _translate_who = {neighbor: 'neighbors',
                      partner: 'partners',
                      everybody: 'everyone'};

function translateWho(oldWho) {
  return _translate_who[oldWho] || oldWho;
}
function untranslateWho(lfWho) {
  // hash table: ur doing it wrong :D
  for(var oldWho in _translate_who){
    if(_translate_who[oldWho]==lfWho) {
      return oldWho;
    }
  }
  return lfWho;
}

var _old_move_is_clockwise = {
  box_the_gnat: true,
  swat_the_flea: false,
  circle_left: true,
  circle_right: false,
  allemande_left: false,
  allemande_right: true,
  pull_by_right: true,
  pull_by_left: false
}

function oldMoveIsClockwise(oldMove) {
  var cw = _old_move_is_clockwise[oldMove];
  if (cw === true || cw === false) {
    return cw;
  } else {
    throw_up("move '"+oldMove+"' missing from oldMoveIsClockwise table");
  }
}

////////////////////////////////////////////////////////////////
// reverse migrator                                           //
////////////////////////////////////////////////////////////////
function jsLibFigureToOriginal(figures) {
  return figures.map(jsLibFigureToOriginal1);
}

function jsLibFigureToOriginal1(figure) {
  var lf_move = figure.move;
  var param_vals = figure.parameter_values;
  var params = parameters(lf_move);
  var h = { who: extractWho(params, param_vals),
            move: findOldMove(figure),
            beats: extractBeats(params, param_vals),
            formation: parseFormationFromNote(figure.note)
          };
  var circling = extractCircling(params, param_vals);
  if (circling) { h.degrees = circling; }
  if (extractBal(params, param_vals)) { h.balance = true; }
  if (figure.note) { h.notes = dropFormationSuffixFromNote(figure.note); }
  return h;
}

function extractWho(params, param_vals) {
  var index = find_parameter_index_by_name('who', params);
  if (index >= 0) {
    return untranslateWho(param_vals[index]);
  } else {
    return 'everybody';
  }
}
function extractBeats(params, param_vals) {
  var index = find_parameter_index_by_name('beats', params);
  if (index >= 0) {
    return param_vals[index];
  } else {
    throw_up('No beats, should I really return 0?'); // I'm okay with it.
    return 0;
  }
}
function extractBal(params, param_vals) {
  var index = find_parameter_index_by_name('bal', params);
  return (index >= 0) && param_vals[index];
}
function extractCircling(params, param_vals) {
  var index = find_parameter_index_by_name('circling', params);
  return (index >= 0) && param_vals[index];
}

function findOldMove(lf_figure) {
  var lf_move = lf_figure.move;
  var param_vals = lf_figure.parameter_values;
  var params = parameters(lf_move);
  var underscore_lf_move = lf_move.replace(/ /g,'_')
  if (oldAtomicMoves[underscore_lf_move]) {
    return underscore_lf_move;
  } else if (oldLeftRightMoves[underscore_lf_move]) {
    var              index = find_parameter_index_by_name('turn', params);
    if (index < 0) { index = find_parameter_index_by_name('hand', params); }
    if (index < 0) { index = find_parameter_index_by_name('shoulder', params); }
    if (index < 0) { index = find_parameter_index_by_name('side', params); }
    if (index < 0) { throw_up('can not find a turn, shoulder, or hand for '+lf_move); }
    return oldLeftRightMoves[underscore_lf_move][param_vals[index] ? 0 : 1];
  } else {
    throw_up('can not findOldMove for '+lf_move);
  }
}

var oldLeftRightMoves = {
  allemande: ['allemande_right', 'allemande_left'],
  circle: ['circle_left', 'circle_right'],
  gyre: ['gyre_right_shoulder', 'gyre_left_shoulder'],
  star: ['star_right', 'star_left'],
  pull_by: ['pull_by_right', 'pull_by_left']
  // unused:
  // gyre_star_ccw_gentlespoons_backing: true,
  // gyre_star_ccw_ladles_backing: true,
  // gyre_star_clockwise_gentlespoons_backing: true,
  // gyre_star_clockwise_ladles_backing: true,

  // roll_away_half_sashay_neighbor: true,
  // roll_away_half_sashay_partner: true,
  // roll_away_neighbor: true,
  // roll_away_partner: true,
  // slide_left_rory_o_moore: true,
  // slide_right_rory_o_moore: true,
};

var oldAtomicMoves = {
  allemande_and_orbit: true,
  arizona_twirl: true,
  balance: true,
  balance_the_ring: true,
  box_circulate: true,
  box_the_gnat: true,
  butterfly_whirl: true,
  california_twirl: true,
  chain: true,
  cross_trails: true,
  custom: true,
  do_si_do: true,
  half_a_hey: true,
  hey: true,
  long_lines: true,
  mad_robin: true,
  petronella: true,
  promenade_across: true,
  right_left_through: true,
  see_saw: true,
  star_promenade: true,
  swat_the_flea: true,
  swing: true,
  to_long_wavy_line: true,
  to_ocean_wave: true
}

function parseFormationFromNote(note) {
  if (!note) { return 'square'; }
  var r = note.match(/from (short line|short wavy lines|long wavy lines|long wavy line|custom)$/);
  if (r) {
    return r[1].replace(/ /g, '_');
  } else {
    return 'square';
  }
}

function dropFormationSuffixFromNote(note) {
  if (!note) { return note; }
  var r = note.match(/from (short line|short wavy lines|long wavy lines|long wavy line|custom)$/);
  if (r) {
    return note.slice(0, note.length - r[0].length);
  } else {
    return note;
  }
}

function testConverters(figures) {
  return figures.map(function(figure) {
    var retranslated_figure = jsLibFigureToOriginal1(originalToJSLibFigure1(figure));
    return [figure, retranslated_figure];
  });
}
<commit_msg>stars, half heys, and jankily leaving wrist grip parameter undefined :'( :'( :'( :'( :'( :O :'( :'( :'( :'( :'( :'( :O :'( :O :'( :'( :'( :O :O :'( :O :O :O :O :'( :'( :) :O :O :'( :'( :O :'( :'( :'( :'( :O :O :'( :'( :O :'(<commit_after>// a JSON-to-JSON translater used by a migration

function originalToJSLibFigure(figures) {
  return figures.map(originalToJSLibFigure1);
}

function originalToJSLibFigure1(figure) {
  var move = translateMoveName(figure.move);
  var params = parameters(move);
  var get_parameter_values = function (param) {
    if (param.name === 'who') {
      return translateWho(figure.who);
    } else if (param.name === 'beats') {
      return figure.beats;
    } else if (param.name === 'bal') {
      return figure.balance || false;
    } else if (param.name === 'hand') {
      return oldMoveIsClockwise(figure.move);
    } else if (param.name === 'circling' ||
               param.name === 'places' ||
               param.name === 'turn' ||
               param.name === 'shoulder') {
      return figure.degrees;
    } else if (param.name === 'custom') {
      return '';
    } else if (param.name === 'grip') {
      return undefined;
    } else {
      throw_up("param name '"+param.name+"' missing from originalToJSLibFigure");
    }
  };
  var h = {parameter_values: params.map(get_parameter_values), move: move};
  if (figure.notes) { h.note = figure.notes; }
  if (figure.formation && (figure.formation !== 'square')) {
    h.note = (h.note || '') + ' from ' + figure.formation.replace(/_/g, ' ');
  }
  return h;
}

var _translate_move_name = {
  allemande_left: 'allemande',
  allemande_right: 'allemande',
  circle_left: 'circle',
  circle_right: 'circle',
  gyre_left: 'gyre',
  gyre_right: 'gyre',
  star_left: 'star',
  star_right: 'star',
  pull_by_left: 'pull by',
  pull_by_right: 'pull by',
  half_a_hey: 'half hey'
}
function translateMoveName(oldMove) {
  return _translate_move_name[oldMove] || oldMove.replace(/_/g, ' ');
}

var _translate_who = {neighbor: 'neighbors',
                      partner: 'partners',
                      everybody: 'everyone'};

function translateWho(oldWho) {
  return _translate_who[oldWho] || oldWho;
}
function untranslateWho(lfWho) {
  // hash table: ur doing it wrong :D
  for(var oldWho in _translate_who){
    if(_translate_who[oldWho]==lfWho) {
      return oldWho;
    }
  }
  return lfWho;
}

var _old_move_is_clockwise = {
  box_the_gnat: true,
  swat_the_flea: false,
  circle_left: true,
  circle_right: false,
  allemande_left: false,
  allemande_right: true,
  pull_by_right: true,
  pull_by_left: false,
  star_left: false,
  star_right: true
}

function oldMoveIsClockwise(oldMove) {
  var cw = _old_move_is_clockwise[oldMove];
  if (cw === true || cw === false) {
    return cw;
  } else {
    throw_up("move '"+oldMove+"' missing from oldMoveIsClockwise table");
  }
}

////////////////////////////////////////////////////////////////
// reverse migrator                                           //
////////////////////////////////////////////////////////////////
function jsLibFigureToOriginal(figures) {
  return figures.map(jsLibFigureToOriginal1);
}

function jsLibFigureToOriginal1(figure) {
  var lf_move = figure.move;
  var param_vals = figure.parameter_values;
  var params = parameters(lf_move);
  var h = { who: extractWho(params, param_vals),
            move: findOldMove(figure),
            beats: extractBeats(params, param_vals),
            formation: parseFormationFromNote(figure.note)
          };
  var circling = extractCircling(params, param_vals);
  if (circling) { h.degrees = circling; }
  if (extractBal(params, param_vals)) { h.balance = true; }
  if (figure.note) { h.notes = dropFormationSuffixFromNote(figure.note); }
  return h;
}

function extractWho(params, param_vals) {
  var index = find_parameter_index_by_name('who', params);
  if (index >= 0) {
    return untranslateWho(param_vals[index]);
  } else {
    return 'everybody';
  }
}
function extractBeats(params, param_vals) {
  var index = find_parameter_index_by_name('beats', params);
  if (index >= 0) {
    return param_vals[index];
  } else {
    throw_up('No beats, should I really return 0?'); // I'm okay with it.
    return 0;
  }
}
function extractBal(params, param_vals) {
  var index = find_parameter_index_by_name('bal', params);
  return (index >= 0) && param_vals[index];
}
function extractCircling(params, param_vals) {
  var index = find_parameter_index_by_name('circling', params);
  return (index >= 0) && param_vals[index];
}

function findOldMove(lf_figure) {
  var lf_move = lf_figure.move;
  var param_vals = lf_figure.parameter_values;
  var params = parameters(lf_move);
  var underscore_lf_move = lf_move.replace(/ /g,'_')
  if (oldAtomicMoves[underscore_lf_move]) {
    return underscore_lf_move;
  } else if (underscore_lf_move === 'half_hey') {
    return 'half_a_hey';
  } else if (oldLeftRightMoves[underscore_lf_move]) {
    var              index = find_parameter_index_by_name('turn', params);
    if (index < 0) { index = find_parameter_index_by_name('hand', params); }
    if (index < 0) { index = find_parameter_index_by_name('shoulder', params); }
    if (index < 0) { index = find_parameter_index_by_name('side', params); }
    if (index < 0) { throw_up('can not find a turn, shoulder, or hand for '+lf_move); }
    return oldLeftRightMoves[underscore_lf_move][param_vals[index] ? 0 : 1];
  } else {
    throw_up('can not findOldMove for '+lf_move);
  }
}

var oldLeftRightMoves = {
  allemande: ['allemande_right', 'allemande_left'],
  circle: ['circle_left', 'circle_right'],
  gyre: ['gyre_right_shoulder', 'gyre_left_shoulder'],
  star: ['star_right', 'star_left'],
  pull_by: ['pull_by_right', 'pull_by_left']
  // unused:
  // gyre_star_ccw_gentlespoons_backing: true,
  // gyre_star_ccw_ladles_backing: true,
  // gyre_star_clockwise_gentlespoons_backing: true,
  // gyre_star_clockwise_ladles_backing: true,

  // roll_away_half_sashay_neighbor: true,
  // roll_away_half_sashay_partner: true,
  // roll_away_neighbor: true,
  // roll_away_partner: true,
  // slide_left_rory_o_moore: true,
  // slide_right_rory_o_moore: true,
};

var oldAtomicMoves = {
  allemande_and_orbit: true,
  arizona_twirl: true,
  balance: true,
  balance_the_ring: true,
  box_circulate: true,
  box_the_gnat: true,
  butterfly_whirl: true,
  california_twirl: true,
  chain: true,
  cross_trails: true,
  custom: true,
  do_si_do: true,
  half_a_hey: true,
  hey: true,
  long_lines: true,
  mad_robin: true,
  petronella: true,
  promenade_across: true,
  right_left_through: true,
  see_saw: true,
  star_promenade: true,
  swat_the_flea: true,
  swing: true,
  to_long_wavy_line: true,
  to_ocean_wave: true
}

function parseFormationFromNote(note) {
  if (!note) { return 'square'; }
  var r = note.match(/from (short line|short wavy lines|long wavy lines|long wavy line|custom)$/);
  if (r) {
    return r[1].replace(/ /g, '_');
  } else {
    return 'square';
  }
}

function dropFormationSuffixFromNote(note) {
  if (!note) { return note; }
  var r = note.match(/from (short line|short wavy lines|long wavy lines|long wavy line|custom)$/);
  if (r) {
    return note.slice(0, note.length - r[0].length);
  } else {
    return note;
  }
}

function testConverters(figures) {
  return figures.map(function(figure) {
    var retranslated_figure = jsLibFigureToOriginal1(originalToJSLibFigure1(figure));
    return [figure, retranslated_figure];
  });
}
<|endoftext|>


<commit_before>elation.extend("events", {
  events: {},

  fire: function(type, fn, element, data) {
    if (typeof type == 'object') {
      fn = elation.utils.arrayget(type, 'fn') || fn;
      element = elation.utils.arrayget(type, 'element') || element;
      data = elation.utils.arrayget(type, 'data') || data;
      type = elation.utils.arrayget(type, 'type');
    }

    console.log('FIRING: ' + type, fn, element, data);
    if (!type)
      return false;

    var list = this.events[type],
        events = [],
        event;

    if (!list) {
      this.events[type] = [];
      return;
    }

    // gather all the events associated with this event type
    for (var i=0; i<list.length; i++) {
      event = list[i];

      if (fn || element) {
        if ((fn && event.origin !== fn) || (element && event.target !== element))
          continue;
        else
          events.push(event);
      } else {
        events.push(event);
      }
    }

    // fire each event
    for (var i=0; i<events.length; i++) {
      var event = events[i];

      if (data)
        event.data = data;

      if (event.origin) {
        if (typeof event.origin == 'function')
          event.origin(event);
        else if (typeof event.origin.handleEvent != 'undefined')
          event.origin.handleEvent(event);
      }
    }

    return events;
  },

  register: function(element, type, fn, custom_event_name) {
    if (custom_event_name)
      custom_event_name = custom_event_name.replace('.','_');

    var event = {
      type: type,
      target: element,
      origin: fn,
      custom_event: custom_event_name,
      preventDefault: function() { return; },
      cancelBubble: function() { return; },
      stopPropogation: function() { return; }
    };

    if (custom_event_name) {
      if (!elation.events.events[custom_event_name])
        elation.events.events[custom_event_name] = [];

      console.log('BINDING '+type+' -> '+custom_event_name);
    }

    if (!elation.events.events[type])
      elation.events.events[type] = [];

    elation.events.events[type].push(event);
    /*
    if (custom_event_name) {
      if (!elation.events.events[custom_event_name])
        elation.events.events[custom_event_name] = [];

      elation.events.events[custom_event_name].push(event);
    }
    */
  },

	// syntax: add(element || [ elements ], "type1,type2,type3", function || object);
	add: function(elements, types, fn, custom_event_name) {
    if (custom_event_name)
      custom_event_name = custom_event_name.replace('.','_');

		if (!types || !fn || typeof types != "string")
			return;

		var	elements = (!elements ? [{}] : ((!elation.utils.isNull(elements.nodeName) || elements == window) ? [ elements ] : elements)),
				types = types.split(',');

		for (var e=0; e<elements.length; e++) {
			var element = elements[e];

			if (typeof element != 'object')
				continue;

			for (var i=0; i<types.length; i++) {
				var type = types[i];

        elation.events.register(element, type, fn, custom_event_name);

				if ("addEventListener" in element) {
          if (type == 'mousewheel' && elation.browser.type != 'safari')
            type = 'DOMMouseScroll';

          if (typeof fn == "object" && fn.handleEvent) {
						element[type+fn] = function(e) {
              if (custom_event_name)
                elation.events.fire({ type: custom_event_name, data: fn });

							fn.handleEvent(e);
						}
						element.addEventListener(type, element[(type + fn)], false);
					} else {
						element.addEventListener(type, fn, false);
					}
				} else if (element.attachEvent) {
					if (typeof fn == "object" && fn.handleEvent) {
						element[type+fn] = function() {
              if (custom_event_name)
                elation.events.fire({ type: custom_event_name, data: fn });

              fn.handleEvent(elation.events.fix(window.event));
						}
					} else {
						element["e" + type + fn] = fn;
						element[type + fn] = function() {
							if (typeof element["e" + type + fn] == 'function')
								element["e" + type + fn](elation.events.fix(window.event));
						}
					}

					element.attachEvent("on" + type, element[type + fn]);
				}
			}
		}

		return this;
	},

	// syntax: remove(element || [ elements ], "type1,type2,type3", reference);
	remove: function(elements, types, fn) {
		if (!elements || !types || !fn || typeof types != "string")
			return;

		var	elements = (!elation.utils.isNull(elements.nodeName) || elements == window) ? [ elements ] : elements,
				types = types.split(',');

		for (var e=0; e<elements.length; e++) {
			var element = elements[e];

			if (typeof element != 'object')
				continue;

			for (var i=0; i<types.length; i++) {
				var type = types[i];

				if (element.removeEventListener) {
					if (typeof fn == "object" && fn.handleEvent) {
						element.removeEventListener(type, element[type+fn], false);
						delete element[type + fn];
					} else {
						element.removeEventListener(type, fn, false);
					}
				} else if (element.detachEvent) {
					if (typeof element[type + fn] == "function")
						element.detachEvent("on" + type, element[type + fn]);

					element[type + fn] = null;
					element["e" + type + fn] = null;
				}
			}
		}

		return this;
	},

  fix: function(event) {
    this.preventDefault = function() {
      this.returnValue = false;
    }

    this.stopPropagation = function() {
      this.cancelBubble = true;
    }

    event.preventDefault = this.preventDefault;
    event.stopPropagation = this.stopPropagation;

    return event;
  },

  getTarget: function(event) {
    return window.event ? event.srcElement : event.target;
  },

  getRelated: function(event) {
    var reltg;

    if (event.relatedTarget) {
      reltg = event.relatedTarget;
    } else {
      if (event.type == "mouseover")
        reltg = event.fromElement;
      else if (event.type == "mouseout")
        reltg = event.toElement;
      else
        reltg = document;
    }

    return reltg;
  },

	getEventTarget: function(event, parentClassName) {
		var target;

		if (!event)
			var event = window.event;

		if (event.target)
			target = event.target;
		else if (event.srcElement)
			target = event.srcElement;

		if (target.nodeType == 3)
			target = target.parentNode; // Defeat Safari bug

		if (parentClassName) {
			// Make sure we're working with the correct element
			var classUp, classDown;

			if (parentClassName.indexOf(">")) {
				var classes = parentClassName.split(">", 2);
				classDown = classes[0];
				classUp = classes[1];
			} else {
				classDown = parentClassName;
			}

			// First run DOWN the heirarchy to find the base class...
			while (!elation.html.hasclass(target,classDown) && target.parentNode) {
				target = target.parentNode;
			}

			// Now if we've specified a child to attach to, find it!
			if (classUp) {
				var elements;
				elements = elation.find("." + classUp, target);
				if (elements.length > 0) {
					target = elements[0];
				}
			}
		}

		return target;
	},

  // returns mouse or all finger touch coords
	coords: function(event) {
		if (typeof event.touches != 'undefined' && event.touches.length > 0) {
			var c = {
        x: event.touches[0].pageX,
        y: event.touches[0].pageY
      };
		} else {
			var	c = {
        x: (event.pageX || (event.clientX + document.body.scrollLeft)),
        y: (event.pageY || (event.clientY + document.body.scrollTop))
      };
		}

		return c;
	}
});

/* backup - original elation add/remove funcs
add: function(obj, type, fn) {
  if (obj) {
    var types = type.split(',');
    for (var i = 0; i < types.length; i++) {
      var type = types[i];
      if (obj.addEventListener) {
        if (type == 'mousewheel' && elation.browser.type != 'safari') type = 'DOMMouseScroll';
        if (typeof fn == "object" && fn.handleEvent) {
          obj[type+fn] = function(e) { fn.handleEvent(e); }
          obj.addEventListener( type, obj[type+fn], false );
        } else {
          obj.addEventListener( type, fn, false );
        }
      } else if (obj.attachEvent) {
        if (typeof fn == "object" && fn.handleEvent) {
          obj[type+fn] = function() { fn.handleEvent(elation.events.fix(window.event)); }
        } else {
          obj["e"+type+fn] = fn;
          obj[type+fn] = function() { obj["e"+type+fn]( elation.events.fix(window.event) ); }
        }
        obj.attachEvent( "on"+type, obj[type+fn]);
      }
    }
  }
  return this;
},

remove: function( obj, type, fn ) {
  var types = type.split(',');
  for (var i = 0; i < types.length; i++) {
    var type = types[i];
    if (obj.removeEventListener) {
      if (typeof fn == "object" && fn.handleEvent) {
        obj.removeEventListener( type, obj[type+fn], false );
        delete obj[type+fn];
      } else {
        obj.removeEventListener( type, fn, false );
      }
    } else if (obj.detachEvent) {
      obj.detachEvent( "on"+type, obj[type+fn] );
      obj[type+fn] = null;
      obj["e"+type+fn] = null;
    }
  }
},
*/
<commit_msg>removed debug crap<commit_after>elation.extend("events", {
  events: {},

  fire: function(type, fn, element, data) {
    if (typeof type == 'object') {
      fn = elation.utils.arrayget(type, 'fn') || fn;
      element = elation.utils.arrayget(type, 'element') || element;
      data = elation.utils.arrayget(type, 'data') || data;
      type = elation.utils.arrayget(type, 'type');
    }

    //console.log('FIRING: ' + type, fn, element, data);
    if (!type)
      return false;

    var list = this.events[type],
        events = [],
        event;

    if (!list) {
      this.events[type] = [];
      return;
    }

    // gather all the events associated with this event type
    for (var i=0; i<list.length; i++) {
      event = list[i];

      if (fn || element) {
        if ((fn && event.origin !== fn) || (element && event.target !== element))
          continue;
        else
          events.push(event);
      } else {
        events.push(event);
      }
    }

    // fire each event
    for (var i=0; i<events.length; i++) {
      var event = events[i];

      if (data)
        event.data = data;

      if (event.origin) {
        if (typeof event.origin == 'function')
          event.origin(event);
        else if (typeof event.origin.handleEvent != 'undefined')
          event.origin.handleEvent(event);
      }
    }

    return events;
  },

  register: function(element, type, fn, custom_event_name) {
    if (custom_event_name)
      custom_event_name = custom_event_name.replace('.','_');

    var event = {
      type: type,
      target: element,
      origin: fn,
      custom_event: custom_event_name,
      preventDefault: function() { return; },
      cancelBubble: function() { return; },
      stopPropogation: function() { return; }
    };

    if (custom_event_name) {
      if (!elation.events.events[custom_event_name])
        elation.events.events[custom_event_name] = [];

      //console.log('BINDING '+type+' -> '+custom_event_name);
    }

    if (!elation.events.events[type])
      elation.events.events[type] = [];

    elation.events.events[type].push(event);
    /*
    if (custom_event_name) {
      if (!elation.events.events[custom_event_name])
        elation.events.events[custom_event_name] = [];

      elation.events.events[custom_event_name].push(event);
    }
    */
  },

	// syntax: add(element || [ elements ], "type1,type2,type3", function || object);
	add: function(elements, types, fn, custom_event_name) {
    if (custom_event_name)
      custom_event_name = custom_event_name.replace('.','_');

		if (!types || !fn || typeof types != "string")
			return;

		var	elements = (!elements ? [{}] : ((!elation.utils.isNull(elements.nodeName) || elements == window) ? [ elements ] : elements)),
				types = types.split(',');

		for (var e=0; e<elements.length; e++) {
			var element = elements[e];

			if (typeof element != 'object')
				continue;

			for (var i=0; i<types.length; i++) {
				var type = types[i];

        elation.events.register(element, type, fn, custom_event_name);

				if ("addEventListener" in element) {
          if (type == 'mousewheel' && elation.browser.type != 'safari')
            type = 'DOMMouseScroll';

          if (typeof fn == "object" && fn.handleEvent) {
						element[type+fn] = function(e) {
              if (custom_event_name)
                elation.events.fire({ type: custom_event_name, data: fn });

							fn.handleEvent(e);
						}
						element.addEventListener(type, element[(type + fn)], false);
					} else {
						element.addEventListener(type, fn, false);
					}
				} else if (element.attachEvent) {
					if (typeof fn == "object" && fn.handleEvent) {
						element[type+fn] = function() {
              if (custom_event_name)
                elation.events.fire({ type: custom_event_name, data: fn });

              fn.handleEvent(elation.events.fix(window.event));
						}
					} else {
						element["e" + type + fn] = fn;
						element[type + fn] = function() {
							if (typeof element["e" + type + fn] == 'function')
								element["e" + type + fn](elation.events.fix(window.event));
						}
					}

					element.attachEvent("on" + type, element[type + fn]);
				}
			}
		}

		return this;
	},

	// syntax: remove(element || [ elements ], "type1,type2,type3", reference);
	remove: function(elements, types, fn) {
		if (!elements || !types || !fn || typeof types != "string")
			return;

		var	elements = (!elation.utils.isNull(elements.nodeName) || elements == window) ? [ elements ] : elements,
				types = types.split(',');

		for (var e=0; e<elements.length; e++) {
			var element = elements[e];

			if (typeof element != 'object')
				continue;

			for (var i=0; i<types.length; i++) {
				var type = types[i];

				if (element.removeEventListener) {
					if (typeof fn == "object" && fn.handleEvent) {
						element.removeEventListener(type, element[type+fn], false);
						delete element[type + fn];
					} else {
						element.removeEventListener(type, fn, false);
					}
				} else if (element.detachEvent) {
					if (typeof element[type + fn] == "function")
						element.detachEvent("on" + type, element[type + fn]);

					element[type + fn] = null;
					element["e" + type + fn] = null;
				}
			}
		}

		return this;
	},

  fix: function(event) {
    this.preventDefault = function() {
      this.returnValue = false;
    }

    this.stopPropagation = function() {
      this.cancelBubble = true;
    }

    event.preventDefault = this.preventDefault;
    event.stopPropagation = this.stopPropagation;

    return event;
  },

  getTarget: function(event) {
    return window.event ? event.srcElement : event.target;
  },

  getRelated: function(event) {
    var reltg;

    if (event.relatedTarget) {
      reltg = event.relatedTarget;
    } else {
      if (event.type == "mouseover")
        reltg = event.fromElement;
      else if (event.type == "mouseout")
        reltg = event.toElement;
      else
        reltg = document;
    }

    return reltg;
  },

	getEventTarget: function(event, parentClassName) {
		var target;

		if (!event)
			var event = window.event;

		if (event.target)
			target = event.target;
		else if (event.srcElement)
			target = event.srcElement;

		if (target.nodeType == 3)
			target = target.parentNode; // Defeat Safari bug

		if (parentClassName) {
			// Make sure we're working with the correct element
			var classUp, classDown;

			if (parentClassName.indexOf(">")) {
				var classes = parentClassName.split(">", 2);
				classDown = classes[0];
				classUp = classes[1];
			} else {
				classDown = parentClassName;
			}

			// First run DOWN the heirarchy to find the base class...
			while (!elation.html.hasclass(target,classDown) && target.parentNode) {
				target = target.parentNode;
			}

			// Now if we've specified a child to attach to, find it!
			if (classUp) {
				var elements;
				elements = elation.find("." + classUp, target);
				if (elements.length > 0) {
					target = elements[0];
				}
			}
		}

		return target;
	},

  // returns mouse or all finger touch coords
	coords: function(event) {
		if (typeof event.touches != 'undefined' && event.touches.length > 0) {
			var c = {
        x: event.touches[0].pageX,
        y: event.touches[0].pageY
      };
		} else {
			var	c = {
        x: (event.pageX || (event.clientX + document.body.scrollLeft)),
        y: (event.pageY || (event.clientY + document.body.scrollTop))
      };
		}

		return c;
	}
});

/* backup - original elation add/remove funcs
add: function(obj, type, fn) {
  if (obj) {
    var types = type.split(',');
    for (var i = 0; i < types.length; i++) {
      var type = types[i];
      if (obj.addEventListener) {
        if (type == 'mousewheel' && elation.browser.type != 'safari') type = 'DOMMouseScroll';
        if (typeof fn == "object" && fn.handleEvent) {
          obj[type+fn] = function(e) { fn.handleEvent(e); }
          obj.addEventListener( type, obj[type+fn], false );
        } else {
          obj.addEventListener( type, fn, false );
        }
      } else if (obj.attachEvent) {
        if (typeof fn == "object" && fn.handleEvent) {
          obj[type+fn] = function() { fn.handleEvent(elation.events.fix(window.event)); }
        } else {
          obj["e"+type+fn] = fn;
          obj[type+fn] = function() { obj["e"+type+fn]( elation.events.fix(window.event) ); }
        }
        obj.attachEvent( "on"+type, obj[type+fn]);
      }
    }
  }
  return this;
},

remove: function( obj, type, fn ) {
  var types = type.split(',');
  for (var i = 0; i < types.length; i++) {
    var type = types[i];
    if (obj.removeEventListener) {
      if (typeof fn == "object" && fn.handleEvent) {
        obj.removeEventListener( type, obj[type+fn], false );
        delete obj[type+fn];
      } else {
        obj.removeEventListener( type, fn, false );
      }
    } else if (obj.detachEvent) {
      obj.detachEvent( "on"+type, obj[type+fn] );
      obj[type+fn] = null;
      obj["e"+type+fn] = null;
    }
  }
},
*/
<|endoftext|>