<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  /////////////////////////////////////////////////////////////////////////////
  // OptionsPage class:

  /**
   * Base class for options page.
   * @constructor
   * @param {string} name Options page name, also defines id of the div element
   *     containing the options view and the name of options page navigation bar
   *     item as name+'PageNav'.
   * @param {string} title Options page title, used for navigation bar
   * @extends {EventTarget}
   */
  function OptionsPage(name, title, pageDivName) {
    this.name = name;
    this.title = title;
    this.pageDivName = pageDivName;
    this.pageDiv = $(this.pageDivName);
    this.tab = null;
    this.managed = false;
  }

  /**
   * Main level option pages.
   * @protected
   */
  OptionsPage.registeredPages = {};

  /**
   * Pages which are nested under a main level page.
   * @protected
   */
  OptionsPage.registeredSubPages = {};

  /**
   * Pages which are meant to behave like modal dialogs.
   * @protected
   */
  OptionsPage.registeredOverlayPages = {};

  /**
   * Whether or not |initialize| has been called.
   * @private
   */
  OptionsPage.initialized_ = false;

  /**
   * Shows a registered page. This handles both top-level pages and sub-pages.
   * @param {string} pageName Page name.
   */
  OptionsPage.showPageByName = function(pageName) {
    // Notify main pages if they will be hidden.
    for (var name in this.registeredPages) {
      var page = this.registeredPages[name];
      if (name != pageName && page.willHidePage)
        page.willHidePage();
    }

    // Update the visibility attribute for main pages.
    for (var name in this.registeredPages) {
      var page = this.registeredPages[name];
      page.visible = name == pageName;
    }

    // Update the visibility attribute for sub-pages.
    for (var name in this.registeredSubPages) {
      var pageInfo = this.registeredSubPages[name];
      var match = name == pageName;
      if (match && document.documentElement.getAttribute('hide-menu') != 'true')
        pageInfo.parentPage.visible = true;
      pageInfo.page.visible = match;
    }

    // Notify main pages if they were shown.
    for (var name in this.registeredPages) {
      var page = this.registeredPages[name];
      if (name == pageName && page.didShowPage)
        page.didShowPage();
    }
  };

  /**
   * Called on load. Dispatch the URL hash to the given page's handleHash
   * function.
   * @param {string} pageName The string name of the (registered) options page.
   * @param {string} hash The value of the hash component of the URL.
   */
  OptionsPage.handleHashForPage = function(pageName, hash) {
    var page = this.registeredPages[pageName];
    if (!page) {
      page = this.registeredSubPages[pageName].page;
    }
    page.handleHash(hash);
  };

  /**
   * Shows a registered Overlay page.
   * @param {string} overlayName Page name.
   */
  OptionsPage.showOverlay = function(overlayName) {
    if (this.registeredOverlayPages[overlayName]) {
      this.registeredOverlayPages[overlayName].visible = true;
    }
  };

  /**
   * Clears overlays (i.e. hide all overlays).
   */
  OptionsPage.clearOverlays = function() {
     for (var name in this.registeredOverlayPages) {
       var page = this.registeredOverlayPages[name];
       page.visible = false;
     }
  };

  /**
   * Handle 'keydown' events.
   * @param {Event} e Key event.
   * @private
   */
  OptionsPage.onKeyDown_ = function(e) {
    if (e.keyCode == 27) { // Esc
      this.clearOverlays();
    }
  };

  /**
   * Closes any currently-open subpage.
   */
  OptionsPage.closeSubPage = function() {
    for (var name in this.registeredSubPages) {
      var pageInfo = this.registeredSubPages[name];
      if (pageInfo.page.visible) {
        pageInfo.page.visible = false;
        // Since the managed pref banner lives outside the overlay, and the
        // parent is not changing visibility, update the banner explicitly.
        pageInfo.parentPage.updateManagedBannerVisibility();
      }
    }
  };

  /**
  * Shows the tab contents for the given navigation tab.
  * @param {!Element} tab The tab that the user clicked.
  */
  OptionsPage.showTab = function(tab) {
    // Search parents until we find a tab, or the nav bar itself. This allows
    // tabs to have child nodes, e.g. labels in separately-styled spans.
    while (tab && !tab.classList.contains('subpages-nav-tabs') &&
           !tab.classList.contains('inactive-tab')) {
      tab = tab.parentNode;
    }
    if (!tab || !tab.classList.contains('inactive-tab'))
      return;

    if (this.activeNavTab != null) {
      this.activeNavTab.classList.remove('active-tab');
      $(this.activeNavTab.getAttribute('tab-contents')).classList.
          remove('active-tab-contents');
    }

    tab.classList.add('active-tab');
    $(tab.getAttribute('tab-contents')).classList.add('active-tab-contents');
    this.activeNavTab = tab;
  };

  /**
   * Registers new options page.
   * @param {OptionsPage} page Page to register.
   */
  OptionsPage.register = function(page) {
    this.registeredPages[page.name] = page;
    // Create and add new page <li> element to navbar.
    var pageNav = document.createElement('li');
    pageNav.id = page.name + 'PageNav';
    pageNav.className = 'navbar-item';
    pageNav.setAttribute('pageName', page.name);
    pageNav.textContent = page.title;
    pageNav.tabIndex = 0;
    pageNav.onclick = function(event) {
      OptionsPage.showPageByName(this.getAttribute('pageName'));
    };
    pageNav.onkeypress = function(event) {
      // Enter or space
      if (event.keyCode == 13 || event.keyCode == 32) {
        OptionsPage.showPageByName(this.getAttribute('pageName'));
      }
    };
    var navbar = $('navbar');
    navbar.appendChild(pageNav);
    page.tab = pageNav;
    page.initializePage();
  };

  /**
   * Registers a new Sub tab page.
   * @param {OptionsPage} page Page to register.
   */
  OptionsPage.registerSubPage = function(subPage, parentPage) {
    this.registeredSubPages[subPage.name] = {
        page: subPage, parentPage: parentPage };
    subPage.tab = undefined;
    subPage.isSubPageSheet = true;
    subPage.initializePage();
  };

  /**
   * Registers a new Overlay page.
   * @param {OptionsPage} page Page to register, must be a class derived from
   * OptionsPage.
   */
  OptionsPage.registerOverlay = function(page) {
    this.registeredOverlayPages[page.name] = page;
    page.tab = undefined;
    page.isOverlay = true;
    page.initializePage();
  };

  /**
   * Callback for window.onpopstate.
   * @param {Object} data State data pushed into history.
   */
  OptionsPage.setState = function(data) {
    if (data && data.pageName) {
      this.showPageByName(data.pageName);
    }
  };

  /**
   * Initializes the complete options page.  This will cause
   * all C++ handlers to be invoked to do final setup.
   */
  OptionsPage.initialize = function() {
    chrome.send('coreOptionsInitialize');
    this.initialized_ = true;

    // Set up the overlay sheet. Clicks on the visible part of the parent page
    // should close the overlay, not fall through to the parent page.
    var self = this;
    $('subpage-sheet-container').onclick = function(event) {
      if (!$('subpage-sheet').contains(event.target))
        self.closeSubPage();
      event.stopPropagation();
    }
  };

  /**
   * Re-initializes the C++ handlers if necessary. This is called if the
   * handlers are torn down and recreated but the DOM may not have been (in
   * which case |initialize| won't be called again). If |initialize| hasn't been
   * called, this does nothing (since it will be later, once the DOM has
   * finished loading).
   */
  OptionsPage.reinitializeCore = function() {
    if (this.initialized_)
      chrome.send('coreOptionsInitialize');
  }

  OptionsPage.prototype = {
    __proto__: cr.EventTarget.prototype,

    /**
     * Initializes page content.
     */
    initializePage: function() {},

    /**
     * Sets managed banner visibility state.
     */
    setManagedBannerVisibility: function(visible) {
      this.managed = visible;
      if (this.visible) {
        this.updateManagedBannerVisibility();
      }
    },

    /**
     * Updates managed banner visibility state.
     */
    updateManagedBannerVisibility: function() {
      if (this.managed) {
        $('managed-prefs-banner').classList.remove('hidden');
      } else {
        $('managed-prefs-banner').classList.add('hidden');
      }
    },

    /**
     * Gets page visibility state.
     */
    get visible() {
      var page = $(this.pageDivName);
      return page && page.ownerDocument.defaultView.getComputedStyle(
          page).display == 'block';
    },

    /**
     * Sets page visibility.
     */
    set visible(visible) {
      if ((this.visible && visible) || (!this.visible && !visible))
        return;

      if (visible) {
        this.pageDiv.classList.remove('hidden');
        if (this.isOverlay) {
          $('overlay').classList.remove('hidden');
          document.addEventListener('keydown', OptionsPage.onKeyDown_);
        } else {
          if (this.isSubPageSheet)
            $('subpage-sheet-container').classList.remove('hidden');

          this.updateManagedBannerVisibility();

          // Recent webkit change no longer allows url change from "chrome://".
          window.history.pushState({pageName: this.name}, this.title);
        }
        if (this.tab) {
          this.tab.classList.add('navbar-item-selected');
        }
      } else {
        this.pageDiv.classList.add('hidden');
        if (this.isOverlay) {
          $('overlay').classList.add('hidden');
          document.removeEventListener('keydown', OptionsPage.onKeyDown_);
        } else if (this.isSubPageSheet) {
          $('subpage-sheet-container').classList.add('hidden');
        }
        if (this.tab) {
          this.tab.classList.remove('navbar-item-selected');
        }
      }

      cr.dispatchPropertyChange(this, 'visible', visible, !visible);
    },

    /**
     * Handles a hash value in the URL (such as bar in
     * chrome://options/foo#bar). Called on page load. By default, this shows
     * an overlay that matches the hash name, but can be overriden by individual
     * OptionsPage subclasses to get other behavior.
     * @param {string} hash The hash value.
     */
    handleHash: function(hash) {
      OptionsPage.showOverlay(hash);
    },
  };

  // Export
  return {
    OptionsPage: OptionsPage
  };

});
<commit_msg>DOMUI Options: Add esc handling for closing subpages<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  /////////////////////////////////////////////////////////////////////////////
  // OptionsPage class:

  /**
   * Base class for options page.
   * @constructor
   * @param {string} name Options page name, also defines id of the div element
   *     containing the options view and the name of options page navigation bar
   *     item as name+'PageNav'.
   * @param {string} title Options page title, used for navigation bar
   * @extends {EventTarget}
   */
  function OptionsPage(name, title, pageDivName) {
    this.name = name;
    this.title = title;
    this.pageDivName = pageDivName;
    this.pageDiv = $(this.pageDivName);
    this.tab = null;
    this.managed = false;
  }

  /**
   * Main level option pages.
   * @protected
   */
  OptionsPage.registeredPages = {};

  /**
   * Pages which are nested under a main level page.
   * @protected
   */
  OptionsPage.registeredSubPages = {};

  /**
   * Pages which are meant to behave like modal dialogs.
   * @protected
   */
  OptionsPage.registeredOverlayPages = {};

  /**
   * Whether or not |initialize| has been called.
   * @private
   */
  OptionsPage.initialized_ = false;

  /**
   * Shows a registered page. This handles both top-level pages and sub-pages.
   * @param {string} pageName Page name.
   */
  OptionsPage.showPageByName = function(pageName) {
    // Notify main pages if they will be hidden.
    for (var name in this.registeredPages) {
      var page = this.registeredPages[name];
      if (name != pageName && page.willHidePage)
        page.willHidePage();
    }

    // Update the visibility attribute for main pages.
    for (var name in this.registeredPages) {
      var page = this.registeredPages[name];
      page.visible = name == pageName;
    }

    // Update the visibility attribute for sub-pages.
    for (var name in this.registeredSubPages) {
      var pageInfo = this.registeredSubPages[name];
      var match = name == pageName;
      if (match && document.documentElement.getAttribute('hide-menu') != 'true')
        pageInfo.parentPage.visible = true;
      pageInfo.page.visible = match;
    }

    // Notify main pages if they were shown.
    for (var name in this.registeredPages) {
      var page = this.registeredPages[name];
      if (name == pageName && page.didShowPage)
        page.didShowPage();
    }
  };

  /**
   * Called on load. Dispatch the URL hash to the given page's handleHash
   * function.
   * @param {string} pageName The string name of the (registered) options page.
   * @param {string} hash The value of the hash component of the URL.
   */
  OptionsPage.handleHashForPage = function(pageName, hash) {
    var page = this.registeredPages[pageName];
    if (!page) {
      page = this.registeredSubPages[pageName].page;
    }
    page.handleHash(hash);
  };

  /**
   * Shows a registered Overlay page.
   * @param {string} overlayName Page name.
   */
  OptionsPage.showOverlay = function(overlayName) {
    if (this.registeredOverlayPages[overlayName]) {
      this.registeredOverlayPages[overlayName].visible = true;
    }
  };

  /**
   * Clears overlays (i.e. hide all overlays).
   */
  OptionsPage.clearOverlays = function() {
     for (var name in this.registeredOverlayPages) {
       var page = this.registeredOverlayPages[name];
       page.visible = false;
     }
  };

  /**
   * Handle 'keydown' events.
   * @param {Event} e Key event.
   * @private
   */
  OptionsPage.onKeyDown_ = function(e) {
    if (e.keyCode == 27) { // Esc
      this.clearOverlays();
    }
  };

  /**
   * Closes any currently-open subpage.
   */
  OptionsPage.closeSubPage = function() {
    for (var name in this.registeredSubPages) {
      var pageInfo = this.registeredSubPages[name];
      if (pageInfo.page.visible) {
        pageInfo.page.visible = false;
        // Since the managed pref banner lives outside the overlay, and the
        // parent is not changing visibility, update the banner explicitly.
        pageInfo.parentPage.updateManagedBannerVisibility();
      }
    }
  };

  /**
  * Shows the tab contents for the given navigation tab.
  * @param {!Element} tab The tab that the user clicked.
  */
  OptionsPage.showTab = function(tab) {
    // Search parents until we find a tab, or the nav bar itself. This allows
    // tabs to have child nodes, e.g. labels in separately-styled spans.
    while (tab && !tab.classList.contains('subpages-nav-tabs') &&
           !tab.classList.contains('inactive-tab')) {
      tab = tab.parentNode;
    }
    if (!tab || !tab.classList.contains('inactive-tab'))
      return;

    if (this.activeNavTab != null) {
      this.activeNavTab.classList.remove('active-tab');
      $(this.activeNavTab.getAttribute('tab-contents')).classList.
          remove('active-tab-contents');
    }

    tab.classList.add('active-tab');
    $(tab.getAttribute('tab-contents')).classList.add('active-tab-contents');
    this.activeNavTab = tab;
  };

  /**
   * Registers new options page.
   * @param {OptionsPage} page Page to register.
   */
  OptionsPage.register = function(page) {
    this.registeredPages[page.name] = page;
    // Create and add new page <li> element to navbar.
    var pageNav = document.createElement('li');
    pageNav.id = page.name + 'PageNav';
    pageNav.className = 'navbar-item';
    pageNav.setAttribute('pageName', page.name);
    pageNav.textContent = page.title;
    pageNav.tabIndex = 0;
    pageNav.onclick = function(event) {
      OptionsPage.showPageByName(this.getAttribute('pageName'));
    };
    pageNav.onkeypress = function(event) {
      // Enter or space
      if (event.keyCode == 13 || event.keyCode == 32) {
        OptionsPage.showPageByName(this.getAttribute('pageName'));
      }
    };
    var navbar = $('navbar');
    navbar.appendChild(pageNav);
    page.tab = pageNav;
    page.initializePage();
  };

  /**
   * Registers a new Sub tab page.
   * @param {OptionsPage} page Page to register.
   */
  OptionsPage.registerSubPage = function(subPage, parentPage) {
    this.registeredSubPages[subPage.name] = {
        page: subPage, parentPage: parentPage };
    subPage.tab = undefined;
    subPage.isSubPageSheet = true;
    subPage.initializePage();
  };

  /**
   * Registers a new Overlay page.
   * @param {OptionsPage} page Page to register, must be a class derived from
   * OptionsPage.
   */
  OptionsPage.registerOverlay = function(page) {
    this.registeredOverlayPages[page.name] = page;
    page.tab = undefined;
    page.isOverlay = true;
    page.initializePage();
  };

  /**
   * Callback for window.onpopstate.
   * @param {Object} data State data pushed into history.
   */
  OptionsPage.setState = function(data) {
    if (data && data.pageName) {
      this.showPageByName(data.pageName);
    }
  };

  /**
   * Initializes the complete options page.  This will cause
   * all C++ handlers to be invoked to do final setup.
   */
  OptionsPage.initialize = function() {
    chrome.send('coreOptionsInitialize');
    this.initialized_ = true;

    // Set up the overlay sheet. Clicks on the visible part of the parent page
    // should close the overlay, not fall through to the parent page.
    var self = this;
    var subpageContainer = $('subpage-sheet-container');
    subpageContainer.onclick = function(event) {
      if (!$('subpage-sheet').contains(event.target))
        self.closeSubPage();
      event.stopPropagation();
    }
    subpageContainer.onkeydown = function(e) {
      if (e.keyCode == 27)  // Esc
        self.closeSubPage();
    };
  };

  /**
   * Re-initializes the C++ handlers if necessary. This is called if the
   * handlers are torn down and recreated but the DOM may not have been (in
   * which case |initialize| won't be called again). If |initialize| hasn't been
   * called, this does nothing (since it will be later, once the DOM has
   * finished loading).
   */
  OptionsPage.reinitializeCore = function() {
    if (this.initialized_)
      chrome.send('coreOptionsInitialize');
  }

  OptionsPage.prototype = {
    __proto__: cr.EventTarget.prototype,

    /**
     * Initializes page content.
     */
    initializePage: function() {},

    /**
     * Sets managed banner visibility state.
     */
    setManagedBannerVisibility: function(visible) {
      this.managed = visible;
      if (this.visible) {
        this.updateManagedBannerVisibility();
      }
    },

    /**
     * Updates managed banner visibility state.
     */
    updateManagedBannerVisibility: function() {
      if (this.managed) {
        $('managed-prefs-banner').classList.remove('hidden');
      } else {
        $('managed-prefs-banner').classList.add('hidden');
      }
    },

    /**
     * Gets page visibility state.
     */
    get visible() {
      var page = $(this.pageDivName);
      return page && page.ownerDocument.defaultView.getComputedStyle(
          page).display == 'block';
    },

    /**
     * Sets page visibility.
     */
    set visible(visible) {
      if ((this.visible && visible) || (!this.visible && !visible))
        return;

      if (visible) {
        this.pageDiv.classList.remove('hidden');
        if (this.isOverlay) {
          $('overlay').classList.remove('hidden');
          document.addEventListener('keydown', OptionsPage.onKeyDown_);
        } else {
          if (this.isSubPageSheet)
            $('subpage-sheet-container').classList.remove('hidden');

          this.updateManagedBannerVisibility();

          // Recent webkit change no longer allows url change from "chrome://".
          window.history.pushState({pageName: this.name}, this.title);
        }
        if (this.tab) {
          this.tab.classList.add('navbar-item-selected');
        }
      } else {
        this.pageDiv.classList.add('hidden');
        if (this.isOverlay) {
          $('overlay').classList.add('hidden');
          document.removeEventListener('keydown', OptionsPage.onKeyDown_);
        } else if (this.isSubPageSheet) {
          $('subpage-sheet-container').classList.add('hidden');
        }
        if (this.tab) {
          this.tab.classList.remove('navbar-item-selected');
        }
      }

      cr.dispatchPropertyChange(this, 'visible', visible, !visible);
    },

    /**
     * Handles a hash value in the URL (such as bar in
     * chrome://options/foo#bar). Called on page load. By default, this shows
     * an overlay that matches the hash name, but can be overriden by individual
     * OptionsPage subclasses to get other behavior.
     * @param {string} hash The hash value.
     */
    handleHash: function(hash) {
      OptionsPage.showOverlay(hash);
    },
  };

  // Export
  return {
    OptionsPage: OptionsPage
  };

});
<|endoftext|>


<commit_before>`use strict`

const db = require('APP/db')
    , {Magnet} = db
    , {expect} = require('chai')

/* global describe it before beforeEach afterEach */

describe('Magnet', () => {
  let testMagnet = {}
  before('Await database sync', () => db.didSync)
  afterEach('Clear the tables', () => db.truncate({ cascade: true }))
  beforeEach(function() {
    testMagnet = {
      quote: 'Many a test has failed',
      price: 3.95,
      image: 'cdn.shopify.com/s/files/1/0273/4903/products/ralph-waldo-emerson-fridge-magnet-1_large.jpg?v=1380467104',
      title: 'Koans about Testing',
      description: 'Amazing magnet with Koans from testing',
      itemNumber: 12345,
      size: [2, 4],
      mood: ['zany', 'moody']
    }
  })

  describe('null not permitted for any field', () => {
    it('throws error if quote is null', () => {
      testMagnet.quote = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: quote cannot be null')
        })
    })
    it('throws error if price is null', () => {
      testMagnet.price = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: price cannot be null')
        })
    })
    it('throws error if image is null', () => {
      testMagnet.image = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: image cannot be null')
        })
    })
    xit('throws error if image is not a URL', () => {
      // testMagnet.quote = null
      // let Magnet.build(testMagnet) = Magnet.build(testMagnet)
      // return Magnet.build(testMagnet).validate()
      //   .then(function(err) {
      //     expect(err).to.exist
      //     expect(err.message).to.equal('notNull Violation: quote cannot be null')
      //   })
    })
    it('throws error if title is null', () => {
      testMagnet.title = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: title cannot be null')
        })
    })
    it('throws error if description is null', () => {
      testMagnet.description = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: description cannot be null')
        })
    })
    it('throws error if itemNumber is null', () => {
      testMagnet.itemNumber = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: itemNumber cannot be null')
        })
    })
    it('throws error if size is null', () => {
      testMagnet.size = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: size cannot be null')
        })
    })
    it('throws error if mood is null', () => {
      testMagnet.mood = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: mood cannot be null')
        })
    })
  })
})
<commit_msg>Added more tests to magnets model file<commit_after>`use strict`

const db = require('APP/db')
    , {Magnet} = db
    , {expect} = require('chai')

/* global describe it before beforeEach afterEach */

describe('Magnet', () => {
  let testMagnet = {}
  before('Await database sync', () => db.didSync)
  afterEach('Clear the tables', () => db.truncate({ cascade: true }))
  beforeEach(function() {
    testMagnet = {
      quote: 'Many a test has failed',
      price: 3.95,
      image: 'cdn.shopify.com/s/files/1/0273/4903/products/ralph-waldo-emerson-fridge-magnet-1_large.jpg?v=1380467104',
      title: 'Koans about Testing',
      description: 'Amazing magnet with Koans from testing',
      itemNumber: 12345,
      size: [2, 4],
      mood: ['zany', 'moody']
    }
  })

  describe('null not permitted for any field', () => {
    it('throws error if quote is null', () => {
      testMagnet.quote = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: quote cannot be null')
        })
    })
    it('throws error if price is null', () => {
      testMagnet.price = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: price cannot be null')
        })
    })
    it('throws error if image is null', () => {
      testMagnet.image = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: image cannot be null')
        })
    })
    // xit('throws error if image is not a URL', () => {
      // testMagnet.quote = null
      // let Magnet.build(testMagnet) = Magnet.build(testMagnet)
      // return Magnet.build(testMagnet).validate()
      //   .then(function(err) {
      //     expect(err).to.exist
      //     expect(err.message).to.equal('notNull Violation: quote cannot be null')
      //   })
    // })
    it('throws error if title is null', () => {
      testMagnet.title = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: title cannot be null')
        })
    })
    it('throws error if description is null', () => {
      testMagnet.description = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: description cannot be null')
        })
    })
    it('throws error if itemNumber is null', () => {
      testMagnet.itemNumber = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: itemNumber cannot be null')
        })
    })
    it('throws error if size is null', () => {
      testMagnet.size = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: size cannot be null')
        })
    })
    it('throws error if mood is null', () => {
      testMagnet.mood = null
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.exist
          expect(err.message).to.equal('notNull Violation: mood cannot be null')
        })
    })
  })
  describe('check types for specific fields', () => {
    it('doesnt create instance if size is an array of string', () => {
      testMagnet.size = ['2', '4']
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.be.null
        })
    })
    it('doesnt create instance if mood is a comma delimited string', () => {
      testMagnet.mood = 'zany, moody'
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.be.null
        })
    })
    it('doesnt create instance if itemNumber is a float', () => {
      testMagnet.itemNumber = 30.96
      return Magnet.build(testMagnet).validate()
        .then(function(err) {
          expect(err).to.be.null
        })
    })
  })
})
<|endoftext|>


<commit_before>"use strict";
var PhotoStreamController = function($scope, $http, analytics) {

	$http({method: "GET", url: "/api/v1/hikes/"}).
		success(function(data, status, headers, config) {
			$scope.hikes = data;
		}).
		error(function(data, status, headers, config) {
		});

	$scope.hikes = [];
};<commit_msg>Remove trailing / from hike getter.<commit_after>"use strict";
var PhotoStreamController = function($scope, $http, analytics) {

	$http({method: "GET", url: "/api/v1/hikes"}).
		success(function(data, status, headers, config) {
			$scope.hikes = data;
		}).
		error(function(data, status, headers, config) {
		});

	$scope.hikes = [];
};<|endoftext|>


<commit_before>/*global define*/
/*jslint nomen: true*/
define([
    'jquery',
    'jquery-ui'
], function ($) {
    'use strict';

    function setValue($elem, value) {
        if ($elem.data('select2')) {
            $elem.select2('val', value);
        } else {
            $elem.val(value);
        }
        $elem.trigger('change');
    }

    $.widget('oroui.itemsManagerEditor', {
        options: {
            namePattern: /^([\w\W]*)$/,
            mapping: {
                /* attrName: elemName */
            },
            addButton: '.add-button',
            saveButton: '.save-button',
            cancelButton: '.cancel-button',
            collection: null,
            setter: function ($el, name, value) {
                return value;
            },
            getter: function ($el, name, value) {
                return value;
            },
            chenged: false
        },

        /**
         * Should return array with validation errors keys
         *
         * @returns {array}
         */
        hasChanges: function () {
            return this.changed;
        },

        _create: function () {
            // turn off global validation on submit form
            this.element.attr('data-validation-ignore', '');
            this.errors = $({});
            this.form = this.element.parents('form');
            this._on(this.form, {
                submit: '_hideErrors'
            });
            if (typeof this.options.namePattern === 'string') {
                this.options.namePattern = new RegExp(this.options.namePattern);
            }

            this.reset();
            this._on({
                change: this._onElementChange,
                click: this._onClick
            });

            this.options.collection.on('action:edit', $.proxy(this._onEditModel, this));
            this.options.collection.on('remove', $.proxy(this._onRemoveModel, this));
        },

        reset: function (model) {
            var elementsMap, attrs,
                self = this;
            this._hideErrors();
            this.validated = false;
            this.model = model;
            if (model) {
                elementsMap = this._elementsMap();
                attrs = model.toJSON();
                $.each(attrs, function (name, value) {
                    var $elem = elementsMap[name];
                    if ($elem) {
                        value = self.options.setter($elem, name, value);
                        setValue($elem, value);
                    }
                });
            } else {
                this._elements().each(function () {
                    setValue($(this), '');
                });
            }
            this._updateActions();
            this.changed = false;
        },

        _onSaveItem: function (e) {
            var attrs, model;
            e.preventDefault();
            if (!this._validate()) {
                return;
            }

            attrs = this._collectAttrs();
            if (this.model) {
                this.model.set(attrs);
            } else {
                model = new (this.options.collection.model)(attrs);
                this.options.collection.add(model);
            }

            this.reset();
        },

        _onEditModel: function (model) {
            this.reset(model);
        },

        _onRemoveModel: function (model) {
            if (this.model === model) {
                this.reset();
            }
        },

        _onCancel: function (e) {
            e.preventDefault();
            this.reset();
        },

        _validate: function (elem) {
            var validator = this._getValidator(),
                result = true;
            if (validator) {
                this.element.removeAttr('data-validation-ignore');
                if (elem) {
                    result = validator.element(elem);
                } else {
                    $.each(this._elements(), function () {
                        result = validator.element(this) && result;
                    });
                    this.validated = true;
                }
                this.errors = validator.toShow;
                this.element.attr('data-validation-ignore', '');
            }
            return result;
        },

        _hideErrors: function () {
            var validator = this._getValidator();
            if (validator) {
                this._elements().each(function () {
                    validator.settings.unhighlight(this);
                });
                this.errors.hide();
            }
        },

        _getValidator: function () {
            var validator;
            if (this.form.data('validator')) {
                validator = this.form.validate();
            }
            return validator;
        },

        _elements: function () {
            return this.element.find('input, select, textarea')
                .not(':submit, :reset, :image');
        },

        _onElementChange: function (e) {
            this.changed = true;
            if (this.validated) {
                this._validate(e.target);
            }
        },

        _onClick: function (e) {
            var $target = $(e.target);
            if ($target.is(this.options.addButton) || $target.is(this.options.saveButton)) {
                this._onSaveItem(e);
            } else if ($target.is(this.options.cancelButton)) {
                this._onCancel(e);
            }
        },

        _collectAttrs: function () {
            var arrts = {},
                self = this;

            $.each(this._elementsMap(), function (name, $elem) {
                arrts[name] = self.options.getter($elem, name, $elem.val());
            });

            return arrts;
        },

        _elementsMap: function () {
            var mapped,
                elementsMap = {},
                $container = this.element,
                pattern = this.options.namePattern;

            // collect elements using map
            $.each(this.options.mapping, function (attrName, elemName) {
                var $elem = $container.find('[name="' + elemName + '"]');
                if ($elem.length) {
                    elementsMap[attrName] = $elem;
                }
            });

            mapped = $.map(elementsMap, function ($elem) {
                return $elem[0];
            });

            // collect elements using name pattern
            $.each(this._elements().not(mapped), function () {
                var name = this.name && (this.name.match(pattern) || [])[1];
                if (name && !elementsMap[name]) {
                    elementsMap[name] = $(this);
                }
            });
            return elementsMap;
        },

        _updateActions: function () {
            this.element.find(this.options.addButton)[this.model ? 'hide' : 'show']();
            this.element.find(this.options.saveButton)[this.model ? 'show' : 'hide']();
        }
    });

    return $;
});
<commit_msg>CRM-1196 chosen column dissapear from query designer<commit_after>/*global define*/
/*jslint nomen: true*/
define([
    'jquery',
    'jquery-ui'
], function ($) {
    'use strict';

    function setValue($elem, value) {
        if ($elem.data('select2')) {
            $elem.select2('val', value);
        } else {
            $elem.val(value);
        }
        $elem.trigger('change');
    }

    $.widget('oroui.itemsManagerEditor', {
        options: {
            namePattern: /^([\w\W]*)$/,
            mapping: {
                /* attrName: elemName */
            },
            addButton: '.add-button',
            saveButton: '.save-button',
            cancelButton: '.cancel-button',
            collection: null,
            setter: function ($el, name, value) {
                return value;
            },
            getter: function ($el, name, value) {
                return value;
            },
            changed: false
        },

        /**
         * Is this component changed by user
         *
         * @returns {boolean}
         */
        hasChanges: function () {
            return this.changed;
        },

        _create: function () {
            // turn off global validation on submit form
            this.element.attr('data-validation-ignore', '');
            this.errors = $({});
            this.form = this.element.parents('form');
            this._on(this.form, {
                submit: '_hideErrors'
            });
            if (typeof this.options.namePattern === 'string') {
                this.options.namePattern = new RegExp(this.options.namePattern);
            }

            this.reset();
            this._on({
                change: this._onElementChange,
                click: this._onClick
            });

            this.options.collection.on('action:edit', $.proxy(this._onEditModel, this));
            this.options.collection.on('remove', $.proxy(this._onRemoveModel, this));
        },

        reset: function (model) {
            var elementsMap, attrs,
                self = this;
            this._hideErrors();
            this.validated = false;
            this.model = model;
            if (model) {
                elementsMap = this._elementsMap();
                attrs = model.toJSON();
                $.each(attrs, function (name, value) {
                    var $elem = elementsMap[name];
                    if ($elem) {
                        value = self.options.setter($elem, name, value);
                        setValue($elem, value);
                    }
                });
            } else {
                this._elements().each(function () {
                    setValue($(this), '');
                });
            }
            this._updateActions();
            this.changed = false;
        },

        _onSaveItem: function (e) {
            var attrs, model;
            e.preventDefault();
            if (!this._validate()) {
                return;
            }

            attrs = this._collectAttrs();
            if (this.model) {
                this.model.set(attrs);
            } else {
                model = new (this.options.collection.model)(attrs);
                this.options.collection.add(model);
            }

            this.reset();
        },

        _onEditModel: function (model) {
            this.reset(model);
        },

        _onRemoveModel: function (model) {
            if (this.model === model) {
                this.reset();
            }
        },

        _onCancel: function (e) {
            e.preventDefault();
            this.reset();
        },

        _validate: function (elem) {
            var validator = this._getValidator(),
                result = true;
            if (validator) {
                this.element.removeAttr('data-validation-ignore');
                if (elem) {
                    result = validator.element(elem);
                } else {
                    $.each(this._elements(), function () {
                        result = validator.element(this) && result;
                    });
                    this.validated = true;
                }
                this.errors = validator.toShow;
                this.element.attr('data-validation-ignore', '');
            }
            return result;
        },

        _hideErrors: function () {
            var validator = this._getValidator();
            if (validator) {
                this._elements().each(function () {
                    validator.settings.unhighlight(this);
                });
                this.errors.hide();
            }
        },

        _getValidator: function () {
            var validator;
            if (this.form.data('validator')) {
                validator = this.form.validate();
            }
            return validator;
        },

        _elements: function () {
            return this.element.find('input, select, textarea')
                .not(':submit, :reset, :image');
        },

        _onElementChange: function (e) {
            this.changed = true;
            if (this.validated) {
                this._validate(e.target);
            }
        },

        _onClick: function (e) {
            var $target = $(e.target);
            if ($target.is(this.options.addButton) || $target.is(this.options.saveButton)) {
                this._onSaveItem(e);
            } else if ($target.is(this.options.cancelButton)) {
                this._onCancel(e);
            }
        },

        _collectAttrs: function () {
            var arrts = {},
                self = this;

            $.each(this._elementsMap(), function (name, $elem) {
                arrts[name] = self.options.getter($elem, name, $elem.val());
            });

            return arrts;
        },

        _elementsMap: function () {
            var mapped,
                elementsMap = {},
                $container = this.element,
                pattern = this.options.namePattern;

            // collect elements using map
            $.each(this.options.mapping, function (attrName, elemName) {
                var $elem = $container.find('[name="' + elemName + '"]');
                if ($elem.length) {
                    elementsMap[attrName] = $elem;
                }
            });

            mapped = $.map(elementsMap, function ($elem) {
                return $elem[0];
            });

            // collect elements using name pattern
            $.each(this._elements().not(mapped), function () {
                var name = this.name && (this.name.match(pattern) || [])[1];
                if (name && !elementsMap[name]) {
                    elementsMap[name] = $(this);
                }
            });
            return elementsMap;
        },

        _updateActions: function () {
            this.element.find(this.options.addButton)[this.model ? 'hide' : 'show']();
            this.element.find(this.options.saveButton)[this.model ? 'show' : 'hide']();
        }
    });

    return $;
});
<|endoftext|>


<commit_before>/*global define*/
/*jslint nomen: true*/
define(['jquery', 'jquery-ui'],   function ($) {
    'use strict';

    function setValue($elem, value) {
        if ($elem.data('select2')) {
            $elem.select2('val', value);
        } else {
            $elem.val(value);
        }
        $elem.trigger('change');
    }

    $.widget('oroui.itemsManagerEditor', {
        options: {
            namePattern: /^([\w\W]*)$/,
            mapping: {
                /* attrName: elemName */
            },
            addButton: '.add-button',
            saveButton: '.save-button',
            cancelButton: '.cancel-button',
            collection: null,
            setter: function ($el, name, value) {
                return value;
            },
            getter: function ($el, name, value) {
                return value;
            }
        },

        _create: function () {
            // turn off global validation on submit form
            this.element.attr('data-validation-ignore', '');
            this.errors = $({});
            this.form = this.element.parents('form');
            this.form.on('submit', $.proxy(this._hideErrors, this));
            if (typeof this.options.namePattern === 'string') {
                this.options.namePattern = new RegExp(this.options.namePattern);
            }

            this.reset();
            this._on({
                change: this._onElementChange,
                click: this._onClick
            });

            this.options.collection.on('action:edit', $.proxy(this._onEditModel, this));
            this.options.collection.on('remove', $.proxy(this._onRemoveModel, this));
        },

        reset: function (model) {
            var elementsMap, attrs,
                self = this;
            this._hideErrors();
            this.validated = false;
            this.model = model;
            if (model) {
                elementsMap = this._elementsMap();
                attrs = model.toJSON();
                $.each(attrs, function (name, value) {
                    var $elem = elementsMap[name];
                    if ($elem) {
                        value = self.options.setter($elem, name, value);
                        setValue($elem, value);
                    }
                });
            } else {
                this._elements().each(function () {
                    setValue($(this), '');
                });
            }
            this._updateActions();
        },

        _onSaveItem: function (e) {
            var attrs, model;
            e.preventDefault();
            if (!this._validate()) {
                return;
            }

            attrs = this._collectAttrs();
            if (this.model) {
                this.model.set(attrs);
            } else {
                model = new (this.options.collection.model)(attrs);
                this.options.collection.add(model);
            }

            this.reset();
        },

        _onEditModel: function (model) {
            this.reset(model);
        },

        _onRemoveModel: function (model) {
            if (this.model === model) {
                this.reset();
            }
        },

        _onCancel: function (e) {
            e.preventDefault();
            this.reset();
        },

        _validate: function (elem) {
            var validator = this._getValidator(),
                result = true;
            if (validator) {
                this.element.removeAttr('data-validation-ignore');
                if (elem) {
                    result = validator.element(elem);
                } else {
                    $.each(this._elements(), function () {
                        result = validator.element(this) && result;
                    });
                    this.validated = true;
                }
                this.errors = validator.toShow;
                this.element.attr('data-validation-ignore', '');
            }
            return result;
        },

        _hideErrors: function () {
            var validator = this._getValidator();
            if (validator) {
                this._elements().each(function () {
                    validator.settings.unhighlight(this);
                });
                this.errors.hide();
            }
        },

        _getValidator: function () {
            var validator;
            if (this.form.data('validator')) {
                validator = this.form.validate();
            }
            return validator;
        },

        _elements: function () {
            return this.element.find('input, select, textarea')
                .not(':submit, :reset, :image');
        },

        _onElementChange: function (e) {
            if (this.validated) {
                this._validate(e.target);
            }
        },

        _onClick: function (e) {
            var $target = $(e.target);
            if ($target.is(this.options.addButton) || $target.is(this.options.saveButton)) {
                this._onSaveItem(e);
            } else if ($target.is(this.options.cancelButton)) {
                this._onCancel(e);
            }
        },

        _collectAttrs: function () {
            var arrts = {},
                self = this;

            $.each(this._elementsMap(), function (name, $elem) {
                arrts[name] = self.options.getter($elem, name, $elem.val());
            });

            return arrts;
        },

        _elementsMap: function () {
            var elementsMap = {},
                $container = this.element,
                pattern = this.options.namePattern;

            // collect elements using map
            $.each(this.options.mapping, function (attrName, elemName) {
                var $elem = $container.find('[name="' + elemName + '"]');
                if ($elem.length) {
                    elementsMap[attrName] = $elem;
                }
            });

            // collect elements using name pattern
            $.each(this._elements(), function () {
                var name = this.name && (this.name.match(pattern) || [])[1];
                if (name && !elementsMap[name]) {
                    elementsMap[name] = $(this);
                }
            });
            return elementsMap;
        },

        _updateActions: function () {
            this.element.find(this.options.addButton)[this.model ? 'hide' : 'show']();
            this.element.find(this.options.saveButton)[this.model ? 'show' : 'hide']();
        }
    });

    return $;
});
<commit_msg>CRM-1786: Custom Report "Leads by Geography" doesn't open properly for editing<commit_after>/*global define*/
/*jslint nomen: true*/
define([
    'jquery',
    'jquery-ui'
], function ($) {
    'use strict';

    function setValue($elem, value) {
        if ($elem.data('select2')) {
            $elem.select2('val', value);
        } else {
            $elem.val(value);
        }
        $elem.trigger('change');
    }

    $.widget('oroui.itemsManagerEditor', {
        options: {
            namePattern: /^([\w\W]*)$/,
            mapping: {
                /* attrName: elemName */
            },
            addButton: '.add-button',
            saveButton: '.save-button',
            cancelButton: '.cancel-button',
            collection: null,
            setter: function ($el, name, value) {
                return value;
            },
            getter: function ($el, name, value) {
                return value;
            }
        },

        _create: function () {
            // turn off global validation on submit form
            this.element.attr('data-validation-ignore', '');
            this.errors = $({});
            this.form = this.element.parents('form');
            this.form.on('submit', $.proxy(this._hideErrors, this));
            if (typeof this.options.namePattern === 'string') {
                this.options.namePattern = new RegExp(this.options.namePattern);
            }

            this.reset();
            this._on({
                change: this._onElementChange,
                click: this._onClick
            });

            this.options.collection.on('action:edit', $.proxy(this._onEditModel, this));
            this.options.collection.on('remove', $.proxy(this._onRemoveModel, this));
        },

        reset: function (model) {
            var elementsMap, attrs,
                self = this;
            this._hideErrors();
            this.validated = false;
            this.model = model;
            if (model) {
                elementsMap = this._elementsMap();
                attrs = model.toJSON();
                $.each(attrs, function (name, value) {
                    var $elem = elementsMap[name];
                    if ($elem) {
                        value = self.options.setter($elem, name, value);
                        setValue($elem, value);
                    }
                });
            } else {
                this._elements().each(function () {
                    setValue($(this), '');
                });
            }
            this._updateActions();
        },

        _onSaveItem: function (e) {
            var attrs, model;
            e.preventDefault();
            if (!this._validate()) {
                return;
            }

            attrs = this._collectAttrs();
            if (this.model) {
                this.model.set(attrs);
            } else {
                model = new (this.options.collection.model)(attrs);
                this.options.collection.add(model);
            }

            this.reset();
        },

        _onEditModel: function (model) {
            this.reset(model);
        },

        _onRemoveModel: function (model) {
            if (this.model === model) {
                this.reset();
            }
        },

        _onCancel: function (e) {
            e.preventDefault();
            this.reset();
        },

        _validate: function (elem) {
            var validator = this._getValidator(),
                result = true;
            if (validator) {
                this.element.removeAttr('data-validation-ignore');
                if (elem) {
                    result = validator.element(elem);
                } else {
                    $.each(this._elements(), function () {
                        result = validator.element(this) && result;
                    });
                    this.validated = true;
                }
                this.errors = validator.toShow;
                this.element.attr('data-validation-ignore', '');
            }
            return result;
        },

        _hideErrors: function () {
            var validator = this._getValidator();
            if (validator) {
                this._elements().each(function () {
                    validator.settings.unhighlight(this);
                });
                this.errors.hide();
            }
        },

        _getValidator: function () {
            var validator;
            if (this.form.data('validator')) {
                validator = this.form.validate();
            }
            return validator;
        },

        _elements: function () {
            return this.element.find('input, select, textarea')
                .not(':submit, :reset, :image');
        },

        _onElementChange: function (e) {
            if (this.validated) {
                this._validate(e.target);
            }
        },

        _onClick: function (e) {
            var $target = $(e.target);
            if ($target.is(this.options.addButton) || $target.is(this.options.saveButton)) {
                this._onSaveItem(e);
            } else if ($target.is(this.options.cancelButton)) {
                this._onCancel(e);
            }
        },

        _collectAttrs: function () {
            var arrts = {},
                self = this;

            $.each(this._elementsMap(), function (name, $elem) {
                arrts[name] = self.options.getter($elem, name, $elem.val());
            });

            return arrts;
        },

        _elementsMap: function () {
            var mapped,
                elementsMap = {},
                $container = this.element,
                pattern = this.options.namePattern;

            // collect elements using map
            $.each(this.options.mapping, function (attrName, elemName) {
                var $elem = $container.find('[name="' + elemName + '"]');
                if ($elem.length) {
                    elementsMap[attrName] = $elem;
                }
            });

            mapped = $.map(elementsMap, function ($elem) {
                return $elem[0];
            });

            // collect elements using name pattern
            $.each(this._elements().not(mapped), function () {
                var name = this.name && (this.name.match(pattern) || [])[1];
                if (name && !elementsMap[name]) {
                    elementsMap[name] = $(this);
                }
            });
            return elementsMap;
        },

        _updateActions: function () {
            this.element.find(this.options.addButton)[this.model ? 'hide' : 'show']();
            this.element.find(this.options.saveButton)[this.model ? 'show' : 'hide']();
        }
    });

    return $;
});
<|endoftext|>


<commit_before>import React from 'react';
import Analyzer from 'Parser/Core/Analyzer';
import SPELLS from 'common/SPELLS/index';
import SpellIcon from 'common/SpellIcon';
import { formatNumber } from 'common/format';
import StatisticBox, { STATISTIC_ORDER } from 'Interface/Others/StatisticBox';
import calculateEffectiveDamage from 'Parser/Core/calculateEffectiveDamage';

const PERCENT_BUFF = 0.20;

//WCL: https://www.warcraftlogs.com/reports/JxyY7HCDcjqMA9tf/#fight=1&source=15
class AgonizingFlames extends Analyzer {

  damage = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.AGONIZING_FLAMES_TALENT.id);
  }

  on_byPlayer_damage(event) {
    const spellID = event.ability.guid;
    if (spellID !== SPELLS.IMMOLATION_AURA_FIRST_STRIKE.id && spellID !== SPELLS.IMMOLATION_AURA_BUFF.id) {
      return;
    }
        this.damage += calculateEffectiveDamage(event, PERCENT_BUFF);
    }

  statistic() {
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.AGONIZING_FLAMES_TALENT.id} />}
        value={`${this.owner.formatItemDamageDone(this.damage)}`}
        label="Agonizing Flames"
        tooltip={`This shows the extra dps that the talent provides.

                  Total extra damage: ${formatNumber(this.damage)}`}
      />
    );
  }
  statisticOrder = STATISTIC_ORDER.CORE(7);
}

export default AgonizingFlames;
<commit_msg>updated statistic order<commit_after>import React from 'react';
import Analyzer from 'Parser/Core/Analyzer';
import SPELLS from 'common/SPELLS/index';
import SpellIcon from 'common/SpellIcon';
import { formatNumber } from 'common/format';
import StatisticBox, { STATISTIC_ORDER } from 'Interface/Others/StatisticBox';
import calculateEffectiveDamage from 'Parser/Core/calculateEffectiveDamage';

const PERCENT_BUFF = 0.20;

//WCL: https://www.warcraftlogs.com/reports/JxyY7HCDcjqMA9tf/#fight=1&source=15
class AgonizingFlames extends Analyzer {

  damage = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.AGONIZING_FLAMES_TALENT.id);
  }

  on_byPlayer_damage(event) {
    const spellID = event.ability.guid;
    if (spellID !== SPELLS.IMMOLATION_AURA_FIRST_STRIKE.id && spellID !== SPELLS.IMMOLATION_AURA_BUFF.id) {
      return;
    }
        this.damage += calculateEffectiveDamage(event, PERCENT_BUFF);
    }

  statistic() {
    return (
      <StatisticBox
        position={STATISTIC_ORDER.CORE(9)}
        icon={<SpellIcon id={SPELLS.AGONIZING_FLAMES_TALENT.id} />}
        value={`${this.owner.formatItemDamageDone(this.damage)}`}
        label="Agonizing Flames"
        tooltip={`This shows the extra dps that the talent provides.

                  Total extra damage: ${formatNumber(this.damage)}`}
      />
    );
  }
}

export default AgonizingFlames;
<|endoftext|>


<commit_before>"use strict";

import React from "react";

import Icon from "./Icon.js";

import NowPlayingActions from "../actions/NowPlayingActions.js";
import NowPlayingStore from "../stores/NowPlayingStore.js";
import NowPlaying from "./NowPlaying.js";

import PlayProgress from "./PlayProgress.js";
import Volume from "./Volume.js";

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

import PlayingStatusStore from "../stores/PlayingStatusStore.js";

import RightColumnStore from "../stores/RightColumnStore.js";
import RightColumnActions from "../actions/RightColumnActions.js";

var BACKWARD_TIMEOUT = 2000;

export default class Bottom extends React.Component {
  render() {
    return (

        <PlayProgress/>

          <NowPlaying />
          <Controls />

            <Volume />
            <RightColumnToggle />

    );
  }
}

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

    this._onClick = this._onClick.bind(this);
  }

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

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

  render() {
    return (

        <Icon icon="queue_music"onClick={this._onClick} />

    );
  }

  _onChange() {
  }

  _onClick() {
    RightColumnActions.toggle();
  }
}

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

    this.state = {
      playing: NowPlayingStore.getPlaying(),
      canNext: PlaylistStore.canNext(),
      canPrev: PlaylistStore.canPrev(),
    };

    this._onChangePlaylist = this._onChangePlaylist.bind(this);
    this._onChange = this._onChange.bind(this);
    this._togglePlayPause = this._togglePlayPause.bind(this);
    this._onBackward = this._onBackward.bind(this);
  }

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

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

  render() {
    var prevClasses = {"skip": true, "enabled": this.state.canPrev};
    var nextClasses = {"skip": true, "enabled": this.state.canNext};
    return (

        <Icon icon="skip_previous"extraClasses={prevClasses} onClick={this._onBackward} />
        <Icon icon={this.state.playing ? "pause_circle_filled" : "play_circle_filled"}extraClasses={{"play-pause": true}} onClick={this._togglePlayPause} />
        <Icon icon="skip_next"extraClasses={nextClasses} onClick={this._onForward} />

    );
  }

  _onChangePlaylist() {
    this.setState({
      canNext: PlaylistStore.canNext(),
      canPrev: PlaylistStore.canPrev(),
    });
  }

  _onChange() {
    this.setState({playing: NowPlayingStore.getPlaying()});

    var favicon = document.querySelector("head link[rel=\"shortcut icon\"]");
    var currentTrack = NowPlayingStore.getTrack();
    if (currentTrack === null) {
      document.title = "tchaik";
      return;
    }
    document.title = currentTrack.Name;
    favicon.href = `/icon/${currentTrack.ID}`;
  }

  _togglePlayPause() {
    NowPlayingActions.playing(!this.state.playing);
    this.setState({
      playing: !this.state.playing,
    });
  }

  _backButtonTimerRunning() {
    if (this._backButtonTimer) {
      return true;
    }
    return false;
  }

  _backButtonTimerStart() {
    if (this._backButtonTimer) {
      clearTimeout(this._backButtonTimer);
    }
    this._backButtonTimer = setTimeout(this._backButtonTimerTimeout, BACKWARD_TIMEOUT);
  }

  _backButtonTimerTimeout() {
    this._backButtonTimer = null;
  }

  _prev() {
    PlaylistActions.prev();
  }

  _onBackward() {
    if (this._backButtonTimerRunning()) {
      PlaylistActions.prev();
    } else if (this.state.playing || PlayingStatusStore.getTime() > 0) {
      NowPlayingActions.setCurrentTime(0);
    } else {
      PlaylistActions.prev();
    }
    this._backButtonTimerStart();
    return;
  }

  _onForward() {
    PlaylistActions.next();
  }

}
<commit_msg>Fix binding to `this` for onForward.<commit_after>"use strict";

import React from "react";

import Icon from "./Icon.js";

import NowPlayingActions from "../actions/NowPlayingActions.js";
import NowPlayingStore from "../stores/NowPlayingStore.js";
import NowPlaying from "./NowPlaying.js";

import PlayProgress from "./PlayProgress.js";
import Volume from "./Volume.js";

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

import PlayingStatusStore from "../stores/PlayingStatusStore.js";

import RightColumnStore from "../stores/RightColumnStore.js";
import RightColumnActions from "../actions/RightColumnActions.js";

var BACKWARD_TIMEOUT = 2000;

export default class Bottom extends React.Component {
  render() {
    return (

        <PlayProgress/>

          <NowPlaying />
          <Controls />

            <Volume />
            <RightColumnToggle />

    );
  }
}

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

    this._onClick = this._onClick.bind(this);
  }

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

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

  render() {
    return (

        <Icon icon="queue_music"onClick={this._onClick} />

    );
  }

  _onChange() {
  }

  _onClick() {
    RightColumnActions.toggle();
  }
}

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

    this.state = {
      playing: NowPlayingStore.getPlaying(),
      canNext: PlaylistStore.canNext(),
      canPrev: PlaylistStore.canPrev(),
    };

    this._onChangePlaylist = this._onChangePlaylist.bind(this);
    this._onChange = this._onChange.bind(this);
    this._togglePlayPause = this._togglePlayPause.bind(this);
    this._onBackward = this._onBackward.bind(this);
    this._onForward = this._onForward.bind(this);
  }

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

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

  render() {
    var prevClasses = {"skip": true, "enabled": this.state.canPrev};
    var nextClasses = {"skip": true, "enabled": this.state.canNext};
    return (

        <Icon icon="skip_previous"extraClasses={prevClasses} onClick={this._onBackward} />
        <Icon icon={this.state.playing ? "pause_circle_filled" : "play_circle_filled"}extraClasses={{"play-pause": true}} onClick={this._togglePlayPause} />
        <Icon icon="skip_next"extraClasses={nextClasses} onClick={this._onForward} />

    );
  }

  _onChangePlaylist() {
    this.setState({
      canNext: PlaylistStore.canNext(),
      canPrev: PlaylistStore.canPrev(),
    });
  }

  _onChange() {
    this.setState({playing: NowPlayingStore.getPlaying()});

    var favicon = document.querySelector("head link[rel=\"shortcut icon\"]");
    var currentTrack = NowPlayingStore.getTrack();
    if (currentTrack === null) {
      document.title = "tchaik";
      return;
    }
    document.title = currentTrack.Name;
    favicon.href = `/icon/${currentTrack.ID}`;
  }

  _togglePlayPause() {
    NowPlayingActions.playing(!this.state.playing);
    this.setState({
      playing: !this.state.playing,
    });
  }

  _backButtonTimerRunning() {
    if (this._backButtonTimer) {
      return true;
    }
    return false;
  }

  _backButtonTimerStart() {
    if (this._backButtonTimer) {
      clearTimeout(this._backButtonTimer);
    }
    this._backButtonTimer = setTimeout(this._backButtonTimerTimeout, BACKWARD_TIMEOUT);
  }

  _backButtonTimerTimeout() {
    this._backButtonTimer = null;
  }

  _prev() {
    PlaylistActions.prev();
  }

  _onBackward() {
    if (this._backButtonTimerRunning()) {
      PlaylistActions.prev();
    } else if (this.state.playing || PlayingStatusStore.getTime() > 0) {
      NowPlayingActions.setCurrentTime(0);
    } else {
      PlaylistActions.prev();
    }
    this._backButtonTimerStart();
    return;
  }

  _onForward() {
    PlaylistActions.next();
  }

}
<|endoftext|>


<commit_before>angular
    .module('app', [
        'apiResponse',
        'unsavedNew',
        'uiHelpers',
        'ui.validate',
        'ui.mask',
        'ui.if',
        'ui.bootstrap',
        'ngCookies',
        'angular-markdown',
        'mb.spinner',
        'ajoslin.promise-tracker',
        'angulartics',
        'angulartics.google.analytics',
        'google-maps',
        'truncate',
        'ui.select2'
    ])

/**
 * Configure angular app
 *
 * @note we dont yet have access to $rootScope, and a few other things
 *
 */
.config([
    '$httpProvider',
    '$compileProvider',
    function(
        $httpProvider,
        $compileProvider,
        promiseTracker
    ) {

        /**
         * Standard CORS Configuration
         *
         */
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];

        /**
         * Configure ngSanitize directive
         * Here we add 'mailto' 'callto' etc. which prevents links with href='mailto:' from
         * being flagged as 'unsafe' by angular sanitizer
         *
         */
        $compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel|callto):/);

    }
])

/**
 * Define constants using Angulars .constant() method
 *
 * @note you need to adjust base_url when developing locally. Don't commit any changes to this since
 *       master is setup alreay to work with heroku
 *
 */
.constant('MARLINAPI_CONFIG', {
    //base_url: 'http://marlinquoter.herokuapp.com/api/v1/'
    //base_url: 'http://localhost:3000/api/v1/'
    //base_url: 'http://0.0.0.0:3000/api/v1/'
    base_url: 'http://127.0.0.1:3000/api/v1/'
    //base_url: 'http://10.1.10.48:3000/api/v1/'
})

/**
 * Define routes
 *
 * @note for this app we set all routes here in the app file. An alternate (any maybe more modular)
 *       is to set routes in the controllers as needed.
 *
 */
.config(['$routeProvider',
    function($router) {

        $router

        // general routes
        .when('/', {
            controller: 'homeController',
            templateUrl: 'app/templates/home.html'
        })

        .when('/changelog', {
            controller: 'changelogController',
            templateUrl: 'app/templates/changelog.html'
        })

        // general routes
        .when('/login', {
            templateUrl: 'app/templates/authenticate.html'
        })

        // general routes
        .when('/logout', {
            controller: 'logoutController',
            templateUrl: 'app/templates/logout.html'
        })

        .when('/tools/api', {
            controller: 'apiController',
            templateUrl: 'app/templates/tools/api/documentation.html'
        })

        .when('/password_reset', {
            templateUrl: 'app/templates/authenticate.html'
        })

        // Quoter tool!
        .when('/tools/quoter', {
            controller: 'quoterToolController',
            templateUrl: 'app/templates/tools/quoter/quoterTool.html'
        })
            .when('/tools/quoter/:id/print', {
                controller: 'quoterToolController',
                templateUrl: 'app/templates/tools/quoter/quoterToolPrint.html'
            })
            .when('/tools/quoter/:id', {
                controller: 'quoterToolController',
                templateUrl: 'app/templates/tools/quoter/quoterTool.html'
            })

        // Application tool!
        .when('/tools/application', {
            controller: 'applicationToolController',
            templateUrl: 'app/templates/tools/application/applicationTool.html'
        })
            .when('/tools/application/:id', {
                controller: 'applicationToolController',
                templateUrl: 'app/templates/tools/application/applicationTool.html'
            })

        // Locator tool!
        .when('/tools/locator', {
            controller: 'locatorToolController',
            templateUrl: 'app/templates/tools/locator/locatorTool.html'
        })

        // Auth user dashboards
        .when('/dashboard', {
            controller: 'applicationController',
            templateUrl: 'app/templates/dashboard/index.html'
        })

        // vendor routes
        .when('/dashboard/vendors', {
            controller: 'vendorController',
            templateUrl: 'app/templates/vendors/vendorList.html'
        })
            .when('/dashboard/vendors/new', {
                controller: 'vendorEditController',
                templateUrl: 'app/templates/vendors/vendorEdit.html'
            })
            .when('/dashboard/vendors/:id', {
                controller: 'vendorEditController',
                templateUrl: 'app/templates/vendors/vendorEdit.html'
            })

        // program routes
        .when('/dashboard/programs', {
            controller: 'programListController',
            templateUrl: 'app/templates/programs/programList.html'
        })
            .when('/dashboard/programs/new', {
                controller: 'programEditController',
                templateUrl: 'app/templates/programs/programEdit.html'
            })
            .when('/dashboard/programs/:id', {
                controller: 'programEditController',
                templateUrl: 'app/templates/programs/programEdit.html'
            })

        // quote routes
        .when('/dashboard/quotes', {
            controller: 'quoteListController',
            templateUrl: 'app/templates/quotes/quoteList.html'
        })
            .when('/dashboard/quotes/new', {
                controller: 'quoteEditController',
                templateUrl: 'app/templates/quotes/quoteEdit.html'
            })
            .when('/dashboard/quotes/:id', {
                controller: 'quoteEditController',
                templateUrl: 'app/templates/quotes/quoteEdit.html'
            })

        // application routes
        .when('/dashboard/applications', {
            controller: 'applicationController',
            templateUrl: 'app/templates/applications/applicationList.html'
        })
            .when('/dashboard/applications/new', {
                controller: 'applicationController',
                templateUrl: 'app/templates/applications/applicationEdit.html'
            })
            .when('/dashboard/applications/:id', {
                controller: 'applicationController',
                templateUrl: 'app/templates/applications/applicationEdit.html'
            })

        // user routes
        .when('/dashboard/users', {
            controller: 'userListController',
            templateUrl: 'app/templates/users/userList.html'
        })
            .when('/dashboard/users/new', {
                controller: 'userEditController',
                templateUrl: 'app/templates/users/userEdit.html'
            })
            .when('/dashboard/users/:id', {
                controller: 'userEditController',
                templateUrl: 'app/templates/users/userEdit.html'
            })

        ;
    }
])

/**
 * Runs one time when our app is finally bootstrapped
 *
 * @note Now we have access to $rootScope.
 *
 * @note Functions defined here run only one time, unless they observe or bind to a variable
 *       in which case the funtions will run as expected when said variables updates.
 *
 * @todo Most of these should be added to our facultyUI repo, however is there an easier way
 *       to add them? IE instead of needing to put in .run() can we leave them in a seperate module
 *       but include them in our app?
 *
 */
.run(['$rootScope', '$location', 'authService', '$document', '$http', 'promiseTracker', 'apiService', 'Validator',
    function($rootScope, $location, Auth, $document, $http, promiseTracker, api, Validator) {

        // PING the server to check for current status and get XSFR cookie
        // @todo this could be expanded to check for API down etc.
        api.ping().then(function() {});

        // define our version
        // @todo this should be set in package.json, and an api call should be made
        //       to get the version number, rather then setting it here.
        $rootScope.version = '0.3.6';

        // @note this is related to experimental promisetracker module
        $rootScope.apiTracker = promiseTracker('api');

        $rootScope.FormHelper = FormHelper;

        $rootScope.Validator = Validator;
        /**
         * Helper functions, which are accessiable anywhere in our app using $rootScope.functionName()
         *
         */

        /**
         * goto a url. This allows us to easily change hash / no-hash method
         * without having to change many links site-wide
         *
         */
        $rootScope.goTo = function(urlToGoTo) {
            $location.url(urlToGoTo);
        };

        /**
         * Sets active class on a link based on current url / location
         *
         * @example Path // adds active class
         *
         */
        $rootScope.getClass = function(path) {
            var cur_path = $location.path();

            // do some counting
            var splitCurPath = cur_path.split('/').length;
            var splitPath = path.split('/').length;

            //console.log('$location.path() is: ' + cur_path + ', path is: ' + path);
            if (cur_path == path) {
                return "active";
            } else if ($location.path().indexOf(path) > -1 && path.split('/').length === 3) {
                // this check prevents 'dashboard' from being active when user is viewing quotes
                return "active active-trail";
            } else {
                return "";
            }
        };

        /**
        * Function that returns true / false if location matches variable
        * @note you must pass a full path, with a leading slash
        *
        * @example isPage('/login') === $location.url('/login')
        * @example isPage('login') !== $location.url('/login')
        *
        */
        $rootScope.isPage = function(slug) {
            return $location.path() === slug;
        };

        /**
         * Helper function that masks auth.showIfUserCanDoAction() method
         *
         * @todo refactor this, to remove from rootScope
         *
         */
        $rootScope.showIfUserCanDoAction = function(action) {
            return Auth.showIfUserCanDoAction(action);
        };

        /**
         * Generate a string of classes which are generally added to document.body
         * This allows us to target specific pages within css
         *
         * @note this will bound to all successful route changes
         *
         * @note it might be useful to expand this function to add prefixes to the class, ie: page-pageName
         *       Wordpress does this and its one of the more useful features
         *
         */
        $rootScope.$on('$routeChangeSuccess', function($event, $route, $previousRoute) {

            // variable we use on body, @example ng-class="{{pageSlug}}"
            $rootScope.pageSlug = "";

            // get the location and split into an array
            var pageSlug = $location.path().split('/');

            // remove the first element, which is always ""
            pageSlug.shift();

            // special case for home page
            if (pageSlug.length === 1 && pageSlug[0] === "") {

                $rootScope.pageSlug = 'home';

                // create string from each slug item
            } else {

                _.each(pageSlug, function(item) {
                    $rootScope.pageSlug += item + " ";
                });

            }

        });

    }
]);
<commit_msg>Remove formHelper from rootScope<commit_after>angular
    .module('app', [
        'apiResponse',
        'unsavedNew',
        'uiHelpers',
        'ui.validate',
        'ui.mask',
        'ui.if',
        'ui.bootstrap',
        'ngCookies',
        'angular-markdown',
        'mb.spinner',
        'ajoslin.promise-tracker',
        'angulartics',
        'angulartics.google.analytics',
        'google-maps',
        'truncate',
        'ui.select2'
    ])

/**
 * Configure angular app
 *
 * @note we dont yet have access to $rootScope, and a few other things
 *
 */
.config([
    '$httpProvider',
    '$compileProvider',
    function(
        $httpProvider,
        $compileProvider,
        promiseTracker
    ) {

        /**
         * Standard CORS Configuration
         *
         */
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];

        /**
         * Configure ngSanitize directive
         * Here we add 'mailto' 'callto' etc. which prevents links with href='mailto:' from
         * being flagged as 'unsafe' by angular sanitizer
         *
         */
        $compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel|callto):/);

    }
])

/**
 * Define constants using Angulars .constant() method
 *
 * @note you need to adjust base_url when developing locally. Don't commit any changes to this since
 *       master is setup alreay to work with heroku
 *
 */
.constant('MARLINAPI_CONFIG', {
    //base_url: 'http://marlinquoter.herokuapp.com/api/v1/'
    //base_url: 'http://localhost:3000/api/v1/'
    //base_url: 'http://0.0.0.0:3000/api/v1/'
    base_url: 'http://127.0.0.1:3000/api/v1/'
    //base_url: 'http://10.1.10.48:3000/api/v1/'
})

/**
 * Define routes
 *
 * @note for this app we set all routes here in the app file. An alternate (any maybe more modular)
 *       is to set routes in the controllers as needed.
 *
 */
.config(['$routeProvider',
    function($router) {

        $router

        // general routes
        .when('/', {
            controller: 'homeController',
            templateUrl: 'app/templates/home.html'
        })

        .when('/changelog', {
            controller: 'changelogController',
            templateUrl: 'app/templates/changelog.html'
        })

        // general routes
        .when('/login', {
            templateUrl: 'app/templates/authenticate.html'
        })

        // general routes
        .when('/logout', {
            controller: 'logoutController',
            templateUrl: 'app/templates/logout.html'
        })

        .when('/tools/api', {
            controller: 'apiController',
            templateUrl: 'app/templates/tools/api/documentation.html'
        })

        .when('/password_reset', {
            templateUrl: 'app/templates/authenticate.html'
        })

        // Quoter tool!
        .when('/tools/quoter', {
            controller: 'quoterToolController',
            templateUrl: 'app/templates/tools/quoter/quoterTool.html'
        })
            .when('/tools/quoter/:id/print', {
                controller: 'quoterToolController',
                templateUrl: 'app/templates/tools/quoter/quoterToolPrint.html'
            })
            .when('/tools/quoter/:id', {
                controller: 'quoterToolController',
                templateUrl: 'app/templates/tools/quoter/quoterTool.html'
            })

        // Application tool!
        .when('/tools/application', {
            controller: 'applicationToolController',
            templateUrl: 'app/templates/tools/application/applicationTool.html'
        })
            .when('/tools/application/:id', {
                controller: 'applicationToolController',
                templateUrl: 'app/templates/tools/application/applicationTool.html'
            })

        // Locator tool!
        .when('/tools/locator', {
            controller: 'locatorToolController',
            templateUrl: 'app/templates/tools/locator/locatorTool.html'
        })

        // Auth user dashboards
        .when('/dashboard', {
            controller: 'applicationController',
            templateUrl: 'app/templates/dashboard/index.html'
        })

        // vendor routes
        .when('/dashboard/vendors', {
            controller: 'vendorController',
            templateUrl: 'app/templates/vendors/vendorList.html'
        })
            .when('/dashboard/vendors/new', {
                controller: 'vendorEditController',
                templateUrl: 'app/templates/vendors/vendorEdit.html'
            })
            .when('/dashboard/vendors/:id', {
                controller: 'vendorEditController',
                templateUrl: 'app/templates/vendors/vendorEdit.html'
            })

        // program routes
        .when('/dashboard/programs', {
            controller: 'programListController',
            templateUrl: 'app/templates/programs/programList.html'
        })
            .when('/dashboard/programs/new', {
                controller: 'programEditController',
                templateUrl: 'app/templates/programs/programEdit.html'
            })
            .when('/dashboard/programs/:id', {
                controller: 'programEditController',
                templateUrl: 'app/templates/programs/programEdit.html'
            })

        // quote routes
        .when('/dashboard/quotes', {
            controller: 'quoteListController',
            templateUrl: 'app/templates/quotes/quoteList.html'
        })
            .when('/dashboard/quotes/new', {
                controller: 'quoteEditController',
                templateUrl: 'app/templates/quotes/quoteEdit.html'
            })
            .when('/dashboard/quotes/:id', {
                controller: 'quoteEditController',
                templateUrl: 'app/templates/quotes/quoteEdit.html'
            })

        // application routes
        .when('/dashboard/applications', {
            controller: 'applicationController',
            templateUrl: 'app/templates/applications/applicationList.html'
        })
            .when('/dashboard/applications/new', {
                controller: 'applicationController',
                templateUrl: 'app/templates/applications/applicationEdit.html'
            })
            .when('/dashboard/applications/:id', {
                controller: 'applicationController',
                templateUrl: 'app/templates/applications/applicationEdit.html'
            })

        // user routes
        .when('/dashboard/users', {
            controller: 'userListController',
            templateUrl: 'app/templates/users/userList.html'
        })
            .when('/dashboard/users/new', {
                controller: 'userEditController',
                templateUrl: 'app/templates/users/userEdit.html'
            })
            .when('/dashboard/users/:id', {
                controller: 'userEditController',
                templateUrl: 'app/templates/users/userEdit.html'
            })

        ;
    }
])

/**
 * Runs one time when our app is finally bootstrapped
 *
 * @note Now we have access to $rootScope.
 *
 * @note Functions defined here run only one time, unless they observe or bind to a variable
 *       in which case the funtions will run as expected when said variables updates.
 *
 * @todo Most of these should be added to our facultyUI repo, however is there an easier way
 *       to add them? IE instead of needing to put in .run() can we leave them in a seperate module
 *       but include them in our app?
 *
 */
.run(['$rootScope', '$location', 'authService', '$document', '$http', 'promiseTracker', 'apiService', 'Validator',
    function($rootScope, $location, Auth, $document, $http, promiseTracker, api, Validator) {

        // PING the server to check for current status and get XSFR cookie
        // @todo this could be expanded to check for API down etc.
        api.ping().then(function() {});

        // define our version
        // @todo this should be set in package.json, and an api call should be made
        //       to get the version number, rather then setting it here.
        $rootScope.version = '0.3.6';

        // @note this is related to experimental promisetracker module
        $rootScope.apiTracker = promiseTracker('api');

        $rootScope.Validator = Validator;
        /**
         * Helper functions, which are accessiable anywhere in our app using $rootScope.functionName()
         *
         */

        /**
         * goto a url. This allows us to easily change hash / no-hash method
         * without having to change many links site-wide
         *
         */
        $rootScope.goTo = function(urlToGoTo) {
            $location.url(urlToGoTo);
        };

        /**
         * Sets active class on a link based on current url / location
         *
         * @example Path // adds active class
         *
         */
        $rootScope.getClass = function(path) {
            var cur_path = $location.path();

            // do some counting
            var splitCurPath = cur_path.split('/').length;
            var splitPath = path.split('/').length;

            //console.log('$location.path() is: ' + cur_path + ', path is: ' + path);
            if (cur_path == path) {
                return "active";
            } else if ($location.path().indexOf(path) > -1 && path.split('/').length === 3) {
                // this check prevents 'dashboard' from being active when user is viewing quotes
                return "active active-trail";
            } else {
                return "";
            }
        };

        /**
        * Function that returns true / false if location matches variable
        * @note you must pass a full path, with a leading slash
        *
        * @example isPage('/login') === $location.url('/login')
        * @example isPage('login') !== $location.url('/login')
        *
        */
        $rootScope.isPage = function(slug) {
            return $location.path() === slug;
        };

        /**
         * Helper function that masks auth.showIfUserCanDoAction() method
         *
         * @todo refactor this, to remove from rootScope
         *
         */
        $rootScope.showIfUserCanDoAction = function(action) {
            return Auth.showIfUserCanDoAction(action);
        };

        /**
         * Generate a string of classes which are generally added to document.body
         * This allows us to target specific pages within css
         *
         * @note this will bound to all successful route changes
         *
         * @note it might be useful to expand this function to add prefixes to the class, ie: page-pageName
         *       Wordpress does this and its one of the more useful features
         *
         */
        $rootScope.$on('$routeChangeSuccess', function($event, $route, $previousRoute) {

            // variable we use on body, @example ng-class="{{pageSlug}}"
            $rootScope.pageSlug = "";

            // get the location and split into an array
            var pageSlug = $location.path().split('/');

            // remove the first element, which is always ""
            pageSlug.shift();

            // special case for home page
            if (pageSlug.length === 1 && pageSlug[0] === "") {

                $rootScope.pageSlug = 'home';

                // create string from each slug item
            } else {

                _.each(pageSlug, function(item) {
                    $rootScope.pageSlug += item + " ";
                });

            }

        });

    }
]);
<|endoftext|>


<commit_before>angular.module('bookstore.shelf', [])
.controller('ShelfController', function($scope, $routeParams, Shelf, Details, $window, Auth) {
  $scope.collections = [];
  $scope.cart = [];
  $scope.items = 0;
  $scope.id = $routeParams.id;
  $scope.totalPrice = 0;
  $scope.checkout = false;
  $scope.location = $window.location;
  $scope.getShelf = function() {
    Shelf.getShelf($window.localStorage.getItem('userId'))
      .then(function(collections) {
        $scope.collections = collections;
      });
  };
  $scope.addToCart = function(book) {
      var bookNames = $scope.cart.map(function(book) {
        return book.title;
      });
      if (bookNames.includes(book.title)) {
        for (var i = 0; i < $scope.cart.length; i++) {
          if (bookNames[i] === book.title) {
            book.dupl++;
            $scope.cart.splice(i, 1, book);
            Shelf.updateBook(book._id, {dupl: book.dupl});
          }
        }
      } else {
        book.dupl = 1;
        $scope.cart.push(book);
        Shelf.updateBook(book._id, {dupl: book.dupl});
    }
    $scope.items++;
    $scope.totalPrice += Number(book.price);
    $scope.roundedPrice = Math.floor($scope.totalPrice * 100) / 100;
    $scope.alert = book.title + ' added to your cart!';
  };
  $scope.removeBook = function(book) {

    $scope.items -= book.dupl;
    // reset dupl for fresh cart
    Shelf.updateBook(book._id, {dupl: 0})
      .then(function(updatedBook) {
        Auth.removeBook(updatedBook)
           .then(function(removed) {
            for (var i = 0; i < $scope.cart.length; i++) {
              if($scope.cart[i].title  === book.title) {
                // update cart
                var removed = $scope.cart.splice(i, 1);
                $scope.totalPrice -= Number(book.price * removed[0].dupl);
                $scope.roundedPrice = Math.floor($scope.totalPrice * 100) / 100;
              }
            }
          })
          .then(function() {
            $scope.alert = book.title + ' removed from your shelf!';
            Shelf.getShelf()
              .then(function(books) {
                $scope.collections = books;
              });
          });
      });
  };
  $scope.fakeBuy = function() {
    $scope.checkout = true;
    $('#myModal').on('shown.bs.modal', function () {
  $('#myInput').focus()
})
  };
  $scope.stripeCallback = function(code, result) {
    if(result.error) {
      alert('it failed! error: ' + result.error.message);
    } else {
      Shelf.sendToken(
        {
          stripeToken: result.id,
          price: Math.round($scope.roundedPrice * 100),
          name: result.card.name
        })
        .then(function(response) {
          var price = (response.amount / 100).toFixed(2);
          $scope.alert = response.outcome.seller_message +  ' Your card was charged with a total of $' + price;
        })
    }
    $('#myModal.modal').hide();
    $('.modal-backdrop').hide();
    // reset cart and price
    $scope.cart = [];
    $scope.roundedPrice = totalPrice = 0;
  };
})<commit_msg>(fix) total items in cart accuratley update<commit_after>angular.module('bookstore.shelf', [])
.controller('ShelfController', function($scope, $routeParams, Shelf, Details, $window, Auth) {
  $scope.collections = [];
  $scope.cart = [];
  $scope.items = 0;
  $scope.id = $routeParams.id;
  $scope.totalPrice = 0;
  $scope.checkout = false;
  $scope.location = $window.location;
  $scope.getShelf = function() {
    Shelf.getShelf($window.localStorage.getItem('userId'))
      .then(function(collections) {
        $scope.collections = collections;
      });
  };
  $scope.addToCart = function(book) {
      var bookNames = $scope.cart.map(function(book) {
        return book.title;
      });
      if (bookNames.includes(book.title)) {
        for (var i = 0; i < $scope.cart.length; i++) {
          if (bookNames[i] === book.title) {
            book.dupl++;
            $scope.cart.splice(i, 1, book);
            Shelf.updateBook(book._id, {dupl: book.dupl});
          }
        }
      } else {
        book.dupl = 1;
        $scope.cart.push(book);
        Shelf.updateBook(book._id, {dupl: book.dupl});
    }
    $scope.items++;
    $scope.totalPrice += Number(book.price);
    $scope.roundedPrice = Math.floor($scope.totalPrice * 100) / 100;
    $scope.alert = book.title + ' added to your cart!';
  };
  $scope.removeBook = function(book) {

    $scope.items -= (book.dupl === 0) ? 0 : book.dupl;
    // reset dupl for fresh cart
    Shelf.updateBook(book._id, {dupl: 0})
      .then(function(updatedBook) {
        Auth.removeBook(updatedBook)
           .then(function(removed) {
            for (var i = 0; i < $scope.cart.length; i++) {
              if($scope.cart[i].title  === book.title) {
                // update cart
                var removed = $scope.cart.splice(i, 1);
                $scope.totalPrice -= Number(book.price * removed[0].dupl);
                $scope.roundedPrice = Math.floor($scope.totalPrice * 100) / 100;
              }
            }
          })
          .then(function() {
            $scope.alert = book.title + ' removed from your shelf!';
            Shelf.getShelf()
              .then(function(books) {
                $scope.collections = books;
              });
          });
      });
  };
  $scope.fakeBuy = function() {
    $scope.checkout = true;
    $('#myModal').on('shown.bs.modal', function () {
  $('#myInput').focus()
})
  };
  $scope.stripeCallback = function(code, result) {
    if(result.error) {
      alert('it failed! error: ' + result.error.message);
    } else {
      Shelf.sendToken(
        {
          stripeToken: result.id,
          price: Math.round($scope.roundedPrice * 100),
          name: result.card.name
        })
        .then(function(response) {
          var price = (response.amount / 100).toFixed(2);
          $scope.alert = response.outcome.seller_message +  ' Your card was charged with a total of $' + price;
        })
    }
    $('#myModal.modal').hide();
    $('.modal-backdrop').hide();
    // reset cart and price
    $scope.cart = [];
    $scope.roundedPrice = totalPrice = 0;
  };
})<|endoftext|>