<commit_before>var EventDispatcherTest = TestCase('EventDispatcherTest');

EventDispatcherTest.prototype.setUp = function() {
  this.fakeHtmlElement_ = { className: '' };
  this.loadingEventCalled_ = false;
  this.fontLoadingEventCalled_ = false;
  this.fontLoading_ = '';
  this.fontActiveEventCalled_ = false;
  this.fontActive_ = '';
  this.fontInactvieEventCalled_ = false;
  this.fontInactive_ = '';
  this.activeEventCalled_ = false;
  this.inactiveEventCalled_ = false;
  var namespace = 'ns';
  var self = this;

  this.eventDispatcher_ = new webfont.EventDispatcher(new webfont.DomHelper(
      document), this.fakeHtmlElement_, {
        loading: function() {
          self.loadingEventCalled_ = true;
        },
        active: function() {
          self.activeEventCalled_ = true;
        },
        inactive: function() {
          self.inactiveEventCalled_ = true;
	      },
        fontloading: function(fontFamily, fontDescription) {
          self.fontLoadingEventCalled_ = true;
          self.fontLoading_ = fontFamily + ' ' + fontDescription;
        },
        fontactive: function(fontFamily, fontDescription) {
          self.fontActiveEventCalled_ = true;
          self.fontActive_ = fontFamily + ' ' + fontDescription;
        },
        fontinactive: function(fontFamily, fontDescription) {
          self.fontInactvieEventCalled_ = true;
          self.fontInactive_ = fontFamily + ' ' + fontDescription;
        }
  }, namespace);
};

EventDispatcherTest.prototype.testClassNamesOnActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertTrue(this.loadingEventCalled_);
  this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
  assertTrue(this.fontLoadingEventCalled_);
  assertEquals('fontFamilyLoading n4', this.fontLoading_);
  this.eventDispatcher_.dispatchFontActive('fontFamilyActive', 'n4');
  assertTrue(this.fontActiveEventCalled_);
  assertEquals('fontFamilyActive n4', this.fontActive_);
  this.eventDispatcher_.dispatchActive();
  assertTrue(this.activeEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveFontButActive = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-inactive ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnInactiveFontButActive = function() {
  this.eventDispatcher_.dispatchLoading();
  assertTrue(this.loadingEventCalled_);
  this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
  assertTrue(this.fontLoadingEventCalled_);
  assertEquals('fontFamilyLoading n4', this.fontLoading_);
  this.eventDispatcher_.dispatchFontInactive('fontFamilyInactive', 'n4');
  assertTrue(this.fontInactvieEventCalled_);
  assertEquals('fontFamilyInactive n4', this.fontInactive_);
  this.eventDispatcher_.dispatchActive();
  assertTrue(this.activeEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertTrue(this.loadingEventCalled_);
  this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
  assertTrue(this.fontLoadingEventCalled_);
  assertEquals('fontFamilyLoading n4', this.fontLoading_);
  this.eventDispatcher_.dispatchFontInactive('fontFamilyInactive', 'n4');
  assertTrue(this.fontInactvieEventCalled_);
  assertEquals('fontFamilyInactive n4', this.fontInactive_);
  this.eventDispatcher_.dispatchInactive();
  assertTrue(this.inactiveEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactive = function() {
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnInactive = function() {
  this.eventDispatcher_.dispatchInactive();
  assertTrue(this.inactiveEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-inactive ns-myfamily2-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenActiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-inactive ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-active ns-active ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenInactiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active ns-myfamily2-n4-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenActiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenInactiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
};
<commit_msg>Fix misspelling in event dispatcher test.<commit_after>var EventDispatcherTest = TestCase('EventDispatcherTest');

EventDispatcherTest.prototype.setUp = function() {
  this.fakeHtmlElement_ = { className: '' };
  this.loadingEventCalled_ = false;
  this.fontLoadingEventCalled_ = false;
  this.fontLoading_ = '';
  this.fontActiveEventCalled_ = false;
  this.fontActive_ = '';
  this.fontInactiveEventCalled_ = false;
  this.fontInactive_ = '';
  this.activeEventCalled_ = false;
  this.inactiveEventCalled_ = false;
  var namespace = 'ns';
  var self = this;

  this.eventDispatcher_ = new webfont.EventDispatcher(new webfont.DomHelper(
      document), this.fakeHtmlElement_, {
        loading: function() {
          self.loadingEventCalled_ = true;
        },
        active: function() {
          self.activeEventCalled_ = true;
        },
        inactive: function() {
          self.inactiveEventCalled_ = true;
	      },
        fontloading: function(fontFamily, fontDescription) {
          self.fontLoadingEventCalled_ = true;
          self.fontLoading_ = fontFamily + ' ' + fontDescription;
        },
        fontactive: function(fontFamily, fontDescription) {
          self.fontActiveEventCalled_ = true;
          self.fontActive_ = fontFamily + ' ' + fontDescription;
        },
        fontinactive: function(fontFamily, fontDescription) {
          self.fontInactiveEventCalled_ = true;
          self.fontInactive_ = fontFamily + ' ' + fontDescription;
        }
  }, namespace);
};

EventDispatcherTest.prototype.testClassNamesOnActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertTrue(this.loadingEventCalled_);
  this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
  assertTrue(this.fontLoadingEventCalled_);
  assertEquals('fontFamilyLoading n4', this.fontLoading_);
  this.eventDispatcher_.dispatchFontActive('fontFamilyActive', 'n4');
  assertTrue(this.fontActiveEventCalled_);
  assertEquals('fontFamilyActive n4', this.fontActive_);
  this.eventDispatcher_.dispatchActive();
  assertTrue(this.activeEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveFontButActive = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-inactive ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnInactiveFontButActive = function() {
  this.eventDispatcher_.dispatchLoading();
  assertTrue(this.loadingEventCalled_);
  this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
  assertTrue(this.fontLoadingEventCalled_);
  assertEquals('fontFamilyLoading n4', this.fontLoading_);
  this.eventDispatcher_.dispatchFontInactive('fontFamilyInactive', 'n4');
  assertTrue(this.fontInactiveEventCalled_);
  assertEquals('fontFamilyInactive n4', this.fontInactive_);
  this.eventDispatcher_.dispatchActive();
  assertTrue(this.activeEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertTrue(this.loadingEventCalled_);
  this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
  assertTrue(this.fontLoadingEventCalled_);
  assertEquals('fontFamilyLoading n4', this.fontLoading_);
  this.eventDispatcher_.dispatchFontInactive('fontFamilyInactive', 'n4');
  assertTrue(this.fontInactiveEventCalled_);
  assertEquals('fontFamilyInactive n4', this.fontInactive_);
  this.eventDispatcher_.dispatchInactive();
  assertTrue(this.inactiveEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactive = function() {
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testEventsOnInactive = function() {
  this.eventDispatcher_.dispatchInactive();
  assertTrue(this.inactiveEventCalled_);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-inactive ns-myfamily2-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenActiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-inactive ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-active ns-active ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenInactiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenActiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily2-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active ns-myfamily2-n4-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnActiveThenActiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
  assertEquals('ns-myfamily-n4-active ns-active ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchActive();
  assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenInactiveLoad = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family 2', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-myfamily2-n4-inactive', this.fakeHtmlElement_.className);
};

EventDispatcherTest.prototype.testClassNamesOnInactiveThenInactiveLoadSameFont = function() {
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchLoading();
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
  assertEquals('ns-myfamily-n4-inactive ns-inactive ns-loading', this.fakeHtmlElement_.className);
  this.eventDispatcher_.dispatchInactive();
  assertEquals('ns-myfamily-n4-inactive ns-inactive', this.fakeHtmlElement_.className);
};
<|endoftext|>


<commit_before>/**
 * Created by Nicholas Hallahan <nhallahan@spatialdev.com>
 *       on 3/19/14.
 */

/**
 * This service is incredible.
 */
angular.module('GeoAngular').factory('VectorProvider', function ($rootScope, $location, $http, LayerConfig) {

  /**
   * This is used by the factory to dynamically state the type (class)
   * that it wants to instantiate.
   *
   * @type {{geojson: GeoJSON, bboxgeojson: BBoxGeoJSON, kml: KML}}
   */
  var types = {
    geojson: GeoJSON,
    bboxgeojson: BBoxGeoJSON,
    kml: KML
  };

  /**
   * This is updated by updateBBox. It is then used to query all
   * VectorProviders that use a bounding box to get additional
   * features.
   *
   * @type {string}
   */
  var bbox = null;

  /**
   * Every resource that has been instantiated.
   * @type {Array}
   */
  var resources = [];
  debug.resources = resources;

  /**
   * Every resource with a bounding box fetching mechanism.
   * @type {Array}
   */
  var bboxResources = [];
  debug.bboxResources = bboxResources;

  /**
   * All VectorProvider resources are children of this class.
   * @param config
   * @constructor
   */
  function Resource(config) {
    resources.push(this);
    this._config = config;
    this._url = null;
    if (typeof config === 'object') {
      this._url = config.url;
    } else {
      this._url = config;
    }

    this._eachLayerCallback = null;
    this._geojsonLayer = null;
  }

  /**
   * Fetches data from the given url of a resource.
   * Subclasses then handle the callback accordingly.
   *
   * Needs to also try to get a resource via the Chubbs
   * proxy.
   *
   * @param cb
   */
  Resource.prototype.fetch = function(cb) {

    $http.get(this._url, {cache: true}).success(function (data, status) {
      cb(data);
    }).error(function() {
      //NH TODO Deal with proxy logic.
      console.log("Trying proxy for " + this.name);

    });

  };

  /**
   * Returns the Leaflet GeoJSON Layer associated with the
   * Resource or creates a new one.
   *
   * @returns {null|*}
   */
  Resource.prototype.getLayer = function () {
    if (typeof this._geojsonLayer !== 'undefined' && this._geojsonLayer !== null) {
      return this._geojsonLayer;
    }

    this._geojsonLayer = L.geoJson(this._geojson || null, {
      style: L.mapbox.simplestyle.style,
      pointToLayer: function(feature, latlon) {
        if (!feature.properties) feature.properties = {};
        if (feature.properties.scale) {
          return L.circleMarker(latlon, {
            fillColor: feature.properties.color || '#FF0000',
            radius: 20 * feature.properties.scale
          });
        }
        return L.mapbox.marker.style(feature, latlon);
      }
    }).eachLayer(this._eachLayerCallback);

    return this._geojsonLayer;
  };

  Resource.prototype.eachLayer = function (cb) {
    this._eachLayerCallback = cb;
    this._geojsonLayer.eachLayer(cb);
  };

  /**
   * This is a basic GeoJSON VectorProvider.
   * @param config
   * @constructor
   */
  function GeoJSON(config) {
    Resource.call(this, config);
    this._geojson = null;
  }

  GeoJSON.prototype = Object.create(Resource.prototype);
  GeoJSON.prototype.constructor = GeoJSON;

  GeoJSON.prototype.fetch = function (cb) {
    if (this._geojson && typeof cb === 'function') {
      cb(this._geojson);
      return;
    }
    var self = this;
    Resource.prototype.fetch.call(this, function(data) {
      self._geojson = data;
      if (typeof self._config.properties === 'object') {
        angular.extend(self._geojson.properties, self._config.properties);
      }

      if (typeof cb === 'function') cb(self._geojson);
    });
  };

  GeoJSON.prototype.getLayer = function() {
    if (this._geojsonLayer) return this._geojsonLayer;
    var layer =  Resource.prototype.getLayer.call(this);
    this.fetch(function(geojson){
      layer.addData(geojson);
    });
    return layer;
  };

  function BBoxGeoJSON(config) {
    Resource.call(this, config);
    this._bboxurl = config.bboxurl;
    this._features = {};
    this._featureLayersByLevel = {};
    this._allFeatureLayers = {};

    bboxResources.push(this);
  }

  BBoxGeoJSON.prototype = Object.create(Resource.prototype);
  BBoxGeoJSON.prototype.constructor = BBoxGeoJSON;

  BBoxGeoJSON.prototype._getFeatures = function (featObj) {
    var url = this._url.replace(':level', featObj.level).replace(':ids', featObj.id);
    var self = this;
    // not cached because we only fetch when we dont have the feature in the hash
    $http.get(url).success(function (geojson, status) {

      if (geojson.error) {
        console.error('Unable to fetch feature: ' + geojson.error);
        return;
      }
      var feat = geojson.features[0];
      for (var key in featObj) {
        feat.properties[key] = featObj[key];
        delete featObj[key];
      }
      for (var k in feat) {
        featObj[k] = feat[k];
      }
      angular.extend(featObj, feat);
      console.log('fetched feature: ' + featObj.properties.name);

      if (!self._geojsonLayer) {
        self._getLayer();
        console.log('creating layer in _getFeatures');
      }

      var options = self._geojsonLayer.options;
      var featLayer = L.GeoJSON.geometryToLayer(featObj, options.pointToLayer, options.coordsToLatLng, options);
      featLayer.feature = L.GeoJSON.asFeature(featObj);
      featLayer.defaultOptions = featLayer.options;
      self._geojsonLayer.resetStyle(featLayer);
      if (options.onEachFeature) {
        options.onEachFeature(featObj, featLayer);
      }
      self._geojsonLayer.addLayer(featLayer);

      var props = featObj.properties;
      var level = props.level;
      if (!self._featureLayersByLevel[level]) {
        self._featureLayersByLevel[level] = [];
      }
      self._featureLayersByLevel[level].push(featLayer);
      self._allFeatureLayers[props.guid] = featLayer;

    }).error(function(err) {
      //NH TODO Deal with proxy logic.
      console.error("Unable to fetch feature: " + err);

    });
  };

  /**
   * Fetches the feature itinerary based on the current bbox.
   *
   * The feature itinerary is a set of features with some properties
   * such as guid and name. The geometry for each of these features
   * has not yet been requested. This is done by _getFeatures.
   */
  BBoxGeoJSON.prototype.fetchFeatureItinerary = function() {
    var url = this._bboxurl.replace(':bbox', bbox);
    var self = this;
    $http.get(url, {cache: true}).success(function (featItinerary, status) {
      console.log('featItinerary: ' + JSON.stringify(featItinerary));
      var activeLevels = {};
      self._activeLevels = activeLevels;
      for (var i=0, len=featItinerary.length; i < len; ++i) {
        var o = featItinerary[i];
        activeLevels[o.level] = true;
        if (!self._features[o.id]) {
          // adding feature to features hash (all features ever)
          self._features[o.id] = o;
          // getting the features (including basic, simplified geometry)
          self._getFeatures(o);
        }
      }
      self._removeInactiveLayers(self);

    }).error(function() {
      //NH TODO Deal with proxy logic.
      console.error("Need to try proxy for _fetchForBBox");

    });
  };

  /**
   * For all of the active layers that we have, remove layers that are
   * not part of the current set of active levels.
   *
   * @private
   */
  BBoxGeoJSON.prototype._removeInactiveLayers = function(self) {
    var activeLevels = this._activeLevels;
    var featureLayersByLevel = this._featureLayersByLevel;
    for (var level in featureLayersByLevel) {
      // if the level is not an active level, remove from map
      if (!activeLevels[level]) {
        var layers = featureLayersByLevel[level];
        for (var i = 0, len = layers.length; i < len; ++i) {
          var layer = layers[i];
          self._geojsonLayer.removeLayer(layer);
          console.log('Removed Layer: ' + layer.feature.properties.name);
        }
        delete featureLayersByLevel[level];
      }
    }
  };

  /**
   * A KML Resource fetches KML and parses it with togeojson.js
   * Note that togeojson.js has bugs and does not accurately parse
   * some of the KML sources we have tested with. This library has
   * been modified with my hotfixes.
   *
   * @param config
   * @constructor
   */
  function KML(config) {
    Resource.call(this, config);
    this._geojson = null;
  }

  KML.prototype = Object.create(Resource.prototype);
  KML.prototype.constructor = KML;

  KML.prototype.fetch = function (cb) {
    var self = this;
    Resource.prototype.fetch.call(this, function(data) {
      var xml = $.parseXML(data);
      self._geojson = toGeoJSON.kml(xml);
      if (typeof self._config.properties === 'object') {
        angular.extend(self._geojson.properties, self._config.properties);
        self._geojson.properties.srcType = 'kml';
      }
      if (typeof cb === 'function') cb(self._geojson);
    });
  };

  return {
    /**
     * You can explicitly name the type of resource. If not,
     * we will figure it out for you...
     *
     * @param resourceName
     * @param type
     */
    createResource: function (resourceName, type) {
      var config = LayerConfig.find(resourceName);
      if (config === null) {
        console.error('VectorProvider: Invalid Resource Configuration Name. Check LayerConfig File...');
        return null;
      }
      if (type || config.type) {
        // if the resource is just a string, then it should be a url
        return new types[(type || config.type).toLowerCase()](config);
      } else {
        if (config.slice(config.length - 3).toLowerCase() === 'kml') {
          return new KML(config);
        }
        // NH TODO Check a bit more into if this resource is valid GeoJSON
        return new GeoJSON(config);
      }
    },

    /**
     * When the bounding box of the map changes, VectorProvider needs
     * to be notified of the current bounding box so it can getch the
     * latest vector data for the bbox of the map viewport.
     *
     * The bbox must be WGS84.
     *
     * @param bboxStr "south,west,north,east" === "minX,minY,maxX,maxY"
     */
    updateBBox: function(bboxStr) {
      bbox = bboxStr;

      console.log('VectorProvider bbox: ' + bbox);
      for(var i = 0, len = bboxResources.length; i < len; ++i) {
        bboxResources[i].fetchFeatureItinerary();
      }

    }
  };
});
<commit_msg>switching between gadm levels seem to be working as intended<commit_after>/**
 * Created by Nicholas Hallahan <nhallahan@spatialdev.com>
 *       on 3/19/14.
 */

/**
 * This service is incredible.
 */
angular.module('GeoAngular').factory('VectorProvider', function ($rootScope, $location, $http, LayerConfig) {

  /**
   * This is used by the factory to dynamically state the type (class)
   * that it wants to instantiate.
   *
   * @type {{geojson: GeoJSON, bboxgeojson: BBoxGeoJSON, kml: KML}}
   */
  var types = {
    geojson: GeoJSON,
    bboxgeojson: BBoxGeoJSON,
    kml: KML
  };

  /**
   * This is updated by updateBBox. It is then used to query all
   * VectorProviders that use a bounding box to get additional
   * features.
   *
   * @type {string}
   */
  var bbox = null;

  /**
   * Every resource that has been instantiated.
   * @type {Array}
   */
  var resources = [];
  debug.resources = resources;

  /**
   * Every resource with a bounding box fetching mechanism.
   * @type {Array}
   */
  var bboxResources = [];
  debug.bboxResources = bboxResources;

  /**
   * All VectorProvider resources are children of this class.
   * @param config
   * @constructor
   */
  function Resource(config) {
    resources.push(this);
    this._config = config;
    this._url = null;
    if (typeof config === 'object') {
      this._url = config.url;
    } else {
      this._url = config;
    }

    this._eachLayerCallback = null;
    this._geojsonLayer = null;
  }

  /**
   * Fetches data from the given url of a resource.
   * Subclasses then handle the callback accordingly.
   *
   * Needs to also try to get a resource via the Chubbs
   * proxy.
   *
   * @param cb
   */
  Resource.prototype.fetch = function(cb) {

    $http.get(this._url, {cache: true}).success(function (data, status) {
      cb(data);
    }).error(function() {
      //NH TODO Deal with proxy logic.
      console.log("Trying proxy for " + this.name);

    });

  };

  /**
   * Returns the Leaflet GeoJSON Layer associated with the
   * Resource or creates a new one.
   *
   * @returns {null|*}
   */
  Resource.prototype.getLayer = function () {
    if (typeof this._geojsonLayer !== 'undefined' && this._geojsonLayer !== null) {
      return this._geojsonLayer;
    }

    this._geojsonLayer = L.geoJson(this._geojson || null, {
      style: L.mapbox.simplestyle.style,
      pointToLayer: function(feature, latlon) {
        if (!feature.properties) feature.properties = {};
        if (feature.properties.scale) {
          return L.circleMarker(latlon, {
            fillColor: feature.properties.color || '#FF0000',
            radius: 20 * feature.properties.scale
          });
        }
        return L.mapbox.marker.style(feature, latlon);
      }
    }).eachLayer(this._eachLayerCallback);

    return this._geojsonLayer;
  };

  Resource.prototype.eachLayer = function (cb) {
    this._eachLayerCallback = cb;
    this._geojsonLayer.eachLayer(cb);
  };

  /**
   * This is a basic GeoJSON VectorProvider.
   * @param config
   * @constructor
   */
  function GeoJSON(config) {
    Resource.call(this, config);
    this._geojson = null;
  }

  GeoJSON.prototype = Object.create(Resource.prototype);
  GeoJSON.prototype.constructor = GeoJSON;

  GeoJSON.prototype.fetch = function (cb) {
    if (this._geojson && typeof cb === 'function') {
      cb(this._geojson);
      return;
    }
    var self = this;
    Resource.prototype.fetch.call(this, function(data) {
      self._geojson = data;
      if (typeof self._config.properties === 'object') {
        angular.extend(self._geojson.properties, self._config.properties);
      }

      if (typeof cb === 'function') cb(self._geojson);
    });
  };

  GeoJSON.prototype.getLayer = function() {
    if (this._geojsonLayer) return this._geojsonLayer;
    var layer =  Resource.prototype.getLayer.call(this);
    this.fetch(function(geojson){
      layer.addData(geojson);
    });
    return layer;
  };

  function BBoxGeoJSON(config) {
    Resource.call(this, config);
    this._bboxurl = config.bboxurl;
    this._features = {};
    this._featureLayersByLevel = {};
    this._allFeatureLayers = {};

    bboxResources.push(this);
  }

  BBoxGeoJSON.prototype = Object.create(Resource.prototype);
  BBoxGeoJSON.prototype.constructor = BBoxGeoJSON;

  BBoxGeoJSON.prototype._getFeatures = function (featObj) {
    var url = this._url.replace(':level', featObj.level).replace(':ids', featObj.id);
    var self = this;
    // not cached because we only fetch when we dont have the feature in the hash
    $http.get(url).success(function (geojson, status) {

      if (geojson.error) {
        console.error('Unable to fetch feature: ' + geojson.error);
        return;
      }
      var feat = geojson.features[0];
      for (var key in featObj) {
        feat.properties[key] = featObj[key];
        delete featObj[key];
      }
      for (var k in feat) {
        featObj[k] = feat[k];
      }
      angular.extend(featObj, feat);
      console.log('fetched feature: ' + featObj.properties.name);

      if (!self._geojsonLayer) {
        self._getLayer();
        console.log('creating layer in _getFeatures');
      }

      var options = self._geojsonLayer.options;
      var featLayer = L.GeoJSON.geometryToLayer(featObj, options.pointToLayer, options.coordsToLatLng, options);
      featLayer.feature = L.GeoJSON.asFeature(featObj);
      featLayer.defaultOptions = featLayer.options;
      self._geojsonLayer.resetStyle(featLayer);
      if (options.onEachFeature) {
        options.onEachFeature(featObj, featLayer);
      }

      BBoxGeoJSON_addLayer(self, featLayer);

    }).error(function(err) {
      //NH TODO Deal with proxy logic.
      console.error("Unable to fetch feature: " + err);

    });
  };

  /**
   * Should only be used by BBoxLayer objects.
   * Consider this a private method.
   *
   * @param self
   * @param featLayer
   */
  function BBoxGeoJSON_addLayer(self, featLayer) {

    self._geojsonLayer.addLayer(featLayer);

    var props = featLayer.feature.properties;
    var level = props.level;
    if (!self._featureLayersByLevel[level]) {
      self._featureLayersByLevel[level] = [];
    }
    self._featureLayersByLevel[level].push(featLayer);
    self._allFeatureLayers[props.guid] = featLayer;
  }

  /**
   * Fetches the feature itinerary based on the current bbox.
   *
   * The feature itinerary is a set of features with some properties
   * such as guid and name. The geometry for each of these features
   * has not yet been requested. This is done by _getFeatures.
   */
  BBoxGeoJSON.prototype.fetchFeatureItinerary = function() {
    var url = this._bboxurl.replace(':bbox', bbox);
    var self = this;
    $http.get(url, {cache: true}).success(function (featItinerary, status) {
      console.log('featItinerary: ' + JSON.stringify(featItinerary));
      var activeLevels = {};
      self._activeLevels = activeLevels;
      for (var i=0, len=featItinerary.length; i < len; ++i) {
        var o = featItinerary[i];
        activeLevels[o.level] = true;
        var guid = o.guid || o.id;
        if (!self._features[guid]) {
          // adding feature to features hash (all features ever)
          self._features[guid] = o;
          // getting the features (including basic, simplified geometry)
          self._getFeatures(o);
        } else {
          // NH TODO: Test to see what happens when layers get re-added but the geometry still hasn't gotten here.

          // if we already have a layer and it is not on the map but should be there, add it to the geojson layer
          var l = self._allFeatureLayers[guid];
          if (l) {
            BBoxGeoJSON_addLayer(self, l);
          }

        }
      }
      self._removeInactiveLayers(self);

    }).error(function() {
      //NH TODO Deal with proxy logic.
      console.error("Need to try proxy for _fetchForBBox");

    });
  };

  /**
   * For all of the active layers that we have, remove layers that are
   * not part of the current set of active levels.
   *
   * @private
   */
  BBoxGeoJSON.prototype._removeInactiveLayers = function(self) {
    var activeLevels = this._activeLevels;
    var featureLayersByLevel = this._featureLayersByLevel;
    for (var level in featureLayersByLevel) {
      // if the level is not an active level, remove from map
      if (!activeLevels[level]) {
        var layers = featureLayersByLevel[level];
        for (var i = 0, len = layers.length; i < len; ++i) {
          var layer = layers[i];
          self._geojsonLayer.removeLayer(layer);
          console.log('Removed Layer: ' + layer.feature.properties.name);
        }
        delete featureLayersByLevel[level];
      }
    }
  };

  /**
   * A KML Resource fetches KML and parses it with togeojson.js
   * Note that togeojson.js has bugs and does not accurately parse
   * some of the KML sources we have tested with. This library has
   * been modified with my hotfixes.
   *
   * @param config
   * @constructor
   */
  function KML(config) {
    Resource.call(this, config);
    this._geojson = null;
  }

  KML.prototype = Object.create(Resource.prototype);
  KML.prototype.constructor = KML;

  KML.prototype.fetch = function (cb) {
    var self = this;
    Resource.prototype.fetch.call(this, function(data) {
      var xml = $.parseXML(data);
      self._geojson = toGeoJSON.kml(xml);
      if (typeof self._config.properties === 'object') {
        angular.extend(self._geojson.properties, self._config.properties);
        self._geojson.properties.srcType = 'kml';
      }
      if (typeof cb === 'function') cb(self._geojson);
    });
  };

  return {
    /**
     * You can explicitly name the type of resource. If not,
     * we will figure it out for you...
     *
     * @param resourceName
     * @param type
     */
    createResource: function (resourceName, type) {
      var config = LayerConfig.find(resourceName);
      if (config === null) {
        console.error('VectorProvider: Invalid Resource Configuration Name. Check LayerConfig File...');
        return null;
      }
      if (type || config.type) {
        // if the resource is just a string, then it should be a url
        return new types[(type || config.type).toLowerCase()](config);
      } else {
        if (config.slice(config.length - 3).toLowerCase() === 'kml') {
          return new KML(config);
        }
        // NH TODO Check a bit more into if this resource is valid GeoJSON
        return new GeoJSON(config);
      }
    },

    /**
     * When the bounding box of the map changes, VectorProvider needs
     * to be notified of the current bounding box so it can getch the
     * latest vector data for the bbox of the map viewport.
     *
     * The bbox must be WGS84.
     *
     * @param bboxStr "south,west,north,east" === "minX,minY,maxX,maxY"
     */
    updateBBox: function(bboxStr) {
      bbox = bboxStr;

      console.log('VectorProvider bbox: ' + bbox);
      for(var i = 0, len = bboxResources.length; i < len; ++i) {
        bboxResources[i].fetchFeatureItinerary();
      }

    }
  };
});
<|endoftext|>


<commit_before><commit_msg>Array methods/<commit_after><|endoftext|>


<commit_before>/**
 *  KitScript - A User Script Manager For Safari
 *
 *  Greasemonkey.js - Javascript file containing Greasemonkey classes
 *  (by Prototype.js) used globally in the extension & implementing core
 *  Greasemonkey API.
 *
 *  @author Seraf Dos Santos <webmaster@cyb3r.ca>
 *  @copyright 2011-2012 Seraf Dos Santos - All rights reserved.
 *  @license MIT License
 *  @version 0.1
 */

//"use strict";

/**
 *  KSGMException (KitScript Greasemonkey Exception Class)
 */
var KSGMException = Class.create({

    initialize: function (msg) {

        this._msg = msg;
    },
    getMessage: function () {

        return this._msg;
    }
});

/**
 *  KSGreasemonkeyMetadata (KitScript Greasemonkey Metadata Class)
 */
var KSGreasemonkeyMetadata = Class.create(_Utils, {

    initialize: function ($super) {

        $super();

        this._isHeaderValid = false;
        this._script = "";
    },
    loadScript: function (scriptStr) {

        this._script = scriptStr;

        if (!this.isHeaderValid())
            throw new KSGMException("User script metadata block is invalid.");
    },
    isHeaderValid: function () {

        this._isValid = /[\/]{2} ==UserScript==[^=]*==[\/]{1}UserScript==/m.test(this._script);

        return this._isValid;
    },

    /**
     *  =========================== SUPPORTED IN v0.1 ==========================
     *  === v === v === v === v === v === v === v === v === v === v === v === v
     */

    /**
     *  @name string – KS Mandatory
     *
     *  - The combination of namespace and name is the unique identifier for a Greasemonkey script.
     *
     *  @returns String
     */
    getName: function () {

        if (/[\/]{2} \@name (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@name (.*)/g.exec(this._script);

            return matches[1];
        } else {

            throw new KSGMException("No mandatory @name in metadata block.");
        }
    },
    /**
     *  @namespace string – KS Mandatory
     *
     *  - The combination of namespace and name is the unique identifier for a Greasemonkey script.
     *
     *  @returns String
     */
    getNamespace: function () {

        if (/[\/]{2} \@namespace (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@namespace (.*)/g.exec(this._script);

            return matches[1];
        } else {

            throw new KSGMException("No mandatory @namesapce in metadata block.");
        }
    },
    /**
     *  @description string – KS Mandatory
     *
     *  @returns String
     */
    getDescription: function () {

        if (/[\/]{2} \@description (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@description (.*)/g.exec(this._script);

            return matches[1];
        } else {

            throw new KSGMException("No mandatory @description in metadata block.");
        }
    },
    /**
     *  @requires url – Optional
     *
     *  @returns Array
     */
    getRequires: function () {

        var _requires = [];

        if (/[\/]{2} \@match (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@require (.*)/g.exec(this._script);

            for (var i = 1; i < matches.length; i++) {

                _requires.push(matches[i]);
            }
        }

        return _requires;
    },
    /**
     *  @includes pattern – Optional
     *
     *  - There can be any number of @include rules in a script.
     *  - If no include rule is provided, @include * is assumed.
     *
     *  @returns Array
     */
    getIncludes: function () {

        var _includes = [];

        if (/[\/]{2} \@include (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@include (.*)/g.exec(this._script);

            if (matches.length > 0) {

                for (var i = 1; i < matches.length; i++) {

                    _includes.push(matches[i]);
                }
            } else {

                _includes.push('*');
            }
        }

        return _includes;
    },
    /**
     *  @excludes pattern – Optional
     *
     *  - There can be any number of @exclude rules in a script.
     *
     *  @returns Array
     */
    getExcludes: function () {

        var _excludes = [];

        if (/[\/]{2} \@exclude (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@exclude (.*)/g.exec(this._script);

            if (matches.length > 0) {

                for (var i = 1; i < matches.length; i++) {

                    _excludes.push(matches[i]);
                }
            }
        }

        return _excludes;
    },
    /**
     *  @version float – Optional
     *
     *  - This is the version of the script, which should be treated like a
     *      firefox extension version, and maintain the same syntax.
     *
     *  KS v0.1:
     *  - No auto-update implemented
     *
     *  @returns String
     */
    getVersion: function () {

        if (/[\/]{2} \@version (.*)/g.test(this._script) === true) {

            var matches = /[\/]{2} \@version (.*)/g.exec(this._script);

            return matches[1];
        } else {

            return "";
        }
    },

    /**
     *  ========================================================================
     *  ===================== SUPPORTED IN FUTUR VERSIONS ======================
     *  ========================================================================
     */

    /**
     *  @icon url
     *
     *  @returns String
     */
    getIcon: function () {

        var matches = /[\/]{2} \@icon (.*)/g.exec(this._script);

        return matches[1];
    },
    /**
     *  @match pattern
     *
     *  @returns Array
     */
    getMatches: function () {

        var _matches = [];

        var matches = /[\/]{2} \@match (.*)/g.exec(this._script);

        for (var i = 1; i < matches.length; i++) {

            _matches.push(matches[i]);
        }

        return _matches;
    },
    /**
     *  @resource url
     *
     *  @returns Array
     */
    getResources: function () {

        var _resources = [];

        var matches = /[\/]{2} \@resource (.*) (.*)/g.exec(this._script);

        for (var i = 1; i < matches.length; i++) {

            _resources.push(new Array(matches[i], matches[i+1]));
        }

        return _resources;
    },
    /**
     *  @run-at "document-end" | "document-start"
     *
     *  - Supports two values: document-end and document-start.
     *
     *  @returns String
     */
    getRunAt: function () {

        var matches = /[\/]{2} \@run-at (.*)/g.exec(this._script);

        // throw Exception if no match one or the other

        return matches[1];
    },
    /**
     *  @unwrap void
     *
     *  - This key is strongly recommended to only be used for debugging purposes.
     *
     *  @returns Boolean
     */
    hasUnwrap: function () {

        var _hasUnwrap = /[\/]{2} \@unwrap (.*)/g.test(this._script);

        return _hasUnwrap;
    }
});

/**
 *  KSGreasemonkeyAPI (KitScript Greasemonkey API Class)
 */
var KSGreasemonkeyAPI = Class.create(_Utils, {

    initialize: function ($super) {

        $super();
    }
});

/**
 *  ============================================================================
 *  ======================== Greasemonkey API Functions ========================
 *  ======================== Supported In Futur Versions =======================
 *  ============================================================================
 */

/**
 *  @param string name
 */
function GM_deleteValue(name) {

}

/**
 *  @param string name
 *  @param mixed defaultVal Default result to be returned
 */
function GM_getValue(name, defaultVal) {

}

function GM_listValues() {

}

/**
 *  @param string name
 *  @param string value
 */
function GM_setValues(name, value) {

}

/**
 *  @param string resource Resource name
 */
function GM_getResourceText(resource) {

}

/**
 *  @param string resource Resource name
 */
function GM_getResourceURL(resource) {

}

/**
 *  @param string css String of CSS
 */
function GM_addStyle(css) {

}

/**
 *  @param boolean binary
 *  @param string data
 *  @param object headers
 *  @param string method
 *  @param function onAbort
 *  @param function onError
 *  @param function onLoad
 *  @param function onProgress
 *  @param function onReadyStateChange
 *  @param string overideMimeType
 *  @param string password
 *  @param boolean synchronous
 *  @param object upload
 *  @param string url
 *  @param string user
 */
function GM_xmlhttpRequest(binary,data,headers,method,onAbort,onError,onLoad,onProgress,onReadyStateChange,overideMimeType,password,synchronous,upload,url,user) {

}

/**
 *  @param string message
 */
function GM_log(message) {

}

/**
 *  @param string url
 */
function GM_openInTab(url) {

}

/**
 *  @param string caption
 *  @param function commandFunc
 *  @param string accessKey
 */
function GMregisterMenuCommand(caption,commandFunc,accessKey) {

}
<commit_msg>rewrite of the metadata fetching<commit_after>/**
 *  KitScript - A User Script Manager For Safari
 *
 *  Greasemonkey.js - Javascript file containing Greasemonkey classes
 *  (by Prototype.js) used globally in the extension & implementing core
 *  Greasemonkey API.
 *
 *  @author Seraf Dos Santos <webmaster@cyb3r.ca>
 *  @copyright 2011-2012 Seraf Dos Santos - All rights reserved.
 *  @license MIT License
 *  @version 0.1
 */

//"use strict";

/**
 *  KSGMException (KitScript Greasemonkey Exception Class)
 */
var KSGMException = Class.create({

    initialize: function (msg) {

        this._msg = msg;
    },
    getMessage: function () {

        return this._msg;
    }
});

/**
 *  KSGreasemonkeyMetadata (KitScript Greasemonkey Metadata Class)
 */
var KSGreasemonkeyMetadata = Class.create(_Utils, {

    initialize: function ($super) {

        $super();

        this._isHeaderValid = false;
        this._script = "";

        this._md_name = '';
        this._md_namespace = '';
        this._md_description = '';
        this._md_requires = [];
        this._md_includes = [];
        this._md_excludes = [];
        this._md_version = '';
    },
    loadScript: function (scriptStr) {

        this._script = scriptStr;

        if (!this.isHeaderValid())
            throw new KSGMException("User script metadata block is invalid.");
        else
            this.parseMetadataBlock();
    },
    isHeaderValid: function () {

        this._isValid = /[\/]{2} ==UserScript==[^=]*==[\/]{1}UserScript==/m.test(this._script);

        return this._isValid;
    },
    parseMetadataBlock: function () {

        var _matches = /[\/]{2} ==UserScript==([^=]*)==[\/]{1}UserScript==/m.exec(this._script);

        var _lines = _matches[1].split("\n");

        for (var i=0; i<_lines.length; i++) {
            var _line = _lines[i].trim();

            if (/[\/]{2} \@name (.*)/g.test(_line) === true) {

                this._md_name = /[\/]{2} \@name (.*)/g.exec(_line)[1].trim();
            } else if (/[\/]{2} \@namespace (.*)/g.test(_line) === true) {

                this._md_namespace = /[\/]{2} \@namespace (.*)/g.exec(_line)[1].trim();
            } else if (/[\/]{2} \@description (.*)/g.test(_line) === true) {

                this._md_description = /[\/]{2} \@description (.*)/g.exec(_line)[1].trim();
            } else if (/[\/]{2} \@match (.*)/g.test(_line) === true) {

                this._md_requires.push(/[\/]{2} \@require (.*)/g.exec(_line)[1].trim());
            } else if (/[\/]{2} \@include (.*)/g.test(_line) === true) {

                this._md_includes.push(/[\/]{2} \@include (.*)/g.exec(_line)[1].trim());
            } else if (/[\/]{2} \@exclude (.*)/g.test(_line) === true) {

                this._md_excludes.push(/[\/]{2} \@exclude (.*)/g.exec(_line)[1].trim());
            } else if (/[\/]{2} \@version (.*)/g.test(_line) === true) {

                this._md_version = /[\/]{2} \@version (.*)/g.exec(_line)[1].trim();
            }
        }
    },

    /**
     *  =========================== SUPPORTED IN v0.1 ==========================
     *  === v === v === v === v === v === v === v === v === v === v === v === v
     */

    /**
     *  @name string – KS Mandatory
     *
     *  - The combination of namespace and name is the unique identifier for a Greasemonkey script.
     *
     *  @returns String
     */
    getName: function () {

        return this._md_name;
    },
    /**
     *  @namespace string – KS Mandatory
     *
     *  - The combination of namespace and name is the unique identifier for a Greasemonkey script.
     *
     *  @returns String
     */
    getNamespace: function () {

        return this._md_namespace;
    },
    /**
     *  @description string – KS Mandatory
     *
     *  @returns String
     */
    getDescription: function () {

        return this._md_description;
    },
    /**
     *  @requires url – Optional
     *
     *  @returns Array
     */
    getRequires: function () {

        return this._md_requires;
    },
    /**
     *  @includes pattern – Optional
     *
     *  - There can be any number of @include rules in a script.
     *  - If no include rule is provided, @include * is assumed.
     *
     *  @returns Array
     */
    getIncludes: function () {

        return this._md_includes;
    },
    /**
     *  @excludes pattern – Optional
     *
     *  - There can be any number of @exclude rules in a script.
     *
     *  @returns Array
     */
    getExcludes: function () {

        return this._md_excludes;
    },
    /**
     *  @version float – Optional
     *
     *  - This is the version of the script, which should be treated like a
     *      firefox extension version, and maintain the same syntax.
     *
     *  KS v0.1:
     *  - No auto-update implemented
     *
     *  @returns String
     */
    getVersion: function () {

        return this._md_version;
    },

    /**
     *  ========================================================================
     *  ===================== SUPPORTED IN FUTUR VERSIONS ======================
     *  ========================================================================
     */

    /**
     *  @icon url
     *
     *  @returns String
     */
    getIcon: function () {

        var matches = /[\/]{2} \@icon (.*)/g.exec(this._script);

        return matches[1];
    },
    /**
     *  @match pattern
     *
     *  @returns Array
     */
    getMatches: function () {

        var _matches = [];

        var matches = /[\/]{2} \@match (.*)/g.exec(this._script);

        for (var i = 1; i < matches.length; i++) {

            _matches.push(matches[i]);
        }

        return _matches;
    },
    /**
     *  @resource url
     *
     *  @returns Array
     */
    getResources: function () {

        var _resources = [];

        var matches = /[\/]{2} \@resource (.*) (.*)/g.exec(this._script);

        for (var i = 1; i < matches.length; i++) {

            _resources.push(new Array(matches[i], matches[i+1]));
        }

        return _resources;
    },
    /**
     *  @run-at "document-end" | "document-start"
     *
     *  - Supports two values: document-end and document-start.
     *
     *  @returns String
     */
    getRunAt: function () {

        var matches = /[\/]{2} \@run-at (.*)/g.exec(this._script);

        // throw Exception if no match one or the other

        return matches[1];
    },
    /**
     *  @unwrap void
     *
     *  - This key is strongly recommended to only be used for debugging purposes.
     *
     *  @returns Boolean
     */
    hasUnwrap: function () {

        var _hasUnwrap = /[\/]{2} \@unwrap (.*)/g.test(this._script);

        return _hasUnwrap;
    }
});

/**
 *  KSGreasemonkeyAPI (KitScript Greasemonkey API Class)
 */
var KSGreasemonkeyAPI = Class.create(_Utils, {

    initialize: function ($super) {

        $super();
    }
});

/**
 *  ============================================================================
 *  ======================== Greasemonkey API Functions ========================
 *  ======================== Supported In Futur Versions =======================
 *  ============================================================================
 */

/**
 *  @param string name
 */
function GM_deleteValue(name) {

}

/**
 *  @param string name
 *  @param mixed defaultVal Default result to be returned
 */
function GM_getValue(name, defaultVal) {

}

function GM_listValues() {

}

/**
 *  @param string name
 *  @param string value
 */
function GM_setValues(name, value) {

}

/**
 *  @param string resource Resource name
 */
function GM_getResourceText(resource) {

}

/**
 *  @param string resource Resource name
 */
function GM_getResourceURL(resource) {

}

/**
 *  @param string css String of CSS
 */
function GM_addStyle(css) {

}

/**
 *  @param boolean binary
 *  @param string data
 *  @param object headers
 *  @param string method
 *  @param function onAbort
 *  @param function onError
 *  @param function onLoad
 *  @param function onProgress
 *  @param function onReadyStateChange
 *  @param string overideMimeType
 *  @param string password
 *  @param boolean synchronous
 *  @param object upload
 *  @param string url
 *  @param string user
 */
function GM_xmlhttpRequest(binary,data,headers,method,onAbort,onError,onLoad,onProgress,onReadyStateChange,overideMimeType,password,synchronous,upload,url,user) {

}

/**
 *  @param string message
 */
function GM_log(message) {

}

/**
 *  @param string url
 */
function GM_openInTab(url) {

}

/**
 *  @param string caption
 *  @param function commandFunc
 *  @param string accessKey
 */
function GMregisterMenuCommand(caption,commandFunc,accessKey) {

}
<|endoftext|>


<commit_before>const sha1 = require('sha1');
const request = require('request');
const products = require('./../grab-products/products.json');
const lodash = require('lodash');

// get all categories
const categories = [];

products.forEach(product => {
    // if (!product.classifications.length) {
    //     console.warn('---> NO classifications');
    //     console.warn(product);
    //     return;
    // }

    product.classifications.forEach(classification => {
        const {taxon} = classification;
        const {name, pretty_name} = taxon;

        const newCategory = {
            name: pretty_name,
            displayName: name
        };

        const savedCategory = lodash.find(categories, newCategory);

        if (!savedCategory) {
            categories.push(newCategory);
        }

    });
});

function addCategory(category) {

    return new Promise((resolve, reject) =>
        request
            .post(
                'http://localhost:3000/add-category',
                {form: category},
                (err, result) => err ? reject(err) : resolve(result)
            )
    );

}

let chain = Promise.resolve();

categories.forEach(category => {
    chain = chain.then(() => addCategory(category).then(result => console.log(result)))
});

console.log(categories);
console.log(categories.length);
<commit_msg>category - add needed category<commit_after>const sha1 = require('sha1');
const request = require('request');
const products = require('./../grab-products/products.json');
const lodash = require('lodash');

// get all categories
const categories = [];

products.forEach(product => {
    // if (!product.classifications.length) {
    //     console.warn('---> NO classifications');
    //     console.warn(product);
    //     return;
    // }

    product.classifications.forEach(classification => {
        const {taxon} = classification;
        const {name, pretty_name} = taxon;

        const newCategory = {
            name: pretty_name,
            displayName: name
        };

        const savedCategory = lodash.find(categories, newCategory);

        if (!savedCategory) {
            categories.push(newCategory);
        }

    });
});

categories.push(
    {
        name: 'Иглы для тату',
        displayName: 'Иглы для тату'
    },
    {
        name: 'Иглы для тату -> Kwadron',
        displayName: 'Kwadron'
    },
    {
        name: 'Иглы для тату -> Иглы стандартные (Китай)',
        displayName: 'Иглы стандартные (Китай)'
    },
    {
        name: 'Иглы для тату -> Модули Cheyenne',
        displayName: 'Модули Cheyenne'
    },
    {
        name: 'Иглы для тату -> Модули Cheyenne -> CHEYENNE HAWK',
        displayName: 'CHEYENNE HAWK'
    },
    {
        name: 'Краски для тату -> WORLD FAMOUS',
        displayName: 'WORLD FAMOUS'
    },
    {
        name: 'Краски для тату -> WORLD FAMOUS -> Индивидуальные цвета',
        displayName: 'Индивидуальные цвета'
    },
    {
        name: 'Краски для тату -> INTENZE',
        displayName: 'INTENZE'
    },
    {
        name: 'Краски для тату -> INTENZE -> Индивидуальные цвета',
        displayName: 'Индивидуальные цвета'
    },
    {
        name: 'Типсы одноразовые',
        displayName: ''
    },
    {
        name: 'Микроблейдинг',
        displayName: ''
    },
    {
        name: 'Перманентный макияж -> Пигменты для татуажа',
        displayName: 'Пигменты для татуажа'
    }
);

function addCategory(category) {

    return new Promise((resolve, reject) =>
        request
            .post(
                'http://localhost:3000/add-category',
                {form: category},
                (err, result) => err ? reject(err) : resolve(result)
            )
    );

}

let chain = Promise.resolve();

categories.forEach(category => {
    chain = chain.then(() => addCategory(category).then(result => console.log(result)))
});

console.log(categories);
console.log(categories.length);
<|endoftext|>


<commit_before>import Ember from 'ember';
import TooltipAndPopoverComponent from 'ember-tooltips/components/tooltip-and-popover';
import layout from 'ember-tooltips/templates/components/popover-on-element';

const { $, run } = Ember;

export default TooltipAndPopoverComponent.extend({

  hideDelay: '250',

  layout,
  classNames: ['ember-popover'],
  _isMouseInside: false,
  didInsertElement() {
    this._super(...arguments);

    const event = this.get('event');
    const target = this.get('target');
    const $target = $(target);
    const $popover = this.$();

    if (event === 'none') {

      return;

    } else if (event === 'hover') {

      const _showOn = this.get('_showOn');
      const _hideOn = this.get('_hideOn');

      // _showOn == 'mouseenter'
      $target.on(_showOn, () => this.show());

      // _hideOn == 'mouseleave'
      $target.add($popover).on(_hideOn, () => {
        run.later(() => {
          if (!this.get('_isMouseInside')) {
            this.hide();
          }
        }, +this.get('hideDelay'));
      });

      // we must use mouseover/mouseout because they correctly
      // register hover interactivity when spacing='0'
      $target.add($popover).on('mouseover', () => this.set('_isMouseInside', true));
      $target.add($popover).on('mouseout', () => this.set('_isMouseInside', false));

    } else if (event === 'click') {

      $(document).on(`click.${target}`, (event) => {
        // this lightweight, name-spaced click handler is necessary to determine
        // if a click is NOT on $target and NOT an ancestor of $target.
        // If so then it must be a click elsewhere and should close the popover
        // see... https://css-tricks.com/dangers-stopping-event-propagation/
        const clickedElement = event.target;
        const isClickOutsideTarget = $target[0] !== clickedElement;
        const isClickOutsidePopover = !$target.find(clickedElement).length;
        const isShown = this.get('isShown');

        if (isClickOutsideTarget && isClickOutsidePopover && isShown) {
          this.hide();
        }
      });

      // we use mousedown because it occurs before the focus event
      $target.on('mousedown', (event) => {
        // $target.on('mousedown') is called when the $popover is
        // clicked because the $popover is contained within the $target.
        // This will ignores those types of clicks.
        if ($popover[0] === event.target || $popover.find(event.target).length) {
          return;
        }
        this.toggle();
      });
    }

    $target.on('focus', () => this.show());

    $popover.on('focusout', () => {
      // use a run.later() to allow the 'focusout' event to finish handling
      run.later(() => {
        const focusedElement = document.activeElement;
        const isFocusedElementTarget = focusedElement === $target[0];
        const isFocusedElementPopover = focusedElement === $popover[0];
        const isFocusedElementInPopover = !!$popover.find(focusedElement).length;
        if (isFocusedElementTarget || isFocusedElementPopover || isFocusedElementInPopover) {
          return;
        }
        this.hide();
      });
    });
  },
  willDestroyElement() {
    this._super(...arguments);

    const target = this.get('target');
    const $target = $(target);
    const $popover = this.$();
    const _showOn = this.get('_showOn');
    const _hideOn = this.get('_hideOn');

    $target.add($popover).off(`${_showOn} mouseover ${_hideOn} mouseout mousedown focus focusout`);

    $(document).off(`click.${target}`);

  },
  actions: {
    hide() {
      this.hide();
    }
  },

});
<commit_msg>use .in & check popover.in and popover.find<commit_after>import Ember from 'ember';
import TooltipAndPopoverComponent from 'ember-tooltips/components/tooltip-and-popover';
import layout from 'ember-tooltips/templates/components/popover-on-element';

const { $, run } = Ember;

export default TooltipAndPopoverComponent.extend({

  hideDelay: '250',

  layout,
  classNames: ['ember-popover'],
  _isMouseInside: false,
  didInsertElement() {
    this._super(...arguments);

    const event = this.get('event');
    const target = this.get('target');
    const $target = $(target);
    const $popover = this.$();

    if (event === 'none') {

      return;

    } else if (event === 'hover') {

      const _showOn = this.get('_showOn');
      const _hideOn = this.get('_hideOn');

      // _showOn == 'mouseenter'
      $target.on(_showOn, () => this.show());

      // _hideOn == 'mouseleave'
      $target.add($popover).on(_hideOn, () => {
        run.later(() => {
          if (!this.get('_isMouseInside')) {
            this.hide();
          }
        }, +this.get('hideDelay'));
      });

      // we must use mouseover/mouseout because they correctly
      // register hover interactivity when spacing='0'
      $target.add($popover).on('mouseover', () => this.set('_isMouseInside', true));
      $target.add($popover).on('mouseout', () => this.set('_isMouseInside', false));

    } else if (event === 'click') {

      $(document).on(`click.${target}`, (event) => {
        // this lightweight, name-spaced click handler is necessary to determine
        // if a click is NOT on $target and NOT an ancestor of $target.
        // If so then it must be a click elsewhere and should close the popover
        // see... https://css-tricks.com/dangers-stopping-event-propagation/
        const isClickedElementElsewhere = this._isElementElsewhere(event.target);
        const isPopoverShown = this.get('isShown');

        if (isClickedElementElsewhere && isPopoverShown) {
          this.hide();
        }
      });

      // we use mousedown because it occurs before the focus event
      $target.on('mousedown', (event) => {
        // $target.on('mousedown') is called when the $popover is
        // clicked because the $popover is contained within the $target.
        // This will ignores those types of clicks.
        const isMouseDownElementInPopover = this._isElementInPopover(event.target);
        if (isMouseDownElementInPopover) {
          return;
        }
        this.toggle();
      });
    }

    $target.on('focus', () => this.show());

    $popover.on('focusout', () => {
      // use a run.later() to allow the 'focusout' event to finish handling
      run.later(() => {
        const isFocusedElementElsewhere = this._isElementElsewhere(document.activeElement);
        if (isFocusedElementElsewhere) {
          this.hide();
        }
      });
    });
  },
  willDestroyElement() {
    this._super(...arguments);

    const target = this.get('target');
    const $target = $(target);
    const $popover = this.$();
    const _showOn = this.get('_showOn');
    const _hideOn = this.get('_hideOn');

    $target.add($popover).off(`${_showOn} mouseover ${_hideOn} mouseout mousedown focus focusout`);

    $(document).off(`click.${target}`);
  },
  _isElementInPopover(newElement) {
    // determines if newElement is $popover or contained within $popover
    const $popover = this.$();
    return $popover.is(newElement) || $popover.find(newElement).length;
  },
  _isElementElsewhere(newElement) {
    // determines if newElement is not $target, not $popover, and not contained within either
    const $target = $(this.get('target'));

    const isNewElementOutsideTarget = !$target.is(newElement) && !$target.find(newElement).length;
    const isNewElementOutsidePopover = !this._isElementInPopover(newElement);

    return isNewElementOutsideTarget && isNewElementOutsidePopover;
  },
  actions: {
    hide() {
      this.hide();
    }
  },
});
<|endoftext|>


<commit_before>import Ember from 'ember';
export default Ember.Mixin.create({
	_orgValue : null,
	_orgArray : null,

	property: null,

	value:null,

	registerComponent:function(component) {
		this._super(component);
		component.set('value',this.get('value'));
	},

	init: function() {
		this._super();
		// If we do not have a name, we're an anonymous option without a counterpart in
		if(this.get('_name')!==null) {
//			Ember.warn("No attribute in target model for input "+this._name+" (path "+this._path+")",this.get('_panel.for.'+this.get('_name'))!==undefined);
//			if(this.get('_panel.for.'+this.get('_name'))!==undefined) {
			var propertyName= '_panel.'+(this._panel['for']  ? 'for.' : 'value.')+this.get('_name');
			this.reopen({
				property:Ember.computed.alias(propertyName)
			});
			var property=this.get('property');
			if(Ember.PromiseProxyMixin.detect(property)) {
				var control=this;

				property.then(function(propertyValue){
					control.set('value',propertyValue);
					control._setOrgValue(propertyValue);
				});
			}
			else {
				this.set('value',this.get('property'));
				this._setOrgValue(this.get('property'));
			}
//			}
//			else {
//				this._setOrgValue(this.get('value'));
//			}
		}
	},

	_propertyObserver:function() {

		// If we sync to the source, do not update the _orgValue so we keep a reliable dirty flag
		// If we're not syncing to the source, something else updated it and we should be dirty accordingly, so update _orgValue
//		if(!this.get('_form._syncToSource')) {
//			this._setOrgValue(this.get('property'));
//		}
//		if(this.get('_name') && this.get('_form._syncFromSource') && this.get('value')!==this.get('property')) {

		// Only run this once. Ember-data relationships may have notified a change, but the changed relationship is not available.
		Ember.run.once(this,function() {
//
			var property=this.get('property');
			if(Ember.PromiseProxyMixin.detect(property)) {
				var control=this;
				property.then(function(propertyValue){
					control.set('value',propertyValue);
				});
			}
			else {
				if( this.get('value')!==property) {
					this.set('value',this.get('property'));
				}
			}
		});
		//this.setDirty(this.get('value')!==this.get('_orgValue'));
	}.observes('property'),

	_valueObserver:function() {
		this._apply();
		var value=this.get('value');
		var dirty=false;
		if(value!==this.get('_orgValue')) {
			dirty=true;
		} else if(this._orgArray) {
			var orgArray=this._orgArray;
			if(value.length!==orgArray.length) {
				dirty=true;
			}
			else {
				value.forEach(function(value) {
					if(!orgArray.contains(value)) {
						dirty=true;
					}
				});
			}

		}
		this.setDirty(dirty);
		this.notifyChange();
	}.observes('value'),

	_apply: function() {
		if(this.property!==null) {
			Ember.run.scheduleOnce('sync',this,function(){
				var property=this.get('property');
				var value=this.get('value');
				this._components.invoke('set','value',this.get('value'));

				if(Ember.Enumerable.detect(property)) {
					var dirty=false;
					if(value.get('length')!==property.get('length')) {
						dirty=true;
					}
					else {
						value.forEach(function(value) {
							if(!property.contains(value)) {
								dirty=true;
							}
						});
						property.forEach(function(property) {
							if(!value.contains(property)) {
								dirty=true;
							}
						});
					}
					if(dirty) {
						property.clear();
						property.pushObjects(value);
					}

				}
				else if(value!==property) {
					try{
						this.set('property',value);
					}
					catch(e) {
						Ember.warn(this.toString()+" (in panel "+this._panel.toString()+" with target "+this.get('_panel.for')+") could not update its corresponding property to the new value: "+e);
					}
				}
			});
		}
	},

	_reset: function(modelChanged) {
		if(modelChanged) {
			var property=this.get('property');
			if(Ember.PromiseProxyMixin.detect(property)) {
				var control=this;
				this._setOrgValue(null);
				this.set('value',null);
				property.then(function(propertyValue){
					if(modelChanged) {
						control._setOrgValue(propertyValue);
					}
					control.set('value',propertyValue);
				});
			}
			else {
				this.set('value',property);
			}
		}
		else {
			this.set('value',this._orgValue);
		}
		this._super(modelChanged);
	},

	_setOrgValue: function(orgValue) {
		this.set('_orgValue',orgValue);
		if(Ember.MutableArray.detect(orgValue)) {
			this.set('_orgArray',orgValue.toArray());
		} else {
			this.set('_orgArray',null);
		}
	}

});<commit_msg>Added value-support onChange event<commit_after>import Ember from 'ember';
export default Ember.Mixin.create({
	_orgValue : null,
	_orgArray : null,

	property: null,

	value:null,

	registerComponent:function(component) {
		this._super(component);
		component.set('value',this.get('value'));
	},

	actions : {

		onChange:function() {

		}
	},
	init: function() {
		this._super();
		// If we do not have a name, we're an anonymous option without a counterpart in
		if(this.get('_name')!==null) {
//			Ember.warn("No attribute in target model for input "+this._name+" (path "+this._path+")",this.get('_panel.for.'+this.get('_name'))!==undefined);
//			if(this.get('_panel.for.'+this.get('_name'))!==undefined) {
			var propertyName= '_panel.'+(this._panel['for']  ? 'for.' : 'value.')+this.get('_name');
			this.reopen({
				property:Ember.computed.alias(propertyName)
			});
			var property=this.get('property');
			if(Ember.PromiseProxyMixin.detect(property)) {
				var control=this;

				property.then(function(propertyValue){
					control.set('value',propertyValue);
					control._setOrgValue(propertyValue);
				});
			}
			else {
				this.set('value',this.get('property'));
				this._setOrgValue(this.get('property'));
			}
//			}
//			else {
//				this._setOrgValue(this.get('value'));
//			}
		}
	},

	_propertyObserver:function() {

		// If we sync to the source, do not update the _orgValue so we keep a reliable dirty flag
		// If we're not syncing to the source, something else updated it and we should be dirty accordingly, so update _orgValue
//		if(!this.get('_form._syncToSource')) {
//			this._setOrgValue(this.get('property'));
//		}
//		if(this.get('_name') && this.get('_form._syncFromSource') && this.get('value')!==this.get('property')) {

		// Only run this once. Ember-data relationships may have notified a change, but the changed relationship is not available.
		Ember.run.once(this,function() {
//
			var property=this.get('property');
			if(Ember.PromiseProxyMixin.detect(property)) {
				var control=this;
				property.then(function(propertyValue){
					control.set('value',propertyValue);
				});
			}
			else {
				if( this.get('value')!==property) {
					this.set('value',this.get('property'));
				}
			}
		});
		//this.setDirty(this.get('value')!==this.get('_orgValue'));
	}.observes('property'),

	_valueObserver:Ember.observer('value',function() {
		this._apply();
		var value=this.get('value');
		var dirty=false;
		if(value!==this.get('_orgValue')) {
			dirty=true;
		} else if(this._orgArray) {
			var orgArray=this._orgArray;
			if(value.length!==orgArray.length) {
				dirty=true;
			}
			else {
				value.forEach(function(value) {
					if(!orgArray.contains(value)) {
						dirty=true;
					}
				});
			}

		}
		this.setDirty(dirty);
		this.send('onChange');
		this.notifyChange();
	}),

	_apply: function() {
		if(this.property!==null) {
			Ember.run.scheduleOnce('sync',this,function(){
				var property=this.get('property');
				var value=this.get('value');
				this._components.invoke('set','value',this.get('value'));

				if(Ember.Enumerable.detect(property)) {
					var dirty=false;
					if(value.get('length')!==property.get('length')) {
						dirty=true;
					}
					else {
						value.forEach(function(value) {
							if(!property.contains(value)) {
								dirty=true;
							}
						});
						property.forEach(function(property) {
							if(!value.contains(property)) {
								dirty=true;
							}
						});
					}
					if(dirty) {
						property.clear();
						property.pushObjects(value);
					}

				}
				else if(value!==property) {
					try{
						this.set('property',value);
					}
					catch(e) {
						Ember.warn(this.toString()+" (in panel "+this._panel.toString()+" with target "+this.get('_panel.for')+") could not update its corresponding property to the new value: "+e);
					}
				}
			});
		}
	},

	_reset: function(modelChanged) {
		if(modelChanged) {
			var property=this.get('property');
			if(Ember.PromiseProxyMixin.detect(property)) {
				var control=this;
				this._setOrgValue(null);
				this.set('value',null);
				property.then(function(propertyValue){
					if(modelChanged) {
						control._setOrgValue(propertyValue);
					}
					control.set('value',propertyValue);
				});
			}
			else {
				this.set('value',property);
			}
		}
		else {
			this.set('value',this._orgValue);
		}
		this._super(modelChanged);
	},

	_setOrgValue: function(orgValue) {
		this.set('_orgValue',orgValue);
		if(Ember.MutableArray.detect(orgValue)) {
			this.set('_orgArray',orgValue.toArray());
		} else {
			this.set('_orgArray',null);
		}
	}

});<|endoftext|>