<commit_before>const ServiceBroker = require("../../../src/service-broker");
const Transit = require("../../../src/transit");
const MqttTransporter = require("../../../src/transporters/mqtt");
const { PacketInfo } = require("../../../src/packets");

jest.mock("mqtt");

let MQTT = require("mqtt");
MQTT.connect = jest.fn(() => {
	let onCallbacks = {};
	return {
		on: jest.fn((event, cb) => onCallbacks[event] = cb),
		end: jest.fn(),
		subscribe: jest.fn(),
		publish: jest.fn(),

		onCallbacks
	};
});

describe("Test NatsTransporter constructor", () => {

	it("check constructor", () => {
		let trans = new MqttTransporter();
		expect(trans).toBeDefined();
		expect(trans.opts).toEqual({});
		expect(trans.connected).toBe(false);
		expect(trans.client).toBeNull();
	});

	it("check constructor with string param", () => {
		let trans = new MqttTransporter("mqtt://localhost");
		expect(trans.opts).toEqual({ mqtt: "mqtt://localhost"});
	});

	it("check constructor with options", () => {
		let opts = { mqtt: { host: "localhost", port: 1234} };
		let trans = new MqttTransporter(opts);
		expect(trans.opts).toBe(opts);
	});
});

describe("Test MqttTransporter connect & disconnect", () => {
	let broker = new ServiceBroker();
	let transit = new Transit(broker);
	let msgHandler = jest.fn();
	let trans;

	beforeEach(() => {
		trans = new MqttTransporter();
		trans.init(transit, msgHandler);
	});

	it("check connect", () => {
		let p = trans.connect().then(() => {
			expect(trans.client).toBeDefined();
			expect(trans.client.on).toHaveBeenCalledTimes(5);
			expect(trans.client.on).toHaveBeenCalledWith("connect", jasmine.any(Function));
			expect(trans.client.on).toHaveBeenCalledWith("error", jasmine.any(Function));
			expect(trans.client.on).toHaveBeenCalledWith("reconnect", jasmine.any(Function));
			expect(trans.client.on).toHaveBeenCalledWith("close", jasmine.any(Function));
			expect(trans.client.on).toHaveBeenCalledWith("message", jasmine.any(Function));
		});

		trans._client.onCallbacks.connect(); // Trigger the `resolve`

		return p;
	});

	it("check disconnect", () => {
		trans.connect();

		let cb = trans.client.end;
		trans.disconnect();
		expect(trans.client).toBeNull();
		expect(cb).toHaveBeenCalledTimes(1);
	});

});

describe("Test NatsTransporter subscribe & publish", () => {
	let trans;
	let msgHandler;

	const fakeTransit = {
		nodeID: "node1",
		serialize: jest.fn(msg => JSON.stringify(msg))
	};

	beforeEach(() => {
		trans = new MqttTransporter({ prefix: "TEST" });
		let broker = new ServiceBroker();
		msgHandler = jest.fn();
		trans.init(broker, msgHandler);
		trans.connect();
	});

	it("check subscribe", () => {
		trans.subscribe("REQ", "node");

		expect(trans.client.subscribe).toHaveBeenCalledTimes(1);
		expect(trans.client.subscribe).toHaveBeenCalledWith("TEST.REQ.node");
	});

	it("check incoming message handler", () => {
		// Test subscribe callback
		trans.client.onCallbacks.message("prefix.event.name", "incoming data");
		expect(msgHandler).toHaveBeenCalledTimes(1);
		expect(msgHandler).toHaveBeenCalledWith("event", "incoming data");
	});

	it("check publish", () => {
		trans.publish(new PacketInfo(fakeTransit, "node2", {}));

		expect(trans.client.publish).toHaveBeenCalledTimes(1);
		expect(trans.client.publish).toHaveBeenCalledWith("TEST.INFO.node2", "{\"sender\":\"node1\",\"actions\":\"{}\"}");
	});
});
<commit_msg>fix mqtt<commit_after>const ServiceBroker = require("../../../src/service-broker");
const Transit = require("../../../src/transit");
const MqttTransporter = require("../../../src/transporters/mqtt");
const { PacketInfo } = require("../../../src/packets");

jest.mock("mqtt");

let MQTT = require("mqtt");
MQTT.connect = jest.fn(() => {
	let onCallbacks = {};
	return {
		on: jest.fn((event, cb) => onCallbacks[event] = cb),
		end: jest.fn(),
		subscribe: jest.fn(),
		publish: jest.fn(),

		onCallbacks
	};
});

describe("Test NatsTransporter constructor", () => {

	it("check constructor", () => {
		let transporter = new MqttTransporter();
		expect(transporter).toBeDefined();
		expect(transporter.opts).toEqual({});
		expect(transporter.connected).toBe(false);
		expect(transporter.client).toBeNull();
	});

	it("check constructor with string param", () => {
		let transporter = new MqttTransporter("mqtt://localhost");
		expect(transporter.opts).toEqual({ mqtt: "mqtt://localhost"});
	});

	it("check constructor with options", () => {
		let opts = { mqtt: { host: "localhost", port: 1234} };
		let transporter = new MqttTransporter(opts);
		expect(transporter.opts).toBe(opts);
	});
});

describe("Test MqttTransporter connect & disconnect", () => {
	let broker = new ServiceBroker();
	let transit = new Transit(broker);
	let msgHandler = jest.fn();
	let transporter;

	beforeEach(() => {
		transporter = new MqttTransporter();
		transit.tx = transporter;
		transporter.init(transit, msgHandler);
	});

	it("check connect", () => {
		let p = transporter.connect().then(() => {
			expect(transporter.client).toBeDefined();
			expect(transporter.client.on).toHaveBeenCalledTimes(5);
			expect(transporter.client.on).toHaveBeenCalledWith("connect", jasmine.any(Function));
			expect(transporter.client.on).toHaveBeenCalledWith("error", jasmine.any(Function));
			expect(transporter.client.on).toHaveBeenCalledWith("reconnect", jasmine.any(Function));
			expect(transporter.client.on).toHaveBeenCalledWith("close", jasmine.any(Function));
			expect(transporter.client.on).toHaveBeenCalledWith("message", jasmine.any(Function));
		});

		transporter._client.onCallbacks.connect(); // Trigger the `resolve`

		return p;
	});

	it("check disconnect", () => {
		let p = transporter.connect().then(() => {
			let cb = transporter.client.end;
			transporter.disconnect();
			expect(transporter.client).toBeNull();
			expect(cb).toHaveBeenCalledTimes(1);

		});

		transporter._client.onCallbacks.connect(); // Trigger the `resolve`
		return p;
	});

});

describe("Test NatsTransporter subscribe & publish", () => {
	let transporter;
	let msgHandler;

	const fakeTransit = {
		nodeID: "node1",
		serialize: jest.fn(msg => JSON.stringify(msg))
	};

	beforeEach(() => {
		transporter = new MqttTransporter({ prefix: "TEST" });
		let broker = new ServiceBroker();
		let transit = new Transit(broker);
		transit.tx = transporter;
		msgHandler = jest.fn();
		transporter.init(transit, msgHandler);
		let p = transporter.connect();
		transporter._client.onCallbacks.connect(); // Trigger the `resolve`
		return p;
	});

	it("check subscribe", () => {
		transporter.client.subscribe.mockClear();
		transporter.subscribe("REQ", "node");

		expect(transporter.client.subscribe).toHaveBeenCalledTimes(1);
		expect(transporter.client.subscribe).toHaveBeenCalledWith("TEST.REQ.node");
	});

	it("check incoming message handler", () => {
		// Test subscribe callback
		transporter.client.onCallbacks.message("prefix.event.name", "incoming data");
		expect(msgHandler).toHaveBeenCalledTimes(1);
		expect(msgHandler).toHaveBeenCalledWith("event", "incoming data");
	});

	it("check publish", () => {
		transporter.client.publish.mockClear();
		transporter.publish(new PacketInfo(fakeTransit, "node2", {}));

		expect(transporter.client.publish).toHaveBeenCalledTimes(1);
		expect(transporter.client.publish).toHaveBeenCalledWith("TEST.INFO.node2", "{\"sender\":\"node1\",\"actions\":\"{}\"}");
	});
});
<|endoftext|>


<commit_before>function httpGet(theUrl) {
    var xmlHttp = new XMLHttpRequest()
    xmlHttp.open('GET', theUrl, false) // false for synchronous request
    xmlHttp.send(null)
    return xmlHttp.responseText
}

export default function(imageName, height = null, width = null, misMatchPercentageMargin = 0.00) {
    return html2canvas(document.getElementById('ember-testing-container'), {
        height: height,
        width: width
    }).then(function(canvas) {
        // Get test dummy image
        var image = canvas.toDataURL('image/png')
        $.ajax({
                type: 'POST',
                async: false,
                url: '/image',
                data: {
                    image: image,
                    name: imageName + '.png'
                }
            })
            // Get passed image
        var res = JSON.parse(httpGet('/image?name=' + imageName + '-passed.png'))
        if (res.error === 'File does not exist') {
            // Save image as passed if no existing passed image
            $.ajax({
                type: 'POST',
                async: false,
                url: '/passed',
                data: {
                    image: image,
                    name: imageName + '.png'
                }
            })

            return 'No passed image. Saving current test as base'

        } else {
            // Passed image exists so compare to current
            res.image = "data:image/png;base64," + res.image
            var diff = resemble(image).compareTo(res.image).scaleToSameSize().onComplete(function(data) {
                var result = false
                if (parseFloat(data.misMatchPercentage) <= misMatchPercentageMargin) {
                    console.log('passed')
                    // Passed
                    $.ajax({
                        type: 'POST',
                        async: false,
                        url: '/passed',
                        data: {
                            image: image,
                            name: imageName + '.png'
                        }
                    })
                    result = true
                    return "No base Image. Saving Current"
                } else {
                    // Fail
                    $.ajax({
                        type: 'POST',
                        async: false,
                        url: '/fail',
                        data: {
                            image: data.getImageDataUrl(),
                            name: imageName + '.png'
                        }
                    })
                    expect(result).to.be.true
                }
                /* Resemblejs Output
                {
                  misMatchPercentage : 100, // %
                  isSameDimensions: true, // or false
                  dimensionDifference: { width: 0, height: -1 }, // defined if dimensions are not the same
                  getImageDataUrl: function(){}
                }
                */

                return data
            })
        }
    }).catch(function(err) {
        // console.log(err)
       return err
    })
}<commit_msg>image threshold throw<commit_after>function httpGet(theUrl) {
  var xmlHttp = new XMLHttpRequest()
  xmlHttp.open('GET', theUrl, false) // false for synchronous request
  xmlHttp.send(null)
  return xmlHttp.responseText
}

export default function(imageName, height = null, width = null, misMatchPercentageMargin = 0.00) {
  return html2canvas(document.getElementById('ember-testing-container'), {
    height: height,
    width: width
  }).then(function(canvas) {
    // Get test dummy image
    var image = canvas.toDataURL('image/png')
    $.ajax({
        type: 'POST',
        async: false,
        url: '/image',
        data: {
          image: image,
          name: imageName + '.png'
        }
      })
      // Get passed image
    var res = JSON.parse(httpGet('/image?name=' + imageName + '-passed.png'))
    if (res.error === 'File does not exist') {
      // Save image as passed if no existing passed image
      $.ajax({
        type: 'POST',
        async: false,
        url: '/passed',
        data: {
          image: image,
          name: imageName + '.png'
        }
      })

      return 'No passed image. Saving current test as base'

    } else {
      // Passed image exists so compare to current
      res.image = "data:image/png;base64," + res.image
      var diff = resemble(image).compareTo(res.image).scaleToSameSize().onComplete(function(data) {
        var result = false
        if (parseFloat(data.misMatchPercentage) <= misMatchPercentageMargin) {
          // Passed
          $.ajax({
            type: 'POST',
            async: false,
            url: '/passed',
            data: {
              image: image,
              name: imageName + '.png'
            }
          })
          result = true
          return "No base Image. Saving Current"
        } else {
          // Fail
          $.ajax({
            type: 'POST',
            async: false,
            url: '/fail',
            data: {
              image: data.getImageDataUrl(),
              name: imageName + '.png'
            }
          }).then(function(e) {
            assert.isTrue(false, "Image is above mismatch threshold.")
          })
        }
        /* Resemblejs Output
        {
          misMatchPercentage : 100, // %
          isSameDimensions: true, // or false
          dimensionDifference: { width: 0, height: -1 }, // defined if dimensions are not the same
          getImageDataUrl: function(){}
        }
        */
        expect(result).to.be.true
        return data
      })
    }
  });
}
<|endoftext|>


<commit_before>/**
 @module ember
 @submodule ember-views
 */
import Ember from 'ember';
import jQuery from 'jquery';
import symbol from './ember-internals/symbol';

const {
  assign,
  get: get,
  set: set,
  isNone,
  run,
  Object,
  View
  } = Ember;

// PLEASE, if you are reading this code, DONT duplicate this hack :)
// This is only here so that we can test this event model prior to it landing in Ember proper.
const ActionManager = Ember.__loader.require('ember-views/system/action_manager')['default'];

/**
 `Ember.EventDispatcher` handles delegating browser events to their
 corresponding `Ember.Views.` For example, when you click on a view,
 `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets
 called.

 @class EventDispatcher
 @namespace Ember
 @private
 @extends Ember.Object
 */
export default Object.extend({

  /**
   Whether or not to cache handler paths on the element
   when `useCapture` is also true.

   This needs to be replaced by a feature flag.

   @private
   @type {boolean}
   */
  useFastPaths: true,

  /**
   The set of events names (and associated handler function names) to be setup
   and dispatched by the `EventDispatcher`. Modifications to this list can be done
   at setup time, generally via the `Ember.Application.customEvents` hash.

   To add new events to be listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        paste: 'paste'
      }
    });
   ```

   To prevent default events from being listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        mouseenter: null,
        mouseleave: null
      }
    });
   ```
   @property events
   @type Object
   @private
   */
  events: {
    touchstart  : 'touchStart',
    touchmove   : 'touchMove',
    touchend    : 'touchEnd',
    touchcancel : 'touchCancel',
    keydown     : 'keyDown',
    keyup       : 'keyUp',
    keypress    : 'keyPress',
    mousedown   : 'mouseDown',
    mouseup     : 'mouseUp',
    contextmenu : 'contextMenu',
    click       : 'click',
    dblclick    : 'doubleClick',
    mousemove   : 'mouseMove',
    focusin     : 'focusIn',
    focusout    : 'focusOut',
    mouseenter  : 'mouseEnter',
    mouseleave  : 'mouseLeave',
    submit      : 'submit',
    input       : 'input',
    change      : 'change',
    dragstart   : 'dragStart',
    drag        : 'drag',
    dragenter   : 'dragEnter',
    dragleave   : 'dragLeave',
    dragover    : 'dragOver',
    drop        : 'drop',
    dragend     : 'dragEnd'
  },

  /**
   The root DOM element to which event listeners should be attached. Event
   listeners will be attached to the document unless this is overridden.

   Can be specified as a DOMElement or a selector string.

   The default body is a string since this may be evaluated before document.body
   exists in the DOM.

   @private
   @property rootElement
   @type DOMElement
   @default 'body'
   */
  rootElement: 'body',

  /**
   It enables events to be dispatched to the view's `eventManager.` When present,
   this object takes precedence over handling of events on the view itself.

   Note that most Ember applications do not use this feature. If your app also
   does not use it, consider setting this property to false to gain some performance
   improvement by allowing the EventDispatcher to skip the search for the
   `eventManager` on the view tree.

   ```javascript
   var EventDispatcher = Em.EventDispatcher.extend({
      events: {
          click       : 'click',
          focusin     : 'focusIn',
          focusout    : 'focusOut',
          change      : 'change'
      },
      canDispatchToEventManager: false
    });
   container.register('event_dispatcher:main', EventDispatcher);
   ```

   @property canDispatchToEventManager
   @type boolean
   @default 'true'
   @since 1.7.0
   @private
   */
  canDispatchToEventManager: true,

  /**
   Enables capturing of events immediately instead of during bubble
   @private
   */
  useCapture: true,

  /**
   Sets up event listeners for standard browser events.

   This will be called after the browser sends a `DOMContentReady` event. By
   default, it will set up all of the listeners on the document body. If you
   would like to register the listeners on a different element, set the event
   dispatcher's `root` property.

   @private
   @method setup
   @param addedEvents {Object}
   */
  setup(addedEvents, rootElement) {
    let event;
    let events = assign({}, get(this, 'events'), addedEvents);
    let viewRegistry = this.container && this.container.lookup('-view-registry:main') || View.views;
    let eventWalker;

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ember.assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is('.ember-application'));
    Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
    Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);

    rootElement.addClass('ember-application');

    Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));

    if (get(this, 'useCapture')) {
      rootElement = rootElement.get(0);
      eventWalker = new EventWalker(viewRegistry);
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupCaptureHandler(viewRegistry, rootElement, event, events[event], eventWalker);
        }
      }
    } else {
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupBubbleHandler(viewRegistry, rootElement, event, events[event]);
        }
      }
    }
  },

  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupBubbleHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   */
  setupBubbleHandler(viewRegistry, rootElement, event, eventName) {
    var self = this;

    if (eventName === null) {
      return;
    }

    rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) {
      var view = viewRegistry[this.id];
      var result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    });

    rootElement.on(event + '.ember', '[data-ember-action]', function(evt) {
      var actionId = jQuery(evt.currentTarget).attr('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          return action.handler(evt);
        }
      }
    });
  },

  /**
   Cache for event listeners attached with `useCapture`

   @private
   */
  _handlers: [],
  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupCaptureHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   @param eventWalker an instance of a walker used to find the closest action or view element
   */
  setupCaptureHandler(viewRegistry, rootElement, event, eventName, eventWalker) {
    let self = this;

    function didFindId(evt, triggeringManager, handlers) {
      let view = viewRegistry[this.id];
      let result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      // collect handler
      if (useFastPaths && handlers) {
        // TODO this logic needs pulled out of _dispatchEvent and _bubbleEvent
        // TODO and we should collect the actual handler, not just the element
        if (manager[eventName] && typeof manager[eventName] === 'function') {
          handlers.push(['id', this]);
        } else if (view.has(eventName)) {
          handlers.push(['id', this]);
        }
      }

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    }

    function didFindAction(evt, handlers) {
      var actionId = this.getAttribute('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          // collect handler
          // TODO this should collect the actual handler instead
          if (useFastPaths && handlers) {
            handlers.push(['action', this]);
          }

          return action.handler(evt);
        }
      }
    }

    let filterFn = filterCaptureFunction(didFindId, didFindAction, eventWalker, this.get('useFastPaths'));
    this._handlers.push({ event: event, method: filterFn });
    rootElement.addEventListener(event, filterFn, true);
  },

  _findNearestEventManager(view, eventName) {
    var manager = null;

    while (view) {
      manager = get(view, 'eventManager');
      if (manager && manager[eventName]) { break; }

      view = get(view, 'parentView');
    }

    return manager;
  },

  _dispatchEvent(object, evt, eventName, view) {
    var result = true;

    var handler = object[eventName];
    if (typeof handler === 'function') {
      result = run(object, handler, evt, view);
      // Do not preventDefault in eventManagers.
      evt.stopPropagation();
    } else {
      result = this._bubbleEvent(view, evt, eventName);
    }

    return result;
  },

  _bubbleEvent(view, evt, eventName) {
    return view.handleEvent(eventName, evt);
  },

  destroy() {
    var rootElement = get(this, 'rootElement');
    if (get(this, 'useCapture')) {
      this._handlers.forEach(function(item) {
        rootElement.removeEventListener(item.event, item.method, true);
      });
      this._handlers = [];
      jQuery(rootElement).removeClass('ember-application');
    } else {
      jQuery(rootElement).off('.ember', '**').removeClass('ember-application');
    }
    return this._super(...arguments);
  },

  toString() {
    return '(EventDispatcher)';
  }

});

function filterCaptureFunction(eventName, idHandler, actionHandler, walker, useFastPaths) {
  return function(e) {
    // normalize the event object
    // this also let's us set currentTarget correctly
    let event = jQuery.event.fix(e);

    let element = event.target;
    let result;
    let handlers;

    // trigger from cached handlers
    if (useFastPaths && element._handlers && element._handlers[eventName]) {
      element._handlers[eventName].forEach((handler) => {
        event.currentTarget = handler[1];
      if (handler[0] === 'id') {
        result = idHandler.call(handler[1], event);
      } else {
        result = actionHandler.call(handler[1], event);
      }
    });
    return result;

    // collect and trigger handlers
  } else {
    if (useFastPaths) {
      element._handlers = element._handlers || {};
      handlers = element._handlers[eventName] = element._handlers[eventName] || [];
    }

    let node;
    do {
      node = walker.closest(element);
      if (node) {
        event.currentTarget = node[1];
        if (node[0] === 'id') {
          result = idHandler.call(node[1], event, null, handlers);
        } else {
          result = actionHandler.call(node[1], event, handlers);
        }
        if (result) {
          node = node.parentNode;
        }
      }
    } while (result && node);
    return result;
  }
};
}

function EventWalker(registry) {
  this.registry = registry;
}

EventWalker.prototype.inRegistry = function EventWalker_inRegistry(id) {
  return !!this.registry[id];
};

EventWalker.prototype.closest = function EventWalker_closest(closest) {
  do {
    if (closest.id && this.inRegistry(closest.id)) {
      return ['id', closest];
    }
    if (closest.hasAttribute('data-ember-action')) {
      return ['action', closest];
    }
  } while (closest = closest.parentNode);
  return null;
};
<commit_msg>eliminate useFastPaths flag, this should be automatic with the new eventing<commit_after>/**
 @module ember
 @submodule ember-views
 */
import Ember from 'ember';
import jQuery from 'jquery';
import symbol from './ember-internals/symbol';

const {
  assign,
  get: get,
  set: set,
  isNone,
  run,
  Object,
  View
  } = Ember;

// PLEASE, if you are reading this code, DONT duplicate this hack :)
// This is only here so that we can test this event model prior to it landing in Ember proper.
const ActionManager = Ember.__loader.require('ember-views/system/action_manager')['default'];

/**
 `Ember.EventDispatcher` handles delegating browser events to their
 corresponding `Ember.Views.` For example, when you click on a view,
 `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets
 called.

 @class EventDispatcher
 @namespace Ember
 @private
 @extends Ember.Object
 */
export default Object.extend({

  /**
   The set of events names (and associated handler function names) to be setup
   and dispatched by the `EventDispatcher`. Modifications to this list can be done
   at setup time, generally via the `Ember.Application.customEvents` hash.

   To add new events to be listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        paste: 'paste'
      }
    });
   ```

   To prevent default events from being listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        mouseenter: null,
        mouseleave: null
      }
    });
   ```
   @property events
   @type Object
   @private
   */
  events: {
    touchstart  : 'touchStart',
    touchmove   : 'touchMove',
    touchend    : 'touchEnd',
    touchcancel : 'touchCancel',
    keydown     : 'keyDown',
    keyup       : 'keyUp',
    keypress    : 'keyPress',
    mousedown   : 'mouseDown',
    mouseup     : 'mouseUp',
    contextmenu : 'contextMenu',
    click       : 'click',
    dblclick    : 'doubleClick',
    mousemove   : 'mouseMove',
    focusin     : 'focusIn',
    focusout    : 'focusOut',
    mouseenter  : 'mouseEnter',
    mouseleave  : 'mouseLeave',
    submit      : 'submit',
    input       : 'input',
    change      : 'change',
    dragstart   : 'dragStart',
    drag        : 'drag',
    dragenter   : 'dragEnter',
    dragleave   : 'dragLeave',
    dragover    : 'dragOver',
    drop        : 'drop',
    dragend     : 'dragEnd'
  },

  /**
   The root DOM element to which event listeners should be attached. Event
   listeners will be attached to the document unless this is overridden.

   Can be specified as a DOMElement or a selector string.

   The default body is a string since this may be evaluated before document.body
   exists in the DOM.

   @private
   @property rootElement
   @type DOMElement
   @default 'body'
   */
  rootElement: 'body',

  /**
   It enables events to be dispatched to the view's `eventManager.` When present,
   this object takes precedence over handling of events on the view itself.

   Note that most Ember applications do not use this feature. If your app also
   does not use it, consider setting this property to false to gain some performance
   improvement by allowing the EventDispatcher to skip the search for the
   `eventManager` on the view tree.

   ```javascript
   var EventDispatcher = Em.EventDispatcher.extend({
      events: {
          click       : 'click',
          focusin     : 'focusIn',
          focusout    : 'focusOut',
          change      : 'change'
      },
      canDispatchToEventManager: false
    });
   container.register('event_dispatcher:main', EventDispatcher);
   ```

   @property canDispatchToEventManager
   @type boolean
   @default 'true'
   @since 1.7.0
   @private
   */
  canDispatchToEventManager: true,

  /**
   Enables capturing of events immediately instead of during bubble
   @private
   */
  useCapture: true,

  /**
   Sets up event listeners for standard browser events.

   This will be called after the browser sends a `DOMContentReady` event. By
   default, it will set up all of the listeners on the document body. If you
   would like to register the listeners on a different element, set the event
   dispatcher's `root` property.

   @private
   @method setup
   @param addedEvents {Object}
   */
  setup(addedEvents, rootElement) {
    let event;
    let events = assign({}, get(this, 'events'), addedEvents);
    let viewRegistry = this.container && this.container.lookup('-view-registry:main') || View.views;
    let eventWalker;

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ember.assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is('.ember-application'));
    Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
    Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);

    rootElement.addClass('ember-application');

    Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));

    if (get(this, 'useCapture')) {
      rootElement = rootElement.get(0);
      eventWalker = new EventWalker(viewRegistry);
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupCaptureHandler(viewRegistry, rootElement, event, events[event], eventWalker);
        }
      }
    } else {
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupBubbleHandler(viewRegistry, rootElement, event, events[event]);
        }
      }
    }
  },

  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupBubbleHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   */
  setupBubbleHandler(viewRegistry, rootElement, event, eventName) {
    var self = this;

    if (eventName === null) {
      return;
    }

    rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) {
      var view = viewRegistry[this.id];
      var result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    });

    rootElement.on(event + '.ember', '[data-ember-action]', function(evt) {
      var actionId = jQuery(evt.currentTarget).attr('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          return action.handler(evt);
        }
      }
    });
  },

  /**
   Cache for event listeners attached with `useCapture`

   @private
   */
  _handlers: [],
  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupCaptureHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   @param eventWalker an instance of a walker used to find the closest action or view element
   */
  setupCaptureHandler(viewRegistry, rootElement, event, eventName, eventWalker) {
    let self = this;

    function didFindId(evt, triggeringManager, handlers) {
      let view = viewRegistry[this.id];
      let result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      // collect handler
      if (handlers) {
        // TODO this logic needs pulled out of _dispatchEvent and _bubbleEvent
        // TODO and we should collect the actual handler, not just the element
        if (manager[eventName] && typeof manager[eventName] === 'function') {
          handlers.push(['id', this]);
        } else if (view.has(eventName)) {
          handlers.push(['id', this]);
        }
      }

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    }

    function didFindAction(evt, handlers) {
      var actionId = this.getAttribute('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          // collect handler
          // TODO this should collect the actual handler instead
          if (handlers) {
            handlers.push(['action', this]);
          }

          return action.handler(evt);
        }
      }
    }

    let filterFn = filterCaptureFunction(didFindId, didFindAction, eventWalker);
    this._handlers.push({ event: event, method: filterFn });
    rootElement.addEventListener(event, filterFn, true);
  },

  _findNearestEventManager(view, eventName) {
    var manager = null;

    while (view) {
      manager = get(view, 'eventManager');
      if (manager && manager[eventName]) { break; }

      view = get(view, 'parentView');
    }

    return manager;
  },

  _dispatchEvent(object, evt, eventName, view) {
    var result = true;

    var handler = object[eventName];
    if (typeof handler === 'function') {
      result = run(object, handler, evt, view);
      // Do not preventDefault in eventManagers.
      evt.stopPropagation();
    } else {
      result = this._bubbleEvent(view, evt, eventName);
    }

    return result;
  },

  _bubbleEvent(view, evt, eventName) {
    return view.handleEvent(eventName, evt);
  },

  destroy() {
    var rootElement = get(this, 'rootElement');
    if (get(this, 'useCapture')) {
      this._handlers.forEach(function(item) {
        rootElement.removeEventListener(item.event, item.method, true);
      });
      this._handlers = [];
      jQuery(rootElement).removeClass('ember-application');
    } else {
      jQuery(rootElement).off('.ember', '**').removeClass('ember-application');
    }
    return this._super(...arguments);
  },

  toString() {
    return '(EventDispatcher)';
  }

});

function filterCaptureFunction(eventName, idHandler, actionHandler, walker) {
  return function(e) {
    // normalize the event object
    // this also let's us set currentTarget correctly
    let event = jQuery.event.fix(e);

    let element = event.target;
    let result;
    let handlers;

    // trigger from cached handlers
    if (element._handlers && element._handlers[eventName]) {
      element._handlers[eventName].forEach((handler) => {
        event.currentTarget = handler[1];
      if (handler[0] === 'id') {
        result = idHandler.call(handler[1], event);
      } else {
        result = actionHandler.call(handler[1], event);
      }
    });
    return result;

    // collect and trigger handlers
  } else {

    element._handlers = element._handlers || {};
    handlers = element._handlers[eventName] = element._handlers[eventName] || [];

    let node;
    do {
      node = walker.closest(element);
      if (node) {
        event.currentTarget = node[1];
        if (node[0] === 'id') {
          result = idHandler.call(node[1], event, null, handlers);
        } else {
          result = actionHandler.call(node[1], event, handlers);
        }
        if (result) {
          node = node.parentNode;
        }
      }
    } while (result && node);
    return result;
  }
};
}

function EventWalker(registry) {
  this.registry = registry;
}

EventWalker.prototype.inRegistry = function EventWalker_inRegistry(id) {
  return !!this.registry[id];
};

EventWalker.prototype.closest = function EventWalker_closest(closest) {
  do {
    if (closest.id && this.inRegistry(closest.id)) {
      return ['id', closest];
    }
    if (closest.hasAttribute('data-ember-action')) {
      return ['action', closest];
    }
  } while (closest = closest.parentNode);
  return null;
};
<|endoftext|>


<commit_before>const convertToArray = elemList => Array.prototype.slice.apply(elemList);

export default function () {
    const sections = convertToArray(
        document.querySelectorAll('.center-stage .section')
    );

    sections.forEach(section => {
        const label = section.querySelector('label');
        const content = section.querySelector('.content');

        label.addEventListener('click', event => {});
    });
};
<commit_msg>create a class that handles state<commit_after>const convertToArray = elemList => Array.prototype.slice.apply(elemList);

class ContentComponent {
    constructor(label, contentMain, contentCollapsed) {
        this.label = label;
        this.contentMain = contentMain;
        this.contentCollapsed = contentCollapsed;
        this.collapsed = false;

        this.addListeners();
        this.setInitialState();
    }

    addListeners() {
        this.label.addEventListener('click', event => this.toggleState());
        this.contentCollapsed.addEventListener('click', event => this.toggleState());
    }

    toggleState() {
        if (this.collapsed) {
            this.contentMain.classList.add('hidden');
            this.contentCollapsed.classList.remove('hidden');
        }
        else {
            this.contentMain.classList.remove('hidden');
            this.contentCollapsed.classList.add('hidden');
        }

        this.collapsed = !this.collapsed;
    }

    setInitialState() {
        this.contentCollapsed.classList.add('hidden');
    }
}

export default function () {
    const sections = convertToArray(
        document.querySelectorAll('.center-stage .section')
    );

    sections.forEach(section => {
        const label = section.querySelector('label');
        const contentMain = section.querySelector('.content');
        const contentCollapsed = section.querySelector('.content-collapsed');

        section.component = new ContentComponent(label, contentMain, contentCollapsed);
    });
};
<|endoftext|>


<commit_before>function clickEvents() {

    $('body').click(function(e) {
        // The element that was clicked.
        // Make sure to use Elem everywhere instead of "this".
        var Elem = e.target;

        // Add Online Streamer
        if ($(Elem).hasClass('addonline')) {
            var username = $(Elem).attr('name');
            console.log('Clicked online for ' + username);
            singleChannelSubscribe(username)
        }

        // Go Button!
        // Finds username and userid then updates notifications.
        if ($(Elem).hasClass('followeraddbtn')) {
            var localUsername = $('.followeradd').val();
            if (localUsername !== '') {
                localStorage.setItem("username", localUsername);
                $.getJSON("https://Mixer.com/api/v1/channels/" + localUsername + "?fields=userId", function(body) {
                    var userID = body.userId;
                    localStorage.setItem('userID', userID);
                    jumperUpdate(0);
                });
            }
        }

        // Add Other Box
        if ($(Elem).hasClass('streamerinputaddbtn')) {
            var username = $('.streamerinputadd').val();

            // Local Storage List
            if (username !== '') {
                if ($('.' + username).length === 0) {
                    singleChannelSubscribe(username);
                    var pastAdds = localStorage.getItem("streamer");
                }
                $('.streamerinputadd').val('');
            }

        }

        // Add All Button
        if ($(Elem).hasClass('addallbutton')) {
            var localUsername = localStorage.getItem('username');

            // Local Storage List
            if (localUsername !== '' && localUsername !== undefined) {
                multiChannelSubscribe(localUsername, 0);
            }
        }

        // Close button
        if ($(Elem).hasClass('closebtn')) {
            var stream = $(Elem).attr('stream');
            var username = $('#' + stream + ' h2').text();
            var savedStreams = localStorage.getItem("streamer");
            $(Elem).closest('.stream').remove();
        };

    }); // end on body clicks

}

function singleChannelSubscribe(username) {
    $.getJSON('https://Mixer.com/api/v1/channels/' + username + '?fields=id,online,token,name,type,partnered,numFollowers', function(body, response) {
        // If response recieved and the div isn't already on the page.
        if ($('.' + body.token).length === 0) {
            var channelID = body.id;
            var cName = body.token;
            var cTitle = body.name;
            if (body.type !== null && body.type !== undefined && body.type !== "") {
                var cGame = body.type.name;
            } else {
                var cGame = "No Game Set";
            }
            var cPartnered = body.partnered;
            var cFollowers = body.numFollowers;

            var cOnline = body.online;
            buildChannel(channelID, cName, cTitle, cGame, cPartnered, cFollowers);

            // If channel is offline when added, make title gray.
            if (cOnline === false) {
                $('#' + channelID + ' h2').addClass('offline');
            };

        } else {
            console.error('Error checking the online state for the channel', username);
        }
    });
}

function multiChannelSubscribe(localUsername, page) {
    // Get user ID.
    $.getJSON('https://Mixer.com/api/v1/channels/' + localUsername + '?fields=userId', function(body, response) {
        // Get list of people user follows.
        var userID = body.userId;
        localStorage.setItem('userID', userID);
        $.getJSON('https://Mixer.com/api/v1/users/' + userID + '/follows?limit=50&where=online:eq:1&page=' + page, function(body, response) {
            // Loop through list.
            $.each(body, function(index, element) {
                // If channel not suspended and they aren't already on the page...
                if (element.suspended !== true && $('#' + element.id).length === 0) {
                    var channelID = element.id;
                    var cName = element.token;
                    var cTitle = element.name;
                    if (element.type !== null && element.type !== undefined && element.type !== "") {
                        var cGame = element.type.name;
                    } else {
                        var cGame = "No Game Set";
                    }
                    var cPartnered = element.partnered;
                    var cFollowers = element.numFollowers;

                    // If the channel is online then go ahead and build it.
                    buildChannel(channelID, cName, cTitle, cGame, cPartnered, cFollowers);
                }
            });

            // If the number of results equals 50, then we need to check the next page for new items.
            // Otherwise, we've cycled through all of their followers.
            if (body.length === 50) {
                var pageCount = parseInt(page, 10) + 1;
                multiChannelSubscribe(localUsername, pageCount);
            }
        });
    });
}

// Build Channel
// This function adds the channel to teh page using gathered info.
function buildChannel(channelID, username, title, game, partnered, followers) {

    // If the channel is partnered we're gonna make the name purple.
    if (partnered === true) {
        var partnered = "partnered";
    } else {
        var partnered = "not-partnered";
    }
    // If channel is not already on the page...
    if ($('#' + channelID).length === 0) {
        var streamEmbed = "https://Mixer.com/embed/player/" + username;
        var chatEmbed = "https://Mixer.com/embed/chat/" + username;

        // Build out the stream on the page.
        $('.channelwrapper').append('

<button class="closebtn" stream="' + channelID + '">X</button>

');
        $('#' + channelID + ' .chatwrap').html('');
        $('#' + channelID + ' .streamtop h2').html('' + username + '');
        $('#' + channelID + ' .cGame').text(game);
        $('#' + channelID + ' .cTitle').text(title);
        $('#' + channelID + ' .streamtop').append('<button class="watch" stream="' + username + '">Watch</button>');
        $('#' + channelID).css('display', 'block');

        // Watch Button to watch streams..
        $('#' + channelID + ' .watch').click(function() {
            $('#' + channelID).before('

<button class="closebtn" stream="' + channelID + '">X</button>

' + username + '

');

            // Set height of chat window to the same height as the video..
            var newHeight = $('.streamembed[stream="' + channelID + '"] iframe').height();
            $('.chatembed').css('height', newHeight);

            // Scroll to element to account for new chat height.
            $('html, body').delay(750).animate({
                scrollTop: $('.streamembed[stream="' + channelID + '"]').offset().top
            }, 1500);

            $('.streamembed[stream="' + channelID + '"] .closestreamembed .closebtn').click(function() {
                $('.streamembed[stream="' + channelID + '"]').remove();
                // Set related chat window back to regular height.
                $('.chatembed').css('height', '400px');
            });
        });

    }
}

// Displays an alert if a new channel comes online that isn't already shown.
function jumperUpdate(page) {

    var userID = localStorage.getItem('userID');
    if (userID !== '' && userID !== undefined && userID !== null) {
        $.getJSON('https://Mixer.com/api/v1/users/' + userID + '/follows?limit=50&where=online:eq:1&page=' + page, function(body, response) {
            // Loop through list.
            $.each(body, function(index, element) {
                var cName = element.token;
                var partnered = element.partnered;
                if (partnered === true) {
                    var partnered = "partner-notification";
                } else {
                    var partnered = "regular-notification";
                }

                // Remove default notification text
                $('.default-notify-text').remove();

                // If channel not suspended and they aren't already on the page...
                if (element.suspended !== true && $('#' + element.id).length === 0 && element.online === true) {
                    // Add line to notification box
                    if ($('.' + cName + '-notification').length < 1) {
                        $('.notification').prepend('
<button class="addonline" name="' + cName + '">Add</button>' + cName + 'New
');
                    }

                    // If menu is not opened then add a notification alert.
                    if ($('.menu-link.active').length === 0) {
                        // Update notification number to match number of new notifications.
                        var notificationNumber = parseInt($('.menu-notification-alert').html());
                        var notificationList = $('.notification .notification-new').length;
                        if (notificationNumber !== notificationList) {
                            $('.menu-notification-alert').text(notificationList);
                            $('.menu-notification-alert').fadeIn('fast');
                        }
                    }

                    // Show scroll bar once notification area hits 600 px tall.
                    if ($('.notification').height() >= 400) {
                        $('.notification').css('overflow-y', 'scroll');
                    } else {
                        $('.notification').css('overflow-y', 'hidden');
                    }

                    // Throw in the add all button if people are online and local username is set.
                    var localUser = localStorage.getItem('username');
                    var onlinePeople = $('.notification-name').length;
                    if (localUser !== undefined && localUser !== '' && $('.addallbutton').is('visible') === false && onlinePeople > 2) {
                        $('.addallbutton').fadeIn('fast');
                    } else {
                        $('.addallbutton').fadeOut('fast');
                    }

                } else if ($('#' + element.id).length > 0 && element.online === false) {

                    // Remove their line from the notification box.
                    $('.' + cName + '-notification').remove();
                }
            });

            // If the number of results equals 50, then we need to check the next page for new items.
            // Otherwise, we've cycled through all of their followers.
            if (body.length === 50) {
                var pageCount = parseInt(page, 10) + 1;
                console.log("Finished page " + page + " moving on to page " + pageCount + ".");
                jumperUpdate(pageCount);
            }
        });
    }
}

// Navigation Open and Closed Triggers
function navOpen() {
    // When menu is opened, clear alert number and hide alert.
    $('.menu-notification-alert').text('0');
    $('.menu-notification-alert').hide();
}

function navClosed() {
    // Remove new notification in notification list.
    $('.notification-new').remove();
}

function stickyHeader() {
    $(window).scroll(function() {
        if ($(this).scrollTop() > 1) {
            $('.top').addClass("sticky");
        } else {
            $('.top').removeClass("sticky");
        }
    });
}

$(document).ready(function() {
    clickEvents();

    // Load up past username.
    var localUsername = localStorage.getItem('username');
    $('.followeradd').val(localUsername);

    // Make streams sortable.
    $(".channelwrapper").sortable({
        placeholder: 'stream-placeholder'
    });

    // Run notification
    setInterval(function() {
        jumperUpdate(0);
    }, 60000)

    // Settings Menu
    $('.menu-link').bigSlide({
        easyClose: true,
        state: 'open',
        afterOpen: function() {
            navOpen();
        },
        afterClose: function() {
            navClosed();
        }
    });

    stickyHeader();
    $('.settings').show();

});
<commit_msg>fix scroll<commit_after>function clickEvents() {

    $('body').click(function(e) {
        // The element that was clicked.
        // Make sure to use Elem everywhere instead of "this".
        var Elem = e.target;

        // Add Online Streamer
        if ($(Elem).hasClass('addonline')) {
            var username = $(Elem).attr('name');
            console.log('Clicked online for ' + username);
            singleChannelSubscribe(username)
        }

        // Go Button!
        // Finds username and userid then updates notifications.
        if ($(Elem).hasClass('followeraddbtn')) {
            var localUsername = $('.followeradd').val();
            if (localUsername !== '') {
                localStorage.setItem("username", localUsername);
                $.getJSON("https://Mixer.com/api/v1/channels/" + localUsername + "?fields=userId", function(body) {
                    var userID = body.userId;
                    localStorage.setItem('userID', userID);
                    jumperUpdate(0);
                });
            }
        }

        // Add Other Box
        if ($(Elem).hasClass('streamerinputaddbtn')) {
            var username = $('.streamerinputadd').val();

            // Local Storage List
            if (username !== '') {
                if ($('.' + username).length === 0) {
                    singleChannelSubscribe(username);
                    var pastAdds = localStorage.getItem("streamer");
                }
                $('.streamerinputadd').val('');
            }

        }

        // Add All Button
        if ($(Elem).hasClass('addallbutton')) {
            var localUsername = localStorage.getItem('username');

            // Local Storage List
            if (localUsername !== '' && localUsername !== undefined) {
                multiChannelSubscribe(localUsername, 0);
            }
        }

        // Close button
        if ($(Elem).hasClass('closebtn')) {
            var stream = $(Elem).attr('stream');
            var username = $('#' + stream + ' h2').text();
            var savedStreams = localStorage.getItem("streamer");
            $(Elem).closest('.stream').remove();
        };

    }); // end on body clicks

}

function singleChannelSubscribe(username) {
    $.getJSON('https://Mixer.com/api/v1/channels/' + username + '?fields=id,online,token,name,type,partnered,numFollowers', function(body, response) {
        // If response recieved and the div isn't already on the page.
        if ($('.' + body.token).length === 0) {
            var channelID = body.id;
            var cName = body.token;
            var cTitle = body.name;
            if (body.type !== null && body.type !== undefined && body.type !== "") {
                var cGame = body.type.name;
            } else {
                var cGame = "No Game Set";
            }
            var cPartnered = body.partnered;
            var cFollowers = body.numFollowers;

            var cOnline = body.online;
            buildChannel(channelID, cName, cTitle, cGame, cPartnered, cFollowers);

            // If channel is offline when added, make title gray.
            if (cOnline === false) {
                $('#' + channelID + ' h2').addClass('offline');
            };

        } else {
            console.error('Error checking the online state for the channel', username);
        }
    });
}

function multiChannelSubscribe(localUsername, page) {
    // Get user ID.
    $.getJSON('https://Mixer.com/api/v1/channels/' + localUsername + '?fields=userId', function(body, response) {
        // Get list of people user follows.
        var userID = body.userId;
        localStorage.setItem('userID', userID);
        $.getJSON('https://Mixer.com/api/v1/users/' + userID + '/follows?limit=50&where=online:eq:1&page=' + page, function(body, response) {
            // Loop through list.
            $.each(body, function(index, element) {
                // If channel not suspended and they aren't already on the page...
                if (element.suspended !== true && $('#' + element.id).length === 0) {
                    var channelID = element.id;
                    var cName = element.token;
                    var cTitle = element.name;
                    if (element.type !== null && element.type !== undefined && element.type !== "") {
                        var cGame = element.type.name;
                    } else {
                        var cGame = "No Game Set";
                    }
                    var cPartnered = element.partnered;
                    var cFollowers = element.numFollowers;

                    // If the channel is online then go ahead and build it.
                    buildChannel(channelID, cName, cTitle, cGame, cPartnered, cFollowers);
                }
            });

            // If the number of results equals 50, then we need to check the next page for new items.
            // Otherwise, we've cycled through all of their followers.
            if (body.length === 50) {
                var pageCount = parseInt(page, 10) + 1;
                multiChannelSubscribe(localUsername, pageCount);
            }
        });
    });
}

// Build Channel
// This function adds the channel to teh page using gathered info.
function buildChannel(channelID, username, title, game, partnered, followers) {

    // If the channel is partnered we're gonna make the name purple.
    if (partnered === true) {
        var partnered = "partnered";
    } else {
        var partnered = "not-partnered";
    }
    // If channel is not already on the page...
    if ($('#' + channelID).length === 0) {
        var streamEmbed = "https://Mixer.com/embed/player/" + username;
        var chatEmbed = "https://Mixer.com/embed/chat/" + username;

        // Build out the stream on the page.
        $('.channelwrapper').append('

<button class="closebtn" stream="' + channelID + '">X</button>

');
        $('#' + channelID + ' .chatwrap').html('');
        $('#' + channelID + ' .streamtop h2').html('' + username + '');
        $('#' + channelID + ' .cGame').text(game);
        $('#' + channelID + ' .cTitle').text(title);
        $('#' + channelID + ' .streamtop').append('<button class="watch" stream="' + username + '">Watch</button>');
        $('#' + channelID).css('display', 'block');

        // Watch Button to watch streams..
        $('#' + channelID + ' .watch').click(function() {
            $('#' + channelID).before('

<button class="closebtn" stream="' + channelID + '">X</button>

' + username + '

');

            // Set height of chat window to the same height as the video..
            var newHeight = $('.streamembed[stream="' + channelID + '"] iframe').height();
            $('.chatembed').css('height', newHeight);

            // Scroll to element to account for new chat height.
            $('html, body').delay(750).animate({
                scrollTop: $('.streamembed[stream="' + channelID + '"]').offset().top
            }, 1500);

            $('.streamembed[stream="' + channelID + '"] .closestreamembed .closebtn').click(function() {
                $('.streamembed[stream="' + channelID + '"]').remove();
                // Set related chat window back to regular height.
                $('.chatembed').css('height', '400px');
            });
        });

    }
}

// Displays an alert if a new channel comes online that isn't already shown.
function jumperUpdate(page) {

    var userID = localStorage.getItem('userID');
    if (userID !== '' && userID !== undefined && userID !== null) {
        $.getJSON('https://Mixer.com/api/v1/users/' + userID + '/follows?limit=50&where=online:eq:1&page=' + page, function(body, response) {
            // Loop through list.
            $.each(body, function(index, element) {
                var cName = element.token;
                var partnered = element.partnered;
                if (partnered === true) {
                    var partnered = "partner-notification";
                } else {
                    var partnered = "regular-notification";
                }

                // Remove default notification text
                $('.default-notify-text').remove();

                // If channel not suspended and they aren't already on the page...
                if (element.suspended !== true && $('#' + element.id).length === 0 && element.online === true) {
                    // Add line to notification box
                    if ($('.' + cName + '-notification').length < 1) {
                        $('.notification').prepend('
<button class="addonline" name="' + cName + '">Add</button>' + cName + 'New
');
                    }

                    // If menu is not opened then add a notification alert.
                    if ($('.menu-link.active').length === 0) {
                        // Update notification number to match number of new notifications.
                        var notificationNumber = parseInt($('.menu-notification-alert').html());
                        var notificationList = $('.notification .notification-new').length;
                        if (notificationNumber !== notificationList) {
                            $('.menu-notification-alert').text(notificationList);
                            $('.menu-notification-alert').fadeIn('fast');
                        }
                    }

                    // Show scroll bar
                    $('.notification').css('overflow-y', 'scroll');

                    // Throw in the add all button if people are online and local username is set.
                    var localUser = localStorage.getItem('username');
                    var onlinePeople = $('.notification-name').length;
                    if (localUser !== undefined && localUser !== '' && $('.addallbutton').is('visible') === false && onlinePeople > 2) {
                        $('.addallbutton').fadeIn('fast');
                    } else {
                        $('.addallbutton').fadeOut('fast');
                    }

                } else if ($('#' + element.id).length > 0 && element.online === false) {

                    // Remove their line from the notification box.
                    $('.' + cName + '-notification').remove();
                }
            });

            // If the number of results equals 50, then we need to check the next page for new items.
            // Otherwise, we've cycled through all of their followers.
            if (body.length === 50) {
                var pageCount = parseInt(page, 10) + 1;
                console.log("Finished page " + page + " moving on to page " + pageCount + ".");
                jumperUpdate(pageCount);
            }
        });
    }
}

// Navigation Open and Closed Triggers
function navOpen() {
    // When menu is opened, clear alert number and hide alert.
    $('.menu-notification-alert').text('0');
    $('.menu-notification-alert').hide();
}

function navClosed() {
    // Remove new notification in notification list.
    $('.notification-new').remove();
}

function stickyHeader() {
    $(window).scroll(function() {
        if ($(this).scrollTop() > 1) {
            $('.top').addClass("sticky");
        } else {
            $('.top').removeClass("sticky");
        }
    });
}

$(document).ready(function() {
    clickEvents();

    // Load up past username.
    var localUsername = localStorage.getItem('username');
    $('.followeradd').val(localUsername);

    // Make streams sortable.
    $(".channelwrapper").sortable({
        placeholder: 'stream-placeholder'
    });

    // Run notification
    setInterval(function() {
        jumperUpdate(0);
    }, 60000)

    // Settings Menu
    $('.menu-link').bigSlide({
        easyClose: true,
        state: 'open',
        afterOpen: function() {
            navOpen();
        },
        afterClose: function() {
            navClosed();
        }
    });

    stickyHeader();
    $('.settings').show();

});
<|endoftext|>


<commit_before>import Ember from 'ember';

var StyleObserver = Ember.Object.extend({
	target: null,
	property: null,
	cssName: null,
	unit: null,
	_cssStyle: null,

	_setup: Ember.on('init', function() {
		this.set('_cssStyle', this.get('target.element').style);
  	this._startObserving();
  	this._setStyle();
	}),

	_teardown: Ember.on('willDestroy', function() {
  	this.stop();
	}),

	_startObserving: function() {
		this.get('target').addObserver(this.get('property'), this, '_propertyDidChange');
	},

	stop: function() {
		var target = this.get('target');
		if (target)
		{
			target.removeObserver(this.get('property'), this, '_propertyDidChange');
	  	this._removeStyle();
			this.set('target', null);
		}
	},

	_propertyDidChange: function (/*target, property*/) {
		this._setStyle();
	},

	_setStyle: function() {
		var name = this.get('cssName');
		var unit = this.get('unit');
		var value = this._getValue();
		var cssStyle = this.get('_cssStyle');
		// add units to numeric value
		if (!isNaN(parseFloat(value)) && isFinite(value)) {
			value = value + unit;
		}
		// escape if necessary
		if (!(value instanceof Ember.Handlebars.SafeString)) {
			value = Ember.Handlebars.Utils.escapeExpression(value);
		}
		// ie9 gets upset if value is 'NaN'
		if (value === 'NaN') {
			value = '';
		}
		// set the property
		if (value != null)
		{
			cssStyle.setProperty(name, value);
		}
		else {
			cssStyle.removeProperty(name, value);
		}
	},

	_getValue: function() {
		var property = this.get('property');
		return this.get('target.'+property);
	},

	_removeStyle: function() {
		var name = this.get('cssName');
		var cssStyle = this.get('_cssStyle');
		cssStyle.removeProperty(name);
	}
});

var YesNoStyleObserver = StyleObserver.extend({
	yesNo: null,

	_getValue: function() {
		var value = this._super();
		var yesNo = this.get('yesNo');
		if (yesNo)
		{
			value = value ? yesNo.yes : yesNo.no;
		}
		return value;
	}
});

export default Ember.Mixin.create({

	concatenatedProperties: ['styleBindings'],
	_styleObservers: null,

	_regex: /^(([^\?:]+):)?([a-z0-9_\.-]+)(\[([a-z%]+)\])?(\?([a-z0-9_\.\-]*):([a-z0-9_\.\-]*))?$/i,

	doInit: Ember.on('willInsertElement', function() {
		this._refreshBindings();
	}),

	styleBindingsChanged: Ember.observer('styleBindings', function() {
		this._refreshBindings();
	}),

	doCleanup: Ember.on('willDestroyElement', function() {
		var observers = this.get('_styleObservers') || {};
		// remove all bindings
		for(var property in observers) {
			if (observers.hasOwnProperty(property)) {
				observers[property].stop();
				delete observers[property];
			}
		}
		this.set('_styleObservers', {});
	}),

	_refreshBindings: function() {

		var hashCode = function(s){
		  return s.split("").reduce(function(a,b){
		  	a=((a<<5)-a)+b.charCodeAt(0);
		  	return a&a;
		  },0);
		};

		var styleBindings = this.get('styleBindings') || [];

		var observers = this.get('_styleObservers') || {};
		var foundBindings = {};

		// iterate the style bindings
		for (var i=0; i< styleBindings.length; i++) {
			var binding = styleBindings[i];

			var hash = hashCode(binding);
			// add the observer if it's not there already
			if (!observers[hash])
			{
				observers[hash] = this._createObserver(binding);
			}
			foundBindings[hash] = true;
		}

		// look for removed bindings
		for(var property in observers) {
			if (observers.hasOwnProperty(property)) {
				if (!foundBindings[property])
				{
					observers[property].stop();
					delete observers[property];
				}
			}
		}

		this.set('_styleObservers', observers);
	},

	_createObserver: function(binding) {
		var match = binding.match(this.get('_regex'));
		if (match) {
      var cssProp = match[3];
      var emberProp = match[2] || Ember.String.camelize(cssProp);
      var unit = match[5];
      var type = StyleObserver;
      var properties = {
				target: this,
				property: emberProp,
				cssName: cssProp,
				unit: unit
			};
      if (match[6]) {
      	type = YesNoStyleObserver;
        properties.yesNo = {
        	yes: match[7],
        	no: match[8]
        };
      }
      return type.create(properties);
    }
	}

});
<commit_msg>fix style injection for ember 2.0<commit_after>import Ember from 'ember';

var StyleObserver = Ember.Object.extend({
	target: null,
	property: null,
	cssName: null,
	unit: null,
	styleChunk: null,

//	_cssStyle: null,

	_setup: Ember.on('init', function() {
//		this.set('_cssStyle', this.$().style);
		this._startObserving();
		this._setStyle();
	}),

	_teardown: Ember.on('willDestroy', function() {
		this.stop();
	}),

	_startObserving: function() {
		this.get('target').addObserver(this.get('property'), this, '_propertyDidChange');
	},

	stop: function() {
		var target = this.get('target');
		if (target)
		{
			target.removeObserver(this.get('property'), this, '_propertyDidChange');
			this._removeStyle();
			this.set('target', null);
		}
	},

	_propertyDidChange: function (/*target, property*/) {
		this._setStyle();
	},

	_setStyle: function() {
		var name = this.get('cssName');
		var unit = this.get('unit');
		var value = this._getValue();
		// add units to numeric value
		if (!isNaN(parseFloat(value)) && isFinite(value) && unit) {
			value = value + unit;
		}
		// escape if necessary
		if (value instanceof Ember.Handlebars.SafeString) {
			value = value.toString();
		}
		else
		{
			value = Ember.Handlebars.Utils.escapeExpression(value);
		}
		// ie9 gets upset if value is 'NaN'
		if (value === 'NaN') {
			value = '';
		}
		// set the property
		this.set('styleChunk', `${name}:${value};`);
		this.get('target')._refreshStyle();
	},

	_getValue: function() {
		var property = this.get('property');
		return this.get('target.'+property);
	},

	_removeStyle: function() {
		this.set('styleChunk', null);
	}
});

var YesNoStyleObserver = StyleObserver.extend({
	yesNo: null,

	_getValue: function() {
		var value = this._super();
		var yesNo = this.get('yesNo');
		if (yesNo)
		{
			value = value ? yesNo.yes : yesNo.no;
		}
		return value;
	}
});

export default Ember.Mixin.create({

	concatenatedProperties: ['styleBindings'],
	attributeBindings: ['style'],
	style: Ember.String.htmlSafe(''),

	_styleObservers: null,

	_regex: /^(([^\?:]+):)?([a-z0-9_\.-]+)(\[([a-z%]+)\])?(\?([a-z0-9_\.\-]*):([a-z0-9_\.\-]*))?$/i,

	doInit: Ember.on('willRender', function() {
		this._refreshBindings();
	}),

	styleBindingsChanged: Ember.observer('styleBindings', function() {
		this._refreshBindings();
	}),

	doCleanup: Ember.on('willDestroyElement', function() {
		var observers = Ember.get(this, '_styleObservers') || {};
		// remove all bindings
		for(var property in observers) {
			if (observers.hasOwnProperty(property)) {
				observers[property].stop();
				delete observers[property];
			}
		}
		Ember.set(this, '_styleObservers', {});
	}),

	_refreshStyle() {
		var style = "";
		var observers = Ember.get(this, '_styleObservers');
		for (var key in observers)
		{
			style += Ember.get(observers[key], 'styleChunk');
		}
		Ember.set(this, 'style', Ember.String.htmlSafe(style));
	},

	_refreshBindings: function() {

		var hashCode = function(s){
		  return s.split("").reduce(function(a,b){
			a=((a<<5)-a)+b.charCodeAt(0);
			return a&a;
		  },0);
		};

		var styleBindings = this.get('styleBindings') || [];

		var observers = this.get('_styleObservers') || {};
		var foundBindings = {};

		// iterate the style bindings
		for (var i=0; i< styleBindings.length; i++) {
			var binding = styleBindings[i];

			var hash = hashCode(binding);
			// add the observer if it's not there already
			if (!observers[hash])
			{
				observers[hash] = this._createObserver(binding);
			}
			foundBindings[hash] = true;
		}

		// look for removed bindings
		for(var property in observers) {
			if (observers.hasOwnProperty(property)) {
				if (!foundBindings[property])
				{
					observers[property].stop();
					delete observers[property];
				}
			}
		}

		this.set('_styleObservers', observers);
		this._refreshStyle();
	},

	_createObserver: function(binding) {
		var match = binding.match(this.get('_regex'));
		if (match) {
			var cssProp = match[3];
			var emberProp = match[2] || Ember.String.camelize(cssProp);
			var unit = match[5];
			var type = StyleObserver;
			var properties = {
				target: this,
				property: emberProp,
				cssName: cssProp,
				unit: unit
			};
			if (match[6]) {
				type = YesNoStyleObserver;
				properties.yesNo = {
					yes: match[7],
					no: match[8]
				};
			}
			return type.create(properties);
		}
	}

});
<|endoftext|>


<commit_before>ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules","ace/worker/worker_client","ace/mode/text"], function(require, exports, module) {

    "use strict";

    var oop = require("../lib/oop");
    var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

    var WorkerClient = require("../worker/worker_client").WorkerClient;
    var jsonataFunctions = Object.keys(jsonata.functions);
    // sort in length order (long->short) otherwise substringAfter gets matched
    // as substring etc.
    jsonataFunctions.sort(function(A,B) {
        return B.length-A.length;
    });
    jsonataFunctions = jsonataFunctions.join("|").replace(/\$/g,"\\$");

    var JSONataHighlightRules = function() {

        var keywordMapper = this.createKeywordMapper({
            "keyword.operator":
            "and|or|in",
            "constant.language":
            "null|Infinity|NaN|undefined",
            "constant.language.boolean":
            "true|false",
            "storage.type":
            "function"
        }, "identifier");
        this.$rules = {
            "start" : [
                {
                    token : "string",
                    regex : "'(?=.)",
                    next  : "qstring"
                },
                {
                    token : "string",
                    regex : '"(?=.)',
                    next  : "qqstring"
                },
                {
                    token : "constant.numeric", // hex
                    regex : /0(?:[xX][0-9a-fA-F]+|[bB][01]+)\b/
                },
                {
                    token : "constant.numeric", // float
                    regex : /[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
                },
                {   token: "keyword",
                regex: /λ/
            },
            {
                token: "keyword",
                regex: jsonataFunctions
            },
            {
                token : keywordMapper,
                regex : "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*"
            },
            {
                token : "punctuation.operator",
                regex : /[.](?![.])/
            },
            {
                token : "keyword.operator",
                regex : /\|\||<=|>=|\.\.|\*\*|!=|:=|[=<>`!$%&*+\-~\/^]/,
                next  : "start"
            },
            {
                token : "punctuation.operator",
                regex : /[?:,;.]/,
                next  : "start"
            },
            {
                token : "paren.lparen",
                regex : /[\[({]/,
                    next  : "start"
                },
                {
                    token : "paren.rparen",
                    regex : /[\])}]/
                }
            ],
            "qqstring" : [
                {
                    token : "string",
                    regex : '"|$',
                    next  : "start"
                }, {
                    defaultToken: "string"
                }
            ],
            "qstring" : [
                {
                    token : "string",
                    regex : "'|$",
                    next  : "start"
                }, {
                    defaultToken: "string"
                }
            ]
        };
    };

    oop.inherits(JSONataHighlightRules, TextHighlightRules);

    var TextMode = require("./text").Mode;
    var Mode = function() {
        this.HighlightRules = JSONataHighlightRules;
    };
    oop.inherits(Mode, TextMode);

    (function() {
        this.createWorker = function(session) {
            var worker = new WorkerClient(["ace"], "ace/mode/jsonata_worker", "JSONataWorker");
            worker.attachToDocument(session.getDocument());

            worker.on("annotate", function(e) {
                session.setAnnotations(e.data);
            });

            worker.on("terminate", function() {
                session.clearAnnotations();
            });

            return worker;
        };
        this.$id = "ace/mode/jsonata";
    }).call(Mode.prototype);

    exports.Mode = Mode;

});
<commit_msg>Add better regex highlighting in jsonata edit mode Fixes #2465<commit_after>ace.define("ace/mode/jsonata",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules","ace/worker/worker_client","ace/mode/text"], function(require, exports, module) {

    "use strict";

    var oop = require("../lib/oop");
    var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

    var WorkerClient = require("../worker/worker_client").WorkerClient;
    var jsonataFunctions = Object.keys(jsonata.functions);
    // sort in length order (long->short) otherwise substringAfter gets matched
    // as substring etc.
    jsonataFunctions.sort(function(A,B) {
        return B.length-A.length;
    });
    jsonataFunctions = jsonataFunctions.join("|").replace(/\$/g,"\\$");

    var JSONataHighlightRules = function() {

        var keywordMapper = this.createKeywordMapper({
            "keyword.operator":
            "and|or|in",
            "constant.language":
            "null|Infinity|NaN|undefined",
            "constant.language.boolean":
            "true|false",
            "storage.type":
            "function"
        }, "identifier");
        this.$rules = {
            "start" : [
                {
                    token: "string.regexp",
                    regex: "\\/",
                    next: "regex"
                },
                {
                    token : "string",
                    regex : "'(?=.)",
                    next  : "qstring"
                },
                {
                    token : "string",
                    regex : '"(?=.)',
                    next  : "qqstring"
                },
                {
                    token : "constant.numeric", // hex
                    regex : /0(?:[xX][0-9a-fA-F]+|[bB][01]+)\b/
                },
                {
                    token : "constant.numeric", // float
                    regex : /[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
                },
                {
                    token: "keyword",
                    regex: /λ/
                },
                {
                    token: "keyword",
                    regex: jsonataFunctions
                },
                {
                    token : keywordMapper,
                    regex : "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*"
                },
                {
                    token : "punctuation.operator",
                    regex : /[.](?![.])/
                },
                {
                    token : "keyword.operator",
                    regex : /\|\||<=|>=|\.\.|\*\*|!=|:=|[=<>`!$%&*+\-~\/^]/,
                    next  : "start"
                },
                {
                    token : "punctuation.operator",
                    regex : /[?:,;.]/,
                    next  : "start"
                },
                {
                    token : "paren.lparen",
                    regex : /[\[({]/,
                    next  : "start"
                },
                {
                    token : "paren.rparen",
                    regex : /[\])}]/
                }
            ],
            "qqstring" : [
                {
                    token : "string",
                    regex : '"|$',
                    next  : "start"
                },
                {
                    defaultToken: "string"
                }
            ],
            "qstring" : [
                {
                    token : "string",
                    regex : "'|$",
                    next  : "start"
                },
                {
                    defaultToken: "string"
                }
            ],
            "regex" : [
                {
                    token: "string.regexp",
                    regex: "\\\\/"
                },
                {
                    token: "string.regexp",
                    regex: "/[sxngimy]*",
                    next: "start"
                },
                {
                    defaultToken: "string.regexp"
                }
            ]
        };
    };

    oop.inherits(JSONataHighlightRules, TextHighlightRules);

    var TextMode = require("./text").Mode;
    var Mode = function() {
        this.HighlightRules = JSONataHighlightRules;
    };
    oop.inherits(Mode, TextMode);

    (function() {
        this.createWorker = function(session) {
            var worker = new WorkerClient(["ace"], "ace/mode/jsonata_worker", "JSONataWorker");
            worker.attachToDocument(session.getDocument());

            worker.on("annotate", function(e) {
                session.setAnnotations(e.data);
            });

            worker.on("terminate", function() {
                session.clearAnnotations();
            });

            return worker;
        };
        this.$id = "ace/mode/jsonata";
    }).call(Mode.prototype);

    exports.Mode = Mode;

});
<|endoftext|>